Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for partner event bus and sources #19072

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4aed4f4
r/aws_cloudwatch_event_rule: Add 'TestAccAWSCloudWatchEventRule_Partn…
ewbankkit Mar 29, 2021
ab22c60
r/aws_cloudwatch_event_rule: Support partner event bus names.
ewbankkit Mar 29, 2021
6543ef8
r/aws_cloudwatch_event_permission: Add 'TestAccAWSCloudWatchEventPerm…
ewbankkit Mar 29, 2021
efc0114
r/aws_cloudwatch_event_permission: Support partner event bus names.
ewbankkit Mar 29, 2021
a975015
Revert "r/aws_cloudwatch_event_permission: Support partner event bus …
ewbankkit Mar 29, 2021
fe0a09c
Revert "r/aws_cloudwatch_event_permission: Add 'TestAccAWSCloudWatchE…
ewbankkit Mar 29, 2021
61e6000
Additional TestRuleParseID case.
ewbankkit Mar 29, 2021
025083e
r/aws_cloudwatch_event_target: Add 'TestAccAWSCloudWatchEventTarget_P…
ewbankkit Mar 30, 2021
627dcf1
r/aws_cloudwatch_event_target: Support partner event bus names.
ewbankkit Mar 30, 2021
81bbfcb
Add CHANGELOG entry.
ewbankkit Mar 30, 2021
addbc8f
Fix terraform errors.
ewbankkit Mar 31, 2021
f462b32
Some additional unit test cases.
ewbankkit Mar 31, 2021
7c92d94
Add 'TestPermissionParseID'.
ewbankkit Mar 31, 2021
57a396e
Add support for partner event bus and source
moensch Apr 23, 2021
357c023
d/aws_cloudwatch_event_source: New data source moved into #19219.
ewbankkit May 4, 2021
c3fd44a
r/aws_cloudwatch_event_bus: Tidy up partner event source acceptance t…
ewbankkit May 4, 2021
55f9b31
Merge remote-tracking branch 'ewbankkit/f-aws_cloudwatch_event_rule-p…
ewbankkit May 4, 2021
9e51097
Fix linter error "`partnerEventBusPattern` is unused (deadcode)".
ewbankkit May 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/19072.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_cloudwatch_event_bus: Support partner event bus creation
```

```release-note:new-data-source
aws_cloudwatch_event_source
```
73 changes: 73 additions & 0 deletions aws/data_source_aws_cloudwatch_event_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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 dataSourceAwsCloudWatchEventSource() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsCloudWatchEventSourceRead,

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"name_prefix": {
Type: schema.TypeString,
Optional: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"created_by": {
Type: schema.TypeString,
Computed: true,
},
"state": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAwsCloudWatchEventSourceRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatcheventsconn

input := &events.ListEventSourcesInput{}
if v, ok := d.GetOk("name_prefix"); ok {
input.NamePrefix = aws.String(v.(string))
}

log.Printf("[DEBUG] Listing cloudwatch Event sources: %s", input)

resp, err := conn.ListEventSources(input)
if err != nil {
return fmt.Errorf("error listing cloudwatch event sources: %w", err)
}

if resp == nil || len(resp.EventSources) == 0 {
return fmt.Errorf("no matching partner event source")
}
if len(resp.EventSources) > 1 {
return fmt.Errorf("multiple event sources matched; use additional constraints to reduce matches to a single event source")
}

es := resp.EventSources[0]

d.SetId(aws.StringValue(es.Name))
d.Set("arn", es.Arn)
d.Set("created_by", es.CreatedBy)
d.Set("name", es.Name)
d.Set("state", es.State)

return nil
}
51 changes: 51 additions & 0 deletions aws/data_source_aws_cloudwatch_event_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package aws

import (
"fmt"
"os"
"strings"
"testing"

"github.com/aws/aws-sdk-go/service/cloudwatchevents"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceAwsCloudWatchEventSource(t *testing.T) {
//resourceName := "aws_cloudwatch_event_bus.test"
dataSourceName := "data.aws_cloudwatch_event_source.test"

key := "EVENT_BRIDGE_PARTNER_EVENT_BUS_NAME"
busName := os.Getenv(key)
if busName == "" {
t.Skipf("Environment variable %s is not set", key)
}
parts := strings.Split(busName, "/")
if len(parts) < 2 {
t.Errorf("unable to parse partner event bus name %s", busName)
}
namePrefix := parts[0] + "/" + parts[1]
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAwsDataSourcePartnerEventSourceConfig(namePrefix),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "name", busName),
resource.TestCheckResourceAttr(dataSourceName, "created_by", namePrefix),
resource.TestCheckResourceAttrSet(dataSourceName, "arn"),
),
},
},
})
}

func testAccAwsDataSourcePartnerEventSourceConfig(namePrefix string) string {
return fmt.Sprintf(`
data "aws_cloudwatch_event_source" "test" {
name_prefix = "%s"
}
`, namePrefix)
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func Provider() *schema.Provider {
"aws_cloudfront_origin_request_policy": dataSourceAwsCloudFrontOriginRequestPolicy(),
"aws_cloudhsm_v2_cluster": dataSourceCloudHsmV2Cluster(),
"aws_cloudtrail_service_account": dataSourceAwsCloudTrailServiceAccount(),
"aws_cloudwatch_event_source": dataSourceAwsCloudWatchEventSource(),
"aws_cloudwatch_log_group": dataSourceAwsCloudwatchLogGroup(),
"aws_codeartifact_authorization_token": dataSourceAwsCodeArtifactAuthorizationToken(),
"aws_codeartifact_repository_endpoint": dataSourceAwsCodeArtifactRepositoryEndpoint(),
Expand Down
20 changes: 20 additions & 0 deletions aws/resource_aws_cloudwatch_event_bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ 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/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

var (
partnerEventBusPattern = regexp.MustCompile(`^aws\.partner(/[\.\-_A-Za-z0-9]+){2,}$`)
)

func resourceAwsCloudWatchEventBus() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCloudWatchEventBusCreate,
Expand All @@ -27,6 +32,13 @@ func resourceAwsCloudWatchEventBus() *schema.Resource {
ForceNew: true,
ValidateFunc: validateCloudWatchEventCustomEventBusName,
},
"event_source_name": {
Type: schema.TypeString,
Required: false,
Optional: true,
ForceNew: true,
ValidateFunc: validateCloudWatchEventCustomEventBusEventSourceName,
},
"arn": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -49,6 +61,10 @@ func resourceAwsCloudWatchEventBusCreate(d *schema.ResourceData, meta interface{
Name: aws.String(eventBusName),
}

if v, ok := d.GetOk("event_source_name"); ok {
input.EventSourceName = aws.String(v.(string))
}

if len(tags) > 0 {
input.Tags = tags.IgnoreAws().CloudwatcheventsTags()
}
Expand Down Expand Up @@ -91,6 +107,10 @@ func resourceAwsCloudWatchEventBusRead(d *schema.ResourceData, meta interface{})

d.Set("arn", output.Arn)
d.Set("name", output.Name)
// EventSourceName is an input field only, faking it on output if the event bus is a partner bus
if output.Name != nil && partnerEventBusPattern.MatchString(*output.Name) {
d.Set("event_source_name", output.Name)
}

tags, err := keyvaluetags.CloudwatcheventsListTags(conn, aws.StringValue(output.Arn))
if err != nil {
Expand Down
37 changes: 37 additions & 0 deletions aws/resource_aws_cloudwatch_event_bus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aws
import (
"fmt"
"log"
"os"
"regexp"
"testing"

Expand Down Expand Up @@ -218,6 +219,33 @@ func TestAccAWSCloudWatchEventBus_disappears(t *testing.T) {
})
}

func TestAccAWSCloudWatchPartnerEventBus(t *testing.T) {
var busOutput events.DescribeEventBusOutput
resourceName := "aws_cloudwatch_event_bus.test"
key := "EVENT_BRIDGE_PARTNER_EVENT_BUS_NAME"
busName := os.Getenv(key)
if busName == "" {
t.Skipf("Environment variable %s is not set", key)
}
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchPartnerEventBusConfig(busName),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchEventBusExists(resourceName, &busOutput),
resource.TestCheckResourceAttr(resourceName, "name", busName),
testAccCheckResourceAttrRegionalARN(resourceName, "arn", "events", fmt.Sprintf("event-bus/%s", busName)),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
},
})
}

func testAccCheckAWSCloudWatchEventBusDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn

Expand Down Expand Up @@ -315,3 +343,12 @@ resource "aws_cloudwatch_event_bus" "test" {
}
`, name, key1, value1, key2, value2)
}

