1// +build go1.13 2 3// Copyright (c) Microsoft Corporation. All rights reserved. 4// Licensed under the MIT License. 5 6package loc 7 8import ( 9 "errors" 10 "fmt" 11 "net/http" 12 13 "github.com/Azure/azure-sdk-for-go/sdk/armcore/internal/pollers" 14 "github.com/Azure/azure-sdk-for-go/sdk/azcore" 15) 16 17// Applicable returns true if the LRO is using Location. 18func Applicable(resp *azcore.Response) bool { 19 return resp.StatusCode == http.StatusAccepted && resp.Header.Get(pollers.HeaderLocation) != "" 20} 21 22// Poller is an LRO poller that uses the Location pattern. 23type Poller struct { 24 // The poller's type, used for resume token processing. 25 Type string `json:"type"` 26 27 // The URL for polling. 28 PollURL string `json:"pollURL"` 29 30 // The LRO's current state. 31 CurState string `json:"state"` 32} 33 34// New creates a new Poller from the provided initial response. 35func New(resp *azcore.Response, pollerID string) (*Poller, error) { 36 azcore.Log().Write(azcore.LogLongRunningOperation, "Using Location poller.") 37 locURL := resp.Header.Get(pollers.HeaderLocation) 38 if locURL == "" { 39 return nil, errors.New("response is missing Location header") 40 } 41 if !pollers.IsValidURL(locURL) { 42 return nil, fmt.Errorf("invalid polling URL %s", locURL) 43 } 44 p := &Poller{ 45 Type: pollers.MakeID(pollerID, "loc"), 46 PollURL: locURL, 47 CurState: pollers.StatusInProgress, 48 } 49 return p, nil 50} 51 52// URL returns the polling URL. 53func (p *Poller) URL() string { 54 return p.PollURL 55} 56 57// Done returns true if the LRO has reached a terminal state. 58func (p *Poller) Done() bool { 59 return pollers.IsTerminalState(p.Status()) 60} 61 62// Update updates the Poller from the polling response. 63func (p *Poller) Update(resp *azcore.Response) error { 64 // location polling can return an updated polling URL 65 if h := resp.Header.Get(pollers.HeaderLocation); h != "" { 66 p.PollURL = h 67 } 68 if resp.HasStatusCode(http.StatusOK, http.StatusCreated) { 69 // if a 200/201 returns a provisioning state, use that instead 70 state, err := pollers.GetProvisioningState(resp) 71 if err != nil && !errors.Is(err, pollers.ErrNoBody) { 72 return err 73 } 74 if state != "" { 75 p.CurState = state 76 } else { 77 // a 200/201 with no provisioning state indicates success 78 p.CurState = pollers.StatusSucceeded 79 } 80 } else if resp.StatusCode == http.StatusNoContent { 81 p.CurState = pollers.StatusSucceeded 82 } else if resp.StatusCode > 399 && resp.StatusCode < 500 { 83 p.CurState = pollers.StatusFailed 84 } 85 // a 202 falls through, means the LRO is still in progress and we don't check for provisioning state 86 return nil 87} 88 89// FinalGetURL returns the empty string as no final GET is required for this poller type. 90func (p *Poller) FinalGetURL() string { 91 return "" 92} 93 94// Status returns the status of the LRO. 95func (p *Poller) Status() string { 96 return p.CurState 97} 98