From e1c8152f372e6dce4810867c3ea5a10b3774982b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Thu, 24 Nov 2016 14:52:53 +0000 Subject: [PATCH] most docker client parts have been moved to docker.js; this version works --- nodejs/package.json.in | 7 +- nodejs/public/javascripts/servicedock.js | 150 +++----------- nodejs/servicedock.js | 5 +- nodejs/sockets/index.js | 252 +---------------------- nodejs/views/index.ejs | 6 +- 5 files changed, 36 insertions(+), 384 deletions(-) diff --git a/nodejs/package.json.in b/nodejs/package.json.in index c2f8f87..d329aea 100644 --- a/nodejs/package.json.in +++ b/nodejs/package.json.in @@ -7,12 +7,9 @@ "stylus": "~0.53.0", "ejs": ">= 0.0.1", "socket.io": "~1.4.4", - "pty.js": "~0.3.0", - "async": "~1.5.2", "socketio-auth": "0.0.5", - "authentication.js": ">= 0.0.2", - "docker.js": ">= 0.0.0", - "ldapauth": "git+https://github.com/DimensionSoftware/node-ldapauth.git" + "authentication.js": ">= 1.0.0", + "docker.js": ">= 0.2.4" }, "description": "@DESCRIPTION@", "main": "@PACKAGE_NAME@.js", diff --git a/nodejs/public/javascripts/servicedock.js b/nodejs/public/javascripts/servicedock.js index 16b2524..a5dbf7c 100644 --- a/nodejs/public/javascripts/servicedock.js +++ b/nodejs/public/javascripts/servicedock.js @@ -9,9 +9,7 @@ // 45678901234567890123456789012345678901234567890123456789012345678901234567890 var socket = null; -var focused = null; - -var docker = new Docker(); +var docker = null; function htmlenc(html) { return $('
').text(html).html(); @@ -97,7 +95,6 @@ function status(text, msg) { zoom(0); $("#main").show(); $("form input:first-child").focus(); - docker.containers.contextmenu("#main"); } function emit(signal, data) { @@ -206,7 +203,7 @@ function previewCreate() { }); $('#dosend').unbind().click(function() { if (Object.keys(tobecreated).length>0) { - emit("create", docker.containers.configuration(tobecreated)); + emit("docker.container.create", docker.containers.configuration(tobecreated)); tobecreated = {}; showImage(); } @@ -285,110 +282,6 @@ function zoom(incr = 0) { } } -var viz = null; -var vizmore = null; -var rankdir = "LR"; -function rotateviz() { - if (!viz) return; - if (rankdir == "LR") - rankdir = "TB"; - else - rankdir = "LR"; - showviz(); - previewCreate(); -} -function showviz(vizpath, more) { - if (!vizpath) { - vizpath = viz; - more = vizmore; - } else { - viz = vizpath; - vizmore = more; - } - res = "digraph {\n"+" rankdir="+rankdir+";\n"+viz+"\n}"; - try { - status(more?Viz(res)+more:Viz(res)); - stats(); - $('#main a > ellipse + text').attr('font-size', '12'); - $('#main a > ellipse + text + text') - .attr('font-weight', 'bold') - .attr('font-size', '16') - .each(function() {$(this).attr('y', parseFloat($(this).attr('y'))+1.0)}); - $('#main a > ellipse + text + text + text, #main a > ellipse + text + text + text + text').attr('font-size', '10'); - } catch(e) { - (res = res.split("\n")).forEach(function(v, i, a) { - a[i] = ("000"+(i+1)).slice(-3)+": "+v; - }); - status("

Exception Caught:

"+e+"

