Skip to content

Commit

Permalink
lifecycle reasons and wait logic
Browse files Browse the repository at this point in the history
  • Loading branch information
deepaksibm committed Oct 18, 2024
1 parent 11df739 commit 2479611
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 1 deletion.
29 changes: 29 additions & 0 deletions ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,32 @@ func DataSourceIBMISEndpointGateway() *schema.Resource {
Computed: true,
Description: "Endpoint gateway lifecycle state",
},
isVirtualEndpointGatewayLifecycleReasons: {
Type: schema.TypeList,
Computed: true,
Description: "The reasons for the current lifecycle_state (if any).",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"code": {
Type: schema.TypeString,
Computed: true,
Description: "A snake case string succinctly identifying the reason for this lifecycle state.",
},

"message": {
Type: schema.TypeString,
Computed: true,
Description: "An explanation of the reason for this lifecycle state.",
},

"more_info": {
Type: schema.TypeString,
Computed: true,
Description: "Link to documentation about the reason for this lifecycle state.",
},
},
},
},
isVirtualEndpointGatewaySecurityGroups: {
Type: schema.TypeSet,
Computed: true,
Expand Down Expand Up @@ -178,6 +204,9 @@ func dataSourceIBMISEndpointGatewayRead(
d.Set(isVirtualEndpointGatewayHealthState, result.HealthState)
d.Set(isVirtualEndpointGatewayCreatedAt, result.CreatedAt.String())
d.Set(isVirtualEndpointGatewayLifecycleState, result.LifecycleState)
if err := d.Set(isVirtualEndpointGatewayLifecycleReasons, resourceEGWFlattenLifecycleReasons(result.LifecycleReasons)); err != nil {
return fmt.Errorf("[ERROR] Error setting lifecycle_reasons: %s", err)
}
d.Set(isVirtualEndpointGatewayResourceType, result.ResourceType)
d.Set(isVirtualEndpointGatewayIPs, flattenIPs(result.Ips))
d.Set(isVirtualEndpointGatewayResourceGroupID, result.ResourceGroup.ID)
Expand Down
27 changes: 27 additions & 0 deletions ibm/service/vpc/data_source_ibm_is_virtual_endpoint_gateways.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,32 @@ func DataSourceIBMISEndpointGateways() *schema.Resource {
Computed: true,
Description: "Endpoint gateway lifecycle state",
},
isVirtualEndpointGatewayLifecycleReasons: {
Type: schema.TypeList,
Computed: true,
Description: "The reasons for the current lifecycle_state (if any).",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"code": {
Type: schema.TypeString,
Computed: true,
Description: "A snake case string succinctly identifying the reason for this lifecycle state.",
},

"message": {
Type: schema.TypeString,
Computed: true,
Description: "An explanation of the reason for this lifecycle state.",
},

"more_info": {
Type: schema.TypeString,
Computed: true,
Description: "Link to documentation about the reason for this lifecycle state.",
},
},
},
},
isVirtualEndpointGatewaySecurityGroups: {
Type: schema.TypeSet,
Computed: true,
Expand Down Expand Up @@ -213,6 +239,7 @@ func dataSourceIBMISEndpointGatewaysRead(d *schema.ResourceData, meta interface{
endpointGatewayOutput[isVirtualEndpointGatewayResourceType] = (*endpointGateway.ResourceType)
endpointGatewayOutput[isVirtualEndpointGatewayHealthState] = *endpointGateway.HealthState
endpointGatewayOutput[isVirtualEndpointGatewayLifecycleState] = *endpointGateway.LifecycleState
endpointGatewayOutput[isVirtualEndpointGatewayLifecycleReasons] = resourceEGWFlattenLifecycleReasons(endpointGateway.LifecycleReasons)
endpointGatewayOutput[isVirtualEndpointGatewayResourceGroupID] = *endpointGateway.ResourceGroup.ID
endpointGatewayOutput[isVirtualEndpointGatewayCRN] = *endpointGateway.CRN
endpointGatewayOutput[isVirtualEndpointGatewayVpcID] = *endpointGateway.VPC.ID
Expand Down
97 changes: 96 additions & 1 deletion ibm/service/vpc/resource_ibm_is_private_path_service_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"context"
"fmt"
"log"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
Expand Down Expand Up @@ -242,6 +244,10 @@ func resourceIBMIsPrivatePathServiceGatewayCreate(context context.Context, d *sc
}

d.SetId(*privatePathServiceGateway.ID)
_, err = isWaitForPPSGAvailable(vpcClient, d.Id(), d.Timeout(schema.TimeoutUpdate))
if err != nil {
return diag.FromErr(err)
}

return resourceIBMIsPrivatePathServiceGatewayUpdate(context, d, meta)
}
Expand Down Expand Up @@ -393,8 +399,97 @@ func resourceIBMIsPrivatePathServiceGatewayDelete(context context.Context, d *sc
log.Printf("[DEBUG] DeletePrivatePathServiceGatewayWithContext failed %s\n%s", err, response)
return diag.FromErr(fmt.Errorf("DeletePrivatePathServiceGatewayWithContext failed %s\n%s", err, response))
}

_, err = isWaitForPPSGDeleted(vpcClient, d.Id(), d.Timeout(schema.TimeoutDelete))
if err != nil {
return diag.FromErr(err)
}
d.SetId("")

return nil
}

func isWaitForPPSGDeleteRetry(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) {
log.Printf("[DEBUG] Retrying PPSG (%s) delete", id)
stateConf := &resource.StateChangeConf{
Pending: []string{"ppsg_in_use"},
Target: []string{"deleting", "done", ""},
Refresh: func() (interface{}, string, error) {
deletePrivatePathServiceGatewayOptions := &vpcv1.DeletePrivatePathServiceGatewayOptions{}
deletePrivatePathServiceGatewayOptions.SetID(id)
log.Printf("[DEBUG] Retrying PPSG (%s) delete", id)
response, err := vpcClient.DeletePrivatePathServiceGateway(deletePrivatePathServiceGatewayOptions)
if err != nil {
if response != nil && response.StatusCode == 409 {
return response, "ppsg_in_use", nil
} else if response != nil && response.StatusCode == 404 {
return response, "done", nil
}
return response, "", fmt.Errorf("[ERROR] Error deleting ppsg: %s\n%s", err, response)
}
return response, "deleting", nil
},
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}
return stateConf.WaitForState()
}
func isWaitForPPSGDeleted(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for ppsg (%s) to be deleted.", id)

stateConf := &resource.StateChangeConf{
Pending: []string{"retry", "deleting", "stable"},
Target: []string{"deleted", ""},
Refresh: isPPSGDeleteRefreshFunc(vpcClient, id),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}

return stateConf.WaitForState()
}

func isPPSGDeleteRefreshFunc(vpcClient *vpcv1.VpcV1, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
log.Printf("[DEBUG] is ppsg delete function here")
getPPSGOptions := &vpcv1.GetPrivatePathServiceGatewayOptions{
ID: &id,
}
ppsg, response, err := vpcClient.GetPrivatePathServiceGateway(getPPSGOptions)
if err != nil {
if response != nil && response.StatusCode == 404 {
return ppsg, "deleted", nil
}
return ppsg, "", fmt.Errorf("[ERROR] The ppsg %s failed to delete: %s\n%s", id, err, response)
}
return ppsg, "deleting", err
}
}
func isWaitForPPSGAvailable(vpcClient *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) {
log.Printf("Waiting for ppsg (%s) to be available.", id)

stateConf := &resource.StateChangeConf{
Pending: []string{"pending", "updating"},
Target: []string{"stable", "failed", "suspended"},
Refresh: isPPSGRefreshFunc(vpcClient, id),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}

return stateConf.WaitForState()
}

