Compare commits
353 Commits
1
...
refactor-w
Author | SHA1 | Date | |
---|---|---|---|
fd919d0b91 | |||
3dcfbf4d77 | |||
db8914ed7f | |||
3db02e036e | |||
0a4162400b | |||
734eaeac2f | |||
7bfda7be23 | |||
e2371fe44e | |||
02e7869846 | |||
f8174428a1 | |||
0ba6589aa7 | |||
36db6be4bc | |||
2fa3ae985b | |||
5cd95e2843 | |||
32a338437e | |||
178838366c | |||
b385c0cb7f | |||
7bbf77c6ec | |||
337423d294 | |||
ce31c7f1d5 | |||
cac789fed3 | |||
1231dbcebc | |||
0ac93e70f6 | |||
a79e994331 | |||
4b6aacb769 | |||
c5e75967d9 | |||
072d321b58 | |||
4afb69cdf7 | |||
a1a85b2c69 | |||
a358a5212a | |||
11e44c94e7 | |||
41874764bd | |||
654628b44d | |||
099bce3846 | |||
482fe08c07 | |||
983b76afce | |||
6a11a0baa5 | |||
43caeb73f0 | |||
87ee3a5fd1 | |||
e94308f6ac | |||
ca0b0ef153 | |||
6e0bf97142 | |||
a3107de459 | |||
2c92d0f232 | |||
81c14dbc80 | |||
b81a5a9c2f | |||
0f0033a646 | |||
127a2caac1 | |||
47027fdf39 | |||
cfd6c373ad | |||
128320f80e | |||
5711070d92 | |||
8e89c986bb | |||
14a628a8ff | |||
b45f45153f | |||
8c64959482 | |||
e74f24b2b9 | |||
5533187636 | |||
4a0e16f5f6 | |||
21ad051a4d | |||
3b36642ff8 | |||
84a51ca0db | |||
8779c5c6ca | |||
3a948df9f1 | |||
c2f7dc72aa | |||
70091ddbdb | |||
ef2e953366 | |||
e01794edbc | |||
00f68ef649 | |||
bfa3e689b3 | |||
ec565c2803 | |||
f525c4d98f | |||
7f04135505 | |||
8e82a7f47a | |||
40b6b6ffdc | |||
3a5c110aec | |||
e412dd3f1f | |||
68e7c48bc7 | |||
bbc1025c7d | |||
08f3b1fce6 | |||
432b056609 | |||
7c49a0c623 | |||
841b7d1b35 | |||
1f4f9686bb | |||
bc1c56f37c | |||
992a891aee | |||
78658a5c9f | |||
ae8c58bfda | |||
cba7ba7dbe | |||
8723a7b97a | |||
8533950663 | |||
4dd67ea2f6 | |||
640fb30c8a | |||
d4b45739f1 | |||
ab317dc791 | |||
9bf4055923 | |||
f836ece931 | |||
2aa0257502 | |||
714ff75cb6 | |||
6b662f131d | |||
e27bb6deba | |||
de4ce8553e | |||
e9bd665cc1 | |||
d90e0aaa25 | |||
d204f29526 | |||
0c46420715 | |||
93bf4b2577 | |||
11c7b1907d | |||
b808d23965 | |||
2a21be1825 | |||
9c69033756 | |||
00bca4ff34 | |||
29ad409649 | |||
aee63de478 | |||
67b717ace1 | |||
4d78659654 | |||
5467209d25 | |||
a432df7879 | |||
ded9cff1dc | |||
9bb9809f51 | |||
9072167e65 | |||
7c97bed5b0 | |||
fd4405bca5 | |||
2237d3cac3 | |||
3e0d34a2f5 | |||
4b4ab75aaa | |||
cfc6d406a1 | |||
1624d9f7ff | |||
e8c26abd52 | |||
5a5c453ea3 | |||
71ab12c64e | |||
be7f518778 | |||
b8dfaff861 | |||
eec89027a4 | |||
421a8ec78b | |||
a77d00aab4 | |||
c971b609ee | |||
b8f72ef13c | |||
f9482b3483 | |||
136bf04825 | |||
6c2a8d48bf | |||
d22a79c81e | |||
4c2a4b7657 | |||
d1a87a033b | |||
18ff2ee3be | |||
651f3835e2 | |||
232e9b72bb | |||
f714a6e179 | |||
9b7936ee3a | |||
ce96c7cb87 | |||
23f7cf1f68 | |||
b1e3e23d91 | |||
f63b6c3acd | |||
05b6a477f4 | |||
848f439122 | |||
f0d6016a63 | |||
37fae2e413 | |||
42ea77720a | |||
4079ee8208 | |||
cd37c680f0 | |||
7d12414d74 | |||
a7e1478697 | |||
571e81ace5 | |||
02c0c85417 | |||
0b9b5c0627 | |||
e6dee5bde3 | |||
586c8cc32f | |||
2ba7fa58e2 | |||
b84c87d55d | |||
f86a74a589 | |||
a51f4c203c | |||
ccd128100a | |||
191851e2bb | |||
b5baacf668 | |||
3e592887d1 | |||
18897cd4e6 | |||
b5737a0470 | |||
732d15cc54 | |||
424b5c68c8 | |||
f6f5b81b49 | |||
eb9b8b2556 | |||
d5bd5d2c39 | |||
71bd4ffc4a | |||
101160e887 | |||
371a40a3d3 | |||
8a5001aee7 | |||
9991e7eb36 | |||
7fcbcecb6a | |||
6b72ddcdd4 | |||
a4f01f8062 | |||
5a0ab51c32 | |||
dd68a29208 | |||
bf21a8b966 | |||
99043948db | |||
ee3091ae3c | |||
ac524a1c76 | |||
d7b32996b3 | |||
7ba58ee8d6 | |||
9a58acdfa2 | |||
28596a0b4d | |||
1086baf65a | |||
8c32b2e246 | |||
c319487141 | |||
a301ad88e5 | |||
d4da910040 | |||
62fcae727a | |||
1ddda799d3 | |||
9a0ad761b9 | |||
26f06c0aa8 | |||
b8f23077da | |||
7d4965b21e | |||
1af8aed161 | |||
5fc47fbbcc | |||
129cd54812 | |||
c6e9ec62ba | |||
caf32c3809 | |||
19293fdaff | |||
f32d6f70a9 | |||
66f6c3b92a | |||
ed2b37d696 | |||
61dedb013d | |||
0e7ccf2637 | |||
b74a71efb4 | |||
4651a2f49c | |||
eff29a9922 | |||
baa8fe6730 | |||
16f91f01a7 | |||
b53c3e6808 | |||
a1338c5792 | |||
f875bf101a | |||
f503f370b2 | |||
32e70d4be4 | |||
15cac181c3 | |||
63b7a3b481 | |||
360f2c591d | |||
d4214cbf1d | |||
d23f1b91d1 | |||
4ca49a9632 | |||
b8ce1fdcfc | |||
4257644d4e | |||
dd759efd8a | |||
ae2a4984e4 | |||
152b206f9c | |||
e6c45352c9 | |||
d00b325625 | |||
f5ea0966dc | |||
405569a0c9 | |||
3b356a48f8 | |||
30525c984c | |||
998063268f | |||
22905cf056 | |||
923b6fdd78 | |||
8f9a43c743 | |||
8962181782 | |||
82ce62a678 | |||
8b0556b545 | |||
2b8ef1d39e | |||
f80988a929 | |||
7834e892bf | |||
1db5cbb600 | |||
18cbb5536b | |||
2e21a7d91b | |||
3a1276db67 | |||
fcb4612e1c | |||
a158d05b9d | |||
7e5fae983b | |||
d10c699145 | |||
c97100c9a7 | |||
2a6cce6296 | |||
2fc8276634 | |||
651a4d82a5 | |||
19395652c4 | |||
7f0489cfa9 | |||
1db7bd8f3c | |||
a65c87017a | |||
70bd796bc6 | |||
a5afd8469c | |||
c742c8fb7a | |||
c42cf797e7 | |||
280a90a7eb | |||
f82968fbbe | |||
ceadfcb24f | |||
f809e57ba5 | |||
d93b43d37f | |||
109db64634 | |||
2f8cf5c120 | |||
d452250126 | |||
6acc3fba21 | |||
5c94ea4c29 | |||
0b1b1fd5c9 | |||
049972b278 | |||
5c91414521 | |||
299040be6f | |||
1dce0358cc | |||
7e2c575a06 | |||
96c931ba5c | |||
c9b66b1bd6 | |||
2ea36dc963 | |||
77d8f2b743 | |||
3a313a21d1 | |||
491f6c57e8 | |||
96b032f816 | |||
fbc9a308b9 | |||
56cebedf04 | |||
b7c8335a82 | |||
57cfc24e92 | |||
9c2fbaab99 | |||
d57058b59c | |||
147d7ab41f | |||
39b64a4ecd | |||
aa5dd97694 | |||
e481f1c071 | |||
2dba8c9c4f | |||
81bda27acd | |||
3b89660ef1 | |||
a74d7130d7 | |||
1ee46f6d2c | |||
99dcc47e00 | |||
8ce30f1e60 | |||
1e3f9a7302 | |||
517690a454 | |||
469d4deb7e | |||
64af338a6c | |||
cf05db1c91 | |||
ee7ff554e7 | |||
c77ee3a007 | |||
46ad5ae25d | |||
8c0d3bd6da | |||
c8d32de96d | |||
f19c673764 | |||
238cfd94b3 | |||
e7987d8035 | |||
f8ff072690 | |||
b0ab1a5313 | |||
a1a0ec8d02 | |||
d438cdd249 | |||
708c5ea5d3 | |||
7c37aa2e8b | |||
025205e349 | |||
85e0dcf729 | |||
45bf9c67f6 | |||
d34a482a60 | |||
0c891f62ef | |||
5df3ecd5af | |||
55813dc422 | |||
ee57ab01e1 | |||
b27f0d6bd9 | |||
303c80f601 | |||
1cafd74cc4 | |||
a8d53d5bc5 | |||
c8a3d5c60d | |||
cb68bc4eec | |||
a4a1cf314a |
3
.gitignore
vendored
3
.gitignore
vendored
@ -29,3 +29,6 @@ node_modules
|
||||
# Debug log from npm
|
||||
npm-debug.log
|
||||
.c9
|
||||
|
||||
# keys
|
||||
secrets.js
|
@ -53,10 +53,11 @@ Clone the repo and set it up:
|
||||
git clone https://github.com/wmantly/lxc_manager_node.git
|
||||
cd lxc_manager_node
|
||||
npm install
|
||||
```
|
||||
|
||||
Its safer at this point to reboot the system, `exit` back to the privlaged user and `reboot`
|
||||
|
||||
**SSH or log dercily into the `virt` user!!!** this will not if you use su!
|
||||
**SSH or log dercily into the `virt` user!!!** this will not work if you use su to get into the user!
|
||||
|
||||
Now you can can create a test container:
|
||||
```bash
|
||||
|
33
allocate_runners.sh
Normal file
33
allocate_runners.sh
Normal file
@ -0,0 +1,33 @@
|
||||
# maxMemoryUsage must be defined
|
||||
|
||||
function usedMemoryPercent () {
|
||||
memoryAvailable=$(head /proc/meminfo|grep MemAvail|grep -Po '\d+');
|
||||
totalMemory=$(head /proc/meminfo|grep MemTotal|grep -Po '\d+');
|
||||
difference=$(expr $totalMemory - $memoryAvailable);
|
||||
difference=$(expr $difference \* 100);
|
||||
memory=$(expr $difference / $totalMemory);
|
||||
}
|
||||
|
||||
function buildRunners () {
|
||||
baseName="crunner0";
|
||||
namePrefix="crunner-batch-${RANDOM}";
|
||||
runners="";
|
||||
usedMemoryPercent;
|
||||
|
||||
# maxMemoryUsage must be defined
|
||||
until [[ $memory -gt $maxMemoryUsage ]]; do
|
||||
|
||||
runnerName="${namePrefix}-id-${RANDOM}";
|
||||
lxc-start-ephemeral -o $baseName -n $runnerName --union-type overlayfs -d;
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
runners="${runners};${runnerName}";
|
||||
fi
|
||||
usedMemoryPercent;
|
||||
done
|
||||
}
|
||||
buildRunners;
|
||||
|
||||
# Add curl to manager here. Sending status report to manager
|
||||
# curl -X POST "${PHONE_HOME}" -d'{"memory":${memory}, "runnersShort": "${runners}", "runnersLong": "'"$(lxc-ls --fancy)"'", "id": "${WORKER_UUID}"}'
|
||||
exit 0;
|
6
app.js
6
app.js
@ -18,6 +18,12 @@ app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||
next();
|
||||
});
|
||||
|
||||
app.use('/', require('./routes/index'));
|
||||
app.use('/api', require('./routes/api'));
|
||||
|
||||
|
178
doapi.js
Normal file
178
doapi.js
Normal file
@ -0,0 +1,178 @@
|
||||
var request = require('request');
|
||||
|
||||
api = function(key){
|
||||
key = key || require('./secrets.js').doAPI;
|
||||
this.BASEURL = 'https://api.digitalocean.com/v2/';
|
||||
this.headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer '+key
|
||||
}
|
||||
this.calls = 0;
|
||||
|
||||
this.account = function(callback){
|
||||
var options = {
|
||||
url: this.BASEURL+'account',
|
||||
headers: this.headers
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.get(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.dropletsByTag = function(tag, callback){
|
||||
var options = {
|
||||
url: this.BASEURL+'droplets?tag_name='+tag,
|
||||
headers: this.headers
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.get(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.dropletSetTag = function(tag, dropletID, callback) {
|
||||
callback = callback || function(){};
|
||||
var data = {
|
||||
resources: [
|
||||
{
|
||||
resource_id: dropletID,
|
||||
resource_type: 'droplet'
|
||||
}
|
||||
]
|
||||
};
|
||||
var options = {
|
||||
url: this.BASEURL+'tags/'+tag+'/resources',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(data)
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.post(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.dropletCreate = function(args, callback){
|
||||
callback = callback || function(){};
|
||||
|
||||
var data = {
|
||||
name: args.name, // || return false,
|
||||
region: args.region || 'nyc3',
|
||||
size: args.size || '512mb',
|
||||
image: args.image || 'ubuntu-14-04-x64',
|
||||
ssh_keys: args.ssh_key || null,
|
||||
backups: args.backup || false,
|
||||
private_networking: args.private_networking || true,
|
||||
user_data: args.user_data || null
|
||||
};
|
||||
var options = {
|
||||
url: this.BASEURL+'droplets',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(data)
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.post(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
}
|
||||
|
||||
this.dropletToActive = function(args){
|
||||
args.__doapi = this; // hold the DO api in the agrs scope
|
||||
args.onCreated = args.onCreate || function(){};
|
||||
|
||||
this.dropletCreate(args, function(data){
|
||||
data = JSON.parse(data);
|
||||
args.onCreate(data, args);
|
||||
|
||||
// check if the server is ready, giving time to allow
|
||||
// digital ocean to do its thing
|
||||
setTimeout(function check(id, args){
|
||||
time = args.time || 10000;
|
||||
args.__doapi.dropletInfo(id, function (data){
|
||||
var droplet = JSON.parse(data)['droplet'];
|
||||
if(droplet.status == 'active'){
|
||||
|
||||
return args.onActive(droplet, args);
|
||||
}else{
|
||||
setTimeout(function(check, id){
|
||||
check(id, args);
|
||||
}, time, check, droplet.id);
|
||||
}
|
||||
});
|
||||
}, 70000, data.droplet.id, args);
|
||||
});
|
||||
};
|
||||
|
||||
this.dropletDestroy = function(dropletID, callback){
|
||||
callback = callback || function(){};
|
||||
var options = {
|
||||
url: this.BASEURL+'droplets/'+dropletID,
|
||||
headers: this.headers
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.del(options, function(error, response, body){
|
||||
callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.dropletInfo = function(dropletID, callback){
|
||||
var options = {
|
||||
url: this.BASEURL+'droplets/'+dropletID,
|
||||
headers: this.headers
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.get(options, function(error, response, body){
|
||||
callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.tagCreate = function(tag, callback){
|
||||
callback = callback || function(){};
|
||||
var options = {
|
||||
url: this.BASEURL+'tags',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({name: tag})
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.post(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
};
|
||||
|
||||
this.tagsList = function(callback){
|
||||
var options = {
|
||||
url: this.BASEURL+'tags',
|
||||
headers: this.headers
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.get(options, function(e,r,b){
|
||||
callback(b,r,e);
|
||||
});
|
||||
};
|
||||
|
||||
this.domianAddRecord = function(args, callback){
|
||||
callback = callback || function(){};
|
||||
var options = {
|
||||
url: this.BASEURL+'domains/'+ args.domain +'/records',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(args)
|
||||
};
|
||||
this.calls++;
|
||||
|
||||
return request.post(options, function(error, response, body){
|
||||
return callback(body, response, error);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = api;
|
19
docs/lxc-world.md
Normal file
19
docs/lxc-world.md
Normal file
@ -0,0 +1,19 @@
|
||||
##### LXC Commands
|
||||
|
||||
|
||||
`lxc-top`:
|
||||
|
||||
Realtime Meta data about containers(not machine friendly). Monitor container statistics.
|
||||
|
||||
`lxc-ls --fancy`:
|
||||
|
||||
list of existing containers
|
||||
|
||||
`lxc-start-ephemeral`, `lxc-copy`:
|
||||
|
||||
start an ephemeral copy of an existing container
|
||||
|
||||
|
||||
`lxc-attach`:
|
||||
|
||||
start a process inside a running container.(enter the droplet)
|
27
docs/memory-managment.md
Normal file
27
docs/memory-managment.md
Normal file
@ -0,0 +1,27 @@
|
||||
##### Memory Managment
|
||||
|
||||
|
||||
`free`, `free -h`:
|
||||
|
||||
display amount of free and used memory in the system.
|
||||
* Disclamers:
|
||||
- DO NOT USE IN SCRIPT
|
||||
|
||||
`/proc/`:
|
||||
|
||||
It is actually an kernel application. Looks like a file, but is actually generated on demand by the kernel. All "files" in proc are kernal commands. Interact with these commands as if they were files.
|
||||
|
||||
|
||||
`/proc/meminfo`:
|
||||
|
||||
File containing realtime memory info.
|
||||
|
||||
`/proc/cpuinfo`:
|
||||
|
||||
cpu info
|
||||
|
||||
|
||||
|
||||
`/dev`:
|
||||
|
||||
DANGER This folder contains physical interfaces to hardware on or connected to the machine. Just don't. Read first. Except `/dev/null` it is a blackhole.
|
50
lxc.js
50
lxc.js
@ -1,8 +1,12 @@
|
||||
'use strict';
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
function sysExec(command, callback){
|
||||
command = 'unset XDG_SESSION_ID XDG_RUNTIME_DIR; cgm movepid all virt $$; ' + command;
|
||||
|
||||
function sysExec(command, ip, callback){
|
||||
ip = ip || '104.236.77.157';
|
||||
command = new Buffer(command).toString('base64')
|
||||
command = 'ssh -i ~/.ssh/clw_rsa -o "StrictHostKeyChecking no" virt@'+ ip + ' "echo ' + command + '|base64 --decode|bash"';
|
||||
// command = 'unset XDG_SESSION_ID XDG_RUNTIME_DIR; cgm movepid all virt $$; ' + command;
|
||||
|
||||
return exec(command, (function(callback){
|
||||
return function(err,data,stderr){
|
||||
@ -13,30 +17,9 @@ function sysExec(command, callback){
|
||||
})(callback));
|
||||
};
|
||||
|
||||
var Container = function(config){
|
||||
this.name = config.name;
|
||||
this.state = config.state;
|
||||
this.ip = config.ip || (config.ipv4 || '').replace('-', '') || null ;
|
||||
}
|
||||
|
||||
Container.prototype.autoShutDown = function(time) {
|
||||
time = time || 600000;
|
||||
|
||||
// this.__shutDownTimeout = setTimeout(function(){}, this.autoShutDown):
|
||||
};
|
||||
|
||||
var lxcORM = function(){
|
||||
var orm = {}
|
||||
lxc.list(function(data){
|
||||
for(var idx = data.length; idx--;){
|
||||
orm[data[idx].name] = new Container(data[idx]);
|
||||
}
|
||||
});
|
||||
|
||||
return orm
|
||||
};
|
||||
|
||||
var lxc = {
|
||||
exec: sysExec,
|
||||
|
||||
create: function(name, template, config, callback){
|
||||
return sysExec('lxc-create -n '+name+' -t '+template, callback);
|
||||
},
|
||||
@ -48,7 +31,7 @@ var lxc = {
|
||||
destroy: function(name, callback){
|
||||
return sysExec('lxc-destroy -n '+ name, function(data){
|
||||
var info = data.match(/Destroyed container/);
|
||||
console.log('destroy info:', info);
|
||||
// console.log('destroy info:', info);
|
||||
var args = [true].concat(Array.prototype.slice.call(arguments, 1));
|
||||
return callback.apply(this, args);
|
||||
});
|
||||
@ -58,10 +41,10 @@ var lxc = {
|
||||
return sysExec('lxc-start --name '+name+' --daemon', callback);
|
||||
},
|
||||
|
||||
startEphemeral: function(name, base_name, callback){
|
||||
startEphemeral: function(name, base_name, ip, callback){
|
||||
var command = 'lxc-start-ephemeral -o '+base_name+ ' -n '+name +' --union-type overlayfs -d';
|
||||
return sysExec(command, function(data){
|
||||
console.log('startEphemeral', arguments);
|
||||
return sysExec(command, ip, function(data){
|
||||
// console.log('startEphemeral', arguments);
|
||||
if(data.match("doesn't exist.")){
|
||||
return callback({status: 500, error: "doesn't exist."});
|
||||
}
|
||||
@ -76,8 +59,8 @@ var lxc = {
|
||||
});
|
||||
},
|
||||
|
||||
stop: function(name, callback){
|
||||
return sysExec('lxc-stop -n '+ name, callback);
|
||||
stop: function(name, ip, callback){
|
||||
return sysExec('lxc-stop -n '+ name, ip, callback);
|
||||
},
|
||||
|
||||
freeze: function(name, callback){
|
||||
@ -90,7 +73,7 @@ var lxc = {
|
||||
|
||||
info: function(name, callback){
|
||||
return sysExec('lxc-info -n '+name, function(data){
|
||||
console.log('info', arguments);
|
||||
// console.log('info', arguments);
|
||||
if(data.match("doesn't exist")){
|
||||
return callback({state: 'NULL'});
|
||||
}
|
||||
@ -133,6 +116,3 @@ var lxc = {
|
||||
};
|
||||
|
||||
module.exports = lxc;
|
||||
|
||||
var orm = lxcORM()
|
||||
setTimeout(function(){console.log(orm)}, 5000)
|
||||
|
974
package-lock.json
generated
Normal file
974
package-lock.json
generated
Normal file
@ -0,0 +1,974 @@
|
||||
{
|
||||
"name": "manager",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"accepts": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz",
|
||||
"integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=",
|
||||
"requires": {
|
||||
"mime-types": "2.1.17",
|
||||
"negotiator": "0.5.3"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
|
||||
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
|
||||
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
|
||||
},
|
||||
"async": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
|
||||
"integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==",
|
||||
"requires": {
|
||||
"lodash": "4.17.4"
|
||||
}
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
|
||||
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||
},
|
||||
"basic-auth": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz",
|
||||
"integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
|
||||
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz",
|
||||
"integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=",
|
||||
"requires": {
|
||||
"readable-stream": "2.0.6"
|
||||
}
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz",
|
||||
"integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=",
|
||||
"requires": {
|
||||
"bytes": "2.1.0",
|
||||
"content-type": "1.0.4",
|
||||
"debug": "2.2.0",
|
||||
"depd": "1.0.1",
|
||||
"http-errors": "1.3.1",
|
||||
"iconv-lite": "0.4.11",
|
||||
"on-finished": "2.3.0",
|
||||
"qs": "4.0.0",
|
||||
"raw-body": "2.1.7",
|
||||
"type-is": "1.6.15"
|
||||
}
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz",
|
||||
"integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
|
||||
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "2.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"has-ansi": "2.0.0",
|
||||
"strip-ansi": "3.0.1",
|
||||
"supports-color": "2.0.0"
|
||||
}
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
|
||||
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
|
||||
"requires": {
|
||||
"delayed-stream": "1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz",
|
||||
"integrity": "sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs="
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
|
||||
"integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
|
||||
},
|
||||
"cookie-parser": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz",
|
||||
"integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=",
|
||||
"requires": {
|
||||
"cookie": "0.1.3",
|
||||
"cookie-signature": "1.0.6"
|
||||
}
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"requires": {
|
||||
"boom": "2.10.1"
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
|
||||
"requires": {
|
||||
"ms": "0.7.1"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
|
||||
"integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo="
|
||||
},
|
||||
"destroy": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||
},
|
||||
"double-ended-queue": {
|
||||
"version": "2.1.0-0",
|
||||
"resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
|
||||
"integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw="
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"jsbn": "0.1.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||
},
|
||||
"ejs": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.3.4.tgz",
|
||||
"integrity": "sha1-PHbKoJZks1g7ADevncE2557Gi5g="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz",
|
||||
"integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg="
|
||||
},
|
||||
"express": {
|
||||
"version": "4.13.4",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.13.4.tgz",
|
||||
"integrity": "sha1-PAt288d1kMg0VzkGHsC9O6Bn7CQ=",
|
||||
"requires": {
|
||||
"accepts": "1.2.13",
|
||||
"array-flatten": "1.1.1",
|
||||
"content-disposition": "0.5.1",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.1.5",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.2.0",
|
||||
"depd": "1.1.1",
|
||||
"escape-html": "1.0.3",
|
||||
"etag": "1.7.0",
|
||||
"finalhandler": "0.4.1",
|
||||
"fresh": "0.3.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "1.1.2",
|
||||
"on-finished": "2.3.0",
|
||||
"parseurl": "1.3.2",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "1.0.10",
|
||||
"qs": "4.0.0",
|
||||
"range-parser": "1.0.3",
|
||||
"send": "0.13.1",
|
||||
"serve-static": "1.10.3",
|
||||
"type-is": "1.6.15",
|
||||
"utils-merge": "1.0.0",
|
||||
"vary": "1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.5.tgz",
|
||||
"integrity": "sha1-armUiksa4hlSzSWIUwpHItQETXw="
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
||||
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
|
||||
}
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz",
|
||||
"integrity": "sha1-haF8bFmpRxfSYtYSMNSw6+PUoU0=",
|
||||
"requires": {
|
||||
"debug": "2.2.0",
|
||||
"escape-html": "1.0.3",
|
||||
"on-finished": "2.3.0",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz",
|
||||
"integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=",
|
||||
"requires": {
|
||||
"async": "2.5.0",
|
||||
"combined-stream": "1.0.5",
|
||||
"mime-types": "2.1.17"
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz",
|
||||
"integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8="
|
||||
},
|
||||
"generate-function": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
||||
"integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ="
|
||||
},
|
||||
"generate-object-property": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
|
||||
"integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
|
||||
"requires": {
|
||||
"is-property": "1.0.2"
|
||||
}
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||
"optional": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
|
||||
"integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
|
||||
"requires": {
|
||||
"chalk": "1.1.3",
|
||||
"commander": "2.11.0",
|
||||
"is-my-json-valid": "2.16.1",
|
||||
"pinkie-promise": "2.0.1"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
"hoek": "2.16.3",
|
||||
"sntp": "1.0.9"
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
|
||||
"integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
|
||||
"requires": {
|
||||
"inherits": "2.0.3",
|
||||
"statuses": "1.3.1"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
|
||||
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
|
||||
"requires": {
|
||||
"assert-plus": "0.2.0",
|
||||
"jsprim": "1.4.1",
|
||||
"sshpk": "1.13.1"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
|
||||
"integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz",
|
||||
"integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c="
|
||||
},
|
||||
"is": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz",
|
||||
"integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU="
|
||||
},
|
||||
"is-my-json-valid": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz",
|
||||
"integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==",
|
||||
"requires": {
|
||||
"generate-function": "2.0.0",
|
||||
"generate-object-property": "1.2.0",
|
||||
"jsonpointer": "4.0.1",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"optional": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
|
||||
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11"
|
||||
}
|
||||
},
|
||||
"jsonpointer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
|
||||
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"verror": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
|
||||
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
|
||||
"integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
|
||||
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.17",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
|
||||
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
|
||||
"requires": {
|
||||
"mime-db": "1.30.0"
|
||||
}
|
||||
},
|
||||
"morgan": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz",
|
||||
"integrity": "sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I=",
|
||||
"requires": {
|
||||
"basic-auth": "1.0.4",
|
||||
"debug": "2.2.0",
|
||||
"depd": "1.0.1",
|
||||
"on-finished": "2.3.0",
|
||||
"on-headers": "1.0.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
|
||||
"integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
|
||||
"integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g="
|
||||
},
|
||||
"node-uuid": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
|
||||
"integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
|
||||
},
|
||||
"node.extend": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.6.tgz",
|
||||
"integrity": "sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y=",
|
||||
"requires": {
|
||||
"is": "3.2.1"
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||
"requires": {
|
||||
"ee-first": "1.1.1"
|
||||
}
|
||||
},
|
||||
"on-headers": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
|
||||
"integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
|
||||
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
},
|
||||
"pinkie": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
|
||||
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
|
||||
},
|
||||
"pinkie-promise": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
||||
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
|
||||
"requires": {
|
||||
"pinkie": "2.0.4"
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz",
|
||||
"integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=",
|
||||
"requires": {
|
||||
"forwarded": "0.1.2",
|
||||
"ipaddr.js": "1.0.5"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
|
||||
"integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc="
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz",
|
||||
"integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
|
||||
"integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=",
|
||||
"requires": {
|
||||
"bytes": "2.4.0",
|
||||
"iconv-lite": "0.4.13",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bytes": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
|
||||
"integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk="
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.13",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
|
||||
"integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI="
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
|
||||
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "1.0.7",
|
||||
"string_decoder": "0.10.31",
|
||||
"util-deprecate": "1.0.2"
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-2.4.2.tgz",
|
||||
"integrity": "sha1-L5FgJVompsrSt5vwhH4GcoChRuo=",
|
||||
"requires": {
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"redis-commands": "1.3.1"
|
||||
}
|
||||
},
|
||||
"redis-commands": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz",
|
||||
"integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.69.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.69.0.tgz",
|
||||
"integrity": "sha1-z5HS4AB1KxIXFVwAUkGRGZGiNGo=",
|
||||
"requires": {
|
||||
"aws-sign2": "0.6.0",
|
||||
"aws4": "1.6.0",
|
||||
"bl": "1.0.3",
|
||||
"caseless": "0.11.0",
|
||||
"combined-stream": "1.0.5",
|
||||
"extend": "3.0.1",
|
||||
"forever-agent": "0.6.1",
|
||||
"form-data": "1.0.1",
|
||||
"har-validator": "2.0.6",
|
||||
"hawk": "3.1.3",
|
||||
"http-signature": "1.1.1",
|
||||
"is-typedarray": "1.0.0",
|
||||
"isstream": "0.1.2",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"mime-types": "2.1.17",
|
||||
"node-uuid": "1.4.8",
|
||||
"oauth-sign": "0.8.2",
|
||||
"qs": "6.0.4",
|
||||
"stringstream": "0.0.5",
|
||||
"tough-cookie": "2.2.2",
|
||||
"tunnel-agent": "0.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.0.4.tgz",
|
||||
"integrity": "sha1-UQGdhHIMk5uCc36EVWp4Izjs6ns="
|
||||
}
|
||||
}
|
||||
},
|
||||
"send": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.13.1.tgz",
|
||||
"integrity": "sha1-ow1fTILIqbrprQCh2bG9vm8Zntc=",
|
||||
"requires": {
|
||||
"debug": "2.2.0",
|
||||
"depd": "1.1.1",
|
||||
"destroy": "1.0.4",
|
||||
"escape-html": "1.0.3",
|
||||
"etag": "1.7.0",
|
||||
"fresh": "0.3.0",
|
||||
"http-errors": "1.3.1",
|
||||
"mime": "1.3.4",
|
||||
"ms": "0.7.1",
|
||||
"on-finished": "2.3.0",
|
||||
"range-parser": "1.0.3",
|
||||
"statuses": "1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
||||
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
|
||||
"integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve-favicon": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz",
|
||||
"integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=",
|
||||
"requires": {
|
||||
"etag": "1.7.0",
|
||||
"fresh": "0.3.0",
|
||||
"ms": "0.7.2",
|
||||
"parseurl": "1.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
|
||||
"integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U="
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"version": "1.10.3",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz",
|
||||
"integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=",
|
||||
"requires": {
|
||||
"escape-html": "1.0.3",
|
||||
"parseurl": "1.3.2",
|
||||
"send": "0.13.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
|
||||
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz",
|
||||
"integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=",
|
||||
"requires": {
|
||||
"debug": "2.2.0",
|
||||
"depd": "1.1.1",
|
||||
"destroy": "1.0.4",
|
||||
"escape-html": "1.0.3",
|
||||
"etag": "1.7.0",
|
||||
"fresh": "0.3.0",
|
||||
"http-errors": "1.3.1",
|
||||
"mime": "1.3.4",
|
||||
"ms": "0.7.1",
|
||||
"on-finished": "2.3.0",
|
||||
"range-parser": "1.0.3",
|
||||
"statuses": "1.2.1"
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
|
||||
"integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
|
||||
}
|
||||
}
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
}
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
||||
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
|
||||
"requires": {
|
||||
"asn1": "0.2.3",
|
||||
"assert-plus": "1.0.0",
|
||||
"bcrypt-pbkdf": "1.0.1",
|
||||
"dashdash": "1.14.1",
|
||||
"ecc-jsbn": "0.1.1",
|
||||
"getpass": "0.1.7",
|
||||
"jsbn": "0.1.1",
|
||||
"tweetnacl": "0.14.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
|
||||
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz",
|
||||
"integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
|
||||
"integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us="
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"optional": true
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.15",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
|
||||
"integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "2.1.17"
|
||||
}
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
|
||||
"integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
|
||||
"integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA="
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
||||
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
||||
}
|
||||
}
|
||||
}
|
@ -11,10 +11,11 @@
|
||||
"debug": "~2.2.0",
|
||||
"ejs": "~2.3.3",
|
||||
"express": "~4.13.1",
|
||||
"jsonfile": "^2.3.1",
|
||||
"morgan": "~1.6.1",
|
||||
"serve-favicon": "~2.3.0",
|
||||
"node.extend": "~1.1.5",
|
||||
"redis": "~2.4.2",
|
||||
"request": "~2.69.0"
|
||||
"request": "~2.69.0",
|
||||
"serve-favicon": "~2.3.0"
|
||||
}
|
||||
}
|
||||
|
132
routes/api.js
132
routes/api.js
@ -2,52 +2,18 @@
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
var extend = require('node.extend');
|
||||
var redis = require("redis");
|
||||
var client = redis.createClient();
|
||||
var request = require('request');
|
||||
// what is util for??
|
||||
var util = require('util');
|
||||
var lxc = require('../lxc');
|
||||
var doapi = require('../doapi')();
|
||||
|
||||
var runner = function(req, res, ip){
|
||||
return request.post({url:'http://'+ip, form: req.body}, function(error, response, body){
|
||||
body = JSON.parse(body);
|
||||
body['ip'] = ip.replace('10.0.', '');
|
||||
return res.json(body);
|
||||
});
|
||||
};
|
||||
var workers = require('./worker_collection.js');
|
||||
|
||||
var addToRedis = 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(){});
|
||||
console.log('========STARTING===========');
|
||||
|
||||
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");
|
||||
return res.json({status: 200, info: data});
|
||||
});
|
||||
};
|
||||
|
||||
router.get('/start/:name', function(req, res, next){
|
||||
return lxc.start(req.params.name, function(data){
|
||||
console.log('start', arguments);
|
||||
if(!data){
|
||||
return res.json({status: 500, name: req.params.name, message: data});
|
||||
}else{
|
||||
res.json({});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/live/:template/:name', function(req, res, next){
|
||||
return lxc.startEphemeral(req.params.name, req.params.template, function (data) {
|
||||
console.log('live', arguments);
|
||||
return res.json(data);
|
||||
});
|
||||
});
|
||||
workers.start();
|
||||
|
||||
// Why is this a GET?
|
||||
router.get('/stop/:name', function(req, res, next){
|
||||
return lxc.stop(req.params.name, function(data){
|
||||
console.log('stop', arguments);
|
||||
@ -59,65 +25,49 @@ router.get('/stop/:name', function(req, res, next){
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/clone/:template/:name', function(req, res, next){
|
||||
return lxc.clone(req.params.name, req.params.template, function(data){
|
||||
console.log('clone', arguments);
|
||||
if( data.match(/Created container/) ){
|
||||
return res.json({status: 200});
|
||||
}else{
|
||||
return res.json({status: 500, message: data});
|
||||
}
|
||||
});
|
||||
// Why is this a GET?
|
||||
router.get('/destroyByTag', function(req, res, next) {
|
||||
workers.destroyByTag();
|
||||
res.send('?');
|
||||
});
|
||||
|
||||
router.get('/destroy/:name', function(req, res, next){
|
||||
return lxc.destroy(req.params.name, function(data){
|
||||
console.log('destroy', arguments);
|
||||
if(data){
|
||||
return res.json({status: 500, message: data});
|
||||
}else{
|
||||
return res.json({status: 200});
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/liststuff', function(req, res, next){
|
||||
var obj = util.inspect(workers, {depth: 4});
|
||||
res.send(`
|
||||
<h1>Workers</h1>
|
||||
<pre>${obj}</pre>
|
||||
<h1>label2runner</h1>
|
||||
<pre>${util.inspect(workers.runnerMap)}</pre>
|
||||
<h1>DO calls</h1>
|
||||
${doapi.calls}
|
||||
`);
|
||||
});
|
||||
|
||||
router.get('/info/:name', function(req, res, next){
|
||||
return lxc.info(req.params.name, function(data){
|
||||
return res.json(data);
|
||||
});
|
||||
router.get('/ping/:runner', function(req, res, next){
|
||||
var runner = workers.getRunner(req.params.runner);
|
||||
// runnerTimeout(runner);
|
||||
runner.setTimeout();
|
||||
res.json({res:''});
|
||||
});
|
||||
|
||||
router.get('/list', function(req, res, next) {
|
||||
return lxc.list(function(data){
|
||||
return res.json(data);
|
||||
});
|
||||
});
|
||||
router.post('/run/:runner?', function (req, res, next){
|
||||
console.log(`Request runner route!`);
|
||||
|
||||
router.post('/run/:ip?', function doRun(req, res, next){
|
||||
// check if server is
|
||||
|
||||
return lxc.list(function(data){
|
||||
if(!req.params.ip) data = [];
|
||||
var ip = '10.0.'+ req.params.ip;
|
||||
var found = false;
|
||||
|
||||
for(var idx=data.length; idx--;){
|
||||
if( data[idx]['ipv4'] === ip ){
|
||||
found = true;
|
||||
break;
|
||||
return workers.attemptRun(
|
||||
req.body.code, req.query.once, req.params.runner,
|
||||
(body) => {
|
||||
res.json(body);
|
||||
},
|
||||
(error, statusCode) => {
|
||||
if (statusCode === 503){
|
||||
res.status(503);
|
||||
return res.json({error: 'No runners, try again soon.'});
|
||||
} else if (statusCode === 400){
|
||||
return res.status(400).json({error: 'Runner restarted too many times'});
|
||||
}
|
||||
}
|
||||
|
||||
if(found){
|
||||
return runner(req, res, ip)
|
||||
}else{
|
||||
var name = 'u1-'+(Math.random()*100).toString().replace('.','');
|
||||
return lxc.startEphemeral(name, 'u1', function(data){
|
||||
return runner(req, res, data.ip);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
607
routes/worker_collection.js
Normal file
607
routes/worker_collection.js
Normal file
@ -0,0 +1,607 @@
|
||||
'use strict';
|
||||
|
||||
var jsonfile = require('jsonfile');
|
||||
var request = require('request');
|
||||
var lxc = require('../lxc');
|
||||
var doapi = require('../doapi')();
|
||||
var settings = require('./workers.json');
|
||||
var fs = require('fs');
|
||||
settings.tagPrefix = settings.tagPrefix || 'clwV';
|
||||
|
||||
var utils = (function(){
|
||||
return {
|
||||
|
||||
"uuid": function(){
|
||||
return (Math.random()*100).toString().slice(-4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
var Runner = (function(){
|
||||
var proto = {};
|
||||
var __empty = function(){};
|
||||
|
||||
proto.runnerMap = {};
|
||||
|
||||
proto.cleanUp = function(label){
|
||||
delete proto.runnerMap[label];
|
||||
};
|
||||
|
||||
proto.set = function(runner){
|
||||
proto.runnerMap[runner.label] = runner;
|
||||
proto.runnerMap[runner.label] = runner;
|
||||
};
|
||||
|
||||
proto.get = function(label){
|
||||
return proto.runnerMap[label];
|
||||
};
|
||||
|
||||
|
||||
proto.create = function(config){
|
||||
var runner = Object.create(proto);
|
||||
Object.assign(runner, config);
|
||||
return runner;
|
||||
};
|
||||
|
||||
proto.free = function(){
|
||||
// track how often this happens in a minute
|
||||
var runner = this;
|
||||
|
||||
lxc.stop(runner.name, runner.worker.ip);
|
||||
// this should be done by the worker
|
||||
runner.worker.usedrunners--;
|
||||
|
||||
if(runner.hasOwnProperty('timeout')){
|
||||
clearTimeout(runner.timeout);
|
||||
}
|
||||
|
||||
if(runner.hasOwnProperty('cleanUp')){
|
||||
runner.cleanUp();
|
||||
}
|
||||
// worker has more space now
|
||||
// worker should track this
|
||||
setTimeout(()=>{
|
||||
runner.worker.populate();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
proto.setTimeout = function(time){
|
||||
time = time || 60000; // 1 minutes
|
||||
var runner = this;
|
||||
if(runner.hasOwnProperty('timeout')){
|
||||
clearTimeout(runner.timeout);
|
||||
}
|
||||
|
||||
return runner.timeout = setTimeout(function(){
|
||||
runner.free();
|
||||
}, time);
|
||||
};
|
||||
|
||||
return proto;
|
||||
})();
|
||||
|
||||
|
||||
var Worker = (function(){
|
||||
var proto = {};
|
||||
var __empty = function(){};
|
||||
|
||||
// settings should probably be retrieved via a function
|
||||
proto.settings = settings;
|
||||
|
||||
var maxSyncAttempts = 6;
|
||||
|
||||
proto.create = function(config){
|
||||
var worker = Object.create(proto);
|
||||
Object.assign(worker, config);
|
||||
worker.networks.v4.forEach(function(value){
|
||||
worker[ value.type + 'IP' ] = value.ip_address;
|
||||
});
|
||||
|
||||
worker.availrunners = [];
|
||||
worker.ip = worker.publicIP;
|
||||
worker.usedrunners = 0;
|
||||
worker.age = +(new Date());
|
||||
worker.canSchedule = true;
|
||||
worker.isBuildingRunners = false;
|
||||
worker.isSyncing = false;
|
||||
worker.syncAttempts = 0;
|
||||
|
||||
|
||||
return worker;
|
||||
};
|
||||
|
||||
proto.populate = function(callback){
|
||||
callback = callback || __empty;
|
||||
return lxc.startEphemeral(
|
||||
"crunner-batch-$RANDOM-id-$RANDOM", "crunner0", this.ip, callback
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
proto.getRunner = function(){
|
||||
if(this.availrunners.length === 0) return false;
|
||||
// console.log('getting runner from ', worker.name, ' avail length ', this.availrunners.length);
|
||||
var runner = this.availrunners.pop();
|
||||
this.usedrunners++;
|
||||
runner.setTimeout();
|
||||
return runner;
|
||||
};
|
||||
|
||||
|
||||
proto.ramPercentUsed = function(callback){
|
||||
// checks the percent of ram used on a worker.
|
||||
return lxc.exec(
|
||||
"python3 -c \"a=`head /proc/meminfo|grep MemAvail|grep -Po '\\d+'`;t=`head /proc/meminfo|grep MemTotal|grep -Po '\\d+'`;print(round(((t-a)/t)*100, 2))\"",
|
||||
this.ip,
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
proto.destroy = function(){
|
||||
var worker = this;
|
||||
worker.canSchedule = false;
|
||||
return doapi.dropletDestroy(this.id, function(body) {
|
||||
console.log('Deleted worker', worker.name);
|
||||
});
|
||||
};
|
||||
|
||||
proto.isZombie = function(){
|
||||
return this.availrunners.length === 0 && this.usedrunners === 0 && !this.isBuildingRunners;
|
||||
};
|
||||
|
||||
proto.register = function(){
|
||||
var worker = this;
|
||||
doapi.domianAddRecord({
|
||||
domain: "codeland.us",
|
||||
type: "A",
|
||||
name: "*." + this.name + ".workers",
|
||||
data: this.publicIP
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// When should this be called
|
||||
proto.sync = function(callback, errorCallback, maxAttempts){
|
||||
var worker = this;
|
||||
|
||||
maxAttempts = maxAttempts || maxSyncAttempts;
|
||||
worker.isSyncing = true;
|
||||
callback = callback || __empty;
|
||||
errorCallback = errorCallback || __empty;
|
||||
// this will call the droplet or the droplet will send the data using a cron job
|
||||
|
||||
// mainly to update the active runners on the worker
|
||||
// potentially collect stats about the droplet as well
|
||||
// - check memory and check runners
|
||||
|
||||
lxc.exec('lxc-ls --fancy', worker.ip, function(data, error, stderr){
|
||||
if (error){
|
||||
console.log("Sync Error: \n", error);
|
||||
if (worker.syncAttempts > maxAttempts){
|
||||
setTimeout(function(){
|
||||
errorCallback(error, worker);
|
||||
}, 0);
|
||||
} else {
|
||||
console.log("Waiting 15 seconds")
|
||||
worker.syncAttempts++;
|
||||
setTimeout(function(){
|
||||
worker.sync(maxAttempts, callback, errorCallback);
|
||||
}, 15000);
|
||||
}
|
||||
} else {
|
||||
|
||||
var output = data.split("\n");
|
||||
var keys = output.splice(0,1)[0].split(/\s+/).slice(0,-1);
|
||||
var runners = [];
|
||||
|
||||
keys = keys.map(function(v){return v.toLowerCase()});
|
||||
output = output.slice(0).slice(0,-1);
|
||||
|
||||
for(var i in output){
|
||||
if(output[i].match(/^-/)) continue; // compatibility with 1.x and 2.x output
|
||||
|
||||
var aIn = output[i].split(/\s+/).slice(0,-1);
|
||||
var mapOut = {};
|
||||
aIn.map(function(value,idx){
|
||||
mapOut[keys[idx]] = value;
|
||||
});
|
||||
runners.push(mapOut);
|
||||
|
||||
}
|
||||
console.log(`RUNNERS FOUND[=> ${worker.ip}`);
|
||||
console.log(`RUNNERS FOUND[=>`, runners);
|
||||
worker.availrunners = [];
|
||||
|
||||
for (let idx = 0, stop = runners.length; idx < stop; idx++){
|
||||
if(runners[idx].state === "STOPPED" || Runner.get(worker.name + ':' + runners[idx].name)){
|
||||
continue;
|
||||
} else {
|
||||
|
||||
var runner = Runner.create({
|
||||
"name": runners[idx].name,
|
||||
"ipv4": runners[idx].ipv4,
|
||||
"worker": worker,
|
||||
"label": worker.name + ':' + runners[idx].name
|
||||
});
|
||||
|
||||
worker.availrunners.push(runner);
|
||||
}
|
||||
}
|
||||
console.log(`RUNNERS AVAILABLE[=>`, worker.availrunners);
|
||||
// TODO: Determine if this flag is needed anymore
|
||||
worker.isBuildingRunners = false;
|
||||
worker.isSyncing = false;
|
||||
worker.syncAttempts = 0;
|
||||
callback(null, worker);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
proto.initialize = function(params, config){
|
||||
// Create droplet
|
||||
// Once active the droplet begins to create runners
|
||||
var maxMemoryUsage = params.maxMemoryUsage || config.maxMemoryUsage || 80;
|
||||
var worker_uuid = utils.uuid();
|
||||
var phone_home = config.home || "/worker/ping";
|
||||
|
||||
|
||||
var callback = params.callback || __empty;
|
||||
var errorCallback = params.errorCallback || empty;
|
||||
|
||||
fs.readFile(__dirname + "/../allocate_runners.sh", function(error, file){
|
||||
|
||||
doapi.dropletToActive({
|
||||
name: config.tagPrefix + (config.version + "") + '-' + utils.uuid(),
|
||||
image: config.image,
|
||||
size: config.size,
|
||||
user_data: proto.__buildCommand(file, maxMemoryUsage, worker_uuid, phone_home),
|
||||
|
||||
onCreate: function(data){
|
||||
doapi.dropletSetTag(
|
||||
config.tagPrefix + config.version,
|
||||
data.droplet.id
|
||||
);
|
||||
},
|
||||
onActive: function(data, args){
|
||||
data.worker_uuid = worker_uuid;
|
||||
var worker = Worker.create(data);
|
||||
|
||||
// wait for boot before syncing runners
|
||||
setTimeout(function(){
|
||||
worker.sync(callback, errorCallback);
|
||||
}, 75000);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
proto.__buildCommand = function(file, maxMemoryUsage, worker_uuid, phone_home){
|
||||
var scriptSetup, script, createScript, makeScriptExecutable, setupCrontab;
|
||||
var interval = 1;
|
||||
|
||||
// worker_uuid and phone_home are only usable with localhost tunnels setup in dev
|
||||
// cronjobSetup = `export PATH=\${PATH};export WORKER_UUID="${worker_uuid}";export PHONE_HOME=${phone_home};export maxMemoryUsage=${maxMemoryUsage};`;
|
||||
scriptSetup = `export PATH=\${PATH};export WORKER_UUID="${worker_uuid}";export maxMemoryUsage=${maxMemoryUsage};`;
|
||||
script = scriptSetup + `echo '${file.toString("base64")}'|base64 --decode|bash`;
|
||||
|
||||
createScript = `echo "${script}" | cat > /home/virt/allocate_runners.sh`;
|
||||
|
||||
makeScriptExecutable = `chmod o+x /home/virt/allocate_runners.sh`;
|
||||
|
||||
setupCrontab = `echo "*/${interval} * * * * /home/virt/allocate_runners.sh > /home/virt/allocate_runners.log 2>&1" | crontab -u virt -`;
|
||||
|
||||
return `#!/bin/bash\n\n${createScript} && ${makeScriptExecutable} && ${setupCrontab};`;
|
||||
};
|
||||
|
||||
return proto;
|
||||
})();
|
||||
|
||||
|
||||
var WorkerCollection = (function(){
|
||||
// works array constructor. This will hold the works(order by creation) and all
|
||||
// the methods interacting with the workers.
|
||||
|
||||
// base array that will be the workers objects.
|
||||
var workers = [];
|
||||
|
||||
|
||||
// persistent settings object
|
||||
// .image is the currently used Digital Ocean snap shot ID
|
||||
// .lastSnapShotId is the previous ID used Digital Ocean snap shot
|
||||
// .version is the current worker version
|
||||
// .size is the base Droplet size for worker creation
|
||||
// .min is the minimum amount of workers that should exist
|
||||
// .max is the maximum amount of works that ca exist
|
||||
// .minAvail is the amount of empty workers there should be
|
||||
workers.settings = settings;
|
||||
|
||||
// How many droplets are currently in the process of being created. It takes
|
||||
// about 3 minutes to create a worker.
|
||||
workers.currentCreating = 0;
|
||||
|
||||
// REMOVE THIS
|
||||
workers.runnerMap = Runner.runnerMap;
|
||||
|
||||
workers.setRunner = function(runner){
|
||||
Runner.set(runner);
|
||||
};
|
||||
|
||||
|
||||
workers.getRunner = function(label){
|
||||
return Runner.get(label);
|
||||
};
|
||||
|
||||
//**************************************************
|
||||
//**************************************************
|
||||
|
||||
workers.getAvailableRunner = function(runner){
|
||||
for(let worker of workers){
|
||||
if(worker.availrunners.length === 0) continue;
|
||||
if(runner && runner.worker.age <= worker.age) break;
|
||||
if(runner) runner.free();
|
||||
|
||||
return worker.getRunner();
|
||||
}
|
||||
|
||||
if(runner) return runner;
|
||||
};
|
||||
|
||||
workers.create = function(config){
|
||||
// manages the creation of a work from first call to all runners seeded
|
||||
|
||||
// dont create more workers then the settings file allows
|
||||
if(workers.length + workers.currentCreating >= workers.settings.max ) return false;
|
||||
workers.currentCreating++;
|
||||
|
||||
var count = 0;
|
||||
config = config || workers.settings;
|
||||
Worker.initialize({
|
||||
"callback": function(error, worker){
|
||||
console.log("Seeded runners on", worker.name);
|
||||
workers.push(worker);
|
||||
worker.register();
|
||||
workers.currentCreating--;
|
||||
},
|
||||
"errorCallback": function(error, worker){
|
||||
// destroy worker
|
||||
workers.currentCreating--;
|
||||
}
|
||||
}, config);
|
||||
};
|
||||
|
||||
workers.__workersId = function(argument){
|
||||
// create array of all current worker Digital Ocean ID
|
||||
return workers.map(function(item){
|
||||
return item.id;
|
||||
});
|
||||
};
|
||||
|
||||
workers.destroy = function(worker){
|
||||
// removes last one
|
||||
// X TODO: If worker is passed, check for it in the workers array and
|
||||
// remove it if found.
|
||||
if ( worker ){
|
||||
var worker_idx = workers.indexOf(worker);
|
||||
if (~worker_idx){
|
||||
workers.splice(worker_idx, 1);
|
||||
return worker.destroy();
|
||||
}
|
||||
} else {
|
||||
worker = workers.pop();
|
||||
return worker.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
workers.destroyByTag = function(tag){
|
||||
// Delete works that with
|
||||
|
||||
tag = tag || workers.settings.tagPrefix + workers.settings.version;
|
||||
let currentIDs = workers.__workersId();
|
||||
|
||||
let deleteDroplets = function(droplets){
|
||||
if(droplets.length === 0) return true;
|
||||
let droplet = droplets.pop();
|
||||
if(~currentIDs.indexOf(droplet.id)) return deleteDroplets(droplets);
|
||||
|
||||
doapi.dropletDestroy(droplet.id, function(body){
|
||||
setTimeout(deleteDroplets, 1000, droplets);
|
||||
if(!droplets.length) console.log(`Finished deleting workers tagged ${tag}.`);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: move to seperate method
|
||||
doapi.dropletsByTag(tag, function(data){
|
||||
data = JSON.parse(data);
|
||||
console.log(`Deleting ${data['droplets'].length} workers tagged ${tag}. Workers`,
|
||||
data['droplets'].map(function(item){
|
||||
return item.name+' | '+item.id;
|
||||
})
|
||||
);
|
||||
|
||||
deleteDroplets(data['droplets']);
|
||||
});
|
||||
};
|
||||
|
||||
workers.checkForZombies = function(callback){
|
||||
// check to make sure all works are used or usable.
|
||||
if (workers.length === 0) callback();
|
||||
let
|
||||
zombies = 0,
|
||||
syncedCount = workers.length,
|
||||
workerCleanUp = function(error, worker){
|
||||
console.log(`Zombie! Worker ${worker.name}, destroying.`);
|
||||
workers.destroy(worker);
|
||||
zombies++;
|
||||
if(!--count) callback();
|
||||
};
|
||||
|
||||
|
||||
for(let worker of workers){
|
||||
console.log(`Checking if ${worker.name} is a zombie worker.`);
|
||||
// if a runner has no available runners and no used runners, its a
|
||||
// zombie. This should happen when a newer image ID has been added
|
||||
// and old workers slowly lose there usefulness.
|
||||
worker.sync(function(error, worker){
|
||||
if(worker.isZombie()) workerCleanUp(error, worker);
|
||||
}, workerCleanUp);
|
||||
}
|
||||
};
|
||||
|
||||
workers.checkBalance = function(){
|
||||
console.log(`${(new Date())} Checking balance.`);
|
||||
|
||||
workers.checkForZombies(function(){
|
||||
// if there are workers being created, stop scale up and down check
|
||||
var skipBalance = workers.currentCreating + workers.length >= workers.settings.min;
|
||||
if(workers.currentCreating && skipBalance){
|
||||
return console.log(`Killing balance, workers are being created.`);
|
||||
}
|
||||
|
||||
workers.balance();
|
||||
});
|
||||
};
|
||||
|
||||
workers.balance = function(){
|
||||
console.log(`BALANCING: ${(new Date())}`);
|
||||
// count workers and locate oldest worker
|
||||
var oldestWorker, isNotOlder, workerCount = 0;
|
||||
|
||||
for(let worker of workers){
|
||||
console.log(`
|
||||
Checking worker
|
||||
worker.name: ${worker.name}
|
||||
worker.usedrunners: ${worker.usedrunners}
|
||||
worker.availrunners: ${worker.availrunners.length}
|
||||
workerCount: ${workerCount}
|
||||
compare: ${worker.usedrunners !== 0}
|
||||
`);
|
||||
|
||||
if(worker.usedrunners === 0){
|
||||
workerCount++;
|
||||
isNotOlder = oldestWorker && oldestWorker.age < worker.age
|
||||
oldestWorker = (isNotOlder ? oldestWorker:worker);
|
||||
}
|
||||
}
|
||||
|
||||
if(workerCount > workers.settings.minAvail){
|
||||
// Remove oldest worker if there are more than the settings file state
|
||||
console.log(`
|
||||
Destroying Worker
|
||||
Last ${workers.settings.minAvail} workers not used, killing last worker
|
||||
workerCount: ${workerCount}
|
||||
minAvail: ${workers.settings.minAvail}
|
||||
workers: ${workers.length}
|
||||
`);
|
||||
return workers.destroy(oldestWorker);
|
||||
|
||||
} else if( workerCount < workers.settings.minAvail){
|
||||
// Creates worker if there are less than the settings state
|
||||
console.log(`
|
||||
Creating Worker
|
||||
last 3 workers have no free runners, starting worker,
|
||||
workerCount: ${workerCount}
|
||||
minAvail: ${workers.settings.minAvail}
|
||||
workers: ${workers.length}
|
||||
`);
|
||||
|
||||
return workers.create();
|
||||
} else {
|
||||
console.log(`
|
||||
Blanced
|
||||
LMA: ${workerCount}
|
||||
Settings MA: ${workers.settings.minAvail}
|
||||
Workers: ${workers.length}
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
workers.start = function(interval){
|
||||
setInterval(workers.checkBalance, interval || 15000);
|
||||
workers.destroyByTag();
|
||||
};
|
||||
|
||||
workers.settingsSave = function(){
|
||||
// save the live settings file to disk
|
||||
|
||||
jsonfile.writeFile('./workers.json', workers.settings, {spaces: 2}, function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
workers.attemptRun = function(code, once, runnerLabel, callback, errorCallback, count){
|
||||
// PARAMS: code, once, runnerLabel, callback, errorCallback, count;
|
||||
|
||||
var runner = workers.getAvailableRunner(
|
||||
workers.getRunner(runnerLabel)
|
||||
);
|
||||
|
||||
if(!runner){
|
||||
console.log(`No runner available!`);
|
||||
return errorCallback(null, 503);
|
||||
}
|
||||
|
||||
count = count || 0;
|
||||
|
||||
console.log(`Runner starting attempt ${count}.`);
|
||||
|
||||
|
||||
if(count > 2){
|
||||
console.log(`Runner attempt failed, to many requests!`);
|
||||
return errorCallback(null, 400);
|
||||
}
|
||||
|
||||
var httpOptions = {
|
||||
url: 'http://' + runner.worker.ip,
|
||||
headers: {
|
||||
Host: runner.name
|
||||
},
|
||||
body: JSON.stringify({
|
||||
code: code
|
||||
})
|
||||
};
|
||||
|
||||
// Move the http stuff to the runner
|
||||
return request.post(httpOptions, function(error, response, body){
|
||||
// console.log('runner response:', arguments)
|
||||
|
||||
if(error || response.statusCode !== 200) {
|
||||
return workers.attemptRun(code, once, void 0, callback, errorCallback, ++count);
|
||||
}
|
||||
|
||||
body = JSON.parse(body);
|
||||
|
||||
if(once){
|
||||
runner.free();
|
||||
} else {
|
||||
runner.setTimeout();
|
||||
body['ip'] = runner.label;
|
||||
body['rname'] = runner.name;
|
||||
body['wname'] = runner.worker.name;
|
||||
workers.setRunner(runner);
|
||||
}
|
||||
return callback(body);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
workers.add = function(newWorkers){
|
||||
newWorkers.forEach(function(worker){
|
||||
workers.push(worker);
|
||||
});
|
||||
};
|
||||
// does this have to be last?
|
||||
// make sure Digital Ocean has a tag for the current worker version
|
||||
doapi.tagCreate(workers.settings.tagPrefix + workers.settings.version);
|
||||
|
||||
return workers;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
module.exports = WorkerCollection;
|
10
routes/workers.json
Normal file
10
routes/workers.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"image":"25092187",
|
||||
"version":10,
|
||||
"lastSnapShotId":"23505298",
|
||||
"size":"512mb",
|
||||
"max":100,
|
||||
"min":3,
|
||||
"minAvail":3,
|
||||
"tagPrefix": "dev--CLW"
|
||||
}
|
3
rx.sh
3
rx.sh
@ -1,3 +0,0 @@
|
||||
sudo cgm create all virt
|
||||
sudo cgm chown all virt $(id -u virt) $(id -g virt)
|
||||
|
13
stuff.md
13
stuff.md
@ -1,5 +1,14 @@
|
||||
# Random things not to lose
|
||||
|
||||
## 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
|
||||
|
||||
```crontab
|
||||
@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/`
|
||||
```
|
||||
|
||||
## LXC permission issue
|
||||
|
||||
```bash
|
||||
sudo cgm create all virt
|
||||
sudo cgm chown all virt $(id -u virt) $(id -g virt)
|
||||
```
|
||||
|
71
testAPI.js
Normal file
71
testAPI.js
Normal file
@ -0,0 +1,71 @@
|
||||
const request = require('request');
|
||||
|
||||
var callRunner = (function(){
|
||||
let started = 0;
|
||||
let completed = 0;
|
||||
let errors = 0;
|
||||
let noRunner = 0;
|
||||
|
||||
let func = function(code, callback) {
|
||||
// code | `string` block of code to send runner or
|
||||
// `number` sleep timeout in seconds
|
||||
let sleepTime = 0;
|
||||
let id = started++;
|
||||
callback = callback || function(){};
|
||||
|
||||
if(/^\+?(0|[1-9]\d*)$/.test(code)){
|
||||
sleepTime = code;
|
||||
code = null;
|
||||
}
|
||||
console.log(id, ': Running...');
|
||||
|
||||
|
||||
let httpOptions = {
|
||||
url: 'http://localhost:2000/api/run?once=true',
|
||||
form: {
|
||||
code: code || `python3 -c "
|
||||
from time import sleep
|
||||
sleep(${sleepTime})
|
||||
"`,
|
||||
}
|
||||
};
|
||||
|
||||
return request.post(httpOptions, function(error, response, body){
|
||||
completed++;
|
||||
let res = ``;
|
||||
if(response.statusCode == 503){
|
||||
noRunner++;
|
||||
}else if(error || response.statusCode !== 200){
|
||||
errors++;
|
||||
console.log(`
|
||||
ID: ${id}
|
||||
Error: ${error}
|
||||
`);
|
||||
} else {
|
||||
body = JSON.parse(body);
|
||||
res = (Buffer.from(body.res, 'base64').toString('ascii'));
|
||||
}
|
||||
console.log(`
|
||||
${id} with results ${res}.
|
||||
Errors ${errors}.
|
||||
No runner ${noRunner}.
|
||||
Completed ${completed}
|
||||
`);
|
||||
|
||||
callback()
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
return func;
|
||||
})();
|
||||
|
||||
|
||||
let __do = function(till){
|
||||
if(!till) return ;
|
||||
|
||||
callRunner(String(Math.random())[3]);
|
||||
setTimeout(__do, 1500, --till);
|
||||
};
|
||||
|
||||
__do(1000);
|
Reference in New Issue
Block a user