Merge pull request #3756 from hashicorp/pr-3708
providers/aws: Add `access_logs` to ELB resource [GH-3756]
This commit is contained in:
commit
caa0baaf87
|
@ -107,6 +107,29 @@ func resourceAwsElb() *schema.Resource {
|
|||
Default: 300,
|
||||
},
|
||||
|
||||
"access_logs": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"interval": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 60,
|
||||
},
|
||||
"bucket": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"bucket_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: resourceAwsElbAccessLogsHash,
|
||||
},
|
||||
|
||||
"listener": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
|
@ -323,6 +346,11 @@ func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("idle_timeout", lbAttrs.ConnectionSettings.IdleTimeout)
|
||||
d.Set("connection_draining", lbAttrs.ConnectionDraining.Enabled)
|
||||
d.Set("connection_draining_timeout", lbAttrs.ConnectionDraining.Timeout)
|
||||
if lbAttrs.AccessLog != nil {
|
||||
if err := d.Set("access_logs", flattenAccessLog(lbAttrs.AccessLog)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := elbconn.DescribeTags(&elb.DescribeTagsInput{
|
||||
LoadBalancerNames: []*string{lb.LoadBalancerName},
|
||||
|
@ -423,7 +451,7 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
d.SetPartial("instances")
|
||||
}
|
||||
|
||||
if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") {
|
||||
if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") || d.HasChange("access_logs") {
|
||||
attrs := elb.ModifyLoadBalancerAttributesInput{
|
||||
LoadBalancerName: aws.String(d.Get("name").(string)),
|
||||
LoadBalancerAttributes: &elb.LoadBalancerAttributes{
|
||||
|
@ -436,6 +464,30 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
},
|
||||
}
|
||||
|
||||
logs := d.Get("access_logs").(*schema.Set).List()
|
||||
if len(logs) > 1 {
|
||||
return fmt.Errorf("Only one access logs config per ELB is supported")
|
||||
} else if len(logs) == 1 {
|
||||
log := logs[0].(map[string]interface{})
|
||||
accessLog := &elb.AccessLog{
|
||||
Enabled: aws.Bool(true),
|
||||
EmitInterval: aws.Int64(int64(log["interval"].(int))),
|
||||
S3BucketName: aws.String(log["bucket"].(string)),
|
||||
}
|
||||
|
||||
if log["bucket_prefix"] != "" {
|
||||
accessLog.S3BucketPrefix = aws.String(log["bucket_prefix"].(string))
|
||||
}
|
||||
|
||||
attrs.LoadBalancerAttributes.AccessLog = accessLog
|
||||
} else if len(logs) == 0 {
|
||||
// disable access logs
|
||||
attrs.LoadBalancerAttributes.AccessLog = &elb.AccessLog{
|
||||
Enabled: aws.Bool(false),
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] ELB Modify Load Balancer Attributes Request: %#v", attrs)
|
||||
_, err := elbconn.ModifyLoadBalancerAttributes(&attrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failure configuring ELB attributes: %s", err)
|
||||
|
@ -568,6 +620,19 @@ func resourceAwsElbHealthCheckHash(v interface{}) int {
|
|||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func resourceAwsElbAccessLogsHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int)))
|
||||
buf.WriteString(fmt.Sprintf("%s-",
|
||||
strings.ToLower(m["bucket"].(string))))
|
||||
if v, ok := m["bucket_prefix"]; ok {
|
||||
buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(v.(string))))
|
||||
}
|
||||
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func resourceAwsElbListenerHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
|
|
|
@ -75,6 +75,52 @@ func TestAccAWSELB_fullCharacterRange(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSELB_AccessLogs(t *testing.T) {
|
||||
var conf elb.LoadBalancerDescription
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSELBDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAccessLogs,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.foo", &conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "name", "FoobarTerraform-test123"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAccessLogsOn,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.foo", &conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "name", "FoobarTerraform-test123"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "access_logs.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "access_logs.1713209538.bucket", "terraform-access-logs-bucket"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "access_logs.1713209538.interval", "5"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccAWSELBAccessLogs,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSELBExists("aws_elb.foo", &conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "name", "FoobarTerraform-test123"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.foo", "access_logs.#", "0"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSELB_generatedName(t *testing.T) {
|
||||
var conf elb.LoadBalancerDescription
|
||||
generatedNameRegexp := regexp.MustCompile("^tf-lb-")
|
||||
|
@ -659,6 +705,64 @@ resource "aws_elb" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccAWSELBAccessLogs = `
|
||||
resource "aws_elb" "foo" {
|
||||
name = "FoobarTerraform-test123"
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
}
|
||||
`
|
||||
const testAccAWSELBAccessLogsOn = `
|
||||
# an S3 bucket configured for Access logs
|
||||
# The 797873946194 is the AWS ID for us-west-2, so this test
|
||||
# must be ran in us-west-2
|
||||
resource "aws_s3_bucket" "acceslogs_bucket" {
|
||||
bucket = "terraform-access-logs-bucket"
|
||||
acl = "private"
|
||||
force_destroy = true
|
||||
policy = <<EOF
|
||||
{
|
||||
"Id": "Policy1446577137248",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "s3:PutObject",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::797873946194:root"
|
||||
},
|
||||
"Resource": "arn:aws:s3:::terraform-access-logs-bucket/*",
|
||||
"Sid": "Stmt1446575236270"
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17"
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_elb" "foo" {
|
||||
name = "FoobarTerraform-test123"
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
lb_port = 80
|
||||
lb_protocol = "http"
|
||||
}
|
||||
|
||||
access_logs {
|
||||
interval = 5
|
||||
bucket = "${aws_s3_bucket.acceslogs_bucket.bucket}"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAWSELBGeneratedName = `
|
||||
resource "aws_elb" "foo" {
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
|
|
@ -238,6 +238,33 @@ func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.Param
|
|||
return parameters, nil
|
||||
}
|
||||
|
||||
// Flattens an access log into something that flatmap.Flatten() can handle
|
||||
func flattenAccessLog(log *elb.AccessLog) []map[string]interface{} {
|
||||
result := make([]map[string]interface{}, 0, 1)
|
||||
|
||||
if log != nil {
|
||||
r := make(map[string]interface{})
|
||||
// enabled is the only value we can rely on to not be nil
|
||||
r["enabled"] = *log.Enabled
|
||||
|
||||
if log.S3BucketName != nil {
|
||||
r["bucket"] = *log.S3BucketName
|
||||
}
|
||||
|
||||
if log.S3BucketPrefix != nil {
|
||||
r["bucket_prefix"] = *log.S3BucketPrefix
|
||||
}
|
||||
|
||||
if log.EmitInterval != nil {
|
||||
r["interval"] = *log.EmitInterval
|
||||
}
|
||||
|
||||
result = append(result, r)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Flattens a health check into something that flatmap.Flatten()
|
||||
// can handle
|
||||
func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} {
|
||||
|
|
|
@ -18,6 +18,12 @@ resource "aws_elb" "bar" {
|
|||
name = "foobar-terraform-elb"
|
||||
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
|
||||
|
||||
access_logs {
|
||||
bucket = "foo"
|
||||
bucket_prefix = "bar"
|
||||
interval = 60
|
||||
}
|
||||
|
||||
listener {
|
||||
instance_port = 8000
|
||||
instance_protocol = "http"
|
||||
|
@ -58,6 +64,7 @@ resource "aws_elb" "bar" {
|
|||
The following arguments are supported:
|
||||
|
||||
* `name` - (Optional) The name of the ELB. By default generated by terraform.
|
||||
* `access_logs` - (Optional) An Access Logs block. Access Logs documented below.
|
||||
* `availability_zones` - (Required for an EC2-classic ELB) The AZ's to serve traffic in.
|
||||
* `security_groups` - (Optional) A list of security group IDs to assign to the ELB.
|
||||
* `subnets` - (Required for a VPC ELB) A list of subnet IDs to attach to the ELB.
|
||||
|
@ -74,6 +81,12 @@ The following arguments are supported:
|
|||
Exactly one of `availability_zones` or `subnets` must be specified: this
|
||||
determines if the ELB exists in a VPC or in EC2-classic.
|
||||
|
||||
Access Logs support the following:
|
||||
|
||||
* `bucket` - (Required) The S3 bucket name to store the logs in.
|
||||
* `bucket_prefix` - (Optional) The S3 bucket prefix. Logs are stored in the root if not configured.
|
||||
* `interval` - (Optional) The publishing interval in minutes. Default: 60 minutes.
|
||||
|
||||
Listeners support the following:
|
||||
|
||||
* `instance_port` - (Required) The port on the instance to route to
|
||||
|
|
Loading…
Reference in New Issue