func isPPSGRefreshFunc(vpcClient *vpcv1.VpcV1, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
getPPSGOptions := &vpcv1.GetPrivatePathServiceGatewayOptions{
ID: &id,
}
ppsg, response, err := vpcClient.GetPrivatePathServiceGateway(getPPSGOptions)
if err != nil {
return nil, "", fmt.Errorf("[ERROR] Error getting ppsg : %s\n%s", err, response)
}

return ppsg, *ppsg.LifecycleState, nil
}
}
79 changes: 79 additions & 0 deletions ibm/service/vpc/resource_ibm_is_virtual_endpoint_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
isVirtualEndpointGatewayIPsResourceType = "resource_type"
isVirtualEndpointGatewayHealthState = "health_state"
isVirtualEndpointGatewayLifecycleState = "lifecycle_state"
isVirtualEndpointGatewayLifecycleReasons = "lifecycle_reasons"
isVirtualEndpointGatewayTarget = "target"
isVirtualEndpointGatewayTargetName = "name"
isVirtualEndpointGatewayTargetCRN = "crn"
Expand Down Expand Up @@ -122,6 +123,32 @@ func ResourceIBMISEndpointGateway() *schema.Resource {
Computed: true,
Description: "Endpoint gateway lifecycle state",
},
isVirtualEndpointGatewayLifecycleReasons: {
Type: schema.TypeList,
Computed: true,
Description: "The reasons for the current lifecycle_state (if any).",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"code": {
Type: schema.TypeString,
Computed: true,
Description: "A snake case string succinctly identifying the reason for this lifecycle state.",
},

"message": {
Type: schema.TypeString,
Computed: true,
Description: "An explanation of the reason for this lifecycle state.",
},

"more_info": {
Type: schema.TypeString,
Computed: true,
Description: "Link to documentation about the reason for this lifecycle state.",
},
},
},
},
isVirtualEndpointGatewaySecurityGroups: {
Type: schema.TypeSet,
Computed: true,
Expand Down Expand Up @@ -507,6 +534,9 @@ func resourceIBMisVirtualEndpointGatewayRead(d *schema.ResourceData, meta interf
d.Set(isVirtualEndpointGatewayHealthState, endpointGateway.HealthState)
d.Set(isVirtualEndpointGatewayCreatedAt, endpointGateway.CreatedAt.String())
d.Set(isVirtualEndpointGatewayLifecycleState, endpointGateway.LifecycleState)
if err := d.Set(isVirtualEndpointGatewayLifecycleReasons, resourceEGWFlattenLifecycleReasons(endpointGateway.LifecycleReasons)); err != nil {
return fmt.Errorf("[ERROR] Error setting lifecycle_reasons: %s", err)
}
d.Set(isVirtualEndpointGatewayAllowDnsResolutionBinding, endpointGateway.AllowDnsResolutionBinding)
d.Set(isVirtualEndpointGatewayResourceType, endpointGateway.ResourceType)
d.Set(isVirtualEndpointGatewayCRN, endpointGateway.CRN)
Expand Down Expand Up @@ -611,9 +641,42 @@ func resourceIBMisVirtualEndpointGatewayDelete(d *schema.ResourceData, meta inte
log.Printf("Delete Endpoint Gateway failed: %v", response)
return fmt.Errorf("Delete Endpoint Gateway failed : %s\n%s", err, response)
}
_, err = isWaitForEGWDelete(sess, d, d.Id())
if err != nil {
return err
}
return nil
}

func isWaitForEGWDelete(vpcClient *vpcv1.VpcV1, d *schema.ResourceData, id string) (interface{}, error) {

stateConf := &resource.StateChangeConf{
Pending: []string{"deleting", "stable"},
Target: []string{"done", ""},
Refresh: func() (interface{}, string, error) {
getegwoptions := &vpcv1.GetEndpointGatewayOptions{
ID: &id,
}
egw, response, err := vpcClient.GetEndpointGateway(getegwoptions)
if err != nil {
if response != nil && response.StatusCode == 404 {
return egw, "done", nil
}
return nil, "", fmt.Errorf("[ERROR] Error Getting EGW: %s\n%s", err, response)
}
if *egw.LifecycleState == "failed" {
return egw, *egw.LifecycleState, fmt.Errorf("[ERROR] The egw %s failed to delete: %v", d.Id(), err)
}
return egw, "deleting", nil
},
Timeout: d.Timeout(schema.TimeoutDelete),
Delay: 10 * time.Second,
MinTimeout: 10 * time.Second,
}

return stateConf.WaitForState()
}

func resourceIBMisVirtualEndpointGatewayExists(d *schema.ResourceData, meta interface{}) (bool, error) {
sess, err := vpcClient(meta)
if err != nil {
Expand Down Expand Up @@ -694,3 +757,19 @@ func flattenEndpointGatewayTarget(target *vpcv1.EndpointGatewayTarget) interface
targetSlice = append(targetSlice, targetOutput)
return targetSlice
}

func resourceEGWFlattenLifecycleReasons(lifecycleReasons []vpcv1.EndpointGatewayLifecycleReason) (lifecycleReasonsList []map[string]interface{}) {
lifecycleReasonsList = make([]map[string]interface{}, 0)
for _, lr := range lifecycleReasons {
currentLR := map[string]interface{}{}
if lr.Code != nil && lr.Message != nil {
currentLR[isInstanceLifecycleReasonsCode] = *lr.Code
currentLR[isInstanceLifecycleReasonsMessage] = *lr.Message
if lr.MoreInfo != nil {
currentLR[isInstanceLifecycleReasonsMoreInfo] = *lr.MoreInfo
}
lifecycleReasonsList = append(lifecycleReasonsList, currentLR)
}
}
return lifecycleReasonsList
}

0 comments on commit 2479611

Please sign in to comment.