with popup menu
This commit is contained in:
		
							
								
								
									
										31
									
								
								ChangeLog
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								ChangeLog
									
									
									
									
									
								
							@@ -1,3 +1,34 @@
 | 
				
			|||||||
 | 
					2015-11-26 15:51  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* html/manage.php: table fixed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2015-11-25 15:26  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* html/images.php, html/index.html.in, html/overview.php,
 | 
				
			||||||
 | 
						  html/rotate.svg, html/servicedock.css, html/servicedock.js,
 | 
				
			||||||
 | 
						  html/zoom.svg: allow image zoom and rotate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2015-11-20 15:14  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* html/images.php, html/servicedock.css: better image overview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2015-11-20 13:49  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* html/makefile.am: typo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2015-11-19 13:13  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* ax_init_standard_project.m4, configure.ac, html/about.php.in,
 | 
				
			||||||
 | 
						  html/images.php, html/index.html.in, html/makefile.am,
 | 
				
			||||||
 | 
						  html/overview.php, html/servicedock.css, html/servicedock.js:
 | 
				
			||||||
 | 
						  added about and images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2015-11-18 15:54  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						* ChangeLog, README, html/details.php, html/manage.php,
 | 
				
			||||||
 | 
						  html/overview.php, html/servicedock.css: added doku for
 | 
				
			||||||
 | 
						  installatin in README
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2015-11-18 13:24  marc
 | 
					2015-11-18 13:24  marc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	* configure.ac, html/details.php, html/index.html.in,
 | 
						* configure.ac, html/details.php, html/index.html.in,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,9 @@ EXTRA_DIST = index.html.in about.php.in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
wwwdir = ${pkgdatadir}/html
 | 
					wwwdir = ${pkgdatadir}/html
 | 
				
			||||||
www_DATA = index.html about.php
 | 
					www_DATA = index.html about.php
 | 
				
			||||||
