From 0d9aa593a49ec9b0c4b6b9c1ef676243b28db6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:40:32 +0100 Subject: [PATCH 01/59] aws_appflow_connector_profile resource --- .github/labeler-issue-triage.yml | 2 + .github/labeler-pr-triage.yml | 3 + internal/provider/provider.go | 3 + internal/service/appflow/connector_profile.go | 1609 +++++++++++++++++ .../service/appflow/connector_profile_test.go | 627 +++++++ website/allowed-subcategories.txt | 1 + .../r/appflow_connector_profile.html.markdown | 367 ++++ 7 files changed, 2612 insertions(+) create mode 100644 internal/service/appflow/connector_profile.go create mode 100644 internal/service/appflow/connector_profile_test.go create mode 100644 website/docs/r/appflow_connector_profile.html.markdown diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index efbed7e61db..5bd27983671 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -50,6 +50,8 @@ service/apigatewayv2: - '((\*|-) ?`?|(data|resource) "?)aws_apigatewayv2_' service/appconfig: - '((\*|-) ?`?|(data|resource) "?)aws_appconfig_' +service/appflow: + - '((\*|-) ?`?|(data|resource) "?)aws_appflow_' service/appintegrations: - '((\*|-) ?`?|(data|resource) "?)aws_appintegrations_' service/applicationautoscaling: diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index 50d71bf9919..9f6cfcdfaec 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -80,6 +80,9 @@ service/apigatewayv2: service/appconfig: - 'internal/service/appconfig/**/*' - 'website/**/appconfig_*' +service/appflow: + - 'internal/service/appflow/**/*' + - 'website/**/appflow_*' service/appintegrations: - 'internal/service/appintegrations/**/*' - 'website/**/appintegrations_*' diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 72cd598284d..68a08407574 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -23,6 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/service/apigatewayv2" "github.com/hashicorp/terraform-provider-aws/internal/service/appautoscaling" "github.com/hashicorp/terraform-provider-aws/internal/service/appconfig" + "github.com/hashicorp/terraform-provider-aws/internal/service/appflow" "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" "github.com/hashicorp/terraform-provider-aws/internal/service/apprunner" "github.com/hashicorp/terraform-provider-aws/internal/service/appstream" @@ -919,6 +920,8 @@ func Provider() *schema.Provider { "aws_appautoscaling_scheduled_action": appautoscaling.ResourceScheduledAction(), "aws_appautoscaling_target": appautoscaling.ResourceTarget(), + "aws_appflow_connector_profile": appflow.ResourceConnectorProfile(), + "aws_appmesh_gateway_route": appmesh.ResourceGatewayRoute(), "aws_appmesh_mesh": appmesh.ResourceMesh(), "aws_appmesh_route": appmesh.ResourceRoute(), diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go new file mode 100644 index 00000000000..e7b0940cd8b --- /dev/null +++ b/internal/service/appflow/connector_profile.go @@ -0,0 +1,1609 @@ +package appflow + +import ( + "fmt" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appflow" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceConnectorProfile() *schema.Resource { + return &schema.Resource{ + Create: resourceConnectorProfileCreate, + Read: resourceConnectorProfileRead, + Update: resourceConnectorProfileUpdate, + Delete: resourceConnectorProfileDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "connection_mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appflow.ConnectionMode_Values(), false), + }, + "connector_profile_arn": { + Type: schema.TypeString, + Computed: true, + }, + "connector_profile_config": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connector_profile_credentials": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "amplitude": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "secret_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "datadog": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "application_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "dynatrace": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_token": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "google_analytics": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "honeycode": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "infor_nexus": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_key_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "datakey": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "secret_access_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "user_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "marketo": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + }, + }, + }, + "redshift": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "salesforce": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_credentials_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "service_now": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "singular": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "slack": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + }, + }, + }, + "snowflake": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "trendmicro": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_secret_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "veeva": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "zendesk": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "connector_profile_properties": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "amplitude": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "datadog": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "dynatrace": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "google_analytics": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "honeycode": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "infor_nexus": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "marketo": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "redshift": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(3, 63), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "bucket_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "database_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "salesforce": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "is_sandbox_environment": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "service_now": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "singular": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "slack": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "snowflake": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "bucket_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(3, 63), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "bucket_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "private_link_service_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "region": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "stage": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return old == new || old == "@"+new + }, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + "warehouse": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 512), + validation.StringMatch(regexp.MustCompile(`[\s\w/!@#+=.-]*`), "must match [\\s\\w/!@#+=.-]*"), + ), + }, + }, + }, + }, + "trendmicro": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + }, + "veeva": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + "zendesk": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "connector_profile_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`[\w/!@#+=.-]+`), "must match [\\w/!@#+=.-]+"), + ), + }, + "connector_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appflow.ConnectorType_Values(), false), + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "kms_arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + "last_updated_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppFlowConn + name := d.Get("connector_profile_name").(string) + + createConnectorProfileInput := appflow.CreateConnectorProfileInput{ + ConnectionMode: aws.String(d.Get("connection_mode").(string)), + ConnectorProfileConfig: expandConnectorProfileConfig(d.Get("connector_profile_config").([]interface{})[0].(map[string]interface{})), + ConnectorProfileName: aws.String(name), + ConnectorType: aws.String(d.Get("connector_type").(string)), + } + + if v, ok := d.Get("kms_arn").(string); ok && len(v) > 0 { + createConnectorProfileInput.KmsArn = aws.String(v) + } + + _, err := conn.CreateConnectorProfile(&createConnectorProfileInput) + + if err != nil { + return fmt.Errorf("error creating AppFlow Connector Profile: %w", err) + } + + d.SetId(name) + + return resourceConnectorProfileRead(d, meta) +} + +func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppFlowConn + + connectorProfile, err := GetConnectorProfile(conn, d.Id()) + + if err != nil { + return err + } + + credentials := d.Get("connector_profile_config.0.connector_profile_credentials").([]interface{}) + + d.Set("connection_mode", connectorProfile.ConnectionMode) + d.Set("connector_profile_arn", connectorProfile.ConnectorProfileArn) + d.Set("connector_profile_name", connectorProfile.ConnectorProfileName) + d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) + d.Set("connector_type", connectorProfile.ConnectorType) + d.Set("created_at", aws.TimeValue(connectorProfile.CreatedAt).Format(time.RFC3339)) + d.Set("last_updated_at", aws.TimeValue(connectorProfile.LastUpdatedAt).Format(time.RFC3339)) + + d.SetId(d.Get("connector_profile_name").(string)) + + return nil +} + +func GetConnectorProfile(conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { + params := &appflow.DescribeConnectorProfilesInput{ + ConnectorProfileNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeConnectorProfiles(params) + + if err != nil { + return nil, err + } + + for _, connectorProfile := range output.ConnectorProfileDetails { + if aws.StringValue(connectorProfile.ConnectorProfileName) == name { + return connectorProfile, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + params.NextToken = output.NextToken + } + + return nil, fmt.Errorf("No AppFlow Connector Profile found with name: %s", name) +} + +func resourceConnectorProfileUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceConnectorProfileDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppFlowConn + _, err := conn.DeleteConnectorProfile(&appflow.DeleteConnectorProfileInput{ + ConnectorProfileName: aws.String(d.Id()), + }) + + if err != nil { + return fmt.Errorf("Error deleting AppFlow Connector Profile (%s): %w", d.Id(), err) + } + + return nil +} + +func expandConnectorProfileConfig(m map[string]interface{}) *appflow.ConnectorProfileConfig { + cpc := appflow.ConnectorProfileConfig{ + ConnectorProfileCredentials: expandConnectorProfileCredentials(m["connector_profile_credentials"].([]interface{})[0].(map[string]interface{})), + ConnectorProfileProperties: expandConnectorProfileProperties(m["connector_profile_properties"].([]interface{})[0].(map[string]interface{})), + } + + return &cpc +} + +func expandConnectorProfileCredentials(m map[string]interface{}) *appflow.ConnectorProfileCredentials { + cpc := appflow.ConnectorProfileCredentials{} + + if v, ok := m["amplitude"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Amplitude = expandAmplitudeConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["datadog"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Datadog = expandDatadogConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["dynatrace"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Dynatrace = expandDynatraceConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["google_analytics"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.GoogleAnalytics = expandGoogleAnalyticsConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["honeycode"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Honeycode = expandHoneycodeConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["infor_nexus"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.InforNexus = expandInforNexusConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["marketo"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Marketo = expandMarketoConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["salesforce"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Salesforce = expandSalesforceConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["service_now"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.ServiceNow = expandServiceNowConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["singular"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Singular = expandSingularConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["slack"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Slack = expandSlackConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["snowflake"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Snowflake = expandSnowflakeConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["trendmicro"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Trendmicro = expandTrendmicroConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["veeva"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Veeva = expandVeevaConnectorProfileCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["zendesk"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Zendesk = expandZendeskConnectorProfileCredentials(v[0].(map[string]interface{})) + } + + return &cpc +} + +func expandAmplitudeConnectorProfileCredentials(m map[string]interface{}) *appflow.AmplitudeConnectorProfileCredentials { + credentials := appflow.AmplitudeConnectorProfileCredentials{ + ApiKey: aws.String(m["api_key"].(string)), + SecretKey: aws.String(m["secret_key"].(string)), + } + + return &credentials +} + +func expandDatadogConnectorProfileCredentials(m map[string]interface{}) *appflow.DatadogConnectorProfileCredentials { + credentials := appflow.DatadogConnectorProfileCredentials{ + ApiKey: aws.String(m["api_key"].(string)), + ApplicationKey: aws.String(m["application_key"].(string)), + } + + return &credentials +} + +func expandDynatraceConnectorProfileCredentials(m map[string]interface{}) *appflow.DynatraceConnectorProfileCredentials { + credentials := appflow.DynatraceConnectorProfileCredentials{ + ApiToken: aws.String(m["api_token"].(string)), + } + + return &credentials +} + +func expandGoogleAnalyticsConnectorProfileCredentials(m map[string]interface{}) *appflow.GoogleAnalyticsConnectorProfileCredentials { + credentials := appflow.GoogleAnalyticsConnectorProfileCredentials{ + ClientId: aws.String(m["client_id"].(string)), + ClientSecret: aws.String(m["client_secret"].(string)), + } + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + if v, ok := m["refresh_token"].(string); ok && v != "" { + credentials.RefreshToken = aws.String(v) + } + + return &credentials +} + +func expandHoneycodeConnectorProfileCredentials(m map[string]interface{}) *appflow.HoneycodeConnectorProfileCredentials { + credentials := appflow.HoneycodeConnectorProfileCredentials{} + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + if v, ok := m["refresh_token"].(string); ok && v != "" { + credentials.RefreshToken = aws.String(v) + } + + return &credentials +} + +func expandInforNexusConnectorProfileCredentials(m map[string]interface{}) *appflow.InforNexusConnectorProfileCredentials { + credentials := appflow.InforNexusConnectorProfileCredentials{ + AccessKeyId: aws.String(m["access_key_id"].(string)), + Datakey: aws.String(m["datakey"].(string)), + SecretAccessKey: aws.String(m["secret_access_key"].(string)), + UserId: aws.String(m["user_id"].(string)), + } + + return &credentials +} + +func expandMarketoConnectorProfileCredentials(m map[string]interface{}) *appflow.MarketoConnectorProfileCredentials { + credentials := appflow.MarketoConnectorProfileCredentials{ + ClientId: aws.String(m["client_id"].(string)), + ClientSecret: aws.String(m["client_secret"].(string)), + } + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + return &credentials +} + +func expandSalesforceConnectorProfileCredentials(m map[string]interface{}) *appflow.SalesforceConnectorProfileCredentials { + credentials := appflow.SalesforceConnectorProfileCredentials{} + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["client_credentials_arn"].(string); ok && v != "" { + credentials.ClientCredentialsArn = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + if v, ok := m["refresh_token"].(string); ok && v != "" { + credentials.RefreshToken = aws.String(v) + } + + return &credentials +} + +func expandServiceNowConnectorProfileCredentials(m map[string]interface{}) *appflow.ServiceNowConnectorProfileCredentials { + credentials := appflow.ServiceNowConnectorProfileCredentials{ + Password: aws.String(m["password"].(string)), + Username: aws.String(m["username"].(string)), + } + + return &credentials +} + +func expandSingularConnectorProfileCredentials(m map[string]interface{}) *appflow.SingularConnectorProfileCredentials { + credentials := appflow.SingularConnectorProfileCredentials{ + ApiKey: aws.String(m["api_key"].(string)), + } + + return &credentials +} + +func expandSlackConnectorProfileCredentials(m map[string]interface{}) *appflow.SlackConnectorProfileCredentials { + credentials := appflow.SlackConnectorProfileCredentials{ + AccessToken: aws.String(m["access_token"].(string)), + ClientId: aws.String(m["client_id"].(string)), + ClientSecret: aws.String(m["client_secret"].(string)), + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + return &credentials +} + +func expandSnowflakeConnectorProfileCredentials(m map[string]interface{}) *appflow.SnowflakeConnectorProfileCredentials { + credentials := appflow.SnowflakeConnectorProfileCredentials{ + Password: aws.String(m["password"].(string)), + Username: aws.String(m["username"].(string)), + } + + return &credentials +} + +func expandTrendmicroConnectorProfileCredentials(m map[string]interface{}) *appflow.TrendmicroConnectorProfileCredentials { + credentials := appflow.TrendmicroConnectorProfileCredentials{ + ApiSecretKey: aws.String(m["api_secret_key"].(string)), + } + + return &credentials +} + +func expandVeevaConnectorProfileCredentials(m map[string]interface{}) *appflow.VeevaConnectorProfileCredentials { + credentials := appflow.VeevaConnectorProfileCredentials{ + Password: aws.String(m["password"].(string)), + Username: aws.String(m["username"].(string)), + } + + return &credentials +} + +func expandZendeskConnectorProfileCredentials(m map[string]interface{}) *appflow.ZendeskConnectorProfileCredentials { + credentials := appflow.ZendeskConnectorProfileCredentials{ + AccessToken: aws.String(m["access_token"].(string)), + ClientId: aws.String(m["client_id"].(string)), + ClientSecret: aws.String(m["client_secret"].(string)), + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + return &credentials +} + +func expandOAuthRequest(m map[string]interface{}) *appflow.ConnectorOAuthRequest { + r := appflow.ConnectorOAuthRequest{} + + if v, ok := m["auth_code"].(string); ok && v != "" { + r.AuthCode = aws.String(v) + } + + if v, ok := m["redirect_uri"].(string); ok && v != "" { + r.RedirectUri = aws.String(v) + } + + return &r +} + +func expandConnectorProfileProperties(m map[string]interface{}) *appflow.ConnectorProfileProperties { + cpc := appflow.ConnectorProfileProperties{} + + if v, ok := m["amplitude"].([]interface{}); ok && len(v) > 0 { + cpc.Amplitude = &appflow.AmplitudeConnectorProfileProperties{} + } + + if v, ok := m["datadog"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Datadog = expandDatadogConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["dynatrace"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Dynatrace = expandDynatraceConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["google_analytics"].([]interface{}); ok && len(v) > 0 { + cpc.GoogleAnalytics = &appflow.GoogleAnalyticsConnectorProfileProperties{} + } + + if v, ok := m["honeycode"].([]interface{}); ok && len(v) > 0 { + cpc.Honeycode = &appflow.HoneycodeConnectorProfileProperties{} + } + + if v, ok := m["infor_nexus"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.InforNexus = expandInforNexusConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["marketo"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Marketo = expandMarketoConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["redshift"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Redshift = expandRedshiftConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["salesforce"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Salesforce = expandSalesforceConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["service_now"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.ServiceNow = expandServiceNowConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["singular"].([]interface{}); ok && len(v) > 0 { + cpc.Singular = &appflow.SingularConnectorProfileProperties{} + } + + if v, ok := m["slack"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Slack = expandSlackConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["snowflake"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Snowflake = expandSnowflakeConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["trendmicro"].([]interface{}); ok && len(v) > 0 { + cpc.Trendmicro = &appflow.TrendmicroConnectorProfileProperties{} + } + + if v, ok := m["veeva"].([]interface{}); ok && len(v) > 0 { + cpc.Veeva = expandVeevaConnectorProfileProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["zendesk"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Zendesk = expandZendeskConnectorProfileProperties(v[0].(map[string]interface{})) + } + + return &cpc +} + +func expandDatadogConnectorProfileProperties(m map[string]interface{}) *appflow.DatadogConnectorProfileProperties { + properties := appflow.DatadogConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandDynatraceConnectorProfileProperties(m map[string]interface{}) *appflow.DynatraceConnectorProfileProperties { + properties := appflow.DynatraceConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandInforNexusConnectorProfileProperties(m map[string]interface{}) *appflow.InforNexusConnectorProfileProperties { + properties := appflow.InforNexusConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandMarketoConnectorProfileProperties(m map[string]interface{}) *appflow.MarketoConnectorProfileProperties { + properties := appflow.MarketoConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandRedshiftConnectorProfileProperties(m map[string]interface{}) *appflow.RedshiftConnectorProfileProperties { + properties := appflow.RedshiftConnectorProfileProperties{ + BucketName: aws.String(m["bucket_name"].(string)), + RoleArn: aws.String(m["role_arn"].(string)), + } + + if v, ok := m["bucket_prefix"].(string); ok && v != "" { + properties.BucketPrefix = aws.String(v) + } + + if v, ok := m["database_url"].(string); ok && v != "" { + properties.DatabaseUrl = aws.String(v) + } + + return &properties +} + +func expandServiceNowConnectorProfileProperties(m map[string]interface{}) *appflow.ServiceNowConnectorProfileProperties { + properties := appflow.ServiceNowConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandSalesforceConnectorProfileProperties(m map[string]interface{}) *appflow.SalesforceConnectorProfileProperties { + properties := appflow.SalesforceConnectorProfileProperties{} + + if v, ok := m["instance_url"].(string); ok && v != "" { + properties.InstanceUrl = aws.String(v) + } + + if v, ok := m["is_sandbox_environment"].(bool); ok { + properties.IsSandboxEnvironment = aws.Bool(v) + } + + return &properties +} + +func expandSlackConnectorProfileProperties(m map[string]interface{}) *appflow.SlackConnectorProfileProperties { + properties := appflow.SlackConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandSnowflakeConnectorProfileProperties(m map[string]interface{}) *appflow.SnowflakeConnectorProfileProperties { + properties := appflow.SnowflakeConnectorProfileProperties{ + BucketName: aws.String(m["bucket_name"].(string)), + Stage: aws.String(m["stage"].(string)), + Warehouse: aws.String(m["warehouse"].(string)), + } + + if v, ok := m["account_name"].(string); ok && v != "" { + properties.AccountName = aws.String(v) + } + + if v, ok := m["bucket_prefix"].(string); ok && v != "" { + properties.BucketPrefix = aws.String(v) + } + + if v, ok := m["private_link_service_name"].(string); ok && v != "" { + properties.PrivateLinkServiceName = aws.String(v) + } + + if v, ok := m["region"].(string); ok && v != "" { + properties.Region = aws.String(v) + } + + return &properties +} + +func expandVeevaConnectorProfileProperties(m map[string]interface{}) *appflow.VeevaConnectorProfileProperties { + properties := appflow.VeevaConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func expandZendeskConnectorProfileProperties(m map[string]interface{}) *appflow.ZendeskConnectorProfileProperties { + properties := appflow.ZendeskConnectorProfileProperties{ + InstanceUrl: aws.String(m["instance_url"].(string)), + } + + return &properties +} + +func flattenConnectorProfileConfig(cpp *appflow.ConnectorProfileProperties, cpc []interface{}) []interface{} { + m := make(map[string]interface{}) + + m["connector_profile_properties"] = flattenConnectorProfileProperties(cpp) + m["connector_profile_credentials"] = cpc + + return []interface{}{m} +} + +func flattenConnectorProfileProperties(cpp *appflow.ConnectorProfileProperties) []interface{} { + result := make(map[string]interface{}) + + if cpp.Amplitude != nil { + m := make(map[string]interface{}) + result["amplitude"] = []interface{}{m} + } + if cpp.Datadog != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Datadog.InstanceUrl) + result["datadog"] = []interface{}{m} + } + if cpp.Dynatrace != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Dynatrace.InstanceUrl) + result["dynatrace"] = []interface{}{m} + } + if cpp.GoogleAnalytics != nil { + m := make(map[string]interface{}) + result["google_analytics"] = []interface{}{m} + } + if cpp.Honeycode != nil { + m := make(map[string]interface{}) + result["honeycode"] = []interface{}{m} + } + if cpp.InforNexus != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.InforNexus.InstanceUrl) + result["infor_nexus"] = []interface{}{m} + } + if cpp.Marketo != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Marketo.InstanceUrl) + result["marketo"] = []interface{}{m} + } + if cpp.Redshift != nil { + result["redshift"] = flattenRedshiftConnectorProfileProperties(cpp.Redshift) + } + if cpp.Salesforce != nil { + result["salesforce"] = flattenSalesforceConnectorProfileProperties(cpp.Salesforce) + } + if cpp.ServiceNow != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.ServiceNow.InstanceUrl) + result["service_now"] = []interface{}{m} + } + if cpp.Singular != nil { + m := make(map[string]interface{}) + result["singular"] = []interface{}{m} + } + if cpp.Slack != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Slack.InstanceUrl) + result["slack"] = []interface{}{m} + } + if cpp.Snowflake != nil { + result["snowflake"] = flattenSnowflakeConnectorProfileProperties(cpp.Snowflake) + } + if cpp.Trendmicro != nil { + m := make(map[string]interface{}) + result["trendmicro"] = []interface{}{m} + } + if cpp.Veeva != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Veeva.InstanceUrl) + result["veeva"] = []interface{}{m} + } + if cpp.Zendesk != nil { + m := make(map[string]interface{}) + m["instance_url"] = aws.StringValue(cpp.Zendesk.InstanceUrl) + result["zendesk"] = []interface{}{m} + } + + return []interface{}{result} +} + +func flattenRedshiftConnectorProfileProperties(properties *appflow.RedshiftConnectorProfileProperties) []interface{} { + m := make(map[string]interface{}) + + m["bucket_name"] = aws.StringValue(properties.BucketName) + + if properties.BucketPrefix != nil { + m["bucket_prefix"] = aws.StringValue(properties.BucketPrefix) + } + + if properties.DatabaseUrl != nil { + m["database_url"] = aws.StringValue(properties.DatabaseUrl) + } + + m["role_arn"] = aws.StringValue(properties.RoleArn) + + return []interface{}{m} +} + +func flattenSalesforceConnectorProfileProperties(properties *appflow.SalesforceConnectorProfileProperties) []interface{} { + m := make(map[string]interface{}) + + if properties.InstanceUrl != nil { + m["instance_url"] = aws.StringValue(properties.InstanceUrl) + } + + if properties.IsSandboxEnvironment != nil { + m["is_sandbox_environment"] = aws.BoolValue(properties.IsSandboxEnvironment) + } + + return []interface{}{m} +} + +func flattenSnowflakeConnectorProfileProperties(properties *appflow.SnowflakeConnectorProfileProperties) []interface{} { + m := make(map[string]interface{}) + if properties.AccountName != nil { + m["account_name"] = aws.StringValue(properties.AccountName) + } + + m["bucket_name"] = aws.StringValue(properties.BucketName) + + if properties.BucketPrefix != nil { + m["bucket_prefix"] = aws.StringValue(properties.BucketPrefix) + } + + if properties.Region != nil { + m["region"] = aws.StringValue(properties.Region) + } + + m["stage"] = aws.StringValue(properties.Stage) + m["warehouse"] = aws.StringValue(properties.Warehouse) + + return []interface{}{m} +} diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go new file mode 100644 index 00000000000..4ea19be1324 --- /dev/null +++ b/internal/service/appflow/connector_profile_test.go @@ -0,0 +1,627 @@ +package appflow_test + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appflow" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfappflow "github.com/hashicorp/terraform-provider-aws/internal/service/appflow" +) + +func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appflow_connector_profile.amplitude" + connectorType := "Amplitude" + + apiKey := os.Getenv("AMPLITUDE_API_KEY") + secretKey := os.Getenv("AMPLITUDE_SECRET_KEY") + + if apiKey == "" || secretKey == "" { + t.Skip("All environment variables: AMPLITUDE_API_KEY, AMPLITUDE_SECRET_KEY must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName, apiKey, secretKey), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Amplitude"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.0.api_key", apiKey), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.0.secret_key", secretKey), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.amplitude.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.datadog" + connectorType := "Datadog" + + apiKey := os.Getenv("DATADOG_API_KEY") + applicationKey := os.Getenv("DATADOG_APPLICATION_KEY") + instanceUrl := os.Getenv("DATADOG_INSTANCE_URL") + + if apiKey == "" || applicationKey == "" || instanceUrl == "" { + t.Skip("All environment variables: DATADOG_API_KEY, DATADOG_APPLICATION_KEY, DATADOG_INSTANCE_URL must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName, apiKey, applicationKey, instanceUrl), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Datadog"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.0.api_key", apiKey), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.0.application_key", applicationKey), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.0.instance_url", instanceUrl), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.dynatrace" + connectorType := "Dynatrace" + + apiToken := os.Getenv("DYNATRACE_API_TOKEN") + instanceUrl := os.Getenv("DYNATRACE_INSTANCE_URL") + + if apiToken == "" || instanceUrl == "" { + t.Skip("All environment variables: DYNATRACE_API_TOKEN, DYNATRACE_INSTANCE_URL must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName, apiToken, instanceUrl), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Dynatrace"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.dynatrace.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.dynatrace.0.api_token", apiToken), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.0.instance_url", instanceUrl), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.slack" + connectorType := "Slack" + + clientId := os.Getenv("SLACK_CLIENT_ID") + clientSecret := os.Getenv("SLACK_CLIENT_SECRET") + accessToken := os.Getenv("SLACK_ACCESS_TOKEN") + instanceUrl := os.Getenv("SLACK_INSTANCE_URL") + + if clientId == "" || clientSecret == "" || accessToken == "" || instanceUrl == "" { + t.Skip("All environment variables: SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_ACCESS_TOKEN, SLACK_INSTANCE_URL must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Slack(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Slack"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.access_token", accessToken), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.client_id", clientId), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.client_secret", clientSecret), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.oauth_request.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.oauth_request.0.redirect_uri"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.0.instance_url", instanceUrl), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.snowflake" + connectorType := "Snowflake" + + password := os.Getenv("SNOWFLAKE_PASSWORD") + username := os.Getenv("SNOWFLAKE_USERNAME") + accountName := os.Getenv("SNOWFLAKE_ACCOUNT_NAME") + bucketName := connectorProfileName + region := os.Getenv("SNOWFLAKE_REGION") + stage := os.Getenv("SNOWFLAKE_STAGE") + warehouse := os.Getenv("SNOWFLAKE_WAREHOUSE") + + if password == "" || username == "" || accountName == "" || region == "" || stage == "" || warehouse == "" { + t.Skip("All environment variables: SNOWFLAKE_PASSWORD, SNOWFLAKE_USERNAME, SNOWFLAKE_ACCOUNT_NAME, SNOWFLAKE_REGION, SNOWFLAKE_STAGE, SNOWFLAKE_WAREHOUSE must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Snowflake(connectorProfileName, password, username, accountName, bucketName, region, stage, warehouse), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Snowflake"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.0.password", password), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.0.username", username), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.account_name", accountName), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.bucket_name", bucketName), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.region", region), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.stage"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.warehouse", warehouse), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.trendmicro" + connectorType := "Trendmicro" + + apiSecretKey := os.Getenv("TRENDMICRO_API_SECRET_KEY") + + if apiSecretKey == "" { + t.Skip("All environment variables: TRENDMICRO_API_SECRET_KEY must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName, apiSecretKey), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Trendmicro"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.0.api_secret_key", apiSecretKey), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") + resourceName := "aws_appflow_connector_profile.zendesk" + connectorType := "Zendesk" + + clientId := os.Getenv("ZENDESK_CLIENT_ID") + clientSecret := os.Getenv("ZENDESK_CLIENT_SECRET") + accessToken := os.Getenv("ZENDESK_ACCESS_TOKEN") + instanceUrl := os.Getenv("ZENDESK_INSTANCE_URL") + + if clientId == "" || clientSecret == "" || accessToken == "" || instanceUrl == "" { + t.Skip("All environment variables: ZENDESK_CLIENT_ID, ZENDESK_CLIENT_SECRET, ZENDESK_ACCESS_TOKEN, ZENDESK_INSTANCE_URL must be set.") + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppFlowConnectorProfile_Zendesk(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), + acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), + resource.TestCheckResourceAttr(resourceName, "connector_type", "Zendesk"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.access_token", accessToken), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.client_id", clientId), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.client_secret", clientSecret), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.oauth_request.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.oauth_request.0.redirect_uri"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.#", "1"), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.0.instance_url", instanceUrl), + resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttrSet(resourceName, "created_at"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + +func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appflow_connector_profile" { + continue + } + + output, err := tfappflow.GetConnectorProfile(conn, rs.Primary.ID) + + if tfawserr.ErrMessageContains(err, appflow.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppFlow Connector profile (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAWSAppFlowConnectorProfileExists(n string, connectorType string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn + + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + req := &appflow.DescribeConnectorProfilesInput{ + ConnectorProfileNames: []*string{aws.String(rs.Primary.Attributes["connector_profile_name"])}, + ConnectorType: aws.String(connectorType), + } + describe, err := conn.DescribeConnectorProfiles(req) + + if len(describe.ConnectorProfileDetails) == 0 { + return fmt.Errorf("AppFlow Connector profile %s does not exist.", n) + } + + if err != nil { + return err + } + + *res = *describe + + return nil + } +} + +func testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName string, apiKey string, secretKey string) string { + return fmt.Sprintf(` +resource "aws_appflow_connector_profile" "amplitude" { + connector_profile_name = %[1]q + connector_type = "Amplitude" + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + amplitude { + api_key = %[2]q + secret_key = %[3]q + } + } + connector_profile_properties { + amplitude { + } + } + } + +} +`, connectorProfileName, apiKey, secretKey) +} + +func testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName string, apiKey string, applicationKey string, instanceUrl string) string { + return fmt.Sprintf(` +resource "aws_appflow_connector_profile" "datadog" { + connector_profile_name = %[1]q + connector_type = "Datadog" + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + datadog { + api_key = %[2]q + application_key = %[3]q + } + } + connector_profile_properties { + datadog { + instance_url = %[4]q + } + } + } + +} +`, connectorProfileName, apiKey, applicationKey, instanceUrl) +} + +func testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName string, apiToken string, instanceUrl string) string { + return fmt.Sprintf(` +resource "aws_appflow_connector_profile" "dynatrace" { + connector_profile_name = %[1]q + connector_type = "Dynatrace" + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + dynatrace { + api_token = %[2]q + } + } + connector_profile_properties { + dynatrace { + instance_url = %[3]q + } + } + } + +} +`, connectorProfileName, apiToken, instanceUrl) +} + +func testAccAWSAppFlowConnectorProfile_Slack(connectorProfileName string, clientId string, clientSecret string, accessToken string, instanceUrl string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_appflow_connector_profile" "slack" { + connection_mode = "Public" + connector_profile_name = %[1]q + connector_type = "Slack" + connector_profile_config { + connector_profile_credentials { + slack { + client_id = %[2]q + client_secret = %[3]q + access_token = %[4]q + oauth_request { + redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" + } + } + } + connector_profile_properties { + slack { + instance_url = %[5]q + } + } + } +} +`, connectorProfileName, clientId, clientSecret, accessToken, instanceUrl) +} + +func testAccAWSAppFlowConnectorProfile_Snowflake(connectorProfileName string, password string, username string, accountName string, bucketName string, region string, stage string, warehouse string) string { + + return fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_s3_bucket" "snowflake" { + bucket = %[1]q + acl = "private" +} + +resource "aws_appflow_connector_profile" "snowflake" { + connector_profile_name = %[2]q + connector_type = "Snowflake" + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + snowflake { + password = %[3]q + username = %[4]q + } + } + connector_profile_properties { + snowflake { + account_name = %[5]q + bucket_name = aws_s3_bucket.snowflake.id + region = %[6]q + stage = %[7]q + warehouse = %[8]q + } + } + } + +} +`, bucketName, connectorProfileName, password, username, accountName, region, stage, warehouse) +} + +func testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName string, apiSecretKey string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_appflow_connector_profile" "trendmicro" { + connector_profile_name = %[1]q + connector_type = "Trendmicro" + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + trendmicro { + api_secret_key = %[2]q + } + } + connector_profile_properties { + trendmicro { + } + } + } + +} +`, connectorProfileName, apiSecretKey) +} + +func testAccAWSAppFlowConnectorProfile_Zendesk(connectorProfileName string, clientId string, clientSecret string, accessToken string, instanceUrl string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_appflow_connector_profile" "zendesk" { + connection_mode = "Public" + connector_profile_name = %[1]q + connector_type = "Zendesk" + connector_profile_config { + connector_profile_credentials { + zendesk { + client_id = %[2]q + client_secret = %[3]q + access_token = %[4]q + oauth_request { + redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" + } + } + } + connector_profile_properties { + zendesk { + instance_url = %[5]q + } + } + } +} +`, connectorProfileName, clientId, clientSecret, accessToken, instanceUrl) +} diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index cf5bc7821f0..827a4c72f33 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -7,6 +7,7 @@ Access Analyzer Account Amplify Console AppConfig +AppFlow AppIntegrations AppMesh App Runner diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown new file mode 100644 index 00000000000..f8a2269403d --- /dev/null +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -0,0 +1,367 @@ +--- +subcategory: "AppFlow" +layout: "aws" +page_title: "AWS: aws_appflow_connector_profile" +description: |- + Provides an AppFlow connector profile resource. +--- + +# Resource: aws_appflow_connector_profile + +Creates an AWS AppFlow connector profile. + +For information about AppFlow flows, see the +[Amazon AppFlow API Reference][1]. For specific information about creating +AppFlow connector profile, see the [CreateConnectorProfile][2] page in the Amazon +AppFlow API Reference. + +## Example Usage + +### Amplitude + +```terraform +resource "aws_appflow_connector_profile" "amplitude" { + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + amplitude { + api_key = "0123456789abcdef0123456789abcdef" + secret_key = "0123456789abcdef0123456789abcdef" + } + } + connector_profile_properties { + amplitude { + } + } + } + connector_profile_name = "amplitude-connector" + connector_type = "Amplitude" +} +``` + +### Zendesk + +```terraform +data "aws_region" "current" {} + +resource "aws_appflow_connector_profile" "zendesk" { + connection_mode = "Public" + connector_profile_config { + connector_profile_credentials { + zendesk { + client_id = "zendesk-client-id" + client_secret = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + access_token = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + oauth_request { + redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" + } + } + } + connector_profile_properties { + zendesk { + instance_url = "https://subdomain.zendesk.com" + } + } + } + connector_profile_name = "zendesk-connector" + connector_type = "Zendesk" +} +``` + +## Argument Reference + +The AppFlow connector profile argument layout is a complex structure. + +### Top-Level Arguments + +* `connection_mode` (Required) - Indicates the connection mode and specifies whether it is public or private. Private flows use AWS PrivateLink to route data over AWS infrastructure without exposing it to the public internet. One of: `Public`, `Private`. + +* `connector_profile_config` (Required) - Defines the connector-specific [configuration and credentials](#connector-profile-config-arguments). + +* `connector_profile_name ` (Required) - The name of the connector profile. The name is unique for each ConnectorProfile in your AWS account. + +* `connector_type` (Required) - The type of connector. One of: `Amplitude`, `Datadog`, `Dynatrace`, `Googleanalytics`, `Honeycode`, `Infornexus`, `Marketo`, `Redshift`, `Salesforce`, `Servicenow`, `Singular`, `Slack`, `Snowflake`, `Trendmicro`, `Veeva`, `Zendesk`. + +* `kms_arn` (Optional) - The ARN (Amazon Resource Name) of the Key Management Service (KMS) key you provide for encryption. This is required if you do not want to use the Amazon AppFlow-managed KMS key. If you don't provide anything here, Amazon AppFlow uses the Amazon AppFlow-managed KMS key. + +#### Connector Profile Config Arguments + +* `connector_profile_credentials` (Required) - The connector-specific [credentials](#connector-profile-credentials-arguments) required by each connector. + +* `connector_profile_properties` (Required) - The connector-specific [properties](#connector-profile-properties-arguments) of the profile configuration. + + +##### Connector Profile Credentials Arguments + +* `amplitude` (Optional) - The connector-specific [credentials](#amplitude-connector-profile-credentials-arguments) required when using Amplitude. + +* `datadog` (Optional) - The connector-specific [credentials](#datadog-connector-profile-credentials-arguments) required when using Datadog. + +* `dynatrace` (Optional) - The connector-specific [credentials](#dynatrace-connector-profile-credentials-arguments) required when using Dynatrace. + +* `google_analytics` (Optional) - The connector-specific [credentials](#google-analytics-connector-profile-credentials-arguments) required when using Google Analytics. + +* `honeycode` (Optional) - The connector-specific [credentials](#honeycode-connector-profile-credentials-arguments) required when using Amazon Honeycode. + +* `infor_nexus` (Optional) - The connector-specific [credentials](#infor-nexus-connector-profile-credentials-arguments) required when using Infor Nexus. + +* `marketo` (Optional) - The connector-specific [credentials](#marketo-connector-profile-credentials-arguments) required when using Marketo. + +* `redshift` (Optional) - The connector-specific [credentials](#redshift-connector-profile-credentials-arguments) required when using Amazon Redshift. + +* `salesforce` (Optional) - The connector-specific [credentials](#salesforce-connector-profile-credentials-arguments) required when using Salesforce. + +* `service_now` (Optional) - The connector-specific [credentials](#servicenow-connector-profile-credentials-arguments) required when using ServiceNow. + +* `singular` (Optional) - The connector-specific [credentials](#singular-connector-profile-credentials-arguments) required when using Singular. + +* `slack` (Optional) - The connector-specific [credentials](#slack-connector-profile-credentials-arguments) required when using Slack. + +* `snowflake` (Optional) - The connector-specific [credentials](#snowflake-connector-profile-credentials-arguments) required when using Snowflake. + +* `trendmicro` (Optional) - The connector-specific [credentials](#trendmicro-connector-profile-credentials-arguments) required when using Trend Micro. + +* `veeva` (Optional) - The connector-specific [credentials](#veeva-connector-profile-credentials-arguments) required when using Veeva. + +* `zendesk` (Optional) - The connector-specific [credentials](#zendesk-connector-profile-credentials-arguments) required when using Zendesk. + +##### Amplitude Connector Profile Credentials Arguments + +* `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. + +* `secret_key` (Required) - The Secret Access Key portion of the credentials. + +##### Datadog Connector Profile Credentials Arguments + +* `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. + +* `application_key` (Required) - Application keys, in conjunction with your API key, give you full access to Datadog’s programmatic API. Application keys are associated with the user account that created them. The application key is used to log all requests made to the API. + +##### Dynatrace Connector Profile Credentials Arguments + +* `api_token` (Required) - The API tokens used by Dynatrace API to authenticate various API calls. + +##### Google Analytics Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Google Analytics resources. + +* `client_id` (Required) - The identifier for the desired client. + +* `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. + +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. + +* `refresh_token` (Optional) - The credentials used to acquire new access tokens. This is required only for OAuth2 access tokens, and is not required for OAuth1 access tokens. + +##### Honeycode Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Amazon Honeycode resources. + +* `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported, such as Salesforce, Google Analytics, Marketo, Zendesk, and Slack. + +* `refresh_token` (Optional) - The credentials used to acquire new access tokens. + +##### Infor Nexus Connector Profile Credentials Arguments + +* `access_key_id` (Required) - The Access Key portion of the credentials. + +* `datakey` (Required) - The encryption keys used to encrypt data. + +* `secret_access_key` (Required) - The secret key used to sign requests. + +* `user_id` (Required) - The identifier for the user. + +##### Marketo Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Marketo resources. + +* `client_id` (Required) - The identifier for the desired client. + +* `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. + +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. + +##### Redshift Connector Profile Credentials Arguments + +* `password` (Required) - The password that corresponds to the user name. + +* `username` (Required) - The name of the user. + +##### Salesforce Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Salesforce resources. + +* `client_credentials_arn` (Optional) - The secret manager ARN, which contains the client ID and client secret of the connected app. + +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. + +* `refresh_token` (Optional) - The credentials used to acquire new access tokens. + +##### ServiceNow Connector Profile Credentials Arguments + +* `password` (Required) - The password that corresponds to the user name. + +* `username` (Required) - The name of the user. + +##### Singular Connector Profile Credentials Arguments + +* `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. + +##### Slack Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Slack resources. + +* `client_id` (Required) - The identifier for the client. + +* `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. + +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. + +##### Snowflake Connector Profile Credentials Arguments + +* `password` (Required) - The password that corresponds to the user name. + +* `username` (Required) - The name of the user. + +##### Trendmicro Connector Profile Credentials Arguments + +* `api_secret_key` (Required) - The Secret Access Key portion of the credentials. + +##### Veeva Connector Profile Credentials Arguments + +* `password` (Required) - The password that corresponds to the user name. + +* `username` (Required) - The name of the user. + +##### Zendesk Connector Profile Credentials Arguments + +* `access_token` (Optional) - The credentials used to access protected Zendesk resources. + +* `client_id` (Required) - The identifier for the desired client. + +* `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. + +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. + +##### Connector Profile Properties Arguments + +* `amplitude` (Optional) - The connector-specific [properties](#amplitude-connector-profile-properties-arguments) required by Amplitude. Configure as an empty block `{}`. + +* `datadog` (Optional) - The connector-specific [properties](#datadog-connector-profile-properties-arguments) required by Datadog. + +* `dynatrace` (Optional) - The connector-specific [properties](#dynatrace-connector-profile-properties-arguments) required by Dynatrace. + +* `google_analytics` (Optional) - The connector-specific [properties](#google-connector-profile-properties-arguments) required by Google Analytics. Configure as an empty block `{}`. + +* `honeycode` (Optional) - The connector-specific [properties](#honeycode-connector-profile-properties-arguments) required by Amazon Honeycode. Configure as an empty block `{}`. + +* `infor_nexus` (Optional) - The connector-specific [properties](#infor-connector-profile-properties-arguments) required by Infor Nexus. + +* `marketo` (Optional) - The connector-specific [properties](#marketo-connector-profile-properties-arguments) required by Marketo. + +* `redshift` (Optional) - The connector-specific [properties](#redshift-connector-profile-properties-arguments) required by Amazon Redshift. + +* `salesforce` (Optional) - The connector-specific [properties](#salesforce-connector-profile-properties-arguments) required by Salesforce. + +* `service_now` (Optional) - The connector-specific [properties](#servicenow-connector-profile-properties-arguments) required by ServiceNow. + +* `singular` (Optional) - The connector-specific [properties](#singular-connector-profile-properties-arguments) required by Singular. Configure as an empty block `{}`. + +* `slack` (Optional) - The connector-specific [properties](#slack-connector-profile-properties-arguments) required by Slack. + +* `snowflake` (Optional) - The connector-specific [properties](#snowflake-connector-profile-properties-arguments) required by Snowflake. + +* `trendmicro` (Optional) - The connector-specific [properties](#trendmicro-connector-profile-properties-arguments) required by Trend Micro. Configure as an empty block `{}`. + +* `veeva` (Optional) - The connector-specific [properties](#veeva-connector-profile-properties-arguments) required by Veeva. + +* `zendesk` (Optional) - The connector-specific [properties](#zendesk-connector-profile-properties-arguments) required by Zendesk. + +##### Datadog Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Datadog resource. + +##### Dynatrace Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Dynatrace resource. + +##### Infor Nexus Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Infor Nexus resource. + +##### Marketo Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Marketo resource. + +##### Redshift Connector Profile Properties Arguments + +* `bucket_name` (Required) - A name for the associated Amazon S3 bucket. + +* `bucket_prefix` (Optional) - The object key for the destination bucket in which Amazon AppFlow places the files. + +* `database_url` (Required) - The JDBC URL of the Amazon Redshift cluster. + +* `role_arn` (Required) - The Amazon Resource Name (ARN) of the IAM role. + +##### Salesforce Connector Profile Properties Arguments + +* `instance_url` (Optional) - The location of the Salesforce resource. + +* `is_sandbox_environment` (Optional) - Indicates whether the connector profile applies to a sandbox or production environment. + +##### ServiceNow Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the ServiceNow resource. + +##### Slack Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Slack resource. + +##### Snowflake Connector Profile Properties Arguments + +* `account_name` (Optional) - The name of the account. + +* `bucket_name` (Required) - The name of the Amazon S3 bucket associated with Snowflake. + +* `bucket_prefix` (Optional) - The bucket path that refers to the Amazon S3 bucket associated with Snowflake. + +* `private_link_service_name` (Optional) - The Snowflake Private Link service name to be used for private data transfers. + +* `region` (Optional) - The AWS Region of the Snowflake account. + +* `stage` (Required) - The name of the Amazon S3 stage that was created while setting up an Amazon S3 stage in the Snowflake account. This is written in the following format: `..`. + +* `warehouse` (Required) - The name of the Snowflake warehouse. + +##### Veeva Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Veeva resource. + +##### Zendesk Connector Profile Properties Arguments + +* `instance_url` (Required) - The location of the Zendesk resource. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `credentials_arn` - The Amazon Resource Name (ARN) of the connector profile credentials. + +* `connector_profile_arn` - The Amazon Resource Name (ARN) of the connector profile. + +* `created_at` - Specifies when the connector profile was created. + +* `last_updated_at` - Specifies when the connector profile was last updated. + + +## Import + +AppFlow Connector Profile can be imported using the connector profile name, e.g. + +``` +$ terraform import aws_appflow_connector_profile.profile connector-profile-name +``` + +[1]: https://docs.aws.amazon.com/appflow/1.0/APIReference/Welcome.html +[2]: https://docs.aws.amazon.com/appflow/1.0/APIReference/API_CreateConnectorProfile.html + From 0d98d1cd3a589a840e698b68816e8dca3fa94c37 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 16:45:19 -0500 Subject: [PATCH 02/59] Remove timestamp attributes Generally, we omit creation + modification times --- internal/service/appflow/connector_profile.go | 11 ----------- internal/service/appflow/connector_profile_test.go | 14 -------------- 2 files changed, 25 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index e7b0940cd8b..7dec40412e1 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -3,7 +3,6 @@ package appflow import ( "fmt" "regexp" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" @@ -903,10 +902,6 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appflow.ConnectorType_Values(), false), }, - "created_at": { - Type: schema.TypeString, - Computed: true, - }, "kms_arn": { Type: schema.TypeString, Optional: true, @@ -914,10 +909,6 @@ func ResourceConnectorProfile() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, - "last_updated_at": { - Type: schema.TypeString, - Computed: true, - }, }, } } @@ -964,8 +955,6 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro d.Set("connector_profile_name", connectorProfile.ConnectorProfileName) d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) d.Set("connector_type", connectorProfile.ConnectorType) - d.Set("created_at", aws.TimeValue(connectorProfile.CreatedAt).Format(time.RFC3339)) - d.Set("last_updated_at", aws.TimeValue(connectorProfile.LastUpdatedAt).Format(time.RFC3339)) d.SetId(d.Get("connector_profile_name").(string)) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 4ea19be1324..4c5f6e0f67a 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -51,8 +51,6 @@ func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.amplitude.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -102,8 +100,6 @@ func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.0.instance_url", instanceUrl), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -151,8 +147,6 @@ func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.0.instance_url", instanceUrl), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -206,8 +200,6 @@ func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.0.instance_url", instanceUrl), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -265,8 +257,6 @@ func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.stage"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.warehouse", warehouse), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -311,8 +301,6 @@ func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.0.api_secret_key", apiSecretKey), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { @@ -366,8 +354,6 @@ func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.0.instance_url", instanceUrl), resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), - resource.TestCheckResourceAttrSet(resourceName, "created_at"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_at"), ), }, { From 57a906c33ecf105ae1107862e12439ec52550d2a Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 17:32:56 -0500 Subject: [PATCH 03/59] Amend maximum length for some attributes --- internal/service/appflow/connector_profile.go | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 7dec40412e1..0da1523315c 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -114,7 +114,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -143,7 +143,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -162,7 +162,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 1024), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -178,7 +178,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -191,7 +191,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -210,7 +210,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 1024), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -266,7 +266,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -343,7 +343,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -361,7 +361,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -380,7 +380,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 1024), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -433,7 +433,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -462,7 +462,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -548,7 +548,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, @@ -579,7 +579,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 512), + validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), ), }, From d08ceae65ff8fa4c63889f82b4255913201b680c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 17:55:41 -0500 Subject: [PATCH 04/59] Add MaxItems: 1 to all TypeList items corresponding to an AWS struct --- internal/service/appflow/connector_profile.go | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 0da1523315c..e1ec8019be5 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -34,16 +34,19 @@ func ResourceConnectorProfile() *schema.Resource { "connector_profile_config": { Type: schema.TypeList, Required: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "connector_profile_credentials": { Type: schema.TypeList, Required: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "amplitude": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_key": { @@ -68,6 +71,7 @@ func ResourceConnectorProfile() *schema.Resource { "datadog": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_key": { @@ -92,6 +96,7 @@ func ResourceConnectorProfile() *schema.Resource { "dynatrace": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_token": { @@ -108,6 +113,7 @@ func ResourceConnectorProfile() *schema.Resource { "google_analytics": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -137,6 +143,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -172,6 +179,7 @@ func ResourceConnectorProfile() *schema.Resource { "honeycode": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -185,6 +193,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -220,6 +229,7 @@ func ResourceConnectorProfile() *schema.Resource { "infor_nexus": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_key_id": { @@ -260,6 +270,7 @@ func ResourceConnectorProfile() *schema.Resource { "marketo": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -289,6 +300,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -316,6 +328,7 @@ func ResourceConnectorProfile() *schema.Resource { "redshift": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "password": { @@ -337,6 +350,7 @@ func ResourceConnectorProfile() *schema.Resource { "salesforce": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -355,6 +369,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -390,6 +405,7 @@ func ResourceConnectorProfile() *schema.Resource { "service_now": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "password": { @@ -411,6 +427,7 @@ func ResourceConnectorProfile() *schema.Resource { "singular": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_key": { @@ -427,6 +444,7 @@ func ResourceConnectorProfile() *schema.Resource { "slack": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -456,6 +474,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -483,6 +502,7 @@ func ResourceConnectorProfile() *schema.Resource { "snowflake": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "password": { @@ -504,6 +524,7 @@ func ResourceConnectorProfile() *schema.Resource { "trendmicro": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_secret_key": { @@ -520,6 +541,7 @@ func ResourceConnectorProfile() *schema.Resource { "veeva": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "password": { @@ -541,6 +563,7 @@ func ResourceConnectorProfile() *schema.Resource { "zendesk": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { @@ -572,6 +595,7 @@ func ResourceConnectorProfile() *schema.Resource { "oauth_request": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { @@ -603,11 +627,13 @@ func ResourceConnectorProfile() *schema.Resource { "connector_profile_properties": { Type: schema.TypeList, Required: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "amplitude": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{}, }, @@ -615,6 +641,7 @@ func ResourceConnectorProfile() *schema.Resource { "datadog": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -631,6 +658,7 @@ func ResourceConnectorProfile() *schema.Resource { "dynatrace": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -647,6 +675,7 @@ func ResourceConnectorProfile() *schema.Resource { "google_analytics": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{}, }, @@ -654,6 +683,7 @@ func ResourceConnectorProfile() *schema.Resource { "honeycode": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{}, }, @@ -661,6 +691,7 @@ func ResourceConnectorProfile() *schema.Resource { "infor_nexus": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -677,6 +708,7 @@ func ResourceConnectorProfile() *schema.Resource { "marketo": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -693,6 +725,7 @@ func ResourceConnectorProfile() *schema.Resource { "redshift": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "bucket_name": { @@ -724,6 +757,7 @@ func ResourceConnectorProfile() *schema.Resource { "salesforce": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -744,6 +778,7 @@ func ResourceConnectorProfile() *schema.Resource { "service_now": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -760,6 +795,7 @@ func ResourceConnectorProfile() *schema.Resource { "singular": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{}, }, @@ -767,6 +803,7 @@ func ResourceConnectorProfile() *schema.Resource { "slack": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -783,6 +820,7 @@ func ResourceConnectorProfile() *schema.Resource { "snowflake": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "account_name": { @@ -847,6 +885,7 @@ func ResourceConnectorProfile() *schema.Resource { "trendmicro": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{}, }, @@ -854,6 +893,7 @@ func ResourceConnectorProfile() *schema.Resource { "veeva": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { @@ -870,6 +910,7 @@ func ResourceConnectorProfile() *schema.Resource { "zendesk": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_url": { From 92bee49822c082b0e5c9462326fddbaee77767c6 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 18:00:56 -0500 Subject: [PATCH 05/59] Mark passwords + access codes as Sensitive --- internal/service/appflow/connector_profile.go | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index e1ec8019be5..9e321d44367 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -58,8 +58,9 @@ func ResourceConnectorProfile() *schema.Resource { ), }, "secret_key": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -117,8 +118,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -133,8 +135,9 @@ func ResourceConnectorProfile() *schema.Resource { ), }, "client_secret": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -183,8 +186,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -249,8 +253,9 @@ func ResourceConnectorProfile() *schema.Resource { ), }, "secret_access_key": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -274,8 +279,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -290,8 +296,9 @@ func ResourceConnectorProfile() *schema.Resource { ), }, "client_secret": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -334,6 +341,7 @@ func ResourceConnectorProfile() *schema.Resource { "password": { Type: schema.TypeString, Required: true, + Sensitive: true, ValidateFunc: validation.StringLenBetween(0, 512), }, "username": { @@ -354,8 +362,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -411,6 +420,7 @@ func ResourceConnectorProfile() *schema.Resource { "password": { Type: schema.TypeString, Required: true, + Sensitive: true, ValidateFunc: validation.StringLenBetween(0, 512), }, "username": { @@ -448,8 +458,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "access_token": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -464,8 +475,9 @@ func ResourceConnectorProfile() *schema.Resource { ), }, "client_secret": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -508,6 +520,7 @@ func ResourceConnectorProfile() *schema.Resource { "password": { Type: schema.TypeString, Required: true, + Sensitive: true, ValidateFunc: validation.StringLenBetween(0, 512), }, "username": { @@ -528,8 +541,9 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_secret_key": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), @@ -547,6 +561,7 @@ func ResourceConnectorProfile() *schema.Resource { "password": { Type: schema.TypeString, Required: true, + Sensitive: true, ValidateFunc: validation.StringLenBetween(0, 512), }, "username": { @@ -599,9 +614,8 @@ func ResourceConnectorProfile() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "auth_code": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, + Type: schema.TypeString, + Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), From 8603da4c78b74847d827d99ff9a4fc4acbcbaded Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 18:10:45 -0500 Subject: [PATCH 06/59] Add more detailed validation errors --- internal/service/appflow/connector_profile.go | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 9e321d44367..be109803a89 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -54,7 +54,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "secret_key": { @@ -63,7 +63,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -80,7 +80,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "application_key": { @@ -88,7 +88,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -105,7 +105,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -123,7 +123,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_id": { @@ -131,7 +131,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_secret": { @@ -140,7 +140,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "oauth_request": { @@ -154,7 +154,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -162,7 +162,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -173,7 +173,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 1024), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -191,7 +191,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "oauth_request": { @@ -205,7 +205,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -213,7 +213,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -224,7 +224,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 1024), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -241,7 +241,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "datakey": { @@ -249,7 +249,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "secret_access_key": { @@ -258,7 +258,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "user_id": { @@ -266,7 +266,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -284,7 +284,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_id": { @@ -292,7 +292,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_secret": { @@ -301,7 +301,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "oauth_request": { @@ -315,7 +315,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -323,7 +323,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -349,7 +349,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -367,7 +367,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_credentials_arn": { @@ -386,7 +386,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -394,7 +394,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -405,7 +405,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 1024), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -428,7 +428,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -445,7 +445,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -463,7 +463,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_id": { @@ -471,7 +471,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_secret": { @@ -480,7 +480,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "oauth_request": { @@ -494,7 +494,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -502,7 +502,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -528,7 +528,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -546,7 +546,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -569,7 +569,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -587,7 +587,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_id": { @@ -595,7 +595,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "client_secret": { @@ -604,7 +604,7 @@ func ResourceConnectorProfile() *schema.Resource { Sensitive: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "oauth_request": { @@ -618,7 +618,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 2048), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "redirect_uri": { @@ -626,7 +626,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -663,7 +663,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -680,7 +680,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -713,7 +713,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -730,7 +730,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -747,7 +747,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(3, 63), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "bucket_prefix": { @@ -779,7 +779,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "is_sandbox_environment": { @@ -800,7 +800,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -825,7 +825,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -842,7 +842,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "bucket_name": { @@ -850,7 +850,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(3, 63), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "bucket_prefix": { @@ -863,7 +863,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "region": { @@ -871,7 +871,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 64), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "stage": { @@ -882,7 +882,7 @@ func ResourceConnectorProfile() *schema.Resource { }, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, "warehouse": { @@ -915,7 +915,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, @@ -932,7 +932,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`\S+`), "must match \\S+"), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), ), }, }, From ac24482b2ec40abc09d68a6bb786e24ffae34230 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 18:29:34 -0500 Subject: [PATCH 07/59] Add more precise validation for Snowflake private link service name --- internal/service/appflow/connector_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index be109803a89..9ae4728fc01 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -863,7 +863,7 @@ func ResourceConnectorProfile() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 512), - validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + validation.StringMatch(regexp.MustCompile(`^$|com.amazonaws.vpce.[\w/!:@#.\-]+`), "must be a valid AWS VPC endpoint address"), ), }, "region": { From f90533747a785b90e5cee2928bf5ce8bd4f90240 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 22:41:48 -0500 Subject: [PATCH 08/59] Add expandRedshiftConnectorProfileCredentials function --- internal/service/appflow/connector_profile.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 9ae4728fc01..70cdee34eb7 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1094,6 +1094,9 @@ func expandConnectorProfileCredentials(m map[string]interface{}) *appflow.Connec if v, ok := m["marketo"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.Marketo = expandMarketoConnectorProfileCredentials(v[0].(map[string]interface{})) } + if v, ok := m["redshift"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.Redshift = expandRedshiftConnectorProfileCredentials(v[0].(map[string]interface{})) + } if v, ok := m["salesforce"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.Salesforce = expandSalesforceConnectorProfileCredentials(v[0].(map[string]interface{})) } @@ -1215,6 +1218,15 @@ func expandMarketoConnectorProfileCredentials(m map[string]interface{}) *appflow return &credentials } +func expandRedshiftConnectorProfileCredentials(m map[string]interface{}) *appflow.RedshiftConnectorProfileCredentials { + credentials := appflow.RedshiftConnectorProfileCredentials{ + Password: aws.String(m["password"].(string)), + Username: aws.String(m["username"].(string)), + } + + return &credentials +} + func expandSalesforceConnectorProfileCredentials(m map[string]interface{}) *appflow.SalesforceConnectorProfileCredentials { credentials := appflow.SalesforceConnectorProfileCredentials{} From 62aefc1b51ffb39074815e5f9cbc2272a69ab29c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Sun, 8 May 2022 22:46:21 -0500 Subject: [PATCH 09/59] Rename connector_profile_arn -> arn, as preferred for resource arn --- internal/service/appflow/connector_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 70cdee34eb7..3ae37f8918e 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -27,7 +27,7 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appflow.ConnectionMode_Values(), false), }, - "connector_profile_arn": { + "arn": { Type: schema.TypeString, Computed: true, }, From 245a2d3e8b18c0714ffbbccedd725a117427eea4 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Mon, 9 May 2022 00:38:56 -0500 Subject: [PATCH 10/59] Add support for SAPODataConnectorProfile credentials + properties --- internal/service/appflow/connector_profile.go | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 3ae37f8918e..d2a566dc3db 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -411,6 +412,105 @@ func ResourceConnectorProfile() *schema.Resource { }, }, }, + "sapo_data": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "basic_auth_credentials": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + "oauth_credentials": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + }, + }, + }, "service_now": { Type: schema.TypeList, Optional: true, @@ -789,6 +889,96 @@ func ResourceConnectorProfile() *schema.Resource { }, }, }, + "sapo_data": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "application_host_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]`), "must provide a valid HTTPS url"), + ), + }, + "application_service_path": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "client_number": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(3, 3), + validation.StringMatch(regexp.MustCompile(`^\d{3}$`), "must consist of exactly three digits"), + ), + }, + "logon_language": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 2), + validation.StringMatch(regexp.MustCompile(` ^[a-zA-Z0-9_]*$`), "must contain only alphanumeric characters and the underscore (_) character"), + ), + }, + "oauth_properties": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]`), "must provide a valid HTTPS url"), + ), + }, + "oauth_scopes": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + "token_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]`), "must provide a valid HTTPS url"), + ), + }, + }, + }, + }, + "port_number": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 65535), + }, + "private_link_service_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`^$|com.amazonaws.vpce.[\w/!:@#.\-]+`), "must be a valid AWS VPC endpoint address"), + ), + }, + }, + }, + }, "service_now": { Type: schema.TypeList, Optional: true, @@ -1100,6 +1290,9 @@ func expandConnectorProfileCredentials(m map[string]interface{}) *appflow.Connec if v, ok := m["salesforce"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.Salesforce = expandSalesforceConnectorProfileCredentials(v[0].(map[string]interface{})) } + if v, ok := m["sapo_data"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.SAPOData = expandSAPODataConnectorProfileCredentials(v[0].(map[string]interface{})) + } if v, ok := m["service_now"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.ServiceNow = expandServiceNowConnectorProfileCredentials(v[0].(map[string]interface{})) } @@ -1249,6 +1442,20 @@ func expandSalesforceConnectorProfileCredentials(m map[string]interface{}) *appf return &credentials } +func expandSAPODataConnectorProfileCredentials(m map[string]interface{}) *appflow.SAPODataConnectorProfileCredentials { + credentials := appflow.SAPODataConnectorProfileCredentials{} + + if v, ok := m["basic_auth_credentials"].([]interface{}); ok && len(v) > 0 { + credentials.BasicAuthCredentials = expandBasicAuthCredentials(v[0].(map[string]interface{})) + } + + if v, ok := m["oauth_credentials"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthCredentials = expandOAuthCredentials(v[0].(map[string]interface{})) + } + + return &credentials +} + func expandServiceNowConnectorProfileCredentials(m map[string]interface{}) *appflow.ServiceNowConnectorProfileCredentials { credentials := appflow.ServiceNowConnectorProfileCredentials{ Password: aws.String(m["password"].(string)), @@ -1334,6 +1541,41 @@ func expandOAuthRequest(m map[string]interface{}) *appflow.ConnectorOAuthRequest return &r } +func expandBasicAuthCredentials(m map[string]interface{}) *appflow.BasicAuthCredentials { + credentials := appflow.BasicAuthCredentials{} + + if v, ok := m["password"].(string); ok && v != "" { + credentials.Password = aws.String(v) + } + + if v, ok := m["username"].(string); ok && v != "" { + credentials.Username = aws.String(v) + } + + return &credentials +} + +func expandOAuthCredentials(m map[string]interface{}) *appflow.OAuthCredentials { + credentials := appflow.OAuthCredentials{ + ClientId: aws.String(m["client_id"].(string)), + ClientSecret: aws.String(m["client_secret"].(string)), + } + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + if v, ok := m["refresh_token"].(string); ok && v != "" { + credentials.RefreshToken = aws.String(v) + } + + return &credentials +} + func expandConnectorProfileProperties(m map[string]interface{}) *appflow.ConnectorProfileProperties { cpc := appflow.ConnectorProfileProperties{} @@ -1373,6 +1615,10 @@ func expandConnectorProfileProperties(m map[string]interface{}) *appflow.Connect cpc.Salesforce = expandSalesforceConnectorProfileProperties(v[0].(map[string]interface{})) } + if v, ok := m["sapo_data"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.SAPOData = expandSAPODataConnectorProfileProperties(v[0].(map[string]interface{})) + } + if v, ok := m["service_now"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.ServiceNow = expandServiceNowConnectorProfileProperties(v[0].(map[string]interface{})) } @@ -1475,6 +1721,29 @@ func expandSalesforceConnectorProfileProperties(m map[string]interface{}) *appfl return &properties } +func expandSAPODataConnectorProfileProperties(m map[string]interface{}) *appflow.SAPODataConnectorProfileProperties { + properties := appflow.SAPODataConnectorProfileProperties{ + ApplicationHostUrl: aws.String(m["application_host_url"].(string)), + ApplicationServicePath: aws.String(m["application_service_path"].(string)), + ClientNumber: aws.String(m["client_number"].(string)), + PortNumber: aws.Int64(int64(m["port_number"].(int))), + } + + if v, ok := m["logon_language"].(string); ok && v != "" { + properties.LogonLanguage = aws.String(v) + } + + if v, ok := m["oauth_properties"].([]interface{}); ok && len(v) > 0 { + properties.OAuthProperties = expandOAuthProperties(v[0].(map[string]interface{})) + } + + if v, ok := m["private_link_service_name"].(string); ok && v != "" { + properties.PrivateLinkServiceName = aws.String(v) + } + + return &properties +} + func expandSlackConnectorProfileProperties(m map[string]interface{}) *appflow.SlackConnectorProfileProperties { properties := appflow.SlackConnectorProfileProperties{ InstanceUrl: aws.String(m["instance_url"].(string)), @@ -1525,6 +1794,16 @@ func expandZendeskConnectorProfileProperties(m map[string]interface{}) *appflow. return &properties } +func expandOAuthProperties(m map[string]interface{}) *appflow.OAuthProperties { + properties := appflow.OAuthProperties{ + AuthCodeUrl: aws.String(m["auth_code_url"].(string)), + OAuthScopes: flex.ExpandStringList(m["oauth_scopes"].([]interface{})), + TokenUrl: aws.String(m["token_url"].(string)), + } + + return &properties +} + func flattenConnectorProfileConfig(cpp *appflow.ConnectorProfileProperties, cpc []interface{}) []interface{} { m := make(map[string]interface{}) @@ -1572,6 +1851,9 @@ func flattenConnectorProfileProperties(cpp *appflow.ConnectorProfileProperties) if cpp.Redshift != nil { result["redshift"] = flattenRedshiftConnectorProfileProperties(cpp.Redshift) } + if cpp.SAPOData != nil { + result["sapo_data"] = flattenSAPODataConnectorProfileProperties(cpp.SAPOData) + } if cpp.Salesforce != nil { result["salesforce"] = flattenSalesforceConnectorProfileProperties(cpp.Salesforce) } @@ -1642,6 +1924,29 @@ func flattenSalesforceConnectorProfileProperties(properties *appflow.SalesforceC return []interface{}{m} } +func flattenSAPODataConnectorProfileProperties(properties *appflow.SAPODataConnectorProfileProperties) []interface{} { + m := make(map[string]interface{}) + + m["application_host_url"] = aws.StringValue(properties.ApplicationHostUrl) + m["application_service_path"] = aws.StringValue(properties.ApplicationServicePath) + m["client_number"] = aws.StringValue(properties.ClientNumber) + m["port_number"] = aws.Int64Value(properties.PortNumber) + + if properties.LogonLanguage != nil { + m["logon_language"] = aws.StringValue(properties.LogonLanguage) + } + + if properties.OAuthProperties != nil { + m["oauth_properties"] = flattenOAuthProperties(properties.OAuthProperties) + } + + if properties.PrivateLinkServiceName != nil { + m["private_link_service_name"] = aws.StringValue(properties.PrivateLinkServiceName) + } + + return []interface{}{m} +} + func flattenSnowflakeConnectorProfileProperties(properties *appflow.SnowflakeConnectorProfileProperties) []interface{} { m := make(map[string]interface{}) if properties.AccountName != nil { @@ -1663,3 +1968,13 @@ func flattenSnowflakeConnectorProfileProperties(properties *appflow.SnowflakeCon return []interface{}{m} } + +func flattenOAuthProperties(properties *appflow.OAuthProperties) []interface{} { + m := make(map[string]interface{}) + + m["auth_code_url"] = aws.StringValue(properties.AuthCodeUrl) + m["oauth_scopes"] = aws.StringValueSlice(properties.OAuthScopes) + m["token_url"] = aws.StringValue(properties.TokenUrl) + + return []interface{}{m} +} From f22346afa24ece4672363c678b230672f3149360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Mon, 9 May 2022 08:42:52 +0200 Subject: [PATCH 11/59] Remove dead links from markdown --- .../docs/r/appflow_connector_profile.html.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index f8a2269403d..96820239b92 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -245,17 +245,17 @@ The AppFlow connector profile argument layout is a complex structure. ##### Connector Profile Properties Arguments -* `amplitude` (Optional) - The connector-specific [properties](#amplitude-connector-profile-properties-arguments) required by Amplitude. Configure as an empty block `{}`. +* `amplitude` (Optional) - The connector-specific properties required by Amplitude. Configure as an empty block `{}`. * `datadog` (Optional) - The connector-specific [properties](#datadog-connector-profile-properties-arguments) required by Datadog. * `dynatrace` (Optional) - The connector-specific [properties](#dynatrace-connector-profile-properties-arguments) required by Dynatrace. -* `google_analytics` (Optional) - The connector-specific [properties](#google-connector-profile-properties-arguments) required by Google Analytics. Configure as an empty block `{}`. +* `google_analytics` (Optional) - The connector-specific properties required by Google Analytics. Configure as an empty block `{}`. -* `honeycode` (Optional) - The connector-specific [properties](#honeycode-connector-profile-properties-arguments) required by Amazon Honeycode. Configure as an empty block `{}`. +* `honeycode` (Optional) - The connector-specific properties required by Amazon Honeycode. Configure as an empty block `{}`. -* `infor_nexus` (Optional) - The connector-specific [properties](#infor-connector-profile-properties-arguments) required by Infor Nexus. +* `infor_nexus` (Optional) - The connector-specific [properties](#infor-nexus-connector-profile-properties-arguments) required by Infor Nexus. * `marketo` (Optional) - The connector-specific [properties](#marketo-connector-profile-properties-arguments) required by Marketo. @@ -265,13 +265,13 @@ The AppFlow connector profile argument layout is a complex structure. * `service_now` (Optional) - The connector-specific [properties](#servicenow-connector-profile-properties-arguments) required by ServiceNow. -* `singular` (Optional) - The connector-specific [properties](#singular-connector-profile-properties-arguments) required by Singular. Configure as an empty block `{}`. +* `singular` (Optional) - The connector-specific properties required by Singular. Configure as an empty block `{}`. * `slack` (Optional) - The connector-specific [properties](#slack-connector-profile-properties-arguments) required by Slack. * `snowflake` (Optional) - The connector-specific [properties](#snowflake-connector-profile-properties-arguments) required by Snowflake. -* `trendmicro` (Optional) - The connector-specific [properties](#trendmicro-connector-profile-properties-arguments) required by Trend Micro. Configure as an empty block `{}`. +* `trendmicro` (Optional) - The connector-specific properties required by Trend Micro. Configure as an empty block `{}`. * `veeva` (Optional) - The connector-specific [properties](#veeva-connector-profile-properties-arguments) required by Veeva. From 2ab0ec36b808f332f6cdd4ce9077b6157b1b687c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 00:16:35 -0500 Subject: [PATCH 12/59] Add support for CustomConnectorProfile credentials + properties --- internal/service/appflow/connector_profile.go | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index d2a566dc3db..ae530b4559e 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -6,6 +6,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -70,6 +72,164 @@ func ResourceConnectorProfile() *schema.Resource { }, }, }, + "custom_connector": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "api_secret_key": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + "authentication_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appflow.AuthenticationType_Values(), false), + }, + "basic": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "username": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + }, + }, + }, + "custom": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials_map": { + Type: schema.TypeMap, + Optional: true, + Sensitive: true, + MaxItems: 50, + ValidateDiagFunc: allDiagFunc( + validation.MapKeyLenBetween(1, 128), + validation.MapKeyMatch(regexp.MustCompile(`[\w]+`), "must contain only alphanumeric and underscore (_) characters"), + ), + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + "custom_authentication_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + }, + }, + }, + }, + "oauth2": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "client_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "client_secret": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "oauth_request": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auth_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + "redirect_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 512), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + "refresh_token": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + }, + }, + }, "datadog": { Type: schema.TypeList, Optional: true, @@ -752,6 +912,68 @@ func ResourceConnectorProfile() *schema.Resource { Schema: map[string]*schema.Schema{}, }, }, + "custom_connector": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "oauth2_properties": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "oauth2_grant_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appflow.OAuth2GrantType_Values(), false), + }, + "token_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]`), "must provide a valid HTTPS url"), + ), + }, + "token_url_custom_properties": { + Type: schema.TypeMap, + Optional: true, + ValidateDiagFunc: allDiagFunc( + validation.MapKeyLenBetween(1, 128), + validation.MapKeyMatch(regexp.MustCompile(`[\w]+`), "must contain only alphanumeric and underscore (_) characters"), + ), + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + }, + "profile_properties": { + Type: schema.TypeMap, + Optional: true, + MaxItems: 50, + ValidateDiagFunc: allDiagFunc( + validation.MapKeyLenBetween(1, 128), + validation.MapKeyMatch(regexp.MustCompile(`[\w]+`), "must contain only alphanumeric and underscore (_) characters"), + ), + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 2048), + validation.StringMatch(regexp.MustCompile(`\S+`), "must not contain any whitespace characters"), + ), + }, + }, + }, + }, + }, "datadog": { Type: schema.TypeList, Optional: true, @@ -1158,6 +1380,16 @@ func ResourceConnectorProfile() *schema.Resource { } } +func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { + return func(i interface{}, k cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + for _, validator := range validators { + diags = append(diags, validator(i, k)...) + } + return diags + } +} + func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppFlowConn name := d.Get("connector_profile_name").(string) @@ -1266,6 +1498,9 @@ func expandConnectorProfileCredentials(m map[string]interface{}) *appflow.Connec if v, ok := m["amplitude"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.Amplitude = expandAmplitudeConnectorProfileCredentials(v[0].(map[string]interface{})) } + if v, ok := m["custom_connector"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + cpc.CustomConnector = expandCustomConnectorProfileCredentials(v[0].(map[string]interface{})) + } if v, ok := m["datadog"].([]interface{}); ok && len(v) > 0 && v[0] != nil { cpc.Datadog = expandDatadogConnectorProfileCredentials(v[0].(map[string]interface{})) } @@ -1327,6 +1562,26 @@ func expandAmplitudeConnectorProfileCredentials(m map[string]interface{}) *appfl return &credentials } +func expandCustomConnectorProfileCredentials(m map[string]interface{}) *appflow.CustomConnectorProfileCredentials { + credentials := appflow.CustomConnectorProfileCredentials{ + AuthenticationType: aws.String(m["authentication_type"].(string)), + } + + if v, ok := m["basic"].([]interface{}); ok && len(v) > 0 { + credentials.Basic = expandBasicAuthCredentials(v[0].(map[string]interface{})) + } + + if v, ok := m["custom"].([]interface{}); ok && len(v) > 0 { + credentials.Custom = expandCustomAuthCredentials(v[0].(map[string]interface{})) + } + + if v, ok := m["oauth2_credentials"].([]interface{}); ok && len(v) > 0 { + credentials.Oauth2 = expandOAuth2Credentials(v[0].(map[string]interface{})) + } + + return &credentials +} + func expandDatadogConnectorProfileCredentials(m map[string]interface{}) *appflow.DatadogConnectorProfileCredentials { credentials := appflow.DatadogConnectorProfileCredentials{ ApiKey: aws.String(m["api_key"].(string)), @@ -1555,6 +1810,20 @@ func expandBasicAuthCredentials(m map[string]interface{}) *appflow.BasicAuthCred return &credentials } +func expandCustomAuthCredentials(m map[string]interface{}) *appflow.CustomAuthCredentials { + credentials := appflow.CustomAuthCredentials{} + + if v, ok := m["credentials_map"].(map[string]interface{}); ok && len(v) > 0 { + credentials.CredentialsMap = flex.ExpandStringMap(v) + } + + if v, ok := m["custom_authentication_type"].(string); ok && v != "" { + credentials.CustomAuthenticationType = aws.String(v) + } + + return &credentials +} + func expandOAuthCredentials(m map[string]interface{}) *appflow.OAuthCredentials { credentials := appflow.OAuthCredentials{ ClientId: aws.String(m["client_id"].(string)), @@ -1576,6 +1845,32 @@ func expandOAuthCredentials(m map[string]interface{}) *appflow.OAuthCredentials return &credentials } +func expandOAuth2Credentials(m map[string]interface{}) *appflow.OAuth2Credentials { + credentials := appflow.OAuth2Credentials{} + + if v, ok := m["access_token"].(string); ok && v != "" { + credentials.AccessToken = aws.String(v) + } + + if v, ok := m["client_id"].(string); ok && v != "" { + credentials.ClientId = aws.String(v) + } + + if v, ok := m["client_secret"].(string); ok && v != "" { + credentials.ClientSecret = aws.String(v) + } + + if v, ok := m["oauth_request"].([]interface{}); ok && len(v) > 0 { + credentials.OAuthRequest = expandOAuthRequest(v[0].(map[string]interface{})) + } + + if v, ok := m["refresh_token"].(string); ok && v != "" { + credentials.RefreshToken = aws.String(v) + } + + return &credentials +} + func expandConnectorProfileProperties(m map[string]interface{}) *appflow.ConnectorProfileProperties { cpc := appflow.ConnectorProfileProperties{} From ac476c5545c153988f4563d6b0713931dab0b966 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 00:19:49 -0500 Subject: [PATCH 13/59] Add support for connector_label attribute Required for CustomConnector connections --- internal/service/appflow/connector_profile.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index ae530b4559e..45f198798c1 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -30,6 +30,14 @@ func ResourceConnectorProfile() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appflow.ConnectionMode_Values(), false), }, + "connector_label": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringMatch(regexp.MustCompile(`[a-zA-Z0-9][\w!@#.-]+`), "must contain only alphanumeric, exclamation point (!), at sign (@), number sign (#), period (.), and hyphen (-) characters"), + validation.StringLenBetween(1, 256), + ), + }, "arn": { Type: schema.TypeString, Computed: true, @@ -1401,6 +1409,10 @@ func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) er ConnectorType: aws.String(d.Get("connector_type").(string)), } + if v, ok := d.Get("connector_label").(string); ok && len(v) > 0 { + createConnectorProfileInput.ConnectorLabel = aws.String(v) + } + if v, ok := d.Get("kms_arn").(string); ok && len(v) > 0 { createConnectorProfileInput.KmsArn = aws.String(v) } @@ -1428,6 +1440,7 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro credentials := d.Get("connector_profile_config.0.connector_profile_credentials").([]interface{}) d.Set("connection_mode", connectorProfile.ConnectionMode) + d.Set("connector_label", connectorProfile.ConnectorLabel) d.Set("connector_profile_arn", connectorProfile.ConnectorProfileArn) d.Set("connector_profile_name", connectorProfile.ConnectorProfileName) d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) From c73a7eda6698875b4beae4fc93ea5dd047f7a7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Tue, 10 May 2022 07:56:31 +0200 Subject: [PATCH 14/59] Remove timestamp attributes, rename credentials_arn to arn in docs --- website/docs/r/appflow_connector_profile.html.markdown | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 96820239b92..e395f4ffe25 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -345,14 +345,9 @@ The AppFlow connector profile argument layout is a complex structure. In addition to all arguments above, the following attributes are exported: -* `credentials_arn` - The Amazon Resource Name (ARN) of the connector profile credentials. - -* `connector_profile_arn` - The Amazon Resource Name (ARN) of the connector profile. - -* `created_at` - Specifies when the connector profile was created. - -* `last_updated_at` - Specifies when the connector profile was last updated. +* `arn` - The Amazon Resource Name (ARN) of the connector profile. +* `credentials_arn` - The Amazon Resource Name (ARN) of the connector profile credentials. ## Import From 38663f246e043c3b5838701f76fd4c4bd3f737a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Wed, 11 May 2022 21:56:16 +0200 Subject: [PATCH 15/59] Extract allDiagFunc to separate file --- internal/service/appflow/connector_profile.go | 12 ------------ internal/service/appflow/flow.go | 12 ------------ internal/service/appflow/validate.go | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+), 24 deletions(-) create mode 100644 internal/service/appflow/validate.go diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 45f198798c1..13c2d80eae7 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -6,8 +6,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" - "github.com/hashicorp/go-cty/cty" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -1388,16 +1386,6 @@ func ResourceConnectorProfile() *schema.Resource { } } -func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { - return func(i interface{}, k cty.Path) diag.Diagnostics { - var diags diag.Diagnostics - for _, validator := range validators { - diags = append(diags, validator(i, k)...) - } - return diags - } -} - func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppFlowConn name := d.Get("connector_profile_name").(string) diff --git a/internal/service/appflow/flow.go b/internal/service/appflow/flow.go index 380abdc2a76..7662dd94ddc 100644 --- a/internal/service/appflow/flow.go +++ b/internal/service/appflow/flow.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -1206,17 +1205,6 @@ func ResourceFlow() *schema.Resource { } } -// https://github.com/hashicorp/terraform-plugin-sdk/issues/780. -func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { - return func(i interface{}, k cty.Path) diag.Diagnostics { - var diags diag.Diagnostics - for _, validator := range validators { - diags = append(diags, validator(i, k)...) - } - return diags - } -} - func resourceFlowCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn diff --git a/internal/service/appflow/validate.go b/internal/service/appflow/validate.go new file mode 100644 index 00000000000..a7b3b31a708 --- /dev/null +++ b/internal/service/appflow/validate.go @@ -0,0 +1,18 @@ +package appflow + +import ( + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// https://github.com/hashicorp/terraform-plugin-sdk/issues/780. +func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { + return func(i interface{}, k cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + for _, validator := range validators { + diags = append(diags, validator(i, k)...) + } + return diags + } +} From 83bdf1a9e81879ce548ece4cef76b24c6039de37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Wed, 11 May 2022 22:23:24 +0200 Subject: [PATCH 16/59] Remove MaxItems for credentials_map because of error --- FAIL: TestProvider (0.16s) provider_test.go:22: err: 1 error occurred: * resource aws_appflow_connector_profile: credentials_map: MaxItems and MinItems are only supported on lists or sets --- internal/service/appflow/connector_profile.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 13c2d80eae7..93d5e2d02b4 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -144,7 +144,6 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeMap, Optional: true, Sensitive: true, - MaxItems: 50, ValidateDiagFunc: allDiagFunc( validation.MapKeyLenBetween(1, 128), validation.MapKeyMatch(regexp.MustCompile(`[\w]+`), "must contain only alphanumeric and underscore (_) characters"), From dcbad60da350c3f80c7035e0e25c74d5af153bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Wed, 11 May 2022 22:54:13 +0200 Subject: [PATCH 17/59] Remove MaxItems for profile_properties due to error --- FAIL: TestProvider (0.17s) provider_test.go:22: err: 1 error occurred: * resource aws_appflow_connector_profile: profile_properties: MaxItems and MinItems are only supported on lists or sets --- internal/service/appflow/connector_profile.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 93d5e2d02b4..e82060ce60c 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -963,7 +963,6 @@ func ResourceConnectorProfile() *schema.Resource { "profile_properties": { Type: schema.TypeMap, Optional: true, - MaxItems: 50, ValidateDiagFunc: allDiagFunc( validation.MapKeyLenBetween(1, 128), validation.MapKeyMatch(regexp.MustCompile(`[\w]+`), "must contain only alphanumeric and underscore (_) characters"), From 15503c23e972b7cd8e323923614e5125e864e4a8 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 17:28:51 -0500 Subject: [PATCH 18/59] Amend expand handling of context-dependent structures --- internal/service/appflow/connector_profile.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index e82060ce60c..49d43edc010 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1874,7 +1874,7 @@ func expandConnectorProfileProperties(m map[string]interface{}) *appflow.Connect cpc := appflow.ConnectorProfileProperties{} if v, ok := m["amplitude"].([]interface{}); ok && len(v) > 0 { - cpc.Amplitude = &appflow.AmplitudeConnectorProfileProperties{} + cpc.Amplitude = v[0].(*appflow.AmplitudeConnectorProfileProperties) } if v, ok := m["datadog"].([]interface{}); ok && len(v) > 0 && v[0] != nil { @@ -1886,11 +1886,11 @@ func expandConnectorProfileProperties(m map[string]interface{}) *appflow.Connect } if v, ok := m["google_analytics"].([]interface{}); ok && len(v) > 0 { - cpc.GoogleAnalytics = &appflow.GoogleAnalyticsConnectorProfileProperties{} + cpc.GoogleAnalytics = v[0].(*appflow.GoogleAnalyticsConnectorProfileProperties) } if v, ok := m["honeycode"].([]interface{}); ok && len(v) > 0 { - cpc.Honeycode = &appflow.HoneycodeConnectorProfileProperties{} + cpc.Honeycode = v[0].(*appflow.HoneycodeConnectorProfileProperties) } if v, ok := m["infor_nexus"].([]interface{}); ok && len(v) > 0 && v[0] != nil { @@ -1918,7 +1918,7 @@ func expandConnectorProfileProperties(m map[string]interface{}) *appflow.Connect } if v, ok := m["singular"].([]interface{}); ok && len(v) > 0 { - cpc.Singular = &appflow.SingularConnectorProfileProperties{} + cpc.Singular = v[0].(*appflow.SingularConnectorProfileProperties) } if v, ok := m["slack"].([]interface{}); ok && len(v) > 0 && v[0] != nil { @@ -1930,7 +1930,7 @@ func expandConnectorProfileProperties(m map[string]interface{}) *appflow.Connect } if v, ok := m["trendmicro"].([]interface{}); ok && len(v) > 0 { - cpc.Trendmicro = &appflow.TrendmicroConnectorProfileProperties{} + cpc.Trendmicro = v[0].(*appflow.TrendmicroConnectorProfileProperties) } if v, ok := m["veeva"].([]interface{}); ok && len(v) > 0 { From 003aa47e633c6e24a97ac2b5ef8b3c80aab2491b Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 17:29:50 -0500 Subject: [PATCH 19/59] Remove references to context-dependent structs in docs Without knowing the members of a struct, assignments to said struct will fail -- unless the operator successfully guesses the underlying types. As such assignments are not officially supported, I don't think we should include them in the documentation. --- .../docs/r/appflow_connector_profile.html.markdown | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index e395f4ffe25..753d42627d6 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -68,6 +68,7 @@ resource "aws_appflow_connector_profile" "zendesk" { } ``` + ## Argument Reference The AppFlow connector profile argument layout is a complex structure. @@ -245,16 +246,10 @@ The AppFlow connector profile argument layout is a complex structure. ##### Connector Profile Properties Arguments -* `amplitude` (Optional) - The connector-specific properties required by Amplitude. Configure as an empty block `{}`. - * `datadog` (Optional) - The connector-specific [properties](#datadog-connector-profile-properties-arguments) required by Datadog. * `dynatrace` (Optional) - The connector-specific [properties](#dynatrace-connector-profile-properties-arguments) required by Dynatrace. -* `google_analytics` (Optional) - The connector-specific properties required by Google Analytics. Configure as an empty block `{}`. - -* `honeycode` (Optional) - The connector-specific properties required by Amazon Honeycode. Configure as an empty block `{}`. - * `infor_nexus` (Optional) - The connector-specific [properties](#infor-nexus-connector-profile-properties-arguments) required by Infor Nexus. * `marketo` (Optional) - The connector-specific [properties](#marketo-connector-profile-properties-arguments) required by Marketo. @@ -265,14 +260,10 @@ The AppFlow connector profile argument layout is a complex structure. * `service_now` (Optional) - The connector-specific [properties](#servicenow-connector-profile-properties-arguments) required by ServiceNow. -* `singular` (Optional) - The connector-specific properties required by Singular. Configure as an empty block `{}`. - * `slack` (Optional) - The connector-specific [properties](#slack-connector-profile-properties-arguments) required by Slack. * `snowflake` (Optional) - The connector-specific [properties](#snowflake-connector-profile-properties-arguments) required by Snowflake. -* `trendmicro` (Optional) - The connector-specific properties required by Trend Micro. Configure as an empty block `{}`. - * `veeva` (Optional) - The connector-specific [properties](#veeva-connector-profile-properties-arguments) required by Veeva. * `zendesk` (Optional) - The connector-specific [properties](#zendesk-connector-profile-properties-arguments) required by Zendesk. From 2e97269bb02be11526c247007769502038c45910 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 17:36:26 -0500 Subject: [PATCH 20/59] Relocate / rename connector profile finder function - Move to find.go - Rename from GetConnectorProfile -> FindConnectorProfileByName --- internal/service/appflow/connector_profile.go | 30 +------------------ internal/service/appflow/find.go | 28 +++++++++++++++++ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 49d43edc010..e191f361aaf 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1417,7 +1417,7 @@ func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) er func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppFlowConn - connectorProfile, err := GetConnectorProfile(conn, d.Id()) + connectorProfile, err := FindConnectorProfileByName(conn, d.Id()) if err != nil { return err @@ -1437,34 +1437,6 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro return nil } -func GetConnectorProfile(conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { - params := &appflow.DescribeConnectorProfilesInput{ - ConnectorProfileNames: []*string{aws.String(name)}, - } - - for { - output, err := conn.DescribeConnectorProfiles(params) - - if err != nil { - return nil, err - } - - for _, connectorProfile := range output.ConnectorProfileDetails { - if aws.StringValue(connectorProfile.ConnectorProfileName) == name { - return connectorProfile, nil - } - } - - if aws.StringValue(output.NextToken) == "" { - break - } - - params.NextToken = output.NextToken - } - - return nil, fmt.Errorf("No AppFlow Connector Profile found with name: %s", name) -} - func resourceConnectorProfileUpdate(d *schema.ResourceData, meta interface{}) error { return nil } diff --git a/internal/service/appflow/find.go b/internal/service/appflow/find.go index ed141ff10cf..177bf10a219 100644 --- a/internal/service/appflow/find.go +++ b/internal/service/appflow/find.go @@ -52,3 +52,31 @@ func FindFlowByArn(ctx context.Context, conn *appflow.Appflow, arn string) (*app return result, nil } + +func FindConnectorProfileByName(conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { + params := &appflow.DescribeConnectorProfilesInput{ + ConnectorProfileNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeConnectorProfiles(params) + + if err != nil { + return nil, err + } + + for _, connectorProfile := range output.ConnectorProfileDetails { + if aws.StringValue(connectorProfile.ConnectorProfileName) == name { + return connectorProfile, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + params.NextToken = output.NextToken + } + + return nil, fmt.Errorf("No connector profile found with name: %s", name) +} From 22f2bbdbc36ea0974b3503a3894e9e4a977bca5e Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 17:39:09 -0500 Subject: [PATCH 21/59] Refactor flattenConnectorProfileProperties --- internal/service/appflow/connector_profile.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index e191f361aaf..f83cd5fbc8e 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -2081,36 +2081,30 @@ func flattenConnectorProfileConfig(cpp *appflow.ConnectorProfileProperties, cpc func flattenConnectorProfileProperties(cpp *appflow.ConnectorProfileProperties) []interface{} { result := make(map[string]interface{}) + m := make(map[string]interface{}) if cpp.Amplitude != nil { - m := make(map[string]interface{}) result["amplitude"] = []interface{}{m} } if cpp.Datadog != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Datadog.InstanceUrl) result["datadog"] = []interface{}{m} } if cpp.Dynatrace != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Dynatrace.InstanceUrl) result["dynatrace"] = []interface{}{m} } if cpp.GoogleAnalytics != nil { - m := make(map[string]interface{}) result["google_analytics"] = []interface{}{m} } if cpp.Honeycode != nil { - m := make(map[string]interface{}) result["honeycode"] = []interface{}{m} } if cpp.InforNexus != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.InforNexus.InstanceUrl) result["infor_nexus"] = []interface{}{m} } if cpp.Marketo != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Marketo.InstanceUrl) result["marketo"] = []interface{}{m} } @@ -2124,16 +2118,13 @@ func flattenConnectorProfileProperties(cpp *appflow.ConnectorProfileProperties) result["salesforce"] = flattenSalesforceConnectorProfileProperties(cpp.Salesforce) } if cpp.ServiceNow != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.ServiceNow.InstanceUrl) result["service_now"] = []interface{}{m} } if cpp.Singular != nil { - m := make(map[string]interface{}) result["singular"] = []interface{}{m} } if cpp.Slack != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Slack.InstanceUrl) result["slack"] = []interface{}{m} } @@ -2141,16 +2132,13 @@ func flattenConnectorProfileProperties(cpp *appflow.ConnectorProfileProperties) result["snowflake"] = flattenSnowflakeConnectorProfileProperties(cpp.Snowflake) } if cpp.Trendmicro != nil { - m := make(map[string]interface{}) result["trendmicro"] = []interface{}{m} } if cpp.Veeva != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Veeva.InstanceUrl) result["veeva"] = []interface{}{m} } if cpp.Zendesk != nil { - m := make(map[string]interface{}) m["instance_url"] = aws.StringValue(cpp.Zendesk.InstanceUrl) result["zendesk"] = []interface{}{m} } From 75385ba9d3a3f1302168f3ed803ea014c20c105c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 19:18:14 -0500 Subject: [PATCH 22/59] Amend oauth2_properties: Required -> Optional --- internal/service/appflow/connector_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index f83cd5fbc8e..475bdd4786c 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -925,7 +925,7 @@ func ResourceConnectorProfile() *schema.Resource { Schema: map[string]*schema.Schema{ "oauth2_properties": { Type: schema.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ From 56b903be00cb99f5851afe7f6ef2bd65552d527c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Tue, 10 May 2022 19:34:29 -0500 Subject: [PATCH 23/59] Amend custom_connector: Required -> Optional --- internal/service/appflow/connector_profile.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 475bdd4786c..4a9fc7b9e2b 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -80,7 +80,7 @@ func ResourceConnectorProfile() *schema.Resource { }, "custom_connector": { Type: schema.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -919,7 +919,7 @@ func ResourceConnectorProfile() *schema.Resource { }, "custom_connector": { Type: schema.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ From 77c8470e69bb59135180914cbe9a2129eb0a341f Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 18:39:58 -0500 Subject: [PATCH 24/59] Passing basic acceptance test using redshift --- internal/service/appflow/connector_profile.go | 5 +- .../service/appflow/connector_profile_test.go | 203 ++++++++++++++++-- internal/service/appflow/find.go | 41 ++-- 3 files changed, 213 insertions(+), 36 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 4a9fc7b9e2b..8626ba67f46 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1,6 +1,7 @@ package appflow import ( + "context" "fmt" "regexp" @@ -1417,7 +1418,7 @@ func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) er func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppFlowConn - connectorProfile, err := FindConnectorProfileByName(conn, d.Id()) + connectorProfile, err := FindConnectorProfileByName(context.Background(), conn, d.Id()) if err != nil { return err @@ -1427,7 +1428,7 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro d.Set("connection_mode", connectorProfile.ConnectionMode) d.Set("connector_label", connectorProfile.ConnectorLabel) - d.Set("connector_profile_arn", connectorProfile.ConnectorProfileArn) + d.Set("arn", connectorProfile.ConnectorProfileArn) d.Set("connector_profile_name", connectorProfile.ConnectorProfileName) d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) d.Set("connector_type", connectorProfile.ConnectorType) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 4c5f6e0f67a..ceded38a529 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -1,13 +1,13 @@ package appflow_test import ( + "context" "fmt" "os" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,12 +16,39 @@ import ( tfappflow "github.com/hashicorp/terraform-provider-aws/internal/service/appflow" ) +func TestAccAppFlowConnectorProfile_basic(t *testing.T) { + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appflow_connector_profile.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppFlowConnectorProfile_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, + }, + }, + }) +} + func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { var connectorProfiles appflow.DescribeConnectorProfilesOutput connectorProfileName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_appflow_connector_profile.amplitude" - connectorType := "Amplitude" apiKey := os.Getenv("AMPLITUDE_API_KEY") secretKey := os.Getenv("AMPLITUDE_SECRET_KEY") @@ -39,7 +66,7 @@ func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName, apiKey, secretKey), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Amplitude"), @@ -68,7 +95,6 @@ func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.datadog" - connectorType := "Datadog" apiKey := os.Getenv("DATADOG_API_KEY") applicationKey := os.Getenv("DATADOG_APPLICATION_KEY") @@ -87,7 +113,7 @@ func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName, apiKey, applicationKey, instanceUrl), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Datadog"), @@ -117,7 +143,6 @@ func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.dynatrace" - connectorType := "Dynatrace" apiToken := os.Getenv("DYNATRACE_API_TOKEN") instanceUrl := os.Getenv("DYNATRACE_INSTANCE_URL") @@ -135,7 +160,7 @@ func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName, apiToken, instanceUrl), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Dynatrace"), @@ -164,7 +189,6 @@ func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.slack" - connectorType := "Slack" clientId := os.Getenv("SLACK_CLIENT_ID") clientSecret := os.Getenv("SLACK_CLIENT_SECRET") @@ -184,7 +208,7 @@ func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Slack(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Slack"), @@ -217,7 +241,6 @@ func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.snowflake" - connectorType := "Snowflake" password := os.Getenv("SNOWFLAKE_PASSWORD") username := os.Getenv("SNOWFLAKE_USERNAME") @@ -240,7 +263,7 @@ func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Snowflake(connectorProfileName, password, username, accountName, bucketName, region, stage, warehouse), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Snowflake"), @@ -274,7 +297,6 @@ func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.trendmicro" - connectorType := "Trendmicro" apiSecretKey := os.Getenv("TRENDMICRO_API_SECRET_KEY") @@ -291,7 +313,7 @@ func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName, apiSecretKey), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Trendmicro"), @@ -318,7 +340,6 @@ func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") resourceName := "aws_appflow_connector_profile.zendesk" - connectorType := "Zendesk" clientId := os.Getenv("ZENDESK_CLIENT_ID") clientSecret := os.Getenv("ZENDESK_CLIENT_SECRET") @@ -338,7 +359,7 @@ func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { { Config: testAccAWSAppFlowConnectorProfile_Zendesk(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, connectorType, &connectorProfiles), + testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), resource.TestCheckResourceAttr(resourceName, "connector_type", "Zendesk"), @@ -374,9 +395,9 @@ func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { continue } - output, err := tfappflow.GetConnectorProfile(conn, rs.Primary.ID) + _, err := tfappflow.FindConnectorProfileByName(context.Background(), conn, rs.Primary.ID) - if tfawserr.ErrMessageContains(err, appflow.ErrCodeResourceNotFoundException, "") { + if _, ok := err.(*resource.NotFoundError); ok { continue } @@ -384,15 +405,13 @@ func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { return err } - if output != nil { - return fmt.Errorf("AppFlow Connector profile (%s) still exists", rs.Primary.ID) - } + return fmt.Errorf("Expected AppFlow Connector Profile to be destroyed, %s found", rs.Primary.ID) } return nil } -func testAccCheckAWSAppFlowConnectorProfileExists(n string, connectorType string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { +func testAccCheckAWSAppFlowConnectorProfileExists(n string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn @@ -406,7 +425,6 @@ func testAccCheckAWSAppFlowConnectorProfileExists(n string, connectorType string req := &appflow.DescribeConnectorProfilesInput{ ConnectorProfileNames: []*string{aws.String(rs.Primary.Attributes["connector_profile_name"])}, - ConnectorType: aws.String(connectorType), } describe, err := conn.DescribeConnectorProfiles(req) @@ -424,6 +442,147 @@ func testAccCheckAWSAppFlowConnectorProfileExists(n string, connectorType string } } +func testAccAppFlowConnectorProfileConfigBase(connectorProfileName string, redshiftPassword string, redshiftUsername string) string { + return acctest.ConfigCompose( + acctest.ConfigAvailableAZsNoOptIn(), + fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/24" + + tags = { + Name = %[1]q + } +} + +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +data "aws_route_table" "test" { + vpc_id = aws_vpc.test.id +} + +resource "aws_route" "test" { + route_table_id = data.aws_route_table.test.id + + destination_cidr_block = "0.0.0.0/0" + + gateway_id = aws_internet_gateway.test.id +} + +resource "aws_subnet" "test" { + cidr_block = aws_vpc.test.cidr_block + availability_zone = data.aws_availability_zones.available.names[0] + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_redshift_subnet_group" "test" { + name = %[1]q + subnet_ids = [ aws_subnet.test.id ] +} + +resource "aws_iam_role" "test" { + name = %[1]q + + managed_policy_arns = [ "arn:aws:iam::aws:policy/AmazonRedshiftAllCommandsFullAccess" ] + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) +} + +resource "aws_security_group" "test" { + name = %[1]q + + vpc_id = aws_vpc.test.id +} + +resource "aws_security_group_rule" "test" { + type = "ingress" + + security_group_id = aws_security_group.test.id + + from_port = 0 + to_port = 65535 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = %[1]q + + availability_zone = data.aws_availability_zones.available.names[0] + cluster_subnet_group_name = aws_redshift_subnet_group.test.name + vpc_security_group_ids = [ aws_security_group.test.id ] + + master_password = %[2]q + master_username = %[3]q + + publicly_accessible = true + + node_type = "dc2.large" + skip_final_snapshot = true +} +`, connectorProfileName, redshiftPassword, redshiftUsername)) +} + +func testAccAppFlowConnectorProfile_basic(connectorProfileName string) string { + const redshiftPassword = "testPassword123!" + const redshiftUsername = "testusername" + + return acctest.ConfigCompose( + testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + fmt.Sprintf(` +resource "aws_appflow_connector_profile" "test" { + connector_profile_name = %[1]q + connector_type = "Redshift" + connection_mode = "Public" + + connector_profile_config { + + connector_profile_credentials { + redshift { + password = %[2]q + username = %[3]q + } + } + + connector_profile_properties { + redshift { + bucket_name = %[1]q + database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" + role_arn = aws_iam_role.test.arn + } + } + } + + depends_on = [ + aws_route.test, + aws_security_group_rule.test, + ] +} +`, connectorProfileName, redshiftPassword, redshiftUsername), + ) +} + func testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName string, apiKey string, secretKey string) string { return fmt.Sprintf(` resource "aws_appflow_connector_profile" "amplitude" { diff --git a/internal/service/appflow/find.go b/internal/service/appflow/find.go index 177bf10a219..66b73870ad0 100644 --- a/internal/service/appflow/find.go +++ b/internal/service/appflow/find.go @@ -53,30 +53,47 @@ func FindFlowByArn(ctx context.Context, conn *appflow.Appflow, arn string) (*app return result, nil } -func FindConnectorProfileByName(conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { +func FindConnectorProfileByName(ctx context.Context, conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { params := &appflow.DescribeConnectorProfilesInput{ ConnectorProfileNames: []*string{aws.String(name)}, } + var result *appflow.ConnectorProfile - for { - output, err := conn.DescribeConnectorProfiles(params) - - if err != nil { - return nil, err + err := conn.DescribeConnectorProfilesPagesWithContext(ctx, params, func(page *appflow.DescribeConnectorProfilesOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, connectorProfile := range output.ConnectorProfileDetails { + for _, connectorProfile := range page.ConnectorProfileDetails { + if connectorProfile == nil { + continue + } + if aws.StringValue(connectorProfile.ConnectorProfileName) == name { - return connectorProfile, nil + result = connectorProfile + return false } } + return !lastPage + }) - if aws.StringValue(output.NextToken) == "" { - break + if tfawserr.ErrCodeEquals(err, appflow.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: params, } + } + + if err != nil { + return nil, err + } - params.NextToken = output.NextToken + if result == nil { + return nil, &resource.NotFoundError{ + Message: fmt.Sprintf("No connector profile with name %q", name), + LastRequest: params, + } } - return nil, fmt.Errorf("No connector profile found with name: %s", name) + return result, nil } From 143e0443e8a082dadfa8db5ffc25c4a38d6f2b52 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 22:30:58 -0500 Subject: [PATCH 25/59] Rename connector_profile_name -> name As this is the name of the resource respsented, we can refer to it as just "name" in the schema --- internal/service/appflow/connector_profile.go | 8 ++--- .../service/appflow/connector_profile_test.go | 32 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 8626ba67f46..3251b56ec98 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1361,7 +1361,7 @@ func ResourceConnectorProfile() *schema.Resource { }, }, }, - "connector_profile_name": { + "name": { Type: schema.TypeString, Required: true, ValidateFunc: validation.All( @@ -1387,7 +1387,7 @@ func ResourceConnectorProfile() *schema.Resource { func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppFlowConn - name := d.Get("connector_profile_name").(string) + name := d.Get("name").(string) createConnectorProfileInput := appflow.CreateConnectorProfileInput{ ConnectionMode: aws.String(d.Get("connection_mode").(string)), @@ -1429,11 +1429,11 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro d.Set("connection_mode", connectorProfile.ConnectionMode) d.Set("connector_label", connectorProfile.ConnectorLabel) d.Set("arn", connectorProfile.ConnectorProfileArn) - d.Set("connector_profile_name", connectorProfile.ConnectorProfileName) + d.Set("name", connectorProfile.ConnectorProfileName) d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) d.Set("connector_type", connectorProfile.ConnectorType) - d.SetId(d.Get("connector_profile_name").(string)) + d.SetId(d.Get("name").(string)) return nil } diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index ceded38a529..79e8ceaebc1 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -77,7 +77,7 @@ func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.0.secret_key", secretKey), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.amplitude.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -125,7 +125,7 @@ func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -171,7 +171,7 @@ func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -223,7 +223,7 @@ func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -279,7 +279,7 @@ func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.region", region), resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.stage"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.warehouse", warehouse), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -322,7 +322,7 @@ func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.0.api_secret_key", apiSecretKey), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -374,7 +374,7 @@ func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.#", "1"), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "connector_profile_name", connectorProfileName), + resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), ), }, { @@ -424,7 +424,7 @@ func testAccCheckAWSAppFlowConnectorProfileExists(n string, res *appflow.Describ } req := &appflow.DescribeConnectorProfilesInput{ - ConnectorProfileNames: []*string{aws.String(rs.Primary.Attributes["connector_profile_name"])}, + ConnectorProfileNames: []*string{aws.String(rs.Primary.Attributes["name"])}, } describe, err := conn.DescribeConnectorProfiles(req) @@ -552,7 +552,7 @@ func testAccAppFlowConnectorProfile_basic(connectorProfileName string) string { testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { - connector_profile_name = %[1]q + name = %[1]q connector_type = "Redshift" connection_mode = "Public" @@ -586,7 +586,7 @@ resource "aws_appflow_connector_profile" "test" { func testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName string, apiKey string, secretKey string) string { return fmt.Sprintf(` resource "aws_appflow_connector_profile" "amplitude" { - connector_profile_name = %[1]q + name = %[1]q connector_type = "Amplitude" connection_mode = "Public" connector_profile_config { @@ -609,7 +609,7 @@ resource "aws_appflow_connector_profile" "amplitude" { func testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName string, apiKey string, applicationKey string, instanceUrl string) string { return fmt.Sprintf(` resource "aws_appflow_connector_profile" "datadog" { - connector_profile_name = %[1]q + name = %[1]q connector_type = "Datadog" connection_mode = "Public" connector_profile_config { @@ -633,7 +633,7 @@ resource "aws_appflow_connector_profile" "datadog" { func testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName string, apiToken string, instanceUrl string) string { return fmt.Sprintf(` resource "aws_appflow_connector_profile" "dynatrace" { - connector_profile_name = %[1]q + name = %[1]q connector_type = "Dynatrace" connection_mode = "Public" connector_profile_config { @@ -659,7 +659,7 @@ data "aws_region" "current" {} resource "aws_appflow_connector_profile" "slack" { connection_mode = "Public" - connector_profile_name = %[1]q + name = %[1]q connector_type = "Slack" connector_profile_config { connector_profile_credentials { @@ -693,7 +693,7 @@ resource "aws_s3_bucket" "snowflake" { } resource "aws_appflow_connector_profile" "snowflake" { - connector_profile_name = %[2]q + name = %[2]q connector_type = "Snowflake" connection_mode = "Public" connector_profile_config { @@ -723,7 +723,7 @@ func testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName string, a data "aws_region" "current" {} resource "aws_appflow_connector_profile" "trendmicro" { - connector_profile_name = %[1]q + name = %[1]q connector_type = "Trendmicro" connection_mode = "Public" connector_profile_config { @@ -748,7 +748,7 @@ data "aws_region" "current" {} resource "aws_appflow_connector_profile" "zendesk" { connection_mode = "Public" - connector_profile_name = %[1]q + name = %[1]q connector_type = "Zendesk" connector_profile_config { connector_profile_credentials { From bb312d42509bc8d784a35a6478aa34077ace0f5a Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 22:39:12 -0500 Subject: [PATCH 26/59] Hoist "arn" and "name" attributes to top of schema --- internal/service/appflow/connector_profile.go | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 3251b56ec98..291a42b3eb7 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -24,6 +24,18 @@ func ResourceConnectorProfile() *schema.Resource { State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`[\w/!@#+=.-]+`), "must match [\\w/!@#+=.-]+"), + ), + }, "connection_mode": { Type: schema.TypeString, Required: true, @@ -37,10 +49,6 @@ func ResourceConnectorProfile() *schema.Resource { validation.StringLenBetween(1, 256), ), }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, "connector_profile_config": { Type: schema.TypeList, Required: true, @@ -1361,14 +1369,6 @@ func ResourceConnectorProfile() *schema.Resource { }, }, }, - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 256), - validation.StringMatch(regexp.MustCompile(`[\w/!@#+=.-]+`), "must match [\\w/!@#+=.-]+"), - ), - }, "connector_type": { Type: schema.TypeString, Required: true, From 3d1745da6db336ad0cac71380c22b4521cbb7b52 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 23:16:37 -0500 Subject: [PATCH 27/59] Add additional test steps to basic test --- internal/service/appflow/connector_profile_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 79e8ceaebc1..e7dff62adfd 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -32,6 +33,13 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { Config: testAccAppFlowConnectorProfile_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "appflow", regexp.MustCompile(`connectorprofile/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrSet(resourceName, "connection_mode"), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.#"), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_credentials.#"), + resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_properties.#"), + resource.TestCheckResourceAttrSet(resourceName, "connector_type"), ), }, { From 5f2a8c3d88565bccdc7fa2c6637a4e39bd8f612c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 23:31:49 -0500 Subject: [PATCH 28/59] Remove acceptance tests referencing external services We cannot reliably test configurations that reference non-AWS resources As connections to external services (e.g. Amplitude, Datadog, etc.) depend on non-AWS resources, we cannot reliably test connector profiles --- .../service/appflow/connector_profile_test.go | 532 ------------------ 1 file changed, 532 deletions(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index e7dff62adfd..ed2371f245e 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -3,7 +3,6 @@ package appflow_test import ( "context" "fmt" - "os" "regexp" "testing" @@ -52,349 +51,6 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { }) } -func TestAccAWSAppFlowConnectorProfile_Amplitude(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_appflow_connector_profile.amplitude" - - apiKey := os.Getenv("AMPLITUDE_API_KEY") - secretKey := os.Getenv("AMPLITUDE_SECRET_KEY") - - if apiKey == "" || secretKey == "" { - t.Skip("All environment variables: AMPLITUDE_API_KEY, AMPLITUDE_SECRET_KEY must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName, apiKey, secretKey), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Amplitude"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.0.api_key", apiKey), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.amplitude.0.secret_key", secretKey), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.amplitude.#", "1"), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Datadog(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.datadog" - - apiKey := os.Getenv("DATADOG_API_KEY") - applicationKey := os.Getenv("DATADOG_APPLICATION_KEY") - instanceUrl := os.Getenv("DATADOG_INSTANCE_URL") - - if apiKey == "" || applicationKey == "" || instanceUrl == "" { - t.Skip("All environment variables: DATADOG_API_KEY, DATADOG_APPLICATION_KEY, DATADOG_INSTANCE_URL must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName, apiKey, applicationKey, instanceUrl), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Datadog"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.0.api_key", apiKey), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.datadog.0.application_key", applicationKey), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.datadog.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Dynatrace(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.dynatrace" - - apiToken := os.Getenv("DYNATRACE_API_TOKEN") - instanceUrl := os.Getenv("DYNATRACE_INSTANCE_URL") - - if apiToken == "" || instanceUrl == "" { - t.Skip("All environment variables: DYNATRACE_API_TOKEN, DYNATRACE_INSTANCE_URL must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName, apiToken, instanceUrl), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Dynatrace"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.dynatrace.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.dynatrace.0.api_token", apiToken), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.dynatrace.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Slack(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.slack" - - clientId := os.Getenv("SLACK_CLIENT_ID") - clientSecret := os.Getenv("SLACK_CLIENT_SECRET") - accessToken := os.Getenv("SLACK_ACCESS_TOKEN") - instanceUrl := os.Getenv("SLACK_INSTANCE_URL") - - if clientId == "" || clientSecret == "" || accessToken == "" || instanceUrl == "" { - t.Skip("All environment variables: SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_ACCESS_TOKEN, SLACK_INSTANCE_URL must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Slack(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Slack"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.access_token", accessToken), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.client_id", clientId), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.client_secret", clientSecret), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.oauth_request.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_credentials.0.slack.0.oauth_request.0.redirect_uri"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.slack.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Snowflake(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.snowflake" - - password := os.Getenv("SNOWFLAKE_PASSWORD") - username := os.Getenv("SNOWFLAKE_USERNAME") - accountName := os.Getenv("SNOWFLAKE_ACCOUNT_NAME") - bucketName := connectorProfileName - region := os.Getenv("SNOWFLAKE_REGION") - stage := os.Getenv("SNOWFLAKE_STAGE") - warehouse := os.Getenv("SNOWFLAKE_WAREHOUSE") - - if password == "" || username == "" || accountName == "" || region == "" || stage == "" || warehouse == "" { - t.Skip("All environment variables: SNOWFLAKE_PASSWORD, SNOWFLAKE_USERNAME, SNOWFLAKE_ACCOUNT_NAME, SNOWFLAKE_REGION, SNOWFLAKE_STAGE, SNOWFLAKE_WAREHOUSE must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Snowflake(connectorProfileName, password, username, accountName, bucketName, region, stage, warehouse), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Snowflake"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.0.password", password), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.snowflake.0.username", username), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.account_name", accountName), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.bucket_name", bucketName), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.region", region), - resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.stage"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.snowflake.0.warehouse", warehouse), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Trendmicro(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.trendmicro" - - apiSecretKey := os.Getenv("TRENDMICRO_API_SECRET_KEY") - - if apiSecretKey == "" { - t.Skip("All environment variables: TRENDMICRO_API_SECRET_KEY must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName, apiSecretKey), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Trendmicro"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.trendmicro.0.api_secret_key", apiSecretKey), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - -func TestAccAWSAppFlowConnectorProfile_Zendesk(t *testing.T) { - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - connectorProfileName := sdkacctest.RandomWithPrefix("tf-acc-test-appflow-connector-profile") - resourceName := "aws_appflow_connector_profile.zendesk" - - clientId := os.Getenv("ZENDESK_CLIENT_ID") - clientSecret := os.Getenv("ZENDESK_CLIENT_SECRET") - accessToken := os.Getenv("ZENDESK_ACCESS_TOKEN") - instanceUrl := os.Getenv("ZENDESK_INSTANCE_URL") - - if clientId == "" || clientSecret == "" || accessToken == "" || instanceUrl == "" { - t.Skip("All environment variables: ZENDESK_CLIENT_ID, ZENDESK_CLIENT_SECRET, ZENDESK_ACCESS_TOKEN, ZENDESK_INSTANCE_URL must be set.") - } - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAppFlowConnectorProfile_Zendesk(connectorProfileName, clientId, clientSecret, accessToken, instanceUrl), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "connection_mode", "Public"), - acctest.CheckResourceAttrRegionalARN(resourceName, "connector_profile_arn", "appflow", fmt.Sprintf("connectorprofile/%s", connectorProfileName)), - resource.TestCheckResourceAttr(resourceName, "connector_type", "Zendesk"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.access_token", accessToken), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.client_id", clientId), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.client_secret", clientSecret), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.oauth_request.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "connector_profile_config.0.connector_profile_credentials.0.zendesk.0.oauth_request.0.redirect_uri"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.#", "1"), - resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.zendesk.0.instance_url", instanceUrl), - resource.TestCheckResourceAttr(resourceName, "name", connectorProfileName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"connector_profile_config.0.connector_profile_credentials"}, - }, - }, - }) -} - func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn @@ -590,191 +246,3 @@ resource "aws_appflow_connector_profile" "test" { `, connectorProfileName, redshiftPassword, redshiftUsername), ) } - -func testAccAWSAppFlowConnectorProfile_Amplitude(connectorProfileName string, apiKey string, secretKey string) string { - return fmt.Sprintf(` -resource "aws_appflow_connector_profile" "amplitude" { - name = %[1]q - connector_type = "Amplitude" - connection_mode = "Public" - connector_profile_config { - connector_profile_credentials { - amplitude { - api_key = %[2]q - secret_key = %[3]q - } - } - connector_profile_properties { - amplitude { - } - } - } - -} -`, connectorProfileName, apiKey, secretKey) -} - -func testAccAWSAppFlowConnectorProfile_Datadog(connectorProfileName string, apiKey string, applicationKey string, instanceUrl string) string { - return fmt.Sprintf(` -resource "aws_appflow_connector_profile" "datadog" { - name = %[1]q - connector_type = "Datadog" - connection_mode = "Public" - connector_profile_config { - connector_profile_credentials { - datadog { - api_key = %[2]q - application_key = %[3]q - } - } - connector_profile_properties { - datadog { - instance_url = %[4]q - } - } - } - -} -`, connectorProfileName, apiKey, applicationKey, instanceUrl) -} - -func testAccAWSAppFlowConnectorProfile_Dynatrace(connectorProfileName string, apiToken string, instanceUrl string) string { - return fmt.Sprintf(` -resource "aws_appflow_connector_profile" "dynatrace" { - name = %[1]q - connector_type = "Dynatrace" - connection_mode = "Public" - connector_profile_config { - connector_profile_credentials { - dynatrace { - api_token = %[2]q - } - } - connector_profile_properties { - dynatrace { - instance_url = %[3]q - } - } - } - -} -`, connectorProfileName, apiToken, instanceUrl) -} - -func testAccAWSAppFlowConnectorProfile_Slack(connectorProfileName string, clientId string, clientSecret string, accessToken string, instanceUrl string) string { - return fmt.Sprintf(` -data "aws_region" "current" {} - -resource "aws_appflow_connector_profile" "slack" { - connection_mode = "Public" - name = %[1]q - connector_type = "Slack" - connector_profile_config { - connector_profile_credentials { - slack { - client_id = %[2]q - client_secret = %[3]q - access_token = %[4]q - oauth_request { - redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" - } - } - } - connector_profile_properties { - slack { - instance_url = %[5]q - } - } - } -} -`, connectorProfileName, clientId, clientSecret, accessToken, instanceUrl) -} - -func testAccAWSAppFlowConnectorProfile_Snowflake(connectorProfileName string, password string, username string, accountName string, bucketName string, region string, stage string, warehouse string) string { - - return fmt.Sprintf(` -data "aws_region" "current" {} - -resource "aws_s3_bucket" "snowflake" { - bucket = %[1]q - acl = "private" -} - -resource "aws_appflow_connector_profile" "snowflake" { - name = %[2]q - connector_type = "Snowflake" - connection_mode = "Public" - connector_profile_config { - connector_profile_credentials { - snowflake { - password = %[3]q - username = %[4]q - } - } - connector_profile_properties { - snowflake { - account_name = %[5]q - bucket_name = aws_s3_bucket.snowflake.id - region = %[6]q - stage = %[7]q - warehouse = %[8]q - } - } - } - -} -`, bucketName, connectorProfileName, password, username, accountName, region, stage, warehouse) -} - -func testAccAWSAppFlowConnectorProfile_Trendmicro(connectorProfileName string, apiSecretKey string) string { - return fmt.Sprintf(` -data "aws_region" "current" {} - -resource "aws_appflow_connector_profile" "trendmicro" { - name = %[1]q - connector_type = "Trendmicro" - connection_mode = "Public" - connector_profile_config { - connector_profile_credentials { - trendmicro { - api_secret_key = %[2]q - } - } - connector_profile_properties { - trendmicro { - } - } - } - -} -`, connectorProfileName, apiSecretKey) -} - -func testAccAWSAppFlowConnectorProfile_Zendesk(connectorProfileName string, clientId string, clientSecret string, accessToken string, instanceUrl string) string { - return fmt.Sprintf(` -data "aws_region" "current" {} - -resource "aws_appflow_connector_profile" "zendesk" { - connection_mode = "Public" - name = %[1]q - connector_type = "Zendesk" - connector_profile_config { - connector_profile_credentials { - zendesk { - client_id = %[2]q - client_secret = %[3]q - access_token = %[4]q - oauth_request { - redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" - } - } - } - connector_profile_properties { - zendesk { - instance_url = %[5]q - } - } - } -} -`, connectorProfileName, clientId, clientSecret, accessToken, instanceUrl) -} From e88611e2a8f23a6aec231f6b0709b7b567ed720e Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 23:37:05 -0500 Subject: [PATCH 29/59] Remove "AWS" from Exist test function name --- internal/service/appflow/connector_profile_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index ed2371f245e..c6b5dae3f75 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -31,7 +31,7 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { { Config: testAccAppFlowConnectorProfile_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "appflow", regexp.MustCompile(`connectorprofile/.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrSet(resourceName, "connection_mode"), @@ -75,7 +75,7 @@ func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSAppFlowConnectorProfileExists(n string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { +func testAccCheckAppFlowConnectorProfileExists(n string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn From 1f50356e695805012fbff8bcf1517d621d027071 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Wed, 11 May 2022 23:39:03 -0500 Subject: [PATCH 30/59] Run terrafmt --- .../service/appflow/connector_profile_test.go | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index c6b5dae3f75..bcdd542f792 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -134,7 +134,7 @@ resource "aws_route" "test" { route_table_id = data.aws_route_table.test.id destination_cidr_block = "0.0.0.0/0" - + gateway_id = aws_internet_gateway.test.id } @@ -150,31 +150,31 @@ resource "aws_subnet" "test" { resource "aws_redshift_subnet_group" "test" { name = %[1]q - subnet_ids = [ aws_subnet.test.id ] + subnet_ids = [aws_subnet.test.id] } resource "aws_iam_role" "test" { name = %[1]q - managed_policy_arns = [ "arn:aws:iam::aws:policy/AmazonRedshiftAllCommandsFullAccess" ] + managed_policy_arns = ["arn:aws:iam::aws:policy/AmazonRedshiftAllCommandsFullAccess"] assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Sid = "" - Principal = { - Service = "ec2.amazonaws.com" - } - }, - ] + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] }) } resource "aws_security_group" "test" { - name = %[1]q + name = %[1]q vpc_id = aws_vpc.test.id } @@ -191,11 +191,11 @@ resource "aws_security_group_rule" "test" { } resource "aws_redshift_cluster" "test" { - cluster_identifier = %[1]q + cluster_identifier = %[1]q availability_zone = data.aws_availability_zones.available.names[0] cluster_subnet_group_name = aws_redshift_subnet_group.test.name - vpc_security_group_ids = [ aws_security_group.test.id ] + vpc_security_group_ids = [aws_security_group.test.id] master_password = %[2]q master_username = %[3]q @@ -216,24 +216,24 @@ func testAccAppFlowConnectorProfile_basic(connectorProfileName string) string { testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { - name = %[1]q - connector_type = "Redshift" - connection_mode = "Public" + name = %[1]q + connector_type = "Redshift" + connection_mode = "Public" connector_profile_config { connector_profile_credentials { redshift { - password = %[2]q - username = %[3]q - } + password = %[2]q + username = %[3]q + } } connector_profile_properties { redshift { - bucket_name = %[1]q - database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" - role_arn = aws_iam_role.test.arn + bucket_name = %[1]q + database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" + role_arn = aws_iam_role.test.arn } } } From 026bf6f0a8fa746cc90623d5576bdda911d43e11 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 00:33:31 -0500 Subject: [PATCH 31/59] Add long-running test guard to connector profile test Test depends on Redshift resources, which take some time to create/destroy --- internal/service/appflow/connector_profile_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index bcdd542f792..f418732106d 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -17,6 +17,10 @@ import ( ) func TestAccAppFlowConnectorProfile_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + var connectorProfiles appflow.DescribeConnectorProfilesOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) From cc0e4deb2db9847057c84adb7fbff8c30ddd3427 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 00:34:43 -0500 Subject: [PATCH 32/59] Change resource.Test -> ParallelTest Ensures test is run in parallel when possible --- internal/service/appflow/connector_profile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index f418732106d..49d4c0648e5 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -26,7 +26,7 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_appflow_connector_profile.test" - resource.Test(t, resource.TestCase{ + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), Providers: acctest.Providers, From 4e0068351976f592ca3257273dba193476da2e18 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 00:35:33 -0500 Subject: [PATCH 33/59] Replace hardcoded arn reference w/ reference to iam_policy data source --- internal/service/appflow/connector_profile_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 49d4c0648e5..7b0d90addf2 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -157,10 +157,14 @@ resource "aws_redshift_subnet_group" "test" { subnet_ids = [aws_subnet.test.id] } +data "aws_iam_policy" "test" { + name = "AmazonRedshiftAllCommandsFullAccess" +} + resource "aws_iam_role" "test" { name = %[1]q - managed_policy_arns = ["arn:aws:iam::aws:policy/AmazonRedshiftAllCommandsFullAccess"] + managed_policy_arns = [data.aws_iam_policy.test.arn] assume_role_policy = jsonencode({ Version = "2012-10-17" From 6c471628a2683287a71e8fdd09508a3294ad107a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Thu, 12 May 2022 07:54:22 +0200 Subject: [PATCH 34/59] Update docs after renaming attribute connector_profile_name to name --- .../r/appflow_connector_profile.html.markdown | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 753d42627d6..7f3d9d5e165 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -21,7 +21,10 @@ AppFlow API Reference. ```terraform resource "aws_appflow_connector_profile" "amplitude" { + name = "amplitude-connector" connection_mode = "Public" + connector_type = "Amplitude" + connector_profile_config { connector_profile_credentials { amplitude { @@ -34,8 +37,6 @@ resource "aws_appflow_connector_profile" "amplitude" { } } } - connector_profile_name = "amplitude-connector" - connector_type = "Amplitude" } ``` @@ -45,7 +46,10 @@ resource "aws_appflow_connector_profile" "amplitude" { data "aws_region" "current" {} resource "aws_appflow_connector_profile" "zendesk" { + name = "zendesk-connector" connection_mode = "Public" + connector_type = "Zendesk" + connector_profile_config { connector_profile_credentials { zendesk { @@ -63,8 +67,6 @@ resource "aws_appflow_connector_profile" "zendesk" { } } } - connector_profile_name = "zendesk-connector" - connector_type = "Zendesk" } ``` @@ -75,13 +77,13 @@ The AppFlow connector profile argument layout is a complex structure. ### Top-Level Arguments -* `connection_mode` (Required) - Indicates the connection mode and specifies whether it is public or private. Private flows use AWS PrivateLink to route data over AWS infrastructure without exposing it to the public internet. One of: `Public`, `Private`. +* `name ` (Required) - The name of the connector profile. The name is unique for each ConnectorProfile in your AWS account. -* `connector_profile_config` (Required) - Defines the connector-specific [configuration and credentials](#connector-profile-config-arguments). +* `connection_mode` (Required) - Indicates the connection mode and specifies whether it is public or private. Private flows use AWS PrivateLink to route data over AWS infrastructure without exposing it to the public internet. One of: `Public`, `Private`. -* `connector_profile_name ` (Required) - The name of the connector profile. The name is unique for each ConnectorProfile in your AWS account. +* `connector_type` (Required) - The type of connector. One of: `Amplitude`, `CustomConnector`, `CustomerProfiles`, `Datadog`, `Dynatrace`, `EventBridge`, `Googleanalytics`, `Honeycode`, `Infornexus`, `LookoutMetrics`, `Marketo`, `Redshift`, `S3`, `Salesforce`, `SAPOData`, `Servicenow`, `Singular`, `Slack`, `Snowflake`, `Trendmicro`, `Upsolver`, `Veeva`, `Zendesk`. -* `connector_type` (Required) - The type of connector. One of: `Amplitude`, `Datadog`, `Dynatrace`, `Googleanalytics`, `Honeycode`, `Infornexus`, `Marketo`, `Redshift`, `Salesforce`, `Servicenow`, `Singular`, `Slack`, `Snowflake`, `Trendmicro`, `Veeva`, `Zendesk`. +* `connector_profile_config` (Required) - Defines the connector-specific [configuration and credentials](#connector-profile-config-arguments). * `kms_arn` (Optional) - The ARN (Amazon Resource Name) of the Key Management Service (KMS) key you provide for encryption. This is required if you do not want to use the Amazon AppFlow-managed KMS key. If you don't provide anything here, Amazon AppFlow uses the Amazon AppFlow-managed KMS key. From 1f87b7ec567b9f56c1d2120fdaf4b5139ba94b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Thu, 12 May 2022 09:03:36 +0200 Subject: [PATCH 35/59] Add details about Customer Connector to docs --- .../r/appflow_connector_profile.html.markdown | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 7f3d9d5e165..468d04b16ae 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -85,6 +85,8 @@ The AppFlow connector profile argument layout is a complex structure. * `connector_profile_config` (Required) - Defines the connector-specific [configuration and credentials](#connector-profile-config-arguments). +* `connector_label` (Optional) - The label of the connector. The label is unique for each ConnectorRegistration in your AWS account. Only needed if calling for `CustomConnector` connector type. + * `kms_arn` (Optional) - The ARN (Amazon Resource Name) of the Key Management Service (KMS) key you provide for encryption. This is required if you do not want to use the Amazon AppFlow-managed KMS key. If you don't provide anything here, Amazon AppFlow uses the Amazon AppFlow-managed KMS key. #### Connector Profile Config Arguments @@ -98,6 +100,8 @@ The AppFlow connector profile argument layout is a complex structure. * `amplitude` (Optional) - The connector-specific [credentials](#amplitude-connector-profile-credentials-arguments) required when using Amplitude. +* `custom_connector` (Optional) - The connector-specific profile [credentials](#custom-connector-profile-credentials-arguments) required when using the custom connector. + * `datadog` (Optional) - The connector-specific [credentials](#datadog-connector-profile-credentials-arguments) required when using Datadog. * `dynatrace` (Optional) - The connector-specific [credentials](#dynatrace-connector-profile-credentials-arguments) required when using Dynatrace. @@ -134,6 +138,31 @@ The AppFlow connector profile argument layout is a complex structure. * `secret_key` (Required) - The Secret Access Key portion of the credentials. +##### Custom Connector Profile Credentials Arguments + +* `api_key` (Optional) - The API keys required for the authentication of the user. + * `api_key` (Required) - The API key required for API key authentication. + * `api_secret_key` (Optional) - The API secret key required for API key authentication. + +* `authentication_type` (Required) - The authentication type that the custom connector uses for authenticating while creating a connector profile. One of: `APIKEY`, `BASIC`, `CUSTOM`, `OAUTH2`. + +* `basic` (Optional) - The basic credentials that are required for the authentication of the user. + * `password` (Required) - The password to use to connect to a resource. + * `username` (Required) - The username to use to connect to a resource. + +* `custom` (Optional) - If the connector uses the custom authentication mechanism, this holds the required credentials. + * `credentials_map` (Optional) - A map that holds custom authentication credentials. + * `custom_authentication_type` (Required) - The custom authentication type that the connector uses. + +* `oauth2` (Optional) - The OAuth 2.0 credentials required for the authentication of the user. + * `access_token` (Optional) - The access token used to access the connector on your behalf. + * `client_id` (Optional) - The identifier for the desired client. + * `client_secret` (Optional) - The client secret used by the OAuth client to authenticate to the authorization server. + * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. + * `auth_code` (Optional) - The code provided by the connector when it has been authenticated via the connected app. + * `redirect_uri` (Optional) - The URL to which the authentication server redirects the browser after authorization has been granted. + * `refresh_token` (Optional) - The refresh token used to refresh an expired access token. + ##### Datadog Connector Profile Credentials Arguments * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. @@ -248,6 +277,8 @@ The AppFlow connector profile argument layout is a complex structure. ##### Connector Profile Properties Arguments +* `custom_connector` (Optional) - The [properties](#custom-connector-profile-properties-arguments) required by the custom connector. + * `datadog` (Optional) - The connector-specific [properties](#datadog-connector-profile-properties-arguments) required by Datadog. * `dynatrace` (Optional) - The connector-specific [properties](#dynatrace-connector-profile-properties-arguments) required by Dynatrace. @@ -270,6 +301,15 @@ The AppFlow connector profile argument layout is a complex structure. * `zendesk` (Optional) - The connector-specific [properties](#zendesk-connector-profile-properties-arguments) required by Zendesk. +##### Custom Connector Profile Properties Arguments + +* `oauth2_properties` (Optional) - The OAuth 2.0 properties required for OAuth 2.0 authentication. + * `oauth2_grant_type` (Required) - The OAuth 2.0 grant type used by connector for OAuth 2.0 authentication. One of: `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`. + * `token_url` (Required) - The token URL required for OAuth 2.0 authentication. + * `token_url_custom_properties` (Optional) - Associates your token URL with a map of properties that you define. Use this parameter to provide any additional details that the connector requires to authenticate your request. + +* `profile_properties` (Optional) - A map of properties that are required to create a profile for the custom connector. + ##### Datadog Connector Profile Properties Arguments * `instance_url` (Required) - The location of the Datadog resource. From a4be5b131654e3a597436018bcbb2aadf1f21d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Thu, 12 May 2022 10:12:36 +0200 Subject: [PATCH 36/59] Indent according to markdown-lint --- .../r/appflow_connector_profile.html.markdown | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 468d04b16ae..d7257867b40 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -141,27 +141,27 @@ The AppFlow connector profile argument layout is a complex structure. ##### Custom Connector Profile Credentials Arguments * `api_key` (Optional) - The API keys required for the authentication of the user. - * `api_key` (Required) - The API key required for API key authentication. - * `api_secret_key` (Optional) - The API secret key required for API key authentication. + * `api_key` (Required) - The API key required for API key authentication. + * `api_secret_key` (Optional) - The API secret key required for API key authentication. * `authentication_type` (Required) - The authentication type that the custom connector uses for authenticating while creating a connector profile. One of: `APIKEY`, `BASIC`, `CUSTOM`, `OAUTH2`. * `basic` (Optional) - The basic credentials that are required for the authentication of the user. - * `password` (Required) - The password to use to connect to a resource. - * `username` (Required) - The username to use to connect to a resource. + * `password` (Required) - The password to use to connect to a resource. + * `username` (Required) - The username to use to connect to a resource. * `custom` (Optional) - If the connector uses the custom authentication mechanism, this holds the required credentials. - * `credentials_map` (Optional) - A map that holds custom authentication credentials. - * `custom_authentication_type` (Required) - The custom authentication type that the connector uses. + * `credentials_map` (Optional) - A map that holds custom authentication credentials. + * `custom_authentication_type` (Required) - The custom authentication type that the connector uses. * `oauth2` (Optional) - The OAuth 2.0 credentials required for the authentication of the user. - * `access_token` (Optional) - The access token used to access the connector on your behalf. - * `client_id` (Optional) - The identifier for the desired client. - * `client_secret` (Optional) - The client secret used by the OAuth client to authenticate to the authorization server. - * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. - * `auth_code` (Optional) - The code provided by the connector when it has been authenticated via the connected app. - * `redirect_uri` (Optional) - The URL to which the authentication server redirects the browser after authorization has been granted. - * `refresh_token` (Optional) - The refresh token used to refresh an expired access token. + * `access_token` (Optional) - The access token used to access the connector on your behalf. + * `client_id` (Optional) - The identifier for the desired client. + * `client_secret` (Optional) - The client secret used by the OAuth client to authenticate to the authorization server. + * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. + * `auth_code` (Optional) - The code provided by the connector when it has been authenticated via the connected app. + * `redirect_uri` (Optional) - The URL to which the authentication server redirects the browser after authorization has been granted. + * `refresh_token` (Optional) - The refresh token used to refresh an expired access token. ##### Datadog Connector Profile Credentials Arguments @@ -304,9 +304,9 @@ The AppFlow connector profile argument layout is a complex structure. ##### Custom Connector Profile Properties Arguments * `oauth2_properties` (Optional) - The OAuth 2.0 properties required for OAuth 2.0 authentication. - * `oauth2_grant_type` (Required) - The OAuth 2.0 grant type used by connector for OAuth 2.0 authentication. One of: `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`. - * `token_url` (Required) - The token URL required for OAuth 2.0 authentication. - * `token_url_custom_properties` (Optional) - Associates your token URL with a map of properties that you define. Use this parameter to provide any additional details that the connector requires to authenticate your request. + * `oauth2_grant_type` (Required) - The OAuth 2.0 grant type used by connector for OAuth 2.0 authentication. One of: `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`. + * `token_url` (Required) - The token URL required for OAuth 2.0 authentication. + * `token_url_custom_properties` (Optional) - Associates your token URL with a map of properties that you define. Use this parameter to provide any additional details that the connector requires to authenticate your request. * `profile_properties` (Optional) - A map of properties that are required to create a profile for the custom connector. From 374d42f884873704e0dac216e0a9c47ebe3c04b3 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 16:32:44 -0500 Subject: [PATCH 37/59] Add ForceNew to attributes where necessary --- internal/service/appflow/connector_profile.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 291a42b3eb7..c57aaca5424 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -44,6 +44,7 @@ func ResourceConnectorProfile() *schema.Resource { "connector_label": { Type: schema.TypeString, Optional: true, + ForceNew: true, ValidateFunc: validation.All( validation.StringMatch(regexp.MustCompile(`[a-zA-Z0-9][\w!@#.-]+`), "must contain only alphanumeric, exclamation point (!), at sign (@), number sign (#), period (.), and hyphen (-) characters"), validation.StringLenBetween(1, 256), @@ -1372,6 +1373,7 @@ func ResourceConnectorProfile() *schema.Resource { "connector_type": { Type: schema.TypeString, Required: true, + ForceNew: true, ValidateFunc: validation.StringInSlice(appflow.ConnectorType_Values(), false), }, "kms_arn": { From 77e0ec2dbad070e3d432e50de8f3c261cd3fb217 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 16:33:17 -0500 Subject: [PATCH 38/59] Add credentials_arn attribute + note re: reading connector profile credentials --- internal/service/appflow/connector_profile.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index c57aaca5424..ee511f439be 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1383,6 +1383,11 @@ func ResourceConnectorProfile() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, + "credentials_arn": { + Type: schema.TypeString, + Computed: true, + ValidateFunc: verify.ValidARN, + }, }, } } @@ -1426,6 +1431,12 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro return err } + // Credentials are not returned by any API operation. Instead, a + // "credentials_arn" property is returned. + // + // It may be possible to implement a function that reads from this + // credentials resource -- but it is not documented in the API reference. + // (https://docs.aws.amazon.com/appflow/1.0/APIReference/API_ConnectorProfile.html#appflow-Type-ConnectorProfile-credentialsArn) credentials := d.Get("connector_profile_config.0.connector_profile_credentials").([]interface{}) d.Set("connection_mode", connectorProfile.ConnectionMode) @@ -1434,6 +1445,7 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro d.Set("name", connectorProfile.ConnectorProfileName) d.Set("connector_profile_config", flattenConnectorProfileConfig(connectorProfile.ConnectorProfileProperties, credentials)) d.Set("connector_type", connectorProfile.ConnectorType) + d.Set("credentials_arn", connectorProfile.CredentialsArn) d.SetId(d.Get("name").(string)) From ac2a3dc383b01526c01621347584d5065f67d064 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 16:43:23 -0500 Subject: [PATCH 39/59] Amend CRUD functions to use context + diag error functions --- internal/service/appflow/connector_profile.go | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index ee511f439be..bd0d5ccaefd 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -2,11 +2,11 @@ package appflow import ( "context" - "fmt" "regexp" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appflow" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -16,10 +16,10 @@ import ( func ResourceConnectorProfile() *schema.Resource { return &schema.Resource{ - Create: resourceConnectorProfileCreate, - Read: resourceConnectorProfileRead, - Update: resourceConnectorProfileUpdate, - Delete: resourceConnectorProfileDelete, + CreateWithoutTimeout: resourceConnectorProfileCreate, + ReadWithoutTimeout: resourceConnectorProfileRead, + UpdateWithoutTimeout: resourceConnectorProfileUpdate, + DeleteWithoutTimeout: resourceConnectorProfileDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -1392,7 +1392,7 @@ func ResourceConnectorProfile() *schema.Resource { } } -func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) error { +func resourceConnectorProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn name := d.Get("name").(string) @@ -1414,21 +1414,21 @@ func resourceConnectorProfileCreate(d *schema.ResourceData, meta interface{}) er _, err := conn.CreateConnectorProfile(&createConnectorProfileInput) if err != nil { - return fmt.Errorf("error creating AppFlow Connector Profile: %w", err) + return diag.Errorf("creating AppFlow Connector Profile: %s", err) } d.SetId(name) - return resourceConnectorProfileRead(d, meta) + return resourceConnectorProfileRead(ctx, d, meta) } -func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) error { +func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn connectorProfile, err := FindConnectorProfileByName(context.Background(), conn, d.Id()) if err != nil { - return err + return diag.Errorf("reading AppFlow Flow (%s): %s", d.Id(), err) } // Credentials are not returned by any API operation. Instead, a @@ -1452,18 +1452,18 @@ func resourceConnectorProfileRead(d *schema.ResourceData, meta interface{}) erro return nil } -func resourceConnectorProfileUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceConnectorProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { return nil } -func resourceConnectorProfileDelete(d *schema.ResourceData, meta interface{}) error { +func resourceConnectorProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn _, err := conn.DeleteConnectorProfile(&appflow.DeleteConnectorProfileInput{ ConnectorProfileName: aws.String(d.Id()), }) if err != nil { - return fmt.Errorf("Error deleting AppFlow Connector Profile (%s): %w", d.Id(), err) + return diag.Errorf("deleting AppFlow Connector Profile (%s): %s", d.Id(), err) } return nil From 061c2ba99f25ae7335694f38bac4a8cff22040bb Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 17:03:32 -0500 Subject: [PATCH 40/59] Remove ValidateFunc from Computed attribute --- internal/service/appflow/connector_profile.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index bd0d5ccaefd..1ba99c24c7a 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1384,9 +1384,8 @@ func ResourceConnectorProfile() *schema.Resource { ValidateFunc: verify.ValidARN, }, "credentials_arn": { - Type: schema.TypeString, - Computed: true, - ValidateFunc: verify.ValidARN, + Type: schema.TypeString, + Computed: true, }, }, } From 0f72965907aac252ec1f25576cf8fd54a62f57cf Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 17:47:41 -0500 Subject: [PATCH 41/59] Add passing Update acceptance test for connector profiles --- internal/service/appflow/connector_profile.go | 19 ++++- .../service/appflow/connector_profile_test.go | 73 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 1ba99c24c7a..35b01aacf50 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -2,6 +2,7 @@ package appflow import ( "context" + "log" "regexp" "github.com/aws/aws-sdk-go/aws" @@ -1452,7 +1453,23 @@ func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, m } func resourceConnectorProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - return nil + conn := meta.(*conns.AWSClient).AppFlowConn + name := d.Get("name").(string) + + updateConnectorProfileInput := appflow.UpdateConnectorProfileInput{ + ConnectionMode: aws.String(d.Get("connection_mode").(string)), + ConnectorProfileConfig: expandConnectorProfileConfig(d.Get("connector_profile_config").([]interface{})[0].(map[string]interface{})), + ConnectorProfileName: aws.String(name), + } + + log.Printf("[DEBUG] Updating AppFlow Connector Profile (%s): %#v", d.Id(), updateConnectorProfileInput) + _, err := conn.UpdateConnectorProfile(&updateConnectorProfileInput) + + if err != nil { + return diag.Errorf("updating AppFlow Connector Profile (%s): %s", d.Id(), err) + } + + return resourceConnectorProfileRead(ctx, d, meta) } func resourceConnectorProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 7b0d90addf2..f49902b8e6a 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -55,6 +55,39 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { }) } +func TestAccAppFlowConnectorProfile_update(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var connectorProfiles appflow.DescribeConnectorProfilesOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appflow_connector_profile.test" + testPrefix := "test-prefix" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppFlowConnectorProfile_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + ), + }, + { + Config: testAccAppFlowConnectorProfile_update(rName, testPrefix), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.redshift.0.bucket_prefix", testPrefix), + ), + }, + }, + }) +} + func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn @@ -254,3 +287,43 @@ resource "aws_appflow_connector_profile" "test" { `, connectorProfileName, redshiftPassword, redshiftUsername), ) } + +func testAccAppFlowConnectorProfile_update(connectorProfileName string, bucketPrefix string) string { + const redshiftPassword = "testPassword123!" + const redshiftUsername = "testusername" + + return acctest.ConfigCompose( + testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + fmt.Sprintf(` +resource "aws_appflow_connector_profile" "test" { + name = %[1]q + connector_type = "Redshift" + connection_mode = "Public" + + connector_profile_config { + + connector_profile_credentials { + redshift { + password = %[2]q + username = %[3]q + } + } + + connector_profile_properties { + redshift { + bucket_name = %[1]q + bucket_prefix = %[4]q + database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" + role_arn = aws_iam_role.test.arn + } + } + } + + depends_on = [ + aws_route.test, + aws_security_group_rule.test, + ] +} +`, connectorProfileName, redshiftPassword, redshiftUsername, bucketPrefix), + ) +} From d4e6a855db04124e5cc491f1340c7b1d40d171c8 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 17:58:01 -0500 Subject: [PATCH 42/59] Add logic to remove connector profile from state if not found --- internal/service/appflow/connector_profile.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 35b01aacf50..117d8a0355e 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -1427,8 +1428,14 @@ func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, m connectorProfile, err := FindConnectorProfileByName(context.Background(), conn, d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] AppFlow Connector Profile (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { - return diag.Errorf("reading AppFlow Flow (%s): %s", d.Id(), err) + return diag.Errorf("reading AppFlow Connector Profile (%s): %s", d.Id(), err) } // Credentials are not returned by any API operation. Instead, a From 24aad0b30eb1eada4b0c7cd2ebd55af4e3c6f898 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 18:08:02 -0500 Subject: [PATCH 43/59] Change ID attribute from "name" to "arn" "name" is only unique to a particular AWS account. To ensure uniqueness of IDs across multiple AWS accounts, we use "arn" instead. --- internal/service/appflow/connector_profile.go | 12 +++++++----- internal/service/appflow/connector_profile_test.go | 2 +- internal/service/appflow/find.go | 10 ++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 117d8a0355e..ea0c74c8055 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1412,13 +1412,17 @@ func resourceConnectorProfileCreate(ctx context.Context, d *schema.ResourceData, createConnectorProfileInput.KmsArn = aws.String(v) } - _, err := conn.CreateConnectorProfile(&createConnectorProfileInput) + out, err := conn.CreateConnectorProfile(&createConnectorProfileInput) if err != nil { return diag.Errorf("creating AppFlow Connector Profile: %s", err) } - d.SetId(name) + if out == nil || out.ConnectorProfileArn == nil { + return diag.Errorf("creating Appflow Connector Profile (%s): empty output", d.Get("name").(string)) + } + + d.SetId(aws.StringValue(out.ConnectorProfileArn)) return resourceConnectorProfileRead(ctx, d, meta) } @@ -1426,7 +1430,7 @@ func resourceConnectorProfileCreate(ctx context.Context, d *schema.ResourceData, func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn - connectorProfile, err := FindConnectorProfileByName(context.Background(), conn, d.Id()) + connectorProfile, err := FindConnectorProfileByArn(context.Background(), conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] AppFlow Connector Profile (%s) not found, removing from state", d.Id()) @@ -1454,8 +1458,6 @@ func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, m d.Set("connector_type", connectorProfile.ConnectorType) d.Set("credentials_arn", connectorProfile.CredentialsArn) - d.SetId(d.Get("name").(string)) - return nil } diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index f49902b8e6a..34939cc743d 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -96,7 +96,7 @@ func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { continue } - _, err := tfappflow.FindConnectorProfileByName(context.Background(), conn, rs.Primary.ID) + _, err := tfappflow.FindConnectorProfileByArn(context.Background(), conn, rs.Primary.ID) if _, ok := err.(*resource.NotFoundError); ok { continue diff --git a/internal/service/appflow/find.go b/internal/service/appflow/find.go index 66b73870ad0..02e1a21c649 100644 --- a/internal/service/appflow/find.go +++ b/internal/service/appflow/find.go @@ -53,10 +53,8 @@ func FindFlowByArn(ctx context.Context, conn *appflow.Appflow, arn string) (*app return result, nil } -func FindConnectorProfileByName(ctx context.Context, conn *appflow.Appflow, name string) (*appflow.ConnectorProfile, error) { - params := &appflow.DescribeConnectorProfilesInput{ - ConnectorProfileNames: []*string{aws.String(name)}, - } +func FindConnectorProfileByArn(ctx context.Context, conn *appflow.Appflow, arn string) (*appflow.ConnectorProfile, error) { + params := &appflow.DescribeConnectorProfilesInput{} var result *appflow.ConnectorProfile err := conn.DescribeConnectorProfilesPagesWithContext(ctx, params, func(page *appflow.DescribeConnectorProfilesOutput, lastPage bool) bool { @@ -69,7 +67,7 @@ func FindConnectorProfileByName(ctx context.Context, conn *appflow.Appflow, name continue } - if aws.StringValue(connectorProfile.ConnectorProfileName) == name { + if aws.StringValue(connectorProfile.ConnectorProfileArn) == arn { result = connectorProfile return false } @@ -90,7 +88,7 @@ func FindConnectorProfileByName(ctx context.Context, conn *appflow.Appflow, name if result == nil { return nil, &resource.NotFoundError{ - Message: fmt.Sprintf("No connector profile with name %q", name), + Message: fmt.Sprintf("No connector profile with arn %q", arn), LastRequest: params, } } From 5918ceaa040b45e4bc824e67e46c14f46dce1fd7 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 18:47:27 -0500 Subject: [PATCH 44/59] Add support for connector profile tags --- internal/service/appflow/connector_profile.go | 41 ++++++ .../service/appflow/connector_profile_test.go | 137 ++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index ea0c74c8055..7bd4a3e8289 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/flex" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -1389,7 +1390,10 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), }, + CustomizeDiff: verify.SetTagsDiff, } } @@ -1424,6 +1428,15 @@ func resourceConnectorProfileCreate(ctx context.Context, d *schema.ResourceData, d.SetId(aws.StringValue(out.ConnectorProfileArn)) + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) + + if len(tags) > 0 { + if err := UpdateTags(conn, d.Id(), nil, tags); err != nil { + return diag.Errorf("adding AppFlow Connector Profile (%s) tags: %s", d.Id(), err) + } + } + return resourceConnectorProfileRead(ctx, d, meta) } @@ -1458,6 +1471,25 @@ func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, m d.Set("connector_type", connectorProfile.ConnectorType) d.Set("credentials_arn", connectorProfile.CredentialsArn) + tags, err := ListTags(conn, d.Id()) + + if err != nil { + return diag.Errorf("listing tags for AppFlow Connector Profile (%s): %s", d.Id(), err) + } + + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.Errorf("setting tags: %s", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.Errorf("setting tags_all: %s", err) + } + return nil } @@ -1478,6 +1510,15 @@ func resourceConnectorProfileUpdate(ctx context.Context, d *schema.ResourceData, return diag.Errorf("updating AppFlow Connector Profile (%s): %s", d.Id(), err) } + arn := d.Get("arn").(string) + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := UpdateTags(conn, arn, o, n); err != nil { + return diag.Errorf("error updating tags: %s", err) + } + } + return resourceConnectorProfileRead(ctx, d, meta) } diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 34939cc743d..4d5aeb60134 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -88,6 +88,56 @@ func TestAccAppFlowConnectorProfile_update(t *testing.T) { }) } +func TestAccAppFlowConnectorProfile_tags(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appflow_connector_profile.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigConnectorProfile_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccConfigConnectorProfile_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccConfigConnectorProfile_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn @@ -327,3 +377,90 @@ resource "aws_appflow_connector_profile" "test" { `, connectorProfileName, redshiftPassword, redshiftUsername, bucketPrefix), ) } + +func testAccConfigConnectorProfile_tags1(connectorProfileName string, tagKey1 string, tagValue1 string) string { + const redshiftPassword = "testPassword123!" + const redshiftUsername = "testusername" + + return acctest.ConfigCompose( + testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + fmt.Sprintf(` +resource "aws_appflow_connector_profile" "test" { + name = %[1]q + connector_type = "Redshift" + connection_mode = "Public" + + connector_profile_config { + + connector_profile_credentials { + redshift { + password = %[2]q + username = %[3]q + } + } + + connector_profile_properties { + redshift { + bucket_name = %[1]q + database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" + role_arn = aws_iam_role.test.arn + } + } + } + + tags = { + %[4]q = %[5]q + } + + depends_on = [ + aws_route.test, + aws_security_group_rule.test, + ] +} +`, connectorProfileName, redshiftPassword, redshiftUsername, tagKey1, tagValue1), + ) +} + +func testAccConfigConnectorProfile_tags2(connectorProfileName string, tagKey1 string, tagValue1 string, tagKey2 string, tagValue2 string) string { + const redshiftPassword = "testPassword123!" + const redshiftUsername = "testusername" + + return acctest.ConfigCompose( + testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + fmt.Sprintf(` +resource "aws_appflow_connector_profile" "test" { + name = %[1]q + connector_type = "Redshift" + connection_mode = "Public" + + connector_profile_config { + + connector_profile_credentials { + redshift { + password = %[2]q + username = %[3]q + } + } + + connector_profile_properties { + redshift { + bucket_name = %[1]q + database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" + role_arn = aws_iam_role.test.arn + } + } + } + + tags = { + %[4]q = %[5]q + %[6]q = %[7]q + } + + depends_on = [ + aws_route.test, + aws_security_group_rule.test, + ] +} +`, connectorProfileName, redshiftPassword, redshiftUsername, tagKey1, tagValue1, tagKey2, tagValue2), + ) +} From 842a0baf1f8de446e060f872bacccfd79a639be3 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 18:47:45 -0500 Subject: [PATCH 45/59] Add Disappears test --- .../service/appflow/connector_profile_test.go | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 4d5aeb60134..0f36b094d67 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -138,6 +138,34 @@ func TestAccAppFlowConnectorProfile_tags(t *testing.T) { }) } +func TestAccAppFlowConnectorProfile_disappears(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var connectorProfiles appflow.DescribeConnectorProfilesOutput + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appflow_connector_profile.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppFlowConnectorProfile_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + acctest.CheckResourceDisappears(acctest.Provider, tfappflow.ResourceConnectorProfile(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn From 00f010d547186204c87a986e4643c94be61e5421 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Thu, 12 May 2022 18:53:49 -0500 Subject: [PATCH 46/59] Amend names of acceptance test configs + helper functions Since these functions are not exported from the service package, we do not generally include the service in these function names --- .../service/appflow/connector_profile_test.go | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 0f36b094d67..cb5798fab35 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -30,12 +30,12 @@ func TestAccAppFlowConnectorProfile_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + CheckDestroy: testAccCheckConnectorProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccAppFlowConnectorProfile_basic(rName), + Config: testAccConfigConnectorProfile_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "appflow", regexp.MustCompile(`connectorprofile/.+`)), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrSet(resourceName, "connection_mode"), @@ -69,18 +69,18 @@ func TestAccAppFlowConnectorProfile_update(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + CheckDestroy: testAccCheckConnectorProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccAppFlowConnectorProfile_basic(rName), + Config: testAccConfigConnectorProfile_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), ), }, { - Config: testAccAppFlowConnectorProfile_update(rName, testPrefix), + Config: testAccConfigConnectorProfile_update(rName, testPrefix), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "connector_profile_config.0.connector_profile_properties.0.redshift.0.bucket_prefix", testPrefix), ), }, @@ -102,12 +102,12 @@ func TestAccAppFlowConnectorProfile_tags(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + CheckDestroy: testAccCheckConnectorProfileDestroy, Steps: []resource.TestStep{ { Config: testAccConfigConnectorProfile_tags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), @@ -120,7 +120,7 @@ func TestAccAppFlowConnectorProfile_tags(t *testing.T) { { Config: testAccConfigConnectorProfile_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -129,7 +129,7 @@ func TestAccAppFlowConnectorProfile_tags(t *testing.T) { { Config: testAccConfigConnectorProfile_tags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -152,12 +152,12 @@ func TestAccAppFlowConnectorProfile_disappears(t *testing.T) { PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckAppFlowConnectorProfileDestroy, + CheckDestroy: testAccCheckConnectorProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccAppFlowConnectorProfile_basic(rName), + Config: testAccConfigConnectorProfile_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAppFlowConnectorProfileExists(resourceName, &connectorProfiles), + testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), acctest.CheckResourceDisappears(acctest.Provider, tfappflow.ResourceConnectorProfile(), resourceName), ), ExpectNonEmptyPlan: true, @@ -166,7 +166,7 @@ func TestAccAppFlowConnectorProfile_disappears(t *testing.T) { }) } -func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { +func testAccCheckConnectorProfileDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn for _, rs := range s.RootModule().Resources { @@ -190,7 +190,7 @@ func testAccCheckAppFlowConnectorProfileDestroy(s *terraform.State) error { return nil } -func testAccCheckAppFlowConnectorProfileExists(n string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { +func testAccCheckConnectorProfileExists(n string, res *appflow.DescribeConnectorProfilesOutput) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppFlowConn @@ -221,7 +221,7 @@ func testAccCheckAppFlowConnectorProfileExists(n string, res *appflow.DescribeCo } } -func testAccAppFlowConnectorProfileConfigBase(connectorProfileName string, redshiftPassword string, redshiftUsername string) string { +func testAccConnectorProfileConfigBase(connectorProfileName string, redshiftPassword string, redshiftUsername string) string { return acctest.ConfigCompose( acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` @@ -327,12 +327,12 @@ resource "aws_redshift_cluster" "test" { `, connectorProfileName, redshiftPassword, redshiftUsername)) } -func testAccAppFlowConnectorProfile_basic(connectorProfileName string) string { +func testAccConfigConnectorProfile_basic(connectorProfileName string) string { const redshiftPassword = "testPassword123!" const redshiftUsername = "testusername" return acctest.ConfigCompose( - testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { name = %[1]q @@ -366,12 +366,12 @@ resource "aws_appflow_connector_profile" "test" { ) } -func testAccAppFlowConnectorProfile_update(connectorProfileName string, bucketPrefix string) string { +func testAccConfigConnectorProfile_update(connectorProfileName string, bucketPrefix string) string { const redshiftPassword = "testPassword123!" const redshiftUsername = "testusername" return acctest.ConfigCompose( - testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { name = %[1]q @@ -411,7 +411,7 @@ func testAccConfigConnectorProfile_tags1(connectorProfileName string, tagKey1 st const redshiftUsername = "testusername" return acctest.ConfigCompose( - testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { name = %[1]q @@ -454,7 +454,7 @@ func testAccConfigConnectorProfile_tags2(connectorProfileName string, tagKey1 st const redshiftUsername = "testusername" return acctest.ConfigCompose( - testAccAppFlowConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), + testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), fmt.Sprintf(` resource "aws_appflow_connector_profile" "test" { name = %[1]q From b4b5c102f7622416ac3c6b39170cf9c0876cccc5 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 00:59:05 -0500 Subject: [PATCH 47/59] Revert "Add support for connector profile tags" This reverts commit 5918ceaa040b45e4bc824e67e46c14f46dce1fd7. Connector profiles do not appear to support tagging. The following AWS CLI operation errors out: aws appflow tag-resource --resource-arn --tags KeyName1=string Returns "Invalud input resource arn" --- internal/service/appflow/connector_profile.go | 41 ------ .../service/appflow/connector_profile_test.go | 137 ------------------ 2 files changed, 178 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 7bd4a3e8289..ea0c74c8055 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/flex" - tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -1390,10 +1389,7 @@ func ResourceConnectorProfile() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "tags": tftags.TagsSchema(), - "tags_all": tftags.TagsSchemaComputed(), }, - CustomizeDiff: verify.SetTagsDiff, } } @@ -1428,15 +1424,6 @@ func resourceConnectorProfileCreate(ctx context.Context, d *schema.ResourceData, d.SetId(aws.StringValue(out.ConnectorProfileArn)) - defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig - tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - - if len(tags) > 0 { - if err := UpdateTags(conn, d.Id(), nil, tags); err != nil { - return diag.Errorf("adding AppFlow Connector Profile (%s) tags: %s", d.Id(), err) - } - } - return resourceConnectorProfileRead(ctx, d, meta) } @@ -1471,25 +1458,6 @@ func resourceConnectorProfileRead(ctx context.Context, d *schema.ResourceData, m d.Set("connector_type", connectorProfile.ConnectorType) d.Set("credentials_arn", connectorProfile.CredentialsArn) - tags, err := ListTags(conn, d.Id()) - - if err != nil { - return diag.Errorf("listing tags for AppFlow Connector Profile (%s): %s", d.Id(), err) - } - - defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig - ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - - //lintignore:AWSR002 - if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return diag.Errorf("setting tags: %s", err) - } - - if err := d.Set("tags_all", tags.Map()); err != nil { - return diag.Errorf("setting tags_all: %s", err) - } - return nil } @@ -1510,15 +1478,6 @@ func resourceConnectorProfileUpdate(ctx context.Context, d *schema.ResourceData, return diag.Errorf("updating AppFlow Connector Profile (%s): %s", d.Id(), err) } - arn := d.Get("arn").(string) - - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - if err := UpdateTags(conn, arn, o, n); err != nil { - return diag.Errorf("error updating tags: %s", err) - } - } - return resourceConnectorProfileRead(ctx, d, meta) } diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index cb5798fab35..7f92aaaff77 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -88,56 +88,6 @@ func TestAccAppFlowConnectorProfile_update(t *testing.T) { }) } -func TestAccAppFlowConnectorProfile_tags(t *testing.T) { - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - - var connectorProfiles appflow.DescribeConnectorProfilesOutput - - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_appflow_connector_profile.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, appflow.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckConnectorProfileDestroy, - Steps: []resource.TestStep{ - { - Config: testAccConfigConnectorProfile_tags1(rName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccConfigConnectorProfile_tags2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - { - Config: testAccConfigConnectorProfile_tags1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckConnectorProfileExists(resourceName, &connectorProfiles), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - }, - }) -} - func TestAccAppFlowConnectorProfile_disappears(t *testing.T) { if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -405,90 +355,3 @@ resource "aws_appflow_connector_profile" "test" { `, connectorProfileName, redshiftPassword, redshiftUsername, bucketPrefix), ) } - -func testAccConfigConnectorProfile_tags1(connectorProfileName string, tagKey1 string, tagValue1 string) string { - const redshiftPassword = "testPassword123!" - const redshiftUsername = "testusername" - - return acctest.ConfigCompose( - testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), - fmt.Sprintf(` -resource "aws_appflow_connector_profile" "test" { - name = %[1]q - connector_type = "Redshift" - connection_mode = "Public" - - connector_profile_config { - - connector_profile_credentials { - redshift { - password = %[2]q - username = %[3]q - } - } - - connector_profile_properties { - redshift { - bucket_name = %[1]q - database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" - role_arn = aws_iam_role.test.arn - } - } - } - - tags = { - %[4]q = %[5]q - } - - depends_on = [ - aws_route.test, - aws_security_group_rule.test, - ] -} -`, connectorProfileName, redshiftPassword, redshiftUsername, tagKey1, tagValue1), - ) -} - -func testAccConfigConnectorProfile_tags2(connectorProfileName string, tagKey1 string, tagValue1 string, tagKey2 string, tagValue2 string) string { - const redshiftPassword = "testPassword123!" - const redshiftUsername = "testusername" - - return acctest.ConfigCompose( - testAccConnectorProfileConfigBase(connectorProfileName, redshiftPassword, redshiftUsername), - fmt.Sprintf(` -resource "aws_appflow_connector_profile" "test" { - name = %[1]q - connector_type = "Redshift" - connection_mode = "Public" - - connector_profile_config { - - connector_profile_credentials { - redshift { - password = %[2]q - username = %[3]q - } - } - - connector_profile_properties { - redshift { - bucket_name = %[1]q - database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" - role_arn = aws_iam_role.test.arn - } - } - } - - tags = { - %[4]q = %[5]q - %[6]q = %[7]q - } - - depends_on = [ - aws_route.test, - aws_security_group_rule.test, - ] -} -`, connectorProfileName, redshiftPassword, redshiftUsername, tagKey1, tagValue1, tagKey2, tagValue2), - ) -} From fa390e403e87322bdbb029ff97ae3b9ececde182 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 01:42:56 -0500 Subject: [PATCH 48/59] Use more resource references in connection profile acceptance test config --- internal/service/appflow/connector_profile_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 7f92aaaff77..419f6ebbe37 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -293,8 +293,8 @@ resource "aws_appflow_connector_profile" "test" { connector_profile_credentials { redshift { - password = %[2]q - username = %[3]q + password = aws_redshift_cluster.test.master_password + username = aws_redshift_cluster.test.master_username } } @@ -332,8 +332,8 @@ resource "aws_appflow_connector_profile" "test" { connector_profile_credentials { redshift { - password = %[2]q - username = %[3]q + password = aws_redshift_cluster.test.master_password + username = aws_redshift_cluster.test.master_username } } From 125b13b0dae845688bea2307f628c60cf18524d8 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 01:44:12 -0500 Subject: [PATCH 49/59] Amend Delete function to account for use of arn as ID --- internal/service/appflow/connector_profile.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index ea0c74c8055..4d2088431d4 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1483,8 +1483,13 @@ func resourceConnectorProfileUpdate(ctx context.Context, d *schema.ResourceData, func resourceConnectorProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).AppFlowConn - _, err := conn.DeleteConnectorProfile(&appflow.DeleteConnectorProfileInput{ - ConnectorProfileName: aws.String(d.Id()), + + out, _ := FindConnectorProfileByArn(ctx, conn, d.Id()) + + log.Printf("[INFO] Deleting AppFlow Flow %s", d.Id()) + + _, err := conn.DeleteConnectorProfileWithContext(ctx, &appflow.DeleteConnectorProfileInput{ + ConnectorProfileName: out.ConnectorProfileName, }) if err != nil { From 2c66e172784c9c946ea4ca9472b849f37f7cb50e Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 02:22:16 -0500 Subject: [PATCH 50/59] Add support for CustomConnector credentials of type apiKey --- internal/service/appflow/connector_profile.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/internal/service/appflow/connector_profile.go b/internal/service/appflow/connector_profile.go index 4d2088431d4..d0f83d97315 100644 --- a/internal/service/appflow/connector_profile.go +++ b/internal/service/appflow/connector_profile.go @@ -1583,6 +1583,10 @@ func expandCustomConnectorProfileCredentials(m map[string]interface{}) *appflow. AuthenticationType: aws.String(m["authentication_type"].(string)), } + if v, ok := m["api_key"].([]interface{}); ok && len(v) > 0 { + credentials.ApiKey = expandApiKeyCredentials(v[0].(map[string]interface{})) + } + if v, ok := m["basic"].([]interface{}); ok && len(v) > 0 { credentials.Basic = expandBasicAuthCredentials(v[0].(map[string]interface{})) } @@ -1812,6 +1816,20 @@ func expandOAuthRequest(m map[string]interface{}) *appflow.ConnectorOAuthRequest return &r } +func expandApiKeyCredentials(m map[string]interface{}) *appflow.ApiKeyCredentials { + credentials := appflow.ApiKeyCredentials{} + + if v, ok := m["api_key"].(string); ok && v != "" { + credentials.ApiKey = aws.String(v) + } + + if v, ok := m["api_secret_key"].(string); ok && v != "" { + credentials.ApiSecretKey = aws.String(v) + } + + return &credentials +} + func expandBasicAuthCredentials(m map[string]interface{}) *appflow.BasicAuthCredentials { credentials := appflow.BasicAuthCredentials{} From 9c7178b4afaefac8234f12049bf91d4021abad4c Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 02:30:54 -0500 Subject: [PATCH 51/59] Edit docs for AppFlow connector profile resource --- .../r/appflow_connector_profile.html.markdown | 360 +++++++----------- 1 file changed, 133 insertions(+), 227 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index d7257867b40..f3e6cfe0106 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -3,391 +3,297 @@ subcategory: "AppFlow" layout: "aws" page_title: "AWS: aws_appflow_connector_profile" description: |- - Provides an AppFlow connector profile resource. + Provides an AppFlow Connector Profile resource. --- # Resource: aws_appflow_connector_profile -Creates an AWS AppFlow connector profile. +Provides an AppFlow connector profile resource. -For information about AppFlow flows, see the -[Amazon AppFlow API Reference][1]. For specific information about creating -AppFlow connector profile, see the [CreateConnectorProfile][2] page in the Amazon -AppFlow API Reference. +For information about AppFlow flows, see the [Amazon AppFlow API Reference][1]. +For specific information about creating an AppFlow connector profile, see the +[CreateConnectorProfile][2] page in the Amazon AppFlow API Reference. ## Example Usage -### Amplitude - ```terraform -resource "aws_appflow_connector_profile" "amplitude" { - name = "amplitude-connector" - connection_mode = "Public" - connector_type = "Amplitude" +data "aws_iam_policy" "example" { + name = "AmazonRedshiftAllCommandsFullAccess" +} - connector_profile_config { - connector_profile_credentials { - amplitude { - api_key = "0123456789abcdef0123456789abcdef" - secret_key = "0123456789abcdef0123456789abcdef" - } - } - connector_profile_properties { - amplitude { - } - } - } +resource "aws_iam_role" "example" { + name = "example_role" + + managed_policy_arns = [data.aws_iam_policy.test.arn] + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) } -``` -### Zendesk +resource "aws_s3_bucket" "example" { + bucket = "example_bucket" +} -```terraform -data "aws_region" "current" {} +resource "aws_redshift_cluster" "example" { + cluster_identifier = "example_cluster" + database_name = "example_db" + master_username = "exampleuser" + master_password = "examplePassword123!" + node_type = "dc1.large" + cluster_type = "single-node" +} -resource "aws_appflow_connector_profile" "zendesk" { - name = "zendesk-connector" +resource "aws_appflow_connector_profile" "example" { + name = "example_profile" + connector_type = "Redshift" connection_mode = "Public" - connector_type = "Zendesk" connector_profile_config { + connector_profile_credentials { - zendesk { - client_id = "zendesk-client-id" - client_secret = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - access_token = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - oauth_request { - redirect_uri = "https://${data.aws_region.current.name}.console.aws.amazon.com/appflow/oauth" - } + redshift { + password = aws_redshift_cluster.example.master_password + username = aws_redshift_cluster.example.master_username } } + connector_profile_properties { - zendesk { - instance_url = "https://subdomain.zendesk.com" + redshift { + bucket_name = aws_s3_bucket.example.name + database_url = "jdbc:redshift://${aws_redshift_cluster.example.endpoint}/${aws_redshift_cluster.example.database_name" + role_arn = aws_iam_role.example.arn } } } } ``` - ## Argument Reference -The AppFlow connector profile argument layout is a complex structure. - -### Top-Level Arguments - -* `name ` (Required) - The name of the connector profile. The name is unique for each ConnectorProfile in your AWS account. +The AppFlow connector profile argument layout is a complex structure. The following top-level arguments are supports: +* `name ` (Required) - The name of the connector profile. The name is unique for each `ConnectorProfile` in your AWS account. * `connection_mode` (Required) - Indicates the connection mode and specifies whether it is public or private. Private flows use AWS PrivateLink to route data over AWS infrastructure without exposing it to the public internet. One of: `Public`, `Private`. - -* `connector_type` (Required) - The type of connector. One of: `Amplitude`, `CustomConnector`, `CustomerProfiles`, `Datadog`, `Dynatrace`, `EventBridge`, `Googleanalytics`, `Honeycode`, `Infornexus`, `LookoutMetrics`, `Marketo`, `Redshift`, `S3`, `Salesforce`, `SAPOData`, `Servicenow`, `Singular`, `Slack`, `Snowflake`, `Trendmicro`, `Upsolver`, `Veeva`, `Zendesk`. - -* `connector_profile_config` (Required) - Defines the connector-specific [configuration and credentials](#connector-profile-config-arguments). - * `connector_label` (Optional) - The label of the connector. The label is unique for each ConnectorRegistration in your AWS account. Only needed if calling for `CustomConnector` connector type. - +* `connector_profile_config` (Required) - Defines the connector-specific configuration and credentials. See [Connector Profile Config](#connector-profile-config) for more details. +* `connector_type` (Required) - The type of connector. One of: `Amplitude`, `CustomConnector`, `CustomerProfiles`, `Datadog`, `Dynatrace`, `EventBridge`, `Googleanalytics`, `Honeycode`, `Infornexus`, `LookoutMetrics`, `Marketo`, `Redshift`, `S3`, `Salesforce`, `SAPOData`, `Servicenow`, `Singular`, `Slack`, `Snowflake`, `Trendmicro`, `Upsolver`, `Veeva`, `Zendesk`. * `kms_arn` (Optional) - The ARN (Amazon Resource Name) of the Key Management Service (KMS) key you provide for encryption. This is required if you do not want to use the Amazon AppFlow-managed KMS key. If you don't provide anything here, Amazon AppFlow uses the Amazon AppFlow-managed KMS key. -#### Connector Profile Config Arguments - -* `connector_profile_credentials` (Required) - The connector-specific [credentials](#connector-profile-credentials-arguments) required by each connector. - -* `connector_profile_properties` (Required) - The connector-specific [properties](#connector-profile-properties-arguments) of the profile configuration. - - -##### Connector Profile Credentials Arguments - -* `amplitude` (Optional) - The connector-specific [credentials](#amplitude-connector-profile-credentials-arguments) required when using Amplitude. - -* `custom_connector` (Optional) - The connector-specific profile [credentials](#custom-connector-profile-credentials-arguments) required when using the custom connector. - -* `datadog` (Optional) - The connector-specific [credentials](#datadog-connector-profile-credentials-arguments) required when using Datadog. - -* `dynatrace` (Optional) - The connector-specific [credentials](#dynatrace-connector-profile-credentials-arguments) required when using Dynatrace. - -* `google_analytics` (Optional) - The connector-specific [credentials](#google-analytics-connector-profile-credentials-arguments) required when using Google Analytics. - -* `honeycode` (Optional) - The connector-specific [credentials](#honeycode-connector-profile-credentials-arguments) required when using Amazon Honeycode. - -* `infor_nexus` (Optional) - The connector-specific [credentials](#infor-nexus-connector-profile-credentials-arguments) required when using Infor Nexus. - -* `marketo` (Optional) - The connector-specific [credentials](#marketo-connector-profile-credentials-arguments) required when using Marketo. - -* `redshift` (Optional) - The connector-specific [credentials](#redshift-connector-profile-credentials-arguments) required when using Amazon Redshift. - -* `salesforce` (Optional) - The connector-specific [credentials](#salesforce-connector-profile-credentials-arguments) required when using Salesforce. - -* `service_now` (Optional) - The connector-specific [credentials](#servicenow-connector-profile-credentials-arguments) required when using ServiceNow. - -* `singular` (Optional) - The connector-specific [credentials](#singular-connector-profile-credentials-arguments) required when using Singular. - -* `slack` (Optional) - The connector-specific [credentials](#slack-connector-profile-credentials-arguments) required when using Slack. - -* `snowflake` (Optional) - The connector-specific [credentials](#snowflake-connector-profile-credentials-arguments) required when using Snowflake. - -* `trendmicro` (Optional) - The connector-specific [credentials](#trendmicro-connector-profile-credentials-arguments) required when using Trend Micro. - -* `veeva` (Optional) - The connector-specific [credentials](#veeva-connector-profile-credentials-arguments) required when using Veeva. - -* `zendesk` (Optional) - The connector-specific [credentials](#zendesk-connector-profile-credentials-arguments) required when using Zendesk. - -##### Amplitude Connector Profile Credentials Arguments +### Connector Profile Config + +* `connector_profile_credentials` (Required) - The connector-specific credentials required by each connector. See [Connector Profile Credentials](#connector-profile-credentials) for more details. +* `connector_profile_properties` (Required) - The connector-specific properties of the profile configuration. See [Connector Profile Properties](#connector-profile-properties) for more details. + +### Connector Profile Credentials + +* `amplitude` (Optional) - The connector-specific credentials required when using Amplitude. See [Amplitude Connector Profile Credentials](#amplitude-connector-profile-credentials) for more details. +* `custom_connector` (Optional) - The connector-specific profile credentials required when using the custom connector. See [Custom Connector Profile Credentials](#custom-connector-profile-credentials) for more details. +* `datadog` (Optional) - The connector-specific credentials required when using Datadog. See [Datadog Connector Profile Credentials](#datadog-connector-profile-credentials) for more details. +* `dynatrace` (Optional) - The connector-specific credentials required when using Dynatrace. See [Dynatrace Connector Profile Credentials](#dynatrace-connector-profile-credentials) for more details. +* `google_analytics` (Optional) - The connector-specific credentials required when using Google Analytics. See [Google Analytics Connector Profile Credentials](#google-analytics-connector-profile-credentials) for more details. +* `honeycode` (Optional) - The connector-specific credentials required when using Amazon Honeycode. See [Honeycode Connector Profile Credentials](#honeycode-connector-profile-credentials) for more details. +* `infor_nexus` (Optional) - The connector-specific credentials required when using Infor Nexus. See [Infor Nexus Connector Profile Credentials](#infor-nexus-connector-profile-credentials) for more details. +* `marketo` (Optional) - The connector-specific credentials required when using Marketo. See [Marketo Connector Profile Credentials](#marketo-connector-profile-credentials) for more details. +* `redshift` (Optional) - The connector-specific credentials required when using Amazon Redshift. See [Redshift Connector Profile Credentials](#redshift-connector-profile-credentials) for more details. +* `salesforce` (Optional) - The connector-specific credentials required when using Salesforce. See [Salesforce Connector Profile Credentials](#salesforce-connector-profile-credentials) for more details. +* `sapo_data` (Optional) - The connector-specific credentials required when using SAPOData. See [SAPOData Connector Profile Credentials](#sapodata-connector-profile-credentials) for more details. +* `service_now` (Optional) - The connector-specific credentials required when using ServiceNow. See [ServiceNow Connector Profile Credentials](#service-now-connector-profile-credentials) for more details. +* `singular` (Optional) - The connector-specific credentials required when using Singular. See [Singular Connector Profile Credentials](#singular-connector-profile-credentials) for more details. +* `slack` (Optional) - The connector-specific credentials required when using Slack. See [Slack Connector Profile Credentials](#amplitude-connector-profile-credentials) for more details. +* `snowflake` (Optional) - The connector-specific credentials required when using Snowflake. See [Snowflake Connector Profile Credentials](#snowflake-connector-profile-credentials) for more details. +* `trendmicro` (Optional) - The connector-specific credentials required when using Trend Micro. See [Trend Micro Connector Profile Credentials](#trendmicro-connector-profile-credentials) for more details. +* `veeva` (Optional) - The connector-specific credentials required when using Veeva. See [Veeva Connector Profile Credentials](#veeva-connector-profile-credentials) for more details. +* `zendesk` (Optional) - The connector-specific credentials required when using Zendesk. See [Zendesk Connector Profile Credentials](#zendesk-connector-profile-credentials) for more details. + +#### Amplitude Connector Profile Credentials * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. - * `secret_key` (Required) - The Secret Access Key portion of the credentials. -##### Custom Connector Profile Credentials Arguments +#### Custom Connector Profile Credentials Arguments -* `api_key` (Optional) - The API keys required for the authentication of the user. +* `api_key` (Optional) - The API keys required for the authentication of the user. * `api_key` (Required) - The API key required for API key authentication. * `api_secret_key` (Optional) - The API secret key required for API key authentication. - * `authentication_type` (Required) - The authentication type that the custom connector uses for authenticating while creating a connector profile. One of: `APIKEY`, `BASIC`, `CUSTOM`, `OAUTH2`. - * `basic` (Optional) - The basic credentials that are required for the authentication of the user. * `password` (Required) - The password to use to connect to a resource. * `username` (Required) - The username to use to connect to a resource. - * `custom` (Optional) - If the connector uses the custom authentication mechanism, this holds the required credentials. * `credentials_map` (Optional) - A map that holds custom authentication credentials. * `custom_authentication_type` (Required) - The custom authentication type that the connector uses. - * `oauth2` (Optional) - The OAuth 2.0 credentials required for the authentication of the user. * `access_token` (Optional) - The access token used to access the connector on your behalf. * `client_id` (Optional) - The identifier for the desired client. * `client_secret` (Optional) - The client secret used by the OAuth client to authenticate to the authorization server. - * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. - * `auth_code` (Optional) - The code provided by the connector when it has been authenticated via the connected app. - * `redirect_uri` (Optional) - The URL to which the authentication server redirects the browser after authorization has been granted. + * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The refresh token used to refresh an expired access token. -##### Datadog Connector Profile Credentials Arguments +#### Datadog Connector Profile Credentials Arguments * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. - * `application_key` (Required) - Application keys, in conjunction with your API key, give you full access to Datadog’s programmatic API. Application keys are associated with the user account that created them. The application key is used to log all requests made to the API. -##### Dynatrace Connector Profile Credentials Arguments +#### Dynatrace Connector Profile Credentials Arguments * `api_token` (Required) - The API tokens used by Dynatrace API to authenticate various API calls. -##### Google Analytics Connector Profile Credentials Arguments +#### Google Analytics Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Google Analytics resources. - * `client_id` (Required) - The identifier for the desired client. - * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. - -* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. - +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. This is required only for OAuth2 access tokens, and is not required for OAuth1 access tokens. -##### Honeycode Connector Profile Credentials Arguments +#### Honeycode Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Amazon Honeycode resources. - -* `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported, such as Salesforce, Google Analytics, Marketo, Zendesk, and Slack. - +* `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported, such as Salesforce, Google Analytics, Marketo, Zendesk, and Slack. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. -##### Infor Nexus Connector Profile Credentials Arguments +#### Infor Nexus Connector Profile Credentials Arguments * `access_key_id` (Required) - The Access Key portion of the credentials. - * `datakey` (Required) - The encryption keys used to encrypt data. - * `secret_access_key` (Required) - The secret key used to sign requests. - * `user_id` (Required) - The identifier for the user. -##### Marketo Connector Profile Credentials Arguments +#### Marketo Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Marketo resources. - * `client_id` (Required) - The identifier for the desired client. - * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. -* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. - -##### Redshift Connector Profile Credentials Arguments +#### Redshift Connector Profile Credentials Arguments * `password` (Required) - The password that corresponds to the user name. - * `username` (Required) - The name of the user. -##### Salesforce Connector Profile Credentials Arguments +#### Salesforce Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Salesforce resources. - * `client_credentials_arn` (Optional) - The secret manager ARN, which contains the client ID and client secret of the connected app. - -* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. - +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. -##### ServiceNow Connector Profile Credentials Arguments +#### ServiceNow Connector Profile Credentials Arguments * `password` (Required) - The password that corresponds to the user name. - * `username` (Required) - The name of the user. -##### Singular Connector Profile Credentials Arguments +#### Singular Connector Profile Credentials Arguments * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. -##### Slack Connector Profile Credentials Arguments +#### Slack Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Slack resources. - * `client_id` (Required) - The identifier for the client. - * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. -* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. - -##### Snowflake Connector Profile Credentials Arguments +#### Snowflake Connector Profile Credentials Arguments * `password` (Required) - The password that corresponds to the user name. - * `username` (Required) - The name of the user. -##### Trendmicro Connector Profile Credentials Arguments +#### Trendmicro Connector Profile Credentials Arguments * `api_secret_key` (Required) - The Secret Access Key portion of the credentials. -##### Veeva Connector Profile Credentials Arguments +#### Veeva Connector Profile Credentials Arguments * `password` (Required) - The password that corresponds to the user name. - * `username` (Required) - The name of the user. -##### Zendesk Connector Profile Credentials Arguments +#### Zendesk Connector Profile Credentials Arguments * `access_token` (Optional) - The credentials used to access protected Zendesk resources. - * `client_id` (Required) - The identifier for the desired client. - * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. - -* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. - -##### Connector Profile Properties Arguments - -* `custom_connector` (Optional) - The [properties](#custom-connector-profile-properties-arguments) required by the custom connector. - -* `datadog` (Optional) - The connector-specific [properties](#datadog-connector-profile-properties-arguments) required by Datadog. - -* `dynatrace` (Optional) - The connector-specific [properties](#dynatrace-connector-profile-properties-arguments) required by Dynatrace. - -* `infor_nexus` (Optional) - The connector-specific [properties](#infor-nexus-connector-profile-properties-arguments) required by Infor Nexus. - -* `marketo` (Optional) - The connector-specific [properties](#marketo-connector-profile-properties-arguments) required by Marketo. - -* `redshift` (Optional) - The connector-specific [properties](#redshift-connector-profile-properties-arguments) required by Amazon Redshift. - -* `salesforce` (Optional) - The connector-specific [properties](#salesforce-connector-profile-properties-arguments) required by Salesforce. - -* `service_now` (Optional) - The connector-specific [properties](#servicenow-connector-profile-properties-arguments) required by ServiceNow. - -* `slack` (Optional) - The connector-specific [properties](#slack-connector-profile-properties-arguments) required by Slack. - -* `snowflake` (Optional) - The connector-specific [properties](#snowflake-connector-profile-properties-arguments) required by Snowflake. - -* `veeva` (Optional) - The connector-specific [properties](#veeva-connector-profile-properties-arguments) required by Veeva. - -* `zendesk` (Optional) - The connector-specific [properties](#zendesk-connector-profile-properties-arguments) required by Zendesk. - -##### Custom Connector Profile Properties Arguments +* `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. + +### Connector Profile Properties + +* `custom_connector` (Optional) - The connector-specific profile properties required when using the custom connector. See [Custom Connector Profile Properties](#custom-connector-profile-properties) for more details. +* `datadog` (Optional) - The connector-specific properties required when using Datadog. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `dynatrace` (Optional) - The connector-specific properties required when using Dynatrace. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `google_analytics` (Optional) - The connector-specific properties required when using Google Analytics. See [Google Analytics Connector Profile Properties](#google-analytics-connector-profile-properties) for more details. +* `honeycode` (Optional) - The connector-specific properties required when using Amazon Honeycode. See [Honeycode Connector Profile Properties](#honeycode-connector-profile-properties) for more details. +* `infor_nexus` (Optional) - The connector-specific properties required when using Infor Nexus. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `marketo` (Optional) - The connector-specific properties required when using Marketo. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `redshift` (Optional) - The connector-specific properties required when using Amazon Redshift. See [Redshift Connector Profile Properties](#redshift-connector-profile-properties) for more details. +* `salesforce` (Optional) - The connector-specific properties required when using Salesforce. See [Salesforce Connector Profile Properties](#salesforce-connector-profile-properties) for more details. +* `sapo_data` (Optional) - The connector-specific properties required when using SAPOData. See [SAPOData Connector Profile Properties](#sapodata-connector-profile-properties) for more details. +* `service_now` (Optional) - The connector-specific properties required when using ServiceNow. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `singular` (Optional) - The connector-specific properties required when using Singular. See [Singular Connector Profile Properties](#singular-connector-profile-properties) for more details. +* `slack` (Optional) - The connector-specific properties required when using Slack. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `snowflake` (Optional) - The connector-specific properties required when using Snowflake. See [Snowflake Connector Profile Properties](#snowflake-connector-profile-properties) for more details. +* `veeva` (Optional) - The connector-specific properties required when using Veeva. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. +* `zendesk` (Optional) - The connector-specific properties required when using Zendesk. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. + +#### Custom Connector Profile Properties * `oauth2_properties` (Optional) - The OAuth 2.0 properties required for OAuth 2.0 authentication. * `oauth2_grant_type` (Required) - The OAuth 2.0 grant type used by connector for OAuth 2.0 authentication. One of: `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`. * `token_url` (Required) - The token URL required for OAuth 2.0 authentication. * `token_url_custom_properties` (Optional) - Associates your token URL with a map of properties that you define. Use this parameter to provide any additional details that the connector requires to authenticate your request. - * `profile_properties` (Optional) - A map of properties that are required to create a profile for the custom connector. -##### Datadog Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Datadog resource. - -##### Dynatrace Connector Profile Properties Arguments +#### Generic Connector Profile Properties -* `instance_url` (Required) - The location of the Dynatrace resource. +Datadog, Dynatrace, Infor Nexus, Marketo, ServiceNow, Slack, Veeva, and Zendesk all support the following attributes: -##### Infor Nexus Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Infor Nexus resource. - -##### Marketo Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Marketo resource. +* `instance_url` (Required) - The location of the Datadog resource. -##### Redshift Connector Profile Properties Arguments +#### Redshift Connector Profile Properties * `bucket_name` (Required) - A name for the associated Amazon S3 bucket. - * `bucket_prefix` (Optional) - The object key for the destination bucket in which Amazon AppFlow places the files. - * `database_url` (Required) - The JDBC URL of the Amazon Redshift cluster. - * `role_arn` (Required) - The Amazon Resource Name (ARN) of the IAM role. -##### Salesforce Connector Profile Properties Arguments +#### Salesforce Connector Profile Properties * `instance_url` (Optional) - The location of the Salesforce resource. - * `is_sandbox_environment` (Optional) - Indicates whether the connector profile applies to a sandbox or production environment. -##### ServiceNow Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the ServiceNow resource. - -##### Slack Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Slack resource. - -##### Snowflake Connector Profile Properties Arguments +#### Snowflake Connector Profile Properties * `account_name` (Optional) - The name of the account. - * `bucket_name` (Required) - The name of the Amazon S3 bucket associated with Snowflake. - * `bucket_prefix` (Optional) - The bucket path that refers to the Amazon S3 bucket associated with Snowflake. - * `private_link_service_name` (Optional) - The Snowflake Private Link service name to be used for private data transfers. - * `region` (Optional) - The AWS Region of the Snowflake account. - * `stage` (Required) - The name of the Amazon S3 stage that was created while setting up an Amazon S3 stage in the Snowflake account. This is written in the following format: `..`. - * `warehouse` (Required) - The name of the Snowflake warehouse. -##### Veeva Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Veeva resource. - -##### Zendesk Connector Profile Properties Arguments - -* `instance_url` (Required) - The location of the Zendesk resource. - ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the connector profile. - * `credentials_arn` - The Amazon Resource Name (ARN) of the connector profile credentials. ## Import -AppFlow Connector Profile can be imported using the connector profile name, e.g. +AppFlow Connector Profile can be imported using the connector profile `arn`, e.g. ``` -$ terraform import aws_appflow_connector_profile.profile connector-profile-name +$ terraform import aws_appflow_connector_profile.profile arn:aws:appflow:us-west-2:123456789012:connectorprofile/example-profile ``` [1]: https://docs.aws.amazon.com/appflow/1.0/APIReference/Welcome.html From 64f9a61b609c3da5d8aba7215fff5064e5cdab90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Fri, 13 May 2022 09:40:15 +0200 Subject: [PATCH 52/59] Remove trailing whitespace in markdown --- .../r/appflow_connector_profile.html.markdown | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index f3e6cfe0106..10366c3c1f1 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -95,7 +95,7 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `connector_profile_credentials` (Required) - The connector-specific credentials required by each connector. See [Connector Profile Credentials](#connector-profile-credentials) for more details. * `connector_profile_properties` (Required) - The connector-specific properties of the profile configuration. See [Connector Profile Properties](#connector-profile-properties) for more details. -### Connector Profile Credentials +### Connector Profile Credentials * `amplitude` (Optional) - The connector-specific credentials required when using Amplitude. See [Amplitude Connector Profile Credentials](#amplitude-connector-profile-credentials) for more details. * `custom_connector` (Optional) - The connector-specific profile credentials required when using the custom connector. See [Custom Connector Profile Credentials](#custom-connector-profile-credentials) for more details. @@ -116,14 +116,14 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `veeva` (Optional) - The connector-specific credentials required when using Veeva. See [Veeva Connector Profile Credentials](#veeva-connector-profile-credentials) for more details. * `zendesk` (Optional) - The connector-specific credentials required when using Zendesk. See [Zendesk Connector Profile Credentials](#zendesk-connector-profile-credentials) for more details. -#### Amplitude Connector Profile Credentials +#### Amplitude Connector Profile Credentials * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. * `secret_key` (Required) - The Secret Access Key portion of the credentials. #### Custom Connector Profile Credentials Arguments -* `api_key` (Optional) - The API keys required for the authentication of the user. +* `api_key` (Optional) - The API keys required for the authentication of the user. * `api_key` (Required) - The API key required for API key authentication. * `api_secret_key` (Optional) - The API secret key required for API key authentication. * `authentication_type` (Required) - The authentication type that the custom connector uses for authenticating while creating a connector profile. One of: `APIKEY`, `BASIC`, `CUSTOM`, `OAUTH2`. @@ -226,7 +226,7 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. -### Connector Profile Properties +### Connector Profile Properties * `custom_connector` (Optional) - The connector-specific profile properties required when using the custom connector. See [Custom Connector Profile Properties](#custom-connector-profile-properties) for more details. * `datadog` (Optional) - The connector-specific properties required when using Datadog. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. @@ -245,7 +245,7 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `veeva` (Optional) - The connector-specific properties required when using Veeva. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. * `zendesk` (Optional) - The connector-specific properties required when using Zendesk. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. -#### Custom Connector Profile Properties +#### Custom Connector Profile Properties * `oauth2_properties` (Optional) - The OAuth 2.0 properties required for OAuth 2.0 authentication. * `oauth2_grant_type` (Required) - The OAuth 2.0 grant type used by connector for OAuth 2.0 authentication. One of: `AUTHORIZATION_CODE`, `CLIENT_CREDENTIALS`. @@ -253,25 +253,25 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `token_url_custom_properties` (Optional) - Associates your token URL with a map of properties that you define. Use this parameter to provide any additional details that the connector requires to authenticate your request. * `profile_properties` (Optional) - A map of properties that are required to create a profile for the custom connector. -#### Generic Connector Profile Properties +#### Generic Connector Profile Properties Datadog, Dynatrace, Infor Nexus, Marketo, ServiceNow, Slack, Veeva, and Zendesk all support the following attributes: * `instance_url` (Required) - The location of the Datadog resource. -#### Redshift Connector Profile Properties +#### Redshift Connector Profile Properties * `bucket_name` (Required) - A name for the associated Amazon S3 bucket. * `bucket_prefix` (Optional) - The object key for the destination bucket in which Amazon AppFlow places the files. * `database_url` (Required) - The JDBC URL of the Amazon Redshift cluster. * `role_arn` (Required) - The Amazon Resource Name (ARN) of the IAM role. -#### Salesforce Connector Profile Properties +#### Salesforce Connector Profile Properties * `instance_url` (Optional) - The location of the Salesforce resource. * `is_sandbox_environment` (Optional) - Indicates whether the connector profile applies to a sandbox or production environment. -#### Snowflake Connector Profile Properties +#### Snowflake Connector Profile Properties * `account_name` (Optional) - The name of the account. * `bucket_name` (Required) - The name of the Amazon S3 bucket associated with Snowflake. From 0cce34be7dc25653320c8d4fe4e4ddbf9f9d2bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Fri, 13 May 2022 09:42:48 +0200 Subject: [PATCH 53/59] Remove redundant "Arguments" in headers --- .../r/appflow_connector_profile.html.markdown | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 10366c3c1f1..fe0695f3097 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -140,16 +140,16 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The refresh token used to refresh an expired access token. -#### Datadog Connector Profile Credentials Arguments +#### Datadog Connector Profile Credentials * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. * `application_key` (Required) - Application keys, in conjunction with your API key, give you full access to Datadog’s programmatic API. Application keys are associated with the user account that created them. The application key is used to log all requests made to the API. -#### Dynatrace Connector Profile Credentials Arguments +#### Dynatrace Connector Profile Credentials * `api_token` (Required) - The API tokens used by Dynatrace API to authenticate various API calls. -#### Google Analytics Connector Profile Credentials Arguments +#### Google Analytics Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Google Analytics resources. * `client_id` (Required) - The identifier for the desired client. @@ -157,69 +157,69 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. This is required only for OAuth2 access tokens, and is not required for OAuth1 access tokens. -#### Honeycode Connector Profile Credentials Arguments +#### Honeycode Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Amazon Honeycode resources. * `oauth_request` (Optional) - Used by select connectors for which the OAuth workflow is supported, such as Salesforce, Google Analytics, Marketo, Zendesk, and Slack. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. -#### Infor Nexus Connector Profile Credentials Arguments +#### Infor Nexus Connector Profile Credentials * `access_key_id` (Required) - The Access Key portion of the credentials. * `datakey` (Required) - The encryption keys used to encrypt data. * `secret_access_key` (Required) - The secret key used to sign requests. * `user_id` (Required) - The identifier for the user. -#### Marketo Connector Profile Credentials Arguments +#### Marketo Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Marketo resources. * `client_id` (Required) - The identifier for the desired client. * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. -#### Redshift Connector Profile Credentials Arguments +#### Redshift Connector Profile Credentials * `password` (Required) - The password that corresponds to the user name. * `username` (Required) - The name of the user. -#### Salesforce Connector Profile Credentials Arguments +#### Salesforce Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Salesforce resources. * `client_credentials_arn` (Optional) - The secret manager ARN, which contains the client ID and client secret of the connected app. * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. -#### ServiceNow Connector Profile Credentials Arguments +#### ServiceNow Connector Profile Credentials * `password` (Required) - The password that corresponds to the user name. * `username` (Required) - The name of the user. -#### Singular Connector Profile Credentials Arguments +#### Singular Connector Profile Credentials * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. -#### Slack Connector Profile Credentials Arguments +#### Slack Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Slack resources. * `client_id` (Required) - The identifier for the client. * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. -#### Snowflake Connector Profile Credentials Arguments +#### Snowflake Connector Profile Credentials * `password` (Required) - The password that corresponds to the user name. * `username` (Required) - The name of the user. -#### Trendmicro Connector Profile Credentials Arguments +#### Trendmicro Connector Profile Credentials * `api_secret_key` (Required) - The Secret Access Key portion of the credentials. -#### Veeva Connector Profile Credentials Arguments +#### Veeva Connector Profile Credentials * `password` (Required) - The password that corresponds to the user name. * `username` (Required) - The name of the user. -#### Zendesk Connector Profile Credentials Arguments +#### Zendesk Connector Profile Credentials * `access_token` (Optional) - The credentials used to access protected Zendesk resources. * `client_id` (Required) - The identifier for the desired client. From c895462428c7b9e5b9ed254b121e04c9642b75ad Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 02:45:45 -0500 Subject: [PATCH 54/59] Run terrafmt --- internal/service/appflow/connector_profile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appflow/connector_profile_test.go b/internal/service/appflow/connector_profile_test.go index 419f6ebbe37..fb16bfddb6c 100644 --- a/internal/service/appflow/connector_profile_test.go +++ b/internal/service/appflow/connector_profile_test.go @@ -340,7 +340,7 @@ resource "aws_appflow_connector_profile" "test" { connector_profile_properties { redshift { bucket_name = %[1]q - bucket_prefix = %[4]q + bucket_prefix = %[4]q database_url = "jdbc:redshift://${aws_redshift_cluster.test.endpoint}/dev" role_arn = aws_iam_role.test.arn } From f072f855ad135e8d5ba3f71015759d684eaa5690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Fri, 13 May 2022 10:07:05 +0200 Subject: [PATCH 55/59] Add "SAPOData Connector Profile Credentials" section --- .../r/appflow_connector_profile.html.markdown | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index fe0695f3097..ab7d53b2e68 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -108,7 +108,7 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `redshift` (Optional) - The connector-specific credentials required when using Amazon Redshift. See [Redshift Connector Profile Credentials](#redshift-connector-profile-credentials) for more details. * `salesforce` (Optional) - The connector-specific credentials required when using Salesforce. See [Salesforce Connector Profile Credentials](#salesforce-connector-profile-credentials) for more details. * `sapo_data` (Optional) - The connector-specific credentials required when using SAPOData. See [SAPOData Connector Profile Credentials](#sapodata-connector-profile-credentials) for more details. -* `service_now` (Optional) - The connector-specific credentials required when using ServiceNow. See [ServiceNow Connector Profile Credentials](#service-now-connector-profile-credentials) for more details. +* `service_now` (Optional) - The connector-specific credentials required when using ServiceNow. See [ServiceNow Connector Profile Credentials](#servicenow-connector-profile-credentials) for more details. * `singular` (Optional) - The connector-specific credentials required when using Singular. See [Singular Connector Profile Credentials](#singular-connector-profile-credentials) for more details. * `slack` (Optional) - The connector-specific credentials required when using Slack. See [Slack Connector Profile Credentials](#amplitude-connector-profile-credentials) for more details. * `snowflake` (Optional) - The connector-specific credentials required when using Snowflake. See [Snowflake Connector Profile Credentials](#snowflake-connector-profile-credentials) for more details. @@ -121,7 +121,7 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `api_key` (Required) - A unique alphanumeric identifier used to authenticate a user, developer, or calling program to your API. * `secret_key` (Required) - The Secret Access Key portion of the credentials. -#### Custom Connector Profile Credentials Arguments +#### Custom Connector Profile Credentials * `api_key` (Optional) - The API keys required for the authentication of the user. * `api_key` (Required) - The API key required for API key authentication. @@ -189,6 +189,18 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. * `refresh_token` (Optional) - The credentials used to acquire new access tokens. +#### SAPOData Connector Profile Credentials + +* `basic_auth_credentials` (Optional) - The SAPOData basic authentication credentials. + * `password` (Required) - The password to use to connect to a resource. + * `username` (Required) - The username to use to connect to a resource. +* `oauth_credentials` (Optional) - The SAPOData OAuth type authentication credentials. + * `access_token` (Optional) - The access token used to access protected SAPOData resources. + * `client_id` (Required) - The identifier for the desired client. + * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. + * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. + * `refresh_token` (Optional) - The refresh token used to refresh expired access token. + #### ServiceNow Connector Profile Credentials * `password` (Required) - The password that corresponds to the user name. From 8dcba01a4f5053f4ebc2c669f2c70ea94cfd0fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20D=C4=85bek?= <373530+szemek@users.noreply.github.com> Date: Fri, 13 May 2022 10:13:43 +0200 Subject: [PATCH 56/59] Add missing curly brace in docs example --- website/docs/r/appflow_connector_profile.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index ab7d53b2e68..0dc246f5286 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -71,7 +71,7 @@ resource "aws_appflow_connector_profile" "example" { connector_profile_properties { redshift { bucket_name = aws_s3_bucket.example.name - database_url = "jdbc:redshift://${aws_redshift_cluster.example.endpoint}/${aws_redshift_cluster.example.database_name" + database_url = "jdbc:redshift://${aws_redshift_cluster.example.endpoint}/${aws_redshift_cluster.example.database_name}" role_arn = aws_iam_role.example.arn } } From 5697310be3386a0a26ee70e80203bdc0e930b145 Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 03:23:15 -0500 Subject: [PATCH 57/59] Amend missing website markdown links error --- website/docs/r/appflow_connector_profile.html.markdown | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 0dc246f5286..4ad0bd00544 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -238,20 +238,22 @@ The AppFlow connector profile argument layout is a complex structure. The follow * `client_secret` (Required) - The client secret used by the OAuth client to authenticate to the authorization server. * `oauth_request` (Optional) - The OAuth requirement needed to request security tokens from the connector endpoint. See [OAuth Request](#oauth-request) for more details. +##### OAuth Request + +* `auth_code` (Optional) - The code provided by the connector when it has been authenticated via the connected app. +* `redirect_uri` (Optional) - The URL to which the authentication server redirects the browser after authorization has been granted. + ### Connector Profile Properties * `custom_connector` (Optional) - The connector-specific profile properties required when using the custom connector. See [Custom Connector Profile Properties](#custom-connector-profile-properties) for more details. * `datadog` (Optional) - The connector-specific properties required when using Datadog. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. * `dynatrace` (Optional) - The connector-specific properties required when using Dynatrace. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. -* `google_analytics` (Optional) - The connector-specific properties required when using Google Analytics. See [Google Analytics Connector Profile Properties](#google-analytics-connector-profile-properties) for more details. -* `honeycode` (Optional) - The connector-specific properties required when using Amazon Honeycode. See [Honeycode Connector Profile Properties](#honeycode-connector-profile-properties) for more details. * `infor_nexus` (Optional) - The connector-specific properties required when using Infor Nexus. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. * `marketo` (Optional) - The connector-specific properties required when using Marketo. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. * `redshift` (Optional) - The connector-specific properties required when using Amazon Redshift. See [Redshift Connector Profile Properties](#redshift-connector-profile-properties) for more details. * `salesforce` (Optional) - The connector-specific properties required when using Salesforce. See [Salesforce Connector Profile Properties](#salesforce-connector-profile-properties) for more details. * `sapo_data` (Optional) - The connector-specific properties required when using SAPOData. See [SAPOData Connector Profile Properties](#sapodata-connector-profile-properties) for more details. * `service_now` (Optional) - The connector-specific properties required when using ServiceNow. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. -* `singular` (Optional) - The connector-specific properties required when using Singular. See [Singular Connector Profile Properties](#singular-connector-profile-properties) for more details. * `slack` (Optional) - The connector-specific properties required when using Slack. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. * `snowflake` (Optional) - The connector-specific properties required when using Snowflake. See [Snowflake Connector Profile Properties](#snowflake-connector-profile-properties) for more details. * `veeva` (Optional) - The connector-specific properties required when using Veeva. See [Generic Connector Profile Properties](#generic-connector-profile-properties) for more details. From 8a4ab01923da96336540ccf7580597ab1873373e Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 03:35:12 -0500 Subject: [PATCH 58/59] Add SAPOData connnector profile properties to docs --- .../docs/r/appflow_connector_profile.html.markdown | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/website/docs/r/appflow_connector_profile.html.markdown b/website/docs/r/appflow_connector_profile.html.markdown index 4ad0bd00544..f78b3a86fb5 100644 --- a/website/docs/r/appflow_connector_profile.html.markdown +++ b/website/docs/r/appflow_connector_profile.html.markdown @@ -285,6 +285,19 @@ Datadog, Dynatrace, Infor Nexus, Marketo, ServiceNow, Slack, Veeva, and Zendesk * `instance_url` (Optional) - The location of the Salesforce resource. * `is_sandbox_environment` (Optional) - Indicates whether the connector profile applies to a sandbox or production environment. +#### SAPOData Connector Profile Properties + +* `application_host_url` (Required) - The location of the SAPOData resource. +* `application_service_path` (Required) - The application path to catalog service. +* `client_number` (Required) - The client number for the client creating the connection. +* `logon_language` (Optional) - The logon language of SAPOData instance. +* `oauth_properties` (Optional) - The SAPOData OAuth properties required for OAuth type authentication. + * `auth_code_url` (Required) - The authorization code url required to redirect to SAP Login Page to fetch authorization code for OAuth type authentication. + * `oauth_scopes` (Required) - The OAuth scopes required for OAuth type authentication. + * `token_url` (Required) - The token url required to fetch access/refresh tokens using authorization code and also to refresh expired access token using refresh token. +* `port_number` (Required) - The port number of the SAPOData instance. +* `private_link_service_name` (Optional) - The SAPOData Private Link service name to be used for private data transfers. + #### Snowflake Connector Profile Properties * `account_name` (Optional) - The name of the account. From 7238c868e46df4d2dad7499bd2b99d097dec5dca Mon Sep 17 00:00:00 2001 From: Zoe Helding Date: Fri, 13 May 2022 03:40:11 -0500 Subject: [PATCH 59/59] Add changelog entry for appflow_connector_profile --- .changelog/23892.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/23892.txt diff --git a/.changelog/23892.txt b/.changelog/23892.txt new file mode 100644 index 00000000000..7235637a8db --- /dev/null +++ b/.changelog/23892.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appflow_connector_profile +```