diff --git a/.changelog/18905.txt b/.changelog/18905.txt new file mode 100644 index 000000000000..69e0051652bb --- /dev/null +++ b/.changelog/18905.txt @@ -0,0 +1,11 @@ +```release-note:new-resource +aws_cloudwatch_event_connection +``` + +```release-note:new-resource +aws_cloudwatch_event_api_destination +``` + +```release-note:new-data-source +aws_cloudwatch_event_connection +``` \ No newline at end of file diff --git a/aws/data_source_aws_cloudwatch_event_connection.go b/aws/data_source_aws_cloudwatch_event_connection.go new file mode 100644 index 000000000000..4c46028e192d --- /dev/null +++ b/aws/data_source_aws_cloudwatch_event_connection.go @@ -0,0 +1,62 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceAwsCloudwatchEventConnection() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsCloudwatchEventConnectionRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "authorization_type": { + Type: schema.TypeString, + Computed: true, + }, + "secret_arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsCloudwatchEventConnectionRead(d *schema.ResourceData, meta interface{}) error { + d.SetId(d.Get("name").(string)) + + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.DescribeConnectionInput{ + Name: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading CloudWatchEvent connection (%s)", d.Id()) + output, err := conn.DescribeConnection(input) + if err != nil { + return fmt.Errorf("error getting CloudWatchEvent connection (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting CloudWatchEvent connection (%s): empty response", d.Id()) + } + + log.Printf("[DEBUG] Found CloudWatchEvent connection: %#v", *output) + d.Set("arn", output.ConnectionArn) + d.Set("secret_arn", output.SecretArn) + d.Set("name", output.Name) + d.Set("authorization_type", output.AuthorizationType) + return nil +} diff --git a/aws/data_source_aws_cloudwatch_event_connection_test.go b/aws/data_source_aws_cloudwatch_event_connection_test.go new file mode 100644 index 000000000000..c148d19bc25a --- /dev/null +++ b/aws/data_source_aws_cloudwatch_event_connection_test.go @@ -0,0 +1,52 @@ +package aws + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSDataSourceCloudwatch_Event_Connection_basic(t *testing.T) { + dataSourceName := "data.aws_cloudwatch_event_connection.test" + resourceName := "aws_cloudwatch_event_connection.api_key" + + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatch_Event_ConnectionDataConfig( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "secret_arn", resourceName, "secret_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "authorization_type", resourceName, "authorization_type"), + ), + }, + }, + }) +} + +func testAccAWSCloudwatch_Event_ConnectionDataConfig(name, description, authorizationType, key, value string) string { + return composeConfig( + testAccAWSCloudWatchEventConnectionConfig_apiKey(name, description, authorizationType, key, value), + ` +data "aws_cloudwatch_event_connection" "test" { + name = aws_cloudwatch_event_connection.api_key.name +} +`) +} diff --git a/aws/internal/service/cloudwatchevents/finder/finder.go b/aws/internal/service/cloudwatchevents/finder/finder.go index 14b1829448c7..408979e14e77 100644 --- a/aws/internal/service/cloudwatchevents/finder/finder.go +++ b/aws/internal/service/cloudwatchevents/finder/finder.go @@ -5,10 +5,40 @@ import ( "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/lister" ) +func ConnectionByName(conn *events.CloudWatchEvents, name string) (*events.DescribeConnectionOutput, error) { + input := &events.DescribeConnectionInput{ + Name: aws.String(name), + } + + output, err := conn.DescribeConnection(input) + + if tfawserr.ErrCodeEquals(err, events.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} + func Rule(conn *events.CloudWatchEvents, eventBusName, ruleName string) (*events.DescribeRuleOutput, error) { input := events.DescribeRuleInput{ Name: aws.String(ruleName), diff --git a/aws/internal/service/cloudwatchevents/waiter/status.go b/aws/internal/service/cloudwatchevents/waiter/status.go new file mode 100644 index 000000000000..7201c0fee798 --- /dev/null +++ b/aws/internal/service/cloudwatchevents/waiter/status.go @@ -0,0 +1,25 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func ConnectionState(conn *events.CloudWatchEvents, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.ConnectionByName(conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.ConnectionState), nil + } +} diff --git a/aws/internal/service/cloudwatchevents/waiter/waiter.go b/aws/internal/service/cloudwatchevents/waiter/waiter.go new file mode 100644 index 000000000000..834d746a5ea8 --- /dev/null +++ b/aws/internal/service/cloudwatchevents/waiter/waiter.go @@ -0,0 +1,65 @@ +package waiter + +import ( + "time" + + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + ConnectionCreatedTimeout = 2 * time.Minute + ConnectionDeletedTimeout = 2 * time.Minute + ConnectionUpdatedTimeout = 2 * time.Minute +) + +func ConnectionCreated(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateCreating, events.ConnectionStateAuthorizing}, + Target: []string{events.ConnectionStateAuthorized, events.ConnectionStateDeauthorized}, + Refresh: ConnectionState(conn, id), + Timeout: ConnectionCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err + } + + return nil, err +} + +func ConnectionDeleted(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateDeleting}, + Target: []string{}, + Refresh: ConnectionState(conn, id), + Timeout: ConnectionDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err + } + + return nil, err +} + +func ConnectionUpdated(conn *events.CloudWatchEvents, id string) (*events.DescribeConnectionOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{events.ConnectionStateUpdating, events.ConnectionStateAuthorizing, events.ConnectionStateDeauthorizing}, + Target: []string{events.ConnectionStateAuthorized, events.ConnectionStateDeauthorized}, + Refresh: ConnectionState(conn, id), + Timeout: ConnectionUpdatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*events.DescribeConnectionOutput); ok { + return v, err + } + + return nil, err +} diff --git a/aws/provider.go b/aws/provider.go index b0cc423bedcd..6388c59682ea 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -218,6 +218,7 @@ func Provider() *schema.Provider { "aws_cloudfront_origin_request_policy": dataSourceAwsCloudFrontOriginRequestPolicy(), "aws_cloudhsm_v2_cluster": dataSourceCloudHsmV2Cluster(), "aws_cloudtrail_service_account": dataSourceAwsCloudTrailServiceAccount(), + "aws_cloudwatch_event_connection": dataSourceAwsCloudwatchEventConnection(), "aws_cloudwatch_event_source": dataSourceAwsCloudWatchEventSource(), "aws_cloudwatch_log_group": dataSourceAwsCloudwatchLogGroup(), "aws_codeartifact_authorization_token": dataSourceAwsCodeArtifactAuthorizationToken(), @@ -543,6 +544,8 @@ func Provider() *schema.Provider { "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), "aws_cloudwatch_event_archive": resourceAwsCloudWatchEventArchive(), + "aws_cloudwatch_event_connection": resourceAwsCloudWatchEventConnection(), + "aws_cloudwatch_event_api_destination": resourceAwsCloudWatchEventApiDestination(), "aws_cloudwatch_log_destination": resourceAwsCloudWatchLogDestination(), "aws_cloudwatch_log_destination_policy": resourceAwsCloudWatchLogDestinationPolicy(), "aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(), diff --git a/aws/resource_aws_cloudwatch_event_api_destination.go b/aws/resource_aws_cloudwatch_event_api_destination.go new file mode 100644 index 000000000000..f2ff0d42af14 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_api_destination.go @@ -0,0 +1,189 @@ +package aws + +import ( + "fmt" + "log" + "math" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsCloudWatchEventApiDestination() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudWatchEventApiDestinationCreate, + Read: resourceAwsCloudWatchEventApiDestinationRead, + Update: resourceAwsCloudWatchEventApiDestinationUpdate, + Delete: resourceAwsCloudWatchEventApiDestinationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "invocation_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "invocation_rate_limit_per_second": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, math.MaxInt64), + Default: 300, + }, + "http_method": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ApiDestinationHttpMethod_Values(), true), + }, + "connection_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsCloudWatchEventApiDestinationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.CreateApiDestinationInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if invocationEndpoint, ok := d.GetOk("invocation_endpoint"); ok { + input.InvocationEndpoint = aws.String(invocationEndpoint.(string)) + } + if invocationRateLimitPerSecond, ok := d.GetOk("invocation_rate_limit_per_second"); ok { + input.InvocationRateLimitPerSecond = aws.Int64(int64(invocationRateLimitPerSecond.(int))) + } + if httpMethod, ok := d.GetOk("http_method"); ok { + input.HttpMethod = aws.String(httpMethod.(string)) + } + if connectionArn, ok := d.GetOk("connection_arn"); ok { + input.ConnectionArn = aws.String(connectionArn.(string)) + } + + log.Printf("[DEBUG] Creating CloudWatchEvent API Destination: %v", input) + + _, err := conn.CreateApiDestination(input) + if err != nil { + return fmt.Errorf("Creating CloudWatchEvent API Destination (%s) failed: %w", *input.Name, err) + } + + d.SetId(aws.StringValue(input.Name)) + + log.Printf("[INFO] CloudWatchEvent API Destination (%s) created", d.Id()) + + return resourceAwsCloudWatchEventApiDestinationRead(d, meta) +} + +func resourceAwsCloudWatchEventApiDestinationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.DescribeApiDestinationInput{ + Name: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Reading CloudWatchEvent API Destination (%s)", d.Id()) + output, err := conn.DescribeApiDestination(input) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent API Destination (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading CloudWatchEvent API Destination: %w", err) + } + + log.Printf("[DEBUG] Found CloudWatchEvent API Destination: %#v", *output) + + d.Set("arn", output.ApiDestinationArn) + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("invocation_endpoint", output.InvocationEndpoint) + d.Set("invocation_rate_limit_per_second", output.InvocationRateLimitPerSecond) + d.Set("http_method", output.HttpMethod) + d.Set("connection_arn", output.ConnectionArn) + + return nil +} + +func resourceAwsCloudWatchEventApiDestinationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.UpdateApiDestinationInput{} + + if name, ok := d.GetOk("name"); ok { + input.Name = aws.String(name.(string)) + } + if description, ok := d.GetOk("description"); ok { + input.Description = aws.String(description.(string)) + } + if invocationEndpoint, ok := d.GetOk("invocation_endpoint"); ok { + input.InvocationEndpoint = aws.String(invocationEndpoint.(string)) + } + if invocationRateLimitPerSecond, ok := d.GetOk("invocation_rate_limit_per_second"); ok { + input.InvocationRateLimitPerSecond = aws.Int64(invocationRateLimitPerSecond.(int64)) + } + if httpMethod, ok := d.GetOk("http_method"); ok { + input.HttpMethod = aws.String(httpMethod.(string)) + } + if connectionArn, ok := d.GetOk("connection_arn"); ok { + input.ConnectionArn = aws.String(connectionArn.(string)) + } + + log.Printf("[DEBUG] Updating CloudWatchEvent API Destination: %s", input) + _, err := conn.UpdateApiDestination(input) + if err != nil { + return fmt.Errorf("error updating CloudWatchEvent API Destination (%s): %w", d.Id(), err) + } + return resourceAwsCloudWatchEventApiDestinationRead(d, meta) +} + +func resourceAwsCloudWatchEventApiDestinationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + log.Printf("[INFO] Deleting CloudWatchEvent API Destination (%s)", d.Id()) + input := &events.DeleteApiDestinationInput{ + Name: aws.String(d.Id()), + } + + _, err := conn.DeleteApiDestination(input) + + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatchEvent API Destination (%s) not found", d.Id()) + return nil + } + if err != nil { + return fmt.Errorf("Error deleting CloudWatchEvent API Destination (%s): %w", d.Id(), err) + } + log.Printf("[INFO] CloudWatchEvent API Destination (%s) deleted", d.Id()) + + return nil +} diff --git a/aws/resource_aws_cloudwatch_event_api_destination_test.go b/aws/resource_aws_cloudwatch_event_api_destination_test.go new file mode 100644 index 000000000000..6ee21570cbd4 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_api_destination_test.go @@ -0,0 +1,366 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudwatchevents" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/go-multierror" + "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" +) + +const uuidRegex = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + +func init() { + resource.AddTestSweepers("aws_cloudwatch_event_api_destination", &resource.Sweeper{ + Name: "aws_cloudwatch_event_api_destination", + F: testSweepCloudWatchEventApiDestination, + Dependencies: []string{ + "aws_cloudwatch_event_connection", + }, + }) +} + +func testSweepCloudWatchEventApiDestination(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).cloudwatcheventsconn + + var sweeperErrs *multierror.Error + + input := &events.ListApiDestinationsInput{ + Limit: aws.Int64(100), + } + var apiDestinations []*events.ApiDestination + for { + output, err := conn.ListApiDestinations(input) + if err != nil { + return err + } + apiDestinations = append(apiDestinations, output.ApiDestinations...) + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, apiDestination := range apiDestinations { + + input := &events.DeleteApiDestinationInput{ + Name: apiDestination.Name, + } + _, err := conn.DeleteApiDestination(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting CloudWatch Event Api Destination (%s): %w", *apiDestination.Name, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d CloudWatch Event Api Destinations", len(apiDestinations)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSCloudWatchEventApiDestination_basic(t *testing.T) { + var v1, v2, v3 events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpointModified := "https://www.hashicorp.com/products/terraform" + httpMethodModified := "POST" + + resourceName := "aws_cloudwatch_event_api_destination.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + name, + invocationEndpoint, + httpMethod, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("api-destination/%s/%s", name, uuidRegex))), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpoint), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + nameModified, + invocationEndpointModified, + httpMethodModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("api-destination/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventApiDestinationRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + ), + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + nameModified, + invocationEndpointModified, + httpMethodModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v3), + testAccCheckCloudWatchEventApiDestinationNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventApiDestination_optional(t *testing.T) { + var v1, v2, v3 events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + description := acctest.RandomWithPrefix("tf-acc-test") + invocationRateLimitPerSecond := 10 + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpointModified := "https://www.hashicorp.com/products/terraform" + httpMethodModified := "POST" + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + invocationRateLimitPerSecondModified := 12 + + resourceName := "aws_cloudwatch_event_api_destination.optional" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + name, + invocationEndpoint, + httpMethod, + description, + int64(invocationRateLimitPerSecond), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpoint), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecond)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + nameModified, + invocationEndpointModified, + httpMethodModified, + descriptionModified, + int64(invocationRateLimitPerSecondModified), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v2), + testAccCheckCloudWatchEventApiDestinationRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecondModified)), + ), + }, + { + Config: testAccAWSCloudWatchEventApiDestinationConfig_optional( + nameModified, + invocationEndpointModified, + httpMethodModified, + descriptionModified, + int64(invocationRateLimitPerSecondModified), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v3), + testAccCheckCloudWatchEventApiDestinationNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecondModified)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventApiDestination_disappears(t *testing.T) { + var v events.DescribeApiDestinationOutput + name := acctest.RandomWithPrefix("tf-acc-test") + invocationEndpoint := "https://www.hashicorp.com/" + httpMethod := "GET" + + resourceName := "aws_cloudwatch_event_api_destination.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventApiDestinationConfig( + name, + invocationEndpoint, + httpMethod, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventApiDestination(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSCloudWatchEventApiDestinationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_event_api_destination" { + continue + } + + params := events.DescribeApiDestinationInput{ + Name: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeApiDestination(¶ms) + + if err == nil { + return fmt.Errorf("CloudWatch Events Api Destination (%s) still exists: %s", rs.Primary.ID, resp) + } + } + + return nil +} + +func testAccCheckCloudWatchEventApiDestinationExists(n string, v *events.DescribeApiDestinationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + params := events.DescribeApiDestinationInput{ + Name: aws.String(rs.Primary.ID), + } + resp, err := conn.DescribeApiDestination(¶ms) + if err != nil { + return err + } + if resp == nil { + return fmt.Errorf("CloudWatch Events Api Destination (%s) not found", n) + } + + *v = *resp + + return nil + } +} + +func testAccCheckCloudWatchEventApiDestinationRecreated(i, j *events.DescribeApiDestinationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ApiDestinationArn) == aws.StringValue(j.ApiDestinationArn) { + return fmt.Errorf("CloudWatch Events Api Destination not recreated") + } + return nil + } +} + +func testAccCheckCloudWatchEventApiDestinationNotRecreated(i, j *events.DescribeApiDestinationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ApiDestinationArn) != aws.StringValue(j.ApiDestinationArn) { + return fmt.Errorf("CloudWatch Events Api Destination was recreated") + } + return nil + } +} + +func testAccAWSCloudWatchEventApiDestinationConfig(name, invocationEndpoint, httpMethod string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_api_destination" "basic" { + name = %[1]q + invocation_endpoint = %[2]q + http_method = %[3]q + connection_arn = aws_cloudwatch_event_connection.test.arn +} + +resource "aws_cloudwatch_event_connection" "test" { + name = %[1]q + authorization_type = "API_KEY" + auth_parameters { + api_key { + key = "testKey" + value = "testValue" + } + } +} +`, name, invocationEndpoint, httpMethod) +} + +func testAccAWSCloudWatchEventApiDestinationConfig_optional(name, invocationEndpoint, httpMethod, description string, invocationRateLimitPerSecond int64) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_api_destination" "optional" { + name = %[1]q + invocation_endpoint = %[2]q + http_method = %[3]q + connection_arn = aws_cloudwatch_event_connection.test.arn + + description = %[4]q + invocation_rate_limit_per_second = %[5]d +} + +resource "aws_cloudwatch_event_connection" "test" { + name = %[1]q + authorization_type = "API_KEY" + auth_parameters { + api_key { + key = "testKey" + value = "testValue" + } + } +} +`, name, invocationEndpoint, httpMethod, description, invocationRateLimitPerSecond) +} diff --git a/aws/resource_aws_cloudwatch_event_connection.go b/aws/resource_aws_cloudwatch_event_connection.go new file mode 100644 index 000000000000..7ca4ffcaabd2 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_connection.go @@ -0,0 +1,793 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func resourceAwsCloudWatchEventConnection() *schema.Resource { + connectionHttpParameters := &schema.Resource{ + Schema: map[string]*schema.Schema{ + "body": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + "header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + "query_string": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "is_value_secret": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + }, + } + + return &schema.Resource{ + Create: resourceAwsCloudWatchEventConnectionCreate, + Read: resourceAwsCloudWatchEventConnectionRead, + Update: resourceAwsCloudWatchEventConnectionUpdate, + Delete: resourceAwsCloudWatchEventConnectionDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + validation.StringMatch(regexp.MustCompile(`^[\.\-_A-Za-z0-9]+`), ""), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "authorization_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ConnectionAuthorizationType_Values(), true), + }, + "auth_parameters": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_key": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + "basic": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "username": { + Type: schema.TypeString, + Required: true, + }, + "password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + "oauth": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{ + "auth_parameters.0.api_key", + "auth_parameters.0.basic", + "auth_parameters.0.oauth", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorization_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "http_method": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.ConnectionOAuthHttpMethod_Values(), true), + }, + "oauth_http_parameters": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: connectionHttpParameters, + }, + "client_parameters": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_id": { + Type: schema.TypeString, + Required: true, + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + }, + }, + }, + }, + }, + }, + "invocation_http_parameters": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: connectionHttpParameters, + }, + }, + }, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "secret_arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsCloudWatchEventConnectionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + name := d.Get("name").(string) + input := &events.CreateConnectionInput{ + AuthorizationType: aws.String(d.Get("authorization_type").(string)), + AuthParameters: expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(d.Get("auth_parameters").([]interface{})), + Name: aws.String(name), + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Creating CloudWatch Events connection: %s", input) + + _, err := conn.CreateConnection(input) + + if err != nil { + return fmt.Errorf("error creating CloudWatch Events connection (%s): %w", name, err) + } + + d.SetId(name) + + _, err = waiter.ConnectionCreated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to create: %w", d.Id(), err) + } + + return resourceAwsCloudWatchEventConnectionRead(d, meta) +} + +func resourceAwsCloudWatchEventConnectionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + output, err := finder.ConnectionByName(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] CloudWatch Events connection (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading CloudWatch Events connection (%s): %w", d.Id(), err) + } + + d.Set("arn", output.ConnectionArn) + d.Set("authorization_type", output.AuthorizationType) + d.Set("description", output.Description) + d.Set("name", output.Name) + d.Set("secret_arn", output.SecretArn) + + if output.AuthParameters != nil { + authParameters := flattenAwsCloudWatchEventConnectionAuthParameters(output.AuthParameters, d) + if err := d.Set("auth_parameters", authParameters); err != nil { + return fmt.Errorf("error setting auth_parameters error: %w", err) + } + } + + return nil +} + +func resourceAwsCloudWatchEventConnectionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + input := &events.UpdateConnectionInput{ + Name: aws.String(d.Id()), + } + + if v, ok := d.GetOk("authorization_type"); ok { + input.AuthorizationType = aws.String(v.(string)) + } + + if v, ok := d.GetOk("auth_parameters"); ok { + input.AuthParameters = expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(v.([]interface{})) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Updating CloudWatch Events connection: %s", input) + _, err := conn.UpdateConnection(input) + + if err != nil { + return fmt.Errorf("error updating CloudWatch Events connection (%s): %w", d.Id(), err) + } + + _, err = waiter.ConnectionUpdated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to update: %w", d.Id(), err) + } + + return resourceAwsCloudWatchEventConnectionRead(d, meta) +} + +func resourceAwsCloudWatchEventConnectionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + log.Printf("[INFO] Deleting CloudWatch Events connection (%s)", d.Id()) + _, err := conn.DeleteConnection(&events.DeleteConnectionInput{ + Name: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, events.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting CloudWatch Events connection (%s): %w", d.Id(), err) + } + + _, err = waiter.ConnectionDeleted(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for CloudWatch Events connection (%s) to delete: %w", d.Id(), err) + } + + return nil +} + +func expandAwsCloudWatchEventCreateConnectionAuthRequestParameters(config []interface{}) *events.CreateConnectionAuthRequestParameters { + authParameters := &events.CreateConnectionAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["api_key"]; ok { + authParameters.ApiKeyAuthParameters = expandAwsCreateConnectionApiKeyAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["basic"]; ok { + authParameters.BasicAuthParameters = expandAwsCreateConnectionBasicAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["oauth"]; ok { + authParameters.OAuthParameters = expandAwsCreateConnectionOAuthAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["invocation_http_parameters"]; ok { + authParameters.InvocationHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + } + + return authParameters +} + +func expandAwsCreateConnectionApiKeyAuthRequestParameters(config []interface{}) *events.CreateConnectionApiKeyAuthRequestParameters { + if len(config) == 0 { + return nil + } + apiKeyAuthParameters := &events.CreateConnectionApiKeyAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["key"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyName = aws.String(val) + } + if val, ok := param["value"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyValue = aws.String(val) + } + } + return apiKeyAuthParameters +} + +func expandAwsCreateConnectionBasicAuthRequestParameters(config []interface{}) *events.CreateConnectionBasicAuthRequestParameters { + if len(config) == 0 { + return nil + } + basicAuthParameters := &events.CreateConnectionBasicAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["username"].(string); ok && val != "" { + basicAuthParameters.Username = aws.String(val) + } + if val, ok := param["password"].(string); ok && val != "" { + basicAuthParameters.Password = aws.String(val) + } + } + return basicAuthParameters +} + +func expandAwsCreateConnectionOAuthAuthRequestParameters(config []interface{}) *events.CreateConnectionOAuthRequestParameters { + if len(config) == 0 { + return nil + } + oAuthParameters := &events.CreateConnectionOAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["authorization_endpoint"].(string); ok && val != "" { + oAuthParameters.AuthorizationEndpoint = aws.String(val) + } + if val, ok := param["http_method"].(string); ok && val != "" { + oAuthParameters.HttpMethod = aws.String(val) + } + if val, ok := param["oauth_http_parameters"]; ok { + oAuthParameters.OAuthHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + if val, ok := param["client_parameters"]; ok { + oAuthParameters.ClientParameters = expandAwsCreateConnectionOAuthClientRequestParameters(val.([]interface{})) + } + } + return oAuthParameters +} + +func expandAwsCreateConnectionOAuthClientRequestParameters(config []interface{}) *events.CreateConnectionOAuthClientRequestParameters { + oAuthClientRequestParameters := &events.CreateConnectionOAuthClientRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["client_id"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientID = aws.String(val) + } + if val, ok := param["client_secret"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientSecret = aws.String(val) + } + } + return oAuthClientRequestParameters +} + +func expandAwsConnectionHttpParameters(config []interface{}) *events.ConnectionHttpParameters { + if len(config) == 0 { + return nil + } + httpParameters := &events.ConnectionHttpParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["body"]; ok { + httpParameters.BodyParameters = expandAwsConnectionHttpParametersBody(val.([]interface{})) + } + if val, ok := param["header"]; ok { + httpParameters.HeaderParameters = expandAwsConnectionHttpParametersHeader(val.([]interface{})) + } + if val, ok := param["query_string"]; ok { + httpParameters.QueryStringParameters = expandAwsConnectionHttpParametersQueryString(val.([]interface{})) + } + } + return httpParameters +} + +func expandAwsConnectionHttpParametersBody(config []interface{}) []*events.ConnectionBodyParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionBodyParameter + for _, c := range config { + parameter := events.ConnectionBodyParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func expandAwsConnectionHttpParametersHeader(config []interface{}) []*events.ConnectionHeaderParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionHeaderParameter + for _, c := range config { + parameter := events.ConnectionHeaderParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func expandAwsConnectionHttpParametersQueryString(config []interface{}) []*events.ConnectionQueryStringParameter { + if len(config) == 0 { + return nil + } + var parameters []*events.ConnectionQueryStringParameter + for _, c := range config { + parameter := events.ConnectionQueryStringParameter{} + + input := c.(map[string]interface{}) + if val, ok := input["key"].(string); ok && val != "" { + parameter.Key = aws.String(val) + } + if val, ok := input["value"].(string); ok && val != "" { + parameter.Value = aws.String(val) + } + if val, ok := input["is_value_secret"].(bool); ok { + parameter.IsValueSecret = aws.Bool(val) + } + parameters = append(parameters, ¶meter) + } + return parameters +} + +func flattenAwsCloudWatchEventConnectionAuthParameters( + authParameters *events.ConnectionAuthResponseParameters, + resourceData *schema.ResourceData, +) []map[string]interface{} { + config := make(map[string]interface{}) + + if authParameters.ApiKeyAuthParameters != nil { + config["api_key"] = flattenAwsConnectionApiKeyAuthParameters(authParameters.ApiKeyAuthParameters, resourceData) + } + + if authParameters.BasicAuthParameters != nil { + config["basic"] = flattenAwsConnectionBasicAuthParameters(authParameters.BasicAuthParameters, resourceData) + } + + if authParameters.OAuthParameters != nil { + config["oauth"] = flattenAwsConnectionOAuthParameters(authParameters.OAuthParameters, resourceData) + } + + if authParameters.InvocationHttpParameters != nil { + config["invocation_http_parameters"] = flattenAwsConnectionHttpParameters(authParameters.InvocationHttpParameters, resourceData, "auth_parameters.0.invocation_http_parameters") + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionApiKeyAuthParameters(apiKeyAuthParameters *events.ConnectionApiKeyAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if apiKeyAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if apiKeyAuthParameters.ApiKeyName != nil { + config["key"] = aws.StringValue(apiKeyAuthParameters.ApiKeyName) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.api_key.0.value"); ok { + config["value"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionBasicAuthParameters(basicAuthParameters *events.ConnectionBasicAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if basicAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if basicAuthParameters.Username != nil { + config["username"] = aws.StringValue(basicAuthParameters.Username) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.basic.0.password"); ok { + config["password"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionOAuthParameters(oAuthParameters *events.ConnectionOAuthResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if oAuthParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if oAuthParameters.AuthorizationEndpoint != nil { + config["authorization_endpoint"] = aws.StringValue(oAuthParameters.AuthorizationEndpoint) + } + if oAuthParameters.HttpMethod != nil { + config["http_method"] = aws.StringValue(oAuthParameters.HttpMethod) + } + config["oauth_http_parameters"] = flattenAwsConnectionHttpParameters(oAuthParameters.OAuthHttpParameters, resourceData, "auth_parameters.0.oauth.0.oauth_http_parameters") + config["client_parameters"] = flattenAwsConnectionOAuthClientResponseParameters(oAuthParameters.ClientParameters, resourceData) + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionOAuthClientResponseParameters(oAuthClientRequestParameters *events.ConnectionOAuthClientResponseParameters, resourceData *schema.ResourceData) []map[string]interface{} { + if oAuthClientRequestParameters == nil { + return nil + } + + config := make(map[string]interface{}) + if oAuthClientRequestParameters.ClientID != nil { + config["client_id"] = aws.StringValue(oAuthClientRequestParameters.ClientID) + } + + if v, ok := resourceData.GetOk("auth_parameters.0.oauth.0.client_parameters.0.client_secret"); ok { + config["client_secret"] = v.(string) + } + + result := []map[string]interface{}{config} + return result +} + +func flattenAwsConnectionHttpParameters( + httpParameters *events.ConnectionHttpParameters, + resourceData *schema.ResourceData, + path string, +) []map[string]interface{} { + if httpParameters == nil { + return nil + } + + var bodyParameters []map[string]interface{} + for i, param := range httpParameters.BodyParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.body.%d.value", path, i)); ok { + config["value"] = v.(string) + } + bodyParameters = append(bodyParameters, config) + } + + var headerParameters []map[string]interface{} + for i, param := range httpParameters.HeaderParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.header.%d.value", path, i)); ok { + config["value"] = v.(string) + } + headerParameters = append(headerParameters, config) + } + + var queryStringParameters []map[string]interface{} + for i, param := range httpParameters.QueryStringParameters { + config := make(map[string]interface{}) + config["is_value_secret"] = aws.BoolValue(param.IsValueSecret) + config["key"] = aws.StringValue(param.Key) + + if param.Value != nil { + config["value"] = aws.StringValue(param.Value) + } else if v, ok := resourceData.GetOk(fmt.Sprintf("%s.0.query_string.%d.value", path, i)); ok { + config["value"] = v.(string) + } + queryStringParameters = append(queryStringParameters, config) + } + + parameters := make(map[string]interface{}) + parameters["body"] = bodyParameters + parameters["header"] = headerParameters + parameters["query_string"] = queryStringParameters + + result := []map[string]interface{}{parameters} + return result +} + +func expandAwsCloudWatchEventUpdateConnectionAuthRequestParameters(config []interface{}) *events.UpdateConnectionAuthRequestParameters { + authParameters := &events.UpdateConnectionAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["api_key"]; ok { + authParameters.ApiKeyAuthParameters = expandAwsUpdateConnectionApiKeyAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["basic"]; ok { + authParameters.BasicAuthParameters = expandAwsUpdateConnectionBasicAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["oauth"]; ok { + authParameters.OAuthParameters = expandAwsUpdateConnectionOAuthAuthRequestParameters(val.([]interface{})) + } + if val, ok := param["invocation_http_parameters"]; ok { + authParameters.InvocationHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + } + + return authParameters +} + +func expandAwsUpdateConnectionApiKeyAuthRequestParameters(config []interface{}) *events.UpdateConnectionApiKeyAuthRequestParameters { + if len(config) == 0 { + return nil + } + apiKeyAuthParameters := &events.UpdateConnectionApiKeyAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["key"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyName = aws.String(val) + } + if val, ok := param["value"].(string); ok && val != "" { + apiKeyAuthParameters.ApiKeyValue = aws.String(val) + } + } + return apiKeyAuthParameters +} + +func expandAwsUpdateConnectionBasicAuthRequestParameters(config []interface{}) *events.UpdateConnectionBasicAuthRequestParameters { + if len(config) == 0 { + return nil + } + basicAuthParameters := &events.UpdateConnectionBasicAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["username"].(string); ok && val != "" { + basicAuthParameters.Username = aws.String(val) + } + if val, ok := param["password"].(string); ok && val != "" { + basicAuthParameters.Password = aws.String(val) + } + } + return basicAuthParameters +} + +func expandAwsUpdateConnectionOAuthAuthRequestParameters(config []interface{}) *events.UpdateConnectionOAuthRequestParameters { + if len(config) == 0 { + return nil + } + oAuthParameters := &events.UpdateConnectionOAuthRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["authorization_endpoint"].(string); ok && val != "" { + oAuthParameters.AuthorizationEndpoint = aws.String(val) + } + if val, ok := param["http_method"].(string); ok && val != "" { + oAuthParameters.HttpMethod = aws.String(val) + } + if val, ok := param["oauth_http_parameters"]; ok { + oAuthParameters.OAuthHttpParameters = expandAwsConnectionHttpParameters(val.([]interface{})) + } + if val, ok := param["client_parameters"]; ok { + oAuthParameters.ClientParameters = expandAwsUpdateConnectionOAuthClientRequestParameters(val.([]interface{})) + } + } + return oAuthParameters +} + +func expandAwsUpdateConnectionOAuthClientRequestParameters(config []interface{}) *events.UpdateConnectionOAuthClientRequestParameters { + oAuthClientRequestParameters := &events.UpdateConnectionOAuthClientRequestParameters{} + for _, c := range config { + param := c.(map[string]interface{}) + if val, ok := param["client_id"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientID = aws.String(val) + } + if val, ok := param["client_secret"].(string); ok && val != "" { + oAuthClientRequestParameters.ClientSecret = aws.String(val) + } + } + return oAuthClientRequestParameters +} diff --git a/aws/resource_aws_cloudwatch_event_connection_test.go b/aws/resource_aws_cloudwatch_event_connection_test.go new file mode 100644 index 000000000000..79a968889a0a --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_connection_test.go @@ -0,0 +1,872 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strconv" + "testing" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/go-multierror" + "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/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func init() { + resource.AddTestSweepers("aws_cloudwatch_event_connection", &resource.Sweeper{ + Name: "aws_cloudwatch_event_connection", + F: testSweepCloudWatchEventConnection, + }) +} + +func testSweepCloudWatchEventConnection(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + conn := client.(*AWSClient).cloudwatcheventsconn + + var sweeperErrs *multierror.Error + + input := &events.ListConnectionsInput{ + Limit: aws.Int64(100), + } + var connections []*events.Connection + for { + output, err := conn.ListConnections(input) + if err != nil { + return err + } + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + for _, connection := range connections { + input := &events.DeleteConnectionInput{ + Name: connection.Name, + } + _, err := conn.DeleteConnection(input) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("Error deleting CloudWatch Event Connection (%s): %w", *connection.Name, err)) + continue + } + } + + log.Printf("[INFO] Deleted %d CloudWatch Event Connections", len(connections)) + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSCloudWatchEventConnection_apiKey(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + keyModified := acctest.RandomWithPrefix("tf-acc-test") + valueModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_cloudwatch_event_connection.api_key" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_parameters.0.api_key.0.value"}, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + nameModified, + descriptionModified, + authorizationType, + keyModified, + valueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", keyModified), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + nameModified, + descriptionModified, + authorizationType, + keyModified, + valueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", keyModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_basic(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "BASIC" + description := acctest.RandomWithPrefix("tf-acc-test") + username := acctest.RandomWithPrefix("tf-acc-test") + password := acctest.RandomWithPrefix("tf-acc-test") + + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + usernameModified := acctest.RandomWithPrefix("tf-acc-test") + passwordModified := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_cloudwatch_event_connection.basic" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + name, + description, + authorizationType, + username, + password, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", username), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_parameters.0.basic.0.password"}, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + nameModified, + descriptionModified, + authorizationType, + usernameModified, + passwordModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", usernameModified), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_basic( + nameModified, + descriptionModified, + authorizationType, + usernameModified, + passwordModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.basic.0.username", usernameModified), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_oAuth(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "OAUTH_CLIENT_CREDENTIALS" + description := acctest.RandomWithPrefix("tf-acc-test") + // oauth + authorizationEndpoint := "https://www.hashicorp.com/products/terraform" + httpMethod := "POST" + + // client_parameters + clientID := acctest.RandomWithPrefix("tf-acc-test") + clientSecret := acctest.RandomWithPrefix("tf-acc-test") + + // oauth_http_parameters + bodyKey := acctest.RandomWithPrefix("tf-acc-test") + bodyValue := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValue := true + + headerKey := acctest.RandomWithPrefix("tf-acc-test") + headerValue := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValue := true + + queryStringKey := acctest.RandomWithPrefix("tf-acc-test") + queryStringValue := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValue := true + + // modified + nameModified := acctest.RandomWithPrefix("tf-acc-test") + descriptionModified := acctest.RandomWithPrefix("tf-acc-test") + // oauth + authorizationEndpointModified := "https://www.hashicorp.com/" + httpMethodModified := "GET" + + // client_parameters + clientIDModified := acctest.RandomWithPrefix("tf-acc-test") + clientSecretModified := acctest.RandomWithPrefix("tf-acc-test") + + // oauth_http_parameters modified + bodyKeyModified := acctest.RandomWithPrefix("tf-acc-test") + bodyValueModified := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValueModified := false + + headerKeyModified := acctest.RandomWithPrefix("tf-acc-test") + headerValueModified := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValueModified := false + + queryStringKeyModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringValueModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValueModified := false + + resourceName := "aws_cloudwatch_event_connection.oauth" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpoint), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethod), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientID), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "auth_parameters.0.oauth.0.client_parameters.0.client_secret", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.value", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.value", + "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.value", + }, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + nameModified, + descriptionModified, + authorizationType, + authorizationEndpointModified, + httpMethodModified, + clientIDModified, + clientSecretModified, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "events", regexp.MustCompile(fmt.Sprintf("connection/%s/%s", nameModified, uuidRegex))), + testAccCheckCloudWatchEventConnectionRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientIDModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_oauth( + nameModified, + descriptionModified, + authorizationType, + authorizationEndpointModified, + httpMethodModified, + clientIDModified, + clientSecretModified, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", nameModified), + resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.authorization_endpoint", authorizationEndpointModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.http_method", httpMethodModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.client_parameters.0.client_id", clientIDModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.oauth.0.oauth_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_invocationHttpParameters(t *testing.T) { + var v1, v2, v3 events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + + // invocation_http_parameters + bodyKey := acctest.RandomWithPrefix("tf-acc-test") + bodyValue := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValue := true + + headerKey := acctest.RandomWithPrefix("tf-acc-test") + headerValue := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValue := true + + queryStringKey := acctest.RandomWithPrefix("tf-acc-test") + queryStringValue := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValue := true + + // invocation_http_parameters modified + bodyKeyModified := acctest.RandomWithPrefix("tf-acc-test") + bodyValueModified := acctest.RandomWithPrefix("tf-acc-test") + bodyIsSecretValueModified := false + + headerKeyModified := acctest.RandomWithPrefix("tf-acc-test") + headerValueModified := acctest.RandomWithPrefix("tf-acc-test") + headerIsSecretValueModified := false + + queryStringKeyModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringValueModified := acctest.RandomWithPrefix("tf-acc-test") + queryStringIsSecretValueModified := false + + resourceName := "aws_cloudwatch_event_connection.invocation_http_parameters" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKey), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKey)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValue)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "auth_parameters.0.api_key.0.value", + "auth_parameters.0.invocation_http_parameters.0.body.0.value", + "auth_parameters.0.invocation_http_parameters.0.body.1.value", + "auth_parameters.0.invocation_http_parameters.0.header.0.value", + "auth_parameters.0.invocation_http_parameters.0.header.1.value", + "auth_parameters.0.invocation_http_parameters.0.query_string.0.value", + "auth_parameters.0.invocation_http_parameters.0.query_string.1.value", + }, + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v2), + testAccCheckCloudWatchEventConnectionNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + { + Config: testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value, + bodyKeyModified, + bodyValueModified, + bodyIsSecretValueModified, + headerKeyModified, + headerValueModified, + headerIsSecretValueModified, + queryStringKeyModified, + queryStringValueModified, + queryStringIsSecretValueModified, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v3), + testAccCheckCloudWatchEventConnectionNotRecreated(&v2, &v3), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "authorization_type", authorizationType), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.api_key.0.key", key), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.key", bodyKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.0.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.key", fmt.Sprintf("second-%s", bodyKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.body.1.is_value_secret", strconv.FormatBool(bodyIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.key", headerKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.0.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.key", fmt.Sprintf("second-%s", headerKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.header.1.is_value_secret", strconv.FormatBool(headerIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.key", queryStringKeyModified), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.0.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.key", fmt.Sprintf("second-%s", queryStringKeyModified)), + resource.TestCheckResourceAttr(resourceName, "auth_parameters.0.invocation_http_parameters.0.query_string.1.is_value_secret", strconv.FormatBool(queryStringIsSecretValueModified)), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventConnection_disappears(t *testing.T) { + var v events.DescribeConnectionOutput + name := acctest.RandomWithPrefix("tf-acc-test") + authorizationType := "API_KEY" + description := acctest.RandomWithPrefix("tf-acc-test") + key := acctest.RandomWithPrefix("tf-acc-test") + value := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudwatch_event_connection.api_key" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventConnectionConfig_apiKey( + name, + description, + authorizationType, + key, + value, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventConnectionExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventConnection(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSCloudWatchEventConnectionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_event_connection" { + continue + } + + _, err := finder.ConnectionByName(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("CloudWatch Events connection %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckCloudWatchEventConnectionExists(n string, v *events.DescribeConnectionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + + output, err := finder.ConnectionByName(conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCheckCloudWatchEventConnectionRecreated(i, j *events.DescribeConnectionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ConnectionArn) == aws.StringValue(j.ConnectionArn) { + return fmt.Errorf("CloudWatch Events Connection not recreated") + } + return nil + } +} + +func testAccCheckCloudWatchEventConnectionNotRecreated(i, j *events.DescribeConnectionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(i.ConnectionArn) != aws.StringValue(j.ConnectionArn) { + return fmt.Errorf("CloudWatch Events Connection was recreated") + } + return nil + } +} + +func testAccAWSCloudWatchEventConnectionConfig_apiKey(name, description, authorizationType, key, value string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "api_key" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + api_key { + key = %[4]q + value = %[5]q + } + } +} +`, name, + description, + authorizationType, + key, + value) +} + +func testAccAWSCloudWatchEventConnectionConfig_basic(name, description, authorizationType, username, password string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "basic" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + basic { + username = %[4]q + password = %[5]q + } + } +} +`, name, + description, + authorizationType, + username, + password) +} + +func testAccAWSCloudWatchEventConnectionConfig_oauth( + name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret string, + bodyKey string, + bodyValue string, + bodyIsSecretValue bool, + headerKey string, + headerValue string, + headerIsSecretValue bool, + queryStringKey string, + queryStringValue string, + queryStringIsSecretValue bool) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "oauth" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + oauth { + authorization_endpoint = %[4]q + http_method = %[5]q + client_parameters { + client_id = %[6]q + client_secret = %[7]q + } + + oauth_http_parameters { + body { + key = %[8]q + value = %[9]q + is_value_secret = %[10]t + } + + header { + key = %[11]q + value = %[12]q + is_value_secret = %[13]t + } + + query_string { + key = %[14]q + value = %[15]q + is_value_secret = %[16]t + } + } + } + } +} +`, name, + description, + authorizationType, + authorizationEndpoint, + httpMethod, + clientID, + clientSecret, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue) +} + +func testAccAWSCloudWatchEventConnectionConfig_invocationHttpParameters( + name, + description, + authorizationType, + key, + value string, + bodyKey string, + bodyValue string, + bodyIsSecretValue bool, + headerKey string, + headerValue string, + headerIsSecretValue bool, + queryStringKey string, + queryStringValue string, + queryStringIsSecretValue bool) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_connection" "invocation_http_parameters" { + name = %[1]q + description = %[2]q + authorization_type = %[3]q + auth_parameters { + api_key { + key = %[4]q + value = %[5]q + } + + invocation_http_parameters { + body { + key = %[6]q + value = %[7]q + is_value_secret = %[8]t + } + + body { + key = "second-%[6]s" + value = "second-%[7]s" + is_value_secret = %[8]t + } + + header { + key = %[9]q + value = %[10]q + is_value_secret = %[11]t + } + + header { + key = "second-%[9]s" + value = "second-%[10]s" + is_value_secret = %[11]t + } + + query_string { + key = %[12]q + value = %[13]q + is_value_secret = %[14]t + } + + query_string { + key = "second-%[12]s" + value = "second-%[13]s" + is_value_secret = %[14]t + } + } + } +} +`, name, + description, + authorizationType, + key, + value, + bodyKey, + bodyValue, + bodyIsSecretValue, + headerKey, + headerValue, + headerIsSecretValue, + queryStringKey, + queryStringValue, + queryStringIsSecretValue) +} diff --git a/aws/resource_aws_cloudwatch_event_rule_test.go b/aws/resource_aws_cloudwatch_event_rule_test.go index 9e0a64d8916e..0b78f9ecf45f 100644 --- a/aws/resource_aws_cloudwatch_event_rule_test.go +++ b/aws/resource_aws_cloudwatch_event_rule_test.go @@ -20,6 +20,8 @@ import ( ) func init() { + RegisterServiceErrorCheckFunc(events.EndpointsID, testAccErrorCheckSkipEvents) + resource.AddTestSweepers("aws_cloudwatch_event_rule", &resource.Sweeper{ Name: "aws_cloudwatch_event_rule", F: testSweepCloudWatchEventRules, @@ -78,6 +80,12 @@ func testSweepCloudWatchEventRules(region string) error { return sweeperErrs.ErrorOrNil() } +func testAccErrorCheckSkipEvents(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "Operation is disabled in this region", + ) +} + func TestAccAWSCloudWatchEventRule_basic(t *testing.T) { var v1, v2, v3 events.DescribeRuleOutput rName := acctest.RandomWithPrefix("tf-acc-test") diff --git a/website/docs/d/cloudwatch_event_connection.html.markdown b/website/docs/d/cloudwatch_event_connection.html.markdown new file mode 100644 index 000000000000..0b6bfeba1fed --- /dev/null +++ b/website/docs/d/cloudwatch_event_connection.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_connection" +description: |- + Provides an EventBridge connection data source. +--- + +# Data source: aws_cloudfront_distribution + +Use this data source to retrieve information about a EventBridge connection. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +data "aws_cloudwatch_event_connection" "test" { + name = "test" +} +``` + +## Argument Reference + +* `name` - The name of the connection. + +## Attributes Reference + +The following attributes are exported: + +* `name` - The name of the connection. + +* `arn` - The ARN (Amazon Resource Name) for the connection. + +* `secret_arn` - The ARN (Amazon Resource Name) for the secret created from the authorization parameters specified for the connection. + +* `authorization_type` - The type of authorization to use to connect. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. diff --git a/website/docs/r/cloudwatch_event_api_destination.html.markdown b/website/docs/r/cloudwatch_event_api_destination.html.markdown new file mode 100644 index 000000000000..c2bf1eca05ba --- /dev/null +++ b/website/docs/r/cloudwatch_event_api_destination.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_api_destination" +description: |- + Provides an EventBridge event API Destination resource. +--- + +# Resource: aws_cloudwatch_event_api_destination + +Provides an EventBridge event API Destination resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_cloudwatch_event_api_destination" "test" { + name = "api-destination" + description = "An API Destination" + invocation_endpoint = "https://api.destination.com/endpoint" + http_method = "POST" + invocation_rate_limit_per_second = 20 + connection_arn = aws_cloudwatch_event_connection.test.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the new API Destination. The name must be unique for your account. Maximum of 64 characters consisting of numbers, lower/upper case letters, .,-,_. +* `description` - (Optional) The description of the new API Destination. Maximum of 512 characters. +* `invocation_endpoint` - (Required) URL endpoint to invoke as a target. This could be a valid endpoint generated by a partner service. You can include "*" as path parameters wildcards to be set from the Target HttpParameters. +* `http_method` - (Required) Select the HTTP method used for the invocation endpoint, such as GET, POST, PUT, etc. +* `invocation_rate_limit_per_second` - (Optional) Enter the maximum number of invocations per second to allow for this destination. Enter a value greater than 0 (default 300). +* `connection_arn` - (Required) ARN of the EventBridge Connection to use for the API Destination. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the event API Destination. + + +## Import + +EventBridge API Destinations can be imported using the `name`, e.g. + +```console +$ terraform import aws_cloudwatch_event_api_destination.test api-destination +``` diff --git a/website/docs/r/cloudwatch_event_connection.html.markdown b/website/docs/r/cloudwatch_event_connection.html.markdown new file mode 100644 index 000000000000..972e6893e4bd --- /dev/null +++ b/website/docs/r/cloudwatch_event_connection.html.markdown @@ -0,0 +1,201 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_connection" +description: |- + Provides an EventBridge connection resource. +--- + +# Resource: aws_cloudwatch_event_connection + +Provides an EventBridge connection resource. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + + +## Example Usage + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "API_KEY" + + auth_parameters { + api_key { + key = "x-signature" + value = "1234" + } + } +} +``` + +## Example Usage Basic Authorization + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + basic { + username = "user" + password = "Pass1234!" + } + } +} +``` + +## Example Usage OAuth Authorization + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + oauth { + authorization_endpoint = "https://auth.url.com/endpoint" + http_method = "GET" + + client_parameters { + client_id = "1234567890" + client_secret = "Pass1234!" + } + + oauth_http_parameters { + body { + key = "body-parameter-key" + value = "body-parameter-value" + is_value_secret = false + } + + header { + key = "header-parameter-key" + value = "header-parameter-value" + is_value_secret = false + } + + query_string { + key = "query-string-parameter-key" + value = "query-string-parameter-value" + is_value_secret = false + } + } + } + } +} +``` + +## Example Usage Invocation Http Parameters + +```terraform +resource "aws_cloudwatch_event_connection" "test" { + name = "ngrok-connection" + description = "A connection description" + authorization_type = "BASIC" + + auth_parameters { + basic { + username = "user" + password = "Pass1234!" + } + + invocation_http_parameters { + body { + key = "body-parameter-key" + value = "body-parameter-value" + is_value_secret = false + } + + body { + key = "body-parameter-key2" + value = "body-parameter-value2" + is_value_secret = true + } + + header { + key = "header-parameter-key" + value = "header-parameter-value" + is_value_secret = false + } + + query_string { + key = "query-string-parameter-key" + value = "query-string-parameter-value" + is_value_secret = false + } + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the new connection. Maximum of 64 characters consisting of numbers, lower/upper case letters, .,-,_. +* `description` - (Optional) Enter a description for the connection. Maximum of 512 characters. +* `authorization_type` - (Required) Choose the type of authorization to use for the connection. One of `API_KEY`,`BASIC`,`OAUTH_CLIENT_CREDENTIALS`. +* `auth_parameters` - (Required) Parameters used for authorization. A maximum of 1 are allowed. Documented below. +* `invocation_http_parameters` - (Optional) Invocation Http Parameters are additional credentials used to sign each Invocation of the ApiDestination created from this Connection. If the ApiDestination Rule Target has additional HttpParameters, the values will be merged together, with the Connection Invocation Http Parameters taking precedence. Secret values are stored and managed by AWS Secrets Manager. A maximum of 1 are allowed. Documented below. + +`auth_parameters` support the following: + +* `api_key` - (Optional) Parameters used for API_KEY authorization. An API key to include in the header for each authentication request. A maximum of 1 are allowed. Conflicts with `basic` and `oauth`. Documented below. +* `basic` - (Optional) Parameters used for BASIC authorization. A maximum of 1 are allowed. Conflicts with `api_key` and `oauth`. Documented below. +* `oauth` - (Optional) Parameters used for OAUTH_CLIENT_CREDENTIALS authorization. A maximum of 1 are allowed. Conflicts with `basic` and `api_key`. Documented below. + +`api_key` support the following: + +* `key` - (Required) Header Name. +* `value` - (Required) Header Value. Created and stored in AWS Secrets Manager. + +`basic` support the following: + +* `username` - (Required) A username for the authorization. +* `password` - (Required) A password for the authorization. Created and stored in AWS Secrets Manager. + +`oauth` support the following: + +* `authorization_endpoint` - (Required) A username for the authorization. +* `http_method` - (Required) A password for the authorization. Created and stored in AWS Secrets Manager. +* `client_parameters` - (Required) Contains the client parameters for OAuth authorization. Contains the following two parameters. + * `client_id` - (Required) The client ID for the credentials to use for authorization. Created and stored in AWS Secrets Manager. + * `client_secret` - (Required) The client secret for the credentials to use for authorization. Created and stored in AWS Secrets Manager. +* `oauth_http_parameters` - (Required) OAuth Http Parameters are additional credentials used to sign the request to the authorization endpoint to exchange the OAuth Client information for an access token. Secret values are stored and managed by AWS Secrets Manager. A maximum of 1 are allowed. Documented below. + +`invocation_http_parameters` and `oauth_http_parameters` support the following: + +* `body` - (Optional) Contains additional body string parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +* `header` - (Optional) Contains additional header parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +* `query_string` - (Optional) Contains additional query string parameters for the connection. You can include up to 100 additional body string parameters per request. Each additional parameter counts towards the event payload size, which cannot exceed 64 KB. Each parameter can contain the following: + * `key` - (Required) The key for the parameter. + * `value` - (Required) The value associated with the key. Created and stored in AWS Secrets Manager if is secret. + * `is_value_secret` - (Optional) Specified whether the value is secret. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the connection. +* `secret_arn` - The Amazon Resource Name (ARN) of the secret created from the authorization parameters specified for the connection. + + +## Import + +EventBridge Connection can be imported using the `name`, e.g. + +```console +$ terraform import aws_cloudwatch_event_connection.test ngrok-connection +```