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

New Resource: aws_cloudwatch_log_resource_policy #2243

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ func Provider() terraform.ResourceProvider {
"aws_cloudwatch_log_destination_policy": resourceAwsCloudWatchLogDestinationPolicy(),
"aws_cloudwatch_log_group": resourceAwsCloudWatchLogGroup(),
"aws_cloudwatch_log_metric_filter": resourceAwsCloudWatchLogMetricFilter(),
"aws_cloudwatch_log_resource_policy": resourceAwsCloudWatchLogResourcePolicy(),
"aws_cloudwatch_log_stream": resourceAwsCloudWatchLogStream(),
"aws_cloudwatch_log_subscription_filter": resourceAwsCloudwatchLogSubscriptionFilter(),
"aws_config_config_rule": resourceAwsConfigConfigRule(),
Expand Down
118 changes: 118 additions & 0 deletions aws/resource_aws_cloudwatch_log_resource_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCloudWatchLogResourcePolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCloudWatchLogResourcePolicyPut,
Read: resourceAwsCloudWatchLogResourcePolicyRead,
Update: resourceAwsCloudWatchLogResourcePolicyPut,
Delete: resourceAwsCloudWatchLogResourcePolicyDelete,

Importer: &schema.ResourceImporter{
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
d.Set("policy_name", d.Id())
return []*schema.ResourceData{d}, nil
},
},

Schema: map[string]*schema.Schema{
"policy_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"policy_document": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateCloudWatchLogResourcePolicyDocument,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},
},
}
}

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

policyName := d.Get("policy_name").(string)

input := &cloudwatchlogs.PutResourcePolicyInput{
PolicyDocument: aws.String(d.Get("policy_document").(string)),
PolicyName: aws.String(policyName),
}

log.Printf("[DEBUG] Writing CloudWatch log resource policy: %#v", input)
_, err := conn.PutResourcePolicy(input)

if err != nil {
return fmt.Errorf("Writing CloudWatch log resource policy failed: %s", err.Error())
}

d.SetId(policyName)
return resourceAwsCloudWatchLogResourcePolicyRead(d, meta)
}

func resourceAwsCloudWatchLogResourcePolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatchlogsconn
policyName := d.Get("policy_name").(string)
resourcePolicy, exists, err := lookupCloudWatchLogResourcePolicy(conn, policyName, nil)
if err != nil {
return err
}

if !exists {
d.SetId("")
return nil
}

d.SetId(policyName)
d.Set("policy_document", *resourcePolicy.PolicyDocument)

return nil
}

func resourceAwsCloudWatchLogResourcePolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatchlogsconn
input := cloudwatchlogs.DeleteResourcePolicyInput{
PolicyName: aws.String(d.Id()),
}

log.Printf("[DEBUG] Deleting CloudWatch log resource policy: %#v", input)
_, err := conn.DeleteResourcePolicy(&input)
if err != nil {
return fmt.Errorf("Deleting CloudWatch log resource policy '%s' failed: %s", *input.PolicyName, err.Error())
}
return nil
}

func lookupCloudWatchLogResourcePolicy(conn *cloudwatchlogs.CloudWatchLogs,
name string, nextToken *string) (*cloudwatchlogs.ResourcePolicy, bool, error) {
input := &cloudwatchlogs.DescribeResourcePoliciesInput{
NextToken: nextToken,
}
log.Printf("[DEBUG] Reading CloudWatch log resource policies: %#v", input)
resp, err := conn.DescribeResourcePolicies(input)
if err != nil {
return nil, true, err
}

for _, resourcePolicy := range resp.ResourcePolicies {
if *resourcePolicy.PolicyName == name {
return resourcePolicy, true, nil
}
}

if resp.NextToken != nil {
return lookupCloudWatchLogResourcePolicy(conn, name, resp.NextToken)
}

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

import (
"fmt"
"testing"

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

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCloudWatchLogResourcePolicy_Basic(t *testing.T) {
name := acctest.RandString(5)
var resourcePolicy cloudwatchlogs.ResourcePolicy
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudWatchLogResourcePolicyDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckAWSCloudWatchLogResourcePolicyResourceConfigBasic1(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogResourcePolicy("aws_cloudwatch_log_resource_policy.test", &resourcePolicy),
resource.TestCheckResourceAttr("aws_cloudwatch_log_resource_policy.test", "policy_name", name),
resource.TestCheckResourceAttr("aws_cloudwatch_log_resource_policy.test", "policy_document", "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"route53.amazonaws.com\"},\"Action\":[\"logs:PutLogEvents\",\"logs:CreateLogStream\"],\"Resource\":\"arn:aws:logs:*:*:log-group:/aws/route53/*\"}]}"),
),
},
resource.TestStep{
Config: testAccCheckAWSCloudWatchLogResourcePolicyResourceConfigBasic2(name),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogResourcePolicy("aws_cloudwatch_log_resource_policy.test", &resourcePolicy),
resource.TestCheckResourceAttr("aws_cloudwatch_log_resource_policy.test", "policy_name", name),
resource.TestCheckResourceAttr("aws_cloudwatch_log_resource_policy.test", "policy_document", "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"route53.amazonaws.com\"},\"Action\":[\"logs:PutLogEvents\",\"logs:CreateLogStream\"],\"Resource\":\"arn:aws:logs:*:*:log-group:/aws/route53/example.com\"}]}"),
),
},
},
})
}

