Add `name_prefix` support to `aws_cloudwatch_log_group` (#13273)

This commit is contained in:
Joshua Spence 2017-04-17 08:50:52 +10:00 committed by Paul Stack
parent 1da9a06a64
commit 8d5fdeae57
5 changed files with 131 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
@ -24,10 +25,18 @@ func resourceAwsCloudWatchLogGroup() *schema.Resource {
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": { "name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateLogGroupName,
},
"name_prefix": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validateLogGroupName, ValidateFunc: validateLogGroupNamePrefix,
}, },
"retention_in_days": { "retention_in_days": {
@ -49,10 +58,19 @@ func resourceAwsCloudWatchLogGroup() *schema.Resource {
func resourceAwsCloudWatchLogGroupCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsCloudWatchLogGroupCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cloudwatchlogsconn conn := meta.(*AWSClient).cloudwatchlogsconn
log.Printf("[DEBUG] Creating CloudWatch Log Group: %s", d.Get("name").(string)) var logGroupName string
if v, ok := d.GetOk("name"); ok {
logGroupName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
logGroupName = resource.PrefixedUniqueId(v.(string))
} else {
logGroupName = resource.UniqueId()
}
log.Printf("[DEBUG] Creating CloudWatch Log Group: %s", logGroupName)
_, err := conn.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{ _, err := conn.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{
LogGroupName: aws.String(d.Get("name").(string)), LogGroupName: aws.String(logGroupName),
}) })
if err != nil { if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceAlreadyExistsException" { if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceAlreadyExistsException" {
@ -61,7 +79,7 @@ func resourceAwsCloudWatchLogGroupCreate(d *schema.ResourceData, meta interface{
return fmt.Errorf("Creating CloudWatch Log Group failed: %s '%s'", err, d.Get("name")) return fmt.Errorf("Creating CloudWatch Log Group failed: %s '%s'", err, d.Get("name"))
} }
d.SetId(d.Get("name").(string)) d.SetId(logGroupName)
log.Println("[INFO] CloudWatch Log Group created") log.Println("[INFO] CloudWatch Log Group created")

View File

@ -2,6 +2,7 @@ package aws
import ( import (
"fmt" "fmt"
"regexp"
"testing" "testing"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/aws-sdk-go/service/cloudwatchlogs"
@ -30,6 +31,43 @@ func TestAccAWSCloudWatchLogGroup_basic(t *testing.T) {
}) })
} }
func TestAccAWSCloudWatchLogGroup_namePrefix(t *testing.T) {
var lg cloudwatchlogs.LogGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchLogGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchLogGroup_namePrefix,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogGroupExists("aws_cloudwatch_log_group.test", &lg),
resource.TestMatchResourceAttr("aws_cloudwatch_log_group.test", "name", regexp.MustCompile("^tf-test-")),
),
},
},
})
}
func TestAccAWSCloudWatchLogGroup_generatedName(t *testing.T) {
var lg cloudwatchlogs.LogGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchLogGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchLogGroup_generatedName,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogGroupExists("aws_cloudwatch_log_group.test", &lg),
),
},
},
})
}
func TestAccAWSCloudWatchLogGroup_retentionPolicy(t *testing.T) { func TestAccAWSCloudWatchLogGroup_retentionPolicy(t *testing.T) {
var lg cloudwatchlogs.LogGroup var lg cloudwatchlogs.LogGroup
rInt := acctest.RandInt() rInt := acctest.RandInt()
@ -256,3 +294,13 @@ resource "aws_cloudwatch_log_group" "charlie" {
} }
`, rInt, rInt+1, rInt+2) `, rInt, rInt+1, rInt+2)
} }
const testAccAWSCloudWatchLogGroup_namePrefix = `
resource "aws_cloudwatch_log_group" "test" {
name_prefix = "tf-test-"
}
`
const testAccAWSCloudWatchLogGroup_generatedName = `
resource "aws_cloudwatch_log_group" "test" {}
`

View File

@ -483,6 +483,26 @@ func validateLogGroupName(v interface{}, k string) (ws []string, errors []error)
return return
} }
func validateLogGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) > 483 {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than 483 characters: %q", k, value))
}
// http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
pattern := `^[\.\-_/#A-Za-z0-9]+$`
if !regexp.MustCompile(pattern).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q isn't a valid log group name (alphanumeric characters, underscores,"+
" hyphens, slashes, hash signs and dots are allowed): %q",
k, value))
}
return
}
func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) { func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) {
value := v.(string) value := v.(string)
_, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value)) _, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value))

View File

@ -410,7 +410,7 @@ func TestValidateLogGroupName(t *testing.T) {
for _, v := range validNames { for _, v := range validNames {
_, errors := validateLogGroupName(v, "name") _, errors := validateLogGroupName(v, "name")
if len(errors) != 0 { if len(errors) != 0 {
t.Fatalf("%q should be a valid Log Metric Filter Transformation Name: %q", v, errors) t.Fatalf("%q should be a valid Log Group name: %q", v, errors)
} }
} }
@ -427,7 +427,42 @@ func TestValidateLogGroupName(t *testing.T) {
for _, v := range invalidNames { for _, v := range invalidNames {
_, errors := validateLogGroupName(v, "name") _, errors := validateLogGroupName(v, "name")
if len(errors) == 0 { if len(errors) == 0 {
t.Fatalf("%q should be an invalid Log Metric Filter Transformation Name", v) t.Fatalf("%q should be an invalid Log Group name", v)
}
}
}
func TestValidateLogGroupNamePrefix(t *testing.T) {
validNames := []string{
"ValidLogGroupName",
"ValidLogGroup.Name",
"valid/Log-group",
"1234",
"YadaValid#0123",
"Also_valid-name",
strings.Repeat("W", 483),
}
for _, v := range validNames {
_, errors := validateLogGroupNamePrefix(v, "name_prefix")
if len(errors) != 0 {
t.Fatalf("%q should be a valid Log Group name prefix: %q", v, errors)
}
}
invalidNames := []string{
"Here is a name with: colon",
"and here is another * invalid name",
"also $ invalid",
"This . is also %% invalid@!)+(",
"*",
"",
// length > 483
strings.Repeat("W", 484),
}
for _, v := range invalidNames {
_, errors := validateLogGroupNamePrefix(v, "name_prefix")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid Log Group name prefix", v)
} }
} }
} }

View File

@ -27,7 +27,8 @@ resource "aws_cloudwatch_log_group" "yada" {
The following arguments are supported: The following arguments are supported:
* `name` - (Required) The name of the log group * `name` - (Optional, Forces new resource) The name of the log group. If omitted, Terraform will assign a random, unique name.
* `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `retention_in_days` - (Optional) Specifies the number of days * `retention_in_days` - (Optional) Specifies the number of days
you want to retain log events in the specified log group. you want to retain log events in the specified log group.
* `tags` - (Optional) A mapping of tags to assign to the resource. * `tags` - (Optional) A mapping of tags to assign to the resource.
@ -45,4 +46,4 @@ Cloudwatch Log Groups can be imported using the `name`, e.g.
``` ```
$ terraform import aws_cloudwatch_log_group.test_group yada $ terraform import aws_cloudwatch_log_group.test_group yada
``` ```