Add support to run an ansible playbook
- Add an API to upload a playbook - Add an API to run an ansible playbook on a rackHD node - fix new eslint errors - Add unit tests Change-Id: Ibe623c228c6ac13cab0f2726e267878bec1bdb6e Implements: blueprint shovel-deployment-capability
This commit is contained in:
parent
9449f7a443
commit
50ec0f2000
@ -589,6 +589,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/run/ansible-playbook/{identifier}": {
|
||||||
|
"post": {
|
||||||
|
"x-swagger-router-controller": "Shovel",
|
||||||
|
"tags": [ "Nodes Provisionning" ],
|
||||||
|
"operationId": "runAnsible",
|
||||||
|
"summary": "run the uploaded ansible playbook",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "identifier",
|
||||||
|
"in": "path",
|
||||||
|
"description": "rackHD node ID",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Config",
|
||||||
|
"in": "body",
|
||||||
|
"description": "OS Configuration",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/run-ansible"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Not Implemented"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "unexpected error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@ -753,7 +787,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example":"Graph.InstallCentOS"
|
"example": "Graph.InstallCentOS"
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -823,6 +857,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"run-ansible": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "runExample"
|
||||||
|
},
|
||||||
|
"vars": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"playbookPath": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "files/extract/main.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,20 +278,20 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
userEntry = req.body;
|
userEntry = req.body;
|
||||||
if (userEntry.driver === 'pxe_ipmitool') {
|
if (userEntry.driver === 'pxe_ipmitool') {
|
||||||
info = {
|
info = {
|
||||||
'ipmi_address': userEntry.ipmihost,
|
ipmi_address: userEntry.ipmihost,
|
||||||
'ipmi_username': userEntry.ipmiuser,
|
ipmi_username: userEntry.ipmiuser,
|
||||||
'ipmi_password': userEntry.ipmipass,
|
ipmi_password: userEntry.ipmipass,
|
||||||
'deploy_kernel': userEntry.kernel,
|
deploy_kernel: userEntry.kernel,
|
||||||
'deploy_ramdisk': userEntry.ramdisk
|
deploy_ramdisk: userEntry.ramdisk
|
||||||
};
|
};
|
||||||
} else if (userEntry.driver === 'pxe_ssh') {
|
} else if (userEntry.driver === 'pxe_ssh') {
|
||||||
info = {
|
info = {
|
||||||
'ssh_address': userEntry.sshhost,
|
ssh_address: userEntry.sshhost,
|
||||||
'ssh_username': userEntry.sshuser,
|
ssh_username: userEntry.sshuser,
|
||||||
'ssh_password': userEntry.sshpass,
|
ssh_password: userEntry.sshpass,
|
||||||
'ssh_port': userEntry.sshport,
|
ssh_port: userEntry.sshport,
|
||||||
'deploy_kernel': userEntry.kernel,
|
deploy_kernel: userEntry.kernel,
|
||||||
'deploy_ramdisk': userEntry.ramdisk
|
deploy_ramdisk: userEntry.ramdisk
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
info = {};
|
info = {};
|
||||||
@ -299,11 +299,11 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
|
|
||||||
/* Fill in the extra meta data with some failover and event data */
|
/* Fill in the extra meta data with some failover and event data */
|
||||||
extra = {
|
extra = {
|
||||||
'nodeid': userEntry.uuid,
|
nodeid: userEntry.uuid,
|
||||||
'name': userEntry.name,
|
name: userEntry.name,
|
||||||
'lsevents': { 'time': 0 },
|
lsevents: { time: 0 },
|
||||||
'eventcnt': 0,
|
eventcnt: 0,
|
||||||
'timer': {}
|
timer: {}
|
||||||
};
|
};
|
||||||
if (typeof userEntry.failovernode !== 'undefined') {
|
if (typeof userEntry.failovernode !== 'undefined') {
|
||||||
extra.failover = userEntry.failovernode;
|
extra.failover = userEntry.failovernode;
|
||||||
@ -315,7 +315,7 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
localGb = 0.0;
|
localGb = 0.0;
|
||||||
return monorail.request_node_get(userEntry.uuid).
|
return monorail.request_node_get(userEntry.uuid).
|
||||||
then(function (result) {
|
then(function (result) {
|
||||||
if (!JSON.parse(result).name) {
|
if (!JSON.parse(result).hasOwnProperty('name')) {
|
||||||
var error = { error_message: { message: 'failed to find required node in RackHD' } };
|
var error = { error_message: { message: 'failed to find required node in RackHD' } };
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
@ -349,16 +349,16 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
propreties = {
|
propreties = {
|
||||||
'cpus': dmiData.cpus,
|
cpus: dmiData.cpus,
|
||||||
'memory_mb': dmiData.memory,
|
memory_mb: dmiData.memory,
|
||||||
'local_gb': localGb
|
local_gb: localGb
|
||||||
};
|
};
|
||||||
node = {
|
node = {
|
||||||
'name': userEntry.uuid,
|
name: userEntry.uuid,
|
||||||
'driver': userEntry.driver,
|
driver: userEntry.driver,
|
||||||
'driver_info': info,
|
driver_info: info,
|
||||||
'properties': propreties,
|
properties: propreties,
|
||||||
'extra': extra
|
extra: extra
|
||||||
};
|
};
|
||||||
return keystone.authenticatePassword(ironicConfig.os_tenant_name, ironicConfig.os_username,
|
return keystone.authenticatePassword(ironicConfig.os_tenant_name, ironicConfig.os_username,
|
||||||
ironicConfig.os_password);
|
ironicConfig.os_password);
|
||||||
@ -373,10 +373,13 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
throw JSON.parse(ret);
|
throw JSON.parse(ret);
|
||||||
}
|
}
|
||||||
ironicNode = JSON.parse(ret);
|
ironicNode = JSON.parse(ret);
|
||||||
port = { 'address': userEntry.port, 'node_uuid': ironicNode.uuid };
|
port = { address: userEntry.port, node_uuid: ironicNode.uuid };
|
||||||
return ironic.createPort(ironicToken, JSON.stringify(port));
|
return ironic.create_port(ironicToken, JSON.stringify(port));
|
||||||
}).
|
}).
|
||||||
then(function (createPort) {
|
then(function (createPort) {
|
||||||
|
if (createPort && JSON.parse(createPort).error_message) {
|
||||||
|
throw JSON.parse(createPort);
|
||||||
|
}
|
||||||
logger.info('\r\nCreate port:\r\n' + JSON.stringify(createPort));
|
logger.info('\r\nCreate port:\r\n' + JSON.stringify(createPort));
|
||||||
return ironic.set_power_state(ironicToken, ironicNode.uuid, 'on');
|
return ironic.set_power_state(ironicToken, ironicNode.uuid, 'on');
|
||||||
}).
|
}).
|
||||||
@ -392,7 +395,7 @@ module.exports.registerpost = function registerpost(req, res) {
|
|||||||
timer.stop = false;
|
timer.stop = false;
|
||||||
timer.timeInterval = 15000;
|
timer.timeInterval = 15000;
|
||||||
timer.isDone = true;
|
timer.isDone = true;
|
||||||
var data = [{ 'path': '/extra/timer', 'value': timer, 'op': 'replace' }];
|
var data = [{ path: '/extra/timer', value: timer, op: 'replace' }];
|
||||||
return ironic.patch_node(ironicToken, ironicNode.uuid, JSON.stringify(data));
|
return ironic.patch_node(ironicToken, ironicNode.uuid, JSON.stringify(data));
|
||||||
}).
|
}).
|
||||||
then(function (result) {
|
then(function (result) {
|
||||||
@ -637,8 +640,8 @@ module.exports.deployOS = function deployOS(req, res) {
|
|||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
return monorail.runWorkFlow(req.swagger.params.identifier.value,
|
return monorail.runWorkFlow(req.swagger.params.identifier.value,
|
||||||
req.body.name,req.body)
|
req.body.name,req.body)
|
||||||
.then(function(data) {
|
.then(function(result) {
|
||||||
res.end(data);
|
res.end(result);
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
res.end(JSON.stringify(err));
|
res.end(JSON.stringify(err));
|
||||||
@ -654,12 +657,79 @@ module.exports.workflowStatus = function workflowStatus(req,res) {
|
|||||||
return monorail.getWorkFlowActive(req.swagger.params.identifier.value)
|
return monorail.getWorkFlowActive(req.swagger.params.identifier.value)
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
res.end(JSON.stringify({'jobStatus':'Running'}));
|
res.end(JSON.stringify({jobStatus:'Running'}));
|
||||||
} else {
|
} else {
|
||||||
res.end(JSON.stringify({'jobStatus':'Currently there is no job running on this node'}));
|
res.end(JSON.stringify({jobStatus:'Currently there is no job running on this node'}));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
res.end(JSON.stringify(err));
|
res.end(JSON.stringify(err));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
|
* @api {put} /api/1.1/uploadFiles/filename / PUT /
|
||||||
|
* @apiDescription uploaded ansible playbook in tar form and extract it
|
||||||
|
*/
|
||||||
|
//Code for tar file uploads
|
||||||
|
// module.exports.uploadFiles = function uploadFiles(req, res) {
|
||||||
|
// 'use strict';
|
||||||
|
// res.setHeader('content-type', 'text/plain');
|
||||||
|
// var tar = require('tar');
|
||||||
|
// var extractor = tar.Extract({path: 'files/extract'})
|
||||||
|
// .on('error', function(err) {
|
||||||
|
// logger.error(err);
|
||||||
|
// res.status(500);
|
||||||
|
// res.end('error');
|
||||||
|
// })
|
||||||
|
// .on('end', function() {
|
||||||
|
// res.status(202);
|
||||||
|
// res.end('success');
|
||||||
|
// });
|
||||||
|
// var stream = require('stream');
|
||||||
|
// var bufferStream = new stream.PassThrough();
|
||||||
|
// bufferStream.end(new Buffer(req.swagger.params.playbook.value.buffer));
|
||||||
|
// bufferStream.pipe(extractor);
|
||||||
|
// };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @api {post} /api/1.1/runAnsible/{identifier} / POST /
|
||||||
|
* @apiDescription run uploaded ansible playbook in tar form and extract it
|
||||||
|
*/
|
||||||
|
module.exports.runAnsible = function runAnsible(req, res) {
|
||||||
|
'use strict';
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
var ansibleTask = {
|
||||||
|
friendlyName: req.body.name,
|
||||||
|
injectableName: 'Task.Ansible.' + req.body.name,
|
||||||
|
implementsTask: 'Task.Base.Ansible',
|
||||||
|
options: {
|
||||||
|
playbook: req.body.playbookPath,
|
||||||
|
vars : req.body.vars
|
||||||
|
},
|
||||||
|
properties: { }
|
||||||
|
};
|
||||||
|
var ansibleWorkflow = {
|
||||||
|
friendlyName: 'Graph ' + req.body.name,
|
||||||
|
injectableName: 'Graph.Ansible.' + req.body.name,
|
||||||
|
tasks : [
|
||||||
|
{
|
||||||
|
label: 'ansible-job',
|
||||||
|
taskName: 'Task.Ansible.' + req.body.name
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return monorail.createTask(ansibleTask)
|
||||||
|
.then(function() {
|
||||||
|
return monorail.createWorkflow(ansibleWorkflow);
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return monorail.runWorkFlow(req.swagger.params.identifier.value,
|
||||||
|
'Graph.Ansible.' + req.body.name,null);
|
||||||
|
})
|
||||||
|
.then(function(result) {
|
||||||
|
res.end(result);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
res.end(JSON.stringify(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
2
index.js
2
index.js
@ -1,7 +1,7 @@
|
|||||||
/* global process */
|
/* global process */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var app = require('connect')();
|
var app = require('express')();
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var swaggerTools = require('swagger-tools');
|
var swaggerTools = require('swagger-tools');
|
||||||
var config = require('./config.json');
|
var config = require('./config.json');
|
||||||
|
@ -50,7 +50,7 @@ var HttpClient = {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
'Accept': 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Length': Buffer.byteLength(msg.data),
|
'Content-Length': Buffer.byteLength(msg.data),
|
||||||
'User-Agent': 'shovel-client'
|
'User-Agent': 'shovel-client'
|
||||||
}
|
}
|
||||||
@ -140,16 +140,16 @@ var HttpClient = {
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
'Accept': 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Length': Buffer.byteLength(msg.data),
|
'Content-Length': Buffer.byteLength(msg.data),
|
||||||
'User-Agent': 'shovel-client'
|
'User-Agent': 'shovel-client'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*Update the request header with special fields*/
|
||||||
if (Buffer.byteLength(msg.token)) {
|
if (Buffer.byteLength(msg.token)) {
|
||||||
options.headers['X-Auth-Token'] = msg.token;
|
options.headers['X-Auth-Token'] = msg.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Buffer.byteLength(JSON.stringify(msg.api))) {
|
if (Buffer.byteLength(JSON.stringify(msg.api))) {
|
||||||
options.headers[msg.api.name] = msg.api.version;
|
options.headers[msg.api.name] = msg.api.version;
|
||||||
}
|
}
|
||||||
@ -159,8 +159,8 @@ var HttpClient = {
|
|||||||
response.on('data', function (chunk) {
|
response.on('data', function (chunk) {
|
||||||
body += chunk;
|
body += chunk;
|
||||||
});
|
});
|
||||||
response.on('error', function (err) {
|
response.on('error', function (e) {
|
||||||
var errorMessage = { errorMessage: { hostname: msg.host, message: err } };
|
var errorMessage = { errorMessage: { hostname: msg.host, message: e } };
|
||||||
output(errorMessage);
|
output(errorMessage);
|
||||||
});
|
});
|
||||||
response.on('end', function () {
|
response.on('end', function () {
|
||||||
@ -174,7 +174,9 @@ var HttpClient = {
|
|||||||
output(errorMessage);
|
output(errorMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Buffer.byteLength(msg.data)) {
|
||||||
request.write(msg.data);
|
request.write(msg.data);
|
||||||
|
}
|
||||||
request.end();
|
request.end();
|
||||||
},
|
},
|
||||||
Patch: function (msg, output) {
|
Patch: function (msg, output) {
|
||||||
@ -187,7 +189,7 @@ var HttpClient = {
|
|||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
'Accept': 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Length': Buffer.byteLength(msg.data),
|
'Content-Length': Buffer.byteLength(msg.data),
|
||||||
'User-Agent': 'shovel-client'
|
'User-Agent': 'shovel-client'
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,9 @@ var MonorailWrapper = {
|
|||||||
runWorkFlow: function runWorkFlow(hwaddr,graphName,content) {
|
runWorkFlow: function runWorkFlow(hwaddr,graphName,content) {
|
||||||
'use strict';
|
'use strict';
|
||||||
request.path = pfx + '/nodes/' + hwaddr + '/workflows/?name=' + graphName;
|
request.path = pfx + '/nodes/' + hwaddr + '/workflows/?name=' + graphName;
|
||||||
|
if (content !== null) {
|
||||||
request.data = JSON.stringify(content);
|
request.data = JSON.stringify(content);
|
||||||
|
}
|
||||||
return client.PostAsync(request);
|
return client.PostAsync(request);
|
||||||
},
|
},
|
||||||
getWorkFlowActive: function getWorkFlowActive(hwaddr) {
|
getWorkFlowActive: function getWorkFlowActive(hwaddr) {
|
||||||
@ -161,6 +163,18 @@ var MonorailWrapper = {
|
|||||||
'use strict';
|
'use strict';
|
||||||
request.path = pfx + '/nodes/' + hwaddr + '/workflows/active';
|
request.path = pfx + '/nodes/' + hwaddr + '/workflows/active';
|
||||||
return client.DeleteAsync(request);
|
return client.DeleteAsync(request);
|
||||||
|
},
|
||||||
|
createTask: function createTask(content) {
|
||||||
|
'use strict';
|
||||||
|
request.path = pfx + '/workflows/tasks/';
|
||||||
|
request.data = JSON.stringify(content);
|
||||||
|
return client.PutAsync(request);
|
||||||
|
},
|
||||||
|
createWorkflow: function createWorkflow(content) {
|
||||||
|
'use strict';
|
||||||
|
request.path = pfx + '/workflows';
|
||||||
|
request.data = JSON.stringify(content);
|
||||||
|
return client.PutAsync(request);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
module.exports = Object.create(MonorailWrapper);
|
module.exports = Object.create(MonorailWrapper);
|
||||||
|
@ -13,8 +13,8 @@ var request = {
|
|||||||
token: '',
|
token: '',
|
||||||
data: '',
|
data: '',
|
||||||
api: {
|
api: {
|
||||||
'name': 'X-OpenStack-Ironic-API-Version',
|
name: 'X-OpenStack-Ironic-API-Version',
|
||||||
'version': '1.6'
|
version: '1.6'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ var KeystoneAuthentication = {
|
|||||||
}
|
}
|
||||||
request.data = JSON.stringify(
|
request.data = JSON.stringify(
|
||||||
{
|
{
|
||||||
'auth': {
|
auth: {
|
||||||
'tenantName': tenantName,
|
tenantName: tenantName,
|
||||||
'passwordCredentials': {
|
passwordCredentials: {
|
||||||
'username': username,
|
username: username,
|
||||||
'password': decrypted
|
password: decrypted
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,10 +49,10 @@ var KeystoneAuthentication = {
|
|||||||
'use strict';
|
'use strict';
|
||||||
request.data = JSON.stringify(
|
request.data = JSON.stringify(
|
||||||
{
|
{
|
||||||
'auth': {
|
auth: {
|
||||||
'tenantName': tenantName,
|
tenantName: tenantName,
|
||||||
'token': {
|
token: {
|
||||||
'id': token
|
id: token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -135,9 +135,9 @@ function Poller(timeInterval) {
|
|||||||
nodeData.extra.events = lastEvent;
|
nodeData.extra.events = lastEvent;
|
||||||
var data = [
|
var data = [
|
||||||
{
|
{
|
||||||
'path': '/extra',
|
path: '/extra',
|
||||||
'value': nodeData.extra,
|
value: nodeData.extra,
|
||||||
'op': 'replace'
|
op: 'replace'
|
||||||
}];
|
}];
|
||||||
return data;
|
return data;
|
||||||
})
|
})
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "3.1.1",
|
"bluebird": "3.1.1",
|
||||||
"connect": "^3.2.0",
|
|
||||||
"swagger-tools": "0.8.*",
|
"swagger-tools": "0.8.*",
|
||||||
"should": "~7.0.1",
|
"should": "~7.0.1",
|
||||||
"mocha": "^2.1.0",
|
"mocha": "^2.1.0",
|
||||||
@ -23,7 +22,9 @@
|
|||||||
"istanbul": "0.4.1",
|
"istanbul": "0.4.1",
|
||||||
"nock": "3.6.0",
|
"nock": "3.6.0",
|
||||||
"eslint-config-openstack": "~1.2.3",
|
"eslint-config-openstack": "~1.2.3",
|
||||||
"eslint": "~1.10.3"
|
"eslint": "~1.10.3",
|
||||||
|
"express": "~4.13.4",
|
||||||
|
"tar": "~2.2.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "start shovel",
|
"start": "start shovel",
|
||||||
|
@ -185,5 +185,19 @@ describe('****Monorail Lib****',function(){
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('monorail.createWorkflow return data from monorail', function (done) {
|
||||||
|
return monorail.createWorkflow({})
|
||||||
|
.then(function (result) {
|
||||||
|
result.should.have.property('data');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('monorail.createTask return data from monorail', function (done) {
|
||||||
|
return monorail.createTask({})
|
||||||
|
.then(function (result) {
|
||||||
|
result.should.have.property('data');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -56,6 +56,8 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
sinon.stub(monorail, 'get_catalog_data_by_source').returns(Promise.resolve(JSON.stringify(catalogSource[0])));
|
sinon.stub(monorail, 'get_catalog_data_by_source').returns(Promise.resolve(JSON.stringify(catalogSource[0])));
|
||||||
sinon.stub(monorail, 'runWorkFlow').returns(Promise.resolve('{"definition":{}}'));
|
sinon.stub(monorail, 'runWorkFlow').returns(Promise.resolve('{"definition":{}}'));
|
||||||
getWorkflow = sinon.stub(monorail,'getWorkFlowActive');
|
getWorkflow = sinon.stub(monorail,'getWorkFlowActive');
|
||||||
|
sinon.stub(monorail, 'createTask').returns(Promise.resolve());
|
||||||
|
sinon.stub(monorail, 'createWorkflow').returns(Promise.resolve());
|
||||||
//glance
|
//glance
|
||||||
sinon.stub(glance, 'get_images').returns(Promise.resolve(JSON.stringify(glanceImages)));
|
sinon.stub(glance, 'get_images').returns(Promise.resolve(JSON.stringify(glanceImages)));
|
||||||
//keystone
|
//keystone
|
||||||
@ -83,6 +85,8 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
monorail['get_catalog_data_by_source'].restore();
|
monorail['get_catalog_data_by_source'].restore();
|
||||||
monorail['runWorkFlow'].restore();
|
monorail['runWorkFlow'].restore();
|
||||||
monorail['getWorkFlowActive'].restore();
|
monorail['getWorkFlowActive'].restore();
|
||||||
|
monorail['createTask'].restore();
|
||||||
|
monorail['createWorkflow'].restore();
|
||||||
//ironic
|
//ironic
|
||||||
ironic['patch_node'].restore();
|
ironic['patch_node'].restore();
|
||||||
ironic['get_node_list'].restore();
|
ironic['get_node_list'].restore();
|
||||||
@ -334,10 +338,8 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
.send({"name": "Graph.InstallCentOS","options": { "defaults": {"obmServiceName": "ipmi-obm-service"}}})
|
.send({"name": "Graph.InstallCentOS","options": { "defaults": {"obmServiceName": "ipmi-obm-service"}}})
|
||||||
.end(function (err, res) {
|
.end(function (err, res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('hey yo');
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
console.log('hello' + res.text)
|
|
||||||
JSON.parse(res.text).should.have.property('definition');
|
JSON.parse(res.text).should.have.property('definition');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -350,11 +352,22 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
console.log(res.text);
|
|
||||||
JSON.parse(res.text).should.have.property('jobStatus');
|
JSON.parse(res.text).should.have.property('jobStatus');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('/api/1.1/run/ansible-playbook/{id} should return property definition', function (done) {
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/run/ansible-playbook/123')
|
||||||
|
.send({"name": "Graph.Example","options": {}})
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('definition');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it('/api/1.1/worflow-status/{identifier} should return property jobStatus even if no job is running', function (done) {
|
it('/api/1.1/worflow-status/{identifier} should return property jobStatus even if no job is running', function (done) {
|
||||||
getWorkflow.returns(Promise.resolve());
|
getWorkflow.returns(Promise.resolve());
|
||||||
request(url)
|
request(url)
|
||||||
@ -379,10 +392,12 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
var output = ({ error: 'error_message' });
|
var output = ({ error: 'error_message' });
|
||||||
sinon.stub(client, 'GetAsync').returns(Promise.reject(output));
|
sinon.stub(client, 'GetAsync').returns(Promise.reject(output));
|
||||||
sinon.stub(client, 'PostAsync').returns(Promise.reject(output));
|
sinon.stub(client, 'PostAsync').returns(Promise.reject(output));
|
||||||
|
sinon.stub(client, 'PutAsync').returns(Promise.reject(output));
|
||||||
});
|
});
|
||||||
after('teardown mocks', function () {
|
after('teardown mocks', function () {
|
||||||
client['GetAsync'].restore();
|
client['GetAsync'].restore();
|
||||||
client['PostAsync'].restore();
|
client['PostAsync'].restore();
|
||||||
|
client['PutAsync'].restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('/api/1.1/nodes/identifier should return error message', function (done) {
|
it('/api/1.1/nodes/identifier should return error message', function (done) {
|
||||||
@ -558,34 +573,92 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('api/1.1/run/ansible-playbook/{id} should return error message', function (done) {
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/run/ansible-playbook/123')
|
||||||
|
.send({name: 'runExample',vars: {},
|
||||||
|
playbookPath: 'main.yml'
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Shovel api unit test for register', function () {
|
describe('Shovel api unit test for register', function () {
|
||||||
var error_message = '{"error_message": "{\\"debuginfo\\": null, \\"faultcode\\": \\"Client\\", \\"faultstring\\": \\"A node with name 5668b42d8bee16a10989e4e4 already exists.\\"}"}';
|
var error_message = '{"error_message": "{\\"debuginfo\\": null, \\"faultcode\\": \\"Client\\", \\"faultstring\\": \\"some error\\"}"}';
|
||||||
var body = { "id": identifier, "driver": "string", "ipmihost": "string", "ipmiusername": "string", "ipmipasswd": "string" };
|
var body = { "id": identifier, "driver": "string", "ipmihost": "string", "ipmiusername": "string", "ipmipasswd": "string" };
|
||||||
|
var getNode, diskSize, memoryCpu, ironicNodeCreate,
|
||||||
|
ironicCreatePort, ironicPowerState, ironicPatch;
|
||||||
beforeEach('set up mocks', function () {
|
beforeEach('set up mocks', function () {
|
||||||
//monorail
|
//monorail
|
||||||
|
getNode = sinon.stub(monorail, 'request_node_get');
|
||||||
|
diskSize = sinon.stub(monorail, 'nodeDiskSize');
|
||||||
|
memoryCpu = sinon.stub(monorail, 'getNodeMemoryCpu');
|
||||||
|
monorailWhiteList = sinon.stub(monorail,'request_whitelist_set');
|
||||||
//keystone
|
//keystone
|
||||||
sinon.stub(keystone, 'authenticatePassword').returns(Promise.resolve(JSON.stringify(keyToken)));
|
sinon.stub(keystone, 'authenticatePassword').returns(Promise.resolve(JSON.stringify(keyToken)));
|
||||||
//ironic
|
//ironic
|
||||||
sinon.stub(ironic, 'create_node').returns(Promise.resolve(error_message));
|
ironicNodeCreate = sinon.stub(ironic, 'create_node');
|
||||||
|
ironicCreatePort = sinon.stub(ironic,'create_port');
|
||||||
|
ironicPowerState = sinon.stub(ironic,'set_power_state');
|
||||||
|
ironicPatch = sinon.stub(ironic, 'patch_node');
|
||||||
});
|
});
|
||||||
afterEach('teardown mocks', function () {
|
afterEach('teardown mocks', function () {
|
||||||
//monorail
|
//monorail
|
||||||
monorail['nodeDiskSize'].restore();
|
monorail['nodeDiskSize'].restore();
|
||||||
monorail['getNodeMemoryCpu'].restore();
|
monorail['getNodeMemoryCpu'].restore();
|
||||||
monorail['request_node_get'].restore();
|
monorail['request_node_get'].restore();
|
||||||
|
monorail['request_whitelist_set'].restore();
|
||||||
//keystone
|
//keystone
|
||||||
keystone['authenticatePassword'].restore();
|
keystone['authenticatePassword'].restore();
|
||||||
//ironic
|
//ironic
|
||||||
ironic['create_node'].restore();
|
ironic['create_node'].restore();
|
||||||
|
ironic['create_port'].restore();
|
||||||
|
ironic['set_power_state'].restore();
|
||||||
|
ironic['patch_node'].restore();
|
||||||
|
});
|
||||||
|
it('response in register should have property error_message when node returns empty ', function (done) {
|
||||||
|
getNode.returns(Promise.resolve('{}'));
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error_message');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('response in register should have property error_message when diskSize has an exception ', function (done) {
|
||||||
|
var output = {error_message: { message: 'failed to get compute node Disk Size' }};
|
||||||
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
|
diskSize.returns(Promise.reject(output));
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error_message');
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('response in register should have property error_message when any of node info equal to 0 ', function (done) {
|
it('response in register should have property error_message when any of node info equal to 0 ', function (done) {
|
||||||
sinon.stub(monorail, 'request_node_get').returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
sinon.stub(monorail, 'nodeDiskSize').returns(Promise.resolve(0));
|
diskSize.returns(Promise.resolve(0));
|
||||||
sinon.stub(monorail, 'getNodeMemoryCpu').returns(Promise.resolve({ cpus: 0, memory: 0 }));
|
memoryCpu.returns(Promise.resolve({ cpus: 0, memory: 0 }));
|
||||||
|
|
||||||
request(url)
|
request(url)
|
||||||
.post('/api/1.1/register')
|
.post('/api/1.1/register')
|
||||||
@ -601,10 +674,10 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('response in register should have property error_message create node return error in ironic', function (done) {
|
it('response in register should have property error_message create node return error in ironic', function (done) {
|
||||||
sinon.stub(monorail, 'request_node_get').returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
sinon.stub(monorail, 'nodeDiskSize').returns(Promise.resolve(1));
|
diskSize.returns(Promise.resolve(1));
|
||||||
sinon.stub(monorail, 'getNodeMemoryCpu').returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
memoryCpu.returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
||||||
|
ironicNodeCreate.returns(Promise.resolve(error_message));
|
||||||
request(url)
|
request(url)
|
||||||
.post('/api/1.1/register')
|
.post('/api/1.1/register')
|
||||||
.send(body)
|
.send(body)
|
||||||
@ -618,5 +691,86 @@ describe('****SHOVEL API Interface****', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('response in register should have property error_message create port return error in ironic', function (done) {
|
||||||
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
|
diskSize.returns(Promise.resolve(1));
|
||||||
|
memoryCpu.returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
||||||
|
ironicNodeCreate.returns(Promise.resolve(JSON.stringify(ironic_node_list[0])));
|
||||||
|
ironicCreatePort.returns(Promise.resolve(error_message));
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error_message');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('response in register should have property error_message set power state return error in ironic', function (done) {
|
||||||
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
|
diskSize.returns(Promise.resolve(1));
|
||||||
|
memoryCpu.returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
||||||
|
ironicNodeCreate.returns(Promise.resolve(JSON.stringify(ironic_node_list[0])));
|
||||||
|
ironicCreatePort.returns(Promise.resolve());
|
||||||
|
ironicPowerState.returns(Promise.resolve(error_message));
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error_message');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('response in register should have property error_message ironic patch node return error in ironic', function (done) {
|
||||||
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
|
diskSize.returns(Promise.resolve(1));
|
||||||
|
memoryCpu.returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
||||||
|
ironicNodeCreate.returns(Promise.resolve(JSON.stringify(ironic_node_list[0])));
|
||||||
|
ironicCreatePort.returns(Promise.resolve());
|
||||||
|
ironicPowerState.returns(Promise.resolve());
|
||||||
|
ironicPatch.returns(Promise.reject({error_message:'some error'}));
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('error_message');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('response in register should have property result on success', function (done) {
|
||||||
|
getNode.returns(Promise.resolve(JSON.stringify(rackhdNode[0])));
|
||||||
|
diskSize.returns(Promise.resolve(1));
|
||||||
|
memoryCpu.returns(Promise.resolve({ cpus: 1, memory: 1 }));
|
||||||
|
ironicNodeCreate.returns(Promise.resolve(JSON.stringify(ironic_node_list[0])));
|
||||||
|
ironicCreatePort.returns(Promise.resolve());
|
||||||
|
ironicPowerState.returns(Promise.resolve());
|
||||||
|
ironicPatch.returns(Promise.resolve());
|
||||||
|
request(url)
|
||||||
|
.post('/api/1.1/register')
|
||||||
|
.send(body)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
JSON.parse(res.text).should.have.property('result');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright 2015, EMC, Inc.
|
// Copyright 2015, EMC, Inc.
|
||||||
|
|
||||||
var app = require('connect')();
|
var app = require('express')();
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var swaggerTools = require('swagger-tools');
|
var swaggerTools = require('swagger-tools');
|
||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
|
Loading…
Reference in New Issue
Block a user