diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..f8d21a2 --- /dev/null +++ b/api/api.go @@ -0,0 +1,28 @@ +package main // import "github.com/kevana/ui-for-docker" + +import ( + "flag" + "log" + "net/http" +) + +func main() { + var ( + endpoint = flag.String("H", "unix:///var/run/docker.sock", "Dockerd endpoint") + addr = flag.String("p", ":9000", "Address and port to serve UI For Docker") + assets = flag.String("a", ".", "Path to the assets") + data = flag.String("d", ".", "Path to the data") + tlsverify = flag.Bool("tlsverify", false, "TLS support") + tlscacert = flag.String("tlscacert", "/certs/ca.pem", "Path to the CA") + tlscert = flag.String("tlscert", "/certs/cert.pem", "Path to the TLS certificate file") + tlskey = flag.String("tlskey", "/certs/key.pem", "Path to the TLS key") + ) + flag.Parse() + + tlsFlags := newTLSFlags(*tlsverify, *tlscacert, *tlscert, *tlskey) + + handler := newHandler(*assets, *data, *endpoint, tlsFlags) + if err := http.ListenAndServe(*addr, handler); err != nil { + log.Fatal(err) + } +} diff --git a/api/csrf.go b/api/csrf.go new file mode 100644 index 0000000..4377ee3 --- /dev/null +++ b/api/csrf.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/gorilla/csrf" + "github.com/gorilla/securecookie" + "io/ioutil" + "log" + "net/http" +) + +const keyFile = "authKey.dat" + +// newAuthKey reuses an existing CSRF authkey if present or generates a new one +func newAuthKey(path string) []byte { + var authKey []byte + authKeyPath := path + "/" + keyFile + data, err := ioutil.ReadFile(authKeyPath) + if err != nil { + log.Print("Unable to find an existing CSRF auth key. Generating a new key.") + authKey = securecookie.GenerateRandomKey(32) + err := ioutil.WriteFile(authKeyPath, authKey, 0644) + if err != nil { + log.Fatal("Unable to persist CSRF auth key.") + log.Fatal(err) + } + } else { + authKey = data + } + return authKey +} + +// newCSRF initializes a new CSRF handler +func newCSRFHandler(keyPath string) func(h http.Handler) http.Handler { + authKey := newAuthKey(keyPath) + return csrf.Protect( + authKey, + csrf.HttpOnly(false), + csrf.Secure(false), + ) +} + +// newCSRFWrapper wraps a http.Handler to add the CSRF token +func newCSRFWrapper(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-CSRF-Token", csrf.Token(r)) + h.ServeHTTP(w, r) + }) +} diff --git a/api/flags.go b/api/flags.go new file mode 100644 index 0000000..9076e64 --- /dev/null +++ b/api/flags.go @@ -0,0 +1,19 @@ +package main + +// TLSFlags defines all the flags associated to the SSL configuration +type TLSFlags struct { + tls bool + caPath string + certPath string + keyPath string +} + +// newTLSFlags creates a new TLSFlags from command flags +func newTLSFlags(tls bool, cacert string, cert string, key string) TLSFlags { + return TLSFlags{ + tls: tls, + caPath: cacert, + certPath: cert, + keyPath: key, + } +} diff --git a/api/handler.go b/api/handler.go new file mode 100644 index 0000000..bf09fb6 --- /dev/null +++ b/api/handler.go @@ -0,0 +1,75 @@ +package main + +import ( + "log" + "net/http" + "net/http/httputil" + "net/url" + "os" +) + +// newHandler creates a new http.Handler with CSRF protection +func newHandler(dir string, d string, e string, tlsFlags TLSFlags) http.Handler { + var ( + mux = http.NewServeMux() + fileHandler = http.FileServer(http.Dir(dir)) + ) + + u, perr := url.Parse(e) + if perr != nil { + log.Fatal(perr) + } + + handler := newAPIHandler(u, tlsFlags) + CSRFHandler := newCSRFHandler(d) + + mux.Handle("/dockerapi/", http.StripPrefix("/dockerapi", handler)) + mux.Handle("/", fileHandler) + return CSRFHandler(newCSRFWrapper(mux)) +} + +// newAPIHandler initializes a new http.Handler based on the URL scheme +func newAPIHandler(u *url.URL, tlsFlags TLSFlags) http.Handler { + var handler http.Handler + if u.Scheme == "tcp" { + if tlsFlags.tls { + handler = newTCPHandlerWithTLS(u, tlsFlags) + } else { + handler = newTCPHandler(u) + } + } else if u.Scheme == "unix" { + socketPath := u.Path + if _, err := os.Stat(socketPath); err != nil { + if os.IsNotExist(err) { + log.Fatalf("Unix socket %s does not exist", socketPath) + } + log.Fatal(err) + } + handler = newUnixHandler(socketPath) + } else { + log.Fatalf("Bad Docker enpoint: %s. Only unix:// and tcp:// are supported.", u) + } + return handler +} + +// newUnixHandler initializes a new UnixHandler +func newUnixHandler(e string) http.Handler { + return &unixHandler{e} +} + +// newTCPHandler initializes a HTTP reverse proxy +func newTCPHandler(u *url.URL) http.Handler { + u.Scheme = "http" + return httputil.NewSingleHostReverseProxy(u) +} + +// newTCPHandlerWithL initializes a HTTPS reverse proxy with a TLS configuration +func newTCPHandlerWithTLS(u *url.URL, tlsFlags TLSFlags) http.Handler { + u.Scheme = "https" + var tlsConfig = newTLSConfig(tlsFlags) + proxy := httputil.NewSingleHostReverseProxy(u) + proxy.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + return proxy +} diff --git a/api/ssl.go b/api/ssl.go new file mode 100644 index 0000000..6d86db5 --- /dev/null +++ b/api/ssl.go @@ -0,0 +1,27 @@ +package main + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "log" +) + +// newTLSConfig initializes a tls.Config from the TLS flags +func newTLSConfig(tlsFlags TLSFlags) *tls.Config { + cert, err := tls.LoadX509KeyPair(tlsFlags.certPath, tlsFlags.keyPath) + if err != nil { + log.Fatal(err) + } + caCert, err := ioutil.ReadFile(tlsFlags.caPath) + if err != nil { + log.Fatal(err) + } + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCertPool, + } + return tlsConfig +} diff --git a/api/unix_handler.go b/api/unix_handler.go new file mode 100644 index 0000000..15a5119 --- /dev/null +++ b/api/unix_handler.go @@ -0,0 +1,47 @@ +package main + +import ( + "io" + "log" + "net" + "net/http" + "net/http/httputil" +) + +// unixHandler defines a handler holding the path to a socket under UNIX +type unixHandler struct { + path string +} + +// ServeHTTP implementation for unixHandler +func (h *unixHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + conn, err := net.Dial("unix", h.path) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Println(err) + return + } + c := httputil.NewClientConn(conn, nil) + defer c.Close() + + res, err := c.Do(r) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Println(err) + return + } + defer res.Body.Close() + + copyHeader(w.Header(), res.Header) + if _, err := io.Copy(w, res.Body); err != nil { + log.Println(err) + } +} + +func copyHeader(dst, src http.Header) { + for k, vv := range src { + for _, v := range vv { + dst.Add(k, v) + } + } +} diff --git a/app/app.js b/app/app.js index 67ae697..0fe4489 100644 --- a/app/app.js +++ b/app/app.js @@ -97,4 +97,4 @@ angular.module('uifordocker', [ // You need to set this to the api endpoint without the port i.e. http://192.168.1.9 .constant('DOCKER_ENDPOINT', 'dockerapi') .constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is requred. If you have a port, prefix it with a ':' i.e. :4243 - .constant('UI_VERSION', 'v0.11.0-beta'); + .constant('UI_VERSION', 'v0.11.0'); diff --git a/app/components/containers/containersController.js b/app/components/containers/containersController.js index 02f7dbc..174b5d4 100644 --- a/app/components/containers/containersController.js +++ b/app/components/containers/containersController.js @@ -37,7 +37,7 @@ angular.module('containers', []) Container.get({id: c.Id}, function (d) { c = d; counter = counter + 1; - action({id: c.Id, HostConfig: c.HostConfig || {}}, function (d) { + action({id: c.Id}, {}, function (d) { Messages.send("Container " + msg, c.Id); var index = $scope.containers.indexOf(c); complete(); diff --git a/app/components/startContainer/startContainerController.js b/app/components/startContainer/startContainerController.js index bc7527b..79c1970 100644 --- a/app/components/startContainer/startContainerController.js +++ b/app/components/startContainer/startContainerController.js @@ -125,19 +125,10 @@ angular.module('startContainer', ['ui.bootstrap']) var s = $scope; Container.create(config, function (d) { if (d.Id) { - var reqBody = config.HostConfig || {}; - reqBody.id = d.Id; - ctor.start(reqBody, function (cd) { - if (cd.id) { - Messages.send('Container Started', d.Id); - $('#create-modal').modal('hide'); - loc.path('/containers/' + d.Id + '/'); - } else { - failedRequestHandler(cd, Messages); - ctor.remove({id: d.Id}, function () { - Messages.send('Container Removed', d.Id); - }); - } + ctor.start({id: d.Id}, {}, function (cd) { + Messages.send('Container Started', d.Id); + $('#create-modal').modal('hide'); + loc.path('/containers/' + d.Id + '/'); }, function (e) { failedRequestHandler(e, Messages); }); diff --git a/bower.json b/bower.json index 9271a98..8b5258a 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "uifordocker", - "version": "0.11.0-beta", + "version": "0.11.0", "homepage": "https://github.com/kevana/ui-for-docker", "authors": [ "Michael Crosby ", diff --git a/dist/ui-for-docker b/dist/ui-for-docker index 114b9a6..01246c3 100755 Binary files a/dist/ui-for-docker and b/dist/ui-for-docker differ diff --git a/dist/uifordocker.js b/dist/uifordocker.js index 22516c8..1833320 100644 --- a/dist/uifordocker.js +++ b/dist/uifordocker.js @@ -1,9 +1,9 @@ -/*! uifordocker - v0.11.0-beta - 2016-07-13 +/*! uifordocker - v0.11.0 - 2016-09-07 * https://github.com/kevana/ui-for-docker * Copyright (c) 2016 Michael Crosby & Kevan Ahlquist; * Licensed MIT */ -function ImageViewModel(a){this.Id=a.Id,this.Tag=a.Tag,this.Repository=a.Repository,this.Created=a.Created,this.Checked=!1,this.RepoTags=a.RepoTags,this.VirtualSize=a.VirtualSize}function ContainerViewModel(a){this.Id=a.Id,this.Image=a.Image,this.Command=a.Command,this.Created=a.Created,this.SizeRw=a.SizeRw,this.Status=a.Status,this.Checked=!1,this.Names=a.Names}angular.module("uifordocker",["uifordocker.templates","ngRoute","uifordocker.services","uifordocker.filters","masthead","footer","dashboard","container","containers","containersNetwork","images","image","pullImage","startContainer","sidebar","info","builder","containerLogs","containerTop","events","stats","network","networks","volumes"]).config(["$routeProvider","$httpProvider",function(a,b){"use strict";b.defaults.xsrfCookieName="csrfToken",b.defaults.xsrfHeaderName="X-CSRF-Token",a.when("/",{templateUrl:"app/components/dashboard/dashboard.html",controller:"DashboardController"}),a.when("/containers/",{templateUrl:"app/components/containers/containers.html",controller:"ContainersController"}),a.when("/containers/:id/",{templateUrl:"app/components/container/container.html",controller:"ContainerController"}),a.when("/containers/:id/logs/",{templateUrl:"app/components/containerLogs/containerlogs.html",controller:"ContainerLogsController"}),a.when("/containers/:id/top",{templateUrl:"app/components/containerTop/containerTop.html",controller:"ContainerTopController"}),a.when("/containers/:id/stats",{templateUrl:"app/components/stats/stats.html",controller:"StatsController"}),a.when("/containers_network",{templateUrl:"app/components/containersNetwork/containersNetwork.html",controller:"ContainersNetworkController"}),a.when("/images/",{templateUrl:"app/components/images/images.html",controller:"ImagesController"}),a.when("/images/:id*/",{templateUrl:"app/components/image/image.html",controller:"ImageController"}),a.when("/info",{templateUrl:"app/components/info/info.html",controller:"InfoController"}),a.when("/events",{templateUrl:"app/components/events/events.html",controller:"EventsController"}),a.otherwise({redirectTo:"/"}),b.interceptors.push(function(){return{response:function(a){"string"==typeof a.data&&(a.data.startsWith("Conflict.")||a.data.startsWith("conflict:"))&&$.gritter.add({title:"Error",text:$("
").text(a.data).html(),time:1e4});var b=a.headers("X-Csrf-Token");return b&&(document.cookie="csrfToken="+b),a}}})}]).constant("DOCKER_ENDPOINT","dockerapi").constant("DOCKER_PORT","").constant("UI_VERSION","v0.11.0-beta"),angular.module("builder",[]).controller("BuilderController",["$scope",function(a){a.template="app/components/builder/builder.html"}]),angular.module("container",[]).controller("ContainerController",["$scope","$routeParams","$location","Container","ContainerCommit","Image","Messages","ViewSpinner","$timeout",function(a,b,c,d,e,f,g,h,i){a.changes=[],a.editEnv=!1,a.editPorts=!1,a.editBinds=!1,a.newCfg={Env:[],Ports:{}};var j=function(){h.spin(),d.get({id:b.id},function(b){a.container=b,a.container.edit=!1,a.container.newContainerName=b.Name,b.Config.Env&&(a.newCfg.Env=b.Config.Env.map(function(a){return{name:a.split("=")[0],value:a.split("=")[1]}})),a.newCfg.Ports={},angular.forEach(b.Config.ExposedPorts,function(c,d){b.HostConfig.PortBindings&&d in b.HostConfig.PortBindings?a.newCfg.Ports[d]=b.HostConfig.PortBindings[d]:a.newCfg.Ports[d]=[]}),a.newCfg.Binds=[];var c={};angular.forEach(b.Config.Volumes,function(a,b){c[b]={ContPath:b,HostPath:"",ReadOnly:!1,DefaultBind:!0}}),angular.forEach(b.HostConfig.Binds,function(b,d){var e=b.split(":")[0],f=b.split(":")[1]||"",g=b.split(":").length>2&&"ro"===b.split(":")[2],h=!1;""===f&&(f=e,e=""),f in c&&(delete c[f],h=!0),a.newCfg.Binds.push({ContPath:f,HostPath:e,ReadOnly:g,DefaultBind:h})}),angular.forEach(c,function(b){a.newCfg.Binds.push(b)}),h.stop()},function(a){404===a.status?($(".detail").hide(),g.error("Not found","Container not found.")):g.error("Failure",a.data),h.stop()})};a.start=function(){h.spin(),d.start({id:a.container.Id,HostConfig:a.container.HostConfig},function(a){j(),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})},a.stop=function(){h.spin(),d.stop({id:b.id},function(a){j(),g.send("Container stopped",b.id)},function(a){j(),g.error("Failure","Container failed to stop."+a.data)})},a.kill=function(){h.spin(),d.kill({id:b.id},function(a){j(),g.send("Container killed",b.id)},function(a){j(),g.error("Failure","Container failed to die."+a.data)})},a.restartEnv=function(){var i=angular.copy(a.container.Config);i.Env=a.newCfg.Env.map(function(a){return a.name+"="+a.value});var k=angular.copy(a.newCfg.Ports);angular.forEach(k,function(a,b){0===a.length&&delete k[b]});var l=[];angular.forEach(a.newCfg.Binds,function(a){if(""!==a.ContPath){var b="";""!==a.HostPath&&(b=a.HostPath+":"),b+=a.ContPath,a.ReadOnly&&(b+=":ro"),""===a.HostPath&&a.DefaultBind||l.push(b)}}),h.spin(),e.commit({id:b.id,tag:a.container.Config.Image,config:i},function(e){if("Id"in e){var h=e.Id;f.inspect({id:h},function(e){e.Config.HostConfig=angular.copy(a.container.HostConfig),e.Config.HostConfig.PortBindings=k,e.Config.HostConfig.Binds=l,"host"===e.Config.HostConfig.NetworkMode&&(e.Config.Hostname=""),d.create(e.Config,function(e){return"Id"in e?void(a.container.State.Running?d.stop({id:b.id},function(a){g.send("Container stopped",b.id),d.start({id:e.Id},function(a){c.url("/containers/"+e.Id+"/"),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})},function(a){j(),g.error("Failure","Container failed to stop."+a.data)}):d.start({id:e.Id},function(a){c.url("/containers/"+e.Id+"/"),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})):void g.error("Failure","Container failed to create.")},function(a){j(),g.error("Failure","Image failed to get."+a.data)})},function(a){j(),g.error("Failure","Image failed to get."+a.data)})}else j(),g.error("Failure","Container commit failed.")},function(a){j(),g.error("Failure","Container failed to commit."+a.data)})},a.commit=function(){h.spin(),e.commit({id:b.id,repo:a.container.Config.Image},function(a){j(),g.send("Container commited",b.id)},function(a){j(),g.error("Failure","Container failed to commit."+a.data)})},a.pause=function(){h.spin(),d.pause({id:b.id},function(a){j(),g.send("Container paused",b.id)},function(a){j(),g.error("Failure","Container failed to pause."+a.data)})},a.unpause=function(){h.spin(),d.unpause({id:b.id},function(a){j(),g.send("Container unpaused",b.id)},function(a){j(),g.error("Failure","Container failed to unpause."+a.data)})},a.remove=function(){h.spin(),d.remove({id:b.id},function(a){j(),c.path("/containers"),g.send("Container removed",b.id)},function(a){j(),g.error("Failure","Container failed to remove."+a.data)})},a.restart=function(){h.spin(),d.restart({id:b.id},function(a){j(),g.send("Container restarted",b.id)},function(a){j(),g.error("Failure","Container failed to restart."+a.data)})},a.hasContent=function(a){return null!==a&&void 0!==a},a.getChanges=function(){h.spin(),d.changes({id:b.id},function(b){a.changes=b,h.stop()})},a.renameContainer=function(){d.rename({id:b.id,name:a.container.newContainerName},function(c){c.name?(a.container.Name=c.name,g.send("Container renamed",b.id)):(a.container.newContainerName=a.container.Name,g.error("Failure","Container failed to rename."))}),a.container.edit=!1},a.addEntry=function(a,b){a.push(b)},a.rmEntry=function(a,b){var c=a.indexOf(b);a.splice(c,1)},a.toggleEdit=function(){a.edit=!a.edit},j(),a.getChanges()}]),angular.module("containerLogs",[]).controller("ContainerLogsController",["$scope","$routeParams","$location","$anchorScroll","ContainerLogs","Container","ViewSpinner",function(a,b,c,d,e,f,g){function h(){g.spin(),e.get(b.id,{stdout:1,stderr:0,timestamps:a.showTimestamps,tail:a.tailLines},function(b,c,d,e){b=b.replace(/[\r]/g,"\n"),b=b.substring(8),b=b.replace(/\n(.{8})/g,"\n"),a.stdout=b,g.stop()}),e.get(b.id,{stdout:0,stderr:1,timestamps:a.showTimestamps,tail:a.tailLines},function(b,c,d,e){b=b.replace(/[\r]/g,"\n"),b=b.substring(8),b=b.replace(/\n(.{8})/g,"\n"),a.stderr=b,g.stop()})}a.stdout="",a.stderr="",a.showTimestamps=!1,a.tailLines=2e3,g.spin(),f.get({id:b.id},function(b){a.container=b,g.stop()},function(a){404===a.status?Messages.error("Not found","Container not found."):Messages.error("Failure",a.data),g.stop()}),h();var i=window.setInterval(h,5e3);a.$on("$destroy",function(){clearInterval(i)}),a.scrollTo=function(a){c.hash(a),d()},a.toggleTimestamps=function(){h()},a.toggleTail=function(){h()}}]),angular.module("containerTop",[]).controller("ContainerTopController",["$scope","$routeParams","ContainerTop","Container","ViewSpinner",function(a,b,c,d,e){a.ps_args="",a.getTop=function(){e.spin(),c.get(b.id,{ps_args:a.ps_args},function(b){a.containerTop=b,e.stop()})},d.get({id:b.id},function(b){a.containerName=b.Name.substring(1)},function(a){Messages.error("Failure",a.data)}),a.getTop()}]),angular.module("containers",[]).controller("ContainersController",["$scope","Container","Settings","Messages","ViewSpinner",function(a,b,c,d,e){a.sortType="Created",a.sortReverse=!0,a.toggle=!1,a.displayAll=c.displayAll,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b};var f=function(c){e.spin(),b.query(c,function(b){a.containers=b.map(function(a){return new ContainerViewModel(a)}),e.stop()})},g=function(g,h,i){e.spin();var j=0,k=function(){j-=1,0===j&&(e.stop(),f({all:c.displayAll?1:0}))};angular.forEach(g,function(c){c.Checked&&(h===b.start?b.get({id:c.Id},function(b){c=b,j+=1,h({id:c.Id,HostConfig:c.HostConfig||{}},function(b){d.send("Container "+i,c.Id);a.containers.indexOf(c);k()},function(a){d.error("Failure",a.data),k()})},function(a){404===a.status?($(".detail").hide(),d.error("Not found","Container not found.")):d.error("Failure",a.data),k()}):(j+=1,h({id:c.Id},function(b){d.send("Container "+i,c.Id);a.containers.indexOf(c);k()},function(a){d.error("Failure",a.data),k()})))}),0===j&&e.stop()};a.toggleSelectAll=function(){angular.forEach(a.filteredContainers,function(b){b.Checked=a.toggle})},a.toggleGetAll=function(){c.displayAll=a.displayAll,f({all:c.displayAll?1:0})},a.startAction=function(){g(a.containers,b.start,"Started")},a.stopAction=function(){g(a.containers,b.stop,"Stopped")},a.restartAction=function(){g(a.containers,b.restart,"Restarted")},a.killAction=function(){g(a.containers,b.kill,"Killed")},a.pauseAction=function(){g(a.containers,b.pause,"Paused")},a.unpauseAction=function(){g(a.containers,b.unpause,"Unpaused")},a.removeAction=function(){g(a.containers,b.remove,"Removed")},f({all:c.displayAll?1:0})}]),angular.module("containersNetwork",["ngVis"]).controller("ContainersNetworkController",["$scope","$location","Container","Messages","VisDataSet",function(a,b,c,d,f){function g(a){this.Id=a.Id,this.Name=a.Name.substring(1),this.Image=a.Config.Image,this.Running=a.State.Running;var b=a.HostConfig.Links;if(null!=b){this.Links={};for(var c=0;c
  • ID: '+a.Id+"
  • Image: "+a.Image+"
  • ",color:a.Running?"#8888ff":"#cccccc"})},this.hasEdge=function(a,b){return this.edges.getIds({filter:function(c){return c.from===a.Id&&c.to===b.Id}}).length>0},this.addLinkEdgeIfExists=function(a,b){null==a.Links||null==a.Links[b.Name]||this.hasEdge(a,b)||this.edges.add({from:a.Id,to:b.Id,label:a.Links[b.Name]})},this.addVolumeEdgeIfExists=function(a,b){null==a.VolumesFrom||null==a.VolumesFrom[b.Id]&&null==a.VolumesFrom[b.Name]||this.hasEdge(a,b)||this.edges.add({from:a.Id,to:b.Id,color:{color:"#A0A0A0",highlight:"#A0A0A0",hover:"#848484"}})},this.removeContainersNodes=function(a){this.nodes.remove(a)}}function i(){this.data=new h,this.containers={},this.selectedContainersIds=[],this.shownContainersIds=[],this.events={select:function(b){a.network.selectedContainersIds=b.nodes,a.$apply(function(){a.query=""})},doubleClick:function(c){a.$apply(function(){b.path("/containers/"+c.nodes[0])})}},this.options={navigation:!0,keyboard:!0,height:"500px",width:"700px",nodes:{shape:"box"},edges:{style:"arrow"},physics:{barnesHut:{springLength:200}}},this.addContainer=function(a){var b=new g(a);this.containers[b.Id]=b,this.shownContainersIds.push(b.Id),this.data.addContainerNode(b);for(var c in this.containers){var d=this.containers[c];this.data.addLinkEdgeIfExists(b,d),this.data.addLinkEdgeIfExists(d,b),this.data.addVolumeEdgeIfExists(b,d),this.data.addVolumeEdgeIfExists(d,b)}},this.selectContainers=function(a){null!=this.component&&(this.selectedContainersIds=this.searchContainers(a),this.component.selectNodes(this.selectedContainersIds))},this.searchContainers=function(a){if(""===a.trim())return[];for(var b=[],c=0;c-1||d.Image.indexOf(a)>-1||d.Id.indexOf(a)>-1)&&b.push(d.Id)}return b},this.hideSelected=function(){for(var b=0;b-1?this.shownContainersIds.splice(b,1):b++;this.data.removeContainersNodes(this.selectedContainersIds),a.query="",this.selectedContainersIds=[]},this.searchDownstream=function(a,b){if(!(b.indexOf(a)>-1)){b.push(a);var c=this.containers[a];if(null!=c.Links||null!=c.VolumesFrom)for(var d in this.containers){var e=this.containers[d];null!=c.Links&&null!=c.Links[e.Name]?this.searchDownstream(e.Id,b):null!=c.VolumesFrom&&null!=c.VolumesFrom[e.Id]&&this.searchDownstream(e.Id,b)}}},this.updateShownContainers=function(a){for(var b in this.containers)a.indexOf(b)>-1&&-1===this.shownContainersIds.indexOf(b)?this.data.addContainerNode(this.containers[b]):-1===a.indexOf(b)&&this.shownContainersIds.indexOf(b)>-1&&this.data.removeContainersNodes(b);this.shownContainersIds=a},this.showSelectedDownstream=function(){for(var a=[],b=0;b-1)){b.push(a);var c=this.containers[a];for(var d in this.containers){var e=this.containers[d];null!=e.Links&&null!=e.Links[c.Name]?this.searchUpstream(e.Id,b):null!=e.VolumesFrom&&null!=e.VolumesFrom[c.Id]&&this.searchUpstream(e.Id,b)}}},this.showSelectedUpstream=function(){for(var a=[],b=0;b:"!==c.RepoTags[0]&&(a.RepoTags=c.RepoTags)})})}a.history=[],a.tagInfo={repo:"",version:"",force:!1},a.id="",a.repoTags=[],a.removeImage=function(b){e.remove({id:b},function(b){b.forEach(function(a){var b=Object.keys(a)[0];g.send(b,a[b])}),b[b.length-1].Deleted?d.path("/images"):d.path("/images/"+a.id)},function(b){a.error=b.data,$("#error-message").show()})},a.getHistory=function(){e.history({id:c.id},function(b){a.history=b})},a.addTag=function(){var b=a.tagInfo;e.tag({id:c.id,repo:b.repo,tag:b.version,force:b.force?1:0},function(b){g.send("Tag Added",c.id),d.path("/images/"+a.id)},function(b){a.error=b.data,$("#error-message").show()})},e.get({id:c.id},function(c){a.image=c,a.id=c.Id,c.RepoTags?a.RepoTags=c.RepoTags:j(a.id),i(b,f,a.id).then(function(a){h.build("#containers-started-chart",a,function(a){return new Date(1e3*a.Created).toLocaleDateString()})})},function(b){404===b.status?($(".detail").hide(),a.error="Image not found.
    "+c.id):a.error=b.data,$("#error-message").show()}),a.getHistory()}]),angular.module("images",[]).controller("ImagesController",["$scope","Image","ViewSpinner","Messages",function(a,b,c,d){a.sortType="Created",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.showBuilder=function(){$("#build-modal").modal("show")},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.images,function(c){c.Checked&&(e+=1,b.remove({id:c.Id},function(b){angular.forEach(b,function(a){d.send("Image deleted",a.Deleted)});var e=a.images.indexOf(c);a.images.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredImages,function(b){b.Checked=a.toggle})},c.spin(),b.query({},function(b){a.images=b.map(function(a){return new ImageViewModel(a)}),c.stop()},function(a){d.error("Failure",a.data),c.stop()})}]),angular.module("info",[]).controller("InfoController",["$scope","Info","Version","Settings",function(a,b,c,d){a.info={},a.docker={},a.endpoint=d.endpoint,c.get({},function(b){a.docker=b}),b.get({},function(b){a.info=b})}]),angular.module("masthead",[]).controller("MastheadController",["$scope","Version",function(a,b){a.template="app/components/masthead/masthead.html",a.showNetworksVolumes=!1,b.get(function(b){b.ApiVersion>=1.21&&(a.showNetworksVolumes=!0)}),a.refresh=function(){location.reload()}}]),angular.module("network",[]).config(["$routeProvider",function(a){a.when("/networks/:id/",{templateUrl:"app/components/network/network.html",controller:"NetworkController"})}]).controller("NetworkController",["$scope","Network","ViewSpinner","Messages","$routeParams","$location","errorMsgFilter",function(a,b,c,d,e,f,g){a.disconnect=function(a,g){c.spin(),b.disconnect({id:e.id},{Container:g},function(a){c.stop(),d.send("Container disconnected",g),f.path("/networks/"+e.id)},function(a){c.stop(),d.error("Failure",a.data)})},a.connect=function(a,h){c.spin(),b.connect({id:e.id},{Container:h},function(a){c.stop();var b=g(a);b?d.error("Error",b):d.send("Container connected",a),f.path("/networks/"+e.id)},function(a){c.stop(),d.error("Failure",a.data)})},a.remove=function(a){c.spin(),b.remove({id:e.id},function(a){c.stop(),d.send("Network removed",a),f.path("/networks")},function(a){c.stop(),d.error("Failure",a.data)})},c.spin(),b.get({id:e.id},function(b){a.network=b,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}]),angular.module("networks",[]).config(["$routeProvider",function(a){a.when("/networks/",{templateUrl:"app/components/networks/networks.html",controller:"NetworksController"})}]).controller("NetworksController",["$scope","Network","ViewSpinner","Messages","$route","errorMsgFilter",function(a,b,c,d,e,f){function g(){c.spin(),b.query({},function(b){a.networks=b,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}a.sortType="Name",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.createNetworkConfig={Name:"",Driver:"",IPAM:{Config:[{Subnet:"",IPRange:"",Gateway:""}]}},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.networks,function(c){c.Checked&&(e+=1,b.remove({id:c.Id},function(b){d.send("Network deleted",c.Id);var e=a.networks.indexOf(c);a.networks.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredNetworks,function(b){b.Checked=a.toggle})},a.addNetwork=function(a){c.spin(),b.create(a,function(a){a.Id?d.send("Network created",a.Id):d.error("Failure",f(a)),c.stop(),g()},function(a){d.error("Failure",a.data),c.stop()})},g()}]),angular.module("pullImage",[]).controller("PullImageController",["$scope","$log","Messages","Image","ViewSpinner",function(a,b,c,d,e){a.template="app/components/pullImage/pullImage.html",a.init=function(){a.config={registry:"",fromImage:"",tag:"latest"}},a.init(),a.pull=function(){$("#error-message").hide();var b=(a.config.registry?a.config.registry+"/":"")+a.config.fromImage,f={};f.fromImage=b,f.tag=a.config.tag,e.spin(),$("#pull-modal").modal("hide"),d.create(f,function(d){if(e.stop(),d.constructor===Array){var f=d.length>0&&d[d.length-1].hasOwnProperty("error");if(f){var g=d[d.length-1];a.error="Cannot pull image "+b+" Reason: "+g.error,$("#pull-modal").modal("show"),$("#error-message").show()}else c.send("Image Added",b),a.init()}else c.send("Image Added",b),a.init()},function(c){e.stop(),a.error="Cannot pull image "+b+" Reason: "+c.data,$("#pull-modal").modal("show"),$("#error-message").show()})}}]),angular.module("sidebar",[]).controller("SideBarController",["$scope","Container","Settings",function(a,b,c){a.template="partials/sidebar.html",a.containers=[],a.endpoint=c.endpoint,b.query({all:0},function(b){a.containers=b})}]),angular.module("startContainer",["ui.bootstrap"]).controller("StartContainerController",["$scope","$routeParams","$location","Container","Messages","containernameFilter","errorMsgFilter",function(a,b,c,d,e,f,g){function h(a,b){b.error("Error",g(a))}function i(a){for(var b in a)(null===a[b]||void 0===a[b]||""===a[b]||$.isPlainObject(a[b])&&$.isEmptyObject(a[b])||0===a[b].length)&&delete a[b]}function j(a){return a.map(function(a){return a.name})}a.template="app/components/startContainer/startcontainer.html",d.query({all:1},function(b){a.containerNames=b.map(function(a){return f(a)})}),a.config={Env:[],Labels:[],Volumes:[],SecurityOpts:[],HostConfig:{PortBindings:[],Binds:[],Links:[],Dns:[],DnsSearch:[],VolumesFrom:[],CapAdd:[],CapDrop:[],Devices:[],LxcConf:[],ExtraHosts:[]}},a.menuStatus={containerOpen:!0,hostConfigOpen:!1},a.create=function(){var f=angular.copy(a.config);f.Image=b.id,f.Cmd&&"["===f.Cmd[0]?f.Cmd=angular.fromJson(f.Cmd):f.Cmd&&(f.Cmd=f.Cmd.split(" ")),f.Env=f.Env.map(function(a){return a.name+"="+a.value});var g={};f.Labels=f.Labels.forEach(function(a){g[a.key]=a.value}),f.Labels=g,f.Volumes=j(f.Volumes),f.SecurityOpts=j(f.SecurityOpts),f.HostConfig.VolumesFrom=j(f.HostConfig.VolumesFrom),f.HostConfig.Binds=j(f.HostConfig.Binds),f.HostConfig.Links=j(f.HostConfig.Links),f.HostConfig.Dns=j(f.HostConfig.Dns),f.HostConfig.DnsSearch=j(f.HostConfig.DnsSearch),f.HostConfig.CapAdd=j(f.HostConfig.CapAdd),f.HostConfig.CapDrop=j(f.HostConfig.CapDrop),f.HostConfig.LxcConf=f.HostConfig.LxcConf.reduce(function(a,b,c){return a[b.name]=b.value,a},{}),f.HostConfig.ExtraHosts=f.HostConfig.ExtraHosts.map(function(a){return a.host+":"+a.ip});var k={},l={};f.HostConfig.PortBindings.forEach(function(a){var b=a.intPort+"/tcp";"udp"===a.protocol&&(b=a.intPort+"/udp");var c={HostIp:a.ip,HostPort:a.extPort};a.intPort?(k[b]={},b in l?l[b].push(c):l[b]=[c]):e.send("Warning","Internal port must be specified for PortBindings")}),f.ExposedPorts=k,f.HostConfig.PortBindings=l,i(f.HostConfig),i(f);var m=d,n=c;d.create(f,function(a){if(a.Id){var b=f.HostConfig||{};b.id=a.Id,m.start(b,function(b){b.id?(e.send("Container Started",a.Id),$("#create-modal").modal("hide"),n.path("/containers/"+a.Id+"/")):(h(b,e),m.remove({id:a.Id},function(){e.send("Container Removed",a.Id)}))},function(a){h(a,e)})}else h(a,e)},function(a){h(a,e)})},a.addEntry=function(a,b){a.push(b)},a.rmEntry=function(a,b){var c=a.indexOf(b);a.splice(c,1)}}]),angular.module("stats",[]).controller("StatsController",["Settings","$scope","Messages","$timeout","Container","$routeParams","humansizeFilter","$sce",function(a,b,c,d,e,f,g,h){function i(){e.stats({id:f.id},function(a){var e=Object.keys(a).map(function(b){return a[b]});return-1!==e.join("").indexOf("no such id")?void c.error("Unable to retrieve stats","Is this container running?"):(b.data=a,j(a),k(a),l(a),void(D=d(i,5e3)))},function(){c.error("Unable to retrieve stats","Is this container running?"),D=d(i,5e3)})}function j(a){A.addData([m(a)],new Date(a.read).toLocaleTimeString()),A.removeData()}function k(a){B.addData([a.memory_stats.usage],new Date(a.read).toLocaleTimeString()),B.removeData()}function l(a){a.networks&&(b.networkName=Object.keys(a.networks)[0],a.network=a.networks[b.networkName]);var c=0,d=0;0===E&&0===F||(c=a.network.rx_bytes-E,d=a.network.tx_bytes-F),E=a.network.rx_bytes,F=a.network.tx_bytes,C.addData([c,d],new Date(a.read).toLocaleTimeString()),C.removeData()}function m(a){var b=a.precpu_stats,c=a.cpu_stats,d=0,e=c.cpu_usage.total_usage-b.cpu_usage.total_usage,f=c.system_cpu_usage-b.system_cpu_usage;return f>0&&e>0&&(d=e/f*c.cpu_usage.percpu_usage.length*100),d}for(var n=[],o=[],p=[],q=[],r=[],s=[],t=[],u=0;20>u;u++)n.push(""),o.push(0),p.push(""),q.push(0),r.push(""),s.push(0),t.push(0);var v={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:o},w={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:q},x={label:"Rx Bytes",fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:t},y={label:"Tx Bytes",fillColor:"rgba(255,180,174,0.5)",strokeColor:"rgba(255,180,174,1)",pointColor:"rgba(255,180,174,1)",pointStrokeColor:"#fff",data:s},z=[{color:"rgba(151,187,205,0.5)",title:"Rx Data"},{color:"rgba(255,180,174,0.5)",title:"Rx Data"}];legend($("#network-legend").get(0),z),Chart.defaults.global.animationSteps=30;var A=new Chart($("#cpu-stats-chart").get(0).getContext("2d")).Line({labels:n,datasets:[v]},{responsive:!0}),B=new Chart($("#memory-stats-chart").get(0).getContext("2d")).Line({labels:p,datasets:[w]},{scaleLabel:function(a){return g(parseInt(a.value,10))},responsive:!0}),C=new Chart($("#network-stats-chart").get(0).getContext("2d")).Line({labels:r,datasets:[x,y]},{scaleLabel:function(a){return g(parseInt(a.value,10))},responsive:!0});b.networkLegend=h.trustAsHtml(C.generateLegend());var D;b.$on("$destroy",function(){d.cancel(D)}),i();var E=0,F=0;e.get({id:f.id},function(a){b.containerName=a.Name.substring(1)},function(a){c.error("Failure",a.data)})}]),angular.module("volumes",[]).config(["$routeProvider",function(a){a.when("/volumes/",{templateUrl:"app/components/volumes/volumes.html",controller:"VolumesController"})}]).controller("VolumesController",["$scope","Volume","ViewSpinner","Messages","$route","errorMsgFilter",function(a,b,c,d,e,f){function g(){c.spin(),b.query({},function(b){a.volumes=b.Volumes,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}a.sortType="Name",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.createVolumeConfig={Name:"",Driver:""},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.volumes,function(c){c.Checked&&(e+=1,b.remove({name:c.Name},function(b){d.send("Volume deleted",c.Name);var e=a.volumes.indexOf(c);a.volumes.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredVolumes,function(b){b.Checked=a.toggle})},a.addVolume=function(a){c.spin(),b.create(a,function(a){a.Name?d.send("Volume created",a.Name):d.error("Failure",f(a)),c.stop(),g()},function(a){d.error("Failure",a.data),c.stop()})},g()}]),angular.module("uifordocker.filters",[]).filter("truncate",function(){"use strict";return function(a,b,c){return isNaN(b)&&(b=10),void 0===c&&(c="..."),a.length<=b||a.length-c.length<=b?a:String(a).substring(0,b-c.length)+c}}).filter("statusbadge",function(){"use strict";return function(a){return"Ghost"===a?"important":-1!==a.indexOf("Exit")&&"Exit 0"!==a?"warning":"success"}}).filter("getstatetext",function(){"use strict";return function(a){return void 0===a?"":a.Ghost&&a.Running?"Ghost":a.Running&&a.Paused?"Running (Paused)":a.Running?"Running":"Stopped"}}).filter("getstatelabel",function(){"use strict";return function(a){return void 0===a?"label-default":a.Ghost&&a.Running?"label-important":a.Running?"label-success":"label-default"}}).filter("humansize",function(){"use strict";return function(a){var b=["Bytes","KB","MB","GB","TB"];if(0===a)return"n/a";var c=parseInt(Math.floor(Math.log(a)/Math.log(1024)),10),d=a/Math.pow(1024,c),e=1>c?0:c-1;return d.toFixed(e)+" "+b[[c]]}}).filter("containername",function(){"use strict";return function(a){var b=a.Names[0];return b.substring(1,b.length)}}).filter("repotag",function(){"use strict";return function(a){if(a.RepoTags&&a.RepoTags.length>0){var b=a.RepoTags[0];return":"===b&&(b=""),b}return""}}).filter("errorMsg",function(){return function(a){for(var b=0,c="";a[b]&&"string"==typeof a[b];)c+=a[b],b++;return c}}),angular.module("uifordocker.services",["ngResource","ngSanitize"]).factory("Container",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/containers/:id/:action",{name:"@name"},{query:{method:"GET",params:{all:0,action:"json"},isArray:!0},get:{method:"GET",params:{action:"json"}},start:{method:"POST",params:{id:"@id",action:"start"}},stop:{method:"POST",params:{id:"@id",t:5,action:"stop"}},restart:{method:"POST",params:{id:"@id",t:5,action:"restart"}},kill:{method:"POST",params:{id:"@id", -action:"kill"}},pause:{method:"POST",params:{id:"@id",action:"pause"}},unpause:{method:"POST",params:{id:"@id",action:"unpause"}},changes:{method:"GET",params:{action:"changes"},isArray:!0},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE",params:{id:"@id",v:0}},rename:{method:"POST",params:{id:"@id",action:"rename"},isArray:!1},stats:{method:"GET",params:{id:"@id",stream:!1,action:"stats"},timeout:5e3}})}]).factory("ContainerCommit",["$resource","$http","Settings",function(a,b,c){"use strict";return{commit:function(a,d){b({method:"POST",url:c.url+"/commit",params:{container:a.id,tag:a.tag||null,repo:a.repo||null},data:a.config}).success(d).error(function(a,b,c,d){console.log(error,a)})}}}]).factory("ContainerLogs",["$resource","$http","Settings",function(a,b,c){"use strict";return{get:function(a,d,e){b({method:"GET",url:c.url+"/containers/"+a+"/logs",params:{stdout:d.stdout||0,stderr:d.stderr||0,timestamps:d.timestamps||0,tail:d.tail||"all"}}).success(e).error(function(a,b,c,d){console.log(error,a)})}}}]).factory("ContainerTop",["$http","Settings",function(a,b){"use strict";return{get:function(c,d,e,f){a({method:"GET",url:b.url+"/containers/"+c+"/top",params:{ps_args:d.ps_args}}).success(e)}}}]).factory("Image",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/images/:id/:action",{},{query:{method:"GET",params:{all:0,action:"json"},isArray:!0},get:{method:"GET",params:{action:"json"}},search:{method:"GET",params:{action:"search"}},history:{method:"GET",params:{action:"history"},isArray:!0},create:{method:"POST",isArray:!0,transformResponse:[function(a){var b=a.replace(/\n/g," ").replace(/\}\W*\{/g,"}, {");return angular.fromJson("["+b+"]")}],params:{action:"create",fromImage:"@fromImage",tag:"@tag"}},insert:{method:"POST",params:{id:"@id",action:"insert"}},push:{method:"POST",params:{id:"@id",action:"push"}},tag:{method:"POST",params:{id:"@id",action:"tag",force:0,repo:"@repo",tag:"@tag"}},remove:{method:"DELETE",params:{id:"@id"},isArray:!0},inspect:{method:"GET",params:{id:"@id",action:"json"}}})}]).factory("Version",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/version",{},{get:{method:"GET"}})}]).factory("Auth",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/auth",{},{get:{method:"GET"},update:{method:"POST"}})}]).factory("Info",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/info",{},{get:{method:"GET"}})}]).factory("Network",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/networks/:id/:action",{id:"@id"},{query:{method:"GET",isArray:!0},get:{method:"GET"},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE"},connect:{method:"POST",params:{action:"connect"}},disconnect:{method:"POST",params:{action:"disconnect"}}})}]).factory("Volume",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/volumes/:name/:action",{name:"@name"},{query:{method:"GET"},get:{method:"GET"},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE"}})}]).factory("Settings",["DOCKER_ENDPOINT","DOCKER_PORT","UI_VERSION",function(a,b,c){"use strict";var d=a;b&&(d=d+b+"\\"+b);var e="true"===(localStorage.getItem("firstLoad")||"true");return{displayAll:!1,endpoint:a,uiVersion:c,url:d,firstLoad:e}}]).factory("ViewSpinner",function(){"use strict";var a=new Spinner,b=document.getElementById("view");return{spin:function(){a.spin(b)},stop:function(){a.stop()}}}).factory("Messages",["$rootScope","$sanitize",function(a,b){"use strict";return{send:function(a,c){$.gritter.add({title:b(a),text:b(c),time:2e3,before_open:function(){return 3===$(".gritter-item-wrapper").length?!1:void 0}})},error:function(a,c){$.gritter.add({title:b(a),text:b(c),time:1e4,before_open:function(){return 4===$(".gritter-item-wrapper").length?!1:void 0}})}}}]).factory("LineChart",["Settings",function(a){"use strict";return{build:function(a,b,c){for(var d=new Chart($(a).get(0).getContext("2d")),e={},f=0;f-1;f--){var m=k[f];j.push(m),b.push(e[m]),e[m]>l&&(l=e[m])}var n=Math.min(l,10),o={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:b};d.Line({labels:j,datasets:[o]},{scaleStepWidth:Math.ceil(l/n),pointDotRadius:1,scaleIntegersOnly:!0,scaleOverride:!0,scaleSteps:n})}}}]),angular.module("uifordocker.templates",["app/components/builder/builder.html","app/components/container/container.html","app/components/containerLogs/containerlogs.html","app/components/containerTop/containerTop.html","app/components/containers/containers.html","app/components/containersNetwork/containersNetwork.html","app/components/dashboard/dashboard.html","app/components/events/events.html","app/components/footer/statusbar.html","app/components/image/image.html","app/components/images/images.html","app/components/info/info.html","app/components/masthead/masthead.html","app/components/network/network.html","app/components/networks/networks.html","app/components/pullImage/pullImage.html","app/components/sidebar/sidebar.html","app/components/startContainer/startcontainer.html","app/components/stats/stats.html","app/components/volumes/volumes.html"]),angular.module("app/components/builder/builder.html",[]).run(["$templateCache",function(a){a.put("app/components/builder/builder.html",'\n')}]),angular.module("app/components/container/container.html",[]).run(["$templateCache",function(a){a.put("app/components/container/container.html",'
    \n\n
    \n

    Container: {{ container.Name }}\n \n

    \n
    \n
    \n

    \n Container:\n \n \n \n

    \n
    \n\n
    \n \n \n \n \n \n \n \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Created:{{ container.Created | date: \'yyyy-MM-dd HH:mm:ss\' }}
    Path:{{ container.Path }}
    Args:\n
    {{ container.Args.join(\' \') || \'None\' }}
    \n
    Exposed Ports:\n
      \n
    • {{ k }}
    • \n
    \n
    Environment:\n
    \n \n
      \n
    • {{ k }}
    • \n
    \n
    \n
    \n \n\n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n
    \n
    \n
    \n \n \n
    \n\n\n
    Labels:\n \n \n \n \n \n \n \n \n \n
    KeyValue
    {{ k }}{{ v }}
    \n
    Publish All:{{ container.HostConfig.PublishAllPorts }}
    Ports:\n
    \n \n
      \n
    • \n {{ containerport }} =>\n {{ v.HostIp }}:{{ v.HostPort }}\n
    • \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n \n
    \n
    Hostname:{{ container.Config.Hostname }}
    IPAddress:{{ container.NetworkSettings.IPAddress }}
    Cmd:{{ container.Config.Cmd }}
    Entrypoint:\n
    {{ container.Config.Entrypoint.join(\' \') }}
    \n
    Bindings:\n
    \n \n\n
      \n
    • {{ b }}
    • \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n \n\n
    \n
    Volumes:{{ container.Volumes }}
    SysInitpath:{{ container.SysInitPath }}
    Image:{{ container.Image }}
    State:\n \n \n
      \n
    • {{key}} : {{ val }}
    • \n
    \n
    \n
    \n
    Logs:stdout/stderr
    Stats:stats
    Top:Top
    \n\n
    \n
    \n Changes:\n
    \n
    \n \n
    \n
    \n\n
    \n
      \n
    • \n {{ change.Path }} {{ change.Kind }}\n
    • \n
    \n
    \n\n
    \n\n
    \n \n
    \n
    \n')}]),angular.module("app/components/containerLogs/containerlogs.html",[]).run(["$templateCache",function(a){a.put("app/components/containerLogs/containerlogs.html",'
    \n
    \n

    Logs for container: {{ container.Name }}

    \n\n
    \n \n \n
    \n
    \n
    \n Reload logs\n \n \n
    \n
    \n \n
    \n
    \n
    \n\n
    \n
    \n
    \n

    STDOUT

    \n
    \n
    \n
    {{stdout}}
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    STDERR

    \n
    \n
    \n
    {{stderr}}
    \n
    \n
    \n
    \n
    \n')}]),angular.module("app/components/containerTop/containerTop.html",[]).run(["$templateCache",function(a){a.put("app/components/containerTop/containerTop.html",'
    \n
    \n
    \n

    Top for: {{ containerName }}

    \n
    \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n
    {{title}}
    {{processInfo}}
    \n
    \n
    \n
    ')}]),angular.module("app/components/containers/containers.html",[]).run(["$templateCache",function(a){a.put("app/components/containers/containers.html",'\n

    Containers:

    \n\n
    \n \n\n
    \n  \n \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Name\n \n \n \n \n \n Image\n \n \n \n \n \n Command\n \n \n \n \n \n Created\n \n \n \n \n \n Status\n \n \n \n \n Log\n
    {{ container|containername}}{{ container.Image }}{{ container.Command|truncate:40 }}{{ container.Created * 1000 | date: \'yyyy-MM-dd\' }}{{ container.Status }}stdout/stderr
    \n')}]),angular.module("app/components/containersNetwork/containersNetwork.html",[]).run(["$templateCache",function(a){a.put("app/components/containersNetwork/containersNetwork.html",'
    \n

    Containers Network

    \n\n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n \n \n
    \n Include stopped containers\n
    \n
    \n \n
    \n
    \n')}]),angular.module("app/components/dashboard/dashboard.html",[]).run(["$templateCache",function(a){a.put("app/components/dashboard/dashboard.html",'
    \n \n
    \n \n
    \n\n
    \n
    \n
    \n

    Running Containers

    \n \n
    \n
    \n

    Status

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n
    \n
    \n
    \n\n
    \n
    \n

    Containers created

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n

    Images created

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n
    \n
    \n')}]),angular.module("app/components/events/events.html",[]).run(["$templateCache",function(a){a.put("app/components/events/events.html",'
    \n
    \n

    Events

    \n\n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n
    EventFromIDTime
    \n \n \n \n
    \n
    \n
    \n'); -}]),angular.module("app/components/footer/statusbar.html",[]).run(["$templateCache",function(a){a.put("app/components/footer/statusbar.html",'
    \n

    \n Docker API Version: {{ apiVersion }} UI Version: {{ uiVersion }} UI For Docker\n

    \n
    \n')}]),angular.module("app/components/image/image.html",[]).run(["$templateCache",function(a){a.put("app/components/image/image.html",'
    \n\n\n\n
    \n\n

    Image: {{ id }}

    \n\n
    \n \n
    \n\n
    \n

    Containers created:

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n
    Tags:\n
      \n
    • {{ tag }}\n \n
    • \n
    \n
    Created:{{ image.Created | date: \'yyyy-MM-dd HH:mm:ss\'}}
    Parent:{{ image.Parent }}
    Size (Virtual Size):{{ image.Size|humansize }} ({{ image.VirtualSize|humansize }})
    Hostname:{{ image.ContainerConfig.Hostname }}
    User:{{ image.ContainerConfig.User }}
    Cmd:{{ image.ContainerConfig.Cmd }}
    Volumes:{{ image.ContainerConfig.Volumes }}
    Volumes from:{{ image.ContainerConfig.VolumesFrom }}
    Built with:Docker {{ image.DockerVersion }} on {{ image.Os}}, {{ image.Architecture }}
    \n\n
    \n
    \n History:\n
    \n
    \n \n
    \n
    \n\n
    \n
      \n
    • \n {{ change.Id }}: Created: {{ change.Created | date: \'yyyy-MM-dd\' }} Created by: {{ change.CreatedBy\n }}\n
    • \n
    \n
    \n\n
    \n\n
    \n
    \n
    \n Tag image\n
    \n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n\n
    \n\n
    \n \n
    \n
    \n')}]),angular.module("app/components/images/images.html",[]).run(["$templateCache",function(a){a.put("app/components/images/images.html",'
    \n
    \n\n

    Images:

    \n\n
    \n \n\n
    \n \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Id\n \n \n \n \n \n Repository\n \n \n \n \n \n VirtualSize\n \n \n \n \n \n Created\n \n \n \n
    {{ image.Id|truncate:20}}{{ image|repotag }}{{ image.VirtualSize|humansize }}{{ image.Created * 1000 | date: \'yyyy-MM-dd\' }}
    \n')}]),angular.module("app/components/info/info.html",[]).run(["$templateCache",function(a){a.put("app/components/info/info.html",'
    \n

    Docker Information

    \n\n
    \n

    \n API Endpoint: {{ endpoint }}
    \n API Version: {{ docker.ApiVersion }}
    \n Docker version: {{ docker.Version }}
    \n Git Commit: {{ docker.GitCommit }}
    \n Go Version: {{ docker.GoVersion }}
    \n

    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Containers:{{ info.Containers }}
    Images:{{ info.Images }}
    Debug:{{ info.Debug }}
    CPUs:{{ info.NCPU }}
    Total Memory:{{ info.MemTotal|humansize }}
    Operating System:{{ info.OperatingSystem }}
    Kernel Version:{{ info.KernelVersion }}
    ID:{{ info.ID }}
    Labels:{{ info.Labels }}
    File Descriptors:{{ info.NFd }}
    Goroutines:{{ info.NGoroutines }}
    Storage Driver:{{ info.Driver }}
    Storage Driver Status:\n

    \n {{ val[0] }}: {{ val[1] }}\n

    \n
    Execution Driver:{{ info.ExecutionDriver }}
    Events:Events
    IPv4 Forwarding:{{ info.IPv4Forwarding }}
    Index Server Address:{{ info.IndexServerAddress }}
    Init Path:{{ info.InitPath }}
    Docker Root Directory:{{ info.DockerRootDir }}
    Init SHA1{{ info.InitSha1 }}
    Memory Limit:{{ info.MemoryLimit }}
    Swap Limit:{{ info.SwapLimit }}
    \n
    \n')}]),angular.module("app/components/masthead/masthead.html",[]).run(["$templateCache",function(a){a.put("app/components/masthead/masthead.html",'
    \n

    UI For Docker

    \n\n \n
    \n \n
    \n
    \n')}]),angular.module("app/components/network/network.html",[]).run(["$templateCache",function(a){a.put("app/components/network/network.html",'
    \n\n

    Network: {{ network.Name }}

    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Name:{{ network.Name }}
    Id:{{ network.Id }}
    Scope:{{ network.Scope }}
    Driver:{{ network.Driver }}
    IPAM:\n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Driver:{{ network.IPAM.Driver }}
    Subnet:{{ network.IPAM.Config[0].Subnet }}
    Gateway:{{ network.IPAM.Config[0].Gateway }}
    \n
    Containers:\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Id:{{ Id }}\n \n
    EndpointID:{{ container.EndpointID}}
    MacAddress:{{ container.MacAddress}}
    IPv4Address:{{ container.IPv4Address}}
    IPv6Address:{{ container.IPv6Address}}
    \n
    \n
    \n \n
    \n \n
    \n
    Options:\n \n \n \n \n \n \n \n \n \n
    KeyValue
    {{ k }}{{ v }}
    \n
    \n\n\n
    \n\n\n
    \n \n
    \n
    ')}]),angular.module("app/components/networks/networks.html",[]).run(["$templateCache",function(a){a.put("app/components/networks/networks.html",'

    Networks:

    \n\n
    \n \n\n
    \n Filter\n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Name\n \n \n \n \n \n Id\n \n \n \n \n \n Scope\n \n \n \n \n \n Driver\n \n \n \n \n \n IPAM Driver\n \n \n \n \n \n IPAM Subnet\n \n \n \n \n \n IPAM Gateway\n \n \n \n
    {{ network.Name|truncate:20}}{{ network.Id }}{{ network.Scope }}{{ network.Driver }}{{ network.IPAM.Driver }}{{ network.IPAM.Config[0].Subnet }}{{ network.IPAM.Config[0].Gateway }}
    \n
    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n
    ')}]),angular.module("app/components/pullImage/pullImage.html",[]).run(["$templateCache",function(a){a.put("app/components/pullImage/pullImage.html",'\n')}]),angular.module("app/components/sidebar/sidebar.html",[]).run(["$templateCache",function(a){a.put("app/components/sidebar/sidebar.html",'
    \n Running containers:\n
    \n Endpoint: {{ endpoint }}\n \n
    \n')}]),angular.module("app/components/startContainer/startcontainer.html",[]).run(["$templateCache",function(a){a.put("app/components/startContainer/startcontainer.html",'\n'); +function ImageViewModel(a){this.Id=a.Id,this.Tag=a.Tag,this.Repository=a.Repository,this.Created=a.Created,this.Checked=!1,this.RepoTags=a.RepoTags,this.VirtualSize=a.VirtualSize}function ContainerViewModel(a){this.Id=a.Id,this.Image=a.Image,this.Command=a.Command,this.Created=a.Created,this.SizeRw=a.SizeRw,this.Status=a.Status,this.Checked=!1,this.Names=a.Names}angular.module("uifordocker",["uifordocker.templates","ngRoute","uifordocker.services","uifordocker.filters","masthead","footer","dashboard","container","containers","containersNetwork","images","image","pullImage","startContainer","sidebar","info","builder","containerLogs","containerTop","events","stats","network","networks","volumes"]).config(["$routeProvider","$httpProvider",function(a,b){"use strict";b.defaults.xsrfCookieName="csrfToken",b.defaults.xsrfHeaderName="X-CSRF-Token",a.when("/",{templateUrl:"app/components/dashboard/dashboard.html",controller:"DashboardController"}),a.when("/containers/",{templateUrl:"app/components/containers/containers.html",controller:"ContainersController"}),a.when("/containers/:id/",{templateUrl:"app/components/container/container.html",controller:"ContainerController"}),a.when("/containers/:id/logs/",{templateUrl:"app/components/containerLogs/containerlogs.html",controller:"ContainerLogsController"}),a.when("/containers/:id/top",{templateUrl:"app/components/containerTop/containerTop.html",controller:"ContainerTopController"}),a.when("/containers/:id/stats",{templateUrl:"app/components/stats/stats.html",controller:"StatsController"}),a.when("/containers_network",{templateUrl:"app/components/containersNetwork/containersNetwork.html",controller:"ContainersNetworkController"}),a.when("/images/",{templateUrl:"app/components/images/images.html",controller:"ImagesController"}),a.when("/images/:id*/",{templateUrl:"app/components/image/image.html",controller:"ImageController"}),a.when("/info",{templateUrl:"app/components/info/info.html",controller:"InfoController"}),a.when("/events",{templateUrl:"app/components/events/events.html",controller:"EventsController"}),a.otherwise({redirectTo:"/"}),b.interceptors.push(function(){return{response:function(a){"string"==typeof a.data&&(a.data.startsWith("Conflict.")||a.data.startsWith("conflict:"))&&$.gritter.add({title:"Error",text:$("
    ").text(a.data).html(),time:1e4});var b=a.headers("X-Csrf-Token");return b&&(document.cookie="csrfToken="+b),a}}})}]).constant("DOCKER_ENDPOINT","dockerapi").constant("DOCKER_PORT","").constant("UI_VERSION","v0.11.0"),angular.module("builder",[]).controller("BuilderController",["$scope",function(a){a.template="app/components/builder/builder.html"}]),angular.module("container",[]).controller("ContainerController",["$scope","$routeParams","$location","Container","ContainerCommit","Image","Messages","ViewSpinner","$timeout",function(a,b,c,d,e,f,g,h,i){a.changes=[],a.editEnv=!1,a.editPorts=!1,a.editBinds=!1,a.newCfg={Env:[],Ports:{}};var j=function(){h.spin(),d.get({id:b.id},function(b){a.container=b,a.container.edit=!1,a.container.newContainerName=b.Name,b.Config.Env&&(a.newCfg.Env=b.Config.Env.map(function(a){return{name:a.split("=")[0],value:a.split("=")[1]}})),a.newCfg.Ports={},angular.forEach(b.Config.ExposedPorts,function(c,d){b.HostConfig.PortBindings&&d in b.HostConfig.PortBindings?a.newCfg.Ports[d]=b.HostConfig.PortBindings[d]:a.newCfg.Ports[d]=[]}),a.newCfg.Binds=[];var c={};angular.forEach(b.Config.Volumes,function(a,b){c[b]={ContPath:b,HostPath:"",ReadOnly:!1,DefaultBind:!0}}),angular.forEach(b.HostConfig.Binds,function(b,d){var e=b.split(":")[0],f=b.split(":")[1]||"",g=b.split(":").length>2&&"ro"===b.split(":")[2],h=!1;""===f&&(f=e,e=""),f in c&&(delete c[f],h=!0),a.newCfg.Binds.push({ContPath:f,HostPath:e,ReadOnly:g,DefaultBind:h})}),angular.forEach(c,function(b){a.newCfg.Binds.push(b)}),h.stop()},function(a){404===a.status?($(".detail").hide(),g.error("Not found","Container not found.")):g.error("Failure",a.data),h.stop()})};a.start=function(){h.spin(),d.start({id:a.container.Id,HostConfig:a.container.HostConfig},function(a){j(),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})},a.stop=function(){h.spin(),d.stop({id:b.id},function(a){j(),g.send("Container stopped",b.id)},function(a){j(),g.error("Failure","Container failed to stop."+a.data)})},a.kill=function(){h.spin(),d.kill({id:b.id},function(a){j(),g.send("Container killed",b.id)},function(a){j(),g.error("Failure","Container failed to die."+a.data)})},a.restartEnv=function(){var i=angular.copy(a.container.Config);i.Env=a.newCfg.Env.map(function(a){return a.name+"="+a.value});var k=angular.copy(a.newCfg.Ports);angular.forEach(k,function(a,b){0===a.length&&delete k[b]});var l=[];angular.forEach(a.newCfg.Binds,function(a){if(""!==a.ContPath){var b="";""!==a.HostPath&&(b=a.HostPath+":"),b+=a.ContPath,a.ReadOnly&&(b+=":ro"),""===a.HostPath&&a.DefaultBind||l.push(b)}}),h.spin(),e.commit({id:b.id,tag:a.container.Config.Image,config:i},function(e){if("Id"in e){var h=e.Id;f.inspect({id:h},function(e){e.Config.HostConfig=angular.copy(a.container.HostConfig),e.Config.HostConfig.PortBindings=k,e.Config.HostConfig.Binds=l,"host"===e.Config.HostConfig.NetworkMode&&(e.Config.Hostname=""),d.create(e.Config,function(e){return"Id"in e?void(a.container.State.Running?d.stop({id:b.id},function(a){g.send("Container stopped",b.id),d.start({id:e.Id},function(a){c.url("/containers/"+e.Id+"/"),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})},function(a){j(),g.error("Failure","Container failed to stop."+a.data)}):d.start({id:e.Id},function(a){c.url("/containers/"+e.Id+"/"),g.send("Container started",b.id)},function(a){j(),g.error("Failure","Container failed to start."+a.data)})):void g.error("Failure","Container failed to create.")},function(a){j(),g.error("Failure","Image failed to get."+a.data)})},function(a){j(),g.error("Failure","Image failed to get."+a.data)})}else j(),g.error("Failure","Container commit failed.")},function(a){j(),g.error("Failure","Container failed to commit."+a.data)})},a.commit=function(){h.spin(),e.commit({id:b.id,repo:a.container.Config.Image},function(a){j(),g.send("Container commited",b.id)},function(a){j(),g.error("Failure","Container failed to commit."+a.data)})},a.pause=function(){h.spin(),d.pause({id:b.id},function(a){j(),g.send("Container paused",b.id)},function(a){j(),g.error("Failure","Container failed to pause."+a.data)})},a.unpause=function(){h.spin(),d.unpause({id:b.id},function(a){j(),g.send("Container unpaused",b.id)},function(a){j(),g.error("Failure","Container failed to unpause."+a.data)})},a.remove=function(){h.spin(),d.remove({id:b.id},function(a){j(),c.path("/containers"),g.send("Container removed",b.id)},function(a){j(),g.error("Failure","Container failed to remove."+a.data)})},a.restart=function(){h.spin(),d.restart({id:b.id},function(a){j(),g.send("Container restarted",b.id)},function(a){j(),g.error("Failure","Container failed to restart."+a.data)})},a.hasContent=function(a){return null!==a&&void 0!==a},a.getChanges=function(){h.spin(),d.changes({id:b.id},function(b){a.changes=b,h.stop()})},a.renameContainer=function(){d.rename({id:b.id,name:a.container.newContainerName},function(c){c.name?(a.container.Name=c.name,g.send("Container renamed",b.id)):(a.container.newContainerName=a.container.Name,g.error("Failure","Container failed to rename."))}),a.container.edit=!1},a.addEntry=function(a,b){a.push(b)},a.rmEntry=function(a,b){var c=a.indexOf(b);a.splice(c,1)},a.toggleEdit=function(){a.edit=!a.edit},j(),a.getChanges()}]),angular.module("containerLogs",[]).controller("ContainerLogsController",["$scope","$routeParams","$location","$anchorScroll","ContainerLogs","Container","ViewSpinner",function(a,b,c,d,e,f,g){function h(){g.spin(),e.get(b.id,{stdout:1,stderr:0,timestamps:a.showTimestamps,tail:a.tailLines},function(b,c,d,e){b=b.replace(/[\r]/g,"\n"),b=b.substring(8),b=b.replace(/\n(.{8})/g,"\n"),a.stdout=b,g.stop()}),e.get(b.id,{stdout:0,stderr:1,timestamps:a.showTimestamps,tail:a.tailLines},function(b,c,d,e){b=b.replace(/[\r]/g,"\n"),b=b.substring(8),b=b.replace(/\n(.{8})/g,"\n"),a.stderr=b,g.stop()})}a.stdout="",a.stderr="",a.showTimestamps=!1,a.tailLines=2e3,g.spin(),f.get({id:b.id},function(b){a.container=b,g.stop()},function(a){404===a.status?Messages.error("Not found","Container not found."):Messages.error("Failure",a.data),g.stop()}),h();var i=window.setInterval(h,5e3);a.$on("$destroy",function(){clearInterval(i)}),a.scrollTo=function(a){c.hash(a),d()},a.toggleTimestamps=function(){h()},a.toggleTail=function(){h()}}]),angular.module("containerTop",[]).controller("ContainerTopController",["$scope","$routeParams","ContainerTop","Container","ViewSpinner",function(a,b,c,d,e){a.ps_args="",a.getTop=function(){e.spin(),c.get(b.id,{ps_args:a.ps_args},function(b){a.containerTop=b,e.stop()})},d.get({id:b.id},function(b){a.containerName=b.Name.substring(1)},function(a){Messages.error("Failure",a.data)}),a.getTop()}]),angular.module("containers",[]).controller("ContainersController",["$scope","Container","Settings","Messages","ViewSpinner",function(a,b,c,d,e){a.sortType="Created",a.sortReverse=!0,a.toggle=!1,a.displayAll=c.displayAll,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b};var f=function(c){e.spin(),b.query(c,function(b){a.containers=b.map(function(a){return new ContainerViewModel(a)}),e.stop()})},g=function(g,h,i){e.spin();var j=0,k=function(){j-=1,0===j&&(e.stop(),f({all:c.displayAll?1:0}))};angular.forEach(g,function(c){c.Checked&&(h===b.start?b.get({id:c.Id},function(b){c=b,j+=1,h({id:c.Id},{},function(b){d.send("Container "+i,c.Id);a.containers.indexOf(c);k()},function(a){d.error("Failure",a.data),k()})},function(a){404===a.status?($(".detail").hide(),d.error("Not found","Container not found.")):d.error("Failure",a.data),k()}):(j+=1,h({id:c.Id},function(b){d.send("Container "+i,c.Id);a.containers.indexOf(c);k()},function(a){d.error("Failure",a.data),k()})))}),0===j&&e.stop()};a.toggleSelectAll=function(){angular.forEach(a.filteredContainers,function(b){b.Checked=a.toggle})},a.toggleGetAll=function(){c.displayAll=a.displayAll,f({all:c.displayAll?1:0})},a.startAction=function(){g(a.containers,b.start,"Started")},a.stopAction=function(){g(a.containers,b.stop,"Stopped")},a.restartAction=function(){g(a.containers,b.restart,"Restarted")},a.killAction=function(){g(a.containers,b.kill,"Killed")},a.pauseAction=function(){g(a.containers,b.pause,"Paused")},a.unpauseAction=function(){g(a.containers,b.unpause,"Unpaused")},a.removeAction=function(){g(a.containers,b.remove,"Removed")},f({all:c.displayAll?1:0})}]),angular.module("containersNetwork",["ngVis"]).controller("ContainersNetworkController",["$scope","$location","Container","Messages","VisDataSet",function(a,b,c,d,f){function g(a){this.Id=a.Id,this.Name=a.Name.substring(1),this.Image=a.Config.Image,this.Running=a.State.Running;var b=a.HostConfig.Links;if(null!=b){this.Links={};for(var c=0;c
  • ID: '+a.Id+"
  • Image: "+a.Image+"
  • ",color:a.Running?"#8888ff":"#cccccc"})},this.hasEdge=function(a,b){return this.edges.getIds({filter:function(c){return c.from===a.Id&&c.to===b.Id}}).length>0},this.addLinkEdgeIfExists=function(a,b){null==a.Links||null==a.Links[b.Name]||this.hasEdge(a,b)||this.edges.add({from:a.Id,to:b.Id,label:a.Links[b.Name]})},this.addVolumeEdgeIfExists=function(a,b){null==a.VolumesFrom||null==a.VolumesFrom[b.Id]&&null==a.VolumesFrom[b.Name]||this.hasEdge(a,b)||this.edges.add({from:a.Id,to:b.Id,color:{color:"#A0A0A0",highlight:"#A0A0A0",hover:"#848484"}})},this.removeContainersNodes=function(a){this.nodes.remove(a)}}function i(){this.data=new h,this.containers={},this.selectedContainersIds=[],this.shownContainersIds=[],this.events={select:function(b){a.network.selectedContainersIds=b.nodes,a.$apply(function(){a.query=""})},doubleClick:function(c){a.$apply(function(){b.path("/containers/"+c.nodes[0])})}},this.options={navigation:!0,keyboard:!0,height:"500px",width:"700px",nodes:{shape:"box"},edges:{style:"arrow"},physics:{barnesHut:{springLength:200}}},this.addContainer=function(a){var b=new g(a);this.containers[b.Id]=b,this.shownContainersIds.push(b.Id),this.data.addContainerNode(b);for(var c in this.containers){var d=this.containers[c];this.data.addLinkEdgeIfExists(b,d),this.data.addLinkEdgeIfExists(d,b),this.data.addVolumeEdgeIfExists(b,d),this.data.addVolumeEdgeIfExists(d,b)}},this.selectContainers=function(a){null!=this.component&&(this.selectedContainersIds=this.searchContainers(a),this.component.selectNodes(this.selectedContainersIds))},this.searchContainers=function(a){if(""===a.trim())return[];for(var b=[],c=0;c-1||d.Image.indexOf(a)>-1||d.Id.indexOf(a)>-1)&&b.push(d.Id)}return b},this.hideSelected=function(){for(var b=0;b-1?this.shownContainersIds.splice(b,1):b++;this.data.removeContainersNodes(this.selectedContainersIds),a.query="",this.selectedContainersIds=[]},this.searchDownstream=function(a,b){if(!(b.indexOf(a)>-1)){b.push(a);var c=this.containers[a];if(null!=c.Links||null!=c.VolumesFrom)for(var d in this.containers){var e=this.containers[d];null!=c.Links&&null!=c.Links[e.Name]?this.searchDownstream(e.Id,b):null!=c.VolumesFrom&&null!=c.VolumesFrom[e.Id]&&this.searchDownstream(e.Id,b)}}},this.updateShownContainers=function(a){for(var b in this.containers)a.indexOf(b)>-1&&-1===this.shownContainersIds.indexOf(b)?this.data.addContainerNode(this.containers[b]):-1===a.indexOf(b)&&this.shownContainersIds.indexOf(b)>-1&&this.data.removeContainersNodes(b);this.shownContainersIds=a},this.showSelectedDownstream=function(){for(var a=[],b=0;b-1)){b.push(a);var c=this.containers[a];for(var d in this.containers){var e=this.containers[d];null!=e.Links&&null!=e.Links[c.Name]?this.searchUpstream(e.Id,b):null!=e.VolumesFrom&&null!=e.VolumesFrom[c.Id]&&this.searchUpstream(e.Id,b)}}},this.showSelectedUpstream=function(){for(var a=[],b=0;b:"!==c.RepoTags[0]&&(a.RepoTags=c.RepoTags)})})}a.history=[],a.tagInfo={repo:"",version:"",force:!1},a.id="",a.repoTags=[],a.removeImage=function(b){e.remove({id:b},function(b){b.forEach(function(a){var b=Object.keys(a)[0];g.send(b,a[b])}),b[b.length-1].Deleted?d.path("/images"):d.path("/images/"+a.id)},function(b){a.error=b.data,$("#error-message").show()})},a.getHistory=function(){e.history({id:c.id},function(b){a.history=b})},a.addTag=function(){var b=a.tagInfo;e.tag({id:c.id,repo:b.repo,tag:b.version,force:b.force?1:0},function(b){g.send("Tag Added",c.id),d.path("/images/"+a.id)},function(b){a.error=b.data,$("#error-message").show()})},e.get({id:c.id},function(c){a.image=c,a.id=c.Id,c.RepoTags?a.RepoTags=c.RepoTags:j(a.id),i(b,f,a.id).then(function(a){h.build("#containers-started-chart",a,function(a){return new Date(1e3*a.Created).toLocaleDateString()})})},function(b){404===b.status?($(".detail").hide(),a.error="Image not found.
    "+c.id):a.error=b.data,$("#error-message").show()}),a.getHistory()}]),angular.module("images",[]).controller("ImagesController",["$scope","Image","ViewSpinner","Messages",function(a,b,c,d){a.sortType="Created",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.showBuilder=function(){$("#build-modal").modal("show")},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.images,function(c){c.Checked&&(e+=1,b.remove({id:c.Id},function(b){angular.forEach(b,function(a){d.send("Image deleted",a.Deleted)});var e=a.images.indexOf(c);a.images.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredImages,function(b){b.Checked=a.toggle})},c.spin(),b.query({},function(b){a.images=b.map(function(a){return new ImageViewModel(a)}),c.stop()},function(a){d.error("Failure",a.data),c.stop()})}]),angular.module("info",[]).controller("InfoController",["$scope","Info","Version","Settings",function(a,b,c,d){a.info={},a.docker={},a.endpoint=d.endpoint,c.get({},function(b){a.docker=b}),b.get({},function(b){a.info=b})}]),angular.module("masthead",[]).controller("MastheadController",["$scope","Version",function(a,b){a.template="app/components/masthead/masthead.html",a.showNetworksVolumes=!1,b.get(function(b){b.ApiVersion>=1.21&&(a.showNetworksVolumes=!0)}),a.refresh=function(){location.reload()}}]),angular.module("network",[]).config(["$routeProvider",function(a){a.when("/networks/:id/",{templateUrl:"app/components/network/network.html",controller:"NetworkController"})}]).controller("NetworkController",["$scope","Network","ViewSpinner","Messages","$routeParams","$location","errorMsgFilter",function(a,b,c,d,e,f,g){a.disconnect=function(a,g){c.spin(),b.disconnect({id:e.id},{Container:g},function(a){c.stop(),d.send("Container disconnected",g),f.path("/networks/"+e.id)},function(a){c.stop(),d.error("Failure",a.data)})},a.connect=function(a,h){c.spin(),b.connect({id:e.id},{Container:h},function(a){c.stop();var b=g(a);b?d.error("Error",b):d.send("Container connected",a),f.path("/networks/"+e.id)},function(a){c.stop(),d.error("Failure",a.data)})},a.remove=function(a){c.spin(),b.remove({id:e.id},function(a){c.stop(),d.send("Network removed",a),f.path("/networks")},function(a){c.stop(),d.error("Failure",a.data)})},c.spin(),b.get({id:e.id},function(b){a.network=b,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}]),angular.module("networks",[]).config(["$routeProvider",function(a){a.when("/networks/",{templateUrl:"app/components/networks/networks.html",controller:"NetworksController"})}]).controller("NetworksController",["$scope","Network","ViewSpinner","Messages","$route","errorMsgFilter",function(a,b,c,d,e,f){function g(){c.spin(),b.query({},function(b){a.networks=b,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}a.sortType="Name",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.createNetworkConfig={Name:"",Driver:"",IPAM:{Config:[{Subnet:"",IPRange:"",Gateway:""}]}},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.networks,function(c){c.Checked&&(e+=1,b.remove({id:c.Id},function(b){d.send("Network deleted",c.Id);var e=a.networks.indexOf(c);a.networks.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredNetworks,function(b){b.Checked=a.toggle})},a.addNetwork=function(a){c.spin(),b.create(a,function(a){a.Id?d.send("Network created",a.Id):d.error("Failure",f(a)),c.stop(),g()},function(a){d.error("Failure",a.data),c.stop()})},g()}]),angular.module("pullImage",[]).controller("PullImageController",["$scope","$log","Messages","Image","ViewSpinner",function(a,b,c,d,e){a.template="app/components/pullImage/pullImage.html",a.init=function(){a.config={registry:"",fromImage:"",tag:"latest"}},a.init(),a.pull=function(){$("#error-message").hide();var b=(a.config.registry?a.config.registry+"/":"")+a.config.fromImage,f={};f.fromImage=b,f.tag=a.config.tag,e.spin(),$("#pull-modal").modal("hide"),d.create(f,function(d){if(e.stop(),d.constructor===Array){var f=d.length>0&&d[d.length-1].hasOwnProperty("error");if(f){var g=d[d.length-1];a.error="Cannot pull image "+b+" Reason: "+g.error,$("#pull-modal").modal("show"),$("#error-message").show()}else c.send("Image Added",b),a.init()}else c.send("Image Added",b),a.init()},function(c){e.stop(),a.error="Cannot pull image "+b+" Reason: "+c.data,$("#pull-modal").modal("show"),$("#error-message").show()})}}]),angular.module("sidebar",[]).controller("SideBarController",["$scope","Container","Settings",function(a,b,c){a.template="partials/sidebar.html",a.containers=[],a.endpoint=c.endpoint,b.query({all:0},function(b){a.containers=b})}]),angular.module("startContainer",["ui.bootstrap"]).controller("StartContainerController",["$scope","$routeParams","$location","Container","Messages","containernameFilter","errorMsgFilter",function(a,b,c,d,e,f,g){function h(a,b){b.error("Error",g(a))}function i(a){for(var b in a)(null===a[b]||void 0===a[b]||""===a[b]||$.isPlainObject(a[b])&&$.isEmptyObject(a[b])||0===a[b].length)&&delete a[b]}function j(a){return a.map(function(a){return a.name})}a.template="app/components/startContainer/startcontainer.html",d.query({all:1},function(b){a.containerNames=b.map(function(a){return f(a)})}),a.config={Env:[],Labels:[],Volumes:[],SecurityOpts:[],HostConfig:{PortBindings:[],Binds:[],Links:[],Dns:[],DnsSearch:[],VolumesFrom:[],CapAdd:[],CapDrop:[],Devices:[],LxcConf:[],ExtraHosts:[]}},a.menuStatus={containerOpen:!0,hostConfigOpen:!1},a.create=function(){var f=angular.copy(a.config);f.Image=b.id,f.Cmd&&"["===f.Cmd[0]?f.Cmd=angular.fromJson(f.Cmd):f.Cmd&&(f.Cmd=f.Cmd.split(" ")),f.Env=f.Env.map(function(a){return a.name+"="+a.value});var g={};f.Labels=f.Labels.forEach(function(a){g[a.key]=a.value}),f.Labels=g,f.Volumes=j(f.Volumes),f.SecurityOpts=j(f.SecurityOpts),f.HostConfig.VolumesFrom=j(f.HostConfig.VolumesFrom),f.HostConfig.Binds=j(f.HostConfig.Binds),f.HostConfig.Links=j(f.HostConfig.Links),f.HostConfig.Dns=j(f.HostConfig.Dns),f.HostConfig.DnsSearch=j(f.HostConfig.DnsSearch),f.HostConfig.CapAdd=j(f.HostConfig.CapAdd),f.HostConfig.CapDrop=j(f.HostConfig.CapDrop),f.HostConfig.LxcConf=f.HostConfig.LxcConf.reduce(function(a,b,c){return a[b.name]=b.value,a},{}),f.HostConfig.ExtraHosts=f.HostConfig.ExtraHosts.map(function(a){return a.host+":"+a.ip});var k={},l={};f.HostConfig.PortBindings.forEach(function(a){var b=a.intPort+"/tcp";"udp"===a.protocol&&(b=a.intPort+"/udp");var c={HostIp:a.ip,HostPort:a.extPort};a.intPort?(k[b]={},b in l?l[b].push(c):l[b]=[c]):e.send("Warning","Internal port must be specified for PortBindings")}),f.ExposedPorts=k,f.HostConfig.PortBindings=l,i(f.HostConfig),i(f);var m=d,n=c;d.create(f,function(a){a.Id?m.start({id:a.Id},{},function(b){e.send("Container Started",a.Id),$("#create-modal").modal("hide"),n.path("/containers/"+a.Id+"/")},function(a){h(a,e)}):h(a,e)},function(a){h(a,e)})},a.addEntry=function(a,b){a.push(b)},a.rmEntry=function(a,b){var c=a.indexOf(b);a.splice(c,1)}}]),angular.module("stats",[]).controller("StatsController",["Settings","$scope","Messages","$timeout","Container","$routeParams","humansizeFilter","$sce",function(a,b,c,d,e,f,g,h){function i(){e.stats({id:f.id},function(a){var e=Object.keys(a).map(function(b){return a[b]});return-1!==e.join("").indexOf("no such id")?void c.error("Unable to retrieve stats","Is this container running?"):(b.data=a,j(a),k(a),l(a),void(D=d(i,5e3)))},function(){c.error("Unable to retrieve stats","Is this container running?"),D=d(i,5e3)})}function j(a){A.addData([m(a)],new Date(a.read).toLocaleTimeString()),A.removeData()}function k(a){B.addData([a.memory_stats.usage],new Date(a.read).toLocaleTimeString()),B.removeData()}function l(a){a.networks&&(b.networkName=Object.keys(a.networks)[0],a.network=a.networks[b.networkName]);var c=0,d=0;0===E&&0===F||(c=a.network.rx_bytes-E,d=a.network.tx_bytes-F),E=a.network.rx_bytes,F=a.network.tx_bytes,C.addData([c,d],new Date(a.read).toLocaleTimeString()),C.removeData()}function m(a){var b=a.precpu_stats,c=a.cpu_stats,d=0,e=c.cpu_usage.total_usage-b.cpu_usage.total_usage,f=c.system_cpu_usage-b.system_cpu_usage;return f>0&&e>0&&(d=e/f*c.cpu_usage.percpu_usage.length*100),d}for(var n=[],o=[],p=[],q=[],r=[],s=[],t=[],u=0;20>u;u++)n.push(""),o.push(0),p.push(""),q.push(0),r.push(""),s.push(0),t.push(0);var v={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:o},w={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:q},x={label:"Rx Bytes",fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:t},y={label:"Tx Bytes",fillColor:"rgba(255,180,174,0.5)",strokeColor:"rgba(255,180,174,1)",pointColor:"rgba(255,180,174,1)",pointStrokeColor:"#fff",data:s},z=[{color:"rgba(151,187,205,0.5)",title:"Rx Data"},{color:"rgba(255,180,174,0.5)",title:"Rx Data"}];legend($("#network-legend").get(0),z),Chart.defaults.global.animationSteps=30;var A=new Chart($("#cpu-stats-chart").get(0).getContext("2d")).Line({labels:n,datasets:[v]},{responsive:!0}),B=new Chart($("#memory-stats-chart").get(0).getContext("2d")).Line({labels:p,datasets:[w]},{scaleLabel:function(a){return g(parseInt(a.value,10))},responsive:!0}),C=new Chart($("#network-stats-chart").get(0).getContext("2d")).Line({labels:r,datasets:[x,y]},{scaleLabel:function(a){return g(parseInt(a.value,10))},responsive:!0});b.networkLegend=h.trustAsHtml(C.generateLegend());var D;b.$on("$destroy",function(){d.cancel(D)}),i();var E=0,F=0;e.get({id:f.id},function(a){b.containerName=a.Name.substring(1)},function(a){c.error("Failure",a.data)})}]),angular.module("volumes",[]).config(["$routeProvider",function(a){a.when("/volumes/",{templateUrl:"app/components/volumes/volumes.html",controller:"VolumesController"})}]).controller("VolumesController",["$scope","Volume","ViewSpinner","Messages","$route","errorMsgFilter",function(a,b,c,d,e,f){function g(){c.spin(),b.query({},function(b){a.volumes=b.Volumes,c.stop()},function(a){d.error("Failure",a.data),c.stop()})}a.sortType="Name",a.sortReverse=!0,a.toggle=!1,a.order=function(b){a.sortReverse=a.sortType===b?!a.sortReverse:!1,a.sortType=b},a.createVolumeConfig={Name:"",Driver:""},a.removeAction=function(){c.spin();var e=0,f=function(){e-=1,0===e&&c.stop()};angular.forEach(a.volumes,function(c){c.Checked&&(e+=1,b.remove({name:c.Name},function(b){d.send("Volume deleted",c.Name);var e=a.volumes.indexOf(c);a.volumes.splice(e,1),f()},function(a){d.error("Failure",a.data),f()}))})},a.toggleSelectAll=function(){angular.forEach(a.filteredVolumes,function(b){b.Checked=a.toggle})},a.addVolume=function(a){c.spin(),b.create(a,function(a){a.Name?d.send("Volume created",a.Name):d.error("Failure",f(a)),c.stop(),g()},function(a){d.error("Failure",a.data),c.stop()})},g()}]),angular.module("uifordocker.filters",[]).filter("truncate",function(){"use strict";return function(a,b,c){return isNaN(b)&&(b=10),void 0===c&&(c="..."),a.length<=b||a.length-c.length<=b?a:String(a).substring(0,b-c.length)+c}}).filter("statusbadge",function(){"use strict";return function(a){return"Ghost"===a?"important":-1!==a.indexOf("Exit")&&"Exit 0"!==a?"warning":"success"}}).filter("getstatetext",function(){"use strict";return function(a){return void 0===a?"":a.Ghost&&a.Running?"Ghost":a.Running&&a.Paused?"Running (Paused)":a.Running?"Running":"Stopped"}}).filter("getstatelabel",function(){"use strict";return function(a){return void 0===a?"label-default":a.Ghost&&a.Running?"label-important":a.Running?"label-success":"label-default"}}).filter("humansize",function(){"use strict";return function(a){var b=["Bytes","KB","MB","GB","TB"];if(0===a)return"n/a";var c=parseInt(Math.floor(Math.log(a)/Math.log(1024)),10),d=a/Math.pow(1024,c),e=1>c?0:c-1;return d.toFixed(e)+" "+b[[c]]}}).filter("containername",function(){"use strict";return function(a){var b=a.Names[0];return b.substring(1,b.length)}}).filter("repotag",function(){"use strict";return function(a){if(a.RepoTags&&a.RepoTags.length>0){var b=a.RepoTags[0];return":"===b&&(b=""),b}return""}}).filter("errorMsg",function(){return function(a){for(var b=0,c="";a[b]&&"string"==typeof a[b];)c+=a[b],b++;return c}}),angular.module("uifordocker.services",["ngResource","ngSanitize"]).factory("Container",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/containers/:id/:action",{name:"@name"},{query:{method:"GET",params:{all:0,action:"json"},isArray:!0},get:{method:"GET",params:{action:"json"}},start:{method:"POST",params:{id:"@id",action:"start"}},stop:{method:"POST",params:{id:"@id",t:5,action:"stop"}},restart:{method:"POST",params:{id:"@id",t:5,action:"restart"}},kill:{method:"POST",params:{id:"@id",action:"kill"}},pause:{method:"POST",params:{id:"@id",action:"pause"}},unpause:{method:"POST",params:{id:"@id",action:"unpause"}},changes:{ +method:"GET",params:{action:"changes"},isArray:!0},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE",params:{id:"@id",v:0}},rename:{method:"POST",params:{id:"@id",action:"rename"},isArray:!1},stats:{method:"GET",params:{id:"@id",stream:!1,action:"stats"},timeout:5e3}})}]).factory("ContainerCommit",["$resource","$http","Settings",function(a,b,c){"use strict";return{commit:function(a,d){b({method:"POST",url:c.url+"/commit",params:{container:a.id,tag:a.tag||null,repo:a.repo||null},data:a.config}).success(d).error(function(a,b,c,d){console.log(error,a)})}}}]).factory("ContainerLogs",["$resource","$http","Settings",function(a,b,c){"use strict";return{get:function(a,d,e){b({method:"GET",url:c.url+"/containers/"+a+"/logs",params:{stdout:d.stdout||0,stderr:d.stderr||0,timestamps:d.timestamps||0,tail:d.tail||"all"}}).success(e).error(function(a,b,c,d){console.log(error,a)})}}}]).factory("ContainerTop",["$http","Settings",function(a,b){"use strict";return{get:function(c,d,e,f){a({method:"GET",url:b.url+"/containers/"+c+"/top",params:{ps_args:d.ps_args}}).success(e)}}}]).factory("Image",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/images/:id/:action",{},{query:{method:"GET",params:{all:0,action:"json"},isArray:!0},get:{method:"GET",params:{action:"json"}},search:{method:"GET",params:{action:"search"}},history:{method:"GET",params:{action:"history"},isArray:!0},create:{method:"POST",isArray:!0,transformResponse:[function(a){var b=a.replace(/\n/g," ").replace(/\}\W*\{/g,"}, {");return angular.fromJson("["+b+"]")}],params:{action:"create",fromImage:"@fromImage",tag:"@tag"}},insert:{method:"POST",params:{id:"@id",action:"insert"}},push:{method:"POST",params:{id:"@id",action:"push"}},tag:{method:"POST",params:{id:"@id",action:"tag",force:0,repo:"@repo",tag:"@tag"}},remove:{method:"DELETE",params:{id:"@id"},isArray:!0},inspect:{method:"GET",params:{id:"@id",action:"json"}}})}]).factory("Version",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/version",{},{get:{method:"GET"}})}]).factory("Auth",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/auth",{},{get:{method:"GET"},update:{method:"POST"}})}]).factory("Info",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/info",{},{get:{method:"GET"}})}]).factory("Network",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/networks/:id/:action",{id:"@id"},{query:{method:"GET",isArray:!0},get:{method:"GET"},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE"},connect:{method:"POST",params:{action:"connect"}},disconnect:{method:"POST",params:{action:"disconnect"}}})}]).factory("Volume",["$resource","Settings",function(a,b){"use strict";return a(b.url+"/volumes/:name/:action",{name:"@name"},{query:{method:"GET"},get:{method:"GET"},create:{method:"POST",params:{action:"create"}},remove:{method:"DELETE"}})}]).factory("Settings",["DOCKER_ENDPOINT","DOCKER_PORT","UI_VERSION",function(a,b,c){"use strict";var d=a;b&&(d=d+b+"\\"+b);var e="true"===(localStorage.getItem("firstLoad")||"true");return{displayAll:!1,endpoint:a,uiVersion:c,url:d,firstLoad:e}}]).factory("ViewSpinner",function(){"use strict";var a=new Spinner,b=document.getElementById("view");return{spin:function(){a.spin(b)},stop:function(){a.stop()}}}).factory("Messages",["$rootScope","$sanitize",function(a,b){"use strict";return{send:function(a,c){$.gritter.add({title:b(a),text:b(c),time:2e3,before_open:function(){return 3===$(".gritter-item-wrapper").length?!1:void 0}})},error:function(a,c){$.gritter.add({title:b(a),text:b(c),time:1e4,before_open:function(){return 4===$(".gritter-item-wrapper").length?!1:void 0}})}}}]).factory("LineChart",["Settings",function(a){"use strict";return{build:function(a,b,c){for(var d=new Chart($(a).get(0).getContext("2d")),e={},f=0;f-1;f--){var m=k[f];j.push(m),b.push(e[m]),e[m]>l&&(l=e[m])}var n=Math.min(l,10),o={fillColor:"rgba(151,187,205,0.5)",strokeColor:"rgba(151,187,205,1)",pointColor:"rgba(151,187,205,1)",pointStrokeColor:"#fff",data:b};d.Line({labels:j,datasets:[o]},{scaleStepWidth:Math.ceil(l/n),pointDotRadius:1,scaleIntegersOnly:!0,scaleOverride:!0,scaleSteps:n})}}}]),angular.module("uifordocker.templates",["app/components/builder/builder.html","app/components/container/container.html","app/components/containerLogs/containerlogs.html","app/components/containerTop/containerTop.html","app/components/containers/containers.html","app/components/containersNetwork/containersNetwork.html","app/components/dashboard/dashboard.html","app/components/events/events.html","app/components/footer/statusbar.html","app/components/image/image.html","app/components/images/images.html","app/components/info/info.html","app/components/masthead/masthead.html","app/components/network/network.html","app/components/networks/networks.html","app/components/pullImage/pullImage.html","app/components/sidebar/sidebar.html","app/components/startContainer/startcontainer.html","app/components/stats/stats.html","app/components/volumes/volumes.html"]),angular.module("app/components/builder/builder.html",[]).run(["$templateCache",function(a){a.put("app/components/builder/builder.html",'\n')}]),angular.module("app/components/container/container.html",[]).run(["$templateCache",function(a){a.put("app/components/container/container.html",'
    \n\n
    \n

    Container: {{ container.Name }}\n \n

    \n
    \n
    \n

    \n Container:\n \n \n \n

    \n
    \n\n
    \n \n \n \n \n \n \n \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Created:{{ container.Created | date: \'yyyy-MM-dd HH:mm:ss\' }}
    Path:{{ container.Path }}
    Args:\n
    {{ container.Args.join(\' \') || \'None\' }}
    \n
    Exposed Ports:\n
      \n
    • {{ k }}
    • \n
    \n
    Environment:\n
    \n \n
      \n
    • {{ k }}
    • \n
    \n
    \n
    \n \n\n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n
    \n
    \n
    \n \n \n
    \n\n\n
    Labels:\n \n \n \n \n \n \n \n \n \n
    KeyValue
    {{ k }}{{ v }}
    \n
    Publish All:{{ container.HostConfig.PublishAllPorts }}
    Ports:\n
    \n \n
      \n
    • \n {{ containerport }} =>\n {{ v.HostIp }}:{{ v.HostPort }}\n
    • \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n \n
    \n
    Hostname:{{ container.Config.Hostname }}
    IPAddress:{{ container.NetworkSettings.IPAddress }}
    Cmd:{{ container.Config.Cmd }}
    Entrypoint:\n
    {{ container.Config.Entrypoint.join(\' \') }}
    \n
    Bindings:\n
    \n \n\n
      \n
    • {{ b }}
    • \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n \n\n
    \n
    Volumes:{{ container.Volumes }}
    SysInitpath:{{ container.SysInitPath }}
    Image:{{ container.Image }}
    State:\n \n \n
      \n
    • {{key}} : {{ val }}
    • \n
    \n
    \n
    \n
    Logs:stdout/stderr
    Stats:stats
    Top:Top
    \n\n
    \n
    \n Changes:\n
    \n
    \n \n
    \n
    \n\n
    \n
      \n
    • \n {{ change.Path }} {{ change.Kind }}\n
    • \n
    \n
    \n\n
    \n\n
    \n \n
    \n
    \n')}]),angular.module("app/components/containerLogs/containerlogs.html",[]).run(["$templateCache",function(a){a.put("app/components/containerLogs/containerlogs.html",'
    \n
    \n

    Logs for container: {{ container.Name }}

    \n\n
    \n \n \n
    \n
    \n
    \n Reload logs\n \n \n
    \n
    \n \n
    \n
    \n
    \n\n
    \n
    \n
    \n

    STDOUT

    \n
    \n
    \n
    {{stdout}}
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    STDERR

    \n
    \n
    \n
    {{stderr}}
    \n
    \n
    \n
    \n
    \n')}]),angular.module("app/components/containerTop/containerTop.html",[]).run(["$templateCache",function(a){a.put("app/components/containerTop/containerTop.html",'
    \n
    \n
    \n

    Top for: {{ containerName }}

    \n
    \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n
    {{title}}
    {{processInfo}}
    \n
    \n
    \n
    ')}]),angular.module("app/components/containers/containers.html",[]).run(["$templateCache",function(a){a.put("app/components/containers/containers.html",'\n

    Containers:

    \n\n
    \n \n\n
    \n  \n \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Name\n \n \n \n \n \n Image\n \n \n \n \n \n Command\n \n \n \n \n \n Created\n \n \n \n \n \n Status\n \n \n \n \n Log\n
    {{ container|containername}}{{ container.Image }}{{ container.Command|truncate:40 }}{{ container.Created * 1000 | date: \'yyyy-MM-dd\' }}{{ container.Status }}stdout/stderr
    \n')}]),angular.module("app/components/containersNetwork/containersNetwork.html",[]).run(["$templateCache",function(a){a.put("app/components/containersNetwork/containersNetwork.html",'
    \n

    Containers Network

    \n\n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n \n \n
    \n Include stopped containers\n
    \n
    \n \n
    \n
    \n')}]),angular.module("app/components/dashboard/dashboard.html",[]).run(["$templateCache",function(a){a.put("app/components/dashboard/dashboard.html",'
    \n \n
    \n \n
    \n\n
    \n
    \n
    \n

    Running Containers

    \n \n
    \n
    \n

    Status

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n
    \n
    \n
    \n\n
    \n
    \n

    Containers created

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n

    Images created

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n
    \n
    \n')}]),angular.module("app/components/events/events.html",[]).run(["$templateCache",function(a){a.put("app/components/events/events.html",'
    \n
    \n

    Events

    \n\n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n
    EventFromIDTime
    \n \n \n \n
    \n
    \n
    \n')}]),angular.module("app/components/footer/statusbar.html",[]).run(["$templateCache",function(a){ +a.put("app/components/footer/statusbar.html",'
    \n

    \n Docker API Version: {{ apiVersion }} UI Version: {{ uiVersion }} UI For Docker\n

    \n
    \n')}]),angular.module("app/components/image/image.html",[]).run(["$templateCache",function(a){a.put("app/components/image/image.html",'
    \n\n\n\n
    \n\n

    Image: {{ id }}

    \n\n
    \n \n
    \n\n
    \n

    Containers created:

    \n \n

    You are using an outdated browser. Please upgrade your browser to improve your experience.

    \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n
    Tags:\n
      \n
    • {{ tag }}\n \n
    • \n
    \n
    Created:{{ image.Created | date: \'yyyy-MM-dd HH:mm:ss\'}}
    Parent:{{ image.Parent }}
    Size (Virtual Size):{{ image.Size|humansize }} ({{ image.VirtualSize|humansize }})
    Hostname:{{ image.ContainerConfig.Hostname }}
    User:{{ image.ContainerConfig.User }}
    Cmd:{{ image.ContainerConfig.Cmd }}
    Volumes:{{ image.ContainerConfig.Volumes }}
    Volumes from:{{ image.ContainerConfig.VolumesFrom }}
    Built with:Docker {{ image.DockerVersion }} on {{ image.Os}}, {{ image.Architecture }}
    \n\n
    \n
    \n History:\n
    \n
    \n \n
    \n
    \n\n
    \n
      \n
    • \n {{ change.Id }}: Created: {{ change.Created | date: \'yyyy-MM-dd\' }} Created by: {{ change.CreatedBy\n }}\n
    • \n
    \n
    \n\n
    \n\n
    \n
    \n
    \n Tag image\n
    \n \n \n \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n\n
    \n\n
    \n \n
    \n
    \n')}]),angular.module("app/components/images/images.html",[]).run(["$templateCache",function(a){a.put("app/components/images/images.html",'
    \n
    \n\n

    Images:

    \n\n
    \n \n\n
    \n \n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Id\n \n \n \n \n \n Repository\n \n \n \n \n \n VirtualSize\n \n \n \n \n \n Created\n \n \n \n
    {{ image.Id|truncate:20}}{{ image|repotag }}{{ image.VirtualSize|humansize }}{{ image.Created * 1000 | date: \'yyyy-MM-dd\' }}
    \n')}]),angular.module("app/components/info/info.html",[]).run(["$templateCache",function(a){a.put("app/components/info/info.html",'
    \n

    Docker Information

    \n\n
    \n

    \n API Endpoint: {{ endpoint }}
    \n API Version: {{ docker.ApiVersion }}
    \n Docker version: {{ docker.Version }}
    \n Git Commit: {{ docker.GitCommit }}
    \n Go Version: {{ docker.GoVersion }}
    \n

    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Containers:{{ info.Containers }}
    Images:{{ info.Images }}
    Debug:{{ info.Debug }}
    CPUs:{{ info.NCPU }}
    Total Memory:{{ info.MemTotal|humansize }}
    Operating System:{{ info.OperatingSystem }}
    Kernel Version:{{ info.KernelVersion }}
    ID:{{ info.ID }}
    Labels:{{ info.Labels }}
    File Descriptors:{{ info.NFd }}
    Goroutines:{{ info.NGoroutines }}
    Storage Driver:{{ info.Driver }}
    Storage Driver Status:\n

    \n {{ val[0] }}: {{ val[1] }}\n

    \n
    Execution Driver:{{ info.ExecutionDriver }}
    Events:Events
    IPv4 Forwarding:{{ info.IPv4Forwarding }}
    Index Server Address:{{ info.IndexServerAddress }}
    Init Path:{{ info.InitPath }}
    Docker Root Directory:{{ info.DockerRootDir }}
    Init SHA1{{ info.InitSha1 }}
    Memory Limit:{{ info.MemoryLimit }}
    Swap Limit:{{ info.SwapLimit }}
    \n
    \n')}]),angular.module("app/components/masthead/masthead.html",[]).run(["$templateCache",function(a){a.put("app/components/masthead/masthead.html",'
    \n

    UI For Docker

    \n\n \n
    \n \n
    \n
    \n')}]),angular.module("app/components/network/network.html",[]).run(["$templateCache",function(a){a.put("app/components/network/network.html",'
    \n\n

    Network: {{ network.Name }}

    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Name:{{ network.Name }}
    Id:{{ network.Id }}
    Scope:{{ network.Scope }}
    Driver:{{ network.Driver }}
    IPAM:\n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Driver:{{ network.IPAM.Driver }}
    Subnet:{{ network.IPAM.Config[0].Subnet }}
    Gateway:{{ network.IPAM.Config[0].Gateway }}
    \n
    Containers:\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Id:{{ Id }}\n \n
    EndpointID:{{ container.EndpointID}}
    MacAddress:{{ container.MacAddress}}
    IPv4Address:{{ container.IPv4Address}}
    IPv6Address:{{ container.IPv6Address}}
    \n
    \n
    \n \n
    \n \n
    \n
    Options:\n \n \n \n \n \n \n \n \n \n
    KeyValue
    {{ k }}{{ v }}
    \n
    \n\n\n
    \n\n\n
    \n \n
    \n
    ')}]),angular.module("app/components/networks/networks.html",[]).run(["$templateCache",function(a){a.put("app/components/networks/networks.html",'

    Networks:

    \n\n
    \n \n\n
    \n Filter\n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Name\n \n \n \n \n \n Id\n \n \n \n \n \n Scope\n \n \n \n \n \n Driver\n \n \n \n \n \n IPAM Driver\n \n \n \n \n \n IPAM Subnet\n \n \n \n \n \n IPAM Gateway\n \n \n \n
    {{ network.Name|truncate:20}}{{ network.Id }}{{ network.Scope }}{{ network.Driver }}{{ network.IPAM.Driver }}{{ network.IPAM.Config[0].Subnet }}{{ network.IPAM.Config[0].Gateway }}
    \n
    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n
    ')}]),angular.module("app/components/pullImage/pullImage.html",[]).run(["$templateCache",function(a){a.put("app/components/pullImage/pullImage.html",'\n')}]),angular.module("app/components/sidebar/sidebar.html",[]).run(["$templateCache",function(a){a.put("app/components/sidebar/sidebar.html",'
    \n Running containers:\n
    \n Endpoint: {{ endpoint }}\n \n
    \n')}]),angular.module("app/components/startContainer/startcontainer.html",[]).run(["$templateCache",function(a){a.put("app/components/startContainer/startcontainer.html",'\n'); }]),angular.module("app/components/stats/stats.html",[]).run(["$templateCache",function(a){a.put("app/components/stats/stats.html",'
    \n
    \n

    Stats for: {{ containerName }}

    \n\n

    CPU

    \n\n
    \n
    \n \n
    \n
    \n\n

    Memory

    \n\n
    \n
    \n \n
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Max usage{{ data.memory_stats.max_usage | humansize }}
    Limit{{ data.memory_stats.limit | humansize }}
    Fail count{{ data.memory_stats.failcnt }}
    \n \n \n \n \n \n \n \n
    {{ key }}{{ value }}
    \n
    \n
    \n
    \n
    \n\n

    Network {{ networkName}}

    \n
    \n
    \n \n
    \n
    \n
    \n \n \n \n \n \n \n \n
    {{ key }}{{ value }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n')}]),angular.module("app/components/volumes/volumes.html",[]).run(["$templateCache",function(a){a.put("app/components/volumes/volumes.html",'

    Volumes:

    \n\n
    \n \n\n
    \n Filter\n
    \n
    \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    \n \n Name\n \n \n \n \n \n Driver\n \n \n \n \n \n Mountpoint\n \n \n \n
    {{ volume.Name|truncate:20 }}{{ volume.Driver }}{{ volume.Mountpoint }}
    \n
    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n
    ')}]); \ No newline at end of file diff --git a/dockerui.go b/dockerui.go deleted file mode 100644 index 7cf0172..0000000 --- a/dockerui.go +++ /dev/null @@ -1,190 +0,0 @@ -package main // import "github.com/kevana/ui-for-docker" - -import ( - "flag" - "io" - "log" - "net" - "net/http" - "net/http/httputil" - "net/url" - "os" - "github.com/gorilla/csrf" - "io/ioutil" - "fmt" - "github.com/gorilla/securecookie" - "crypto/tls" - "crypto/x509" -) - -var ( - endpoint = flag.String("H", "unix:///var/run/docker.sock", "Dockerd endpoint") - addr = flag.String("p", ":9000", "Address and port to serve UI For Docker") - assets = flag.String("a", ".", "Path to the assets") - data = flag.String("d", ".", "Path to the data") - tlsverify = flag.Bool("tlsverify", false, "TLS support") - tlscacert = flag.String("tlscacert", "/certs/ca.pem", "Path to the CA") - tlscert = flag.String("tlscert", "/certs/cert.pem", "Path to the TLS certificate file") - tlskey = flag.String("tlskey", "/certs/key.pem", "Path to the TLS key") - authKey []byte - authKeyFile = "authKey.dat" -) - -type UnixHandler struct { - path string -} - -type TLSFlags struct { - tls bool - caPath string - certPath string - keyPath string -} - -func (h *UnixHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - conn, err := net.Dial("unix", h.path) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - log.Println(err) - return - } - c := httputil.NewClientConn(conn, nil) - defer c.Close() - - res, err := c.Do(r) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - log.Println(err) - return - } - defer res.Body.Close() - - copyHeader(w.Header(), res.Header) - if _, err := io.Copy(w, res.Body); err != nil { - log.Println(err) - } -} - -func copyHeader(dst, src http.Header) { - for k, vv := range src { - for _, v := range vv { - dst.Add(k, v) - } - } -} - -func createTLSConfig(flags TLSFlags) *tls.Config { - cert, err := tls.LoadX509KeyPair(flags.certPath, flags.keyPath) - if err != nil { - log.Fatal(err) - } - caCert, err := ioutil.ReadFile(flags.caPath) - if err != nil { - log.Fatal(err) - } - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{cert}, - RootCAs: caCertPool, - } - return tlsConfig; -} - -func createTcpHandler(u *url.URL) http.Handler { - u.Scheme = "http"; - return httputil.NewSingleHostReverseProxy(u) -} - -func createTcpHandlerWithTLS(u *url.URL, flags TLSFlags) http.Handler { - u.Scheme = "https"; - var tlsConfig = createTLSConfig(flags) - proxy := httputil.NewSingleHostReverseProxy(u) - proxy.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } - return proxy; -} - -func createUnixHandler(e string) http.Handler { - return &UnixHandler{e} -} - -func createHandler(dir string, d string, e string, flags TLSFlags) http.Handler { - var ( - mux = http.NewServeMux() - fileHandler = http.FileServer(http.Dir(dir)) - h http.Handler - ) - - u, perr := url.Parse(e) - if perr != nil { - log.Fatal(perr) - } - - if u.Scheme == "tcp" { - if flags.tls { - h = createTcpHandlerWithTLS(u, flags) - } else { - h = createTcpHandler(u) - } - } else if u.Scheme == "unix" { - var socketPath = u.Path - if _, err := os.Stat(socketPath); err != nil { - if os.IsNotExist(err) { - log.Fatalf("unix socket %s does not exist", socketPath) - } - log.Fatal(err) - } - h = createUnixHandler(socketPath) - } else { - log.Fatalf("Bad Docker enpoint: %s. Only unix:// and tcp:// are supported.", e) - } - - // Use existing csrf authKey if present or generate a new one. - var authKeyPath = d + "/" + authKeyFile - dat, err := ioutil.ReadFile(authKeyPath) - if err != nil { - fmt.Println(err) - authKey = securecookie.GenerateRandomKey(32) - err := ioutil.WriteFile(authKeyPath, authKey, 0644) - if err != nil { - fmt.Println("unable to persist auth key", err) - } - } else { - authKey = dat - } - - CSRF := csrf.Protect( - authKey, - csrf.HttpOnly(false), - csrf.Secure(false), - ) - - mux.Handle("/dockerapi/", http.StripPrefix("/dockerapi", h)) - mux.Handle("/", fileHandler) - return CSRF(csrfWrapper(mux)) -} - -func csrfWrapper(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-CSRF-Token", csrf.Token(r)) - h.ServeHTTP(w, r) - }) -} - -func main() { - flag.Parse() - - tlsFlags := TLSFlags{ - tls: *tlsverify, - caPath: *tlscacert, - certPath: *tlscert, - keyPath: *tlskey, - } - - handler := createHandler(*assets, *data, *endpoint, tlsFlags) - if err := http.ListenAndServe(*addr, handler); err != nil { - log.Fatal(err) - } -} diff --git a/gruntFile.js b/gruntFile.js index c917008..8dbf1ed 100644 --- a/gruntFile.js +++ b/gruntFile.js @@ -248,10 +248,10 @@ module.exports = function (grunt) { }, buildBinary: { command: [ - 'docker run --rm -v $(pwd):/src centurylink/golang-builder', - 'shasum ui-for-docker > ui-for-docker-checksum.txt', + 'docker run --rm -v $(pwd)/api:/src centurylink/golang-builder', + 'shasum api/ui-for-docker > ui-for-docker-checksum.txt', 'mkdir -p dist', - 'mv ui-for-docker dist/' + 'mv api/ui-for-docker dist/' ].join(' && ') }, run: { diff --git a/package.json b/package.json index 7fb094c..97c264f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Michael Crosby & Kevan Ahlquist", "name": "uifordocker", "homepage": "https://github.com/kevana/ui-for-docker", - "version": "0.11.0-beta", + "version": "0.11.0", "repository": { "type": "git", "url": "git@github.com:kevana/ui-for-docker.git" diff --git a/ui-for-docker-checksum.txt b/ui-for-docker-checksum.txt index c18067a..7f5afab 100644 --- a/ui-for-docker-checksum.txt +++ b/ui-for-docker-checksum.txt @@ -1 +1 @@ -a0fa0caaaf7d8b37e8d32b32c5a41fc20deb67d1 ui-for-docker +4c0f6ff8f77da9eabf56155e8a488c6d632189ce api/ui-for-docker