lib/api/redfish-1.0/systems.js
// Copyright 2016, EMC, Inc.
'use strict';
var injector = require('../../../index.js').injector;
var redfish = injector.get('Http.Api.Services.Redfish');
var waterline = injector.get('Services.Waterline');
var taskProtocol = injector.get('Protocol.Task');
var Promise = injector.get('Promise');
var _ = injector.get('_');
var nodeApi = injector.get('Http.Services.Api.Nodes');
var controller = injector.get('Http.Services.Swagger').controller;
var Errors = injector.get('Errors');
var moment = require('moment');
var wsman = injector.get('Http.Services.Wsman');
var configuration = injector.get('Services.Configuration');
var mktemp = require('mktemp');
var lookup = injector.get('Services.Lookup');
var fs = require('fs');
var encryption = injector.get('Services.Encryption');
var dataFactory = function(identifier, dataName) {
switch(dataName) {
case 'catData':
return Promise.all([nodeApi.getNodeCatalogSourceById(identifier,'ohai'), nodeApi.getNodeCatalogSourceById(identifier,'dmi')])
.spread(function(ohai, dmi) {
var catData = _.merge(ohai.data, dmi.data);
return catData;
});
case 'chassis':
return nodeApi.getNodeByIdentifier(identifier)
.then(function(node) {
return _.filter(node.relations, function(relation) {
return relation.relationType === 'enclosedBy';
}).map(function(relation) {
return relation.targets[0];
});
});
case 'chassisData':
return nodeApi.getPollersByNodeId(identifier)
.filter(function(poller) {
return poller.config.command === 'chassis';
}).spread(function(poller) {
return taskProtocol.requestPollerCache(poller.id, { latestOnly: true });
}).then(function(data) {
var chassisData = data[0].chassis;
chassisData.power = (chassisData.power) ? 'On' : 'Off';
var uidStatus = ['Off', 'Temporary On', 'On', 'Reserved'];
var validEnum = ['Off', 'Blinking', 'Lit', 'Unknown'];
chassisData.uid = validEnum[_.indexOf(uidStatus, chassisData.uid)];
return chassisData;
}).catch(function() {
return { power: "Unknown", uid: "Unknown"};
});
case 'selInfoData':
return nodeApi.getPollersByNodeId(identifier)
.filter(function(poller) {
return poller.config.command === 'selInformation';
}).spread(function(poller) {
return taskProtocol.requestPollerCache(poller.id, { latestOnly: true });
}).then(function(data) {
return data[0].selInformation;
});
case 'selData':
return nodeApi.getPollersByNodeId(identifier)
.filter(function(poller) {
return poller.config.command === 'sel';
}).spread(function(poller) {
return taskProtocol.requestPollerCache(poller.id, { latestOnly: true });
}).then(function(data) {
return data[0].sel;
});
default:
return nodeApi.getNodeCatalogSourceById(identifier, dataName);
}
};
//DCIM_View mappings to redfish equivalents
var autoNeg = {
"2": true, "3": false };
var fullDuplex = {
"1": true, "2": false };
var linkSpeed = {
"1": 10, "2": 100, "3": 1000, "4": 2500, "5": 10000,
"6": 20000, "7": 40000, "8": 100000, "9": 25000, "10":50000 };
var selTranslator = function(selArray, identifier) {
var dateRegex = /(\d{1,2})\/(\d{1,2})\/(\d{4})/;
var timeRegex = /(\d{1,2}):(\d{1,2}):(\d{1,2})/;
var ipmiEventTypeMap = {
'Asserted': 'Assert',
'Deasserted': 'Deassert',
'Lower Non-critical going low': 'Lower Non-critical - going low',
'Lower Non-critical going high': 'Lower Non-critical - going high',
'Lower Critical going low': 'Lower Critical - going low',
'Lower Critical going high': 'Lower Critical - going high',
'Lower Non-recoverable going low': 'Lower Non-recoverable - going low',
'Lower Non-recoverable going high': 'Lower Non-recoverable - going high',
'Upper Non-critical going low': 'Upper Non-critical - going low',
'Upper Non-critical going high': 'Upper Non-critical - going high',
'Upper Critical going low': 'Upper Critical - going low',
'Upper Critical going high': 'Upper Critical - going high',
'Upper Non-recoverable going low': 'Upper Non-recoverable - going low',
'Upper Non-recoverable going high': 'Upper Non-recoverable - going high',
'Predictive Failure Deasserted': 'Predictive Failure deasserted',
'Predictive Failure Asserted': 'Predictive Failure asserted',
'Transition to Non-critical from OK': 'Transition to Non-Critical from OK',
'Device Absent': 'Device Removed / Device Absent',
'Device Present': 'Device Inserted / Device Present',
'Non-Redundant: Sufficient from Redundant': 'Non-redundant:Sufficient Resources from Redundant',
'Non-Redundant: Sufficient from Insufficient': 'Non-redundant:Sufficient Resources from Insufficient Resources',
'Non-Redundant: Insufficient Resources': 'Non-redundant:Insufficient Resources',
'Redundancy Degraded from Fully Redundant': 'Redundancy Degraded from Fully Redundant',
'Redundancy Degraded from Non-Redundant': 'Redundancy Degraded from Fully Redundant'
};
var ipmiSensorTypeMap = {
'Temperature': 'Temperature',
'Voltage': 'Voltage',
'Current': 'Current',
'Fan': 'Fan',
'Physical Security': 'Physical Chassis Security',
'Platform Security': 'Platform Security Violation Attempt',
'Processor': 'Processor',
'Power Supply': 'Power Supply / Converter',
'Power Unit': 'PowerUnit',
'Cooling Device': 'CoolingDevice',
'Memory': 'Memory',
'Drive Slot': 'Drive Slot/Bay',
'System Firmware Progress': 'System Firmware Progress',
'Event Logging Disabled': 'Event Logging Disabled',
'Watchdog 1': 'Watchdog',
'System Event': 'System Event',
'Critical Interrupt': 'Critical Interrupt',
'Button': 'Button/Switch',
'Module/Board': 'Module/Board',
'Microcontroller/Coprocessor': 'Microcontroller/Coprocessor',
'Add-in Card': 'Add-in Card',
'Chassis': 'Chassis',
'Chip Set': 'ChipSet',
'Other FRU': 'Other FRU',
'Cable/Interconnect': 'Cable/Interconnect',
'Terminator': 'Terminator',
'System Boot Initiated': 'SystemBoot/Restart',
'Boot Error': 'Boot Error',
'OS Boot': 'BaseOSBoot/InstallationStatus',
'OS Stop/Shutdown': 'OS Stop/Shutdown',
'Slot/Connector': 'Slot/Connector',
'System ACPI Power State': 'System ACPI PowerState',
'Watchdog 2': 'Watchdog',
'Platform Alert': 'Platform Alert',
'Entity Presence': 'Entity Presence',
'Monitor ASIC/IC': 'Monitor ASIC/IC',
'LAN': 'LAN',
'Management Subsystem Health': 'Management Subsystem Health',
'Battery': 'Battery',
'Version Change': 'Version Change',
'FRU State': 'FRUState'
};
var selTranslatorOrigin = function(sensorType, identifier) {
switch(sensorType) {
case 'Drive Slot':
return '/redfish/v1/Systems/' + identifier + '/SimpleStorage';
case 'Power Unit':
return dataFactory(identifier, 'chassis')
.then(function(chassis) {
return '/redfish/v1/Chassis/' + chassis + '/Power';
});
case 'Power Supply':
return dataFactory(identifier, 'chassis')
.then(function(chassis) {
return '/redfish/v1/Chassis/' + chassis + '/Power';
});
case 'Fan':
return dataFactory(identifier, 'chassis')
.then(function(chassis) {
return '/redfish/v1/Chassis/' + chassis + '/Thermal';
});
case 'Temperature':
return dataFactory(identifier, 'chassis')
.then(function(chassis) {
return '/redfish/v1/Chassis/' + chassis + '/Thermal';
});
}
return null;
};
return Promise.map(selArray, function(entry) {
// if date is an empty string then so is time
var dates = entry.date !== "" ? dateRegex.exec(entry.date) : "";
var times = entry.date !== "" ? timeRegex.exec(entry.time) : "";
if(entry.sensorNumber.indexOf('#') !== 0) {
entry.sensorNumber = '#'+entry.sensorNumber;
}
return Promise.props({
logId: entry.logId,
// Month is zero indexed by moment so we must decrement
timestamp: dates !== "" ? moment.utc([dates[3], dates[1] - 1, dates[2], times[1], times[2], times[3]]).format() : "",
sensorType: _.get(ipmiSensorTypeMap, entry.sensorType, 'Other Units-based Sensor'),
value: _.get(ipmiEventTypeMap, entry.value, entry.value),
event: entry.event,
sensorNumber: parseInt(entry.sensorNumber.substr(1)),
origin: selTranslatorOrigin(entry.sensorType, identifier)
});
});
};
var getObmSettings = function(nodeId){
return waterline.obms.findByNode(nodeId, 'ipmi-obm-service', true)
.then(function (obm) {
if (!obm) {
return waterline.obms.findByNode(nodeId, 'dell-wsman-obm-service', true)
.then(function (obm2) {
if (!obm2) {
return waterline.obms.findByNode(nodeId, 'redfish-obm-service', true);
}
return obm2;
});
}
return obm;
})
.catch(function(err) {
return (err);
});
};
var getRedfishDeviceResponse = function(nodeid, req) {
var catalogSource = req.url.replace(req.swagger.params.identifier.value, nodeid).replace(/\/$/, "");
return dataFactory(nodeid,catalogSource)
.then(function(response) {
return response.data;
})
.catch(function() {
throw new Errors.NotImplementedError(req.url + ' Is Not Implemented on this Device');
});
};
/**
* Generate a list of systems managed by RackHD
* @param {Object} req
* @param {Object} res
*/
var listSystems = controller(function(req, res) {
var options = redfish.makeOptions(req, res);
return nodeApi.getAllNodes({type: ['compute','redfish']}).then(function(nodes) {
options.nodes = nodes;
return redfish.render('redfish.1.0.0.computersystemcollection.json',
'ComputerSystemCollection.json#/definitions/ComputerSystemCollection',
options);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about a specific system
* @param {Object} req
* @param {Object} res
*/
var getSystem = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
options.systemType = 'Physical';
if(result.vendor === 'Dell'){
return Promise.props({
hardware: dataFactory(identifier, 'hardware'),
boot: dataFactory(identifier, 'boot'),
chassis: dataFactory(identifier, 'chassis'),
chassisData: dataFactory(identifier, 'chassisData'),
secureBoot: true,
obm: [node.id, 'RackHD']
}).then(function(data) {
return redfish.render('redfish.2016.3.computersystem.1.3.0.json',
'ComputerSystem.v1_3_0.json#/definitions/ComputerSystem',
_.merge(options, data));
});
} else if(result.vendor === 'Cisco'){
return Promise.props({
hardware: dataFactory(identifier,'UCS'),
bios: dataFactory(identifier,'UCS:bios'),
led: dataFactory(identifier,'UCS:locator-led'),
skuInfo: Promise.try(function(){
return node.sku === undefined ? "": node.sku;
}),
chassis: Promise.map(node.relations,function(val){
if(val.relationType === 'enclosedBy'){
return val.targets;
}
}),
obm: [node.id, 'RackHD']
}).then(function(data){
return redfish.render('ucs.1.0.0.computersystem.1.3.0.json',
'ComputerSystem.v1_3_0.json#/definitions/ComputerSystem',
_.merge(options, data));
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.props({
catData: dataFactory(identifier, 'catData'),
chassis: dataFactory(identifier, 'chassis'),
chassisData: dataFactory(identifier, 'chassisData'),
secureBoot: false,
obm: [node.id, 'RackHD']
}).then(function(data) {
return redfish.render('redfish.1.0.0.computersystem.1.1.0.json',
'ComputerSystem.v1_3_0.json#/definitions/ComputerSystem',
_.merge(options, data));
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the bios of a specific system
* @param {Object} req
* @param {Object} res
*/
var listSystemBios = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result) {
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
if (result.vendor === 'Dell') {
return dataFactory(identifier, 'bios')
.then(function(bios) {
options.bios = bios;
bios.attributes = [];
var key;
// create a single bios attribute list (not organized by type)
for(key in bios.data) {
if (bios.data.hasOwnProperty(key)) {
bios.attributes = bios.attributes.concat(bios.data[key]);
}
}
// normalize the currentValue field (some need value fields)
for(key in bios.attributes) {
if (bios.attributes[key].currentValue[0] === null) {
bios.attributes[key].currentValue[0] = {"value": null};
}
}
return options;
})
.then(function(options) {
return redfish.render('redfish.1.0.0.bios.1.0.0.json',
'Bios.v1_0_1.json#/definitions/Bios',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
throw new Errors.NotFoundError('No BIOS found for node ' + identifier);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the bios settings data of a specific system
* @param {Object} req
* @param {Object} res
*/
var listSystemBiosSettings = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if (result.vendor === 'Dell') {
return dataFactory(identifier, 'bios').then(function(bios) {
options.bios = bios;
bios.attributes = [];
var key;
// create a single bios attribute list (not organized by type)
for(key in bios.data) {
if (bios.data.hasOwnProperty(key)) {
bios.attributes = bios.attributes.concat(bios.data[key]);
}
}
for (key = bios.attributes.length - 1; key >= 0; key -= 1) {
// remove entries that are readOnly
if (bios.attributes[key].isReadOnly.value === "true") {
bios.attributes.splice(key, 1);
continue;
}
// normalize the currentValue field (some need value fields)
if (bios.attributes[key].currentValue[0] === null) {
bios.attributes[key].currentValue[0] = {"value": null};
}
}
return redfish.render('redfish.1.0.0.bios.1.0.0.settings.json',
'Bios.v1_0_1.json#/definitions/Bios',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
/* TODO: Not implemented? */
throw new Errors.NotFoundError(
'No BIOS found for node ' + identifier
);
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Patch information about the bios settings data of a specific system
* @param {Object} req
* @param {Object} res
*/
var patchSystemBiosSettings = controller({success: 202}, function(req, res) {
var identifier = req.swagger.params.identifier.value;
var payload = req.swagger.params.payload.value;
var southboundApiRouter = _.filter(configuration.get('httpEndpoints', []),
_.matches({routers:'southbound-api-router'}))[0];
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
redfish.makeOptions(req, res, identifier);
if (result.vendor === 'Dell') {
var results = { name: "Graph.Dell.Wsman.UpdateSystemComponents", options: {} };
return dataFactory(identifier, 'DeviceSummary').then(function(summary) {
results.options = {
defaults: {
serverIP: summary.data.id,
fileName: "",
shareType: 0,
shareAddress: southboundApiRouter.address,
shareName: "/nfs",
shutdownType: 0,
serverUsername: "",
serverPassword: "",
serverComponents: [{fqdd: "BIOS.Setup.1-1", attributes: []}]
}
};
for (var key in payload.Attributes) {
if (payload.Attributes.hasOwnProperty(key)) {
results.options.defaults.serverComponents[0].attributes.push(
{name: key, value: payload.Attributes[key]});
}
}
return results;
});
} else if(result.vendor === 'Redfish'){
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'PATCH',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
/* TODO: Not implemented? */
throw new Errors.NotFoundError(
'Update Bios is not implemented for node ' + identifier
);
}
}).then(function(results) {
return nodeApi.setNodeWorkflowById(results, identifier);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Change Bios password of a specific system
* @param {Object} req
* @param {Object} res
*/
var changeSystemBiosPassword = controller({success: 202}, function(req, res) {
var identifier = req.swagger.params.identifier.value;
var payload = req.swagger.params.payload.value;
var southboundApiRouter = _.filter(configuration.get('httpEndpoints', []),
_.matches({routers:'southbound-api-router'}))[0];
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>`;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
if (result.vendor === 'Dell') {
var results = { name: "Graph.Dell.Wsman.UpdateSystemComponents", options: {} };
return mktemp
.createFile('/nfs/XXXXXX.xml')
.then(function(path) {
fs.writeFile(path, xmlData,function() {});
return dataFactory(identifier, 'DeviceSummary').then(function(summary) {
results.options = {
defaults: {
serverIP: summary.data.id,
fileName: path.split('/')[2],
shareType: 0,
shareAddress: southboundApiRouter.address,
shareName: "/nfs",
shutdownType: 0,
serverUsername: "",
serverPassword: "",
serverComponents: [{fqdd: "BIOS.Setup.1-1", attributes: []}],
cleanup: true
}
};
if (payload.PasswordName === "SysPassword") {
results.options.defaults.serverComponents[0].attributes.push(
{name: 'PasswordStatus', value: 'Unlocked'});
results.options.defaults.serverComponents[0].attributes.push(
{name: 'OldSysPassword', value: payload.OldPassword});
results.options.defaults.serverComponents[0].attributes.push(
{name: 'NewSysPassword', value: payload.NewPassword});
}
else if (payload.PasswordName ==="SetupPassword") {
results.options.defaults.serverComponents[0].attributes.push(
{name: 'OldSetupPassword', value: payload.OldPassword});
results.options.defaults.serverComponents[0].attributes.push(
{name: 'NewSetupPassword', value: payload.NewPassword});
}
else {
throw new Errors.BadRequestError('Invalid PasswordName: ' + payload.PasswordName);
}
return results;
});
});
} else if(result.vendor === 'Redfish'){
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'POST',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
/* TODO: Not implemented? */
throw new Errors.NotFoundError(
'Update Bios is not implemented for node ' + identifier
);
}
}).then(function(results) {
return nodeApi.setNodeWorkflowById(results, identifier);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Reset bios settings of a specific system
* @param {Object} req
* @param {Object} res
*/
var resetSystemBios = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var options = redfish.makeOptions(req, res, identifier);
var payload = req.swagger.params.payload.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
if (result.vendor === 'Dell') {
var graph = {
name: "Graph.Dell.Wsman.Reset.Components",
options: {
defaults: {
components: ["bios"]
}
}
};
return graph;
} else if(result.vendor === 'Redfish') {
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'POST',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
/* TODO: Not implemented? */
throw new Errors.NotFoundError(
'Reset Bios is not implemented for node ' + identifier
);
}
}).then(function(graph) {
return nodeApi.setNodeWorkflowById(graph, identifier);
}).then(function(graph) {
var output = {
'@odata.id': options.basepath + '/TaskService/Tasks/' + graph.instanceId
};
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the processors of a specific system
* @param {Object} req
* @param {Object} res
*/
var listSystemProcessors = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return dataFactory(identifier, 'hardware')
.then(function(hardware) {
options.hardware = hardware;
})
.then(function(){
return redfish.render(
'wsman.1.0.0.processorcollection.json',
'ProcessorCollection.json#/definitions/ProcessorCollection',
options
);
});
} else if(result.vendor === 'Cisco'){
return dataFactory(identifier, 'UCS')
.then(function(data) {
options.processors = data;
})
.then(function(){
return redfish.render(
'ucs.1.0.0.processorcollection.json',
'ProcessorCollection.json#/definitions/ProcessorCollection',
options
);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return dataFactory(identifier, 'dmi').then(function(dmi) {
options.dmi = dmi;
options.dmi.data['Processor Information'].forEach(function(element,index){
if(element.Status.indexOf('Unpopulated') !== -1){
options.dmi.data['Processor Information'].splice(index,1);
}
});
if(options.dmi.data['Processor Information'].length === 0){
throw new Errors.NotFoundError('no valid processor found');
}
return redfish.render('redfish.1.0.0.processorcollection.json',
'ProcessorCollection.json#/definitions/ProcessorCollection',
options);
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate specific information about the processors of a specific system
* @param {Object} req
* @param {Object} res
*/
var getSystemProcessor = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result) {
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return Promise.props({
socketId: req.swagger.params.socket.value,
hardware: dataFactory(identifier, 'hardware')
}).then(function(data) {
if(data.hardware.data.cpus.length <= data.socketId) {
throw new Errors.NotFoundError('invalid socketId');
}
return redfish.render('wsman.1.0.0.processor.1.0.0.json',
'Processor.v1_0_3.json#/definitions/Processor',
_.merge(options, data));
}).catch(function(error) {
return redfish.handleError(error, res);
});
} else if(result.vendor === 'Cisco') {
return Promise.props({
socketId: req.swagger.params.socket.value,
ucsData: dataFactory(identifier, 'UCS:board')
}).then(function(data) {
data.ucsData.data.children['cpu-collection']
= _.sortBy(data.ucsData.data.children['cpu-collection'], 'rn');
if(data.ucsData.data.children['cpu-collection'].length <= data.socketId) {
throw new Errors.NotFoundError('invalid socketId');
}
options._ = _; //In this case, lodash is required in view
return redfish.render('ucs.1.0.0.processor.1.0.0.json',
'Processor.v1_0_3.json#/definitions/Processor',
_.merge(options, data));
}).catch(function(error) {
return redfish.handleError(error, res);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.props({
socketId: req.swagger.params.socket.value,
catData: dataFactory(identifier, 'catData')
}).then(function(data) {
if(!_.has(data.catData.cpu, data.socketId)) {
throw new Errors.NotFoundError('invalid socketId');
}
return redfish.render('redfish.1.0.0.processor.1.0.0.json',
'Processor.v1_0_3.json#/definitions/Processor',
_.merge(options, data));
}).catch(function(error) {
return redfish.handleError(error, res);
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage adapters of a specific system
* @param {Object} req
* @param {Object} res
*/
var listSimpleStorage = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return dataFactory(identifier, 'hardware')
.then(function(hardware) {
options.hardware = hardware;
var controllers = new Set();
_.forEach(hardware.data.storage.controllers, function(ele) {
var id = ele.fQDD.replace(/[:.]/g, '_'); // jshint ignore: line
controllers.add(id);
});
options.controllers = Array.from(controllers);
return redfish.render('redfish.1.0.0.simplestoragecollection.json',
'SimpleStorageCollection.json#/definitions/SimpleStorageCollection',
options);
}).catch(function(error) {
return redfish.handleError(error, res);
});
} else if(result.vendor === 'Cisco') {
return dataFactory(identifier, 'UCS:board')
.then(function(storage) {
var controllers = [];
var regexObj = /storage-(.*)-collection/;
var allKeys = Object.keys(storage.data.children);
_.forEach(allKeys, function(key) {
if (regexObj.test(key)) {
_.forEach(storage.data.children[key], function(ele) {
controllers.push(key.split('-')[1]
+ '_'
+ ele.pci_addr.replace(/[:.]/g, '_')
+ '_'
+ ele.id);
});
}
});
options.controllers = controllers;
return redfish.render('redfish.1.0.0.simplestoragecollection.json',
'SimpleStorageCollection.json#/definitions/SimpleStorageCollection',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.all([ dataFactory(identifier, 'dmi'),
dataFactory(identifier, 'smart') ])
.spread(function(dmi, smart) {
options.dmi = dmi;
var controllers = new Set();
_.forEach(smart.data, function(ele) {
if (typeof ele.Controller.controller_PCI_BDF !== 'undefined') {
var id = ele.Controller.controller_PCI_BDF.replace(/[:.]/g, '_');
controllers.add(id);
}
});
options.controllers = Array.from(controllers);
return redfish.render('redfish.1.0.0.simplestoragecollection.json',
'SimpleStorageCollection.json#/definitions/SimpleStorageCollection',
options);
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage devices on an adapter of a specific system
* @param {Object} req
* @param {Object} res
*/
var getSimpleStorage = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.index = index;
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
options.hardware = hardware;
var controllers = {};
_.forEach(hardware.data.storage.controllers, function(ele) {
var id = ele.fQDD.replace(/[:.]/g, '_'); // jshint ignore: line
if(!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
});
options.controller = controllers[index][0];
options.devices = [];
_.forEach(hardware.data.storage.physicalDisks, function(ele) {
if(ele.fqdd.indexOf(options.controller.fQDD) !== -1) {
ele.size = ele.sizeInBytes.replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " bytes";
options.devices.push(ele);
}
});
return redfish.render('wsman.1.0.0.simplestorage.1.0.0.json',
'SimpleStorage.v1_1_1.json#/definitions/SimpleStorage',
options);
});
} else if(result.vendor === 'Cisco'){
return dataFactory(identifier, 'UCS:board')
.then(function(catalogsData){
var controllerId = 'storage-' + index.split('_')[0] + '-collection';
if(catalogsData.data.children[controllerId] === undefined){
return Promise.reject(new Errors.NotFoundError('simplestorage contorller not found'));
}
//_.forEach(catalogsData.data.children[controllerRedfishId], function(ele){
_.forEach(catalogsData.data.children[controllerId], function(ele){
var newIndex = index.split('_')[0] + "_" + ele.pci_addr.replace(/[:.]/g, '_')
+ "_" + ele.id;
if(index === newIndex){
options.description = ele.model;
options.devices = ele.children['disk-collection'];
return false;
}
});
return redfish.render('ucs.1.0.0.simplestorage.1.1.1.json',
'SimpleStorage.v1_1_1.json#/definitions/SimpleStorage',
options);
}).catch(function(error){
return redfish.handleError(error, res);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.all([ dataFactory(identifier, 'dmi'),
dataFactory(identifier, 'smart') ])
.spread(function(dmi, smart) {
options.dmi = dmi;
var controllers = {};
_.forEach(smart.data, function(ele) {
if (typeof ele.Controller.controller_PCI_BDF !== 'undefined') {
var id = ele.Controller.controller_PCI_BDF.replace(/[:.]/g, '_');
if(!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
}
});
options.controller = controllers[index][0].Controller;
options.devices = [];
_.forEach(controllers[index], function(ele) {
if(ele.SMART.Identity){
options.devices.push(ele.SMART);
}
});
return redfish.render('redfish.1.0.0.simplestorage.1.0.0.json',
'SimpleStorage.v1_1_1.json#/definitions/SimpleStorage',
options);
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage adapters of a specific system
* @param {Object} req
* @param {Object} res
*/
var listStorage = controller(function (req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function (result) {
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function (hardware) {
options.hardware = hardware;
var controllers = {};
_.forEach(hardware.data.storage.controllers, function (ele) {
var id = ele.fQDD.replace(/[:.]/g, '_'); // jshint ignore: line
if (!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
});
var ids = [];
_.forOwn(controllers, function (val, key) {
ids.push(key);
});
options.controllers = ids;
return redfish.render('redfish.1.0.0.storagecollection.json',
'SimpleStorageCollection.json#/definitions/SimpleStorageCollection',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.all([dataFactory(identifier, 'dmi'),
(identifier, 'smart')])
.spread(function (dmi, smart) {
// TODO: should this be an 'or'
if (dmi === undefined && smart === undefined){
return;
}
options.dmi = dmi;
var controllers = {};
_.forEach(smart.data, function (ele) {
if (typeof ele.Controller.controller_PCI_BDF !== 'undefined') {
var id = ele.Controller.controller_PCI_BDF.replace(/[:.]/g, '_');
if (!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
}
});
var ids = [];
_.forOwn(controllers, function (val, key) {
ids.push(key);
});
options.controllers = ids;
return redfish.render('redfish.1.0.0.storagecollection.json',
'SimpleStorageCollection.json#/definitions/SimpleStorageCollection',
options);
});
}
})
.catch(function (error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage devices on an adapter of a specific system
* @param {Object} req
* @param {Object} res
*/
var getStorage = controller(function (req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
return redfish.getVendorNameById(identifier)
.then(function (result) {
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.system = identifier;
options.index = index;
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function (hardware) {
options.hardware = hardware;
var controllers = {};
_.forEach(hardware.data.storage.controllers, function (ele) {
var id = ele.fQDD.replace(/[:.]/g, '_'); // jshint ignore: line
if (!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
});
options.controllers = [];
_.forEach(hardware.data.storage.controllers, function (ele) {
var speed = ele.possibleSpeed; //possibleSpeed format is X_X_GBS or X_GBS, convert to decimal
var speedInDecimal;
if (speed) {
speed = speed.split('_');
speed.splice(speed.length - 1, 1);
speedInDecimal = speed[0];
if (speed.length > 1) {
speedInDecimal += "." + speed[1];
}
}
else {
speedInDecimal = 0;
}
ele.possibleSpeed = speedInDecimal;
options.controllers.push(ele);
});
options.drives = [];
_.forEach(hardware.data.storage.physicalDisks, function (ele) {
options.drives.push(ele);
});
return redfish.render('redfish.2016.3.storage.1.1.1.json',
'Storage.v1_1_1.json#/definitions/Storage',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.all([dataFactory(identifier, 'dmi'),
dataFactory(identifier, 'smart')])
.spread(function (dmi, smart) {
options.dmi = dmi;
var controllers = {};
_.forEach(smart.data, function (ele) {
if (typeof ele.Controller.controller_PCI_BDF !== 'undefined') {
var id = ele.Controller.controller_PCI_BDF.replace(/[:.]/g, '_');
if (!(id in controllers)) {
controllers[id] = [];
}
controllers[id].push(ele);
}
});
options.dmi = dmi;
//It is assumed to have one controller per storage subsystem
options.controllerArr = [controllers[index][0].Controller];
options.devices = [];
_.forEach(controllers[index], function (ele) {
if (ele.SMART.Identity) {
options.devices.push(ele.SMART);
}
});
return redfish.render('redfish.1.0.0.storage.1.0.0.json',
'Storage.v1_1_1.json#/definitions/Storage',
options);
});
}
})
.catch(function (error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage devices on an adapter of a specific system
* @param {Object} req
* @param {Object} res
*/
var getDrive = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
var driveIndex = req.swagger.params.driveIndex.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.driveIndex = driveIndex;
options.identifier = identifier;
options.index = index;
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
options.hardware = hardware;
options.drive = hardware.data.storage.physicalDisks[driveIndex];
options.volumeIds = [];
//get redfish ids of all volumes related to this drive
var currFqdd = hardware.data.storage.physicalDisks[driveIndex].fqdd;
for(var i = 0; i < hardware.data.storage.virtualDisks.length; i+=1){
if (hardware.data.storage.virtualDisks[i].physicalDiskIds.indexOf(currFqdd) > -1){
options.volumeIds.push(i);
}
}
return redfish.render('redfish.2016.3.drive.1.1.1.json',
'Drive.v1_1_1.json#/definitions/Drive',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return Promise.resolve(dataFactory(identifier, 'smart'))
.then(function(smart) {
for( var i = 0; i < smart.data.length; i++) {
var drive = smart.data[i];
var id = drive.SMART.Identity["Serial number"] ? drive.SMART.Identity["Serial number"] : drive.SMART.Identity["Serial Number"];
if (typeof drive.Controller.controller_PCI_BDF !== 'undefined' && index === drive.Controller.controller_PCI_BDF.replace(/[:.]/g, '_')) {
if (id === driveIndex && typeof drive.SMART.Identity["Rotation Rate"] !== 'undefined') {
return drive;
}
}
}
throw new Errors.NotFoundError('drive ' + driveIndex + ' was not found');
})
.then(function(drive) {
var driveIdenity = drive.SMART.Identity;
options.capacityBytes = Number(driveIdenity["User Capacity"].replace(/,/g, "").split(" ")[0]);
options.serialNumber = driveIdenity["Serial number"] ? driveIdenity["Serial number"] : driveIdenity["Serial Number"];
options.manufacturer = driveIdenity["Vendor"];
options.blockSizeInBytes = (driveIdenity["Logical block size"] ? driveIdenity["Logical block size"] : driveIdenity["Sector Size"]).split(" ")[0];
options.model = driveIdenity["Product"] ? driveIdenity["Product"] : driveIdenity["Device Model"];
options.mediaType = driveIdenity["Rotation Rate"].indexOf("Solid") >= 0 ? "SSD" : "HDD";
options.protocol = driveIdenity["Transport protocol"];
options.revision = driveIdenity["Revision"];
})
.then(function() {
return redfish.render('redfish.1.0.0.drive.1.0.0.json',
'Drive.v1_1_1.json#/definitions/Drive',
options);
});
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
var listVolume = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.identifier = identifier;
options.index = index;
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
options.hardware = hardware;
options.virtualDisks = [];
_.forEach(hardware.data.storage.virtualDisks, function(ele) {
options.virtualDisks.push(ele);
});
return redfish.render('redfish.2016.3.volumecollection.json',
'VolumeCollection.json#/definitions/VolumeCollection',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not supported for non-Dell hardware.", res, null, 404);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the storage devices on an adapter of a specific system
* @param {Object} req
* @param {Object} res
*/
var getVolume = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
var volumeIndex = req.swagger.params.volumeIndex.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.volumeIndex = volumeIndex;
options.identifier = identifier;
options.index = index;
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
options.hardware = hardware;
options.volume = hardware.data.storage.virtualDisks[volumeIndex];
options.driveIds = [];
//convert drive fqdds into the ids used for redfish
_.forEach(hardware.data.storage.virtualDisks[volumeIndex].physicalDiskIds, function(ele){
for(var i = 0; i < ele.length; i+=1){
if (ele === hardware.data.storage.physicalDisks[i].fqdd){
options.driveIds.push(i);
break;
}
}
});
return redfish.render('redfish.2016.3.volume.1.0.2.json',
'Volume.v1_0_2.json#/definitions/Volume',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not supported for non-Dell hardware.", res, null, 404);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the log services available for a system
* @param {Object} req
* @param {Object} res
*/
var listLogService = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
if(result.vendor === 'Dell'){
options.logSource = ['SEL', 'lc'];
} else {
options.logSource = ['SEL'];
}
return redfish.render('redfish.1.0.0.logservicecollection.json',
'LogServiceCollection.json#/definitions/LogServiceCollection',
options);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the log service provider for a system
* @param {Object} req
* @param {Object} res
*/
var getSelLogService = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
var node = result.node;
if(result.vendor === 'Dell'){
options.type = 'SEL';
options.description = 'iDRAC System Event Log';
options.name = 'idrac-sel-information';
options.log = {};
return wsman.getLog(node, options.type)
.then(function(sel) {
options.log.size = sel.length || 0;
options.log.policy = 'WrapsWhenFull';
options.log.lastWriteDate = sel.length > 0 ? sel[0].creationTimeStamp : 'Unknown';
return redfish.render('redfish.1.0.0.logservice.1.0.0.json',
'LogService.v1_0_3.json#/definitions/LogService',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
options.type = 'SEL';
options.description = 'IPMI System Event Log';
options.name = 'ipmi-sel-information';
options.log = {};
return dataFactory(identifier, 'selInfoData')
.then(function(sel) {
options.log.size = sel['# of Alloc Units'] || 0;
options.log.policy = sel.Overflow && sel.Overflow === 'false' ?
'WrapsWhenFull' :
'NeverOverWrites';
options.log.lastWriteDate = sel['Last Add Time'] || 'Unknown';
return redfish.render('redfish.1.0.0.logservice.1.0.0.json',
'LogService.v1_0_3.json#/definitions/LogService',
options);
});
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the log entries of a log service for a system
* @param {Object} req
* @param {Object} res
*/
var listSelLogServiceEntries = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
options.type = 'SEL';
if(result.vendor === 'Dell'){
return wsman.getLog(node, options.type)
.then(function(selData) {
options.logEntries = selData;
return redfish.render('wsman.1.0.0.logentrycollection.json',
'LogEntryCollection.json#/definitions/LogEntryCollection',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return dataFactory(identifier, 'selData')
.then(function(selData) {
if(selData) {
return selTranslator(selData, identifier);
}
return [];
})
.then(function(selData) {
options.logEntries = selData;
return redfish.render('redfish.1.0.0.logentrycollection.json',
'LogEntryCollection.json#/definitions/LogEntryCollection',
options);
});
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about a specific log entry for a system
* @param {Object} req
* @param {Object} res
*/
var getSelLogServiceEntry = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var entryId = req.swagger.params.entryId.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
options.type = 'SEL';
options.description = 'IPMI System Event Log';
options.name = 'ipmi-sel-information';
options.log = {};
if(result.vendor === 'Dell'){
return wsman.getLog(node, options.type)
.then(function(selData) {
options.entries = _.filter(selData, function(entry) {
return entry.recordID === entryId;
});
if(!options.entries.length) {
throw new Errors.NotFoundError('sel entry ' + entryId + ' was not found');
}
options.entry = options.entries[0];
return redfish.render('wsman.1.0.0.logentry.1.0.0.json',
'LogEntry.v1_1_1.json#/definitions/LogEntry',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return dataFactory(identifier, 'selData')
.then(function(selData) {
options.entries = _.filter(selData, function(entry) {
return entry.logId === entryId;
});
if(!options.entries.length) {
throw new Errors.NotFoundError('SEL entry ' + entryId + ' was not found');
}
return selTranslator(options.entries, identifier);
})
.then(function(selData) {
options.entries = selData;
options.entry = options.entries[0];
return redfish.render('redfish.1.0.0.logentry.1.0.0.json',
'LogEntry.v1_1_1.json#/definitions/LogEntry',
options);
});
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the log service provider for a system
* @param {Object} req
* @param {Object} res
*/
var getLcLogService = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
options.type = 'LC';
options.description = 'iDRAC Lifecycle Controller Log';
options.name = 'idrac-lc-information';
options.log = {};
return wsman.getLog(node, options.type)
.then(function(lc) {
options.log.size = lc.length || 0;
options.log.policy = 'WrapsWhenFull';
options.log.lastWriteDate = lc.length > 0 ? lc[0].creationTimeStamp : 'Unknown';
return redfish.render('redfish.1.0.0.logservice.1.0.0.json',
'LogService.v1_0_3.json#/definitions/LogService',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the log entries of a log service for a system
* @param {Object} req
* @param {Object} res
*/
var listLcLogServiceEntries = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
options.type = 'LC';
if(result.vendor === 'Dell'){
return wsman.getLog(node, options.type)
.then(function(lcData) {
options.logEntries = lcData;
return redfish.render('wsman.1.0.0.lclogentrycollection.json',
'LogEntryCollection.json#/definitions/LogEntryCollection',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about a specific log entry for a system
* @param {Object} req
* @param {Object} res
*/
var getLcLogServiceEntry = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var entryId = req.swagger.params.entryId.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
var node = result.node;
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
options.type = 'LC';
options.description = 'Lifecycle Controller Log';
options.name = 'wsman-lc-information';
options.log = {};
if(result.vendor === 'Dell'){
return wsman.getLog(node, options.type)
.then(function(lcData) {
var id = parseInt(entryId);
options.entries = _.filter(lcData, function(entry) {
return entry.recordId === id;
});
if(!options.entries.length) {
throw new Errors.NotFoundError('LC entry ' + entryId + ' was not found');
}
options.entry = options.entries[0];
return redfish.render('wsman.1.0.0.lclogentry.1.0.0.json',
'LogEntry.v1_1_1.json#/definitions/LogEntry',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about available reset types for a system
* @param {Object} req
* @param {Object} res
*/
var listResetTypes = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result) {
var node = result.node;
if(!node) {
throw new Errors.NotFoundError('identifier not found');
}
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
}
return redfish.get('redfish.1.0.0.rackhd.reset.actions.json', options);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Perform the specified reset operation on the system
* @param {Object} req
* @param {Object} res
*/
var doReset = controller(function(req,res) {
//TODO Fix for node types
var identifier = req.swagger.params.identifier.value;
var payload = req.swagger.params.payload.value;
var options;
return redfish.getVendorNameById(identifier)
.then(function(result) {
var node = result.node;
if(!node) {
throw new Errors.NotFoundError('identifier not found');
}
identifier = node.id;
options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Redfish') {
return result;
}
return redfish.validateSchema(payload, 'RackHD.ResetAction.json#/definitions/ResetAction');
})
.then(function(result) {
if (result.vendor === 'Redfish') {
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'PATCH',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return nodeApi.setNodeWorkflowById(results, identifier);
});
}
var map = {
On: 'Graph.PowerOn.Node',
ForceOff: 'Graph.PowerOff.Node',
GracefulRestart: 'Graph.Reset.Soft.Node',
ForceRestart: 'Graph.Reboot.Node',
ForceOn: 'Graph.PowerOn.Node',
PushPowerButton: 'Graph.Reset.Soft.Node'
};
if(result.error) {
throw new Error(result.error);
}
if(!_.has(map, payload.ResetType)) {
throw new Error('value not found in map');
}
return nodeApi.setNodeWorkflowById({
name: map[payload.ResetType]
}, identifier);
})
.then(function(data) {
return {
'@odata.id': options.basepath + '/TaskService/Tasks/' + data.instanceId
};
})
.then(function(output) {
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* List the ethernet interfaces for specified system
* @param {Object} req
* @param {Object} res
*/
var listSystemEthernetInterfaces = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
options.name = "Systems Ethernet Interface Collection";
if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
if(result.vendor === 'Dell'){
return dataFactory(identifier, 'nics')
.then(function(nics) {
options.baseprofile = 'Systems';
options.net = [];
_.forEach(nics.data, (function(data) {
options.net.push(data.fqdd);
}));
return redfish.render('redfish.1.0.0.ethernetinterfacecollection.json',
'EthernetInterfaceCollection.json#/definitions/EthernetInterfaceCollection',
options);
});
} else {
return dataFactory(identifier, 'ohai')
.then(function(ohai) {
options.baseprofile = 'Systems';
options.net = [];
_.forEach(Object.keys(ohai.data.network.interfaces), (function(key) {
options.net.push(key);
}));
return redfish.render('redfish.1.0.0.ethernetinterfacecollection.json',
'EthernetInterfaceCollection.json#/definitions/EthernetInterfaceCollection',
options);
});
}
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* List an ethernet interface by system and id
* @param {Object} req
* @param {Object} res
*/
var listSystemEthernetInterfacesById = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
var index = req.swagger.params.index.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return dataFactory(identifier, 'nics')
.then(function(nics) {
options.baseprofile = 'Systems';
options.net = [];
_.forEach(nics.data, function(data) {
if(data.fqdd === index) {
options.nic = data;
}
});
if(typeof options.nic === 'undefined') {
// raise an exception
throw new Errors.NotFoundError('No Ethernet index found for node ' + index);
}
return options;
}).then(function(options) {
options.name = "Systems Ethernet Interface";
options.index = index;
options.autoneg = autoNeg[options.nic.autoNegotiation];
options.description = options.nic.deviceDescription;
options.fullduplex = fullDuplex[options.nic.linkDuplex];
options.linkstatus = options.nic.linkStatus;
options.macaddress = options.nic.currentMACAddress;
options.permanentmacaddress = options.nic.permanentMacAddress;
options.speedmbps = linkSpeed[options.nic.linkSpeed];
lookup.macAddressToIp(options.macaddress)
.then(function(ipaddress) {
if (typeof ipaddress !== 'undefined') {
options.ipv4 = [];
var ip4 = {
ipaddr: ipaddress
};
options.ipv4.push(ip4);
}
});
return options;
}).then(function(options) {
return redfish.render('redfish.1.0.0.ethernetinterface.1.0.0.json',
'EthernetInterface.v1_2_0.json#/definitions/EthernetInterface',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return dataFactory(identifier, 'ohai')
.then(function(ohai) {
options.baseprofile = 'Systems';
options.net = [];
_.forEach(Object.keys(ohai.data.network.interfaces), function(key) {
if(key === index) {
options.nic = ohai.data.network.interfaces[key];
}
});
if(typeof options.nic === 'undefined') {
// raise an exception
throw new Errors.NotFoundError('No Ethernet index found for node ' + index);
}
return options;
}).then(function(options) {
options.name = "Systems Ethernet Interface";
options.index = index;
options.mtusize = options.nic.mtu;
if ('addresses' in options.nic) {
_.forEach(Object.keys(options.nic.addresses), function(key) {
switch (options.nic.addresses[key].family)
{
case "lladdr":
options.macaddress = key;
break;
case "inet":
if (typeof options.ipv4 === 'undefined' ) {
options.ipv4 = [];
}
var ip4 = {
ipaddr: key,
ipsubnet: options.nic.addresses[key].netmask
};
options.ipv4.push(ip4);
break;
case "inet6":
if (typeof options.ipv6 === 'undefined' ) {
options.ipv6 = [];
}
var ip6 = {
ipaddr: key,
prefixlength: options.nic.addresses[key].prefixlen
};
options.ipv6.push(ip6);
break;
default:
break;
}
});
}
return options;
}).then(function(options) {
if (typeof options.macaddress !== 'undefined') {
lookup.macAddressToIp(options.macaddress)
.then(function(ipaddress) {
if (typeof ipaddress !== 'undefined') {
if (typeof options.ipv4 === 'undefined') {
options.ipv4 = [];
var ip4 = {
ipaddr: ipaddress
};
options.ipv4.push(ip4);
} else {
options.ipv4[0].ipaddr = ipaddress;
}
} else {
if (typeof options.ipv4 !== "undefined") {
delete options.ipv4;
}
if (typeof options.ipv6 !== "undefined") {
delete options.ipv6;
}
}
});
}
return options;
}).then(function(options) {
return redfish.render('redfish.1.0.0.ethernetinterface.1.0.0.json',
'EthernetInterface.v1_2_0.json#/definitions/EthernetInterface',
options);
});
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Generate information about the available boot images for the system
* @param {Object} req
* @param {Object} res
*/
var listBootImage = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return nodeApi.getNodeByIdentifier(identifier)
.then(function(node) {
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
return redfish.get('redfish.1.0.0.rackhd.bootimage.json', options);
})
.catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Perform the boot image installation on the specified system
* @param {Object} req
* @param {Object} res
*/
var doBootImage = controller(function(req,res) {
var identifier = req.swagger.params.identifier.value;
var payload = req.swagger.params.payload.value;
return nodeApi.getNodeByIdentifier(identifier)
.then(function(node) {
identifier = node.id;
var options = redfish.makeOptions(req, res, identifier);
return redfish.validateSchema(payload, 'RackHD.BootImage.json#/definitions/BootImage')
.then(function validatePayload(result) {
if(result.error) {
throw new Error(result.error);
}
var graphOptions = {
defaults: payload
};
if( payload.osName.indexOf('+KVM') !== -1) {
graphOptions.defaults.kvm = true;
}
var graphName = '';
if( payload.osName.indexOf('CentOS') !== -1) {
graphName = 'Graph.InstallCentOS';
graphOptions.defaults.osName = 'CentOS';
} else if(payload.osName.indexOf('ESXi') !== -1) {
graphName = 'Graph.InstallESXi';
graphOptions.defaults.osName = 'ESXi';
} else if(payload.osName.indexOf('RHEL') !== -1) {
graphName = 'Graph.InstallRHEL';
graphOptions.defaults.osName = 'RHEL';
} else {
throw new Error('invalid osName');
}
return [ graphName, graphOptions ];
}).spread(function launchTask(name, graphOptions) {
return nodeApi.setNodeWorkflowById({ name: name, options: graphOptions }, node.id);
}).then(function reportTask(data) {
return {
'@odata.id': options.basepath + '/TaskService/Tasks/' + data.instanceId
};
}).then(function(output) {
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
});
var deleteVolume = controller(function(req,res) {
var identifier = req.swagger.params.identifier.value;
var volumeIndex = req.swagger.params.volumeIndex.value;
var payload = req.swagger.params.payload.value;
var graphName = 'Graph.Dell.Wsman.Delete.Volume';
var graphOptions = {
defaults: payload
};
var options;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
graphOptions.defaults.volumeId = hardware.data.storage.virtualDisks[volumeIndex].fqdd;
graphOptions.defaults.ipAddress = hardware.data.id;
return { name: graphName, options: graphOptions };
});
} else if(result.vendor === 'Redfish'){
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'POST',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
}).then(function(results){
return nodeApi.setNodeWorkflowById(results, identifier);
}).then(function reportTask(data) {
return {
'@odata.id': options.basepath + '/TaskService/Tasks/' + data.instanceId
};
}).then(function(output) {
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
var addVolume = controller(function(req,res) {
var identifier = req.swagger.params.identifier.value;
var payload = req.swagger.params.payload.value;
var graphName = 'Graph.Dell.Wsman.Add.Volume';
var graphOptions = {
defaults: {
username: payload.username,
password: payload.password
}
};
var options;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
var driveIndices = [];
var i;
for(i = 0; i < payload.volume.Links.Drives.length; i+=1)
{
var odataId = payload.volume.Links.Drives[i]['@odata.id'].split('/');
var ind = odataId[odataId.length - 1];
driveIndices.push(ind);
}
if (driveIndices.length === 0){
throw new Error("No Drives specified for the Volume to use.");
}
graphOptions.defaults.ipAddress = hardware.data.id;
graphOptions.defaults.name = payload.volume.Name;
if (graphOptions.defaults.name.indexOf(" ") !== -1){
throw new Error("Virtual disk name cannot have spaces");
}
graphOptions.defaults.sizeInBytes = payload.volume.CapacityBytes;
graphOptions.defaults.drives = "";
for(i = 0; i < driveIndices.length; i+=1) {
if (driveIndices[i] >= hardware.data.storage.physicalDisks.length){
throw "No drive exists with id " + driveIndices[i];
}
graphOptions.defaults.drives += hardware.data.storage.physicalDisks[driveIndices[i]].fqdd;
if (i+1 < driveIndices.length){
graphOptions.defaults.drives += ',';
}
}
var raidLevel = payload.volume.VolumeType;
switch(raidLevel)
{
case "NonRedundant":
graphOptions.defaults.raidLevel = 0;
break;
case "Mirrored":
graphOptions.defaults.raidLevel = 1;
break;
case "StripedWithParity":
graphOptions.defaults.raidLevel = 5;
break;
case "SpannedMirrors":
graphOptions.defaults.raidLevel = 10;
break;
case "SpannedStripesWithParity":
graphOptions.defaults.raidLevel = 50;
break;
default:
throw "Invalid Raid Level for creating volume";
}
return { name: graphName, options: graphOptions };
});
} else if(result.vendor === 'Redfish'){
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'POST',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
}).then(function(results){
return nodeApi.setNodeWorkflowById(results, identifier);
}).then(function reportTask(data) {
return {'@odata.id': options.basepath + '/TaskService/Tasks/' + data.instanceId};
}).then(function(output) {
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
var addHotspare = controller(function(req,res) {
var identifier = req.swagger.params.identifier.value;
var driveIndex = req.swagger.params.driveIndex.value;
var payload = req.swagger.params.payload.value;
/*
payload looks like for dhs:
{
username:
password:
volumeId:(fqdd of volume)
}
*/
var graphName = 'Graph.Dell.Wsman.Add.Hotspare';
var graphOptions = {
defaults: payload
};
var options;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return Promise.resolve(dataFactory(identifier, 'hardware'))
.then(function(hardware) {
graphOptions.defaults.driveId = hardware.data.storage.physicalDisks[driveIndex].fqdd;
graphOptions.defaults.ipAddress = hardware.data.id;
if(payload.hotspareType === 'dhs'){
//get volume fqqd using redfish path to volume
var volumeId = payload.volumeId.split('/');
var volumeIndex = volumeId[volumeId.length - 1];
if (hardware.data.storage.virtualDisks.length <= volumeIndex) {
throw "No Volume found with id " + volumeIndex;
}
graphOptions.defaults.volumeId = hardware.data.storage.virtualDisks[volumeIndex].fqdd;
}
return { name: graphName, options: graphOptions };
});
} else if(result.vendor === 'Redfish'){
return getObmSettings(identifier)
.then(function(obm) {
var results = { name: "Graph.Run.Rest.Command", options: {} };
results.options = {
defaults: {
url: {
protocol: obm.config.protocol,
host: obm.config.host,
port: obm.config.port,
path: req.url.replace(req.swagger.params.identifier.value, result.node.identifiers[0])
},
credential: {username: obm.config.username, password: encryption.decrypt(obm.config.password)},
method: 'POST',
headers: {},
data: payload,
verifySSL: obm.config.verifySSL,
recvTimeoutMs: 360000
}
};
return results;
});
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
}).then(function(results){
return nodeApi.setNodeWorkflowById(results, identifier);
}).then(function reportTask(data) {
return {'@odata.id': options.basepath + '/TaskService/Tasks/' + data.instanceId};
}).then(function(output) {
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
var getSecureBoot = controller(function(req, res) {
var identifier = req.swagger.params.identifier.value;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
var options = redfish.makeOptions(req, res, identifier);
if(result.vendor === 'Dell'){
return dataFactory(identifier, 'bios').then(function(bios) {
return _.get(_.find(bios.data.dcimBIOSEnumerationTypeList, function(attribute) {
return attribute.attributeName.value === 'SecureBoot';
}), 'currentValue[0].value');
})
.then(function(secureBoot) {
options.SecureBoot = secureBoot;
return redfish.render('redfish.1.0.0.secureboot.1.0.1.json',
'SecureBoot.v1_0_1.json#/definitions/SecureBoot',
options);
});
} else if (result.vendor === 'Redfish') {
return getRedfishDeviceResponse(identifier, req);
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
}).catch(function(error) {
return redfish.handleError(error, res);
});
});
/**
* Set UEFI Secure Boot status for a system
* @param {Object} req
* @param {Object} res
*/
var setSecureBoot = controller(function(req, res) {
//TODO Write logic for non racadm
var identifier = req.swagger.params.identifier.value;
var options = redfish.makeOptions(req, res, identifier);
var graphName = 'Graph.Dell.Wsman.ConfigureBios';
var secureBootEnable;
if (req.body.SecureBootEnable) {
secureBootEnable = "Enabled";
} else {
secureBootEnable = "Disabled";
}
//1 - PowerCycle(cold boot)
//2 - Graceful Reboot without forced shutdown
//3 - Graceful Reboot with forced shutdown
var rebootJobType = 2;
return redfish.getVendorNameById(identifier)
.then(function(result){
identifier = result.node.id;
if(result.vendor === 'Dell'){
var graphOptions = {
defaults: {
"attributes": [{
"name": "SecureBoot",
"value": secureBootEnable
}],
"rebootJobType": rebootJobType
}
};
return nodeApi.setNodeWorkflowById({
name: graphName,
options: graphOptions
}, identifier)
.then(function(graph) {
var output = {'@odata.id': options.basepath + '/TaskService/Tasks/' + graph.instanceId};
res.setHeader('Location', output['@odata.id']);
res.status(202).json(output);
});
} else {
return redfish.handleError("Not implemented for non-Dell hardware.", res, null, 501);
}
})
.catch(function(error) {
return redfish.handleError(error, res);
// return nodeApi.getNodeByIdentifier(identifier)
// .then(function(node) {
// identifier = node.id;
// return getObmSettings(identifier)
// .then(function(obmSettings) {
// return racadm.runCommand (
// obmSettings.host,
// obmSettings.user,
// obmSettings.password,
// 'set bios.SysSecurity.SecureBoot ' + command
// );
// })
// .then(function() {
// res.status(202).json({"Message": "Successfully Completed Request"});
// })
// .catch(function(error) {
// return redfish.handleError(error, res);
// });
});
});
module.exports = {
listSystems: listSystems,
getSystem: getSystem,
listSystemBios: listSystemBios,
listSystemBiosSettings: listSystemBiosSettings,
patchSystemBiosSettings: patchSystemBiosSettings,
changeSystemBiosPassword: changeSystemBiosPassword,
resetSystemBios: resetSystemBios,
listSystemProcessors: listSystemProcessors,
getSystemProcessor: getSystemProcessor,
listSimpleStorage: listSimpleStorage,
getSimpleStorage: getSimpleStorage,
listStorage: listStorage,
getStorage: getStorage,
getDrive: getDrive,
listVolume: listVolume,
getVolume: getVolume,
listLogService: listLogService,
getSelLogService: getSelLogService,
listSelLogServiceEntries: listSelLogServiceEntries,
getSelLogServiceEntry: getSelLogServiceEntry,
getLcLogService: getLcLogService,
listLcLogServiceEntries: listLcLogServiceEntries,
getLcLogServiceEntry: getLcLogServiceEntry,
listResetTypes: listResetTypes,
doReset: doReset,
listBootImage: listBootImage,
doBootImage: doBootImage,
deleteVolume: deleteVolume,
addVolume: addVolume,
addHotspare: addHotspare,
getSecureBoot: getSecureBoot,
setSecureBoot: setSecureBoot,
listSystemEthernetInterfaces: listSystemEthernetInterfaces,
listSystemEthernetInterfacesById: listSystemEthernetInterfacesById,
dataFactory: dataFactory
};