dist_www_DATA = servicedock.css servicedock.js jquery.js viz.js	\
 | 
					dist_www_DATA = servicedock.css servicedock.js jquery.js viz.js		\
 | 
				
			||||||
                menu.svg overview.php details.php manage.php	\
 | 
					                menu.svg overview.php details.php manage.php		\
 | 
				
			||||||
                action.php jquery-ui.js jquery-ui.css images.php
 | 
					                action.php jquery-ui.js jquery-ui.css images.php	\
 | 
				
			||||||
 | 
					                zoom.svg rotate.svg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAINTAINERCLEANFILES = makefile.in
 | 
					MAINTAINERCLEANFILES = makefile.in
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,14 +124,26 @@ function zoom(incr = 0) {
 | 
				
			|||||||
        case 1: {
 | 
					        case 1: {
 | 
				
			||||||
            $("#main svg").css("width", "100%");
 | 
					            $("#main svg").css("width", "100%");
 | 
				
			||||||
            $("#main svg").css("height", "auto");
 | 
					            $("#main svg").css("height", "auto");
 | 
				
			||||||
            $("#main svg").css("max-width", "100%");
 | 
					            $("#main svg").css("max-width", "none");
 | 
				
			||||||
            $("#main svg").css("max-height", "none");
 | 
					            $("#main svg").css("max-height", "none");
 | 
				
			||||||
        } break;
 | 
					        } break;
 | 
				
			||||||
        case 2: {
 | 
					        case 2: {
 | 
				
			||||||
            $("#main.svg").css("width", "auto");
 | 
					            $("#main.svg").css("width", "auto");
 | 
				
			||||||
            $("#main.svg").css("height", "100%");
 | 
					            $("#main.svg").css("height", "100%");
 | 
				
			||||||
            $("#main.svg").css("max-width", "none");
 | 
					            $("#main.svg").css("max-width", "none");
 | 
				
			||||||
            $("#main.svg").css("max-height", "100%");
 | 
					            $("#main.svg").css("max-height", "none");
 | 
				
			||||||
 | 
					        } break;
 | 
				
			||||||
 | 
					        case 3: {
 | 
				
			||||||
 | 
					            $("#main svg").css("width", "200%");
 | 
				
			||||||
 | 
					            $("#main svg").css("height", "auto");
 | 
				
			||||||
 | 
					            $("#main svg").css("max-width", "none");
 | 
				
			||||||
 | 
					            $("#main svg").css("max-height", "none");
 | 
				
			||||||
 | 
					        } break;
 | 
				
			||||||
 | 
					        case 4: {
 | 
				
			||||||
 | 
					            $("#main.svg").css("width", "auto");
 | 
				
			||||||
 | 
					            $("#main.svg").css("height", "200%");
 | 
				
			||||||
 | 
					            $("#main.svg").css("max-width", "none");
 | 
				
			||||||
 | 
					            $("#main.svg").css("max-height", "none");
 | 
				
			||||||
        } break;
 | 
					        } break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,66 +9,219 @@
 | 
				
			|||||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
					// 45678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var socket = io.connect();
 | 
					var socket = io.connect();
 | 
				
			||||||
 | 
					var focused = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function DockerContainers() {
 | 
					function DockerContainers() {
 | 
				
			||||||
    var Status = Object.freeze({
 | 
					    var Status = Object.freeze({
 | 
				
			||||||
        Error:      "red",
 | 
					        Error:      {color: "red", action1: "start", action2: "remove"},
 | 
				
			||||||
        Terminated: "yellow",
 | 
					        Terminated: {color: "yellow", action1: "start", action2: "remove"},
 | 
				
			||||||
        Restarting: "lightblue",
 | 
					        Restarting: {color: "lightblue", action1: "start", action2: "remove"},
 | 
				
			||||||
        Paused:     "lightgrey",
 | 
					        Paused:     {color: "lightgrey", action1: "unpause", action2: null},
 | 
				
			||||||
        Running:    "lightgreen"
 | 
					        Running:    {color: "lightgreen", action1: "pause", action2: "stop"}
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    var containers = [];
 | 
					    var containers = [];
 | 
				
			||||||
    var nodes = [];
 | 
					    var nodes = [];
 | 
				
			||||||
    this.graph = function() {
 | 
					    function protocol(port) {
 | 
				
			||||||
        var res = "";
 | 
					        if (port.toString().match("443")) return "https://";
 | 
				
			||||||
        console.log("nodes["+nodes.length+"]=", nodes);
 | 
					        if (port.toString().match("3304")) return "mysql://";
 | 
				
			||||||
        for (name in nodes) {
 | 
					        if (port.toString().match("22")) return "ssh://";
 | 
				
			||||||
 | 
					        return "http://";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.exists = function(name) {
 | 
				
			||||||
 | 
					        if (nodes[name]) return true;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.contextmenu = function(selector) {
 | 
				
			||||||
 | 
					        $('a[xlink\\:href^=#]').click(function(e) {
 | 
				
			||||||
 | 
					            name = $(this).attr("xlink:href").replace(/^#/, "");
 | 
				
			||||||
            var n = nodes[name];
 | 
					            var n = nodes[name];
 | 
				
			||||||
            var label = n.name+'\\n'+n.image;
 | 
					            $(selector).prepend('<div id="popup"></div>')
 | 
				
			||||||
            res += '"'+n.name+'"'
 | 
					            $("#popup").empty();
 | 
				
			||||||
                +' [label="'+label
 | 
					            if (n.status.action1) {
 | 
				
			||||||
                +'",URL="details('+"'"+n.name+"'"
 | 
					                $("#popup").append('<button id="popup1">'+n.status.action1+'</button>');
 | 
				
			||||||
                +')",style=filled,fillcolor='+n.status+"];\n";
 | 
					                $("#popup1").click(function() {
 | 
				
			||||||
        }
 | 
					                    socket.emit(n.status.action1, name);
 | 
				
			||||||
        res += "{rank=same;\n";
 | 
					                });
 | 
				
			||||||
        for (name in nodes) {
 | 
					            }
 | 
				
			||||||
            var n = nodes[name];
 | 
					            $("#popup").append('<button id="popup2">'+(focused?"overview":"focus")+'</button>');
 | 
				
			||||||
            n.volumes.forEach(function(v) {
 | 
					            $("#popup2").click(function() {
 | 
				
			||||||
                res += '"'+v.id+'" [label="'+v.inside+'",shape=box];\n';
 | 
					                if (focused) overview(); else details(name);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					            if (n.status.action2) {
 | 
				
			||||||
        res+="}\n";
 | 
					                $("#popup").append('<button id="popup3">'+n.status.action2+'</button>');
 | 
				
			||||||
        res += "{rank=same;\n";
 | 
					                $("#popup3").click(function() {
 | 
				
			||||||
        for (name in nodes) {
 | 
					                    socket.emit(n.status.action2, name);
 | 
				
			||||||
            var n = nodes[name];
 | 
					 | 
				
			||||||
            n.volumes.forEach(function(v) {
 | 
					 | 
				
			||||||
                if (v.host)
 | 
					 | 
				
			||||||
                    res += '"'+v.outside+'" [label="'+v.host+'",shape=box];\n';
 | 
					 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					            }
 | 
				
			||||||
        res+="}\n";
 | 
					            $("#popup").append('<br/>');
 | 
				
			||||||
        for (name in nodes) {
 | 
					            $("#popup").append('<button id="popup4">download</button>');
 | 
				
			||||||
            var n = nodes[name];
 | 
					            $("#popup").css("position", "fixed");
 | 
				
			||||||
            n.volumes.forEach(function(v) {
 | 
					            $("#popup").css("top", e.pageY-$("#popup").height()/4);
 | 
				
			||||||
                if (v.host)
 | 
					            $("#popup").css("left", e.pageX-$("#popup").width()/2);
 | 
				
			||||||
                    res += '"'+v.id+'" -> "'+v.outside+'"\n';
 | 
					            $("#popup").mouseleave(function() {
 | 
				
			||||||
 | 
					                $("#popup").hide();
 | 
				
			||||||
 | 
					            }).click(function() {
 | 
				
			||||||
 | 
					                $("#popup").hide();
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					            $("#popup").show();
 | 
				
			||||||
        for (name in nodes) {
 | 
					        })
 | 
				
			||||||
            var n = nodes[name];
 | 
					    }
 | 
				
			||||||
            n.volumes.forEach(function(v) {
 | 
					    this.details = function(name) {
 | 
				
			||||||
                res += '"'+n.name+'" -> "'+v.id+'"\n';
 | 
					        var res = `
 | 
				
			||||||
            });
 | 
					                <div id="tabs">
 | 
				
			||||||
        }
 | 
					                  <ul>
 | 
				
			||||||
 | 
					                    <li><a href="#tabs-1">Overview</a></li>
 | 
				
			||||||
 | 
					                    <li><a href="#tabs-2">Logs</a></li>
 | 
				
			||||||
 | 
					                    <li><a href="#tabs-3">Dump</a></li>
 | 
				
			||||||
 | 
					                  </ul>
 | 
				
			||||||
 | 
					                  <div id="tabs-1">
 | 
				
			||||||
 | 
					                    <table class="details docker">
 | 
				
			||||||
 | 
					                      <thead>
 | 
				
			||||||
 | 
					                        <tr>
 | 
				
			||||||
 | 
					                          <th>Name</th>
 | 
				
			||||||
 | 
					                          <th>Ports</th>
 | 
				
			||||||
 | 
					                          <th>Volumes</th>
 | 
				
			||||||
 | 
					                          <th>Links</th>
 | 
				
			||||||
 | 
					                          <th>Environments</th>
 | 
				
			||||||
 | 
					                          <th>Image</th>
 | 
				
			||||||
 | 
					                          <th>Command</th>
 | 
				
			||||||
 | 
					                        </tr>
 | 
				
			||||||
 | 
					                      </thead>
 | 
				
			||||||
 | 
					                      <tbody>
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
 | 
					        var n = nodes[name];
 | 
				
			||||||
 | 
					        res += `
 | 
				
			||||||
 | 
					                      </tbody>
 | 
				
			||||||
 | 
					                    </table>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                  <div id="tabs-2">
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                  <div id="tabs-3">
 | 
				
			||||||
 | 
					                    <pre>`;
 | 
				
			||||||
 | 
					        res += JSON.stringify(containers[nodes[name].id], null, 4);
 | 
				
			||||||
 | 
					        res += `
 | 
				
			||||||
 | 
					                    </pre>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <script>
 | 
				
			||||||
 | 
					                  $(function() {$("#tabs").tabs();});
 | 
				
			||||||
 | 
					                </script>
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    function getIps(n, ips) {
 | 
				
			||||||
 | 
					        n.ports.forEach(function(p) {
 | 
				
			||||||
 | 
					            if (!ips[p.ip]) ips[p.ip] = [];
 | 
				
			||||||
 | 
					            ips[p.ip].push(p);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function graphIpClusters(ips) {
 | 
				
			||||||
 | 
					        var res = "newrank=true;\n";
 | 
				
			||||||
 | 
					        var i = 0;
 | 
				
			||||||
 | 
					        for (ip in ips) {
 | 
				
			||||||
 | 
					            res += "subgraph clusterIp"+(++i)+' {\nlabel="'+ip+'";\n';
 | 
				
			||||||
 | 
					            ips[ip].forEach(function(p) {
 | 
				
			||||||
 | 
					                res += '"'+p.ip+":"+p.external
 | 
				
			||||||
 | 
					                    +'" [label="'+p.external+'",URL="'
 | 
				
			||||||
 | 
					                    +protocol(p.internal)+p.ip+':'+p.external+'",shape=box];\n';
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            res+="}\n";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        res += "{rank=same;\n";
 | 
				
			||||||
 | 
					        for (ip in ips) {
 | 
				
			||||||
 | 
					            ips[ip].forEach(function(p) {
 | 
				
			||||||
 | 
					                res += '"'+p.ip+":"+p.external+'";\n';
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        res+="}\n";
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function graphNode(n) {
 | 
				
			||||||
 | 
					        var res = "";
 | 
				
			||||||
 | 
					        var label = n.name+'\\n'+n.image;
 | 
				
			||||||
 | 
					        res += '"'+n.name+'"'
 | 
				
			||||||
 | 
					            +' [label="'+label
 | 
				
			||||||
 | 
					            +'",URL="#'+n.name
 | 
				
			||||||
 | 
					            +'",style=filled,fillcolor='+n.status.color+"];\n";
 | 
				
			||||||
 | 
					        n.ports.forEach(function(p) {
 | 
				
			||||||
 | 
					            res += '"'+(p.ip?p.ip+":":"")+p.external+'" -> "'+n.name
 | 
				
			||||||
 | 
					                +'" [label="'+p.internal+'"];\n';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        n.links.forEach(function(l) {
 | 
				
			||||||
 | 
					            res += '"'+n.name+'" -> "'+l.to+'" [label="link: '+l.link+'"];\n'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function graphVolumesInside(n) {
 | 
				
			||||||
 | 
					        var res = "";
 | 
				
			||||||
 | 
					        n.volumes.forEach(function(v) {
 | 
				
			||||||
 | 
					            res += '"'+v.id+'" [label="'+v.inside+'",shape=box];\n';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function graphVolumesOutside(n) {
 | 
				
			||||||
 | 
					        var res = "";
 | 
				
			||||||
 | 
					        n.volumes.forEach(function(v) {
 | 
				
			||||||
 | 
					            if (v.host)
 | 
				
			||||||
 | 
					                res += '"'+v.outside+'" [label="'+v.host+'",shape=box];\n';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function graphVolumesConnections(n) {
 | 
				
			||||||
 | 
					        var res = "";
 | 
				
			||||||
 | 
					        n.volumes.forEach(function(v) {
 | 
				
			||||||
 | 
					            if (v.host)
 | 
				
			||||||
 | 
					                res += '"'+v.id+'" -> "'+v.outside+'" [label="mounted from"]\n';
 | 
				
			||||||
 | 
					            res += '"'+n.name+'" -> "'+v.id+'" [label="volume/'+v.rw+'"]\n';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        n.volumesfrom.forEach(function(o) {
 | 
				
			||||||
 | 
					            res += '"'+n.name+'" -> "'+nodes[o].name+'" [label="volumes from"]\n';
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.graph = function(n) {
 | 
				
			||||||
 | 
					        var res = "";
 | 
				
			||||||
 | 
					        var ips = [];
 | 
				
			||||||
 | 
					        n = n || nodes;
 | 
				
			||||||
 | 
					        for (name in n) getIps(n[name], ips);
 | 
				
			||||||
 | 
					        res += graphIpClusters(ips);
 | 
				
			||||||
 | 
					        for (name in n) res += graphNode(n[name]);        
 | 
				
			||||||
 | 
					        res += "{rank=same;\n";
 | 
				
			||||||
 | 
					        for (name in n) res += graphVolumesInside(n[name]);
 | 
				
			||||||
 | 
					        res+="}\n";
 | 
				
			||||||
 | 
					        res += "{rank=same;\n";
 | 
				
			||||||
 | 
					        for (name in n) res += graphVolumesOutside(n[name]);
 | 
				
			||||||
 | 
					        res+="}\n";
 | 
				
			||||||
 | 
					        for (name in n) res += graphVolumesConnections(n[name]);
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function addNodes(ns, name) {
 | 
				
			||||||
 | 
					        var n = nodes[name];
 | 
				
			||||||
 | 
					        ns[name] = n;
 | 
				
			||||||
 | 
					        n.links.forEach(function(peer) {
 | 
				
			||||||
 | 
					            if (!ns[peer.to]) addNodes(ns, peer.to);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        n.usedby.forEach(function(peer) {
 | 
				
			||||||
 | 
					            if (!ns[peer]) addNodes(ns, peer);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        n.volumesfrom.forEach(function(peer) {
 | 
				
			||||||
 | 
					            if (!ns[peer]) addNodes(ns, peer);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        n.volumesto.forEach(function(peer) {
 | 
				
			||||||
 | 
					            if (!ns[peer]) addNodes(ns, peer);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.subgraph = function(name) {
 | 
				
			||||||
 | 
					        var ns = [];
 | 
				
			||||||
 | 
					        addNodes(ns, name);
 | 
				
			||||||
 | 
					        return this.graph(ns);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    function setup() {
 | 
					    function setup() {
 | 
				
			||||||
        delete nodes; nodes=[];
 | 
					        delete nodes; nodes = [];
 | 
				
			||||||
        containers.forEach(function(c) {
 | 
					        containers.forEach(function(c, i) {
 | 
				
			||||||
            var name = c.Name.replace(/^\//, "");
 | 
					            var name = c.Name.replace(/^\//, "");
 | 
				
			||||||
            nodes[name] = {};
 | 
					            if (!nodes[name]) nodes[name] = {};
 | 
				
			||||||
            console.log("container: "+name);
 | 
					            nodes[name].id = i;
 | 
				
			||||||
            nodes[name].name = name;
 | 
					            nodes[name].name = name;
 | 
				
			||||||
            nodes[name].image = c.Config.Image;
 | 
					            nodes[name].image = c.Config.Image;
 | 
				
			||||||
            nodes[name].ports = [];
 | 
					            nodes[name].ports = [];
 | 
				
			||||||
@@ -78,43 +231,80 @@ function DockerContainers() {
 | 
				
			|||||||
                    if (ports[port])
 | 
					                    if (ports[port])
 | 
				
			||||||
                        for (var expose in ports[port]) {
 | 
					                        for (var expose in ports[port]) {
 | 
				
			||||||
                            var ip = ports[port][expose].HostIp;
 | 
					                            var ip = ports[port][expose].HostIp;
 | 
				
			||||||
                            if (ip==""||ip=="127.0.0.1"||ip=="0.0.0.0") ip=null;
 | 
					                            if (!ip||ip==""||ip=="0.0.0.0"||ip==0) ip=window.location.hostname;
 | 
				
			||||||
                            nodes[name].ports.push({
 | 
					                            nodes[name].ports.push({
 | 
				
			||||||
                                internal: port,
 | 
					                                internal: port,
 | 
				
			||||||
                                external: ports[port][expose].HostPort,
 | 
					                                external: ports[port][expose].HostPort,
 | 
				
			||||||
                                ip: ip
 | 
					                                ip: ip
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
            if (c.State.Running) nodes[name].status = Status.Running;
 | 
					            if (c.State.Paused) nodes[name].status = Status.Paused;
 | 
				
			||||||
            else if (c.State.Paused) nodes[name].status = Status.Paused;
 | 
					            else if (c.State.Running) nodes[name].status = Status.Running;
 | 
				
			||||||
            else if (c.State.Restarting) nodes[name].status = Status.Restarting;
 | 
					            else if (c.State.Restarting) nodes[name].status = Status.Restarting;
 | 
				
			||||||
            else if (c.State.ExitCode == 0) nodes[name].status = Status.Terminated;
 | 
					            else if (c.State.ExitCode == 0) nodes[name].status = Status.Terminated;
 | 
				
			||||||
            else nodes[name].status = Status.Error;
 | 
					            else nodes[name].status = Status.Error;
 | 
				
			||||||
 | 
					            console.log("STATUS", name, c.State, nodes[name].status);
 | 
				
			||||||
            nodes[name].volumes = [];
 | 
					            nodes[name].volumes = [];
 | 
				
			||||||
            var volumes = c.Volumes || c.Config.Volumes;
 | 
					            var volumes = c.Volumes || c.Config.Volumes;
 | 
				
			||||||
            nodes[name].volumes = [];
 | 
					            nodes[name].volumes = [];
 | 
				
			||||||
            if (volumes)
 | 
					            if (volumes)
 | 
				
			||||||
                for (var volume in volumes) {
 | 
					                for (var volume in volumes) {
 | 
				
			||||||
 | 
					                    var rw = "rw";
 | 
				
			||||||
                    var outside = (typeof volumes[volume]=="string")?volumes[volume]:null;
 | 
					                    var outside = (typeof volumes[volume]=="string")?volumes[volume]:null;
 | 
				
			||||||
 | 
					                    if (c.Mounts) c.Mounts.forEach(function(mnt) {
 | 
				
			||||||
 | 
					                        if (mnt.Destination==volume) {
 | 
				
			||||||
 | 
					                            outside = mnt.Source;
 | 
				
			||||||
 | 
					                            rw = mnt.RW ? "rw" : "ro";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
                    nodes[name].volumes.push({
 | 
					                    nodes[name].volumes.push({
 | 
				
			||||||
                        id: volume+':'+(outside?outside:name),
 | 
					                        id: volume+':'+(outside?outside:name),
 | 
				
			||||||
 | 
					                        rw:rw,
 | 
				
			||||||
                        inside: volume,
 | 
					                        inside: volume,
 | 
				
			||||||
                        outside: outside,
 | 
					                        outside: outside,
 | 
				
			||||||
                        host: outside && !outside.match(/^\/var\/lib\/docker/)
 | 
					                        host: outside && !outside.match(/^\/var\/lib\/docker/)
 | 
				
			||||||
                            ? volumes[volume] : null
 | 
					                            ? outside : null
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            nodes[name].volumesfrom = c.VolumesFrom;
 | 
					            nodes[name].volumesfrom = [];
 | 
				
			||||||
 | 
					            if (!nodes[name].volumesto) nodes[name].volumesto = [];
 | 
				
			||||||
 | 
					            if (c.HostConfig.VolumesFrom) c.HostConfig.VolumesFrom.forEach(function(id) {
 | 
				
			||||||
 | 
					                containers.forEach(function(c) {
 | 
				
			||||||
 | 
					                    if (c.Id == id || c.Name == "/"+id || c.Name == id) {
 | 
				
			||||||
 | 
					                        var src = c.Name.replace(/^\//, "");
 | 
				
			||||||
 | 
					                        nodes[name].volumesfrom.push(src);
 | 
				
			||||||
 | 
					                        if (!nodes[src]) nodes[src] = {};
 | 
				
			||||||
 | 
					                        if (!nodes[src].volumesto) nodes[src].volumesto = [];
 | 
				
			||||||
 | 
					                        nodes[src].volumesto.push(name);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
            nodes[name].links = [];
 | 
					            nodes[name].links = [];
 | 
				
			||||||
 | 
					            if (!nodes[name].usedby) nodes[name].usedby = [];
 | 
				
			||||||
            if (c.HostConfig && c.HostConfig.Links)
 | 
					            if (c.HostConfig && c.HostConfig.Links)
 | 
				
			||||||
                c.HostConfig.Links.forEach(function(l) {
 | 
					                c.HostConfig.Links.forEach(function(l) {
 | 
				
			||||||
                    nodes[name].links.push({
 | 
					                    var target = {
 | 
				
			||||||
                        to:   l.replace(/^\/?([^:]*).*$/, "$1"),
 | 
					                        to:   l.replace(/^\/?([^:]*).*$/, "$1"),
 | 
				
			||||||
                        link: l.replace(new RegExp("^.*:/?"+name+"/"), "")
 | 
					                        link: l.replace(new RegExp("^.*:/?"+name+"/"), "")
 | 
				
			||||||
                    });
 | 
					                    };
 | 
				
			||||||
 | 
					                    nodes[name].links.push(target);
 | 
				
			||||||
 | 
					                    if (!nodes[target.to]) nodes[target.to] = {};
 | 
				
			||||||
 | 
					                    if (!nodes[target.to].usedby) nodes[target.to].usedby = [];
 | 
				
			||||||
 | 
					                    nodes[target.to].usedby.push(name);
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            console.log(nodes[name]);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					        for (name in nodes) { // cleanup duplicate links to volumes when using volumes-from
 | 
				
			||||||
 | 
					            var n = nodes[name];
 | 
				
			||||||
 | 
					            n.volumesfrom.forEach(function(other) {
 | 
				
			||||||
 | 
					                var o = nodes[other];
 | 
				
			||||||
 | 
					                o.volumes.forEach(function(ovol) {
 | 
				
			||||||
 | 
					                    n.volumes.reduceRight(function(x, nvol, i, arr) {
 | 
				
			||||||
 | 
					                        if (nvol.id == ovol.id)
 | 
				
			||||||
 | 
					                            arr.splice(i, 1);
 | 
				
			||||||
 | 
					                    }, [])
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.setContainers = function(c) {
 | 
					    this.setContainers = function(c) {
 | 
				
			||||||
        if (typeof c == "string") c = JSON.parse(c);
 | 
					        if (typeof c == "string") c = JSON.parse(c);
 | 
				
			||||||
@@ -131,7 +321,7 @@ var dc = new DockerContainers();
 | 
				
			|||||||
    @param data (optional) The error can be a string or any structure.
 | 
					    @param data (optional) The error can be a string or any structure.
 | 
				
			||||||
                Strings are shown to the user, structures are logged only.
 | 
					                Strings are shown to the user, structures are logged only.
 | 
				
			||||||
    @param stay (optional) If not given as @c true, reloads page after 5s. */
 | 
					    @param stay (optional) If not given as @c true, reloads page after 5s. */
 | 
				
			||||||
function error(data, stay) {
 | 
					function error(data) {
 | 
				
			||||||
    $("#status").fadeOut("slow", function() {
 | 
					    $("#status").fadeOut("slow", function() {
 | 
				
			||||||
        $("#status").addClass("error")
 | 
					        $("#status").addClass("error")
 | 
				
			||||||
        $("#status").removeClass("notice")
 | 
					        $("#status").removeClass("notice")
 | 
				
			||||||
@@ -149,7 +339,6 @@ function error(data, stay) {
 | 
				
			|||||||
            console.log("error");
 | 
					            console.log("error");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $("#status").fadeIn("slow");
 | 
					        $("#status").fadeIn("slow");
 | 
				
			||||||
        if (!stay) setTimeout(start, 5000);
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -195,14 +384,14 @@ function success(text) {
 | 
				
			|||||||
/** @param text Text is a message or some complex HTML from the server.
 | 
					/** @param text Text is a message or some complex HTML from the server.
 | 
				
			||||||
    @param msg The success message text */
 | 
					    @param msg The success message text */
 | 
				
			||||||
function status(text, msg) {
 | 
					function status(text, msg) {
 | 
				
			||||||
    $("#main").fadeOut("slow", function() {
 | 
					    $("#main").hide();
 | 
				
			||||||
        $("#main").html(text);
 | 
					    $("#main").html(text);
 | 
				
			||||||
        if (msg) success(msg);
 | 
					    $("#popup").hide();
 | 
				
			||||||
        else setTimeout("$('#status').fadeOut('slow')", 5000);
 | 
					    if (msg) success(msg);
 | 
				
			||||||
        $("#main").fadeIn("slow", function() {
 | 
					    else setTimeout("$('#status').fadeOut('slow')", 5000);
 | 
				
			||||||
            $("form input:first-child").focus();
 | 
					    $("#main").show();
 | 
				
			||||||
        })
 | 
					    $("form input:first-child").focus();
 | 
				
			||||||
    });
 | 
					    dc.contextmenu("#main");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function emit(signal, data) {
 | 
					function emit(signal, data) {
 | 
				
			||||||
@@ -278,6 +467,7 @@ function zoom(incr = 0) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var viz = null;
 | 
					var viz = null;
 | 
				
			||||||
 | 
					var vizmore = null;
 | 
				
			||||||
var rankdir = "LR";
 | 
					var rankdir = "LR";
 | 
				
			||||||
function rotateviz() {
 | 
					function rotateviz() {
 | 
				
			||||||
    if (!viz) return;
 | 
					    if (!viz) return;
 | 
				
			||||||
@@ -285,16 +475,21 @@ function rotateviz() {
 | 
				
			|||||||
        rankdir = "TB";
 | 
					        rankdir = "TB";
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        rankdir = "LR";
 | 
					        rankdir = "LR";
 | 
				
			||||||
    showviz(viz);
 | 
					    showviz();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
function showviz(vizpath) {
 | 
					function showviz(vizpath, more) {
 | 
				
			||||||
    $("#imagetools").show();
 | 
					    $("#imagetools").show();
 | 
				
			||||||
    viz = vizpath;
 | 
					    if (!vizpath) {
 | 
				
			||||||
    console.log("DRAW: "+viz);
 | 
					        vizpath = viz;
 | 
				
			||||||
 | 
					        more = vizmore;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        viz = vizpath;
 | 
				
			||||||
 | 
					        vizmore = more;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    res = "digraph {\n"+"  rankdir="+rankdir+";\n"+viz+"\n}";
 | 
					    res = "digraph {\n"+"  rankdir="+rankdir+";\n"+viz+"\n}";
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        zoomlevel = 0;
 | 
					        zoomlevel = 0;
 | 
				
			||||||
        status(Viz(res));
 | 
					        status(more?Viz(res)+more:Viz(res));
 | 
				
			||||||
    } catch(e) {
 | 
					    } catch(e) {
 | 
				
			||||||
        (res = res.split("\n")).forEach(function(v, i, a) {
 | 
					        (res = res.split("\n")).forEach(function(v, i, a) {
 | 
				
			||||||
            a[i] = ("000"+(i+1)).slice(-3)+": "+v;
 | 
					            a[i] = ("000"+(i+1)).slice(-3)+": "+v;
 | 
				
			||||||
@@ -303,18 +498,10 @@ function showviz(vizpath) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function details(c) {
 | 
					function details(name) {
 | 
				
			||||||
    $("#imagetools").hide();
 | 
					    if (name) focused = name;
 | 
				
			||||||
    $.ajax({url: "details.php?container="+c, success: function(res) {
 | 
					    else if (!focused) return overview();
 | 
				
			||||||
        try {
 | 
					    showviz(dc.subgraph(focused));
 | 
				
			||||||
            status(res);
 | 
					 | 
				
			||||||
        } catch(e) {
 | 
					 | 
				
			||||||
            status("<pre>"+res+"</pre>");
 | 
					 | 
				
			||||||
            error("Exception Caught: "+e);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }}).fail(function() {
 | 
					 | 
				
			||||||
        error("offline");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function action(container, action) {
 | 
					function action(container, action) {
 | 
				
			||||||
@@ -337,11 +524,6 @@ function manage() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Show an Overview of all Docker Services */
 | 
					 | 
				
			||||||
function overview() {
 | 
					 | 
				
			||||||
    $("#imagetools").hide();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Show an Overview of all Docker Images */
 | 
					/** Show an Overview of all Docker Images */
 | 
				
			||||||
function imgs() {
 | 
					function imgs() {
 | 
				
			||||||
    $("#imagetools").hide();
 | 
					    $("#imagetools").hide();
 | 
				
			||||||
@@ -362,6 +544,14 @@ function imgs() {
 | 
				
			|||||||
function containers(c) {
 | 
					function containers(c) {
 | 
				
			||||||
    console.log("->rcv containers");
 | 
					    console.log("->rcv containers");
 | 
				
			||||||
    dc.setContainers(c);
 | 
					    dc.setContainers(c);
 | 
				
			||||||
 | 
					    if (focused && dc.exists(focused))
 | 
				
			||||||
 | 
					        details(focused);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        overview();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function overview() {
 | 
				
			||||||
 | 
					    focused = null;
 | 
				
			||||||
    showviz(dc.graph());
 | 
					    showviz(dc.graph());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -380,11 +570,14 @@ function start() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function init() {
 | 
					function init() {
 | 
				
			||||||
    socket.io.on("connect", connected);
 | 
					    socket.io
 | 
				
			||||||
    socket.io.on("reconnect", connected);
 | 
					        .on("connect", connected)
 | 
				
			||||||
    socket.io.on("disconnect", disconnected);
 | 
					        .on("reconnect", connected)
 | 
				
			||||||
    socket.io.on("error", disconnected);
 | 
					        .on("disconnect", disconnected)
 | 
				
			||||||
    socket.on("containers", containers);
 | 
					        .on("error", disconnected);
 | 
				
			||||||
 | 
					    socket
 | 
				
			||||||
 | 
					        .on("fail", error)
 | 
				
			||||||
 | 
					        .on("containers", containers);
 | 
				
			||||||
    start();
 | 
					    start();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,8 @@ svg {
 | 
				
			|||||||
  max-height: 100%;
 | 
					  max-height: 100%;
 | 
				
			||||||
  width: auto;
 | 
					  width: auto;
 | 
				
			||||||
  height: auto;
 | 
					  height: auto;
 | 
				
			||||||
 | 
					  z-index: -1;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
form {
 | 
					form {
 | 
				
			||||||
@@ -238,6 +240,13 @@ table.docker li+li {
 | 
				
			|||||||
  z-index: 0;
 | 
					  z-index: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#popup {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  background-color: lightblue;
 | 
				
			||||||
 | 
					  border: .1ex solid blue;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.clear {
 | 
					.clear {
 | 
				
			||||||
  clear: both;
 | 
					  clear: both;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,13 +4,13 @@ module.exports = function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    module.connection = function(socket) {
 | 
					    module.connection = function(socket) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var sys = require('sys');
 | 
					        //var sys = require('sys');
 | 
				
			||||||
        var exec = require('child_process').exec;
 | 
					        var proc = require('child_process');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.log("new client");
 | 
					        console.log("new client");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        function emit(signal, data, info) {
 | 
					        function emit(signal, data, info) {
 | 
				
			||||||
            if (typeof data == 'string') {
 | 
					            if (typeof data == 'string' && !data.match("\n")) {
 | 
				
			||||||
                console.log("<- signal: "+signal+"("+data+")");
 | 
					                console.log("<- signal: "+signal+"("+data+")");
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                console.log("<- signal: "+signal);
 | 
					                console.log("<- signal: "+signal);
 | 
				
			||||||
@@ -24,31 +24,86 @@ module.exports = function() {
 | 
				
			|||||||
            socket.broadcast.emit(signal, data);
 | 
					            socket.broadcast.emit(signal, data);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function exec(cmd, callback) {
 | 
				
			||||||
 | 
					            console.log("== "+cmd);
 | 
				
			||||||
 | 
					            proc.exec(cmd, callback);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function fail(txt, data) {
 | 
				
			||||||
 | 
					            console.log("** "+txt, data);
 | 
				
			||||||
 | 
					            emit("fail", txt);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        function containerinspect(error, stdout, stderr) {
 | 
					        function containerinspect(error, stdout, stderr) {
 | 
				
			||||||
            console.log(error);
 | 
					            if (error || stderr)
 | 
				
			||||||
            if (!error && !stderr) {
 | 
					                return fail("inspect docker containers failed", {
 | 
				
			||||||
                // var res = {};
 | 
					                    error: error, stderr: stderr, stdout: stdout
 | 
				
			||||||
                // JSON.parse(stdout).forEach(function(c) {
 | 
					                });
 | 
				
			||||||
                //     res[c.Id] = c;
 | 
					            emit("containers", stdout);
 | 
				
			||||||
                // });
 | 
					 | 
				
			||||||
                emit("containers", stdout);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        function containerlist(error, stdout, stderr) {
 | 
					        function containerlist(error, stdout, stderr) {
 | 
				
			||||||
            console.log(error);
 | 
					            if (error || stderr)
 | 
				
			||||||
            console.log("docker inspect "+stdout.trim().replace(/\n/g, " "));
 | 
					                return fail("list docker containers failed", {
 | 
				
			||||||
            if (!error && !stderr)
 | 
					                    error: error, stderr: stderr, stdout: stdout
 | 
				
			||||||
                exec("docker inspect "+stdout.trim().replace(/\n/g, " "),
 | 
					                });
 | 
				
			||||||
                     containerinspect);
 | 
					            exec("docker inspect "+stdout.trim().replace(/\n/g, " "), containerinspect);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket.on("containers", function() {
 | 
					        function updatecontainers(error, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (error || stderr)
 | 
				
			||||||
 | 
					                return fail("update docker container failed", {
 | 
				
			||||||
 | 
					                    error: error, stderr: stderr, stdout: stdout
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            exec("docker ps -aq", containerlist);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            exec("docker "+cmd+" "+name, updatecontainers);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function containers() {
 | 
				
			||||||
            console.log("-> containers");
 | 
					            console.log("-> containers");
 | 
				
			||||||
            exec("docker ps -aq",
 | 
					            updatecontainers();
 | 
				
			||||||
                 containerlist);
 | 
					        }
 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket
 | 
				
			||||||
 | 
					            .on("containers", containers)
 | 
				
			||||||
 | 
					            .on("start", start)
 | 
				
			||||||
 | 
					            .on("stop", stop)
 | 
				
			||||||
 | 
					            .on("pause", pause)
 | 
				
			||||||
 | 
					            .on("unpause", unpause)
 | 
				
			||||||
 | 
					            .on("remove", remove);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return module;
 | 
					    return module;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,9 +43,12 @@
 | 
				
			|||||||
      <p>start up engine, please wait ...</p>
 | 
					      <p>start up engine, please wait ...</p>
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div id="status">
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      <noscript>JavaScript is required for the interface.</noscript>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
<div id="status">
 | 
					  </body>
 | 
				
			||||||
  
 | 
					</html>
 | 
				
			||||||
  <noscript>JavaScript is required for the interface.</noscript>
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user