on-http-y1
Version:
OnRack Http Server
1,295 lines (1,163 loc) • 57 kB
JavaScript
// Copyright 2015, EMC, Inc.
/* jshint node:true */
'use strict';
describe('Redfish Systems Root', function () {
var tv4;
var validator;
var redfish;
var waterline;
var Promise;
var taskProtocol;
var view;
var fs;
var nodeApi;
var Errors;
var racadm;
var wsman;
var configuration;
var mktemp = require('mktemp');
var xmlData = `<SystemConfiguration Model=" " ServiceTag=" " TimeStamp=" ">
<Component FQDD="BIOS.Setup.1-1">
<Attribute Name="OldSetupPassword">xxxx</Attribute>
<Attribute Name="NewSetupPassword">xxxx</Attribute>
<Attribute Name="PasswordStatus">Unlocked</Attribute>
</Component>
</SystemConfiguration>`;
// Skip reading the entry from Mongo and return the entry directly
function redirectGet(entry) {
if( entry !== 'error.2.0.json') {
entry = 'redfish-1.0/' + entry;
}
return fs.readFileAsync(__dirname + '/../../../../data/views/' + entry, 'utf-8')
.then(function(contents) {
return { contents: contents };
});
}
before('start HTTP server', function () {
this.timeout(10000);
return helper.startServer([]).then(function () {
view = helper.injector.get('Views');
sinon.stub(view, "get", redirectGet);
redfish = helper.injector.get('Http.Api.Services.Redfish');
sinon.spy(redfish, 'render');
sinon.spy(redfish, 'validateSchema');
validator = helper.injector.get('Http.Api.Services.Schema');
sinon.spy(validator, 'validate');
waterline = helper.injector.get('Services.Waterline');
sinon.stub(waterline.nodes);
sinon.stub(waterline.catalogs);
sinon.stub(waterline.workitems);
sinon.stub(waterline.obms);
Promise = helper.injector.get('Promise');
Errors = helper.injector.get('Errors');
taskProtocol = helper.injector.get('Protocol.Task');
sinon.stub(taskProtocol);
nodeApi = helper.injector.get('Http.Services.Api.Nodes');
sinon.stub(nodeApi, "setNodeWorkflowById");
sinon.stub(nodeApi, "getAllNodes");
racadm = helper.injector.get('JobUtils.RacadmTool');
sinon.stub(racadm, "runCommand");
wsman = helper.injector.get('Http.Services.Wsman');
sinon.stub(wsman, "getLog");
sinon.stub(wsman, "isDellSystem");
configuration = helper.injector.get('Services.Configuration');
var nodeFs = helper.injector.get('fs');
fs = Promise.promisifyAll(nodeFs);
sinon.stub(mktemp, 'createFile');
sinon.stub(fs, 'writeFile');
});
});
beforeEach('set up mocks', function () {
tv4 = require('tv4');
sinon.spy(tv4, "validate");
validator.validate.reset();
redfish.render.reset();
redfish.validateSchema.reset();
nodeApi.setNodeWorkflowById.reset();
racadm.runCommand.reset();
function resetStubs(obj) {
_(obj).methods().forEach(function (method) {
if (obj[method] && obj[method].reset) {
obj[method].reset();
}
}).value();
}
resetStubs(waterline.nodes);
resetStubs(waterline.catalogs);
resetStubs(waterline.workitems);
resetStubs(waterline.obms);
resetStubs(taskProtocol);
resetStubs(nodeApi);
waterline.nodes.needByIdentifier.withArgs('1234abcd1234abcd1234abcd')
.resolves(Promise.resolve({
id: '1234abcd1234abcd1234abcd',
name: '1234abcd1234abcd1234abcd'
}));
waterline.nodes.getNodeById.withArgs('1234abcd1234abcd1234abcd')
.resolves(Promise.resolve({
id: '1234abcd1234abcd1234abcd',
name: '1234abcd1234abcd1234abcd',
identifiers: ['1234']
}));
waterline.nodes.getNodeById.withArgs('bad' + '1234abcd1234abcd1234abcd').resolves();
waterline.nodes.needByIdentifier.rejects(new Errors.NotFoundError('Not Found'));
waterline.nodes.getNodeById.resolves({
identifiers: ['1234']
});
waterline.catalogs.findLatestCatalogOfSource.rejects(new Errors.NotFoundError());
nodeApi.setNodeWorkflowById.resolves({instanceId: 'abcdef'});
waterline.obms.findByNode.resolves({
id: '12341234',
node: '12345678',
service: 'ipmi-obm-service',
config: {
host: '1.1.1.1',
user: 'user',
password: 'passw'
}
});
wsman.isDellSystem.rejects(new Errors.NotFoundError('Not Found'));
waterline.nodes.getNodeById.withArgs('DELLabcd1234abcd1234abcd')
.resolves(Promise.resolve({
id: 'DELLabcd1234abcd1234abcd',
name: 'DELLabcd1234abcd1234abcd',
identifiers: [ "ABCDEFG" ]
}));
waterline.nodes.needByIdentifier.withArgs('DELLabcd1234abcd1234abcd')
.resolves(Promise.resolve({
id: 'DELLabcd1234abcd1234abcd',
name: 'DELLabcd1234abcd1234abcd'
}));
mktemp.createFile.withArgs('/nfs/XXXXXX.xml')
.resolves(Promise.resolve('/nfs/file.xml'));
fs.writeFile.withArgs('/nfs/file.xml',xmlData, function() {})
.resolves(Promise.resolve(undefined));
});
afterEach('tear down mocks', function () {
tv4.validate.restore();
});
after('stop HTTP server', function () {
validator.validate.restore();
redfish.render.restore();
redfish.validateSchema.restore();
view.get.restore();
nodeApi.setNodeWorkflowById.restore();
function restoreStubs(obj) {
_(obj).methods().forEach(function (method) {
if (obj[method] && obj[method].restore) {
obj[method].restore();
}
}).value();
}
restoreStubs(waterline.nodes);
restoreStubs(waterline.catalogs);
restoreStubs(waterline.workitems);
restoreStubs(taskProtocol);
return helper.stopServer();
});
//OBM model's mock data
var obm =[{
id: "574dcd5794ab6e2506fd107a",
node: "1234abcd1234abcd1234abcd",
service: 'ipmi-obm-service',
config: {
host: '1.2.3.4',
user: 'myuser',
password: 'mypass'
}
}];
// Node new mock data with OBM model change
var node = {
autoDiscover: false,
id: '1234abcd1234abcd1234abcd',
name: 'name',
identifiers: [],
tags: [],
obms: [{ obm: '/api/2.0/obms/574dcd5794ab6e2506fd107a'}],
type: 'compute',
relations: [
{
relationType: 'enclosedBy',
targets: [ '4567efgh4567efgh4567efgh' ]
}
]
};
// Node new mock data with OBM model change
var dellNode = {
autoDiscover: false,
id: 'DELLabcd1234abcd1234abcd',
name: 'dell node',
identifiers: [],
tags: [],
obms: [{ obm: '/api/2.0/obms/574dcd5794ab6e2506fd107a'}],
type: 'compute',
relations: [
{
relationType: 'enclosedBy',
targets: [ '4567efgh4567efgh4567efgh' ]
}
]
};
var rawNode = {
autoDiscover: false,
id: '1234abcd1234abcd1234abcd',
name: 'name',
identifiers: ['1234'],
tags: [],
obms: obm,
type: 'compute',
relations: [
{
relationType: 'enclosedBy',
targets: [ '4567efgh4567efgh4567efgh' ]
}
]
};
var catalogData = {
dmi: {
chassis : {
asset_tag: 'test'
},
system: {
Manufacturer: 'test',
sku_number: 'test',
product_name: 'test',
serial_number: 'test',
uuid: 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'
},
bios: {
version : "S2S_3A14 ",
release_date : "09/18/2014",
bios_revision : "5.6"
},
processor: {
version: 'test'
}
},
cpu: {
real: "1",
0: {
vendor_id: 'test'
}
},
kernel: {
machine: 'x86_64'
},
'Memory Device': [
{
Size: '16384 MB'
}
],
'Processor Information' : [
{
'Socket Designation': 'test',
Manufacturer: 'test',
'Max Speed': '2300 MHz',
'Core Count': '10',
'Thread Count': '20',
Version: 'Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz',
ID: 'test',
'Status': 'Populated, Enabled',
Family: 'test'
},
{
"Asset Tag": "Not Specified",
"Characteristics": "None",
"Current Speed": "Unknown",
"External Clock": "Unknown",
Family: "<OUT OF SPEC>",
ID: "test2",
"L1 Cache Handle": "Not Provided",
"L2 Cache Handle": "Not Provided",
"L3 Cache Handle": "Not Provided",
Manufacturer: "Not Specified",
"Max Speed": "Unknown",
"Part Number": "Not Specified",
"Serial Number": "Not Specified",
"Socket Designation": "SOCKET 1",
"Status": "Unpopulated",
"Type": "<OUT OF SPEC>",
"Upgrade": "<OUT OF SPEC>",
Version: "Not Specified",
"Voltage": "Unknown"
}
]
};
var dellCatalogData =
{
bios: {
"dcimBIOSEnumerationTypeList": [
{
"any": [],
"attributeDisplayName": {
"otherAttributes": {},
"value": "System Memory Testing"
},
"attributeName": {
"otherAttributes": {},
"value": "MemTest"
},
"caption": null,
"currentValue": [
{
"otherAttributes": {},
"value": "Disabled"
}
],
"isReadOnly": {
"otherAttributes": {},
"value": "false"
}
}
]
},
DeviceSummary: {
id: "1.2.3.4"
},
nics: [
{
"autoNegotiation": "2",
"busNumber": "5",
"controllerBiosVersion": null,
"currentMACAddress": "F8:BC:12:0B:0B:40",
"dataBusWidth": "0002",
"deviceDescription": "Integrated NIC 1 Port 1 Partition 1",
"deviceNumber": "0",
"familyDriverVersion": "16.5.20",
"familyVersion": "16.5.20",
"fcoEOffloadMode": "3",
"fcoEWwnn": null,
"fqdd": "NIC.Integrated.1-1-1",
"id": 0,
"iscsiBootMode": null,
"iscsiInitiatorGateway": null,
"iscsiInitiatorIpAddress": null,
"iscsiInitiatorName": null,
"iscsiInitiatorPrimaryDns": null,
"iscsiInitiatorSecondryDns": null,
"iscsiInitiatorSubnet": null,
"iscsiMacAddress": null,
"iscsiOffloadMode": "3",
"iscsiOffloadSupport": null,
"legacyBootProtocol": null,
"linkDuplex": "1",
"linkSpeed": "3",
"linkStatus": null,
"macAddress": null,
"maxBandwidth": "0",
"mediaType": "Base T",
"minBandwidth": "0",
"nicMode": "3",
"osDriverState": null,
"pciDeviceID": "1521",
"pciSubDeviceID": "1028",
"permanentFcoMacAddress": "F8:BC:12:0B:0B:40",
"permanentMacAddress": "F8:BC:12:0B:0B:40",
"permanentiScsiMacAddress": "",
"productName": "Intel(R) Gigabit 4P X710/I350 rNDC - F8:BC:12:0B:0B:40",
"receiveFlowControl": "2",
"slotLength": "0002",
"slotType": "0002",
"teaming": "< NIC # > , < NIC # >",
"toeSupport": null,
"transmitFlowControl": "3",
"vendorName": "Intel Corp",
"virtWwn": null,
"virtWwpn": null,
"virtualIscsiMacAddress": null,
"virtualMacAddress": null,
"wwn": null,
"wwpn": null
},
{
"autoNegotiation": "2",
"busNumber": "5",
"controllerBiosVersion": null,
"currentMACAddress": "F8:BC:12:0B:0B:41",
"dataBusWidth": "0002",
"deviceDescription": "Integrated NIC 1 Port 2 Partition 1",
"deviceNumber": "0",
"familyDriverVersion": "16.5.20",
"familyVersion": "16.5.20",
"fcoEOffloadMode": "3",
"fcoEWwnn": null,
"fqdd": "NIC.Integrated.1-2-1",
"id": 0,
"iscsiBootMode": null,
"iscsiInitiatorGateway": null,
"iscsiInitiatorIpAddress": null,
"iscsiInitiatorName": null,
"iscsiInitiatorPrimaryDns": null,
"iscsiInitiatorSecondryDns": null,
"iscsiInitiatorSubnet": null,
"iscsiMacAddress": null,
"iscsiOffloadMode": "3",
"iscsiOffloadSupport": null,
"legacyBootProtocol": null,
"linkDuplex": "1",
"linkSpeed": "3",
"linkStatus": null,
"macAddress": null,
"maxBandwidth": "0",
"mediaType": "Base T",
"minBandwidth": "0",
"nicMode": "3",
"osDriverState": null,
"pciDeviceID": "1521",
"pciSubDeviceID": "1028",
"permanentFcoMacAddress": "F8:BC:12:0B:0B:41",
"permanentMacAddress": "F8:BC:12:0B:0B:41",
"permanentiScsiMacAddress": "",
"productName": "Intel(R) Gigabit 4P X710/I350 rNDC - F8:BC:12:0B:0B:41",
"receiveFlowControl": "2",
"slotLength": "0002",
"slotType": "0002",
"teaming": "< NIC # > , < NIC # >",
"toeSupport": null,
"transmitFlowControl": "3",
"vendorName": "Intel Corp",
"virtWwn": null,
"virtWwpn": null,
"virtualIscsiMacAddress": null,
"virtualMacAddress": null,
"wwn": null,
"wwpn": null
}
]
};
var catalogDataWithBadProcessor = {
'Processor Information' : [
{
"Asset Tag": "Not Specified",
"Characteristics": "None",
"Current Speed": "Unknown",
"External Clock": "Unknown",
Family: "<OUT OF SPEC>",
ID: "test2",
"L1 Cache Handle": "Not Provided",
"L2 Cache Handle": "Not Provided",
"L3 Cache Handle": "Not Provided",
Manufacturer: "Not Specified",
"Max Speed": "Unknown",
"Part Number": "Not Specified",
"Serial Number": "Not Specified",
"Socket Designation": "SOCKET 1",
"Status": "Unpopulated",
"Type": "<OUT OF SPEC>",
"Upgrade": "<OUT OF SPEC>",
Version: "Not Specified",
"Voltage": "Unknown"
}
]
};
var smartCatalog = [
{
SMART: {
Identity: {
}
},
Controller: {
controller_PCI_BDF : "0000:00:01.1"
}
}
];
var wsmanSelLog = [
{
"creationTimeStamp": "20161206135247.000000-360",
"elementName": "System Event Log Entry",
"instanceID": "DCIM:SEL:Entry:23",
"logInstanceID": "DCIM:SEL:1",
"logName": "System Event Log",
"perceivedSeverity": "2",
"recordData": "Drive 0 is installed in disk drive bay 1.",
"recordFormat": "string Description",
"recordID": "23"
}
];
var wsmanLcLog = [
{
"recordId": 1234567,
"logName": "LifeCycle Log",
"creationTimeStamp": "20170520141756.000000-300",
"message": "Successfully logged in using root, from 100.68.124.32 and REDFISH.",
"severity": "2",
"category": "Audit",
"messageId": "USR0030",
"elementName": "USR0030",
"instanceId": "DCIM:LifeCycleLog:2173760",
"logInstanceId": "DCIM:LifeCycleLog",
"comment": "[set comment here]",
"agentId": "RACLOG",
"configResultsAvailable": "false",
"fqdd": "iDRAC.Embedded.1",
"messageArguments": "REDFISH",
"owningEntity": "DCIM",
"rawEventData": "",
"sequenceNumber": 2173760
}
];
var httpEndpoints = [
{
"address": "172.31.128.1",
"authEnabled": false,
"httpsEnabled": false,
"port": 9080,
"proxiesEnabled": true,
"routers": "southbound-api-router"
}
];
it('should return a valid system root', function () {
waterline.nodes.find.resolves([node]);
return helper.request().get('/redfish/v1/Systems')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function(res) {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
expect(res.body['Members@odata.count']).to.equal(1);
expect(res.body.Members[0]['@odata.id']).to.equal('/redfish/v1/Systems/' + node.id);
});
});
it('should return a valid system', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: false, isRedfishCapable: false
});
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
waterline.workitems.findPollers.resolves([{
config: { command: 'chassis' }
}]);
taskProtocol.requestPollerCache.resolves([{
chassis: { power: "Unknown", uid: "Reserved"}
}]);
waterline.nodes.getNodeById.withArgs('1234abcd1234abcd1234abcd').resolves(rawNode);
return helper.request().get('/redfish/v1/Systems/' + node.id)
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid system with sku', function() {
waterline.nodes.needByIdentifier.withArgs('1234abcd1234abcd1234abcd')
.resolves(Promise.resolve({
id: '1234abcd1234abcd1234abcd',
name: '1234abcd1234abcd1234abcd',
sku: 'sku-value'
}));
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
waterline.workitems.findPollers.resolves([{
config: { command: 'chassis' }
}]);
taskProtocol.requestPollerCache.resolves([{
chassis: { power: "Unknown", uid: "Reserved"}
}]);
waterline.nodes.getNodeById.withArgs('1234abcd1234abcd1234abcd').resolves(rawNode);
return helper.request().get('/redfish/v1/Systems/' + node.id)
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid system', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id)
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 an invalid identifier for bios query', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/Bios')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 a non-Dell identifier for bios query', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Bios')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid bios block for Dell-based catalog', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'bios').resolves(Promise.resolve({
node: dellNode.id,
source: 'bios',
data: dellCatalogData.bios
}));
return helper.request().get('/redfish/v1/Systems/' + dellNode.id + '/Bios')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid identifier for bios settings query', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/Bios/Settings')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 a non-Dell identifier for bios settings query', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Bios/Settings')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid bios settings block for Dell-based catalog', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'bios').resolves(Promise.resolve({
node: dellNode.id,
source: 'bios',
data: dellCatalogData.bios
}));
return helper.request().get('/redfish/v1/Systems/' + dellNode.id + '/Bios/Settings')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid system for bios settings patch', function() {
return helper.request().patch('/redfish/v1/Systems/bad' + node.id + '/Bios/Settings')
.send({ Name: "bogusname", Id: "someid"})
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 non-Dell identifier for bios settings patch', function() {
return helper.request().patch('/redfish/v1/Systems/' + node.id + '/Bios/Settings')
.send({ Name: "bogusname", Id: "someid"})
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a 202 for a Dell-based bios settings patch', function() {
// Force a southbound interface through httpEndpoints
configuration.set('httpEndpoints', httpEndpoints);
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'DeviceSummary').resolves(Promise.resolve({
node: dellNode.id,
source: 'DeviceSummary',
data: dellCatalogData.DeviceSummary
}));
return helper.request().patch('/redfish/v1/Systems/' + dellNode.id + '/Bios/Settings')
.send({ "@odata.context": "string", "@odata.id": "string", "@odata.type": "string", "Actions": { "Oem": {} }, "AttributeRegistry": "string", "Attributes": { "X": "y"}, "Description": "string", "Id": "string", "Name": "string", "Oem": {} })
.expect('Content-Type', /^application\/json/)
.expect(202);
});
it('should 404 an invalid system for Bios.ChangePassword post', function() {
return helper.request().post('/redfish/v1/Systems/bad' + node.id + '/Bios.ChangePassword')
.send({ PasswordName: "bogusname", OldPassword: "somepass", NewPassword: "newpass"})
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 an non-Dell system for Bios.ChangePassword post', function() {
return helper.request().post('/redfish/v1/Systems/' + node.id + '/Bios.ChangePassword')
.send({ PasswordName: "bogusname", OldPassword: "somepass", NewPassword: "newpass"})
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a 202 for a Dell-based bios change password SysPassword', function() {
// Force a southbound interface through httpEndpoints
configuration.set('httpEndpoints', httpEndpoints);
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'DeviceSummary').resolves(Promise.resolve({
node: dellNode.id,
source: 'DeviceSummary',
data: dellCatalogData.DeviceSummary
}));
return helper.request().post('/redfish/v1/Systems/' + dellNode.id + '/Bios.ChangePassword')
.send({ PasswordName: "SysPassword", OldPassword: "somepass", NewPassword: "newpass"})
.expect('Content-Type', /^application\/json/)
.expect(202);
});
it('should return a 202 for a Dell-based bios change password SetupPassword', function() {
// Force a southbound interface through httpEndpoints
configuration.set('httpEndpoints', httpEndpoints);
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'DeviceSummary').resolves(Promise.resolve({
node: dellNode.id,
source: 'DeviceSummary',
data: dellCatalogData.DeviceSummary
}));
return helper.request().post('/redfish/v1/Systems/' + dellNode.id + '/Bios.ChangePassword')
.send({ PasswordName: "SetupPassword", OldPassword: "somepass", NewPassword: "newpass"})
.expect('Content-Type', /^application\/json/)
.expect(202);
});
it('should 400 an invalid password name for Bios.ChangePassword post', function() {
return helper.request().post('/redfish/v1/Systems/' + dellNode.id + '/Bios.ChangePassword')
.send({ PasswordName: "bogusname", OldPassword: "somepass", NewPassword: "newpass"})
.expect('Content-Type', /^application\/json/)
.expect(400);
});
it('should 404 an invalid identifier for ethernet query', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/EthernetInterfaces')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 a non-Dell identifier for ethernet query', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id + '/EthernetInterfaces')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid ethernet block for Dell-based catalog', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'nics').resolves(Promise.resolve({
node: dellNode.id,
source: 'nics',
data: dellCatalogData.nics
}));
return helper.request().get('/redfish/v1/Systems/' + dellNode.id + '/EthernetInterfaces')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid identifier for ethernet index query with valid index', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/EthernetInterfaces/' + "NIC.Integrated.1-1-1")
.expect('Content-Type', /^application\/json/)
.expect(404)
.expect(function(res) {
expect(res.text).contains("Node not Found bad1234abcd1234abcd1234abcd");
});
});
it('should 404 a non-Dell identifier for ethernet index query with valid index', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id + '/EthernetInterfaces/' + "NIC.Integrated.1-1-1")
.expect('Content-Type', /^application\/json/)
.expect(404)
.expect(function(res) {
expect(res.text).contains("No Ethernet found for node " + node.id);
});
});
it('should 404 a valid identifier for ethernet index query with invalid index', function() {
return helper.request().get('/redfish/v1/Systems/' + dellNode.id + '/EthernetInterfaces/' + "BADNIC.Integrated.1-1-1")
.expect('Content-Type', /^application\/json/)
.expect(404)
.expect(function(res) {
expect(res.text).contains("No Ethernet index found for node " + "BADNIC.Integrated.1-1-1");
});
});
it('should return a valid ethernet index block for Dell-based catalog with valid index', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(dellNode.id, 'nics').resolves(Promise.resolve({
node: dellNode.id,
source: 'nics',
data: dellCatalogData.nics
}));
return helper.request().get('/redfish/v1/Systems/' + dellNode.id + '/EthernetInterfaces/' + 'NIC.Integrated.1-1-1')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid processor list', function() {
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Processors')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid processor list', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/Processors')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 an invalid processor list', function() {
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogDataWithBadProcessor
}));
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Processors')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid processor', function() {
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Processors/0')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid processor', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id + '/Processors/bad')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid simple storage list', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(node.id, 'smart').resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: smartCatalog
}));
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
return helper.request().get('/redfish/v1/Systems/' + node.id + '/SimpleStorage')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid simple storage', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id + '/SimpleStorage')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid simple storage device', function() {
waterline.catalogs.findLatestCatalogOfSource.withArgs(node.id, 'smart')
.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: smartCatalog
}));
waterline.catalogs.findLatestCatalogOfSource.resolves(Promise.resolve({
node: '1234abcd1234abcd1234abcd',
source: 'dummysource',
data: catalogData
}));
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/SimpleStorage/0000_00_01_1')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid simple storage device', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/SimpleStorage/bad')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid log service', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid sel log service', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: false, isRedfishCapable: false
});
waterline.workitems.findPollers.resolves([{
config: { command: 'selInformation' }
}]);
taskProtocol.requestPollerCache.resolves([{
selInformation: { '# of Alloc Units': 10, uid: "Reserved"}
}]);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid iDRAC sel log service', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: true, isRedfishCapable: false
});
wsman.getLog.withArgs(node, 'SEL').resolves(wsmanSelLog);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid sel log service', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id +
'/LogServices/sel')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid sel log service entry collection', function() {
waterline.nodes.find.resolves([node]);
waterline.workitems.findPollers.resolves([{
config: { command: 'sel' }
}]);
taskProtocol.requestPollerCache.resolves([{
sel: [{
logId: 'abcd',
value: 'Assert',
sensorType: 'Temperature',
event: 'thermal event',
sensorNumber: '#0x01',
date: '01/01/1970',
time: '01:01:01'
}]
}]);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid iDRAC sel log service entry collection', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: true, isRedfishCapable: false
});
wsman.getLog.withArgs(node, 'SEL').resolves(wsmanSelLog);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return an empty sel log service entry collection', function() {
waterline.workitems.findPollers.resolves([{
config: { command: 'sel' }
}]);
taskProtocol.requestPollerCache.resolves([{
sel: undefined
}]);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid sel log service entry list', function() {
return helper.request().get('/redfish/v1/Systems/bad' + node.id +
'/LogServices/sel/Entries')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid sel log service entry', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: false, isRedfishCapable: false
});
waterline.nodes.find.resolves([node]);
waterline.workitems.findPollers.resolves([{
config: { command: 'sel' }
}]);
taskProtocol.requestPollerCache.resolves([{
sel: [{
logId: 'abcd',
value: 'Assert',
sensorType: 'Temperature',
event: 'Thermal Event',
sensorNumber: '#0x01',
date: '01/01/1970',
time: '01:01:01'
}]
}]);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries/abcd')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid sel log service entry despite no #', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: false, isRedfishCapable: false
});
waterline.nodes.find.resolves([node]);
waterline.workitems.findPollers.resolves([{
config: { command: 'sel' }
}]);
taskProtocol.requestPollerCache.resolves([{
sel: [{
logId: 'abcd',
value: 'Assert',
sensorType: 'Temperature',
event: 'Thermal Event',
sensorNumber: '1',
date: '01/01/1970',
time: '01:01:01'
}]
}]);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries/abcd')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should return a valid iDrac sel log service entry', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: true, isRedfishCapable: false
});
wsman.getLog.withArgs(node, 'SEL').resolves(wsmanSelLog);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries/23')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.render.called).to.be.true;
});
});
it('should 404 an invalid sel log service entry', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: false, isRedfishCapable: false
});
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries/abcdefg')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should 404 an invalid iDRAC sel log service entry', function() {
wsman.isDellSystem.withArgs('1234abcd1234abcd1234abcd').resolves({
node: node, isDell: true, isRedfishCapable: false
});
wsman.getLog.withArgs(node, 'SEL').resolves(wsmanSelLog);
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/LogServices/sel/Entries/abcdefg')
.expect('Content-Type', /^application\/json/)
.expect(404);
});
it('should return a valid reset type list', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/Actions/ComputerSystem.Reset')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(view.get.called).to.be.true;
});
});
it('should 404 a reset type list on an invalid node', function() {
waterline.nodes.getNodeById.resolves();
return helper.request().get('/redfish/v1/Systems/' + node.id +
'invalid/Actions/ComputerSystem.Reset')
.expect(404);
});
it('should perform the specified valid reset', function() {
return helper.request().post('/redfish/v1/Systems/' + node.id +
'/Actions/ComputerSystem.Reset')
.send({ reset_type: "ForceRestart"})
.expect('Content-Type', /^application\/json/)
.expect(202)
.expect(function(res) {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(res.body['@odata.id']).to.equal('/redfish/v1/TaskService/Tasks/abcdef');
});
});
it('should 404 a reset on an invalid node', function() {
waterline.nodes.getNodeById.resolves();
return helper.request().post('/redfish/v1/Systems/' + node.id +
'invalid/Actions/ComputerSystem.Reset')
.send({ reset_type: "ForceRestart"})
.expect(404);
});
it('should 400 an invalid reset type', function() {
return helper.request().post('/redfish/v1/Systems/' + node.id +
'/Actions/ComputerSystem.Reset')
.send({ reset_type: "HalfForceRestart"})
.expect('Content-Type', /^application\/json/)
.expect(400);
});
it('should return a valid boot image list', function() {
return helper.request().get('/redfish/v1/Systems/' + node.id +
'/Actions/RackHD.BootImage')
.expect('Content-Type', /^application\/json/)
.expect(200)
.expect(function() {
expect(view.get.called).to.be.true;
});
});
it('should perform the specified boot image installation with minimum payload', function() {
var minimumValidBody = {
repo: "http://172.31.128.1:9080/esxi/5.5",
version: "6.0",
rootPassword: "passw0rd"
};
return Promise.map(['CentOS', 'CentOS+KVM', 'ESXi', 'RHEL', 'RHEL+KVM'], function(osName) {
return helper.request().post('/redfish/v1/Systems/' + node.id +
'/Actions/RackHD.BootImage')
.send( _.merge(minimumValidBody, {osName: osName}) )
.expect('Content-Type', /^application\/json/)
.expect(202)
.expect(function(res) {
expect(tv4.validate.called).to.be.true;
expect(validator.validate.called).to.be.true;
expect(redfish.validateSchema.called).to.be.true;
expect(res.body['@odata.id']).to.equal('/redfish/v1/TaskService/Tasks/abcdef');
});
});
});
it('should perform the specified boot image installation', function() {
var minimumValidBody = {
domain: "rackhd.com",
hostname: "rackhd",
osName: "ESXi",
repo: "http://172.31.128.1:9080/esxi/5.5",
version: "6.0",
rootPassword: "passw0rd",
dnsServers: [ "172.31.128.1" ],
installDisk: "firstdisk",
postInstallCommands:['touch a.txt', 'ls /var']
};
return Promise.map(['CentOS', 'CentOS+KVM', 'ESXi', 'RHEL', 'RHEL+KVM'], function(osName) {
return helper.request().post('/redfish/v1/Systems/' + node.id +
'/Actions/RackHD.BootImage')
.send( _.merge(minimumValidBody, {osName: osName}) )
.expect('Content-Type', /^application\/json/)
.expect(202)
.expect(function(res) {
expect(tv4.va