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

DocumentDB: aws_docdb_cluster_snapshot resource added #7123

Merged
merged 2 commits into from
Feb 8, 2019
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 @@ -410,6 +410,7 @@ func Provider() terraform.ResourceProvider {
"aws_dms_replication_subnet_group": resourceAwsDmsReplicationSubnetGroup(),
"aws_dms_replication_task": resourceAwsDmsReplicationTask(),
"aws_docdb_cluster_parameter_group": resourceAwsDocDBClusterParameterGroup(),
"aws_docdb_cluster_snapshot": resourceAwsDocDBClusterSnapshot(),
"aws_docdb_subnet_group": resourceAwsDocDBSubnetGroup(),
"aws_dx_bgp_peer": resourceAwsDxBgpPeer(),
"aws_dx_connection": resourceAwsDxConnection(),
Expand Down
206 changes: 206 additions & 0 deletions aws/resource_aws_docdb_cluster_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package aws

import (
"fmt"
"log"
"time"

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

func resourceAwsDocDBClusterSnapshot() *schema.Resource {
return &schema.Resource{
Create: resourceAwsDocDBClusterSnapshotCreate,
Read: resourceAwsDocDBClusterSnapshotRead,
Delete: resourceAwsDocDBClusterSnapshotDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(20 * time.Minute),
},

Schema: map[string]*schema.Schema{
"db_cluster_snapshot_identifier": {
Type: schema.TypeString,
ValidateFunc: validateDocDBClusterSnapshotIdentifier,
Required: true,
ForceNew: true,
},
"db_cluster_identifier": {
Type: schema.TypeString,
ValidateFunc: validateDocDBClusterIdentifier,
Required: true,
ForceNew: true,
},

"availability_zones": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
},
"db_cluster_snapshot_arn": {
Type: schema.TypeString,
Computed: true,
},
"storage_encrypted": {
Type: schema.TypeBool,
Computed: true,
},
"engine": {
Type: schema.TypeString,
Computed: true,
},
"engine_version": {
Type: schema.TypeString,
Computed: true,
},
"kms_key_id": {
Type: schema.TypeString,
Computed: true,
},
"port": {
Type: schema.TypeInt,
Computed: true,
},
"source_db_cluster_snapshot_arn": {
Type: schema.TypeString,
Computed: true,
},
"snapshot_type": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"vpc_id": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

params := &docdb.CreateDBClusterSnapshotInput{
DBClusterIdentifier: aws.String(d.Get("db_cluster_identifier").(string)),
DBClusterSnapshotIdentifier: aws.String(d.Get("db_cluster_snapshot_identifier").(string)),
}

_, err := conn.CreateDBClusterSnapshot(params)
if err != nil {
return fmt.Errorf("error creating DocDB Cluster Snapshot: %s", err)
}
d.SetId(d.Get("db_cluster_snapshot_identifier").(string))

stateConf := &resource.StateChangeConf{
Pending: []string{"creating"},
Target: []string{"available"},
Refresh: resourceAwsDocDBClusterSnapshotStateRefreshFunc(d.Id(), conn),
Timeout: d.Timeout(schema.TimeoutCreate),
MinTimeout: 10 * time.Second,
Delay: 5 * time.Second,
}

// Wait, catching any errors
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("error waiting for DocDB Cluster Snapshot %q to create: %s", d.Id(), err)
}

return resourceAwsDocDBClusterSnapshotRead(d, meta)
}

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

params := &docdb.DescribeDBClusterSnapshotsInput{
DBClusterSnapshotIdentifier: aws.String(d.Id()),
}
resp, err := conn.DescribeDBClusterSnapshots(params)
if err != nil {
if isAWSErr(err, docdb.ErrCodeDBClusterSnapshotNotFoundFault, "") {
log.Printf("[WARN] DocDB Cluster Snapshot %q not found, removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("error reading DocDB Cluster Snapshot %q: %s", d.Id(), err)
}

if resp == nil || len(resp.DBClusterSnapshots) == 0 || resp.DBClusterSnapshots[0] == nil || aws.StringValue(resp.DBClusterSnapshots[0].DBClusterSnapshotIdentifier) != d.Id() {
log.Printf("[WARN] DocDB Cluster Snapshot %q not found, removing from state", d.Id())
d.SetId("")
return nil
}

snapshot := resp.DBClusterSnapshots[0]

if err := d.Set("availability_zones", flattenStringList(snapshot.AvailabilityZones)); err != nil {
return fmt.Errorf("error setting availability_zones: %s", err)
}
d.Set("db_cluster_identifier", snapshot.DBClusterIdentifier)
d.Set("db_cluster_snapshot_arn", snapshot.DBClusterSnapshotArn)
d.Set("db_cluster_snapshot_identifier", snapshot.DBClusterSnapshotIdentifier)
d.Set("engine_version", snapshot.EngineVersion)
d.Set("engine", snapshot.Engine)
d.Set("kms_key_id", snapshot.KmsKeyId)
d.Set("port", snapshot.Port)
d.Set("snapshot_type", snapshot.SnapshotType)
d.Set("source_db_cluster_snapshot_arn", snapshot.SourceDBClusterSnapshotArn)
d.Set("status", snapshot.Status)
d.Set("storage_encrypted", snapshot.StorageEncrypted)
d.Set("vpc_id", snapshot.VpcId)

return nil
}

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

params := &docdb.DeleteDBClusterSnapshotInput{
DBClusterSnapshotIdentifier: aws.String(d.Id()),
}
_, err := conn.DeleteDBClusterSnapshot(params)
if err != nil {
if isAWSErr(err, docdb.ErrCodeDBClusterSnapshotNotFoundFault, "") {
return nil
}
return fmt.Errorf("error deleting DocDB Cluster Snapshot %q: %s", d.Id(), err)
}

return nil
}

func resourceAwsDocDBClusterSnapshotStateRefreshFunc(dbClusterSnapshotIdentifier string, conn *docdb.DocDB) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
opts := &docdb.DescribeDBClusterSnapshotsInput{
DBClusterSnapshotIdentifier: aws.String(dbClusterSnapshotIdentifier),
}

log.Printf("[DEBUG] DocDB Cluster Snapshot describe configuration: %#v", opts)

resp, err := conn.DescribeDBClusterSnapshots(opts)
if err != nil {
if isAWSErr(err, docdb.ErrCodeDBClusterSnapshotNotFoundFault, "") {
return nil, "", nil
}
return nil, "", fmt.Errorf("Error retrieving DocDB Cluster Snapshots: %s", err)
}

if resp == nil || len(resp.DBClusterSnapshots) == 0 || resp.DBClusterSnapshots[0] == nil {
return nil, "", fmt.Errorf("No snapshots returned for %s", dbClusterSnapshotIdentifier)
}

snapshot := resp.DBClusterSnapshots[0]

return resp, aws.StringValue(snapshot.Status), nil
}
}
153 changes: 153 additions & 0 deletions aws/resource_aws_docdb_cluster_snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/docdb"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSDocDBClusterSnapshot_basic(t *testing.T) {
var dbClusterSnapshot docdb.DBClusterSnapshot
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_docdb_cluster_snapshot.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDocDBClusterSnapshotDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsDocDBClusterSnapshotConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckDocDBClusterSnapshotExists(resourceName, &dbClusterSnapshot),
resource.TestCheckResourceAttrSet(resourceName, "availability_zones.#"),
testAccMatchResourceAttrRegionalARN(resourceName, "db_cluster_snapshot_arn", "rds", regexp.MustCompile(`cluster-snapshot:.+`)),
resource.TestCheckResourceAttrSet(resourceName, "engine"),
resource.TestCheckResourceAttrSet(resourceName, "engine_version"),
resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""),
resource.TestCheckResourceAttrSet(resourceName, "port"),
resource.TestCheckResourceAttr(resourceName, "snapshot_type", "manual"),
resource.TestCheckResourceAttr(resourceName, "source_db_cluster_snapshot_arn", ""),
resource.TestCheckResourceAttr(resourceName, "status", "available"),
resource.TestCheckResourceAttr(resourceName, "storage_encrypted", "false"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_id", "aws_vpc.test", "id"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

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

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

input := &docdb.DescribeDBClusterSnapshotsInput{
DBClusterSnapshotIdentifier: aws.String(rs.Primary.ID),
}

output, err := conn.DescribeDBClusterSnapshots(input)
if err != nil {
if isAWSErr(err, docdb.ErrCodeDBClusterSnapshotNotFoundFault, "") {
continue
}
return err
}

if output != nil && len(output.DBClusterSnapshots) > 0 && output.DBClusterSnapshots[0] != nil && aws.StringValue(output.DBClusterSnapshots[0].DBClusterSnapshotIdentifier) == rs.Primary.ID {
return fmt.Errorf("DocDB Cluster Snapshot %q still exists", rs.Primary.ID)
}
}

