Skip to content

Commit

Permalink
r/aws_cloudsearch_domain_service_access_policy: New resource.
Browse files Browse the repository at this point in the history
  • Loading branch information
ewbankkit committed Dec 13, 2021
1 parent a9c8cfc commit 933837c
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 43 deletions.
4 changes: 4 additions & 0 deletions .changelog/17723.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
```release-note:new-resource
aws_cloudsearch_domain
```

```release-note:new-resource
aws_cloudsearch_domain_service_access_policy
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,7 @@ func Provider() *schema.Provider {
"aws_cloudhsm_v2_hsm": cloudhsmv2.ResourceHSM(),

"aws_cloudsearch_domain": cloudsearch.ResourceDomain(),
"aws_cloudsearch_domain_service_access_policy": cloudsearch.ResourceDomainServiceAccessPolicy(),

"aws_cloudtrail": cloudtrail.ResourceCloudTrail(),

Expand Down
44 changes: 1 addition & 43 deletions internal/service/cloudsearch/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import (
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

func ResourceDomain() *schema.Resource {
Expand All @@ -37,18 +35,6 @@ func ResourceDomain() *schema.Resource {
},

Schema: map[string]*schema.Schema{
// TODO: Separate access policy resource?
// TODO: Is it Required?
"access_policies": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},
"arn": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -204,17 +190,6 @@ func resourceCloudSearchDomainCreate(d *schema.ResourceData, meta interface{}) e

d.SetId(name)

// TODO: Separate domain access policy resource?
// log.Printf("[DEBUG] Updating CloudSearch Domain (%s) access policies", name)
// _, err = conn.UpdateServiceAccessPolicies(&cloudsearch.UpdateServiceAccessPoliciesInput{
// DomainName: aws.String(d.Id()),
// AccessPolicies: aws.String(d.Get("access_policies").(string)),
// })

// if err != nil {
// return fmt.Errorf("error updating CloudSearch Domain (%s) service access policies: %w", d.Id(), err)
// }

if v, ok := d.GetOk("scaling_parameters"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
input := &cloudsearch.UpdateScalingParametersInput{
DomainName: aws.String(d.Id()),
Expand Down Expand Up @@ -373,30 +348,13 @@ func resourceCloudSearchDomainRead(d *schema.ResourceData, meta interface{}) err
}
d.Set("index", result)

// Read service access policies.
// policyResult, err := conn.DescribeServiceAccessPolicies(&cloudsearch.DescribeServiceAccessPoliciesInput{
// DomainName: aws.String(d.Get("name").(string)),
// })
// if err != nil {
// return err
// }
// d.Set("service_access_policies", policyResult.AccessPolicies.Options)

return err
}

func resourceCloudSearchDomainUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).CloudSearchConn

_, err := conn.UpdateServiceAccessPolicies(&cloudsearch.UpdateServiceAccessPoliciesInput{
DomainName: aws.String(d.Get("name").(string)),
AccessPolicies: aws.String(d.Get("service_access_policies").(string)),
})
if err != nil {
return err
}

_, err = conn.UpdateScalingParameters(&cloudsearch.UpdateScalingParametersInput{
_, err := conn.UpdateScalingParameters(&cloudsearch.UpdateScalingParametersInput{
DomainName: aws.String(d.Get("name").(string)),
ScalingParameters: &cloudsearch.ScalingParameters{
DesiredInstanceType: aws.String(d.Get("instance_type").(string)),
Expand Down
217 changes: 217 additions & 0 deletions internal/service/cloudsearch/domain_service_access_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package cloudsearch

import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudsearch"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

func ResourceDomainServiceAccessPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceDomainServiceAccessPolicyPut,
Read: resourceDomainServiceAccessPolicyRead,
Update: resourceDomainServiceAccessPolicyPut,
Delete: resourceDomainServiceAccessPolicyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"access_policy": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
ValidateFunc: validation.StringIsJSON,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},
"domain_name": {
Type: schema.TypeString,
Required: true,
},
},
}
}

func resourceDomainServiceAccessPolicyPut(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).CloudSearchConn

domainName := d.Get("domain_name").(string)
input := &cloudsearch.UpdateServiceAccessPoliciesInput{
DomainName: aws.String(domainName),
}

accessPolicy := d.Get("access_policy").(string)
policy, err := structure.NormalizeJsonString(accessPolicy)

if err != nil {
return fmt.Errorf("policy (%s) is invalid JSON: %w", accessPolicy, err)
}

input.AccessPolicies = aws.String(policy)

log.Printf("[DEBUG] Updating CloudSearch Domain access policies: %s", input)
_, err = conn.UpdateServiceAccessPolicies(input)

if err != nil {
return fmt.Errorf("error creating CloudSearch Domain Service Access Policy (%s): %w", domainName, err)
}

d.SetId(domainName)

_, err = waitAccessPolicyActive(conn, d.Id())

if err != nil {
return fmt.Errorf("error waiting for CloudSearch Domain Service Access Policy (%s) to become active: %w", d.Id(), err)
}

return nil
}

func resourceDomainServiceAccessPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).CloudSearchConn

accessPolicy, err := FindAccessPolicyByName(conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] CloudSearch Domain Service Access Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading CloudSearch Domain Service Access Policy (%s): %w", d.Id(), err)
}

policyToSet, err := verify.PolicyToSet(d.Get("access_policy").(string), accessPolicy)

if err != nil {
return err
}

d.Set("access_policy", policyToSet)
d.Set("domain_name", d.Id())

return nil
}

func resourceDomainServiceAccessPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).CloudSearchConn

domainName := d.Get("domain_name").(string)
input := &cloudsearch.UpdateServiceAccessPoliciesInput{
AccessPolicies: aws.String(""),
DomainName: aws.String(d.Id()),
}

log.Printf("[DEBUG] Deleting CloudSearch Domain Service Access Policy: %s", d.Id())
_, err := conn.UpdateServiceAccessPolicies(input)

if tfawserr.ErrCodeEquals(err, cloudsearch.ErrCodeResourceNotFoundException) {
return nil
}

if err != nil {
return fmt.Errorf("error deleting CloudSearch Domain Service Access Policy (%s): %w", d.Id(), err)
}

_, err = waitAccessPolicyActive(conn, d.Id())

if err != nil {
return fmt.Errorf("error waiting for CloudSearch Domain Service Access Policy (%s) to delete: %w", d.Id(), err)
}

return nil
}

func FindAccessPolicyByName(conn *cloudsearch.CloudSearch, name string) (string, error) {
output, err := findAccessPoliciesStatusByName(conn, name)

if err != nil {
return "", err
}

accessPolicy := aws.StringValue(output.Options)

if accessPolicy == "" {
return "", tfresource.NewEmptyResultError(name)
}

return accessPolicy, nil
}

func findAccessPoliciesStatusByName(conn *cloudsearch.CloudSearch, name string) (*cloudsearch.AccessPoliciesStatus, error) {
input := &cloudsearch.DescribeServiceAccessPoliciesInput{
Deployed: aws.Bool(true),
DomainName: aws.String(name),
}

output, err := conn.DescribeServiceAccessPolicies(input)

if tfawserr.ErrCodeEquals(err, cloudsearch.ErrCodeResourceNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.AccessPolicies == nil || output.AccessPolicies.Status == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.AccessPolicies, nil
}

func statusAccessPolicyState(conn *cloudsearch.CloudSearch, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := findAccessPoliciesStatusByName(conn, name)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.Status.State), nil
}
}

const (
accessPolicyTimeout = 2 * time.Minute
)

func waitAccessPolicyActive(conn *cloudsearch.CloudSearch, name string) (*cloudsearch.AccessPoliciesStatus, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{cloudsearch.OptionStateProcessing},
Target: []string{cloudsearch.OptionStateActive},
Refresh: statusAccessPolicyState(conn, name),
Timeout: accessPolicyTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*cloudsearch.AccessPoliciesStatus); ok {
return output, err
}

return nil, err
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cloudsearch_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
subcategory: "CloudSearch"
layout: "aws"
page_title: "AWS: aws_cloudsearch_domain_service_access_policy"
description: |-
Provides an CloudSearch domain service access policy resource.
---

# Resource: aws_cloudsearch_domain_service_access_policy

Provides an CloudSearch domain service access policy resource.

## Example Usage

```terraform
resource "aws_cloudsearch_domain" "example" {
name = "example-domain"
}
resource "aws_cloudsearch_domain_service_access_policy" "example" {
domain_name = aws_cloudsearch_domain.example.id
policy = <<POLICY
{
"Version":"2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["cloudsearch:search"],
"Resource": "${aws_cloudsearch_domain.example.arn}/movies"
}
]
}
POLICY
}
```

## Argument Reference

The following arguments are supported:

* `access_policy` - (Required) The access rules you want to configure. These rules replace any existing rules. See the [AWS documentation](https://docs.aws.amazon.com/cloudsearch/latest/developerguide/configuring-access.html) for details.
* `domain_name` - (Required) The CloudSearch domain name the policy applies to.

## Attributes Reference

No additional attributes are exported.

## Import

CloudSearch domain service access policies can be imported using the domain name, e.g.,

```
$ terraform import aws_cloudsearch_domain_service_access_policy.example example-domain
```

0 comments on commit 933837c

Please sign in to comment.