aboutsummaryrefslogtreecommitdiffstats
path: root/lib/deploy.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/deploy.js')
-rw-r--r--lib/deploy.js184
1 files changed, 147 insertions, 37 deletions
diff --git a/lib/deploy.js b/lib/deploy.js
index e807060..fcee43d 100644
--- a/lib/deploy.js
+++ b/lib/deploy.js
@@ -26,6 +26,8 @@ const DELAY_RETRIEVE_OUTPUTS = 5000;
const DELAY_DELETE_DEPLOYMENT = 30000;
const DELAY_DELETE_BLUEPRINT = 10000;
+const createError = require('./dispatcher-error').createDispatcherError;
+
/* Set up the Cloudify low-level interface library */
var cfy = require("./cloudify.js");
/* Set config for deploy module */
@@ -52,36 +54,37 @@ var parseContent = function(input) {
// create a normalized representation of errors, whether they're a node.js Error or a Cloudify API error
var normalizeError = function (err) {
- var e = {};
+ var e;
+
if (err instanceof Error) {
- e.message = err.message;
- if (err.code) {
- e.code = err.code;
- }
- if (err.status) {
- e.status = err.status;
- }
+ /* node.js system error */
+ e = createError("Error communicating with CM: " + err.message, 504, "system", 202, 'cloudify-manager');
}
else {
// Try to populate error with information from a Cloudify API error
// We expect to see err.body, which is a stringified JSON object
// We can parse it and extract message and error_code
- e.message = "unknown API error";
- e.code = "UNKNOWN";
- if (err.status) {
- e.status = err.status;
- }
+ var message = err.message || "unknown Cloudify Manager API error";
+ var status = err.status || 502;
+ var cfyCode = "UNKNOWN";
+ var cfyMessage;
+
if (err.body) {
var p = parseContent(err.body);
if (p.json) {
- e.message = p.content.message ? p.content.message : "unknown API error";
- e.code = p.content.error_code ? p.content.error_code : "UNKNOWN";
+ cfyMessage = p.content.message ? p.content.message : "unknown Cloudify API error";
+ cfyCode = p.content.error_code ? p.content.error_code : "UNKNOWN";
}
else {
// if there's a body and we can't parse it just attach it as the message
- e.message = err.body;
+ cfyMessage = err.body;
}
+ message = "Status " + status + " from CM API -- error code: " + cfyCode + " -- message: " + cfyMessage;
}
+
+ /* Pass through 400-level status, recast 500-level */
+ var returnStatus = (err.status > 499) ? 502 : err.status;
+ e = createError(message, returnStatus, "api", 502, 'cloudify-manager');
}
return e;
@@ -129,26 +132,43 @@ var delay = function(dtime) {
});
};
-// Go through the Cloudify API call sequence to do a deployment
-exports.deployBlueprint = function(id, blueprint, inputs) {
-
+// Go through the Cloudify API call sequence to upload blueprint, create deployment, and launch install workflow
+// (but don't wait for the workflow to finish)
+const launchBlueprint = function(id, blueprint, inputs) {
logger.debug("deploymentId: " + id + " starting blueprint upload");
// Upload blueprint
return cfy.uploadBlueprint(id, blueprint)
+
+ // Create deployment
.then (function(result) {
logger.debug("deploymentId: " + id + " blueprint uploaded");
// Create deployment
return cfy.createDeployment(id, id, inputs);
})
+
+ // Launch the workflow, but don't wait for it to complete
.then(function(result){
logger.debug("deploymentId: " + id + " deployment created");
- // Execute the install workflow
- return delay(DELAY_INSTALL_WORKFLOW).then(function(){ return cfy.executeWorkflow(id, 'install');});
+ return delay(DELAY_INSTALL_WORKFLOW)
+ .then(function(){
+ return cfy.initiateWorkflowExecution(id, 'install');
+ });
})
- .then(function(result) {
- logger.debug("deploymentId: " + id + " install workflow successfully executed");
+ .catch(function(error) {
+ logger.debug("Error: " + error + " for launch blueprint for deploymentId " + id);
+ throw normalizeError(error);
+ })
+};
+exports.launchBlueprint = launchBlueprint;
+
+// Finish installation launched with launchBlueprint
+const finishInstallation = function(deploymentId, executionId) {
+ logger.debug("finishInstallation: " + deploymentId + " -- executionId: " + executionId);
+ return cfy.getWorkflowResult(executionId)
+ .then (function(result){
+ logger.debug("deploymentId: " + deploymentId + " install workflow successfully executed");
// Retrieve the outputs from the deployment, as specified in the blueprint
- return delay(DELAY_RETRIEVE_OUTPUTS).then(function() { return cfy.getOutputs(id); });
+ return delay(DELAY_RETRIEVE_OUTPUTS).then(function() { return cfy.getOutputs(deploymentId); });
})
.then(function(result) {
// We have the raw outputs from the deployment but not annotated with the descriptions
@@ -161,35 +181,125 @@ exports.deployBlueprint = function(id, blueprint, inputs) {
}
}
}
- logger.debug("output retrieval result for " + id + ": " + JSON.stringify(result));
- logger.info("deploymentId " + id + " successfully deployed");
- return annotateOutputs(id, rawOutputs);
+ logger.debug("output retrieval result for " + deploymentId + ": " + JSON.stringify(result));
+ logger.info("deploymentId " + deploymentId + " successfully deployed");
+ return annotateOutputs(deploymentId, rawOutputs);
})
.catch(function(err) {
+ logger.debug("Error finishing install workflow: " + err + " -- " + JSON.stringify(err));
throw normalizeError(err);
});
-};
+}
+exports.finishInstallation = finishInstallation;
-// Go through the Cloudify API call sequence to do an undeployment of a previously deployed blueprint
-exports.undeployDeployment = function(id) {
- logger.debug("deploymentId: " + id + " starting uninstall workflow");
+// Initiate uninstall workflow against a deployment, but don't wait for workflow to finish
+const launchUninstall = function(deploymentId) {
+ logger.debug("deploymentId: " + deploymentId + " starting uninstall workflow");
// Run uninstall workflow
- return cfy.executeWorkflow(id, 'uninstall', 0)
+ return cfy.initiateWorkflowExecution(deploymentId, 'uninstall')
+ .then(function(result) {
+ return result;
+ })
+ .catch(function(err) {
+ logger.debug("Error initiating uninstall workflow: " + err + " -- " + JSON.stringify(err));
+ throw normalizeError(err);
+ });
+};
+exports.launchUninstall = launchUninstall;
+
+const finishUninstall = function(deploymentId, executionId) {
+ logger.debug("finishUninstall: " + deploymentId + " -- executionId: " + executionId);
+ return cfy.getWorkflowResult(executionId)
.then (function(result){
- logger.debug("deploymentId: " + id + " uninstall workflow completed");
+ logger.debug("deploymentId: " + deploymentId + " uninstall workflow successfully executed");
// Delete the deployment
- return delay(DELAY_DELETE_DEPLOYMENT).then(function() {return cfy.deleteDeployment(id);});
+ return delay(DELAY_DELETE_DEPLOYMENT).then(function() {return cfy.deleteDeployment(deploymentId);});
})
.then (function(result){
- logger.debug("deploymentId: " + id + " deployment deleted");
+ logger.debug("deploymentId: " + deploymentId + " deployment deleted");
// Delete the blueprint
- return delay(DELAY_DELETE_BLUEPRINT).then(function() {return cfy.deleteBlueprint(id);});
+ return delay(DELAY_DELETE_BLUEPRINT).then(function() {return cfy.deleteBlueprint(deploymentId);});
})
.then (function(result){
- logger.info("deploymentId: " + id + " successfully undeployed");
+ logger.info("deploymentId: " + deploymentId + " successfully undeployed");
return result;
})
.catch (function(err){
throw normalizeError(err);
});
+
};
+exports.finishUninstall = finishUninstall;
+
+// Get the status of a workflow execution
+exports.getExecutionStatus = function (exid) {
+ return cfy.getWorkflowExecutionStatus(exid)
+ .then(function(res){
+
+ var result = {
+ operationType: res.json.workflow_id
+ }
+
+ // Map execution status
+ if (res.json.status === "terminated") {
+ result.status = "succeeded";
+ }
+ else if (res.json.status === "failed") {
+ result.status = "failed";
+ }
+ else if (res.json.status === "cancelled" || res.stats === "canceled") {
+ result.status = "canceled";
+ }
+ else {
+ result.status = "processing";
+ }
+
+ if (res.json.error) {
+ result.error = res.json.error;
+ }
+ logger.debug("getExecutionStatus result: " + JSON.stringify(result));
+ return result;
+ })
+ .catch(function(error) {
+ throw normalizeError(error);
+ });
+};
+
+// Go through the Cloudify API call sequence to do a deployment
+exports.deployBlueprint = function(id, blueprint, inputs) {
+
+ // Upload blueprint, create deployment, and initiate install workflow
+ return launchBlueprint(id, blueprint, inputs)
+
+ // Wait for the workflow to complete
+ .then(
+
+ // launchBlueprint promise fulfilled -- finish installation
+ function(result){
+ return finishInstallation(result.deploymentId, result.executionId); // Will throw normalized error if it fails
+ },
+
+ // launchBlueprint promise rejected -- report error
+ function(err) {
+ throw normalizeError(err);
+ });
+};
+
+// Go through the Cloudify API call sequence to do an undeployment of a previously deployed blueprint
+exports.undeployDeployment = function(id) {
+ logger.debug("deploymentId: " + id + " starting uninstall workflow");
+
+ // Run launch uninstall workflow
+ return launchUninstall(id)
+
+ // launchUninstall promise fulfilled -- finish uninstall
+ .then (function(result){
+ return finishUninstall(result.deploymentId, result.executionId); // Will throw normalized error if it fails
+ },
+
+ // launchUninstall promise rejected -- report error
+ function(err){
+ throw normalizeError(err);
+ });
+};
+