Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RAC-6492] Task and job for adding hotspare via WSMAN #576

Merged
merged 1 commit into from
Dec 27, 2017

Conversation

AlaricChan
Copy link
Contributor

Background
This story is to implement adding hot spare via WSMAN, replace the RACADM dependencies in Redfish API with WSMAN implementation.

Details

  1. add task, base task and job implementation, using WSMAN API.
  2. add unit tests for tasks and job

Reviewer
@yaolingling @pengz1 @nortonluo

});

it('should catch error occurred while updating xml', function() {
updateXmlJob.dell = dellConfigs

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon.

hotspareType: 'ghs'
};
updateXmlJob = new UpdateXmlJob(options, {}, uuid.v4());
this.sandbox.stub(configuration, 'get').returns(dellConfigs);;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary semicolon.

var stateChild = doc.createElement('Attribute');
stateChild.setAttribute('Name', 'RAIDPDState');
stateChild.textContent = 'Ready';
var breaklineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' is already defined.

} else {
//Update hotspare status of specified drive
for(var i = 0; i < components.length; i++) { //jshint ignore:line
var fqdd = components[i].getAttribute('FQDD');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'fqdd' is already defined.

newDriveNode.appendChild(breaklineChild);
newDriveNode.appendChild(stateChild);
breaklineChild = doc.createTextNode('\n');
newDriveNode.appendChild(breaklineChild);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

breaklineChild = doc.createTextNode('\n');
newDriveNode.appendChild(breaklineChild);
newDriveNode.appendChild(stateChild);
breaklineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

newDriveNode.appendChild(breaklineChild);
newDriveNode.appendChild(statusChild);
breaklineChild = doc.createTextNode('\n');
newDriveNode.appendChild(breaklineChild);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

breaklineChild = doc.createTextNode('\n');
newDriveNode.appendChild(breaklineChild);
newDriveNode.appendChild(statusChild);
breaklineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

stateChild.setAttribute('Name', 'RAIDPDState');
stateChild.textContent = 'Ready';
breaklineChild = doc.createTextNode('\n');
newDriveNode.appendChild(breaklineChild);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

var stateChild = doc.createElement('Attribute');
stateChild.setAttribute('Name', 'RAIDPDState');
stateChild.textContent = 'Ready';
breaklineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

fqdd = components[i].getAttribute('FQDD');
if(fqdd === self.options.driveId) {
var newDriveNode = doc.createElement('Component');
newDriveNode.setAttribute('FQDD', fqdd);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'fqdd' used out of scope.

//Update hotspare status of specified drive
for(var i = 0; i < components.length; i++) { //jshint ignore:line
fqdd = components[i].getAttribute('FQDD');
if(fqdd === self.options.driveId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'fqdd' used out of scope.

} else {
//Update hotspare status of specified drive
for(var i = 0; i < components.length; i++) { //jshint ignore:line
fqdd = components[i].getAttribute('FQDD');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'fqdd' used out of scope.

@AlaricChan AlaricChan force-pushed the raid-add-hotspare branch 3 times, most recently from 7754838 to e241676 Compare December 20, 2017 07:05
newNode.setAttribute('Name', 'RAIDdedicatedSpare');
newNode.textContent = self.options.driveId;
components[i].appendChild(newNode);
var lineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'lineChild' is defined but never used.

newNode.textContent = self.options.driveId;
components[i].appendChild(newNode);
var lineChild = doc.createTextNode('\n');
components[i].appendChild(breaklineChild);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' used out of scope.

var stateChild = doc.createElement('Attribute');
stateChild.setAttribute('Name', 'RAIDPDState');
stateChild.textContent = 'Ready';
var breaklineChild = doc.createTextNode('\n');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'breaklineChild' was used before it was defined.

logger.info('Status from SCP Microservice for RAID operation: ' + json["status"]);
if (json["status"] === "OK") {
var status = response.body.status;
logger.info('Status from SCP Microservice for RAID operation: ' + status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log is not necessary.

};

WsmanAddHotspareUpdateXmlJob.prototype.updateXmlForRaid = function() {
logger.info('Update xml for adding hotspare.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log is not necessary.

);
} else {
throw new Error('Invalid shareType in smiConfig.json. The shareType should be 0 or 2.');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't want process panic, it would be better put above code into a Promise.try()

self.dell.shareFolder.password
);
} else {
throw new Error('Invalid shareType in smiConfig.json. The shareType should be 0 or 2.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Promise.reject.

if(!self.options.volumeId) {
throw new errors.NotFoundError('The volumeId should not be empty.');
}
for(var i = 0; i < components.length; i++) { //jshint ignore:line
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use _.forEach to replace the "for" expression. This kind of expression (like i++) is not suggested by jshint

logger.info('Status from SCP Microservice for getXml: ' + json["status"]);
if (json["status"] === "OK") {
var status = response.body.status;
logger.info('Status from SCP Microservice for getXml: ' + status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary log

}
for(var i = 0; i < components.length; i++) { //jshint ignore:line
var volumeFQDD = components[i].getAttribute('FQDD');
if(volumeFQDD === self.options.volumeId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines inside if are difficult to understand, you could put them into a function.

//Update hotspare status of specified drive
for(var i = 0; i < components.length; i++) { //jshint ignore:line
var diskFQDD = components[i].getAttribute('FQDD');
if(diskFQDD === self.options.driveId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines inside if are difficult to understand, you could put them into a function.


module.exports = {
friendlyName: "Dell Wsman Add Hotspare UpdateXml Base Task",
injectableName: "Task.Base.Dell.Wsman.Add.Hotspare.UpdateXml",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, if this UpdateXml is only used for AddHostSpare, you should not create a job for it but to put in into add host spare job.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just follow the code structure design as how add-volume and delete-volume did, and reuse the common code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, A task for RackHD should be able to be executed independently with input options, it should not be coupled with other tasks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. But I prefer to create another story, to refactor these code structure in add hot spare, add volume and delete volume features.
@yaolingling


function WsmanAddHotspareUpdateXmlJob(options, context, taskId) {
WsmanAddHotspareUpdateXmlJob.super_.call(this, logger, options, context, taskId);
assert.object(this.options);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not necessary.


WsmanAddHotspareUpdateXmlJob.prototype._run = function() {
var self = this;
if(!self.options.driveId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of driveId is string. It should be self.options.driveId === ''

self.dell.shareFolder.shareName,
self.context.mountDir
);
} else if(self.dell.shareFolder.shareType === 2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shareType 0 and 2 is better to defined as a constants

Copy link
Contributor Author

@AlaricChan AlaricChan Dec 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/*
* Dedicated hotspare should be added into corresponding volume
*/
WsmanAddHotspareUpdateXmlJob.prototype.UpdateVolumeElement = function(doc) {
Copy link
Contributor

@yyscamper yyscamper Dec 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming style suggestion: the PascalCase style function name is usually used for constructer or class, for function, use camelCase instead.

The same for function UpdateDiskElement

};
updateXmlJob.dell = config;
this.sandbox.stub(smb2Clinet.prototype, 'readFile').resolves(xmlData);
this.sandbox.stub(smb2Clinet.prototype, 'writeFile');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since writeFile is a promise, so also stub it as promise

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean that I should let the writeFile stub call resolves(), instead of leaving the stub call its default action, maybe returns() or any else? @yyscamper

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a thought that, in this test case whether the writeFile return a promise or return a value, it is not a key point. Just let the UT ensure the promise chain could be fulfilled. Is that right?
Whatever, it could be funny to dig into the default behavior of stub.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the function is a promise, but you not stub it as a promise, your unit-test case may not find the potential problem.

Just like my purpose is to test A, but my test stubs it as B, so I am testing B, even B passes, I still cannot make sure A is OK.

newDriveNode.appendChild(breakLineChild);
newDriveNode.appendChild(statusChild);

breakLineChild = doc.createTextNode('\n');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is duplicated with line 152

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each node is identified as a instance, could not be appended to multiple nodes.

newDriveNode.appendChild(breakLineChild);
newDriveNode.appendChild(stateChild);

breakLineChild = doc.createTextNode('\n');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is duplicated with line 152

@pengz1 pengz1 merged commit 263ad90 into RackHD:master Dec 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
5 participants