diff --git a/nodejs/package.json.in b/nodejs/package.json.in
index 9d546cb..d9fbcc9 100644
--- a/nodejs/package.json.in
+++ b/nodejs/package.json.in
@@ -3,10 +3,11 @@
"version": "@PACKAGE_VERSION@",
"private": true,
"dependencies": {
- "express": "~2.5.8",
- "stylus": "~0.53.0",
- "ejs": ">= 0.0.1",
- "socket.io": "~1.4.4"
+ "express": "~2.5.8",
+ "stylus": "~0.53.0",
+ "ejs": ">= 0.0.1",
+ "socket.io": "~1.4.4",
+ "pty.js": "~0.3.0"
},
"description": "Docker as a Service",
"main": "servicedock.js",
diff --git a/nodejs/public/javascripts/servicedock.js b/nodejs/public/javascripts/servicedock.js
index ad5f0cb..1c6b707 100644
--- a/nodejs/public/javascripts/servicedock.js
+++ b/nodejs/public/javascripts/servicedock.js
@@ -13,11 +13,11 @@ var focused = null;
function DockerContainers() {
var Status = Object.freeze({
- Error: {color: "red", action1: "start", action2: "remove"},
- Terminated: {color: "yellow", action1: "start", action2: "remove"},
- Restarting: {color: "lightblue", action1: "start", action2: "remove"},
- Paused: {color: "lightgrey", action1: "unpause", action2: null},
- Running: {color: "lightgreen", action1: "pause", action2: "stop"}
+ Error: {color: "red", action1: "start", action2: "remove", bash: false},
+ Terminated: {color: "yellow", action1: "start", action2: "remove", bash: false},
+ Restarting: {color: "lightblue", action1: "start", action2: "remove", bash: false},
+ Paused: {color: "lightgrey", action1: "unpause", action2: null, bash: false},
+ Running: {color: "lightgreen", action1: "pause", action2: "stop", bash: true}
});
var containers = [];
var nodes = [];
@@ -40,7 +40,7 @@ function DockerContainers() {
if (n.status.action1) {
$("#popup").append('');
$("#popup1").click(function() {
- socket.emit(n.status.action1, name);
+ emit(n.status.action1, name);
});
}
$("#popup").append('');
@@ -50,11 +50,27 @@ function DockerContainers() {
if (n.status.action2) {
$("#popup").append('');
$("#popup3").click(function() {
- socket.emit(n.status.action2, name);
+ emit(n.status.action2, name);
});
}
$("#popup").append('
');
- $("#popup").append('');
+ $("#popup").append('');
+ $("#popup4").click(function() {
+ emit("logs", name);
+ });
+ if (n.status.bash) {
+ $("#popup").append('');
+ $("#popup5").click(function() {
+ emit("bash-start", name);
+ $("#console").show();
+ $("#main").hide();
+ $("#bash").submit(function() {
+ emit("bash-input", {name: name, text: $("#command").val()+"\n"});
+ $("#command").val("");
+ })
+ });
+ }
+ $("#popup").append('');
$("#popup").css("position", "fixed");
$("#popup").css("top", e.pageY-$("#popup").height()/4);
$("#popup").css("left", e.pageX-$("#popup").width()/2);
@@ -66,49 +82,6 @@ function DockerContainers() {
$("#popup").show();
})
}
- this.details = function(name) {
- var res = `
-
| Name | -Ports | -Volumes | -Links | -Environments | -Image | -Command | -
|---|
`; - res += JSON.stringify(containers[nodes[name].id], null, 4); - res += ` --
"+e+"
"+res.join("\n")+"");
- }
- }}).fail(function() {
- error("offline");
- });
-}
-
function containers(c) {
console.log("->rcv containers");
dc.setContainers(c);
@@ -550,6 +493,109 @@ function containers(c) {
overview();
}
+function logs(data) {
+ console.log("->rcv logs("+data.name+")");
+ $("#main").hide();
+ $("#console").hide();
+ $("#logs").show();
+ if (data.type=='done') {
+ $("#logs").append('\nDONE');
+ } else {
+ $("#logs").append(''+htmlenc(data.text)+'');
+ }
+}
+
+function strInsert(str, pos, txt) {
+ return str.slice(0, pos)+txt+str.slice(pos);
+}
+
+function ansifilter(data) {
+ console.log("ansifilter");
+ var res = data;
+ var pos = -1;
+ var spans = 0;
+ while ((pos=res.indexOf("\x1B[")) >= 0) {
+ var end = res.indexOf("m", pos+2);
+ if (end>0) {
+ var control= res.slice(pos+2, end);
+ res = res.slice(0, pos)+res.slice(end+1);
+ control.split(';').forEach(function(c) {
+ switch (parseInt(c)) {
+ // set
+ case 1: res = strInsert(res, pos, ''); ++spans; break;
+ case 2: res = strInsert(res, pos, ''); ++spans; break;
+ case 4: res = strInsert(res, pos, ''); ++spans; break;
+ case 5: res = strInsert(res, pos, ''); ++spans; break;
+ case 7: res = strInsert(res, pos, ''); ++spans; break;
+ case 8: res = strInsert(res, pos, ''); ++spans; break;
+ // reset
+ case 0: for (;spans;--spans) res = strInsert(res, pos, ""); break;
+ case 21: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ case 22: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ case 23: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ case 25: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ case 27: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ case 28: if (spans) --spans; res = strInsert(res, pos, ""); break;
+ // fg colors
+ case 39: res = strInsert(res, pos, ''); ++spans; break;
+ case 30: res = strInsert(res, pos, ''); ++spans; break;
+ case 31: res = strInsert(res, pos, ''); ++spans; break;
+ case 32: res = strInsert(res, pos, ''); ++spans; break;
+ case 33: res = strInsert(res, pos, ''); ++spans; break;
+ case 34: res = strInsert(res, pos, ''); ++spans; break;
+ case 35: res = strInsert(res, pos, ''); ++spans; break;
+ case 36: res = strInsert(res, pos, ''); ++spans; break;
+ case 37: res = strInsert(res, pos, ''); ++spans; break;
+ case 90: res = strInsert(res, pos, ''); ++spans; break;
+ case 91: res = strInsert(res, pos, ''); ++spans; break;
+ case 92: res = strInsert(res, pos, ''); ++spans; break;
+ case 93: res = strInsert(res, pos, ''); ++spans; break;
+ case 94: res = strInsert(res, pos, ''); ++spans; break;
+ case 95: res = strInsert(res, pos, ''); ++spans; break;
+ case 96: res = strInsert(res, pos, ''); ++spans; break;
+ case 97: res = strInsert(res, pos, ''); ++spans; break;
+ // bg colors
+ case 49: res = strInsert(res, pos, ''); ++spans; break;
+ case 40: res = strInsert(res, pos, ''); ++spans; break;
+ case 41: res = strInsert(res, pos, ''); ++spans; break;
+ case 42: res = strInsert(res, pos, ''); ++spans; break;
+ case 43: res = strInsert(res, pos, ''); ++spans; break;
+ case 44: res = strInsert(res, pos, ''); ++spans; break;
+ case 45: res = strInsert(res, pos, ''); ++spans; break;
+ case 46: res = strInsert(res, pos, ''); ++spans; break;
+ case 47: res = strInsert(res, pos, ''); ++spans; break;
+ case 100: res = strInsert(res, pos, ''); ++spans; break;
+ case 101: res = strInsert(res, pos, ''); ++spans; break;
+ case 102: res = strInsert(res, pos, ''); ++spans; break;
+ case 103: res = strInsert(res, pos, ''); ++spans; break;
+ case 104: res = strInsert(res, pos, ''); ++spans; break;
+ case 105: res = strInsert(res, pos, ''); ++spans; break;
+ case 106: res = strInsert(res, pos, ''); ++spans; break;
+ case 107: res = strInsert(res, pos, ''); ++spans; break;
+
+ }
+ });
+ } else {
+ break;
+ }
+ }
+ for (;spans;--spans) res += "";
+ console.log(res);
+ return res.replace(/\r\r\n/g, '\n');
+}
+
+function bash_data(data) {
+ console.log("->rcv bash-data("+data.name+")", data);
+ $("#main").hide();
+ $("#logs").hide();
+ $("#console").show();
+ if (data.type=='done') {
+ $("#screen").append('\nDONE');
+ } else {
+ $("#screen").append(''+ansifilter(htmlenc(data.text))+'');
+ }
+}
+
function overview() {
focused = null;
showviz(dc.graph());
@@ -577,7 +623,9 @@ function init() {
.on("error", disconnected);
socket
.on("fail", error)
- .on("containers", containers);
+ .on("containers", containers)
+ .on("logs", logs)
+ .on("bash-data", bash_data);
start();
}
diff --git a/nodejs/public/stylesheets/servicedock.css b/nodejs/public/stylesheets/servicedock.css
index d126f0e..2aff43a 100644
--- a/nodejs/public/stylesheets/servicedock.css
+++ b/nodejs/public/stylesheets/servicedock.css
@@ -3,6 +3,10 @@
padding: 0;
}
+body {
+ background-color: blue;
+}
+
@media (min-resolution: 120dpi) {
html {
font-size: 120%;
@@ -228,18 +232,22 @@ table.docker li+li {
padding-top: 0.5em;
}
-#main {
+#main, #logs, #console {
position: fixed;
- top: 2em;
+ top: 1.5em;
left: 0;
right: 0;
- bottom: 2em;
- padding: 0em 1em 0em 1em;
+ bottom: 1.5em;
+ padding: 1em 1em 1em 1em;
clear: both;
overflow: auto;
z-index: 0;
}
+#main {
+ background-color: white;
+}
+
#popup {
position: fixed;
background-color: lightblue;
@@ -308,3 +316,62 @@ table.docker li+li {
#preview img {
height: 4em;
}
+
+#logs {
+ background-color: lightgray;
+}
+#logs .stdout {
+ color: black;
+}
+.stderr {
+ color: red;
+}
+.done {
+ color: green;
+}
+
+#console {
+ background-color: black;
+ color: white
+}
+.bold {font-weight: bold}
+.dim {color: grey}
+.underline {text-decoration: underline}
+.blink {animation: blinker 1s linear infinite}
+@keyframes blinker {50% { opacity: 0.0;}}
+.reverse {color: black; background-color: white}
+.hidden {color: black}
+.fgdefault {color: white}
+.fgblack {color: black}
+.fgred {color: red}
+.fggreen {color: green}
+.fgyellow {color: yellow}
+.fgblue {color: blue}
+.fgmagenta {color: magenta}
+.fgcyan {color: cyan}
+.fglightgrey {color: lightgrey}
+.fgdarkgrey {color: darkgrey}
+.fglightred {color: lightred}
+.fglightgreen {color: lightgreen}
+.fglightyellow {color: lightyellow}
+.fglightblue {color: lightblue}
+.fglightmagenta {color: lightmagenta}
+.fglightcyan {color: lightcyan}
+.fgwhite {color: white}
+.bgdefault {background-color: black}
+.bgblack {background-color: black}
+.bgred {background-color: red}
+.bggreen {background-color: green}
+.bgyellow {background-color: yellow}
+.bgblue {background-color: blue}
+.bgmagenta {background-color: magenta}
+.bgcyan {background-color: cyan}
+.bglightgrey {background-color: lightgrey}
+.bgdarkgrey {background-color: darkgrey}
+.bglightred {background-color: lightred}
+.bglightgreen {background-color: lightgreen}
+.bglightyellow {background-color: lightyellow}
+.bglightblue {background-color: lightblue}
+.bglightmagenta {background-color: lightmagenta}
+.bglightcyan {background-color: lightcyan}
+.bgwhite {background-color: white}
diff --git a/nodejs/sockets/index.js b/nodejs/sockets/index.js
index a5670e3..b6c4c19 100644
--- a/nodejs/sockets/index.js
+++ b/nodejs/sockets/index.js
@@ -5,6 +5,7 @@ module.exports = function() {
module.connection = function(socket) {
//var sys = require('sys');
+ var pty = require('pty.js');
var proc = require('child_process');
console.log("new client");
@@ -60,9 +61,7 @@ module.exports = function() {
function modify(cmd, name) {
if (!name.match(/^[a-z0-9][-_:.+a-z0-9]*$/i))
- return fail("illegal instance name", {
- error: error, stderr: stderr, stdout: stdout
- });
+ return fail("illegal instance name");
exec("docker "+cmd+" "+name, updatecontainers);
}
@@ -96,14 +95,62 @@ module.exports = function() {
modify("rm", name);
}
+ function logs(name) {
+ console.log("-> logs("+name+")");
+ var l = proc.spawn("docker", ["logs", "-f", name])
+ .on('close', function(code) {
+ emit('logs', {name: name, type: 'done'});
+ });
+ l.stdout.on('data', function(data) {
+ emit('logs', {name: name, type: 'stdout', text: data.toString()});
+ });
+ l.stderr.on('data', function(data) {
+ emit('logs', {name: name, type: 'stderr', text: data.toString()});
+ });
+ }
+
+ var bash_connections = {};
+
+ function bash_start(name) {
+ console.log("-> bash-start("+name+")");
+ if (!name.match(/^[a-z0-9][-_:.+a-z0-9]*$/i))
+ return fail("illegal instance name");
+ if (bash_connections[name]) return fail("bash already open");
+ bash_connections[name] =
+ pty.spawn("docker", ["exec", "-it", name, "bash", "-i"]);
+ bash_connections[name].stdout.on('data', function(data) {
+ emit('bash-data', {name: name, type: 'stdout', text: data.toString()});
+ });
+ // bash_connections[name].stderr.on('data', function(data) {
+ // emit('bash-data', {name: name, type: 'stdout', text: data.toString()});
+ // });
+ }
+
+ function bash_input(data) {
+ console.log("-> bash-input("+data.name+", "+data.text+")");
+ if (!bash_connections[data.name]) return fail("bash not open");
+ bash_connections[data.name].stdin.resume();
+ bash_connections[data.name].stdin.write(data.text);
+ }
+
+ // function bash_end(name, text) {
+ // console.log("-> bash-end("+name+")");
+ // if (!bash_connections[name]) return fail("bash not open");
+ // bash_connections[name].stdin.close();
+ // }
+
socket
.on("containers", containers)
.on("start", start)
.on("stop", stop)
.on("pause", pause)
.on("unpause", unpause)
- .on("remove", remove);
-
+ .on("remove", remove)
+ .on('logs', logs)
+ .on('bash-start', bash_start)
+ .on('bash-input', bash_input);
+ //.on('bash-end', bash_end);
+
}
return module;
diff --git a/nodejs/views/index.ejs b/nodejs/views/index.ejs
index 5934c35..7e38332 100644
--- a/nodejs/views/index.ejs
+++ b/nodejs/views/index.ejs
@@ -44,6 +44,16 @@
+
+
+
+