UNPKG

@azure/ms-rest-azure-js

Version:

Isomorphic Azure client runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest

585 lines 27.4 kB
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. import { __assign, __awaiter, __extends, __generator } from "tslib"; import { delay, RestError, stripRequest, WebResource } from "@azure/ms-rest-js"; /** * A long-running operation polling strategy base class that other polling strategies should extend. */ var LROPollStrategy = /** @class */ (function () { function LROPollStrategy(_azureServiceClient, _pollState) { this._azureServiceClient = _azureServiceClient; this._pollState = _pollState; } LROPollStrategy.prototype.getOperationStatus = function () { return this._pollState.state; }; /** * Get whether or not this poll strategy's LRO is finished. * @returns Whether or not this poll strategy's LRO is finished. */ LROPollStrategy.prototype.isFinished = function () { return isFinished(this._pollState.state); }; /** * Send poll requests that check the LRO's status until it is determined that the LRO is finished. * @returns Whether or not the LRO succeeded. */ LROPollStrategy.prototype.pollUntilFinished = function () { return __awaiter(this, void 0, void 0, function () { var delayInSeconds; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!!this.isFinished()) return [3 /*break*/, 3]; delayInSeconds = getDelayInSeconds(this._azureServiceClient, this._pollState.mostRecentResponse); return [4 /*yield*/, delay(delayInSeconds * 1000)]; case 1: _a.sent(); return [4 /*yield*/, this.sendPollRequest()]; case 2: _a.sent(); return [3 /*break*/, 0]; case 3: return [2 /*return*/, this.isFinalStatusAcceptable()]; } }); }); }; LROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () { var initialRequestMethod = this._pollState.initialResponse.request.method; return !this._pollState.resource && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH" || initialRequestMethod === "POST"); }; LROPollStrategy.prototype.getMostRecentResponse = function () { return this._pollState.mostRecentResponse; }; LROPollStrategy.prototype.getOperationResponse = function () { return __awaiter(this, void 0, void 0, function () { var response, result, resource; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.shouldDoFinalGetResourceRequest()) return [3 /*break*/, 2]; return [4 /*yield*/, this.doFinalGetResourceRequest()]; case 1: _a.sent(); _a.label = 2; case 2: response = this._pollState.mostRecentResponse; result = __assign(__assign({}, response), { headers: response.headers.clone() }); resource = this._pollState.resource; if (!resource) { result.bodyAsText = response.bodyAsText; result.parsedBody = response.parsedBody; } else if (typeof resource.valueOf() === "string") { result.bodyAsText = resource; try { result.parsedBody = JSON.parse(resource); } catch (err) { // There was an error parsing the JSON. Hence we set the resource as-is. Most likely, the // resource is a string that was already parsed. result.parsedBody = resource; } } else { result.bodyAsText = JSON.stringify(resource); result.parsedBody = resource; } return [2 /*return*/, result]; } }); }); }; LROPollStrategy.prototype.getRestError = function () { var error = new RestError(""); error.request = stripRequest(this._pollState.mostRecentRequest); error.response = this._pollState.mostRecentResponse; error.message = "Long running operation failed with status: \"" + this._pollState.state + "\"."; error.body = this._pollState.resource; if (error.body) { var innerError = error.body.error; if (innerError) { if (innerError.message) { error.message = "Long running operation failed with error: \"" + innerError.message + "\"."; } if (innerError.code) { error.code = innerError.code; } } } return error; }; LROPollStrategy.prototype.updateState = function (url, shouldDeserialize) { var _this = this; return this.updateOperationStatus(url, shouldDeserialize).then(function (result) { _this._pollState.state = getProvisioningState(result.parsedBody) || "Succeeded"; _this._pollState.mostRecentResponse = result; _this._pollState.mostRecentRequest = result.request; _this._pollState.resource = getResponseBody(result); }).catch(function (error) { var resultStatus; if (error.response && error.response.status) { resultStatus = error.response.status; if (_this._pollState.initialResponse.request.method !== "DELETE" || resultStatus < 400 || 499 < resultStatus) { throw error; } } else { throw error; } }); }; /** * Retrieves operation status by querying the operation URL. * @param {string} statusUrl URL used to poll operation result. */ LROPollStrategy.prototype.updateOperationStatus = function (statusUrl, shouldDeserialize) { var requestUrl = statusUrl.replace(" ", "%20"); var httpRequest = new WebResource(requestUrl, "GET"); var pollState = this._pollState; httpRequest.operationSpec = pollState.mostRecentRequest.operationSpec; httpRequest.shouldDeserialize = shouldDeserialize; httpRequest.operationResponseGetter = getOperationResponse; var options = pollState.options; if (options && options.customHeaders) { var customHeaders = options.customHeaders; for (var _i = 0, _a = Object.keys(customHeaders); _i < _a.length; _i++) { var headerName = _a[_i]; httpRequest.headers.set(headerName, customHeaders[headerName]); } } return this._azureServiceClient.sendRequest(httpRequest); }; LROPollStrategy.prototype.getPollState = function () { return this._pollState; }; return LROPollStrategy; }()); export { LROPollStrategy }; function getOperationResponse(operationSpec, response) { var statusCode = response.status; var operationResponses = operationSpec.responses; var result = operationResponses[statusCode]; if (!result) { if (statusCode === 200) { result = operationResponses[201] || operationResponses[202]; } else if (201 <= statusCode && statusCode <= 299) { result = {}; } } return result; } export function getDelayInSeconds(azureServiceClient, previousResponse) { var delayInSeconds = 30; if (azureServiceClient.longRunningOperationRetryTimeout != undefined) { delayInSeconds = azureServiceClient.longRunningOperationRetryTimeout; } else { var retryAfterHeaderValue = previousResponse.headers.get("retry-after"); if (retryAfterHeaderValue) { var retryAfterDelayInSeconds = parseInt(retryAfterHeaderValue); if (!Number.isNaN(retryAfterDelayInSeconds)) { delayInSeconds = retryAfterDelayInSeconds; } } } return delayInSeconds; } function getProvisioningState(responseBody) { var result; if (responseBody) { if (responseBody.provisioningState) { result = responseBody.provisioningState; } else if (responseBody.properties) { result = responseBody.properties.provisioningState; } } return result; } function getResponseBody(response) { var result; try { if (response.parsedBody) { result = response.parsedBody; } else if (response.bodyAsText && response.bodyAsText.length > 0) { result = JSON.parse(response.bodyAsText); } } catch (error) { var deserializationError = new RestError("Error \"" + error + "\" occurred in parsing the responseBody \" +\n \"while creating the PollingState for Long Running Operation- \"" + response.bodyAsText + "\""); deserializationError.request = response.request; deserializationError.response = response; throw deserializationError; } return result; } function getStatusFromResponse(response, responseBody) { if (responseBody == undefined) { responseBody = getResponseBody(response); } var result; switch (response.status) { case 202: result = "InProgress"; break; case 204: result = "Succeeded"; break; case 201: result = getProvisioningState(responseBody) || "InProgress"; break; case 200: var provisioningState = getProvisioningState(responseBody); if (provisioningState) { result = provisioningState; } else if (getAzureAsyncOperationHeaderValue(response) || getLocationHeaderValue(response)) { result = "InProgress"; } else { result = "Succeeded"; } break; default: result = "Failed"; break; } return result; } var terminalStates = ["Succeeded", "Failed", "Canceled", "Cancelled"]; /** * Get whether or not a long-running operation with the provided status is finished. * @param status The current status of a long-running operation. * @returns Whether or not a long-running operation with the provided status is finished. */ export function isFinished(status) { var result = false; for (var _i = 0, terminalStates_1 = terminalStates; _i < terminalStates_1.length; _i++) { var terminalState = terminalStates_1[_i]; if (longRunningOperationStatesEqual(status, terminalState)) { result = true; break; } } return result; } export function longRunningOperationStatesEqual(lhs, rhs) { var lhsLowerCased = lhs && lhs.toLowerCase(); var rhsLowerCased = rhs && rhs.toLowerCase(); return lhsLowerCased === rhsLowerCased; } /** * Create a new long-running operation polling strategy based on the provided initial response. * @param initialResponse The initial response to the long-running operation's initial request. * @param azureServiceClient The AzureServiceClient that was used to send the initial request. * @param options Any options that were provided to the initial request. */ export function createLROPollStrategyFromInitialResponse(initialResponse, azureServiceClient, options) { var initialRequestMethod = initialResponse.request.method; var initialResponseStatus = initialResponse.status; var lroPollStrategyType; if (getAzureAsyncOperationHeaderValue(initialResponse)) { lroPollStrategyType = "AzureAsyncOperation"; } else if (getLocationHeaderValue(initialResponse)) { lroPollStrategyType = "Location"; } else if (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH") { lroPollStrategyType = "GetResource"; } else if (initialResponseStatus !== 201 && initialResponseStatus !== 202 && !isFinished(getStatusFromResponse(initialResponse))) { throw new Error("Can't determine long running operation polling strategy."); } var result; if (lroPollStrategyType) { var resource = getResponseBody(initialResponse); var lroPollState = { pollStrategyType: lroPollStrategyType, options: options, initialResponse: initialResponse, mostRecentResponse: initialResponse, mostRecentRequest: initialResponse.request, azureAsyncOperationHeaderValue: getAzureAsyncOperationHeaderValue(initialResponse), locationHeaderValue: getLocationHeaderValue(initialResponse), resource: resource, state: getStatusFromResponse(initialResponse, resource) }; result = createLROPollStrategyFromPollState(azureServiceClient, lroPollState); } else { result = undefined; } return result; } export function createLROPollStrategyFromPollState(azureServiceClient, lroPollState) { var result; switch (lroPollState.pollStrategyType) { case "AzureAsyncOperation": result = new AzureAsyncOperationLROPollStrategy(azureServiceClient, lroPollState); break; case "Location": result = new LocationLROPollStrategy(azureServiceClient, lroPollState); break; case "GetResource": result = new GetResourceLROPollStrategy(azureServiceClient, lroPollState); break; default: throw new Error("Unrecognized LRO poll strategy type: \"" + lroPollState.pollStrategyType + "\""); break; } return result; } function getLocationHeaderValue(response) { return response.headers.get("location"); } /** * A long-running operation polling strategy that is based on the location header. */ var LocationLROPollStrategy = /** @class */ (function (_super) { __extends(LocationLROPollStrategy, _super); function LocationLROPollStrategy() { return _super !== null && _super.apply(this, arguments) || this; } LocationLROPollStrategy.prototype.locationStrategyShouldDeserialize = function (parsedResponse) { var shouldDeserialize = false; var initialResponse = this._pollState.initialResponse; var initialRequestMethod = initialResponse.request.method; var statusCode = parsedResponse.status; if (statusCode === 200 || (statusCode === 201 && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH")) || (statusCode === 204 && (initialRequestMethod === "DELETE" || initialRequestMethod === "POST"))) { shouldDeserialize = true; } return shouldDeserialize; }; /** * Retrieve PUT operation status by polling from "location" header. * @param {string} method - The HTTP method. * @param {PollingState} pollingState - The object to persist current operation state. */ LocationLROPollStrategy.prototype.sendPollRequest = function () { var lroPollState = this._pollState; return this.updateOperationStatus(lroPollState.locationHeaderValue, this.locationStrategyShouldDeserialize.bind(this)).then(function (result) { var locationHeaderValue = getLocationHeaderValue(result); if (locationHeaderValue) { lroPollState.locationHeaderValue = locationHeaderValue; } lroPollState.mostRecentResponse = result; lroPollState.mostRecentRequest = result.request; var initialResponse = lroPollState.initialResponse; var initialRequestMethod = initialResponse.request.method; var initialResponseStatusCode = initialResponse.status; var statusCode = result.status; if (statusCode === 202) { lroPollState.state = "InProgress"; } else if (statusCode === 200 || (statusCode === 201 && (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH")) || (statusCode === 204 && (initialRequestMethod === "DELETE" || initialRequestMethod === "POST"))) { lroPollState.state = "Succeeded"; lroPollState.resource = getResponseBody(result); } else if (statusCode === 404 && initialRequestMethod === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) { lroPollState.state = "Failed"; lroPollState.resource = getResponseBody(result); } else if (400 <= statusCode && statusCode <= 499) { var resultBody = result.bodyAsText; var errorMessage = resultBody; try { var resultObject = JSON.parse(resultBody); errorMessage = resultObject.message; } catch (parseError) { // Ignore the exception, use resultBody as the error message } throw new RestError(errorMessage, undefined, statusCode, stripRequest(result.request), result, resultBody); } else { throw new Error("The response with status code " + statusCode + " from polling for long running operation url \"" + lroPollState.locationHeaderValue + "\" is not valid."); } }); }; LocationLROPollStrategy.prototype.isFinalStatusAcceptable = function () { var lroPollState = this._pollState; var initialResponse = lroPollState.initialResponse; var initialResponseStatusCode = initialResponse.status; return longRunningOperationStatesEqual(lroPollState.state, "Succeeded") || (initialResponse.request.method === "POST" && lroPollState.mostRecentResponse.status === 404 && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)); }; LocationLROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () { var lroPollState = this._pollState; var initialResponse = lroPollState.initialResponse; var result; var initialRequestMethod = initialResponse.request.method; var initialResponseStatusCode = initialResponse.status; if (initialRequestMethod === "POST" && lroPollState.mostRecentResponse.status === 404 && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) { result = false; } else { result = _super.prototype.shouldDoFinalGetResourceRequest.call(this) || (initialRequestMethod === "POST" && initialResponseStatusCode === 201); } return result; }; LocationLROPollStrategy.prototype.doFinalGetResourceRequest = function () { var lroPollState = this._pollState; var initialResponse = lroPollState.initialResponse; var getResourceRequestUrl; var initialResponseStatusCode = initialResponse.status; var initialRequest = initialResponse.request; if (initialRequest.method === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) { getResourceRequestUrl = lroPollState.locationHeaderValue; } else { getResourceRequestUrl = initialRequest.url; } return this.updateState(getResourceRequestUrl, true); }; return LocationLROPollStrategy; }(LROPollStrategy)); function getAzureAsyncOperationHeaderValue(response) { return response.headers.get("azure-asyncoperation"); } /** * A long-running operation polling strategy that is based on the azure-asyncoperation header. */ var AzureAsyncOperationLROPollStrategy = /** @class */ (function (_super) { __extends(AzureAsyncOperationLROPollStrategy, _super); function AzureAsyncOperationLROPollStrategy() { return _super !== null && _super.apply(this, arguments) || this; } /** * Retrieve operation status by polling from "azure-asyncoperation" header. * @param {PollingState} pollingState - The object to persist current operation state. * @param {boolean} inPostOrDelete - Invoked by Post Or Delete operation. */ AzureAsyncOperationLROPollStrategy.prototype.sendPollRequest = function () { var lroPollState = this._pollState; return this.updateOperationStatus(lroPollState.azureAsyncOperationHeaderValue, false).then(function (response) { var statusCode = response.status; var parsedResponse = response.parsedBody; if (statusCode !== 200 && statusCode !== 201 && statusCode !== 202 && statusCode !== 204) { var error = new RestError("Invalid status code (" + statusCode + ") with response body \"" + response.bodyAsText + "\" occurred when polling for operation status."); error.statusCode = statusCode; error.request = stripRequest(response.request); error.response = response; error.body = parsedResponse; throw error; } if (!parsedResponse) { throw new Error("The response from long running operation does not contain a body."); } else if (!parsedResponse.status) { throw new Error("The response \"" + response.bodyAsText + "\" from long running operation does not contain the status property."); } var azureAsyncOperationHeaderValue = getAzureAsyncOperationHeaderValue(response); if (azureAsyncOperationHeaderValue) { lroPollState.azureAsyncOperationHeaderValue = azureAsyncOperationHeaderValue; } lroPollState.state = parsedResponse.status; lroPollState.mostRecentResponse = response; lroPollState.mostRecentRequest = response.request; lroPollState.resource = getResponseBody(response); }); }; AzureAsyncOperationLROPollStrategy.prototype.shouldDoFinalGetResourceRequest = function () { var lroPollState = this._pollState; var initialResponse = lroPollState.initialResponse; var initialRequestMethod = initialResponse.request.method; var result = false; if (initialRequestMethod === "PUT" || initialRequestMethod === "PATCH") { result = true; } else { if (lroPollState.locationHeaderValue) { var initialResponseStatusCode = initialResponse.status; if (initialRequestMethod === "POST") { result = initialResponseStatusCode === 200 || initialResponseStatusCode === 201; } else if (initialRequestMethod === "DELETE") { result = initialResponseStatusCode === 200 || initialResponseStatusCode === 202; } } } return result; }; AzureAsyncOperationLROPollStrategy.prototype.doFinalGetResourceRequest = function () { var lroPollState = this._pollState; var locationHeaderValue = lroPollState.locationHeaderValue; var initialResponse = lroPollState.initialResponse; var initialRequest = initialResponse.request; var getResourceRequestUrl = initialRequest.url; if (locationHeaderValue) { var initialRequestMethod = initialRequest.method; var initialResponseStatusCode = initialResponse.status; if (initialRequestMethod === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201 || initialResponseStatusCode === 202)) { getResourceRequestUrl = locationHeaderValue; } else if (initialRequestMethod === "DELETE" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 202)) { getResourceRequestUrl = locationHeaderValue; } } return this.updateState(getResourceRequestUrl, true); }; AzureAsyncOperationLROPollStrategy.prototype.isFinalStatusAcceptable = function () { var lroPollState = this._pollState; var initialResponse = lroPollState.initialResponse; var initialResponseStatusCode = initialResponse.status; return longRunningOperationStatesEqual(lroPollState.state, "Succeeded") || (initialResponse.request.method === "POST" && (initialResponseStatusCode === 200 || initialResponseStatusCode === 201)); }; return AzureAsyncOperationLROPollStrategy; }(LROPollStrategy)); /** * A long-running operation polling strategy that is based on the resource's provisioning state. */ var GetResourceLROPollStrategy = /** @class */ (function (_super) { __extends(GetResourceLROPollStrategy, _super); function GetResourceLROPollStrategy() { return _super !== null && _super.apply(this, arguments) || this; } GetResourceLROPollStrategy.prototype.sendPollRequest = function () { var lroPollState = this._pollState; return this.updateOperationStatus(lroPollState.initialResponse.request.url, false).then(function (result) { var statusCode = result.status; var responseBody = result.parsedBody; if (statusCode !== 200 && statusCode !== 201 && statusCode !== 202 && statusCode !== 204) { var error = new RestError("Invalid status code with response body \"" + result.bodyAsText + "\" occurred when polling for operation status."); error.statusCode = statusCode; error.request = stripRequest(result.request); error.response = result; error.body = responseBody; throw error; } if (!result.parsedBody) { throw new Error("The response from long running operation does not contain a body."); } lroPollState.state = getProvisioningState(result.parsedBody) || "Succeeded"; lroPollState.mostRecentResponse = result; lroPollState.mostRecentRequest = result.request; lroPollState.resource = getResponseBody(result); }); }; GetResourceLROPollStrategy.prototype.isFinalStatusAcceptable = function () { return longRunningOperationStatesEqual(this._pollState.state, "Succeeded"); }; GetResourceLROPollStrategy.prototype.doFinalGetResourceRequest = function () { return this.sendPollRequest(); }; return GetResourceLROPollStrategy; }(LROPollStrategy)); //# sourceMappingURL=lroPollStrategy.js.map