Skip to content

Commit

Permalink
Merge pull request #8064 from kterada0509/feature/add-snapshot-schedu…
Browse files Browse the repository at this point in the history
…les-resource-for-redshift

Feature/add snapshot schedules resource for redshift
  • Loading branch information
bflad authored Aug 7, 2019
2 parents 10c145f + b31d8d9 commit 946cf3e
Show file tree
Hide file tree
Showing 8 changed files with 1,143 additions and 0 deletions.
2 changes: 2 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ func Provider() terraform.ResourceProvider {
"aws_redshift_parameter_group": resourceAwsRedshiftParameterGroup(),
"aws_redshift_subnet_group": resourceAwsRedshiftSubnetGroup(),
"aws_redshift_snapshot_copy_grant": resourceAwsRedshiftSnapshotCopyGrant(),
"aws_redshift_snapshot_schedule": resourceAwsRedshiftSnapshotSchedule(),
"aws_redshift_snapshot_schedule_association": resourceAwsRedshiftSnapshotScheduleAssociation(),
"aws_redshift_event_subscription": resourceAwsRedshiftEventSubscription(),
"aws_resourcegroups_group": resourceAwsResourceGroupsGroup(),
"aws_route53_delegation_set": resourceAwsRoute53DelegationSet(),
Expand Down
234 changes: 234 additions & 0 deletions aws/resource_aws_redshift_snapshot_schedule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package aws

import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/redshift"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsRedshiftSnapshotSchedule() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRedshiftSnapshotScheduleCreate,
Read: resourceAwsRedshiftSnapshotScheduleRead,
Update: resourceAwsRedshiftSnapshotScheduleUpdate,
Delete: resourceAwsRedshiftSnapshotScheduleDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"identifier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"identifier_prefix"},
},
"identifier_prefix": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"definitions": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"force_destroy": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"tags": tagsSchema(),
},
}

}

func resourceAwsRedshiftSnapshotScheduleCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn
tags := tagsFromMapRedshift(d.Get("tags").(map[string]interface{}))
var identifier string
if v, ok := d.GetOk("identifier"); ok {
identifier = v.(string)
} else {
if v, ok := d.GetOk("identifier_prefix"); ok {
identifier = resource.PrefixedUniqueId(v.(string))
} else {
identifier = resource.UniqueId()
}
}
createOpts := &redshift.CreateSnapshotScheduleInput{
ScheduleIdentifier: aws.String(identifier),
ScheduleDefinitions: expandStringSet(d.Get("definitions").(*schema.Set)),
Tags: tags,
}
if attr, ok := d.GetOk("description"); ok {
createOpts.ScheduleDescription = aws.String(attr.(string))
}

resp, err := conn.CreateSnapshotSchedule(createOpts)
if err != nil {
return fmt.Errorf("Error creating Redshift Snapshot Schedule: %s", err)
}

d.SetId(aws.StringValue(resp.ScheduleIdentifier))

return resourceAwsRedshiftSnapshotScheduleRead(d, meta)
}

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

descOpts := &redshift.DescribeSnapshotSchedulesInput{
ScheduleIdentifier: aws.String(d.Id()),
}

resp, err := conn.DescribeSnapshotSchedules(descOpts)
if err != nil {
return fmt.Errorf("Error describing Redshift Cluster Snapshot Schedule %s: %s", d.Id(), err)
}

if resp.SnapshotSchedules == nil || len(resp.SnapshotSchedules) != 1 {
log.Printf("[WARN] Unable to find Redshift Cluster Snapshot Schedule (%s)", d.Id())
d.SetId("")
return nil
}
snapshotSchedule := resp.SnapshotSchedules[0]

d.Set("identifier", snapshotSchedule.ScheduleIdentifier)
d.Set("description", snapshotSchedule.ScheduleDescription)
if err := d.Set("definitions", flattenStringList(snapshotSchedule.ScheduleDefinitions)); err != nil {
return fmt.Errorf("Error setting definitions: %s", err)
}
d.Set("tags", tagsToMapRedshift(snapshotSchedule.Tags))

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "redshift",
Region: meta.(*AWSClient).region,
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("snapshotschedule:%s", d.Id()),
}.String()