"+res.join("\n")+"
"); - } -} - -function details(name) { - if (name) focused = name; - else if (!focused) return overview(); - showviz(docker.containers.subgraph(focused)); -} - -/// Convert number of bytes to readable text -function size(num) { - if (num>0.6*1024) { - if (num>0.6*1024*1024) { - if (num>0.6*1024*1024*1024) { - if (num>0.6*1024*1024*1024*1024) { - return Math.round(num/1024/1024/1024/1024)+"TB"; - } else { - return Math.round(num/1024/1024/1024)+"GB"; - } - } else { - return Math.round(num/1024/1024)+"MB"; - } - } else { - return Math.round(num/1024)+"kB"; - } - } else { - return num+"B"; - } -} - -var laststats=null; -function stats(data) { - if (data) - console.log("->rcv stats"); - else - data=laststats; - if (!data) return; - var lines = data.split("\n"); - var head = lines.shift(); - lines.forEach(function(line) { - if (!line) return; - elements = line.split(/ +/); - $('#main text + text:contains("'+elements[0]+'") + text + text') - .html('cpu: '+elements[1]+' mem: '+elements[7]); - $('#main text + text:contains("'+elements[0]+'") + text') - .html('net: '+elements[8]+elements[9]+' '+elements[11]+elements[12] - +' block: '+elements[13]+elements[14]+' '+elements[16]+elements[17]); - }); -} - -function images(i) { - console.log("->rcv images"); - docker.images.set(i); - $('#imagedata').empty().append(docker.images.tags().map(function(i) { - var option = document.createElement('option'); - option.value = i; - return option; - })); -} - -function containers(c) { - console.log("->rcv containers"); - docker.containers.set(c); - if (focused && docker.containers.exists(focused)) - details(focused); - else - overview(); -} - function showLogin() { $("#close").hide(); $("#console").hide(); @@ -443,6 +336,16 @@ function showLogs() { $("#main").hide(); } +function images(i) { + console.log("->rcv images"); + docker.images.set(i); + $('#imagedata').empty().append(docker.images.tags().map(function(i) { + var option = document.createElement('option'); + option.value = i; + return option; + })); +} + function logs(data) { console.log("->rcv logs("+data.name+")"); if (data.type=='done') { @@ -568,11 +471,6 @@ function bash_data(data) { $("#screen").focus(); } -function overview() { - focused = null; - showviz(docker.containers.graph()); -} - /// Initial Function: Startup /** To be called after login */ function start() { @@ -582,8 +480,8 @@ function start() { $("#menu").hide(); try { status("Starting up ..."); - emit("images"); - emit("containers"); + emit("docker.images"); + emit("docker.containers"); showImage(); } catch (m) { error(m); @@ -601,8 +499,8 @@ function initForms() { var obj = this; this.getAttribute('data-name').split(' ').forEach(function(n) { res += 'data-'+n+'="'+ - (obj.type!='checkbox'||obj.checked - ?obj.value:obj.getAttribute('data-false')) + (obj.type!='checkbox'||obj.checked + ?obj.value:obj.getAttribute('data-false')) .replace(/&/g, '&') .replace(/"/g, '"') +'"'; @@ -629,6 +527,10 @@ function initForms() { function init() { socket = io.connect(); + docker = new Docker(socket, '#main', error); + $("#server").html($("#username").value+'@'+window.location.hostname) + initForms(); + showLogin(); socket .io .on("connect", connect) @@ -638,15 +540,9 @@ function init() { socket .on("authenticated", authenticated) .on("unauthorized", unauthorized) - .on("fail", error) - .on("containers", containers) - .on("images", images) - .on("stats", stats) - .on("logs", logs) - .on("bash-data", bash_data); - $("#server").html($("#username").value+'@'+window.location.hostname) - initForms(); - showLogin(); + .on("docker.images", images) + .on("docker.container.logs", logs) + .on("docker.container.bash.data", bash_data); } /// On Load, Call @ref start diff --git a/nodejs/servicedock.js b/nodejs/servicedock.js index c7cb87a..82262b1 100644 --- a/nodejs/servicedock.js +++ b/nodejs/servicedock.js @@ -20,13 +20,12 @@ try { var express = require('express') , routes = require(__dirname+'/routes'); - var app = module.exports = express.createServer(); + var app = express.createServer(); var io = require('socket.io').listen(app); var package = require(__dirname+'/package.json'); var config = require(package.path.config); - var docker = require('docker.js')(app); var authentication = require('authentication.js')(config.restrict); - var sockets = require(__dirname+'/sockets')(app, io, docker, authentication); + var sockets = require(__dirname+'/sockets')(app, io, authentication); // Configuration process.argv.forEach(function(val, index) { diff --git a/nodejs/sockets/index.js b/nodejs/sockets/index.js index a565a4a..a63a74b 100644 --- a/nodejs/sockets/index.js +++ b/nodejs/sockets/index.js @@ -1,247 +1,17 @@ -module.exports = function(app, io, docker, authentication) { - - var pty = require('pty.js'); - var proc = require('child_process'); - - var module={}; - var running=""; - - function broadcast(signal, data) { - console.log("<= signal: "+signal); - io.sockets.emit(signal, data); - } - - function exec(cmd, callback) { - if (cmd.length>40) { - console.log("== "+cmd.slice(0, 30+cmd.slice(30).indexOf(' '))+" ..."); - } else { - console.log("== "+cmd); - } - proc.exec(cmd, {maxBuffer: 10*1024*1024}, callback); - } - - function fail(txt, data) { - console.log("** "+txt, data); - } - - var oldcontainer = null; - function containerinspect(error, stdout, stderr) { - if (error || stderr) - return fail("inspect docker containers failed", { - error: error, stderr: stderr, stdout: stdout - }); - running = ""; - JSON.parse(stdout).forEach(function(n) { - if (n.State.Running) running+=" "+n.Name.replace(/^\//, ''); - }); - if (oldcontainer!=stdout) broadcast("containers", stdout); - oldcontainer = stdout; - } +module.exports = function(app, io, authentication) { - function containerlist(error, stdout, stderr) { - if (error || stderr) - return fail("list docker containers failed", { - error: error, stderr: stderr, stdout: stdout - }); - var containers = stdout.trim().replace(/\n/g, " "); - exec("docker inspect "+containers, containerinspect); - } - - function updatecontainers(error, stdout, stderr) { - if (error || stderr) - return fail("update docker container failed", { - error: error, stderr: stderr, stdout: stdout - }); - exec("docker ps -aq --no-trunc ", containerlist); - } - - var oldimage = null; - function imageinspect(error, stdout, stderr) { - if (error || stderr) - return fail("inspect docker images failed", { - error: error, stderr: stderr, stdout: stdout - }); - if (oldimage && oldimage==stdout) return; // do not resend same images - oldimage = stdout; - broadcast("images", stdout); - } - - function imagelist(error, stdout, stderr) { - if (error || stderr) - return fail("list docker images failed", { - error: error, stderr: stderr, stdout: stdout - }); - exec("docker inspect "+stdout.trim().replace(/\n/g, " "), - imageinspect); - } - - function updateimages(error, stdout, stderr) { - if (error || stderr) - return fail("update docker images failed", { - error: error, stderr: stderr, stdout: stdout - }); - exec("docker images -q --no-trunc", imagelist); - } + var docker = require('docker.js')(app, io); + // New Authenticated Client function connection(socket, userdata) { - console.log("=> new connection from "+userdata.username); - - function emit(signal, data, info) { - if (typeof data == 'string' && !data.match("\n")) { - console.log("<- signal: "+signal+"("+data+")"); - } else { - console.log("<- signal: "+signal); - } - if (info) console.log(info); - socket.emit(signal, data); - } - - function fail(txt, data) { - console.log("** "+txt, data); - emit("fail", txt); - } - - function modify(cmd, name) { - if (!name.match(/^[a-z0-9][-_:.+a-z0-9]*$/i)) - return this.fail("illegal instance name"); - exec("docker "+cmd+" "+name, updatecontainers); - } - - function createContainer(cmds) { - if (cmds.length>0) - exec(cmds.shift(), function(error, stdout, stderr) { - if (error || stderr) - return this.fail("create container failed", { - error: error, stderr: stderr, stdout: stdout - }); - createContainer(cmds); - }) - else - updatecontainers(); - } - - function containers() { - console.log("-> containers"); - if (oldcontainer) emit("containers", oldcontainer); - else updatecontainers(); - } - - function images() { - console.log("-> images"); - if (oldimage) emit("images", oldimage); - else updateimages(); - } - - function start(name) { - console.log("-> start("+name+")"); - modify("start", name); - } - - function stop(name) { - console.log("-> stop("+name+")"); - modify("stop", name); - } - - function pause(name) { - console.log("-> pause("+name+")"); - modify("pause", name); - } - - function unpause(name) { - console.log("-> unpause("+name+")"); - modify("unpause", name); - } - - function remove(name) { - console.log("-> remove("+name+")"); - modify("rm", name); - } - - function create(data) { - console.log("-> create"); - var d = new docker.Docker(); - var dc = new d.Containers(); - createContainer(dc.creation(data)); - } - - 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 new_bash(name) { - if (!name.match(/^[a-z0-9][-_:.+a-z0-9]*$/i)) - return this.fail("illegal instance name"); - if (bash_connections[name]) return; - 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: 'stderr', text: data.toString()}); - }); - } - - function bash_start(name) { - console.log("-> bash-start("+name+")"); - new_bash(name); - } - - function bash_input(data) { - console.log("-> bash-input("+data.name+", "+data.text+")"); - new_bash(data.name); - 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; - bash_connections[name].stdin.close(); - delete bash_connections[name]; bash_connections[name] = null; - } - - socket - .on("containers", containers) - .on("images", images) - .on("start", start) - .on("stop", stop) - .on("pause", pause) - .on("unpause", unpause) - .on("remove", remove) - .on("create", create) - .on('logs', logs) - .on('bash-start', bash_start) - .on('bash-input', bash_input) - .on('bash-end', bash_end); - + docker.connect(socket); } - function stats(error, stdout, stderr) { - if (error || stderr) - return fail("get containers stats failed", { - error: error, stderr: stderr, stdout: stdout - }); - broadcast("stats", stdout); - } - - // Handle Connection + // Handle Connection Authentication require('socketio-auth')(io, { authenticate: function (socket, data, callback) { console.log("=> authenticate: ", data.username); - //get credentials sent by the client authentication(data.username, data.password, function() { console.log("####LOGIN-SUCESS####"); @@ -256,16 +26,6 @@ module.exports = function(app, io, docker, authentication) { timeout: "none" }); - // Regular Update of Images and Containers - setInterval(function() { - updateimages(); - updatecontainers(); - }, 10000); - - // Regular Update of Stats - setInterval(function() { - if (running) exec('docker stats --no-stream'+running, stats); - }, 1000); - + var module = {}; return module; } diff --git a/nodejs/views/index.ejs b/nodejs/views/index.ejs index 52d7487..8ef0808 100644 --- a/nodejs/views/index.ejs +++ b/nodejs/views/index.ejs @@ -7,9 +7,9 @@ - + - + ServiceDock: Docker as a Service @@ -21,7 +21,7 @@