This commit is contained in:
wmantly committed 2016-01-29 14:49:03 -05:00
1 parent 9026010aa1
commit 9ce292e020
12 files changed
+573

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', users);
app.use('/api', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Executable
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('manager:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '2000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
+125
View File
@@ -0,0 +1,125 @@
module.exports = function(config){
var obj = {};
var child = require('child'),
sshBind = config.sshBind || false;
//http://stackoverflow.com/questions/10530532/
function textToArgs(s){
var words = [];
s.replace(/"([^"]*)"|'([^']*)'|(\S+)/g,function(g0,g1,g2,g3){ words.push(g1 || g2 || g3 || '')});
return words;
}
var sysExec = function(command, onData, onClose){
onData = onData || function(){};
onClose = onClose || function(){};
if (sshBind != false)
{
var runCommand = sshBind.slice();
runCommand.push(command);
} else {
var runCommand = textToArgs(command);
}
var errors = '';
child({
command: runCommand.slice(0,1)[0],
args: runCommand.slice(1),
cbStdout: function(data){ onData(''+data) },
cbStderr: function(data){ errors+=data; onData(''+data) },
cbClose: function(exitCode){ onClose(exitCode == 0 ? null:exitCode, errors) }
}).start();
};
obj.create = function(name, template, config, cbComplete, cbData){
sysExec('lxc-create -n '+name+' -t '+template, cbComplete, cbData);
};
obj.clone = function(name, base_name, cbComplete, cbData){
sysExec('lxc-clone -o '+base_name+ ' -n '+name +' -B overlayfs -s', cbComplete, cbData);
};
obj.destroy = function(name, cbComplete, cbData){
sysExec('lxc-destroy -n '+ name, cbComplete, cbData);
};
obj.start = function(name, cbComplete, cbData){
var cmd = 'lxc-start --name '+name+' --daemon';
console.log('start cmd\n', cmd, '\n');
sysExec(cmd, cbComplete, cbData);
};
obj.startEphemeral = function(name, base_name, cbComplete, cbData){
var output = '';
sysExec('lxc-start-ephemeral -o '+base_name+ ' -n '+name +' --union-type overlayfs -d', function(data){output+=data}, function(error){
if(output.match("doesn't exist.")) return cbData({status: 500, error: "doesn't exist."});
if(output.match("already exists.")) return cbData({status: 500, error: "already exists"});
if(output.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)) return cbData({status: 200, state:'RUNNING', ip: output.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)[0]});
cbData({'?': '?', data: output, name: name, base_name: base_name});
});
};
obj.stop = function(name, cbComplete, cbData){
sysExec('lxc-stop -n '+ name, cbComplete, cbData);
};
obj.freeze = function(name, cbComplete, cbData){
sysExec('lxc-freeze -n '+name, cbComplete, cbData);
};
obj.unfreeze = function(name, cbComplete, cbData){
sysExec('lxc-unfreeze -n '+name, cbComplete, cbData);
};
obj.info = function(name, cbComplete, cbData){
var output = '';
sysExec('lxc-info -n'+name, function(data){output+=data}, function(error){
if(output.match("doesn't exist")) return cbData({state: 'NULL'});
var info = {};
output = output.replace(/\suse/ig, '').replace(/\sbytes/ig, '').split("\n").slice(0,-1);
for(var i in output){
var temp = output[i].split(/\:\s+/);
info[temp[0].toLowerCase().trim()] = temp[1].trim();
}
cbData(info);
});
};
obj.list = function(cbData){
var output = '';
sysExec('lxc-ls --fancy', function(data){output+=data}, function(error){
output = output.split("\n");
var keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1);
keys = keys.map(function(v){return v.toLowerCase()});
output = output.slice(0).splice(1).slice(0,-1);
var info = [];
for (var i in output)
{
var aIn = output[i].split(/\s+/).slice(0,-1),
mapOut = {};
aIn.map( function(v,i){ mapOut[keys[i]] = v; } );
info.push(mapOut);
}
cbData(info);
});
};
return obj;
};
+17
View File
@@ -0,0 +1,17 @@
{
"name": "manager",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.13.2",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"ejs": "~2.3.3",
"express": "~4.13.1",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+24
View File
@@ -0,0 +1,24 @@
<!DOCTYPE html><html lang="en"><head prefix="og: http://ogp.me/ns#"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"><title>loading.io - Your SVG + GIF Ajax Loading Icons</title><meta property="og:locale" content="zh_TW"><meta property="og:image" content="http://loading.io/icons/gears/main.png"><meta property="og:image:type" content="image/svg+xml"><meta property="og:image:width" content="64"><meta property="og:image:height" content="64"><meta property="og:type" content="website"><meta property="og:url" content="http://loading.io/loader/?key=undefined"><meta property="og:title" content="loading.io - Your SVG + GIF Ajax Loading Icons"><meta property="og:description" content="A customized 'gears' loading icon built with loading.io, in SVG / CSS / GIF format"><meta name="twitter:card" content="summary"><meta name="twitter:site" content="@loadingio"><meta name="twitter:title" content="loading.io - Your SVG + GIF Ajax Loading Icons"><meta name="twitter:description" content="A customized 'gears' loading icon built with loading.io, in SVG / CSS / GIF format"><meta name="twitter:creator" content="@loadingio"><meta name="twitter:image" content="http://loading.io/icons/gears/main.png"><link rel="icon" type="image/x-icon" href="/assets/img/favicon.png"><link rel="stylesheet" type="text/css" href="/assets/bootstrap/3.3.5/css/bootstrap.min.css"><link rel="stylesheet" type="text/css" href="/assets/fontawesome/4.3.0/css/font-awesome.min.css"><script type="text/javascript" src="/assets/jquery/1.10.2/jquery.min.js"></script><script type="text/javascript" src="/assets/d3js/3.3.11/d3.v3.min.js"></script><script type="text/javascript" src="/assets/angular/1.3.15/angular.min.js"></script><script type="text/javascript" src="/assets/bootstrap/3.3.5/js/bootstrap.min.js"></script><link rel="stylesheet" type="text/css" href="/css/index.css?26"><link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/einojbmllcjnkcapgajdbjjnpibkjnhh"><script type="text/javascript" src="/global"></script><script type="text/javascript" src="/js/index.js"></script><script type="text/javascript" src="/assets/clipboard/1.3.1/clipboard.min.js"></script></head><body ng-app="loadingIO" ng-controller="ldMain" id="iconview"><div id="nav-top"><nav role="navigation" class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header"><a href="/" class="navbar-brand">LOADING.IO</a></div><div><ul class="nav navbar-nav"><li id="nav-loader"><a href="/">LOADER</a></li><li id="nav-palette" class="dropdown"><a data-toggle="dropdown">PALETTE <span class="caret"></span></a><ul class="dropdown-menu"><li><a href="/color/">Editor</a></li><li><a href="/color/random/">Random</a></li></ul></li></ul><ul ng-cloak class="nav navbar-nav pull-right"><li ng-show="!user.data"><a id="nav-login" href="#" ng-click="auth.show=!!!auth.show"><i class="fa fa-sign-in"></i>&nbsp; <span>LOGIN / SIGNUP</span></a></li><li id="nav-profile" ng-show="user.data" class="dropdown"><div data-toggle="dropdown" class="btn"><div ng-attr-style="background-image:url({{user.data.avatar || '/assets/img/avatar.png'}})" class="avatar"></div><span class="caret"></span></div><ul class="dropdown-menu"><li><a href="/me/">Profile</a></li><li><a href="/me/edit/">Setting</a></li><li class="divider"></li><li><a href="#" ng-click="auth.logout()">Logout</a></li></ul></li><li class="heart"><a href="#">&#x2764;</a></li></ul></div></div></nav></div><div id="authpanel-outer" ng-class="{'active':auth.show || auth.stick}"><div id="authpanel-inner"><div ng-show="!auth.stick" ng-click="auth.show=!!!auth.show" class="close-btn"><i class="glyphicon glyphicon-remove"></i></div><div class="title">LOADING.IO</div><div class="form"><a ng-attr-href="/u/auth/facebook?nexturl={{nexturl}}" class="btn btn-primary btn-block">Login With Facebook</a><br><div class="or"></div><br><div ng-show="auth.failed" ng-cloak class="error">{{auth.failed}}</div><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span><input type="text" ng-model="auth.email" placeholder="email" ng-keydown="auth.keyHandler($event)" class="form-control"></div><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span><input type="password" ng-model="auth.passwd" placeholder="password" ng-keydown="auth.keyHandler($event)" class="form-control"></div><div ng-click="auth.login()" class="btn btn-danger btn-block"> <span ng-show="auth.model!='signup'">Login</span><span ng-show="auth.model=='signup'">Sign up</span></div><div ng-show="auth.model!='signup'" ng-click="auth.model='signup'" class="hint pull-right">Sign up</div><div ng-cloak ng-show="auth.model=='signup'" ng-click="auth.model='login'" class="hint pull-right">Log In</div><div class="hint hidden">forgot password ?</div></div></div></div><div id="notifications"><div ng-repeat="n in notifications" ng-class="'notify-'+n.type" ng-cloaLine truncated
&#60;div class='uil-battery-demo-css' style='-webkit-transform:scale(0.6)'&#62;
&#60;outer&#62;&#60;/outer&#62;
&#60;inner&#62;&#60;/inner&#62;
&#60;inner&#62;&#60;/inner&#62;
&#60;inner&#62;&#60;/inner&#62;
&#60;inner&#62;&#60;/inner&#62;
&#60;/div&#62;</div><p>will look like this:</p><link rel="stylesheet" type="text/css" href="/assets/icon/examples/battery.css"><div style="-webkit-transform:scale(0.6)" class="uil-battery-demo-css"><div class="outer"></div><div class="inner"></div><div class="inner"></div><div class="inner"></div><div class="inner"></div></div><br><h4>GIF Loader</h4><p>Use GIF loader in an &#60;img&#62; tag or as background of another element:</p><div class="code">&#60;img src="spinner.gif"&#62;
&#60;div style="background:url(spinner.gif) no-repeat center center;width:32px;height:32px;"&#62;&#60;/div&#62;</div><p>
For example:</p><div style="background-image:url(/assets/img/default-loader.gif)" class="icon-block-sample"></div><br></div></div><br><div class="section color3"><a id="icon-compatibility" class="hash-anchor"></a><h3 class="tag">Browser Compatibility</h3><div class="content"><h4>tl;dr</h4><p>
Use <b>GIF loader</b> if you need compatibility in<b> Internet Explorer.</b></p><br><h4>SVG Loader <small> ( not for IE )</small></h4><p>All SVG loaders use SMIL to animate elements. Modern browsers support SVG and SMIL except Internet Explorer:<ul><li>SVG: IE &#x2265; 9.0</li><li>SMIL: IE doesn't Support</li></ul></p><br><h4>CSS Loader <small> ( IE &#x2265; 10.0 )</small></h4><p>All CSS loaders use CSS3 Animation to animate elements. Modern browsers support CSS3 except Internet Explorer:<ul><li>CSS3 Animation: IE &#x2265; 10.0</li><li>CSS3 Transform: IE &#x2265; 10.0 (partially)</li></ul></p><br><h4>
GIF Loader <small> ( cross-platform )</small></h4><p>All modern browsers support GIF loader. Use GIF loader to ensure optimized browser compatibility.</p><br></div></div><br><div class="section color2"><a id="icon-about" class="hash-anchor"></a><h3 class="tag">This Tool</h3><div class="content"><p>This tool is tested against following browsers:<ul><li>Google Chrome 34.0.</li><li>Firefox 28.0</li><li>Safari 7.03</li><li>Opera 18.0.</li><li>Internet Explorer 11.0</li></ul></p><p>It's built upon <a href="http://getbootstrap.com">bootstrap</a>, <a href="https://angularjs.org/">angularjs</a>, <a href="https://code.google.com/p/canvg/">canvg</a>, <a href="http://jnordberg.github.io/gif.js/">gif.js</a> and <a href="http://caniuse.com/webworkers">web workers</a>. It's known that some browsers ( e.g., IE10 ) are not supported, so please upgrade your browser if you want to use this tool.</p></div></div><div id="icon-getlink-modal" class="getlink-modal modal fade"><div class="modal-dialog"><div class="modal-content"><div class="modal-body"><div class="form-group"><input id="icon-getlink-input" ng-model="build.shareLink" type="text" class="form-control"></div><a ng-attr-href="{{build.shareLink}}" target="_blank" class="btn btn-primary btn-sm">Open in New Tab</a><span>&nbsp; </span><div data-clipboard-target="#icon-getlink-input" class="btn btn-primary btn-sm copy">Copy to Clipboard</div><span>&nbsp; </span><a ng-attr-href="http://twitter.com/intent/tweet?url={{build.shareLink}}&amp;hashtags=loadingio" style="padding: 1px 10px 5px" class="btn btn-primary btn-sm">Tweet This <big><i style="margin-top:5px" class="fa fa-twitter"></i></big></a><div data-dismiss="modal" class="btn btn-default btn-sm pull-right">Dismiss</div></div></div></div></div><div id="output-modal" class="modal fade"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" data-dismiss="modal" aria-hidden="true" class="close">&times;</button><h2 class="modal-title">Build Complete!</h2></div><div ng-cloak class="modal-body"><div id="output-box"></div>Here is the requested {{mode}}<div class="glyphicon glyphicon-circle-arrow-up"></div></div><div class="modal-footer"><a id="output-box-link" href="#" ng-cloak class="btn btn-success">Download {{mode}}</a><div data-dismiss="modal" class="btn btn-default">Dismiss</div></div></div></div></div><br><div style="background:rgba(255,255,255,0.8)" class="section color1"><a id="icon-comment" class="hash-anchor"></a><h3 class="tag">Comments</h3><div id="icon-comment-box" class="content"><div class="ib"><div data-href="http://loading.io" data-width="100%" data-numposts="5" data-colorscheme="light" class="fb-comments"></div></div></div></div></div><div id="footer-top"></div><div id="footer"><div class="ib"><a id="eula"> <i class="glyphicon glyphicon-info-sign"></i><span>Term of Use</span></a><a id="pap" href="/privacy.html"><i class="glyphicon glyphicon-info-sign"></i><span>Privacy Policy</span></a><a id="attribution"><i class="glyphicon glyphicon-heart-empty"></i><span>Attribution</span></a><a id="about"><i class="glyphicon glyphicon-globe"></i><span>About Us</span></a><div style="float:right;" data-href="http://loading.io" data-layout="button_count" data-action="like" data-show-faces="true" data-share="true" class="fb-like"></div></div></div><link rel="stylesheet" type="text/css" href="/assets/ldColorPicker/ldcp.css"><link rel="stylesheet" type="text/css" href="/assets/select2/4.0.0/select2.min.css"><script type="text/javascript" src="/assets/ldColorPicker/ldcp.min.js"></script><script type="text/javascript" src="/assets/html2canvas/html2canvas.js"></script><script type="text/javascript" src="/assets/select2/4.0.0/select2.min.js"></script><script type="text/javascript" src="/assets/gifjs/gif.js"></script><script type="text/javascript" src="/assets/rgbcolor/rgbcolor.js"></script><script type="text/javascript" src="/assets/stackblur/StackBlur.js"></script><script type="text/javascript" src="/assets/canvg/canvg.js"></script><script type="text/javascript" src="/js/icon.js?26"></script><script type="text/javascript" src="/js/ldIconType.js?26"></script><link href="http://fonts.googleapis.com/css?family=Varela+Round" rel="stylesheet" type="text/css"></div><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-49953904-1', 'loading.io');
ga('send', 'pageview');</script><div id="fb-root"></div><script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/zh_TW/all.js#xfbml=1&appId=538062799648166";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script></body></html>
+8
View File
@@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}
+81
View File
@@ -0,0 +1,81 @@
var express = require('express');
var router = express.Router();
var extend = require('node.extend');
var redis = require("redis");
var client = redis.createClient();
var lxc = require('../lxc')({sshBind: ['/usr/bin/ssh', 'virt@127.0.0.1']});
//lxc.startEphemeral('ubuntu_template', 'ue0', function(){console.log('cb1', arguments)}, function(){console.log('cb2', arguments)})
router.get('/start/:name', function(req, res, next){
lxc.start(req.params.name, null, function(status, message){
if(status){
res.json({status: 500, name: req.params.name, message: message});
}else{
setTimeout(function() {
lxc.info(req.params.name, null, function(data){
var domain = req.query.domain || 'vm42.us';
domain = req.params.name+'.'+domain;
client.SADD("hosts", domain, function(){});
var ip = data.ip + ':5000';
client.HSET(domain, "ip", ip, redis.print);
client.HSET(domain, "updated", (new Date).getTime(), redis.print);
client.hset(domain, "include", "proxy.include");
res.json({status: 200, info: data});
});
}, 5000);
}
});
});
router.get('/live/:template/:name', function(req, res, next){
lxc.startEphemeral(req.params.name, req.params.template, null, function (data) {
res.json(data);
});
});
router.get('/stop/:name', function(req, res, next){
lxc.stop(req.params.name, null, function(data, message){
if(data){
res.json({status: 500, name: req.params.name, message: message});
}else{
res.json({status: 200});
}
});
});
router.get('/clone/:template/:name', function(req, res, next){
lxc.clone(req.params.name, req.params.template, function(message){
if( message.match(/Created container/) ){
res.json({status: 200});
}else{
res.json({status: 500, message: message});
}
});
});
router.get('/destroy/:name', function(req, res, next){
lxc.destroy(req.params.name, null, function(data, message){
if(data){
res.json({status: 500, message: message});
}else{
res.json({status: 200});
}
});
});
router.get('/info/:name', function(req, res, next){
lxc.info(req.params.name, null, function(data){
res.json(data);
});
});
router.get('/list', function(req, res, next) {
lxc.list(function(data){
res.json(data);
});
});
module.exports = router;
// {"changed":true,"filter":false,"title":"index.js","tooltip":"/routes/index.js","value":"var express = require('express');\nvar router = express.Router();\nvar extend = require('node.extend');\nvar redis = require(\"redis\");\nvar client = redis.createClient();\nvar lxc = require('../lxc')({sshBind: ['/usr/bin/ssh', 'virt@127.0.0.1']});\n//lxc.startEphemeral('ubuntu_template', 'ue0', function(){console.log('cb1', arguments)}, function(){console.log('cb2', arguments)})\n\nrouter.get('/start/:name', function(req, res, next){\n lxc.start(req.params.name, null, function(status, message){\n if(status){\n res.json({status: 500, name: req.params.name, message: message});\n }else{\n setTimeout(function() {\n lxc.info(req.params.name, null, function(data){\n var domain = req.query.domain || 'vm42.us';\n domain = req.params.name+'.'+domain;\n client.SADD(\"hosts\", domain, function(){});\n \n var ip = data.ip + ':5000';\n client.HSET(domain, \"ip\", ip, redis.print);\n client.HSET(domain, \"updated\", (new Date).getTime(), redis.print);\n client.hset(domain, \"include\", \"proxy.include\");\n res.json({status: 200, info: data});\n });\n }, 5000);\n\n }\n });\n});\n\nrouter.get('/live/:template/:name', function(req, res, next){\n lxc.startEphemeral(req.params.name, req.params.template, null, function (data) {\n res.json(data);\n });\n});\n\nrouter.get('/stop/:name', function(req, res, next){\n lxc.stop(req.params.name, null, function(data, message){\n if(data){\n res.json({status: 500, name: req.params.name, message: message});\n }else{\n res.json({status: 200});\n }\n });\n});\n\nrouter.get('/clone/:template/:name', function(req, res, next){\n lxc.clone(req.params.name, req.params.template, function(message){\n if( message.match(/Created container/) ){\n res.json({status: 200});\n }else{\n res.json({status: 500, message: message});\n }\n });\n});\n\nrouter.get('/destroy/:name', function(req, res, next){\n lxc.destroy(req.params.name, null, function(data, message){\n if(data){\n res.json({status: 500, message: message});\n }else{\n res.json({status: 200});\n }\n });\n});\n\nrouter.get('/info/:name', function(req, res, next){\n lxc.info(req.params.name, null, function(data){\n res.json(data);\n });\n});\n\nrouter.get('/list', function(req, res, next) {\n lxc.list(function(data){\n res.json(data); \n });\n});\n\nmodule.exports = router;","undoManager":{"mark":90,"position":100,"stack":[[{"start":{"row":32,"column":27},"end":{"row":32,"column":30},"action":"remove","lines":["par"],"id":37},{"start":{"row":32,"column":27},"end":{"row":32,"column":33},"action":"insert","lines":["params"]}],[{"start":{"row":32,"column":33},"end":{"row":32,"column":34},"action":"insert","lines":["."],"id":38}],[{"start":{"row":32,"column":34},"end":{"row":32,"column":35},"action":"insert","lines":["n"],"id":39}],[{"start":{"row":32,"column":35},"end":{"row":32,"column":36},"action":"insert","lines":["a"],"id":40}],[{"start":{"row":32,"column":36},"end":{"row":32,"column":37},"action":"insert","lines":["m"],"id":41}],[{"start":{"row":32,"column":37},"end":{"row":32,"column":38},"action":"insert","lines":["e"],"id":42}],[{"start":{"row":32,"column":38},"end":{"row":32,"column":39},"action":"insert","lines":[","],"id":43}],[{"start":{"row":32,"column":39},"end":{"row":32,"column":40},"action":"insert","lines":[" "],"id":44}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"insert","lines":["p"],"id":45}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"insert","lines":["a"],"id":46}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"insert","lines":["q"],"id":47}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"remove","lines":["q"],"id":48}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"remove","lines":["a"],"id":49}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"remove","lines":["p"],"id":50}],[{"start":{"row":32,"column":40},"end":{"row":32,"column":41},"action":"insert","lines":["r"],"id":51}],[{"start":{"row":32,"column":41},"end":{"row":32,"column":42},"action":"insert","lines":["e"],"id":52}],[{"start":{"row":32,"column":42},"end":{"row":32,"column":43},"action":"insert","lines":["q"],"id":53}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"action":"insert","lines":[","],"id":54}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"action":"remove","lines":[","],"id":55}],[{"start":{"row":32,"column":43},"end":{"row":32,"column":44},"actio Line truncated
+9
View File
@@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('index')
});
module.exports = router;
+5
View File
@@ -0,0 +1,5 @@
## Auto start
`@reboot /usr/local/bin/forever start -o /var/log/forver.out.log -e /var/log/sorver.err.log -c "/usr/local/bin/codebox run -p 5000" /workspace/`
http://stackoverflow.com/a/13388741/3140931
+3
View File
@@ -0,0 +1,3 @@
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>
+151
View File
@@ -0,0 +1,151 @@
<!DOCTYPE html>
<html>
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link rel='stylesheet' href='/stylesheets/style.css' />
<style>
.input-xs {
height: 22px;
padding: 2px 5px;
font-size: 12px;
line-height: 1.5; //If Placeholder of the input is moved up, rem/modify this.
border-radius: 3px;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha256-Sk3nkD6mLTMOF0EOpNtsIry+s1CsaqQC1rVLTAy+0yc= sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js"></script>
<script src="//dev.718it.biz/repeat/js/repeat.js"></script>
<script>
var vmDataParse = function(data){
data.ip = data.ip || (data.ipv4 || '').replace('-', '') || null ;
data.url = null;
data.clone = null;
if(data.state === 'RUNNING'){
var url = '//'+data.name+'.vm42.us';
data.url = '<a href="'+url+'" target="_blank">'+url+'</a>';
}else if( data.state !== "RUNNING" && data.name.match(/_template/) ){
data.clone = $('#cloneFormTemplate').html();
}
return data
};
var getVmList = function(){
$.scope.vm.splice(0);
$.getJSON('api/list',function(data){
data.forEach(function(value){
value = vmDataParse(value);
$.scope.vm.push(value);
});
});
};
var updateVmList = function(name){
$.getJSON('api/info/'+name, function(data){
if(data.state === 'NULL') return $.scope.vm.splice(name,1);
data = vmDataParse(data);
$.scope.vm.update(name, data);
});
};
var addMessage = function(name, message, time){
time = time || 10000;
var index = $.scope.vm.indexOf(name);
$.extend(true, $.scope.vm[index], {message: message})
//$.scope.vm.update(name, {message: message})
setTimeout(function() {
$.scope.vm.update(name, {message: null})
}, time);
};
$(document).ready(function(){
// set up animation for adding to taks list
$.scope.vm.__put = function(){
this.slideDown( 'fast' );
};
// set up animation for removing taks from list
$.scope.vm.__take = function(){
this.slideUp( 'fast', function(){
this.remove();
});
};
$.scope.vm.__index = 'name';
getVmList();
$('ol').on('click', 'button', function(event){
var $closest = $(this).closest('[data-name]');
var name = $closest.data('name');
var call = $(this).data('call');
$closest.find('span.options').html('<img src="images/gears.gif"/>');
$.getJSON('api/'+call+'/'+name, function(data){
if(data.status !== 200) addMessage(name, data.message);
updateVmList(name);
});
}).on('submit', 'form', function(event){
event.preventDefault();
var $closest = $(this).closest('[data-name]');
var templateName = $closest.data('name');
var name = $(this).find('[name="name"]').val();
var call = $(this).find('[name="live"]').prop('checked') ? 'live' : 'clone';
if(!name) return alert('Please add a name!');
else if($.scope.vm.indexOf(name) !== -1 ) return alert('Name allready in use!')
else $closest.find('span.options').html('<img src="images/gears.gif"/>');
$.getJSON('api/'+call+'/'+templateName+'/'+name, function(data){
console.log(data.status, data);
if(data.status == 200){
getVmList();
}else{
addMessage(name, data.message);
}
});
});
});
</script>
<script id="cloneFormTemplate" type="x-mustache-template">
<form class="form-inline" style="display: inline-block; max-height: 2em;">
[<input name="live" type="checkbox" /> Start Live]
<div class="input-group">
<div class="row" style="margin-left:1px;">
<input type="text" class="form-control input-xs" name="name" placeholder="Clone name">
<span class="input-group-btn">
<input class="btn btn-default btn-xs" type="submit" value="Clone" data-call="clone" />
</span>
</div>
</div>
</form>
</script>
</head>
<body>
<h2>Start will take atlest 5 seconds!</h2>
<!--<input type="text" name="domain" value="vm42.us"/>-->
<ol>
<li jq-repeat="vm" data-name="{{ name }}" style="height:2em">
{{ name }} | {{ state }} | {{ ip }}
<span class="options">
<div class="btn-group btn-group-xs">
<button class="btn btn-warning" data-call="stop">Stop</button>
<button class="btn btn-success" data-call="start">Start</button>
<button class="btn btn-danger" data-call="destroy">Destroy</button>
</div>
{{{ url }}}
{{{ clone }}}
{{{ message }}}
</span>
</li>
</ol>
</body>
</html>