Skip to content

Commit

Permalink
service/cloudhsmv2: Implement sweeper
Browse files Browse the repository at this point in the history
To prevent sweeper errors such as:

```
2019/09/04 02:12:15 [ERR] error running (aws_vpc): Error deleting Subnet (subnet-064c5a7cad5a28b9e): DependencyViolation: The subnet 'subnet-064c5a7cad5a28b9e' has dependencies and cannot be deleted.
```

Output from sweeper in AWS Commercial:

```console
$ go test ./aws -v -sweep=us-east-1,us-west-2 -sweep-run=aws_cloudhsm_v2_cluster -timeout 10h
2019/09/04 10:27:24 [DEBUG] Running Sweepers for region (us-east-1):
...
2019/09/04 10:27:25 [INFO] Deleting CloudHSMv2 Cluster (cluster-wporekks46b) HSM: hsm-y4tvi5ukedh
...
2019/09/04 10:29:06 [INFO] Deleting CloudHSMv2 Cluster: cluster-wporekks46b
...
2019/09/04 10:30:57 Sweeper Tests ran:
  - aws_cloudhsm_v2_cluster
2019/09/04 10:30:57 [DEBUG] Running Sweepers for region (us-west-2):
...
2019/09/04 10:30:59 [INFO] Deleting CloudHSMv2 Cluster: cluster-w56d2uzszjf
...
2019/09/04 10:31:30 [INFO] Deleting CloudHSMv2 Cluster: cluster-zrvllautsay
...
2019/09/04 10:32:01 [INFO] Deleting CloudHSMv2 Cluster: cluster-chxrr77wb2v
...
2019/09/04 10:32:32 Sweeper Tests ran:
  - aws_cloudhsm_v2_cluster
```

Output from sweeper in AWS GovCloud (US):

```console
$ go test ./aws -v -sweep=us-gov-west-1 -sweep-run=aws_cloudhsm_v2_cluster -timeout 10h
2019/09/04 10:28:52 [DEBUG] Running Sweepers for region (us-gov-west-1):
...
2019/09/04 10:28:54 Sweeper Tests ran:
  - aws_cloudhsm_v2_cluster
```

Output from acceptance testing:

```
--- PASS: TestAccAWSCloudHsm2Cluster_basic (285.06s)

--- PASS: TestAccAWSCloudHsm2Hsm_basic (898.88s)
```
  • Loading branch information
bflad committed Sep 4, 2019
1 parent 960a406 commit 7f01d1d
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 43 deletions.
33 changes: 18 additions & 15 deletions aws/resource_aws_cloudhsm2_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,23 +286,11 @@ func resourceAwsCloudHsm2ClusterDelete(d *schema.ResourceData, meta interface{})
}

if err != nil {
return err
return fmt.Errorf("error deleting CloudHSMv2 Cluster (%s): %s", d.Id(), err)
}
log.Println("[INFO] Waiting for CloudHSMv2 Cluster to be deleted")

stateConf := &resource.StateChangeConf{
Pending: []string{cloudhsmv2.ClusterStateDeleteInProgress},
Target: []string{cloudhsmv2.ClusterStateDeleted},
Refresh: resourceAwsCloudHsm2ClusterRefreshFunc(cloudhsm2, d.Id()),
Timeout: d.Timeout(schema.TimeoutCreate),
MinTimeout: 30 * time.Second,
Delay: 30 * time.Second,
}

// Wait, catching any errors
_, errWait := stateConf.WaitForState()
if errWait != nil {
return fmt.Errorf("Error waiting for CloudHSMv2 Cluster state to be \"DELETED\": %s", errWait)
if err := waitForCloudhsmv2ClusterDeletion(cloudhsm2, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("error waiting for CloudHSMv2 Cluster (%s) deletion: %s", d.Id(), err)
}

return nil
Expand Down Expand Up @@ -367,3 +355,18 @@ func readCloudHsm2ClusterCertificates(cluster *cloudhsmv2.Cluster) []map[string]
}
return []map[string]interface{}{}
}

