Skip to content

Commit

Permalink
Merge pull request #510 from nortonluo/master
Browse files Browse the repository at this point in the history
Refine firmware file upload method for EMC diag firmware update job
  • Loading branch information
iceiilin committed Sep 15, 2017
2 parents 29be06d + af2c90d commit 9bdf4b2
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 97 deletions.
20 changes: 10 additions & 10 deletions lib/jobs/emc-diag-update-firmware.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ function diagUpdateFirmwareFactory(
DiagUpdateFirmware.super_.call(this, logger, options, context, taskId);

this.nodeId = this.context.target;
this.localImagePath = options.localImagePath;
this.imageUrl = options.imageUrl;
this.imageName = options.imageName;
this.imageMode = options.imageMode;
this.firmwareName = options.firmwareName;
this.firmwareType = options.firmwareType;
this.skipReset = options.skipReset || false;
this.diagImagePath = '/uploads';
this.biosModeMapping = {
this.spiModeMapping = {
'fullbios': '0',
'bios': '1',
'uefi': '2',
Expand Down Expand Up @@ -72,10 +72,10 @@ function diagUpdateFirmwareFactory(
return self.diagTool.getAllDevices();
})
.then(function(){
return self.diagTool.uploadImageFile(self.localImagePath);
return self.diagTool.uploadImageFile(self.imageUrl, self.imageName, '/api/upload/file');
})
.then(function(){
var method = 'update' + _.capitalize(self.firmwareName);
var method = 'update' + _.capitalize(self.firmwareType);
return self[method](self.imageName, self.imageMode, self.diagImagePath);
})
.then(function(){
Expand Down Expand Up @@ -107,11 +107,11 @@ function diagUpdateFirmwareFactory(
* '5'/5/'me' - ME
* @return {String} mode string, a value of '0' - '5'
*/
DiagUpdateFirmware.prototype.parseBiosMode = function(mode){
DiagUpdateFirmware.prototype.parseSpiMode = function(mode){
var self = this;
var _mode = parseInt(mode);
if (_.isNaN(_mode)){
_mode = self.biosModeMapping[mode];
_mode = self.spiModeMapping[mode];
} else {
_mode = _(mode).toString();
}
Expand Down Expand Up @@ -164,11 +164,11 @@ function diagUpdateFirmwareFactory(
* @param {String} diagImagePath: image file path in diag system
* @return {Promise}
*/
DiagUpdateFirmware.prototype.updateBios = function(imageName, imageMode, diagImagePath){
DiagUpdateFirmware.prototype.updateSpi = function(imageName, imageMode, diagImagePath){
var self = this;
var _imageMode = self.parseBiosMode(imageMode);
var _imageMode = self.parseSpiMode(imageMode);
assert.isIn(_imageMode, ['0', '1', '2', '3', '4', '5']);
return self.diagTool.updateFirmware('bios', imageName, _imageMode, diagImagePath)
return self.diagTool.updateFirmware('spi', imageName, _imageMode, diagImagePath)
.then(function(body){
var resetFlag;
var error;
Expand Down
32 changes: 19 additions & 13 deletions lib/task-data/schemas/emc-diag-update-firmware.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"copyright": "Copyright 2017, Dell EMC, Inc.",
"definitions": {
"localImagePath": {
"description": "Image zip file path",
"imageUrl": {
"description": "Image URL in on-http",
"type": "string",
"pattern": "^/.*\\.zip$"
"pattern": ".*\\.bin$"
},
"imageMode": {
"description": "Update mode",
Expand All @@ -18,28 +18,34 @@
},
"imageName": {
"description": "Image bin file name",
"type": "string",
"pattern": ".*.bin$"
"type": "string"
},
"firmwareName": {
"description": "Name of firmware to be updated",
"firmwareType": {
"description": "Type of firmware to be updated",
"type": "string",
"enum": ["bios", "bmc"]
"enum": ["spi", "bmc"]
},
"skipReset": {
"description": "Whether skip reset SP after firmware update",
"type": "boolean"
}
},
"properties": {
"imageName": {
"$ref": "#/definitions/imageName"
},
"localImagePath": {
"$ref": "#/definitions/localImagePath"
"imageUrl": {
"$ref": "#/definitions/imageUrl"
},
"imageMode": {
"$ref": "#/definitions/imageMode"
},
"firmwareName": {
"$ref": "#/definitions/firmwareName"
"firmwareType": {
"$ref": "#/definitions/firmwareType"
},
"skipReset": {
"$ref": "#/definitions/skipReset"
}
},
"required": ["imageName", "imageMode", "firmwareName"]
"required": ["imageUrl", "firmwareType", "imageName", "imageMode"]
}
76 changes: 34 additions & 42 deletions lib/utils/job-utils/diag-tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@ function diagToolFactory(Promise, _, Logger, assert) {
settings.port || '8080'
);
this.nodeId = nodeId;
this.serverIp = settings.host;
this.platformDevice = {};
this.spDevice = {};
this.spChildren = [];
// Define device names required in test API
this.deviceMap = {
bmcUpdate: "BMC_EMC_OEM",
biosUpdate: "SPIROM",
spiUpdate: "SPIROM",
sp: "",
platform: ""
};
// Define device names used to get slot required in test API
// For devices that are children of spChildren, to avoid recursive http querying,
// Define device names used to get slot required in test API
// For devices that are children of spChildren, to avoid recursive http querying,
// slot is retrieve slot from spChildren.
// It is based on the suppose that spChildren and all its children have the same slot id
// Slot ids of platformDevice, spDevice, spChildren should be retrieved with device names
Expand All @@ -43,54 +44,45 @@ function diagToolFactory(Promise, _, Logger, assert) {

var logger = Logger.initialize(diagToolFactory);

/**
* Wrap fs.createReadStream as Promise
* @param {String} filename: file to be read to stream
* @return {Promise}
*/
function _createReadStream(filename){
return new Promise(function(resolve, reject){
var stream;
function _onError(err){
reject(err);
}

function _onReadable(){
_cleanup();
resolve(stream);
}

function _cleanup(){
stream.removeListener('readable', _onReadable);
stream.removeListener('error', _onError);
}

stream = fs.createReadStream(filename);
stream.on('error', _onError);
stream.on('readable', _onReadable);
});
}

/**
* Diag upload image file API
* @param {String} imageFilePath: local file path for the image to be uploaded
* @param {String} imageUrl: Image file url link in on-httpi
* @param {String} imageName: Image file name
* @param {String} uploadApi: diag API used to upload file
* @return {Promise}
*/
DiagToolFactory.prototype.uploadImageFile = function(imageFilePath, uploadApi){
DiagToolFactory.prototype.uploadImageFile = function(imageUrl, imageName, uploadApi){
var self = this;
var api = uploadApi || '/api/upload/folder';

var options = {
var api = uploadApi || '/api/upload/file';
//Use customized HTTP header to make on-http fetch the file in skupack
var optionsGet = {
uri: imageUrl,
method: 'GET',
encoding: null,
headers:{
'X-Real-IP': self.serverIp
}
};
var optionsPost = {
uri: self.server + api,
method: 'POST'
method: 'POST',
encoding: null
};
return _createReadStream(imageFilePath)
return request(optionsGet)
.then(function(stream){
options.formData = {file: stream};
optionsPost.formData = {
name: imageName,
file:{
value : stream,
options:{
filename: imageName,
contentType: 'application/octet-stream'
}
}
};
})
.then(function(){
return request(options);
return request(optionsPost);
});
};

Expand Down Expand Up @@ -150,7 +142,7 @@ function diagToolFactory(Promise, _, Logger, assert) {
case 'bmc':
modeConfig = {"value": mode, "base": "hex", "name": "image_id"};
break;
case 'bios':
case 'spi':
modeConfig = {"value": mode, "base": "dec", "name": "mode"};
break;
default:
Expand Down Expand Up @@ -274,7 +266,7 @@ function diagToolFactory(Promise, _, Logger, assert) {

/**
* Get device slot id
* @param {String} key: device key used to get device name
* @param {String} key: device key used to get device name
*/
DiagToolFactory.prototype.getSlotByDeviceKey = function(deviceKey){
var self = this;
Expand Down
60 changes: 48 additions & 12 deletions spec/lib/jobs/emc-diag-update-firmware-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ describe('update firmware by diag', function(){
var nodeId = uuid.v4();
var context = {target: nodeId, nodeIp: "172.31.128.6"};
var options = {
localImagePath: "/home/onrack/Oberon_EMC_test.zip",
imageUrl: "http://172.31.128.1:9080/emc_c_bios_oberon_5042.bin",
imageName: "emc_c_bios_oberon_5042.bin",
firmwareName: 'bios'
firmwareType: 'spi'
};
var updateBiosResult = {
"result": [
Expand All @@ -34,7 +34,28 @@ describe('update firmware by diag', function(){
}
]
};

var updateBiosFailResult = {
"result": [
{
"error": {
"device_name": "SPIROM",
"error_code": "1000000080020301",
"error_detail": [
"CoreId: 8",
"Update firmware got an exception"
],
"error_group": "Errors",
"guid": "07dc05d4-6d87-11e7-89a1-0060166fb462",
"timestamp": "2017-07-20 20:23:46.440809"
}
},
{
"atomic_test_end": {
"timestamp": "2017-07-20 20:23:46.445271"
}
}
]
};
var sandbox = sinon.sandbox.create();
var diagTool = {};
function DiagTool() {return diagTool;}
Expand Down Expand Up @@ -84,7 +105,7 @@ describe('update firmware by diag', function(){
});

it('should run update bios job with integer mode and reset', function() {
var _options = _.defaults({firmwareName: 'bios', imageMode: 1}, options);
var _options = _.defaults({firmwareType: 'spi', imageMode: 1}, options);
job = new UpdatefirmwareJob(_options, context, taskId);
sandbox.spy(job, '_done');
return job._run()
Expand All @@ -96,9 +117,9 @@ describe('update firmware by diag', function(){
expect(diagTool.warmReset).to.be.calledOnce;
expect(job._done).to.be.calledOnce;
expect(diagTool.retrySyncDiscovery).to.be.calledWith(5000, 6);
expect(diagTool.uploadImageFile).to.be.calledWith(options.localImagePath);
expect(diagTool.uploadImageFile).to.be.calledWith(options.imageUrl, options.imageName);
expect(diagTool.updateFirmware).to.be.calledWith(
'bios',
'spi',
options.imageName,
'1',
'/uploads'
Expand All @@ -108,13 +129,13 @@ describe('update firmware by diag', function(){
});

it('should run update bios job with mode name and without reset', function() {
var _options = _.defaults({imageMode: 'bios', skipReset: true}, options);
var _options = _.defaults({firmwareType: 'spi', imageMode: 'bios', skipReset: true}, options);
job = new UpdatefirmwareJob(_options, context, taskId);
sandbox.spy(job, '_done');
return job._run()
.then(function(){
expect(diagTool.updateFirmware).to.be.calledWith(
'bios',
'spi',
options.imageName,
'1',
'/uploads'
Expand All @@ -130,7 +151,22 @@ describe('update firmware by diag', function(){
sandbox.stub(job, '_done').resolves();
updateBiosResult.result[1].atomic_test_data.secure_firmware_update = '';
diagTool.updateFirmware.reset();
diagTool.updateFirmware.resolves(updateBiosResult);
return job._run()
.then(function(){
expect(job._done).to.be.calledOnce;
expect(job._done.args[0][0].message).to.equal(
'Failed to get reset flags from diag'
);
});
});

it('should throw firmware update error', function() {
var _options = _.defaults({imageMode: '1'}, options);
job = new UpdatefirmwareJob(_options, context, taskId);
sandbox.stub(job, '_done').resolves();
updateBiosResult.result[1].atomic_test_data.secure_firmware_update = '';
diagTool.updateFirmware.reset();
diagTool.updateFirmware.resolves(updateBiosFailResult);
return job._run()
.then(function(){
expect(job._done).to.be.calledOnce;
Expand All @@ -143,7 +179,7 @@ describe('update firmware by diag', function(){

describe('bmc update', function(){
it('should run update bmc firmware job', function() {
var _options = _.defaults({firmwareName: 'bmc', imageMode: '0x5f'}, options);
var _options = _.defaults({firmwareType: 'bmc', imageMode: '0x5f'}, options);
job = new UpdatefirmwareJob(_options, context, taskId);
sandbox.spy(job, '_done');
return job._run()
Expand All @@ -155,7 +191,7 @@ describe('update firmware by diag', function(){
expect(diagTool.bmcReset).to.be.calledOnce;
expect(job._done).to.be.calledOnce;
expect(diagTool.retrySyncDiscovery).to.be.calledWith(5000, 6);
expect(diagTool.uploadImageFile).to.be.calledWith(options.localImagePath);
expect(diagTool.uploadImageFile).to.be.calledWith(options.imageUrl, options.imageName);
expect(diagTool.updateFirmware).to.be.calledWith(
'bmc',
options.imageName,
Expand All @@ -168,7 +204,7 @@ describe('update firmware by diag', function(){

it('should run update bmc firmware job with mode name and without reset', function() {
var _options = _.defaults(
{firmwareName: 'bmc', imageMode: 'fullbmc', skipReset: true},
{firmwareType: 'bmc', imageMode: 'fullbmc', skipReset: true},
options
);
job = new UpdatefirmwareJob(_options, context, taskId);
Expand Down
Loading

0 comments on commit 9bdf4b2

Please sign in to comment.