Skip to content

Commit

Permalink
adding waiting for a share's port to be deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
morozovalekseywot committed Nov 29, 2024
1 parent 4dcb375 commit fab697b
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ description: |-

#### v0.8.5 (unreleased)
- Fix an issue with marking subnet as ready while DHCP service is not configured yet
- Fix an issue with marking share as deleted while share's port in subnet is still active
- Fix panic on empty taint to vkcs_kubernetes_node_group resource
- Fix order-induced changes in the plan for "databases" of the vkcs_db_user resource
- Fix panic on VKCS Kubernetes API error in vkcs_kubernetes_clustertemplates data source
Expand Down
122 changes: 118 additions & 4 deletions vkcs/sharedfilesystem/resource_share.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import (
"context"
"fmt"
"log"
"strings"
"time"

"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/vk-cs/terraform-provider-vkcs/vkcs/internal/clients"
inetworking "github.com/vk-cs/terraform-provider-vkcs/vkcs/internal/services/networking"
"github.com/vk-cs/terraform-provider-vkcs/vkcs/internal/util"

"github.com/gophercloud/gophercloud"
Expand All @@ -26,7 +29,7 @@ const (
minManilaShareMicroversion = "2.14"
shareOperationCreateTimeout = 40
shareOperationUpdateTimeout = 40
shareOperationDeleteTimeout = 20
shareOperationDeleteTimeout = 30
)

func ResourceSharedFilesystemShare() *schema.Resource {
Expand Down Expand Up @@ -195,6 +198,7 @@ func resourceSharedFilesystemShareCreate(ctx context.Context, d *schema.Resource
if err != nil {
return diag.FromErr(err)
}
time.Sleep(2 * time.Minute)

return resourceSharedFilesystemShareRead(ctx, d, meta)
}
Expand Down Expand Up @@ -350,6 +354,27 @@ func resourceSharedFilesystemShareDelete(ctx context.Context, d *schema.Resource
if err != nil {
return diag.Errorf("Error creating VKCS sharedfilesystem client: %s", err)
}
sfsClient.Microversion = minManilaShareMicroversion

networkingClient, err := config.NetworkingV2Client(util.GetRegion(d, config), inetworking.SearchInAllSDNs)
if err != nil {
return diag.Errorf("Error creating VKCS networking client: %s", err)
}

share, getErr := ishares.Get(sfsClient, d.Id()).Extract()
if getErr != nil {
err = util.CheckDeleted(d, err, "Unable to delete share")
if err != nil {
return diag.FromErr(err)
}

return nil
}

portID, err := getSubnetPort(networkingClient, sfsClient, share)
if err != nil {
return diag.Errorf("Unable to delete %s share: %s", d.Id(), err)
}

timeout := d.Timeout(schema.TimeoutDelete)

Expand All @@ -365,13 +390,15 @@ func resourceSharedFilesystemShareDelete(ctx context.Context, d *schema.Resource
if err != nil {
e := util.CheckDeleted(d, err, "")
if e == nil {
return nil
return waitForPortDeleting(ctx, networkingClient, portID, timeout)
}

detailedErr := sfserrors.ErrorDetails{}
e = sfserrors.ExtractErrorInto(err, &detailedErr)
if e != nil {
return diag.Errorf("Unable to delete %s share: %s: %s", d.Id(), err, e)
}

for k, msg := range detailedErr {
return diag.Errorf("Unable to delete %s share: %s (%d): %s", d.Id(), k, msg.Code, msg.Message)
}
Expand All @@ -384,10 +411,9 @@ func resourceSharedFilesystemShareDelete(ctx context.Context, d *schema.Resource
return diag.FromErr(err)
}

return nil
return waitForPortDeleting(ctx, networkingClient, portID, timeout)
}

// Full list of the share statuses: https://developer.vkcs.org/api-ref/shared-file-system/#shares
func waitForSFShare(ctx context.Context, sfsClient *gophercloud.ServiceClient, id string, target string, pending []string, timeout time.Duration) error {
log.Printf("[DEBUG] Waiting for share %s to become %s.", id, target)

Expand All @@ -410,11 +436,13 @@ func waitForSFShare(ctx context.Context, sfsClient *gophercloud.ServiceClient, i
return fmt.Errorf("error: share %s not found: %s", id, err)
}
}

errorMessage := fmt.Sprintf("error waiting for share %s to become %s", id, target)
msg := resourceSFSShareManilaMessage(sfsClient, id)
if msg == nil {
return fmt.Errorf("%s: %s", errorMessage, err)
}

return fmt.Errorf("%s: %s: the latest manila message (%s): %s", errorMessage, err, msg.CreatedAt, msg.UserMessage)
}

Expand Down Expand Up @@ -460,3 +488,89 @@ func resourceSFSShareManilaMessage(sfsClient *gophercloud.ServiceClient, id stri

return &allMessages[0]
}

func getSubnetPort(networkingClient, sfsClient *gophercloud.ServiceClient, share *shares.Share) (string, error) {
exportLocationPath, err := getShareExportLocationPath(sfsClient, share.ID)
if err != nil {
return "", fmt.Errorf("error retrieving share export location path: %s", err)
}

portIP, _, found := strings.Cut(exportLocationPath, ":/shares")
if !found {
return "", nil
}

listOpts := ports.ListOpts{
FixedIPs: []ports.FixedIPOpts{
{
IPAddress: portIP,
},
},
}
allPages, err := ports.List(networkingClient, listOpts).AllPages()
if err != nil {
return "", fmt.Errorf("error listing ports: %s", err)
}

var sharePorts []struct {
ID string `json:"id"`
}
err = ports.ExtractPortsInto(allPages, &sharePorts)
if err != nil {
return "", fmt.Errorf("error reading VKCS Networking API response: %s", err)
}

if len(sharePorts) == 0 {
return "", nil
}

return sharePorts[0].ID, nil
}

func waitForPortDeleting(ctx context.Context, networkingClient *gophercloud.ServiceClient, portID string, timeout time.Duration) diag.Diagnostics {
if portID == "" {
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Warning,
Summary: "Failed to delete share's port in subnet",
Detail: "Couldn't get port ip address from share",
},
}
}

log.Printf("[DEBUG] Waiting for share's port %s to become deleted.", portID)
err := retry.RetryContext(ctx, timeout, func() *retry.RetryError {
listOpts := ports.ListOpts{
ID: portID,
}
allPages, err := ports.List(networkingClient, listOpts).AllPages()
if err != nil {
return util.CheckForRetryableError(err)
}

var sharePorts []struct {
ID string `json:"id"`
}
err = ports.ExtractPortsInto(allPages, &sharePorts)
if err != nil {
return util.CheckForRetryableError(err)
}

if len(sharePorts) == 0 {
return nil
}

return retry.RetryableError(fmt.Errorf("port %s in subnet is still active", portID))
})
if err != nil {
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("Failed to delete share's port %s in subnet", portID),
Detail: err.Error(),
},
}
}

return nil
}

0 comments on commit fab697b

Please sign in to comment.