aboutsummaryrefslogtreecommitdiffstats
path: root/lib/cloudify.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cloudify.js')
-rw-r--r--lib/cloudify.js268
1 files changed, 98 insertions, 170 deletions
diff --git a/lib/cloudify.js b/lib/cloudify.js
index 5c5c658..138b986 100644
--- a/lib/cloudify.js
+++ b/lib/cloudify.js
@@ -19,8 +19,7 @@ See the License for the specific language governing permissions and limitations
"use strict";
const CLOUDIFY = "cloudify-manager";
-const FINISHED = [ "terminated", "cancelled", "failed" ];
-const DEPLOYMENT_CREATION_FINISHED = [ "terminated" ];
+const FINISHED = [ "terminated", "cancelled", "canceled", "failed" ];
const RETRY_INTERVAL = 5000; // Every 5 seconds
const MAX_TRIES = 720; // Up to 1 hour
const DEP_CREATION_STATUS_RETRY_INTERVAL = 30000; // Every 30 seconds
@@ -71,8 +70,8 @@ const exeQueue = new ExeQueue();
exports.exeQueue = exeQueue;
// Get current status of a workflow execution
-const getExecutionStatus = function(req, execution_id) {
- var reqOptions = {
+exports.getExecutionStatus = function(req, execution_id) {
+ const reqOptions = {
method : "GET",
uri : cfyAPI + "/executions/" + execution_id
};
@@ -84,7 +83,7 @@ const getExecutionStatus = function(req, execution_id) {
// Get current status of a deployment creation
const getDeploymentCreationStatus = function(req, deployment_id) {
- var reqOptions = {
+ const reqOptions = {
method : "GET",
uri : cfyAPI + "/executions?deployment_id=" + deployment_id + "&workflow_id=create_deployment_environment&_include=id,status"
};
@@ -94,77 +93,29 @@ const getDeploymentCreationStatus = function(req, deployment_id) {
};
// Poll for the result of a workflow execution until it's done
-const getWorkflowResult = function(mainReq, execution_id) {
+// Return a promise for the final result of a workflow execution
+exports.waitForWorkflowExecution = function(mainReq, execution_id) {
/* Defense: Some callers do not supply mainReq */
mainReq = mainReq || {};
- logger.info(mainReq.dcaeReqId, "Getting workflow result for execution id: " + execution_id);
-
- // Function for testing if workflow is finished
- // Expects the result of getExecStatus
- var checkStatus = function(res) {
- logger.info(mainReq.dcaeReqId, "Checking result: " + JSON.stringify(res) + " ==> " + (res.json && res.json.status && FINISHED.indexOf(res.json.status) < 0));
- return res.json && res.json.status && FINISHED.indexOf(res.json.status) < 0;
- };
-
- // Create execution status checker function
- var getExecStatus = function() {return getExecutionStatus(mainReq, execution_id);};
-
- return repeat.repeatWhile(getExecStatus, checkStatus, MAX_TRIES, RETRY_INTERVAL)
- .then(
-
- /* Handle fulfilled promise from repeatWhile */
- function(res) {
-
- logger.info(mainReq.dcaeReqId, 'workflow result: ' + JSON.stringify(res));
-
- /* Successful completion */
- if (res.json && res.json.status && res.json.status === 'terminated') {
- return res;
- }
-
- /* If we get here, we don't have a success and we're going to throw something */
-
- var error = {};
-
- /* We expect a JSON object with a status */
- if (res.json && res.json.status) {
-
- /* Failure -- we need to return something that looks like the CM API failures */
- if (res.json.status === 'failed') {
- error.body = 'workflow failed: ' + execution_id + ' -- ' + (res.json.error ? JSON.stringify(res.json.error) : 'no error information');
- }
-
- /* Cancellation -- don't really expect this */
- else if (res.json.status === 'canceled' || res.json.status === 'cancelled') {
- error.body = 'workflow canceled: ' + execution_id;
- }
-
- /* Don't expect anything else -- but if we get it, it's not a success! */
- else {
- error.body = 'workflow--unexpected status ' + res.json.status + ' for ' + execution_id;
- }
- }
-
- /* The body of the response from the API call to get execution status is not what we expect at all */
- else {
- error.body = 'workflow--unexpected result body getting execution status from CM for ' + execution_id;
- }
-
- throw error;
- },
-
- /* Handle rejection of promise from repeatWhile--don't use a catch because it would catch the error thrown above */
- function(err) {
- /* repeatWhile could fail and we get here because:
- * -- repeatWhile explicitly rejects the promise because it has exhausted the retries
- * -- repeatWhile propagates a system error (e.g., network problem) trying to access the API
- * -- repeatWhile propagates a rejected promise due to a bad HTTP response status
- * These should all get normalized in deploy.js--so we just rethrow the error.
- */
-
- throw err;
-
- });
+ const log_title = "execution_id(" + execution_id + "): workflow execution";
+ logger.info(mainReq.dcaeReqId, log_title + ": waiting for completion");
+
+ const getStatus = function(res) {return res && res.json && res.json.status;};
+
+ return repeat.repeatWhile(function() {return exports.getExecutionStatus(mainReq, execution_id);},
+ function(res) {return checkExecutionRunning(mainReq, res, log_title, getStatus);},
+ MAX_TRIES, RETRY_INTERVAL)
+ .then(function (res) {return onFinishedExecution(mainReq, res, log_title, getStatus);},
+ /* Handle rejection of promise from repeatWhile--don't use a catch because it would catch the error thrown above */
+ function(err) {
+ /* repeatWhile could fail and we get here because:
+ * -- repeatWhile explicitly rejects the promise because it has exhausted the retries
+ * -- repeatWhile propagates a system error (e.g., network problem) trying to access the API
+ * -- repeatWhile propagates a rejected promise due to a bad HTTP response status
+ * These should all get normalized in deploy.js--so we just rethrow the error.
+ */
+ throw err;
+ });
};
// bare start of a workflow execution against a deployment
@@ -172,7 +123,7 @@ const startWorkflowExecution = function(mainReq, deployment_id, workflow_id, par
/* Defense: Some callers do not supply mainReq */
mainReq = mainReq || {};
// Set up the HTTP POST request
- var reqOptions = {
+ const reqOptions = {
method : "POST",
uri : cfyAPI + "/executions",
headers : {
@@ -183,7 +134,7 @@ const startWorkflowExecution = function(mainReq, deployment_id, workflow_id, par
addAuthToOptions(reqOptions, mainReq);
- var body = {
+ const body = {
"deployment_id" : deployment_id,
"workflow_id" : workflow_id
};
@@ -194,7 +145,7 @@ const startWorkflowExecution = function(mainReq, deployment_id, workflow_id, par
};
//Initiate a workflow execution against a deployment
-const initiateWorkflowExecution = function(req, deployment_id, workflow_id, parameters) {
+exports.initiateWorkflowExecution = function(req, deployment_id, workflow_id, parameters) {
return startWorkflowExecution(req, deployment_id, workflow_id, parameters)
.then(function(result) {
logger.info(req.dcaeReqId, "Result from POSTing workflow execution start: " + JSON.stringify(result));
@@ -208,81 +159,70 @@ const initiateWorkflowExecution = function(req, deployment_id, workflow_id, para
});
};
+// Function for testing if workflow execution or deployment creation has finished or still running
+// Expects the result of getExecStatus
+const checkExecutionRunning = function(mainReq, res, log_title, getStatus) {
+ const still_running = !FINISHED.includes(getStatus(res));
+ logger.info(mainReq.dcaeReqId, log_title + ": checking status: " + JSON.stringify(res) + " ==> " + still_running);
+ return still_running;
+};
+
+const onFinishedExecution = function(mainReq, res, log_title, getStatus) {
+ logger.info(mainReq.dcaeReqId, log_title + " result: " + JSON.stringify(res));
+ const status = getStatus(res);
+ /* Successful completion */
+ if (status === 'terminated') {
+ logger.info(mainReq.dcaeReqId, log_title + ' completed');
+ return res;
+ }
+ /* If we get here, we don't have a success and we're going to throw something */
+ const error = { "body": log_title + " " + status };
+ /* We expect a JSON object with a status */
+ if (status) {
+ /* Failure -- we need to return something that looks like the CM API failures */
+ if (status === 'failed') {
+ error.body += ' -- ' + (res.json.error ? JSON.stringify(res.json.error) : 'no error information');
+ }
+ /* Cancellation -- don't really expect this */
+ else if (status === 'canceled' || status === 'cancelled') { }
+ /* Don't expect anything else -- but if we get it, it's not a success! */
+ else {
+ error.body += ' -- unexpected status';
+ }
+ }
+ /* The body of the response from the API call to get execution status is not what we expect at all */
+ else {
+ error.body += ' -- unexpected result body from Cloudify Manager';
+ }
+ throw error;
+};
+
// Poll for the deployment creation status
-const getDeploymentCreationResult = function(mainReq, deployment_id) {
+const waitForDeploymentCreation = function(mainReq, deployment_id) {
/* Defense: Some callers do not supply mainReq */
mainReq = mainReq || {};
- logger.info(mainReq.dcaeReqId, "Getting status for deployment id: " + deployment_id);
-
- // Function for testing if deployment creation is complete
- // Expects the result of getDepCrStatus
- const checkDepStatus = function(cloudify_response) {
- cloudify_response = cloudify_response && cloudify_response.json;
- logger.info(mainReq.dcaeReqId, "Checking Deployment creation result: " + JSON.stringify(cloudify_response) + " ==> " +
- (cloudify_response.items.length == 1 && DEPLOYMENT_CREATION_FINISHED.indexOf(cloudify_response.items[0].status) < 0));
- return cloudify_response.items.length == 1 && DEPLOYMENT_CREATION_FINISHED.indexOf(cloudify_response.items[0].status) < 0;
- };
-
- // Create deployment creation status checker function
- const getDepCrStatus = function() {return getDeploymentCreationStatus(mainReq, deployment_id);};
-
- return repeat.repeatWhile(getDepCrStatus, checkDepStatus, DEP_CREATION_STATUS_MAX_TRIES, DEP_CREATION_STATUS_RETRY_INTERVAL)
- .then(
-
- /* Handle fulfilled promise from repeatWhile */
- function(res) {
-
- logger.info(mainReq.dcaeReqId, 'Deployment creation result: ' + JSON.stringify(res));
-
- /* Successful completion */
- if (res.json && res.json.items.length == 1 && res.json.items[0].status === 'terminated') {
- logger.info(mainReq.dcaeReqId, 'Deployment creation completed for deployment_id: ' + deployment_id);
- return res;
- }
-
- /* If we get here, we don't have a success and we're going to throw something */
-
- var error = {};
-
- /* We expect a JSON object with a status */
- if (res.json && res.json.items.length == 1 && res.json.items[0].status) {
-
- /* Failure -- we need to return something that looks like the CM API failures */
- if (res.json.items[0].status === 'failed') {
- error.body = 'Deployment creation failed: ' + deployment_id + ' -- ' + (res.json.error ? JSON.stringify(res.json.error) : 'no error information');
- }
+ const log_title = "deployment_id(" + deployment_id + "): deployment creation";
+ logger.info(mainReq.dcaeReqId, log_title + ": waiting for completion");
- /* Cancellation -- don't really expect this */
- else if (res.json.items[0].status === 'canceled' || res.json.status === 'cancelled') {
- error.body = 'Deployment creation canceled: ' + deployment_id;
- }
-
- /* Don't expect anything else -- but if we get it, it's not a success! */
- else {
- error.body = 'Deployment creation--unexpected status ' + res.json.items[0].status + ' for ' + deployment_id;
- }
- }
-
- /* The body of the response from the API call to get execution status is not what we expect at all */
- else {
- error.body = 'Deployment creation--unexpected result body getting execution status from CM for ' + deployment_id;
- }
-
- throw error;
- },
-
- /* Handle rejection of promise from repeatWhile--don't use a catch because it would catch the error thrown above */
- function(err) {
- /* repeatWhile could fail and we get here because:
- * -- repeatWhile explicitly rejects the promise because it has exhausted the retries
- * -- repeatWhile propagates a system error (e.g., network problem) trying to access the API
- * -- repeatWhile propagates a rejected promise due to a bad HTTP response status
- * These should all get normalized in deploy.js--so we just rethrow the error.
- */
-
- throw err;
+ const getStatus = function(res) {
+ return res && res.json && Array.isArray(res.json.items)
+ && res.json.items.length == 1 && res.json.items[0].status;
+ };
- });
+ return repeat.repeatWhile(function() {return getDeploymentCreationStatus(mainReq, deployment_id);},
+ function(res) {return checkExecutionRunning(mainReq, res, log_title, getStatus);},
+ DEP_CREATION_STATUS_MAX_TRIES, DEP_CREATION_STATUS_RETRY_INTERVAL)
+ .then(function (res) {return onFinishedExecution(mainReq, res, log_title, getStatus);},
+ /* Handle rejection of promise from repeatWhile--don't use a catch because it would catch the error thrown above */
+ function(err) {
+ /* repeatWhile could fail and we get here because:
+ * -- repeatWhile explicitly rejects the promise because it has exhausted the retries
+ * -- repeatWhile propagates a system error (e.g., network problem) trying to access the API
+ * -- repeatWhile propagates a rejected promise due to a bad HTTP response status
+ * These should all get normalized in deploy.js--so we just rethrow the error.
+ */
+ throw err;
+ });
};
// Uploads a blueprint via the Cloudify API
@@ -314,7 +254,7 @@ exports.uploadBlueprint = function(req, bpid, blueprint) {
exports.createDeployment = function(req, dpid, bpid, inputs) {
// Set up the HTTP PUT request
- var reqOptions = {
+ const reqOptions = {
method : "PUT",
uri : cfyAPI + "/deployments/" + dpid,
headers : {
@@ -324,7 +264,7 @@ exports.createDeployment = function(req, dpid, bpid, inputs) {
};
addAuthToOptions(reqOptions, req);
- var body = {
+ const body = {
blueprint_id : bpid
};
if (inputs) {
@@ -335,35 +275,23 @@ exports.createDeployment = function(req, dpid, bpid, inputs) {
return doRequest(req, reqOptions, JSON.stringify(body), CLOUDIFY);
};
-// Initiate a workflow execution against a deployment
-exports.initiateWorkflowExecution = initiateWorkflowExecution;
-
-// Get the status of a workflow execution
-exports.getWorkflowExecutionStatus = getExecutionStatus;
-
-// Return a promise for the final result of a workflow execution
-exports.getWorkflowResult = getWorkflowResult;
-
// Executes a workflow against a deployment and returns a promise for final result
exports.executeWorkflow = function(req, deployment_id, workflow_id, parameters) {
- return initiateWorkflowExecution(req, deployment_id, workflow_id, parameters)
+ return exports.initiateWorkflowExecution(req, deployment_id, workflow_id, parameters)
// Wait for the result
.then (function(result) {
logger.info(req.dcaeReqId, "Result from initiating workflow: " + JSON.stringify(result));
- return getWorkflowResult(req, result.executionId);
+ return exports.waitForWorkflowExecution(req, result.executionId);
});
};
// Return a promise for the final result of a deployment update
-exports.getDeploymentCreationResult = getDeploymentCreationResult;
-
-// Get the status of a deployment update
-exports.getDeploymentCreationStatus = getDeploymentCreationStatus;
+exports.waitForDeploymentCreation = waitForDeploymentCreation;
// Retrieves outputs for a deployment
exports.getOutputs = function(req, dpid) {
- var reqOptions = {
+ const reqOptions = {
method : "GET",
uri : cfyAPI + "/deployments/" + dpid + "/outputs",
headers : {
@@ -378,7 +306,7 @@ exports.getOutputs = function(req, dpid) {
// Get the output descriptions for a deployment
exports.getOutputDescriptions = function(req, dpid) {
- var reqOptions = {
+ const reqOptions = {
method : "GET",
uri : cfyAPI + "/deployments/" + dpid + "?include=outputs",
headers : {
@@ -393,7 +321,7 @@ exports.getOutputDescriptions = function(req, dpid) {
// Deletes a deployment
exports.deleteDeployment = function(req, dpid) {
- var reqOptions = {
+ const reqOptions = {
method : "DELETE",
uri : cfyAPI + "/deployments/" + dpid
};
@@ -405,7 +333,7 @@ exports.deleteDeployment = function(req, dpid) {
// Deletes a blueprint
exports.deleteBlueprint = function(req, bpid) {
- var reqOptions = {
+ const reqOptions = {
method : "DELETE",
uri : cfyAPI + "/blueprints/" + bpid
};
@@ -444,7 +372,7 @@ exports.setLogger = function(log) {
exports.getNodeInstances = function (mainReq, on_next_node_instances, offset) {
offset = offset || 0;
- var reqOptions = {
+ const reqOptions = {
method : "GET",
uri : cfyAPI + "/node-instances?_include=id,deployment_id,runtime_properties&_size=1000&_offset=" + offset
};
@@ -506,7 +434,7 @@ const runQueuedExecution = function(mainReq, deployment_id, workflow_id, paramet
553, "api", 553, CLOUDIFY);
}
exeQueue.setExecutionId(deployment_id, execution_id);
- return getWorkflowResult(mainReq, execution_id);
+ return exports.waitForWorkflowExecution(mainReq, execution_id);
})
.then(function(result) {
logger.info(mainReq.dcaeReqId, 'successfully finished execution: ' + execution_id + " for" + exe_deployment_str);