provider/aws: Add aws_elasticsearch_domain_policy (#8648)

This commit is contained in:
Radek Simko 2017-02-08 13:20:57 +00:00 committed by GitHub
parent d3c9a4b265
commit c25579a6f8
7 changed files with 315 additions and 0 deletions

View File

@ -0,0 +1,38 @@
package aws
import (
"fmt"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/jen20/awspolicyequivalence"
)
func testAccCheckAwsPolicyMatch(resource, attr, expectedPolicy string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resource]
if !ok {
return fmt.Errorf("Not found: %s", resource)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
given, ok := rs.Primary.Attributes[attr]
if !ok {
return fmt.Errorf("Attribute %q not found for %q", attr, resource)
}
areEquivalent, err := awspolicy.PoliciesAreEquivalent(given, expectedPolicy)
if err != nil {
return fmt.Errorf("Comparing AWS Policies failed: %s", err)
}
if !areEquivalent {
return fmt.Errorf("AWS policies differ.\nGiven: %s\nExpected: %s", given, expectedPolicy)
}
return nil
}
}

View File

@ -278,6 +278,7 @@ func Provider() terraform.ResourceProvider {
"aws_elastic_beanstalk_configuration_template": resourceAwsElasticBeanstalkConfigurationTemplate(),
"aws_elastic_beanstalk_environment": resourceAwsElasticBeanstalkEnvironment(),
"aws_elasticsearch_domain": resourceAwsElasticSearchDomain(),
"aws_elasticsearch_domain_policy": resourceAwsElasticSearchDomainPolicy(),
"aws_elastictranscoder_pipeline": resourceAwsElasticTranscoderPipeline(),
"aws_elastictranscoder_preset": resourceAwsElasticTranscoderPreset(),
"aws_elb": resourceAwsElb(),

View File

@ -25,6 +25,7 @@ func resourceAwsElasticSearchDomain() *schema.Resource {
"access_policies": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validateJsonString,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},

View File

@ -0,0 +1,127 @@
package aws
import (
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsElasticSearchDomainPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsElasticSearchDomainPolicyUpsert,
Read: resourceAwsElasticSearchDomainPolicyRead,
Update: resourceAwsElasticSearchDomainPolicyUpsert,
Delete: resourceAwsElasticSearchDomainPolicyDelete,
Schema: map[string]*schema.Schema{
"domain_name": {
Type: schema.TypeString,
Required: true,
},
"access_policies": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},
},
}
}
func resourceAwsElasticSearchDomainPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).esconn
name := d.Get("domain_name").(string)
out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{
DomainName: aws.String(name),
})
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFound" {
log.Printf("[WARN] ElasticSearch Domain %q not found, removing", name)
d.SetId("")
return nil
}
return err
}
log.Printf("[DEBUG] Received ElasticSearch domain: %s", out)
ds := out.DomainStatus
d.Set("access_policies", ds.AccessPolicies)
return nil
}
func resourceAwsElasticSearchDomainPolicyUpsert(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).esconn
domainName := d.Get("domain_name").(string)
_, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{
DomainName: aws.String(domainName),
AccessPolicies: aws.String(d.Get("access_policies").(string)),
})
if err != nil {
return err
}
d.SetId("esd-policy-" + domainName)
err = resource.Retry(50*time.Minute, func() *resource.RetryError {
out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{
DomainName: aws.String(d.Get("domain_name").(string)),
})
if err != nil {
return resource.NonRetryableError(err)
}
if *out.DomainStatus.Processing == false {
return nil
}
return resource.RetryableError(
fmt.Errorf("%q: Timeout while waiting for changes to be processed", d.Id()))
})
if err != nil {
return err
}
return resourceAwsElasticSearchDomainPolicyRead(d, meta)
}
func resourceAwsElasticSearchDomainPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).esconn
_, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{
DomainName: aws.String(d.Get("domain_name").(string)),
AccessPolicies: aws.String(""),
})
if err != nil {
return err
}
log.Printf("[DEBUG] Waiting for ElasticSearch domain policy %q to be deleted", d.Get("domain_name").(string))
err = resource.Retry(60*time.Minute, func() *resource.RetryError {
out, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{
DomainName: aws.String(d.Get("domain_name").(string)),
})
if err != nil {
return resource.NonRetryableError(err)
}
if *out.DomainStatus.Processing == false {
return nil
}
return resource.RetryableError(
fmt.Errorf("%q: Timeout while waiting for policy to be deleted", d.Id()))
})
if err != nil {
return err
}
d.SetId("")
return nil
}

