diff --git a/builtin/providers/azurerm/provider.go b/builtin/providers/azurerm/provider.go index 42135a50ee..a715a7d267 100644 --- a/builtin/providers/azurerm/provider.go +++ b/builtin/providers/azurerm/provider.go @@ -2,9 +2,11 @@ package azurerm import ( "fmt" + "log" "net/http" "strings" + "github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest" "github.com/hashicorp/terraform/helper/mutexkv" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" @@ -112,10 +114,47 @@ func registerAzureResourceProvidersWithSubscription(config *Config, client *ArmC return nil } +// azureRMNormalizeLocation is a function which normalises human-readable region/location +// names (e.g. "West US") to the values used and returned by the Azure API (e.g. "westus"). +// In state we track the API internal version as it is easier to go from the human form +// to the canonical form than the other way around. func azureRMNormalizeLocation(location interface{}) string { input := location.(string) return strings.Replace(strings.ToLower(input), " ", "", -1) } +// pollIndefinitelyAsNeeded is a terrible hack which is necessary because the Azure +// Storage API (and perhaps others) can have response times way beyond the default +// retry timeouts, with no apparent upper bound. This effectively causes the client +// to continue polling when it reaches the configured timeout. My investigations +// suggest that this is neccesary when deleting and recreating a storage account with +// the same name in a short (though undetermined) time period. +// +// It is possible that this will give Terraform the appearance of being slow in +// future: I have attempted to mitigate this by logging whenever this happens. We +// may want to revisit this with configurable timeouts in the future as clearly +// unbounded wait loops is not ideal. It does seem preferable to the current situation +// where our polling loop will time out _with an operation in progress_, but no ID +// for the resource - so the state will not know about it, and conflicts will occur +// on the next run. +func pollIndefinitelyAsNeeded(client autorest.Client, response *http.Response, acceptableCodes ...int) (*http.Response, error) { + var resp *http.Response + var err error + + for { + resp, err = client.PollAsNeeded(response, acceptableCodes...) + if err != nil { + if resp.StatusCode != http.StatusAccepted { + log.Printf("[DEBUG] Starting new polling loop for %q", response.Request.URL.Path) + continue + } + + return resp, err + } + + return resp, nil + } +} + // armMutexKV is the instance of MutexKV for ARM resources var armMutexKV = mutexkv.NewMutexKV()