Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 86 additions & 123 deletions lib/jobs/generate-enclosure.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,90 +68,41 @@ function generateEnclosureJobFactory(
var self = this;
var enclNode;

Promise.all([
Promise.any([
self._findSerialNumber(self.enclConst.snPath[0]),
self._findSerialNumber(self.enclConst.snPath[1])
]),
waterline.nodes.find({ type: self.enclConst.type })
Promise.any([
self._findSerialNumber(self.enclConst.snPath[0]),
self._findSerialNumber(self.enclConst.snPath[1])
])
.spread(self._matchEnclosure.bind(self))
.then(function (matchInfo) {
// Create an enclosure node if there isn't matched one
enclNode = matchInfo.encl;

if (_.isEmpty(enclNode)) {

var enclData = {
name: self.enclConst.namePrefix + matchInfo.sn,
type: self.enclConst.type,
relations: []
};

return waterline.nodes.create(enclData)
.then(function(node) {
if (!node) {
return Promise.reject('Could not create enclosure node');
}
enclNode = node;
logger.debug('No matched enclosure, create a new one', {
id: self.nodeId,
enclosure: enclNode.id
});
});
}
else {
logger.debug(enclNode.name + ' matched', {
id: self.nodeId,
enclosure: enclNode.id
});
.then(function(nodeSn){
var enclName = self.enclConst.namePrefix + nodeSn;
var enclData = {
name: enclName,
type: self.enclConst.type,
relations: []
};
return waterline.nodes.findOrCreate({ type: self.enclConst.type, name: enclName}, enclData);
})
.then(function(node) {
if (!node) {
return Promise.reject('Could not create enclosure node');
}
enclNode = node;
logger.debug('findOrCreate enclosure', {
id: self.nodeId,
enclosure: enclNode.id
});
})
.then(function () {
// Add compute node info into enclosure node

var enclosedNodes = self._popEnclTarget(enclNode);

if (enclosedNodes.indexOf(self.nodeId) === -1) {
// If current compute node id isn't in enclosure node, update the latter

enclosedNodes.push(self.nodeId);

enclNode.relations.push({
relationType: self.enclConst.relationEncl,
targets: enclosedNodes
});

return waterline.nodes.updateByIdentifier(
enclNode.id,
{relations: enclNode.relations});
}
// Add compute relations into enclosure node
return self.addRelation(enclNode, self.enclConst.relationEncl, self.nodeId);
})
.then(function () {
// Add enclosure node info into compute node

return waterline.nodes.findByIdentifier(self.nodeId)
.then(function (node) {
if (!node) {
return Promise.reject('Could not find node with identifier ' + self.nodeId);
}

var enclTarget = self._popEnclTarget(node);

if (enclTarget.length !== 1 ||
enclTarget.indexOf(enclNode.id) === -1) {
// If enclosedBy relation of the compute node is not this enclosure,
// update it to this enclosure node

node.relations.push({
relationType: self.enclConst.relationEnclBy,
targets: [enclNode.id]
});

return waterline.nodes.updateByIdentifier(
self.nodeId,
{relations: node.relations});
}
return self.addRelation(node, self.enclConst.relationEnclBy, enclNode);
});
})
.then(function () {
Expand Down Expand Up @@ -191,62 +142,74 @@ function generateEnclosureJobFactory(
};

/**
* Find enclosure node that matches given catalog info
*
* @param {object} nodeSn node's serial number
* @param {object} encls enclosure nodes
* @return {object} matched serial number and enclosure node
* This function is duplicated with on-http/lib/service/node-api-service.js/addRelation
* Add the given target nodes to the given relationType on the given node. Fail
* silently with missing arguments. If a relation does not already exist on the node
* create it, otherwise append to the existing one.
* @param {Object} node - node whose relation needs to be updated
* @param {String} type - relation type that needs to be updated
* @param {String[] | Object[]} targets - nodes or ids in relation type that to be added
* @return {Object} the updated node
*/
GenerateEnclosureJob.prototype._matchEnclosure = function (nodeSn, encls) {
var self = this;

return _.transform(encls, function (result, encl) {
var enclSn = encl.name.slice(self.enclConst.namePrefix.length, encl.name.length);

if (enclSn === '') {
// No serial number in enclosure name, jump to the next entry
return true;
GenerateEnclosureJob.prototype.addRelation = function addRelation(node, type, targets) {
if (!(node && type && targets)) {
return;
}
return waterline.nodes.addFieldIfNotExistByIdentifier(node.id, "relations", [])
.then(function(){
var relationsItemToBeAdded = {
relations: [{relationType: type, targets: []}]
};
var existSign = [{relationType: type}];
return waterline.nodes.addListItemsIfNotExistByIdentifier(
node.id,
relationsItemToBeAdded,
existSign
);
})
.then(function(modifiedNode){
if (!modifiedNode){
return node;
}

if (enclSn === nodeSn) {
result.encl = encl;
// Find the match and exit the loop
return false;
return modifiedNode;
})
.then(function(modifiedNode){
var targetsItems = _.map([].concat(targets), function(targetNode) {
targetNode = targetNode.id || targetNode;
if(targetNode === node.id ) {
return Promise.reject(new Error('Node cannot have relationship '+type+' with itself'));
}
return targetNode;
});
var index = _.findIndex(modifiedNode.relations, { relationType: type });
var field = ["relations.", String(index),".targets"].join("");
var targetsToBeAdded = {};
targetsToBeAdded[field] = _.uniq(targetsItems);

// Can not make sure prevent every exception in high concurrency.
if (type === 'containedBy' &&
modifiedNode.relations[index].targets.length + targets.length > 1) {
return Promise.reject(new Error("Node "+node.id+" can only be contained by one node"));
}
}, {
sn: nodeSn,
encl: {}
});
};

/**
* Get target nodes of the encloses or enclosedBy relation, and
* remove this relation type from node's relations
*
* @param {object} node
* @return {array} target nodes
*/
GenerateEnclosureJob.prototype._popEnclTarget = function (node) {
var self = this;
var enclRelation = _.find(node.relations, function(entry) {
return entry.relationType === self.enclConst.relationEncl ||
entry.relationType === self.enclConst.relationEnclBy;
});

var targetNodes = [];

if (enclRelation) {
if (enclRelation.hasOwnProperty('targets')) {
// Store existing target node id
targetNodes = enclRelation.targets;
// Compute node can only have one enclosure target.
if (type === "enclosedBy") {
var targetsToBeRemoveded = {};
targetsToBeRemoveded[field] = [modifiedNode.relations[index].targets[0]];
return waterline.nodes.removeListItemsByIdentifier(
node.id, targetsToBeRemoveded
)
.then(function(){
return targetsToBeAdded;
});
}

// Remove encloses relation
node.relations.pop(enclRelation);
}

return targetNodes;
return targetsToBeAdded;
})
.then(function(targetsToBeAdded){
return waterline.nodes.addListItemsIfNotExistByIdentifier(
node.id, targetsToBeAdded
Copy link
Member

Choose a reason for hiding this comment

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

without signs, is there any possibility that enclosure node will "encloses" one compute node more than once, if running this job multiple times?

Copy link
Member Author

Choose a reason for hiding this comment

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

Mongo list update operator won't add two same items of value type to one list.

);
});

Choose a reason for hiding this comment

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

Expected ')' and instead saw ';'.
Missing semicolon.

};

return GenerateEnclosureJob;
}
Loading