View File

@ -0,0 +1,97 @@
package aws
import (
"fmt"
"testing"
elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSElasticSearchDomainPolicy_basic(t *testing.T) {
var domain elasticsearch.ElasticsearchDomainStatus
ri := acctest.RandInt()
policy := `{
"Version": "2012-10-17",
"Statement": [
{
"Action": "es:*",
"Principal": "*",
"Effect": "Allow",
"Condition": {
"IpAddress": {"aws:SourceIp": "127.0.0.1/32"}
},
"Resource": "${aws_elasticsearch_domain.example.arn}"
}
]
}`
expectedPolicyTpl := `{
"Version": "2012-10-17",
"Statement": [
{
"Action": "es:*",
"Principal": "*",
"Effect": "Allow",
"Condition": {
"IpAddress": {"aws:SourceIp": "127.0.0.1/32"}
},
"Resource": "%s"
}
]
}`
name := fmt.Sprintf("tf-test-%d", ri)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckESDomainDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccESDomainPolicyConfig(ri, policy),
Check: resource.ComposeTestCheckFunc(
testAccCheckESDomainExists("aws_elasticsearch_domain.example", &domain),
resource.TestCheckResourceAttr("aws_elasticsearch_domain.example", "elasticsearch_version", "2.3"),
func(s *terraform.State) error {
awsClient := testAccProvider.Meta().(*AWSClient)
expectedArn, err := buildESDomainArn(name, awsClient.partition, awsClient.accountid, awsClient.region)
if err != nil {
return err
}
expectedPolicy := fmt.Sprintf(expectedPolicyTpl, expectedArn)
return testAccCheckAwsPolicyMatch("aws_elasticsearch_domain_policy.main", "access_policies", expectedPolicy)(s)
},
),
},
},
})
}
func buildESDomainArn(name, partition, accId, region string) (string, error) {
if partition == "" {
return "", fmt.Errorf("Unable to construct ES Domain ARN because of missing AWS partition")
}
if accId == "" {
return "", fmt.Errorf("Unable to construct ES Domain ARN because of missing AWS Account ID")
}
// arn:aws:es:us-west-2:187416307283:domain/example-name
return fmt.Sprintf("arn:%s:es:%s:%s:domain/%s", partition, region, accId, name), nil
}
func testAccESDomainPolicyConfig(randInt int, policy string) string {
return fmt.Sprintf(`
resource "aws_elasticsearch_domain" "example" {
domain_name = "tf-test-%d"
elasticsearch_version = "2.3"
}
resource "aws_elasticsearch_domain_policy" "main" {
domain_name = "${aws_elasticsearch_domain.example.domain_name}"
access_policies = <<POLICIES
%s
POLICIES
}
`, randInt, policy)
}

View File

@ -0,0 +1,47 @@
---
layout: "aws"
page_title: "AWS: aws_elasticsearch_domain"
sidebar_current: "docs-aws-resource-elasticsearch-domain"
description: |-
Provides an ElasticSearch Domain.
---
# aws\_elasticsearch\_domain\_policy
Allows setting policy to an ElasticSearch domain while referencing domain attributes (e.g. ARN)
## Example Usage
```
resource "aws_elasticsearch_domain" "example" {
domain_name = "tf-test"
elasticsearch_version = "2.3"
}
resource "aws_elasticsearch_domain_policy" "main" {
domain_name = "${aws_elasticsearch_domain.example.domain_name}"
access_policies = <<POLICIES
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "es:*",
"Principal": "*",
"Effect": "Allow",
"Condition": {
"IpAddress": {"aws:SourceIp": "127.0.0.1/32"}
},
"Resource": "${aws_elasticsearch_domain.example.arn}"
}
]
}
POLICIES
}
```
## Argument Reference
The following arguments are supported:
* `domain_name` - (Required) Name of the domain.
* `access_policies` - (Optional) IAM policy document specifying the access policies for the domain

View File

@ -609,6 +609,10 @@
<a href="/docs/providers/aws/r/elasticsearch_domain.html">aws_elasticsearch_domain</a>
</li>
<li<%= sidebar_current("docs-aws-resource-elasticsearch-domain-policy") %>>
<a href="/docs/providers/aws/r/elasticsearch_domain_policy.html">aws_elasticsearch_domain_policy</a>
</li>
</ul>
</li>