func testAccAWSCloudWatchPartnerEventBusConfig(name string) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_event_bus" "test" {
name = %[1]q
event_source_name = %[1]q
}
`, name)
}
7 changes: 6 additions & 1 deletion aws/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2347,10 +2347,15 @@ func validateRoute53ResolverName(v interface{}, k string) (ws []string, errors [

var validateCloudWatchEventCustomEventBusName = validation.All(
validation.StringLenBetween(1, 256),
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9._\-]+$`), ""),
validation.StringMatch(regexp.MustCompile(`^[/\.\-_A-Za-z0-9]+$`), ""),
validation.StringDoesNotMatch(regexp.MustCompile(`^default$`), "cannot be 'default'"),
)

var validateCloudWatchEventCustomEventBusEventSourceName = validation.All(
validation.StringLenBetween(1, 256),
validation.StringMatch(regexp.MustCompile(`^aws\.partner(/[\.\-_A-Za-z0-9]+){2,}$`), ""),
)

var validateCloudWatchEventBusNameOrARN = validation.Any(
validateArn,
validation.All(
Expand Down
51 changes: 48 additions & 3 deletions aws/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3136,12 +3136,12 @@ func TestCloudWatchEventCustomEventBusName(t *testing.T) {
IsValid: false,
},
{
Value: "aws.partner/test/test",
IsValid: false,
Value: "aws.partner/example.com/test/12345ab-cdef-1235",
IsValid: true,
},
{
Value: "/test0._1-",
IsValid: false,
IsValid: true,
},
{
Value: "test0._1-",
Expand All @@ -3159,6 +3159,51 @@ func TestCloudWatchEventCustomEventBusName(t *testing.T) {
}
}

func TestCloudWatchEventCustomEventBusEventSourceName(t *testing.T) {
cases := []struct {
Value string
IsValid bool
}{
{
Value: "",
IsValid: false,
},
{
Value: "default",
IsValid: false,
},
{
Value: "aws.partner/example.com/test/" + acctest.RandStringFromCharSet(227, acctest.CharSetAlpha),
IsValid: true,
},
{
Value: "aws.partner/example.com/test/" + acctest.RandStringFromCharSet(228, acctest.CharSetAlpha),
IsValid: false,
},
{
Value: "aws.partner/example.com/test/12345ab-cdef-1235",
IsValid: true,
},
{
Value: "/test0._1-",
IsValid: false,
},
{
Value: "test0._1-",
IsValid: false,
},
}
for _, tc := range cases {
_, errors := validateCloudWatchEventCustomEventBusEventSourceName(tc.Value, "aws_cloudwatch_event_bus_event_source_name")
isValid := len(errors) == 0
if tc.IsValid && !isValid {
t.Errorf("expected %q to return valid, but did not", tc.Value)
} else if !tc.IsValid && isValid {
t.Errorf("expected %q to not return valid, but did", tc.Value)
}
}
}

func TestValidateServiceDiscoveryNamespaceName(t *testing.T) {
validNames := []string{
"ValidName",
Expand Down
1 change: 1 addition & 0 deletions docs/MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi
| `DX_CONNECTION_ID` | Identifier for Direct Connect Connection testing. |
| `DX_VIRTUAL_INTERFACE_ID` | Identifier for Direct Connect Virtual Interface testing. |
| `EC2_SECURITY_GROUP_RULES_PER_GROUP_LIMIT` | EC2 Quota for Rules per Security Group. Defaults to 50. **DEPRECATED:** Can be augmented or replaced with Service Quotas lookup. |
| `EVENT_BRIDGE_PARTNER_EVENT_BUS_NAME` | Amazon EventBridge partner event bus name. |
| `GCM_API_KEY` | API Key for Google Cloud Messaging in Pinpoint and SNS Platform Application testing. |
| `GITHUB_TOKEN` | GitHub token for CodePipeline testing. |
| `MACIE_MEMBER_ACCOUNT_ID` | Identifier of AWS Account for Macie Member testing. **DEPRECATED:** Should be replaced with standard alternate account handling for tests. |
Expand Down
40 changes: 40 additions & 0 deletions website/docs/d/cloudwatch_event_source.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
subcategory: "CloudWatch"
layout: "aws"
page_title: "AWS: aws_cloudwatch_event_source"
description: |-
Get information on an EventBridge (Cloudwatch) Event Source.
---

# Data Source: aws_cloudwatch_event_source

Use this data source to get information about an EventBridge Partner Event Source. This data source will only return one partner event source. An error will be returned if multiple sources match the same name prefix.

~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical.

## Example Usage

```terraform
data "aws_cloudwatch_event_source" "examplepartner" {
name_prefix = "aws.partner/examplepartner.com"
}

resource "aws_cloudwatch_event_bus" "examplepartner" {
name = data.aws_cloudwatch_event_source.examplepartner.name
event_source_name = data.aws_cloudwatch_event_source.examplepartner.name
}
```

## Argument Reference

The following arguments are supported:

* `name_prefix` - (Optional) A name prefix to filter results returned. Only API destinations with a name that starts with the prefix are returned

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `arn` - The ARN of the Partner event source
* `created_by` - The name of the SaaS partner that created the event source.
* `state` - The state of the event source (`ACTIVE` or `PENDING`)
Loading