d.Set("arn", arn)

return nil
}

func resourceAwsRedshiftSnapshotScheduleUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn
d.Partial(true)

if tagErr := setTagsRedshift(conn, d); tagErr != nil {
return tagErr
} else {
d.SetPartial("tags")
}

if d.HasChange("definitions") {
modifyOpts := &redshift.ModifySnapshotScheduleInput{
ScheduleIdentifier: aws.String(d.Id()),
ScheduleDefinitions: expandStringList(d.Get("definitions").(*schema.Set).List()),
}
_, err := conn.ModifySnapshotSchedule(modifyOpts)
if isAWSErr(err, redshift.ErrCodeSnapshotScheduleNotFoundFault, "") {
log.Printf("[WARN] Redshift Snapshot Schedule (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return fmt.Errorf("Error modifying Redshift Snapshot Schedule %s: %s", d.Id(), err)
}
d.SetPartial("definitions")
}

return resourceAwsRedshiftSnapshotScheduleRead(d, meta)
}

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

if d.Get("force_destroy").(bool) {
if err := resourceAwsRedshiftSnapshotScheduleDeleteAllAssociatedClusters(conn, d.Id()); err != nil {
return err
}
}

_, err := conn.DeleteSnapshotSchedule(&redshift.DeleteSnapshotScheduleInput{
ScheduleIdentifier: aws.String(d.Id()),
})
if isAWSErr(err, redshift.ErrCodeSnapshotScheduleNotFoundFault, "") {
return nil
}
if err != nil {
return fmt.Errorf("Error deleting Redshift Snapshot Schedule %s: %s", d.Id(), err)
}

return nil
}

func resourceAwsRedshiftSnapshotScheduleDeleteAllAssociatedClusters(conn *redshift.Redshift, scheduleIdentifier string) error {

resp, err := conn.DescribeSnapshotSchedules(&redshift.DescribeSnapshotSchedulesInput{
ScheduleIdentifier: aws.String(scheduleIdentifier),
})
if isAWSErr(err, redshift.ErrCodeSnapshotScheduleNotFoundFault, "") {
return nil
}
if err != nil {
return fmt.Errorf("Error describing Redshift Cluster Snapshot Schedule %s: %s", scheduleIdentifier, err)
}
if resp.SnapshotSchedules == nil || len(resp.SnapshotSchedules) != 1 {
log.Printf("[WARN] Unable to find Redshift Cluster Snapshot Schedule (%s)", scheduleIdentifier)
return nil
}

snapshotSchedule := resp.SnapshotSchedules[0]

for _, associatedCluster := range snapshotSchedule.AssociatedClusters {
_, err = conn.ModifyClusterSnapshotSchedule(&redshift.ModifyClusterSnapshotScheduleInput{
ClusterIdentifier: associatedCluster.ClusterIdentifier,
ScheduleIdentifier: aws.String(scheduleIdentifier),
DisassociateSchedule: aws.Bool(true),
})

if isAWSErr(err, redshift.ErrCodeClusterNotFoundFault, "") {
log.Printf("[WARN] Redshift Snapshot Cluster (%s) not found, removing from state", aws.StringValue(associatedCluster.ClusterIdentifier))
continue
}
if isAWSErr(err, redshift.ErrCodeSnapshotScheduleNotFoundFault, "") {
log.Printf("[WARN] Redshift Snapshot Schedule (%s) not found, removing from state", scheduleIdentifier)
continue
}
if err != nil {
return fmt.Errorf("Error disassociate Redshift Cluster (%s) and Snapshot Schedule (%s) Association: %s", aws.StringValue(associatedCluster.ClusterIdentifier), scheduleIdentifier, err)
}
}

for _, associatedCluster := range snapshotSchedule.AssociatedClusters {
if err := waitForRedshiftSnapshotScheduleAssociationDestroy(conn, 75*time.Minute, aws.StringValue(associatedCluster.ClusterIdentifier), scheduleIdentifier); err != nil {
return err
}
}

return nil
}
Loading

0 comments on commit 946cf3e

Please sign in to comment.