ilorest
Version:
iLO REST JavaScript Library
482 lines (452 loc) • 19.3 kB
JavaScript
;
/*
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*/
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _bluebird = require('bluebird');
var _bluebird2 = _interopRequireDefault(_bluebird);
/*
BIOS regitry URL will probably be unmatched for a while during the Gen10 development
Creating this function to contain all workarounds before everything get fixed
*/
var isValidBiosRegistry = function isValidBiosRegistry(target, registry) {
target = encodeURIComponent(target);
registry = registry.split('/');
registry = registry[registry.length - 2];
if (target === registry) {
//Idealy this statement should covers all
return true;
} else {
//But we still need some workarounds during Gen10 development
target = target.split('.')[0];
registry = registry.split('.')[0];
if (target === registry) {
return true;
}
}
return false;
};
/*
Gen9/Gen10 have different object hierachy so this function returns object in an unified hierachy.
Currently the unified hierachy looks like Gen9 (just to make things work) but I think Gen10 is better.
Or we can have our own version if something good comes up. We'll see.
*/
var normalizeRBSUdata = function normalizeRBSUdata(data, isGen9, oem) {
if (isGen9) {
var unified_struct = {};
unified_struct.Attributes = data;
if (data.links && data.links.Settings) {
unified_struct['@Redfish.Settings'] = {
SettingsObject: {
'@odata.id': data.links.Settings.href
}
};
}
if (data.AttributeRegistry) {
unified_struct.AttributeRegistry = data.AttributeRegistry;
}
return unified_struct;
} else {
return data;
}
return null;
};
/*
Retreive settings URI from rbsu data
*/
var getSettingsURI = function getSettingsURI(rbsuData) {
if (rbsuData['@Redfish.Settings'] && rbsuData['@Redfish.Settings'].SettingsObject) {
return rbsuData['@Redfish.Settings'].SettingsObject['@odata.id'];
} else {
return null;
}
};
/*
Create conditional statement out of dependency object for dependency parser
Compatiable with Gen9/Gen10
*/
var _create_conditional_statement = function _create_conditional_statement(obj) {
var evalStr = '';
if (obj.MapFromCondition) {
switch (obj.MapFromCondition) {
case 'EQU':
obj.MapFromCondition = '==';
break;
case 'NEQ':
obj.MapFromCondition = '!=';
break;
default:
break;
}
}
if (obj.MapTerms && obj.MapTerms === 'AND') {
obj.MapTerms = '&&';
}
evalStr = (obj.MapTerms ? obj.MapTerms : '') + ' (tempRBSU.Attributes["' + obj.MapFromAttribute + '"].' + obj.MapFromProperty + ' ' + obj.MapFromCondition + ' "' + obj.MapFromValue + '")';
return evalStr;
};
/*
Patch data in correct structure (Gen9/Gen10)
*/
var _patchData = function _patchData(rbsuData, isGen9) {
var returnData = null;
if (isGen9) {
returnData = rbsuData.Attributes;
} else {
returnData = rbsuData;
}
return returnData;
};
/*
Parse the output from dependency parser
If it's violating the rules, a human-readable string will be returned as explanation.
Return false if there's no violation.
*/
var isViolating = function isViolating(data) {
if (!data || !data.modified) {
return 'Error when checking data from dependency parser';
}
var violate = [];
for (var key in data.modified) {
if (data.modified[key].force) {
violate.push(data.modified[key]);
}
}
if (violate.length > 0) {
var explanation = '[Invalid RBSU configuration]\n' + 'Please correct RBSU setting based on following suggestions:\n';
for (var key in violate) {
explanation += '[' + violate[key].name + '] should be [' + violate[key].value + '] because: \n';
for (var index in violate[key].why) {
var why = violate[key].why[index];
explanation += '- ' + why.MapFromAttribute + '[' + why.MapFromProperty + '] ' + why.MapFromCondition + ' ' + why.MapFromValue + '\n';
}
}
return explanation;
} else {
return false;
}
};
/** RBSU class */
var rbsu = (function () {
/**
* RBSU This class is initiated by other helper function. User won't need to initiate it directly.
* Data structure used by this class is OData-Version: 4.0
*/
function rbsu(client, password) {
_classCallCheck(this, rbsu);
rbsu.client = client;
if (password) {
rbsu.addPassword(password);
}
rbsu.biosSetting = null;
rbsu.headers = {};
rbsu.headers['OData-Version'] = '4.0';
rbsu.gen9 = false;
}
_createClass(rbsu, [{
key: 'getRegistryContent',
value: function getRegistryContent(schemaData) {
var registryUri = null;
if (rbsu.gen9) {
if (schemaData.Uri && schemaData.Uri.extref) {
registryUri = schemaData.Uri.extref;
}
} else {
if (schemaData.Uri) {
registryUri = schemaData.Uri;
}
}
if (registryUri) {
return rbsu.client.get(registryUri, null, null, rbsu.headers).then(function (res) {
return res.body;
});
} else {
return null;
}
}
/*
Get schema options for current RBSU setting
*/
}, {
key: 'getRegistryOption',
value: function getRegistryOption(rbsuData) {
if (rbsuData.hasOwnProperty('AttributeRegistry')) {
var AttributeRegistry = rbsuData.AttributeRegistry;
}
return rbsu.client.getRootObject(rbsu.headers).then(function (res) {
return rbsu.client.get(res.body.Registries['@odata.id'], null, null, rbsu.headers);
}).then(function (res) {
var registryItems = res.body.Members;
for (var key in registryItems) {
if (isValidBiosRegistry(AttributeRegistry, registryItems[key]['@odata.id'])) {
return rbsu.client.get(registryItems[key]['@odata.id'], null, null, rbsu.headers);
}
}
console.log('ERROR: Could not find correct RBSU Registry');
console.log("We can still return the closest, but let's just return null for now");
throw 'ERROR: Could not find correct RBSU Registry';
}).then(function (res) {
if (res.body && res.body.Location) {
return res.body.Location;
} else {
throw 'ERROR: Could not find correct RBSU Registry';
}
});
}
/*
Returns settings of this RBSU which will be applied after next reboot
*/
}, {
key: 'getNextSetting',
value: function getNextSetting(rbsuData) {
var settingsURI = getSettingsURI(rbsuData);
if (settingsURI) {
return rbsu.client.get(settingsURI, null, null, rbsu.headers).then(function (res) {
return normalizeRBSUdata(res.body, rbsu.gen9, null);
});
} else {
throw 'ERROR: Could not get pending RBSU setting';
}
}
/**
* Retrieve the RBSU data
* @return {promise} A Promise object which returns the HTTP response after login
*/
}, {
key: 'getRBSUdata',
value: function getRBSUdata() {
var oem = null; // Oem info is needed in iLO 4
var rbsuDataCollection = [];
return rbsu.client.getRootObject(rbsu.headers).then(function (res) {
//GET system
if (res.body.Systems && res.body.Systems['@odata.id']) {
if (res.body.hasOwnProperty('Oem')) {
//Check the OEM count, should be only 1 OEM.
if (Object.keys(res.body.Oem).length === 1) {
oem = Object.getOwnPropertyNames(res.body.Oem)[0];
if (res.body.Oem[oem]) {
if (res.body.Oem[oem].Manager && res.body.Oem[oem].Manager.length === 1) {
if (res.body.Oem[oem].Manager[0].ManagerType === 'iLO 4') {
// iLO 4 has different schema. Set the flag for future reference.
rbsu.gen9 = true;
} else {
rbsu.gen9 = false;
}
}
return rbsu.client.get(res.body.Systems['@odata.id'], null, null, rbsu.headers);
}
} else {
throw 'Invalid Oem count';
}
}
}
throw 'Root object is not valid';
}).then(function (res) {
//GET data from each system node and return an array of promise
res.body.Members.forEach(function (node) {
rbsuDataCollection.push(node);
});
var systemArray = rbsuDataCollection.map(function (obj) {
return rbsu.client.get(obj['@odata.id'], null, null, rbsu.headers);
});
return systemArray;
}) //Resolve promise array of system node
.then(function (systemArray) {
return _bluebird2['default'].all(systemArray);
}) //Get BIOS data from each system node
.then(function (result) {
var biosLinkArray = result.map(function (obj) {
try {
if (rbsu.gen9) {
return rbsu.client.get(obj.body.Oem[oem].Links.BIOS['@odata.id']);
} else {
if (obj.body.Bios && obj.body.Bios['@odata.id']) {
return rbsu.client.get(obj.body.Bios['@odata.id']);
}
}
} catch (error) {
throw error;
}
});
return _bluebird2['default'].all(biosLinkArray);
}).then(function (result) {
rbsu.biosSetting = result.map(function (obj) {
if (obj && obj.body) {
return normalizeRBSUdata(obj.body, rbsu.gen9, oem);
}
});
return rbsu.biosSetting;
});
}
/*
Check if newRBSU obeys dependency rules
Dependecy parser BETA
*/
}, {
key: 'validateRBSU',
value: function validateRBSU(registry, currentRBSU, nextRBSU) {
var returnData = {
registry: {},
RBSU: {},
modified: []
};
var tempRBSU = {
Attributes: {}
};
var attribute = registry.RegistryEntries.Attributes;
var attributeName, menuName;
if (rbsu.gen9) {
attributeName = 'Name';
menuName = 'Name';
} else {
attributeName = 'AttributeName';
menuName = 'MenuName';
}
for (var key in attribute) {
tempRBSU.Attributes[attribute[key][attributeName]] = attribute[key];
if (nextRBSU.Attributes[attribute[key][attributeName]] !== currentRBSU.Attributes[attribute[key][attributeName]]) {
tempRBSU.Attributes[attribute[key][attributeName]].CurrentValue = nextRBSU.Attributes[attribute[key][attributeName]];
} else {
tempRBSU.Attributes[attribute[key][attributeName]].CurrentValue = currentRBSU.Attributes[attribute[key][attributeName]];
}
}
var dependency = registry.RegistryEntries.Dependencies;
for (key in dependency) {
var mapFrom = dependency[key].Dependency.MapFrom,
evalStr = '';
for (var index in mapFrom) {
//Constructing eval string
var obj = mapFrom[index];
if (obj.MapFromAttribute in tempRBSU.Attributes) {
evalStr += _create_conditional_statement(obj);
}
}
var check = false;
try {
check = eval(evalStr);
} catch (err) {
console.error('[Invalid parser rule]' + evalStr);
continue;
}
if (check) {
var mapTo = dependency[key].Dependency,
tmpValue,
checkStr = null;
if (typeof mapTo.MapToValue === 'string') {
tmpValue = '"' + mapTo.MapToValue + '"';
} else {
tmpValue = '' + mapTo.MapToValue;
}
if (tempRBSU.Attributes[mapTo.MapToAttribute]) {
checkStr = 'tempRBSU.Attributes["' + mapTo.MapToAttribute + '"]["' + mapTo.MapToProperty + '"] === ' + tmpValue;
} else {
var menuObj = registry.RegistryEntries.Menus;
for (index in menuObj) {
if (menuObj[index][menuName] === mapTo.MapToAttribute) {
checkStr = 'menuObj[' + index + ']["' + mapTo.MapToProperty + '"] === ' + tmpValue;
}
}
}
if (!checkStr) {
console.error('Attribute not found: ' + mapTo.MapToAttribute);
continue;
}
try {
var actionStr = checkStr.replace('===', '='),
force = false;
if (tempRBSU.Attributes[mapTo.MapToAttribute] && mapTo.MapToProperty === 'CurrentValue') {
if (tempRBSU.Attributes[mapTo.MapToAttribute].CurrentValue) {
force = true;
}
}
if (!eval(checkStr)) {
returnData.modified.push({
type: tempRBSU.Attributes[mapTo.MapToAttribute] ? 'Attributes' : 'Menus',
name: mapTo.MapToAttribute,
attribute: mapTo.MapToProperty,
value: mapTo.MapToValue,
force: force,
why: mapFrom
});
eval(actionStr);
}
} catch (err) {
console.error('eval error, check string: ' + checkStr);
console.error('eval error, action string: ' + checkStr);
}
}
}
for (key in tempRBSU.Attributes) {
returnData.RBSU[key] = tempRBSU.Attributes[key].CurrentValue;
}
returnData.registry = registry;
return returnData;
}
}, {
key: 'updateRBSU',
value: function updateRBSU(registry, currentRBSU, nextRBSU) {
var data = this.validateRBSU(registry, currentRBSU, nextRBSU);
var result = isViolating(data);
if (result) {
throw result;
} else {
nextRBSU.Attributes = data.RBSU;
return rbsu.client.patch(getSettingsURI(currentRBSU), _patchData(nextRBSU, rbsu.gen9));
}
}
}, {
key: 'addPassword',
value: function addPassword(password) {
return rbsu.client.setBiosPassword(password);
}
}, {
key: 'changePassword',
value: function changePassword(rbsuData, oldPassword, newPassword) {
var passwordURL = null;
if (rbsuData && rbsuData.Actions) {
if (rbsuData.Actions['#Bios.ChangePasswords']) {
passwordURL = rbsuData.Actions['#Bios.ChangePasswords'].target;
}
}
return passwordURL ? rbsu.client.patch(passwordURL, {
PasswordName: 'Administrator',
OldPassword: oldPassword,
NewPassword: newPassword
}).then(function () {
rbsu.client.setBiosPassword(newPassword);
return true;
}) : null;
}
}, {
key: 'reset',
value: function reset(rbsuData) {
var resetURI = null;
if (rbsuData && rbsuData.Actions) {
if (rbsuData.Actions['#Bios.ResetBios']) {
resetURI = rbsuData.Actions['#Bios.ResetBios'].target;
}
}
return resetURI ? rbsu.client.post(resetURI, {
ResetType: 'default'
}).then(function (res) {
return res.body;
}) : null;
}
}]);
return rbsu;
})();
exports.rbsu = rbsu;