Skip to content

Commit

Permalink
fix(security_group): added wait logic to wait for target removal to a…
Browse files Browse the repository at this point in the history
…void 409
  • Loading branch information
uibm committed Aug 17, 2022
1 parent cc54999 commit 69929e0
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 2 deletions.
108 changes: 106 additions & 2 deletions ibm/service/vpc/resource_ibm_is_security_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"log"
"os"
"reflect"
"time"

"github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex"
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate"
"github.com/IBM/vpc-go-sdk/vpcv1"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -42,6 +44,11 @@ func ResourceIBMISSecurityGroup() *schema.Resource {
},
),

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

Schema: map[string]*schema.Schema{

isSecurityGroupName: {
Expand Down Expand Up @@ -410,7 +417,19 @@ func resourceIBMISSecurityGroupDelete(d *schema.ResourceData, meta interface{})
deleteSecurityGroupTargetBindingOptions := sess.NewDeleteSecurityGroupTargetBindingOptions(id, *securityGroupTargetReference.ID)
response, err = sess.DeleteSecurityGroupTargetBinding(deleteSecurityGroupTargetBindingOptions)
if err != nil {
return fmt.Errorf("[ERROR] Error deleting security group target binding while deleting security group : %s\n%s", err, response)
if response != nil {
if response.StatusCode == 404 {
log.Printf("[DEBUG] Security group target(%s) binding is already deleted", *securityGroupTargetReference.ID)
} else if response.StatusCode == 409 {
log.Printf("[DEBUG] Security group target(%s) binding is in deleting status, waiting till target is removed", *securityGroupTargetReference.ID)
_, err = isWaitForTargetDeleted(sess, id, *securityGroupTargetReference.ID, securityGroupTargetReferenceIntf, d.Timeout(schema.TimeoutDelete))
if err != nil {
return err
}
}
} else {
return fmt.Errorf("[ERROR] Error deleting security group target binding while deleting security group : %s\n%s", err, response)
}
}

}
Expand All @@ -421,8 +440,21 @@ func resourceIBMISSecurityGroupDelete(d *schema.ResourceData, meta interface{})
ID: &id,
}
response, err = sess.DeleteSecurityGroup(deleteSecurityGroupOptions)

if err != nil {
return fmt.Errorf("[ERROR] Error Deleting Security Group : %s\n%s", err, response)
if response != nil {
if response.StatusCode == 404 {
log.Printf("[DEBUG] Security group(%s) target bindings are already deleted", id)
} else if response.StatusCode == 409 {
log.Printf("[DEBUG] Security group(%s) has target bindings is in deleting, will wait till target is removed", id)
_, err = isWaitForSgCleanup(sess, id, allrecs, d.Timeout(schema.TimeoutDelete))
if err != nil {
return err
}
}
} else {
return fmt.Errorf("[ERROR] Error Deleting Security Group : %s\n%s", err, response)
}
}
d.SetId("")
return nil
Expand Down Expand Up @@ -495,3 +527,75 @@ func makeIBMISSecurityRuleSchema() map[string]*schema.Schema {
},
}
}

func isWaitForTargetDeleted(client *vpcv1.VpcV1, sgId, targetId string, target vpcv1.SecurityGroupTargetReferenceIntf, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for Security group(%s) target(%s) to be deleted.", sgId, targetId)

stateConf := &resource.StateChangeConf{
Pending: []string{"deleting"},
Target: []string{"done", ""},
Refresh: isTargetRefreshFunc(client, sgId, targetId, target),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}

return stateConf.WaitForState()
}

func isTargetRefreshFunc(client *vpcv1.VpcV1, sgId, targetId string, target vpcv1.SecurityGroupTargetReferenceIntf) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
targetgetoptions := &vpcv1.GetSecurityGroupTargetOptions{
SecurityGroupID: &sgId,
ID: &targetId,
}
sgTarget, response, err := client.GetSecurityGroupTarget(targetgetoptions)
if err != nil {
return target, "", fmt.Errorf("[ERROR] Error getting target(%s): %s\n%s", targetId, err, response)
}
if response != nil && response.StatusCode == 404 {
return target, "done", nil
}
return sgTarget, "deleting", nil
}
}
func isWaitForSgCleanup(client *vpcv1.VpcV1, sgId string, targets []vpcv1.SecurityGroupTargetReferenceIntf, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for Security group(%s) target(%s) to be deleted.", sgId, targets)

stateConf := &resource.StateChangeConf{
Pending: []string{"deleting"},
Target: []string{"done", ""},
Refresh: isSgRefreshFunc(client, sgId, targets),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}

return stateConf.WaitForState()
}