func TestAccAWSCloudWatchLogResourcePolicy_Import(t *testing.T) {
resourceName := "aws_cloudwatch_log_resource_policy.test"

name := acctest.RandString(5)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudWatchLogResourcePolicyDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckAWSCloudWatchLogResourcePolicyResourceConfigBasic1(name),
},

resource.TestStep{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckCloudWatchLogResourcePolicy(pr string, resourcePolicy *cloudwatchlogs.ResourcePolicy) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).cloudwatchlogsconn
rs, ok := s.RootModule().Resources[pr]
if !ok {
return fmt.Errorf("Not found: %s", pr)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

policy, exists, err := lookupCloudWatchLogResourcePolicy(conn, rs.Primary.ID, nil)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("Resource policy does not exist: %q", rs.Primary.ID)
}

*resourcePolicy = *policy

return nil
}
}

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

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_cloudwatch_log_resource_policy" {
continue
}

_, exists, err := lookupCloudWatchLogResourcePolicy(conn, rs.Primary.ID, nil)
if err != nil {
return nil
}

if exists {
return fmt.Errorf("Resource policy exists: %q", rs.Primary.ID)
}
}

return nil
}

func testAccCheckAWSCloudWatchLogResourcePolicyResourceConfigBasic1(name string) string {
return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]

resources = ["arn:aws:logs:*:*:log-group:/aws/route53/*"]

principals {
identifiers = ["route53.amazonaws.com"]
type = "Service"
}
}
}

resource "aws_cloudwatch_log_resource_policy" "test" {
policy_name = "%s"
policy_document = "${data.aws_iam_policy_document.test.json}"
}
`, name)
}

func testAccCheckAWSCloudWatchLogResourcePolicyResourceConfigBasic2(name string) string {
return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]

resources = ["arn:aws:logs:*:*:log-group:/aws/route53/example.com"]

principals {
identifiers = ["route53.amazonaws.com"]
type = "Service"
}
}
}

resource "aws_cloudwatch_log_resource_policy" "test" {
policy_name = "%s"
policy_document = "${data.aws_iam_policy_document.test.json}"
}
`, name)
}
12 changes: 12 additions & 0 deletions aws/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@ func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, erro
return
}

func validateCloudWatchLogResourcePolicyDocument(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutResourcePolicy.html
if len(value) > 5120 || (len(value) == 0) {
errors = append(errors, fmt.Errorf("CloudWatch log resource policy document must be between 1 and 5120 characters."))
}
if _, err := normalizeJsonString(v); err != nil {
errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
}
return
}

func validateMaxLength(length int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
Expand Down
4 changes: 4 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@
<a href="/docs/providers/aws/r/cloudwatch_log_metric_filter.html">aws_cloudwatch_log_metric_filter</a>
</li>

<li<%= sidebar_current("docs-aws-resource-cloudwatch-log-resource-policy") %>>
<a href="/docs/providers/aws/r/cloudwatch_log_resource_policy.html">aws_cloudwatch_log_resource_policy</a>
</li>

<li<%= sidebar_current("docs-aws-resource-cloudwatch-log-stream") %>>
<a href="/docs/providers/aws/r/cloudwatch_log_stream.html">aws_cloudwatch_log_stream</a>
</li>
Expand Down
59 changes: 59 additions & 0 deletions website/docs/r/cloudwatch_log_resource_policy.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
layout: "aws"
page_title: "AWS: aws_cloudwatch_log_resource_policy"
sidebar_current: "docs-aws-resource-cloudwatch-log-resource-policy"
description: |-
Provides a resource to manage a CloudWatch log resource policy
---

# aws_cloudwatch_log_resource_policy

Provides a resource to manage a CloudWatch log resource policy.

## Example Usage

### Route53 Query Logging

```hcl
data "aws_iam_policy_document" "route53-query-logging-policy" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]
resources = ["arn:aws:logs:*:*:log-group:/aws/route53/*"]
principals {
identifiers = ["route53.amazonaws.com"]
type = "Service"
}
}
}
resource "aws_cloudwatch_log_resource_policy" "route53-query-logging-policy" {
policy_document = "${data.aws_iam_policy_document.route53-query-logging-policy.json}"
policy_name = "route53-query-logging-policy"
}
```

## Argument Reference

The following arguments are supported:

* `policy_document` - (Required) Details of the resource policy, including the identity of the principal that is enabled to put logs to this account. This is formatted as a JSON string. Maximum length of 5120 characters.
* `policy_name` - (Required) Name of the resource policy.

## Attributes Reference

The following additional attributes are exported:

* `id` - The name of the CloudWatch log resource policy

## Import

CloudWatch log resource policies can be imported using the policy name, e.g.

```
$ terraform import aws_cloudwatch_log_resource_policy.MyPolicy MyPolicy
```