return nil
}

func testAccCheckDocDBClusterSnapshotExists(resourceName string, dbClusterSnapshot *docdb.DBClusterSnapshot) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("Not found: %s", resourceName)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set for %s", resourceName)
}

conn := testAccProvider.Meta().(*AWSClient).docdbconn

request := &docdb.DescribeDBClusterSnapshotsInput{
DBClusterSnapshotIdentifier: aws.String(rs.Primary.ID),
}

response, err := conn.DescribeDBClusterSnapshots(request)
if err != nil {
return err
}

if response == nil || len(response.DBClusterSnapshots) == 0 || response.DBClusterSnapshots[0] == nil || aws.StringValue(response.DBClusterSnapshots[0].DBClusterSnapshotIdentifier) != rs.Primary.ID {
return fmt.Errorf("DocDB Cluster Snapshot %q not found", rs.Primary.ID)
}

*dbClusterSnapshot = *response.DBClusterSnapshots[0]

return nil
}
}

func testAccAwsDocDBClusterSnapshotConfig(rName string) string {
return fmt.Sprintf(`
data "aws_availability_zones" "available" {}

resource "aws_vpc" "test" {
cidr_block = "192.168.0.0/16"

tags = {
Name = %q
}
}

resource "aws_subnet" "test" {
count = 2

availability_zone = "${data.aws_availability_zones.available.names[count.index]}"
cidr_block = "192.168.${count.index}.0/24"
vpc_id = "${aws_vpc.test.id}"

tags = {
Name = %q
}
}

resource "aws_docdb_subnet_group" "test" {
name = %q
subnet_ids = ["${aws_subnet.test.*.id}"]
}

resource "aws_docdb_cluster" "test" {
cluster_identifier = %q
db_subnet_group_name = "${aws_docdb_subnet_group.test.name}"
master_password = "barbarbarbar"
master_username = "foo"
skip_final_snapshot = true
}

resource "aws_docdb_cluster_snapshot" "test" {
db_cluster_identifier = "${aws_docdb_cluster.test.id}"
db_cluster_snapshot_identifier = %q
}
`, rName, rName, rName, rName, rName)
}
Loading