func isSgRefreshFunc(client *vpcv1.VpcV1, sgId string, groups []vpcv1.SecurityGroupTargetReferenceIntf) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
start := ""
allrecs := []vpcv1.SecurityGroupTargetReferenceIntf{}
for {
listSecurityGroupTargetsOptions := client.NewListSecurityGroupTargetsOptions(sgId)

sggroups, response, err := client.ListSecurityGroupTargets(listSecurityGroupTargetsOptions)
if err != nil || sggroups == nil {
return groups, "", fmt.Errorf("[ERROR] Error Getting Security Group Targets %s\n%s", err, response)
}
if *sggroups.TotalCount == int64(0) {
return groups, "done", nil
}

start = flex.GetNext(sggroups.Next)
allrecs = append(allrecs, sggroups.Targets...)

if start == "" {
break
}
}
return allrecs, "deleting", nil
}
}
101 changes: 101 additions & 0 deletions ibm/service/vpc/resource_ibm_is_security_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package vpc_test
import (
"errors"
"fmt"
"strings"
"testing"

acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest"
Expand Down Expand Up @@ -52,6 +53,48 @@ func TestAccIBMISSecurityGroup_basic(t *testing.T) {
},
})
}
func TestAccIBMISSecurityGroup_wait(t *testing.T) {
var securityGroup string

vpcname := fmt.Sprintf("tfsg-vpc-%d", acctest.RandIntRange(10, 100))
subnetname := fmt.Sprintf("tfsg-subnet-%d", acctest.RandIntRange(10, 100))
sshname := fmt.Sprintf("tfsg-ssh-%d", acctest.RandIntRange(10, 100))
vsiname := fmt.Sprintf("tfsg-vsi-%d", acctest.RandIntRange(10, 100))
bmname := fmt.Sprintf("tfsg-bm-%d", acctest.RandIntRange(10, 100))
name1 := fmt.Sprintf("tfsg-createname-%d", acctest.RandIntRange(10, 100))
publickey := strings.TrimSpace(`
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR
`)
//name2 := fmt.Sprintf("tfsg-updatename-%d", acctest.RandIntRange(10, 100))

resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckIBMISSecurityGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckIBMISsecurityGroupWaitConfig(name1, vpcname, subnetname, sshname, publickey, vsiname, bmname),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMISSecurityGroupExists("ibm_is_security_group.testacc_security_group", securityGroup),
resource.TestCheckResourceAttr(
"ibm_is_security_group.testacc_security_group", "name", name1),
resource.TestCheckResourceAttr(
"ibm_is_security_group.testacc_security_group", "tags.#", "2"),
resource.TestCheckResourceAttr(
"ibm_is_vpc.testacc_vpc", "name", vpcname),
resource.TestCheckResourceAttr(
"ibm_is_subnet.testacc_subnet", "name", subnetname),
resource.TestCheckResourceAttr(
"ibm_is_ssh_key.testacc_sshkey", "name", sshname),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "name", vsiname),
resource.TestCheckResourceAttr(
"ibm_is_bare_metal_server.testacc_bms", "name", bmname),
),
},
},
})
}

func testAccCheckIBMISSecurityGroupDestroy(s *terraform.State) error {
sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API()
Expand Down Expand Up @@ -111,6 +154,64 @@ resource "ibm_is_security_group" "testacc_security_group" {
tags = ["Tag1", "tag2"]
}`, vpcname, name)

}
func testAccCheckIBMISsecurityGroupWaitConfig(name, vpcname, subnetname, sshname, publicKey, vsiname, bmname string) string {
return fmt.Sprintf(`
resource "ibm_is_vpc" "testacc_vpc" {
name = "%s"
}
resource ibm_is_subnet testacc_subnet {
name = "%s"
zone = "%s"
vpc = "${ibm_is_vpc.testacc_vpc.id}"
total_ipv4_address_count = 16
}
resource "ibm_is_security_group" "testacc_security_group" {
name = "%s"
vpc = "${ibm_is_vpc.testacc_vpc.id}"
tags = ["tag1", "tag2"]
}
resource "ibm_is_ssh_key" "testacc_sshkey" {
name = "%s"
public_key = "%s"
}
resource "ibm_is_instance" "testacc_instance" {
name = "%s"
image = "%s"
profile = "%s"
primary_network_interface {
subnet = ibm_is_subnet.testacc_subnet.id
security_groups = [ibm_is_security_group.testacc_security_group.id]
}
vpc = ibm_is_vpc.testacc_vpc.id
zone = "%s"
keys = [ibm_is_ssh_key.testacc_sshkey.id]
network_interfaces {
subnet = ibm_is_subnet.testacc_subnet.id
name = "eth12"
security_groups = [ibm_is_security_group.testacc_security_group.id]
}
}
resource "ibm_is_bare_metal_server" "testacc_bms" {
profile = "%s"
name = "%s"
image = "%s"
zone = "%s"
keys = [ibm_is_ssh_key.testacc_sshkey.id]
primary_network_interface {
subnet = ibm_is_subnet.testacc_subnet.id
security_groups = [ibm_is_security_group.testacc_security_group.id]
}
vpc = ibm_is_vpc.testacc_vpc.id
}
`, vpcname, subnetname, acc.ISZoneName, name, sshname, publicKey, vsiname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, acc.IsBareMetalServerProfileName, bmname, acc.IsBareMetalServerImage, acc.ISZoneName)

}

func testAccCheckIBMISsecurityGroupConfigUpdate(vpcname, name string) string {
Expand Down

0 comments on commit 69929e0

Please sign in to comment.