func waitForCloudhsmv2ClusterDeletion(conn *cloudhsmv2.CloudHSMV2, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{cloudhsmv2.ClusterStateDeleteInProgress},
Target: []string{cloudhsmv2.ClusterStateDeleted},
Refresh: resourceAwsCloudHsm2ClusterRefreshFunc(conn, id),
Timeout: timeout,
MinTimeout: 30 * time.Second,
Delay: 30 * time.Second,
}

_, err := stateConf.WaitForState()

return err
}
74 changes: 74 additions & 0 deletions aws/resource_aws_cloudhsm2_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,88 @@ package aws

import (
"fmt"
"log"
"testing"
"time"

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

func init() {
resource.AddTestSweepers("aws_cloudhsm_v2_cluster", &resource.Sweeper{
Name: "aws_cloudhsm_v2_cluster",
F: testSweepCloudhsmv2Clusters,
})
}

func testSweepCloudhsmv2Clusters(region string) error {
client, err := sharedClientForRegion(region)
if err != nil {
return fmt.Errorf("error getting client: %s", err)
}
conn := client.(*AWSClient).cloudhsmv2conn

input := &cloudhsmv2.DescribeClustersInput{}

err = conn.DescribeClustersPages(input, func(page *cloudhsmv2.DescribeClustersOutput, lastPage bool) bool {
for _, cluster := range page.Clusters {
clusterID := aws.StringValue(cluster.ClusterId)
input := &cloudhsmv2.DeleteClusterInput{
ClusterId: cluster.ClusterId,
}

for _, hsm := range cluster.Hsms {
hsmID := aws.StringValue(hsm.HsmId)
input := &cloudhsmv2.DeleteHsmInput{
ClusterId: cluster.ClusterId,
HsmId: hsm.HsmId,
}

log.Printf("[INFO] Deleting CloudHSMv2 Cluster (%s) HSM: %s", clusterID, hsmID)
_, err := conn.DeleteHsm(input)

if err != nil {
log.Printf("[ERROR] Error deleting CloudHSMv2 Cluster (%s) HSM (%s): %s", clusterID, hsmID, err)
continue
}

if err := waitForCloudhsmv2HsmDeletion(conn, hsmID, 120*time.Minute); err != nil {
log.Printf("[ERROR] Error waiting for CloudHSMv2 Cluster (%s) HSM (%s) deletion: %s", clusterID, hsmID, err)
}
}

log.Printf("[INFO] Deleting CloudHSMv2 Cluster: %s", clusterID)
_, err := conn.DeleteCluster(input)

if err != nil {
log.Printf("[ERROR] Error deleting CloudHSMv2 Cluster (%s): %s", clusterID, err)
continue
}

if err := waitForCloudhsmv2ClusterDeletion(conn, clusterID, 120*time.Minute); err != nil {
log.Printf("[ERROR] Error waiting for CloudHSMv2 Cluster (%s) deletion: %s", clusterID, err)
}
}

return !lastPage
})

if testSweepSkipSweepError(err) {
log.Printf("[WARN] Skipping CloudHSMv2 Cluster sweep for %s: %s", region, err)
return nil
}

if err != nil {
return fmt.Errorf("error describing CloudHSMv2 Clusters: %s", err)
}

return nil
}

func TestAccAWSCloudHsm2Cluster_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down
60 changes: 32 additions & 28 deletions aws/resource_aws_cloudhsm2_hsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,16 @@ func describeHsm(conn *cloudhsmv2.CloudHSMV2, hsmId string) (*cloudhsmv2.Hsm, er
return hsm, nil
}

func resourceAwsCloudHsm2HsmRefreshFunc(
d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
func resourceAwsCloudHsm2HsmRefreshFunc(conn *cloudhsmv2.CloudHSMV2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
hsm, err := describeHsm(meta.(*AWSClient).cloudhsmv2conn, d.Id())
hsm, err := describeHsm(conn, id)

if hsm == nil {
return 42, "destroyed", nil
}

if hsm.State != nil {
log.Printf("[DEBUG] CloudHSMv2 Cluster status (%s): %s", d.Id(), *hsm.State)
log.Printf("[DEBUG] CloudHSMv2 Cluster status (%s): %s", id, *hsm.State)
}

return hsm, aws.StringValue(hsm.State), err
Expand Down Expand Up @@ -174,22 +173,9 @@ func resourceAwsCloudHsm2HsmCreate(d *schema.ResourceData, meta interface{}) err
}

d.SetId(aws.StringValue(output.Hsm.HsmId))
log.Printf("[INFO] CloudHSMv2 HSM Id: %s", d.Id())
log.Println("[INFO] Waiting for CloudHSMv2 HSM to be available")

stateConf := &resource.StateChangeConf{
Pending: []string{cloudhsmv2.HsmStateCreateInProgress, "destroyed"},
Target: []string{cloudhsmv2.HsmStateActive},
Refresh: resourceAwsCloudHsm2HsmRefreshFunc(d, meta),
Timeout: d.Timeout(schema.TimeoutCreate),
MinTimeout: 30 * time.Second,
Delay: 30 * time.Second,
}

// Wait, catching any errors
_, errWait := stateConf.WaitForState()
if errWait != nil {
return fmt.Errorf("Error waiting for CloudHSMv2 HSM state to be \"ACTIVE\": %s", errWait)
if err := waitForCloudhsmv2HsmActive(cloudhsm2, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return fmt.Errorf("error waiting for CloudHSMv2 HSM (%s) creation: %s", d.Id(), err)
}

return resourceAwsCloudHsm2HsmRead(d, meta)
Expand Down Expand Up @@ -246,22 +232,40 @@ func resourceAwsCloudHsm2HsmDelete(d *schema.ResourceData, meta interface{}) err
if err != nil {
return fmt.Errorf("error deleting CloudHSM v2 HSM module (%s): %s", d.Id(), err)
}
log.Println("[INFO] Waiting for CloudHSMv2 HSM to be deleted")

if err := waitForCloudhsmv2HsmDeletion(cloudhsm2, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("error waiting for CloudHSMv2 HSM (%s) deletion: %s", d.Id(), err)
}

return nil
}

func waitForCloudhsmv2HsmActive(conn *cloudhsmv2.CloudHSMV2, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{cloudhsmv2.HsmStateCreateInProgress, "destroyed"},
Target: []string{cloudhsmv2.HsmStateActive},
Refresh: resourceAwsCloudHsm2HsmRefreshFunc(conn, id),
Timeout: timeout,
MinTimeout: 30 * time.Second,
Delay: 30 * time.Second,
}

_, err := stateConf.WaitForState()

return err
}

func waitForCloudhsmv2HsmDeletion(conn *cloudhsmv2.CloudHSMV2, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{cloudhsmv2.HsmStateDeleteInProgress},
Target: []string{"destroyed"},
Refresh: resourceAwsCloudHsm2HsmRefreshFunc(d, meta),
Timeout: d.Timeout(schema.TimeoutCreate),
Refresh: resourceAwsCloudHsm2HsmRefreshFunc(conn, id),
Timeout: timeout,
MinTimeout: 30 * time.Second,
Delay: 30 * time.Second,
}

// Wait, catching any errors
_, errWait := stateConf.WaitForState()
if errWait != nil {
return fmt.Errorf("Error waiting for CloudHSMv2 HSM state to be \"DELETED\": %s", errWait)
}
_, err := stateConf.WaitForState()

return nil
return err
}
1 change: 1 addition & 0 deletions aws/resource_aws_subnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func init() {
"aws_autoscaling_group",
"aws_batch_compute_environment",
"aws_beanstalk_environment",
"aws_cloudhsm_v2_cluster",
"aws_db_subnet_group",
"aws_directory_service_directory",
"aws_ec2_client_vpn_endpoint",
Expand Down

0 comments on commit 7f01d1d

Please sign in to comment.