Skip to content

Commit

Permalink
sdk/resourcemanager: adding a DELETE-only LRO to poll on the resource…
Browse files Browse the repository at this point in the history
… once it's marked as gone
  • Loading branch information
tombuildsstuff committed Feb 28, 2023
1 parent 9c62df3 commit 7ffbebc
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
12 changes: 12 additions & 0 deletions sdk/client/resourcemanager/poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,17 @@ func PollerFromResponse(response *client.Response, client *Client) (poller polle
return pollers.NewPoller(provisioningState, provisioningState.initialRetryDuration, pollers.DefaultNumberOfDroppedConnectionsToAllow), nil
}

// finally, if it was a Delete that returned a 204
methodIsDelete := strings.EqualFold(response.Request.Method, "DELETE")
statusCodesToCheckDelete := response.StatusCode == http.StatusOK || response.StatusCode == http.StatusNoContent
if methodIsDelete && statusCodesToCheckDelete {
deletePoller, deletePollerErr := deletePollerFromResponse(response, client, DefaultPollingInterval)
if deletePollerErr != nil {
err = deletePollerErr
return pollers.Poller{}, fmt.Errorf("building delete poller: %+v", deletePollerErr)
}
return pollers.NewPoller(deletePoller, deletePoller.initialRetryDuration, pollers.DefaultNumberOfDroppedConnectionsToAllow), nil
}

return pollers.Poller{}, fmt.Errorf("no applicable pollers were found for the response")
}
120 changes: 120 additions & 0 deletions sdk/client/resourcemanager/poller_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package resourcemanager

import (
"context"
"fmt"
"net/http"
"time"

"github.com/hashicorp/go-azure-sdk/sdk/client"
"github.com/hashicorp/go-azure-sdk/sdk/client/pollers"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
)

var _ pollers.PollerType = &deletePoller{}

type deletePoller struct {
apiVersion string
client *Client
initialRetryDuration time.Duration
originalUri string
resourcePath string
}

func deletePollerFromResponse(response *client.Response, client *Client, pollingInterval time.Duration) (*deletePoller, error) {
// if we've gotten to this point then we're polling against a Resource Manager resource/operation of some kind
// we next need to determine if the current URI is a Resource Manager resource, or if we should be polling on the
// resource (e.g. `/my/resource`) rather than an operation on the resource (e.g. `/my/resource/start`)
if response.Request == nil {
return nil, fmt.Errorf("request was nil")
}
originalUri := response.Request.URL.RequestURI()
if response.Request.URL == nil {
return nil, fmt.Errorf("request url was nil")
}

// all Resource Manager operations require the `api-version` querystring
apiVersion := response.Request.URL.Query().Get("api-version")
if apiVersion == "" {
return nil, fmt.Errorf("unable to determine `api-version` from %q", originalUri)
}

resourcePath, err := resourceManagerResourcePathFromUri(originalUri)
if err != nil {
return nil, fmt.Errorf("determining Resource Manager Resource Path from %q: %+v", originalUri, err)
}

return &deletePoller{
apiVersion: apiVersion,
client: client,
initialRetryDuration: pollingInterval,
originalUri: originalUri,
resourcePath: *resourcePath,
}, nil
}

func (p deletePoller) Poll(ctx context.Context) (result *pollers.PollResult, err error) {
opts := client.RequestOptions{
ContentType: "application/json; charset=utf-8",
ExpectedStatusCodes: []int{
http.StatusOK,
http.StatusNotFound,
},
HttpMethod: http.MethodGet,
OptionsObject: deleteOptions{
apiVersion: p.apiVersion,
},
Path: p.resourcePath,
}
req, err := p.client.NewRequest(ctx, opts)
if err != nil {
return nil, fmt.Errorf("building request: %+v", err)
}
resp, err := p.client.Execute(ctx, req)
if err != nil {
return nil, fmt.Errorf("executing request: %+v", err)
}
if resp == nil {
return nil, pollers.PollingDroppedConnectionError{}
}

result = &pollers.PollResult{
PollInterval: p.initialRetryDuration,
}

if resp.Response != nil {
switch resp.StatusCode {
case http.StatusNotFound:
result.Status = pollers.PollingStatusSucceeded
return

case http.StatusOK:
result.Status = pollers.PollingStatusInProgress
return
}

err = fmt.Errorf("unexpected status code when polling for resource after deletion, expected a 200/204 but got %d", resp.StatusCode)
}

return
}

var _ client.Options = deleteOptions{}

type deleteOptions struct {
apiVersion string
}

func (p deleteOptions) ToHeaders() *client.Headers {
return &client.Headers{}
}

func (p deleteOptions) ToOData() *odata.Query {
return &odata.Query{}
}

func (p deleteOptions) ToQuery() *client.QueryParams {
q := client.QueryParams{}
q.Append("api-version", p.apiVersion)
return &q
}

0 comments on commit 7ffbebc

Please sign in to comment.