Beispiel #1
0
func newPollingRequest(resp *http.Response, ps pollingState) (*http.Request, error) {
	req := resp.Request
	if req == nil {
		return nil, autorest.NewError("azure", "newPollingRequest", "Azure Polling Error - Original HTTP request is missing")
	}

	reqPoll, err := autorest.Prepare(&http.Request{Cancel: req.Cancel},
		autorest.AsGet(),
		autorest.WithBaseURL(ps.uri))
	if err != nil {
		return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri)
	}

	return reqPoll, nil
}
Beispiel #2
0
//	updatePollingState maps the operation status -- retrieved from either a provisioningState
// 	field, the status field of an OperationResource, or inferred from the HTTP status code --
// 	into a well-known states. Since the process begins from the initial request, the state
//	always comes from either a the provisioningState returned or is inferred from the HTTP
//	status code. Subsequent requests will read an Azure OperationResource object if the
//	service initially returned the Azure-AsyncOperation header. The responseFormat field notes
//	the expected response format.
func updatePollingState(resp *http.Response, ps *pollingState) error {
	// Determine the response shape
	// -- The first response will always be a provisioningStatus response; only the polling requests,
	//    depending on the header returned, may be something otherwise.
	var pt provisioningTracker
	if ps.responseFormat == usesOperationResponse {
		pt = &operationResource{}
	} else {
		pt = &provisioningStatus{}
	}

	// If this is the first request (that is, the polling response shape is unknown), determine how
	// to poll and what to expect
	if ps.responseFormat == formatIsUnknown {
		req := resp.Request
		if req == nil {
			return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing")
		}

		// Prefer the Azure-AsyncOperation header
		ps.uri = getAsyncOperation(resp)
		if ps.uri != "" {
			ps.responseFormat = usesOperationResponse
		} else {
			ps.responseFormat = usesProvisioningStatus
		}

		// Else, use the Location header
		if ps.uri == "" {
			ps.uri = autorest.GetLocation(resp)
		}

		// Lastly, requests against an existing resource, use the last request URI
		if ps.uri == "" {
			m := strings.ToUpper(req.Method)
			if m == methodPatch || m == methodPut || m == methodGet {
				ps.uri = req.URL.String()
			}
		}
	}

	// Read and interpret the response (saving the Body in case no polling is necessary)
	b := &bytes.Buffer{}
	err := autorest.Respond(resp,
		autorest.ByCopying(b),
		autorest.ByUnmarshallingJSON(pt),
		autorest.ByClosing())
	resp.Body = ioutil.NopCloser(b)
	if err != nil {
		return err
	}

	// Interpret the results
	// -- Terminal states apply regardless
	// -- Unknown states are per-service inprogress states
	// -- Otherwise, infer state from HTTP status code
	if pt.hasTerminated() {
		ps.state = pt.state()
	} else if pt.state() != "" {
		ps.state = operationInProgress
	} else {
		switch resp.StatusCode {
		case http.StatusAccepted:
			ps.state = operationInProgress

		case http.StatusNoContent, http.StatusCreated, http.StatusOK:
			ps.state = operationSucceeded

		default:
			ps.state = operationFailed
		}
	}

	if ps.state == operationInProgress && ps.uri == "" {
		return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Unable to obtain polling URI for %s %s", resp.Request.Method, resp.Request.URL)
	}

	// For failed operation, check for error code and message in
	// -- Operation resource
	// -- Response
	// -- Otherwise, Unknown
	if ps.hasFailed() {
		if ps.responseFormat == usesOperationResponse {
			or := pt.(*operationResource)
			ps.code = or.OperationError.Code
			ps.message = or.OperationError.Message
		} else {
			p := pt.(*provisioningStatus)
			if p.hasProvisioningError() {
				ps.code = p.ProvisioningError.Code
				ps.message = p.ProvisioningError.Message
			} else {
				ps.code = "Unknown"
				ps.message = "None"
			}
		}
	}
	return nil
}