pads_app
Version:
playground of algorithms for Distributed Systems(PADS)
423 lines (377 loc) • 11.4 kB
JavaScript
/*globals define*/
/*jshint node:true, browser:true*/
/**
* Generated by PluginGenerator 0.14.0 from webgme on Wed Dec 02 2015 15:06:02 GMT-0600 (CST).
*/
define([
'text!./metadata.json',
'plugin/PluginBase',
'common/util/ejs',
'Templates/Templates',
'c2wtng-meta/modelLoader',
'c2wtng-meta/remote_utils',
'q'
], function (
pluginMetadata,
PluginBase,
ejs,
TEMPLATES,
loader,
utils,
Q) {
'use strict';
// fixed vars
var marathonIP = "129.59.107.73";
var marathonUser = 'ubuntu';
var marathonKey = '/home/jeb/.ssh/id_rsa_marathon';
var marathonUrl = "10.100.0.11";
var inputfilesServerHost = "10.100.0.11";
var inputfilesServerPort = 8081;
var logPathBase = "/mnt/nfs/demo-share/";
pluginMetadata = JSON.parse(pluginMetadata)
/**
* Initializes a new instance of RunFederation.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin RunFederation.
* @constructor
*/
var RunFederation = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
};
// Prototypal inheritance from PluginBase.
RunFederation.prototype = Object.create(PluginBase.prototype);
RunFederation.prototype.constructor = RunFederation;
RunFederation.pluginMetadata = pluginMetadata;
RunFederation.prototype.notify = function(level, msg) {
var self = this;
var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
var max_msg_len = 100;
if (level=='error')
self.logger.error(msg);
else if (level=='debug')
self.logger.debug(msg);
else if (level=='info')
self.logger.info(msg);
else if (level=='warning')
self.logger.warn(msg);
self.createMessage(self.activeNode, msg, level);
if (msg.length < max_msg_len)
self.sendNotification(prefix+msg);
else {
var splitMsgs = utils.chunkString(msg, max_msg_len);
splitMsgs.map(function(splitMsg) {
self.sendNotification(prefix+splitMsg);
});
}
};
/**
* Main function for the plugin to execute. This will perform the execution.
* Notes:
* - Always log with the provided logger.[error,warning,info,debug].
* - Do NOT put any user interaction logic UI, etc. inside this method.
* - callback always has to be called even if error happened.
*
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
RunFederation.prototype.main = function (callback) {
// Use self to access core, project, result, logger etc from PluginBase.
// These are all instantiated at this point.
var self = this;
if (typeof WebGMEGlobal !== 'undefined') {
var msg = 'You must run this plugin on the server!';
self.notify('error', msg);
callback(new Error(msg), self.result);
}
// make sure it's always unique!
var timestamp = (new Date()).getTime();
self.basePath = '/home/vagrant/nistDemo/'+timestamp ;
self.inputPrefix = self.basePath + '/input/';
self.outputPrefix = self.basePath + '/output/';
// What did the user select for our configuration?
var currentConfig = self.getCurrentConfig();
self.deploymentFiles = currentConfig.deploymentFiles;
self.runLocally = currentConfig.runLocally;
self.projectName = self.core.getAttribute(self.rootNode, 'name');
var modelNode = self.activeNode;
self.modelName = self.core.getAttribute(modelNode, 'name');
self.dockerInfoMap = {
'JavaFed': {
'name': 'cpswt/c2wtcore_v002',
'tag': '160816'
},
'CppFed': {
'name': 'cpswt/c2wtcore_v002',
'tag': '160816'
},
'OmnetFed': {
'name': 'cpswt/c2wtcore_v002',
'tag': '160816'
},
};
var path = require('path');
var filendir = require('filendir');
self.root_dir = path.join(process.cwd(),
'generated',
self.project.projectId,
self.branchName,
'models');
return loader.loadModel(self.core, modelNode)
.then(function(federationModel) {
self.pads_datamodel = pads_datamodel;
})
.then(function() {
return self.renderDockerFile();
})
.then(function() {
return self.renderStartScript();
})
.then(function() {
return self.createInputsFolder();
})
.then(function() {
return self.writeInputs();
})
.then(function() {
return self.runSimulation();
})
.then(function() {
return self.copyArtifacts();
})
.then(function() {
self.result.success = true;
self.notify('info', 'Simulation Complete.');
callback(null, self.result);
})
.catch(function(err) {
self.notify('error', err);
self.result.success = false;
callback(err, self.result);
});
};
RunFederation.prototype.renderDockerFile = function() {
// render docker compose file with federate type + shared folder name + command
var self = this;
self.fedInfos = [];
if (self.pads_datamodel.JavaFederate_list) {
self.pads_datamodel.JavaFederate_list.map((fed) => {
self.fedInfos.push({
name: fed.name,
type: 'JavaFed'
});
});
}
if (self.pads_datamodel.CppFederate_list) {
self.pads_datamodel.CppFederate_list.map((fed) => {
self.fedInfos.push({
name: fed.name,
type: 'CppFed'
});
});
}
self.dockerFileData = ejs.render(
TEMPLATES['topologyFileTemplate.ejs'],
{
inputPrefix: self.inputPrefix,
outputPrefix: self.outputPrefix,
fedInfos: self.fedInfos,
dockerInfoMap: self.dockerInfoMap
}
);
var path = require('path'),
filendir = require('filendir'),
fileName = 'docker-compose.yml';
var deferred = Q.defer();
filendir.writeFile(path.join(self.basePath, fileName), self.dockerFileData, function(err) {
if (err)
deferred.reject(err);
else
deferred.resolve();
});
return deferred.promise;
};
RunFederation.prototype.renderStartScript = function() {
// render docker compose file with federate type + shared folder name + command
var self = this;
self.startScriptData = ejs.render(
TEMPLATES['startScript.ejs'], {}
);
};
RunFederation.prototype.createInputsFolder = function() {
var self = this;
var path = require('path'),
filendir = require('filendir'),
fileName = 'start.sh';
var tasks = self.fedInfos.map((fedInfo) => {
var deferred = Q.defer();
filendir.writeFile(path.join(
self.inputPrefix + fedInfo.name, fileName), self.startScriptData, function(err) {
if (err)
deferred.reject(err);
else
deferred.resolve();
});
return deferred.promise;
});
return Q.all(tasks)
.then(function() {
var deferred = Q.defer();
filendir.writeFile(path.join(self.inputPrefix + 'FedManager', fileName),
self.startScriptData, function(err) {
if (err)
deferred.reject(err);
else
deferred.resolve();
});
return deferred.promise;
});
};
RunFederation.prototype.writeInputs = function() {
// Copy the user input files (pom + xml + fed) into docker shared folder
var self = this;
var fs = require('fs'),
path = require('path'),
unzip = require('unzip'),
stream = require('stream'),
fstream = require('fstream');
return self.blobClient.getMetadata(self.deploymentFiles)
.then(function(metaData) {
self.deploymentFilesName = metaData.name;
return self.blobClient.getObject(self.deploymentFiles);
})
.then(function(objBuffer) {
self.zipBuffer = new Buffer(objBuffer);
var tasks = self.fedInfos.map((fedInfo) => {
var writeStream = fstream.Writer(self.inputPrefix+fedInfo.name);
var deferred = Q.defer();
writeStream.on('unpipe', () => {
deferred.resolve();
});
var bufferStream = new stream.PassThrough();
bufferStream.end(self.zipBuffer);
bufferStream
.pipe(unzip.Parse())
.pipe(writeStream);
return deferred.promise;
});
return Q.all(tasks);
})
.then(function() {
var writeStream = fstream.Writer(self.inputPrefix+'FedManager');
var deferred = Q.defer();
writeStream.on('unpipe', () => {
deferred.resolve();
});
var bufferStream = new stream.PassThrough();
bufferStream.end(self.zipBuffer);
bufferStream
.pipe(unzip.Parse())
.pipe(writeStream);
return deferred.promise;
});
};
RunFederation.prototype.runSimulation = function() {
var self = this;
var path = require('path');
var cp = require('child_process');
self.notify('info', 'Starting Simulation');
return self.startFederates()
.then(function() {
return self.killFederates();
});
};
RunFederation.prototype.startFederates = function() {
// run-cpp-feds.sh
var self = this;
var cp = require('child_process');
var deferred = Q.defer();
var fedMgr = cp.spawn('bash', [], {cwd:self.basePath});
fedMgr.stdout.on('data', function (data) {
self.logger.error('STDOUT::'+data);
});
fedMgr.stderr.on('data', function (error) {
self.logger.error('STDERR::'+error);
});
fedMgr.on('exit', function (code) {
if (code == 0) {
self.notify('info', 'Started Federates.');
deferred.resolve(code);
}
else {
self.notify('error', 'error code: ' + code);
deferred.reject('federates:: child process exited with code ' + code);
}
});
setTimeout(function() {
self.notify('info', 'Starting Federates.');
fedMgr.stdin.write('sudo docker-compose up\n');
fedMgr.stdin.end();
}, 1000);
return deferred.promise;
};
RunFederation.prototype.killFederates = function() {
// kill-all.sh
var self = this;
var cp = require('child_process');
var deferred = Q.defer();
var stopFeds = cp.spawn('bash', [], {cwd:self.basePath});
stopFeds.stdout.on('data', function (data) {});
stopFeds.stderr.on('data', function (error) {
});
stopFeds.on('exit', function (code) {
if (code == 0) {
self.notify('info', 'Killed all experiment feds.');
deferred.resolve(code);
}
else {
deferred.reject('stopFeds:: child process exited with code ' + code);
}
});
setTimeout(function() {
self.notify('info', 'Killing experiment feds.');
//stopFeds.stdin.write('docker stop $(docker ps -a -q)\n');
stopFeds.stdin.write('sudo docker-compose down\n');
stopFeds.stdin.end();
}, 1000);
return deferred.promise;
};
RunFederation.prototype.copyArtifacts = function() {
var self = this;
self.notify('info', 'Copying output.');
return new Promise(function(resolve, reject) {
var zlib = require('zlib'),
tar = require('tar'),
fstream = require('fstream'),
input = self.outputPrefix;
var bufs = [];
var packer = tar.Pack()
.on('error', function(e) { reject(e); });
var gzipper = zlib.Gzip()
.on('error', function(e) { reject(e); })
.on('data', function(d) { bufs.push(d); })
.on('end', function() {
var buf = Buffer.concat(bufs);
self.blobClient.putFile('output.tar.gz',buf)
.then(function (hash) {
self.result.addArtifact(hash);
resolve();
})
.catch(function(err) {
reject(err);
})
.done();
});
var reader = fstream.Reader({ 'path': input, 'type': 'Directory' })
.on('error', function(e) { reject(e); });
reader
.pipe(packer)
.pipe(gzipper);
})
.then(function() {
self.notify('info', 'Created archive.');
});
};
return RunFederation;
});