aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShadi Haidar <sh1986@att.com>2018-09-07 22:05:43 -0400
committerShadi Haidar <sh1986@att.com>2018-09-12 13:58:04 -0400
commitceda84d021dde70299f96984ca7aec16740854be (patch)
tree967b1c37a9e21721240d68e9b81dc59a0a593512
parent8ca8ddf40decb543e5ea634e29efe6972272a2f6 (diff)
Check deployment creation before install
Unit Test Code Coverage: Statements : 76.85% ( 893/1162 ) Branches : 52.99% ( 275/519 ) Functions : 78.68% ( 155/197 ) Lines : 77.21% ( 884/1145 ) Issue-ID: DCAEGEN2-754 Change-Id: Id8f3fa26e8ece7e9099145ea20034829a1ad7d13 Signed-off-by: Shadi Haidar <sh1986@att.com>
-rw-r--r--lib/cloudify.js97
-rw-r--r--lib/deploy.js28
-rw-r--r--package.json2
-rw-r--r--pom.xml2
-rw-r--r--tests/test_dcae-deployments.js23
-rw-r--r--version.properties2
6 files changed, 137 insertions, 17 deletions
diff --git a/lib/cloudify.js b/lib/cloudify.js
index 053bdb8..5ab0663 100644
--- a/lib/cloudify.js
+++ b/lib/cloudify.js
@@ -20,8 +20,11 @@ See the License for the specific language governing permissions and limitations
const CLOUDIFY = "cloudify-manager";
const FINISHED = [ "terminated", "cancelled", "failed" ];
+const DEPLOYMENT_CREATION_FINISHED = [ "terminated" ];
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
+const DEP_CREATION_STATUS_MAX_TRIES = 10; // Up to 5 minutes
const DEFAULT_TENANT = "default_tenant";
const doRequest = require('./promise_request').doRequest;
const repeat = require('./repeat');
@@ -79,6 +82,17 @@ const getExecutionStatus = function(req, execution_id) {
return doRequest(req, reqOptions, null, CLOUDIFY);
};
+// Get current status of a deployment creation
+const getDeploymentCreationStatus = function(req, deployment_id) {
+ var reqOptions = {
+ method : "GET",
+ uri : cfyAPI + "/executions?deployment_id=" + deployment_id + "&workflow_id=create_deployment_environment&_include=id,status"
+ };
+ addAuthToOptions(reqOptions, req);
+
+ return doRequest(req, reqOptions, null, CLOUDIFY);
+};
+
// Poll for the result of a workflow execution until it's done
const getWorkflowResult = function(mainReq, execution_id) {
/* Defense: Some callers do not supply mainReq */
@@ -194,6 +208,83 @@ const initiateWorkflowExecution = function(req, deployment_id, workflow_id, para
});
};
+// Poll for the deployment creation status
+const getDeploymentCreationResult = 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');
+ }
+
+ /* 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;
+
+ });
+};
+
// Uploads a blueprint via the Cloudify API
exports.uploadBlueprint = function(req, bpid, blueprint) {
logger.info(req.dcaeReqId, "uploadBlueprint " + bpid);
@@ -264,6 +355,11 @@ exports.executeWorkflow = function(req, deployment_id, workflow_id, parameters)
});
};
+// Return a promise for the final result of a deployment update
+exports.getDeploymentCreationResult = getDeploymentCreationResult;
+
+// Get the status of a deployment update
+exports.getDeploymentCreationStatus = getDeploymentCreationStatus;
// Retrieves outputs for a deployment
exports.getOutputs = function(req, dpid) {
@@ -469,3 +565,4 @@ exports.executeOperation = function (mainReq, deployment_id, operation, operatio
exeQueue.queueUpExecution(mainReq, deployment_id, workflow_id, parameters);
runQueuedExecution(mainReq, deployment_id, workflow_id, parameters);
};
+
diff --git a/lib/deploy.js b/lib/deploy.js
index ee31fd3..2d75b52 100644
--- a/lib/deploy.js
+++ b/lib/deploy.js
@@ -144,23 +144,23 @@ const launchBlueprint = function(req, id, blueprint, inputs) {
// Create deployment
.then (function(result) {
- logger.info(req.dcaeReqId, "deploymentId: " + id + " blueprint uploaded");
- // Create deployment
- return cfy.createDeployment(req, id, id, inputs);
+ logger.info(req.dcaeReqId, "deploymentId: " + id + " blueprint uploaded");
+ // Create deployment
+ return cfy.createDeployment(req, id, id, inputs);
})
- // Launch the workflow, but don't wait for it to complete
+ // create the deployment and keep checking, for up to 5 minutes, until creation is complete
.then(function(result){
- logger.info(req.dcaeReqId, "deploymentId: " + id + " deployment created");
- return delay(DELAY_INSTALL_WORKFLOW)
- .then(function(){
- return cfy.initiateWorkflowExecution(req, id, 'install');
- });
- })
- .catch(function(error) {
- logger.info(req.dcaeReqId, "Error: " + JSON.stringify(error) + " for launch blueprint for deploymentId " + id);
- throw normalizeError(error);
- });
+ return cfy.getDeploymentCreationResult(req, id);
+ })
+ .then(function(){
+ logger.info(req.dcaeReqId, "deploymentId: " + id + " deployment created");
+ return cfy.initiateWorkflowExecution(req, id, 'install');
+ })
+ .catch(function(error) {
+ logger.info(req.dcaeReqId, "Error: " + JSON.stringify(error) + " for launch blueprint/deployment creation for deploymentId " + id);
+ throw normalizeError(error);
+ });
};
exports.launchBlueprint = launchBlueprint;
diff --git a/package.json b/package.json
index 196c8e2..4611db6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "onap-dcae-deployment-handler",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "ONAP DCAE Deployment Handler",
"main": "deployment-handler.js",
"dependencies": {
diff --git a/pom.xml b/pom.xml
index 283843c..03ed413 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
<groupId>org.onap.dcaegen2.platform</groupId>
<artifactId>deployment-handler</artifactId>
<name>dcaegen2-platform-deployment-handler</name>
- <version>3.0.0-SNAPSHOT</version>
+ <version>3.0.1-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/tests/test_dcae-deployments.js b/tests/test_dcae-deployments.js
index a010017..ca64d94 100644
--- a/tests/test_dcae-deployments.js
+++ b/tests/test_dcae-deployments.js
@@ -174,6 +174,23 @@ const Cloudify = {
"blueprint_id": blueprint_id || deployment_id
};
},
+ resp_dep_creation: function(deployment_id) {
+ return {
+ "items": [
+ {
+ "status": "terminated",
+ "id": "ee6b0d21-0257-46a3-bb83-6f61f9ab5f99"
+ }
+ ],
+ "metadata": {
+ "pagination": {
+ "total": 1,
+ "offset": 0,
+ "size": 10000
+ }
+ }
+ };
+ },
resp_execution: function(deployment_id, blueprint_id, execution_id, terminated, workflow_id) {
return {
"status": (terminated && "terminated") || "pending",
@@ -406,6 +423,12 @@ function test_put_dcae_deployments_success(dh_server) {
return JSON.stringify(Cloudify.resp_deploy(DEPLOYMENT_ID_JFL_1, DEPLOYMENT_ID_JFL_1, message.inputs));
});
+ nock(dh.CLOUDIFY_URL).get("/api/v2.1/executions?deployment_id=" + DEPLOYMENT_ID_JFL_1 + "&workflow_id=create_deployment_environment&_include=id,status")
+ .reply(200, function(uri) {
+ console.log(action_timer.step, "get", dh.CLOUDIFY_URL, uri);
+ return JSON.stringify(Cloudify.resp_dep_creation(DEPLOYMENT_ID_JFL_1));
+ });
+
nock(dh.CLOUDIFY_URL).post("/api/v2.1/executions")
.reply(201, function(uri, requestBody) {
console.log(action_timer.step, "post", dh.CLOUDIFY_URL, uri, JSON.stringify(requestBody));
diff --git a/version.properties b/version.properties
index b67dd8a..77d3d8c 100644
--- a/version.properties
+++ b/version.properties
@@ -1,6 +1,6 @@
major=3
minor=0
-patch=0
+patch=1
base_version=${major}.${minor}.${patch}
release_version=${base_version}
snapshot_version=${base_version}-SNAPSHOT