Victor Vieux 12 rokov pred
rodič
commit
e1fa989ec9

+ 2 - 0
.mailmap

@@ -23,3 +23,5 @@ Thatcher Peskens <thatcher@dotcloud.com>
 Walter Stanish <walter@pratyeka.org>
 <daniel@gasienica.ch> <dgasienica@zynga.com>
 Roberto Hashioka <roberto_hashioka@hotmail.com>
+Konstantin Pelykh <kpelykh@zettaset.com>
+David Sissitka <me@dsissitka.com>

+ 24 - 1
AUTHORS

@@ -4,12 +4,15 @@
 # For a list of active project maintainers, see the MAINTAINERS file.
 #
 Al Tobey <al@ooyala.com>
+Alex Gaynor <alex.gaynor@gmail.com>
 Alexey Shamrin <shamrin@gmail.com>
 Andrea Luzzardi <aluzzardi@gmail.com>
 Andreas Tiefenthaler <at@an-ti.eu>
 Andrew Munsell <andrew@wizardapps.net>
+Andrews Medina <andrewsmedina@gmail.com>
 Andy Rothfusz <github@metaliveblog.com>
 Andy Smith <github@anarkystic.com>
+Anthony Bishopric <git@anthonybishopric.com>
 Antony Messerli <amesserl@rackspace.com>
 Barry Allard <barry.allard@gmail.com>
 Brandon Liu <bdon@bdon.org>
@@ -23,17 +26,23 @@ Daniel Gasienica <daniel@gasienica.ch>
 Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
 Daniel Robinson <gottagetmac@gmail.com>
 Daniel Von Fange <daniel@leancoder.com>
+Daniel YC Lin <dlin.tw@gmail.com>
+David Calavera <david.calavera@gmail.com>
+David Sissitka <me@dsissitka.com>
 Dominik Honnef <dominik@honnef.co>
 Don Spaulding <donspauldingii@gmail.com>
 Dr Nic Williams <drnicwilliams@gmail.com>
 Elias Probst <mail@eliasprobst.eu>
 Eric Hanchrow <ehanchrow@ine.com>
-Evan Wies <evan@neomantra.net>
 Eric Myhre <hash@exultant.us>
+Erno Hopearuoho <erno.hopearuoho@gmail.com>
+Evan Wies <evan@neomantra.net>
 ezbercih <cem.ezberci@gmail.com>
+Fabrizio Regini <freegenie@gmail.com>
 Flavio Castelli <fcastelli@suse.com>
 Francisco Souza <f@souza.cc>
 Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
+Gabriel Monroy <gabriel@opdemand.com>
 Gareth Rushgrove <gareth@morethanseven.net>
 Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
 Harley Laue <losinggeneration@gmail.com>
@@ -41,6 +50,7 @@ Hunter Blanks <hunter@twilio.com>
 Jeff Lindsay <progrium@gmail.com>
 Jeremy Grosser <jeremy@synack.me>
 Joffrey F <joffrey@dotcloud.com>
+Johan Euphrosine <proppy@google.com>
 John Costa <john.costa@gmail.com>
 Jon Wedaman <jweede@gmail.com>
 Jonas Pfenniger <jonas@pfenniger.name>
@@ -48,28 +58,39 @@ Jonathan Rudenberg <jonathan@titanous.com>
 Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
 Julien Barbier <write0@gmail.com>
 Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
+Karan Lyons <karan@karanlyons.com>
+Keli Hu <dev@keli.hu>
 Ken Cochrane <kencochrane@gmail.com>
 Kevin J. Lynagh <kevin@keminglabs.com>
 kim0 <email.ahmedkamal@googlemail.com>
+Kimbro Staken <kstaken@kstaken.com>
 Kiran Gangadharan <kiran.daredevil@gmail.com>
+Konstantin Pelykh <kpelykh@zettaset.com>
 Louis Opter <kalessin@kalessin.fr>
+Marco Hennings <marco.hennings@freiheit.com>
 Marcus Farkas <toothlessgear@finitebox.com>
 Mark McGranaghan <mmcgrana@gmail.com>
 Maxim Treskin <zerthurd@gmail.com>
 meejah <meejah@meejah.ca>
 Michael Crosby <crosby.michael@gmail.com>
+Mike Gaffney <mike@uberu.com>
 Mikhail Sobolev <mss@mawhrin.net>
+Nan Monnand Deng <monnand@gmail.com>
 Nate Jones <nate@endot.org>
 Nelson Chen <crazysim@gmail.com>
 Niall O'Higgins <niallo@unworkable.org>
+Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
+Nick Stinemates <nick@stinemates.org>
 odk- <github@odkurzacz.org>
 Paul Bowsher <pbowsher@globalpersonals.co.uk>
 Paul Hammond <paul@paulhammond.org>
 Phil Spitler <pspitler@gmail.com>
 Piotr Bogdan <ppbogdan@gmail.com>
 Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
+Rhys Hiltner <rhys@twitch.tv>
 Robert Obryk <robryk@gmail.com>
 Roberto Hashioka <roberto_hashioka@hotmail.com>
+Ryan Fowler <rwfowler@gmail.com>
 Sam Alba <sam.alba@gmail.com>
 Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
 Shawn Siefkas <shawn.siefkas@meredith.com>
@@ -83,6 +104,8 @@ Thomas Hansen <thomas.hansen@gmail.com>
 Tianon Gravi <admwiggin@gmail.com>
 Tim Terhorst <mynamewastaken+git@gmail.com>
 Tobias Bieniek <Tobias.Bieniek@gmx.de>
+Tobias Schwab <tobias.schwab@dynport.de>
+Tom Hulihan <hulihan.tom159@gmail.com>
 unclejack <unclejacksons@gmail.com>
 Victor Vieux <victor.vieux@dotcloud.com>
 Vivek Agarwal <me@vivek.im>

+ 211 - 137
README.md

@@ -1,80 +1,129 @@
 Docker: the Linux container engine
 ==================================
 
-Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers.
+Docker is an open-source engine which automates the deployment of
+applications as highly portable, self-sufficient containers.
 
-Docker containers are both *hardware-agnostic* and *platform-agnostic*. This means that they can run anywhere, from your
-laptop to the largest EC2 compute instance and everything in between - and they don't require that you use a particular
-language, framework or packaging system. That makes them great building blocks for deploying and scaling web apps, databases
-and backend services without depending on a particular stack or provider.
+Docker containers are both *hardware-agnostic* and
+*platform-agnostic*. This means that they can run anywhere, from your
+laptop to the largest EC2 compute instance and everything in between -
+and they don't require that you use a particular language, framework
+or packaging system. That makes them great building blocks for
+deploying and scaling web apps, databases and backend services without
+depending on a particular stack or provider.
 
-Docker is an open-source implementation of the deployment engine which powers [dotCloud](http://dotcloud.com), a popular Platform-as-a-Service.
-It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
-of applications and databases.
+Docker is an open-source implementation of the deployment engine which
+powers [dotCloud](http://dotcloud.com), a popular
+Platform-as-a-Service.  It benefits directly from the experience
+accumulated over several years of large-scale operation and support of
+hundreds of thousands of applications and databases.
 
-![Docker L](docs/sources/concepts/images/lego_docker.jpg "Docker")
+![Docker L](docs/sources/concepts/images/dockerlogo-h.png "Docker")
 
 ## Better than VMs
 
-A common method for distributing applications and sandbox their execution is to use virtual machines, or VMs. Typical VM formats
-are VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory these formats should allow every developer to
-automatically package their application into a "machine" for easy distribution and deployment. In practice, that almost never
-happens, for a few reasons:
-
-  * *Size*: VMs are very large which makes them impractical to store and transfer.
-  * *Performance*: running VMs consumes significant CPU and memory, which makes them impractical in many scenarios, for example local development of multi-tier applications, and
-    large-scale deployment of cpu and memory-intensive applications on large numbers of machines.
-  * *Portability*: competing VM environments don't play well with each other. Although conversion tools do exist, they are limited and add even more overhead.
-  * *Hardware-centric*: VMs were designed with machine operators in mind, not software developers. As a result, they offer very limited tooling for what developers need most:
-    building, testing and running their software. For example, VMs offer no facilities for application versioning, monitoring, configuration, logging or service discovery.
-
-By contrast, Docker relies on a different sandboxing method known as *containerization*. Unlike traditional virtualization,
-containerization takes place at the kernel level. Most modern operating system kernels now support the primitives necessary
-for containerization, including Linux with [openvz](http://openvz.org), [vserver](http://linux-vserver.org) and more recently [lxc](http://lxc.sourceforge.net),
-    Solaris with [zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc) and FreeBSD with [Jails](http://www.freebsd.org/doc/handbook/jails.html).
-
-Docker builds on top of these low-level primitives to offer developers a portable format and runtime environment that solves
-all 4 problems. Docker containers are small (and their transfer can be optimized with layers), they have basically zero memory and cpu overhead,
-they are completely portable and are designed from the ground up with an application-centric design.
-
-The best part: because docker operates at the OS level, it can still be run inside a VM!
+A common method for distributing applications and sandbox their
+execution is to use virtual machines, or VMs. Typical VM formats are
+VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In
+theory these formats should allow every developer to automatically
+package their application into a "machine" for easy distribution and
+deployment. In practice, that almost never happens, for a few reasons:
+
+  * *Size*: VMs are very large which makes them impractical to store
+     and transfer.
+  * *Performance*: running VMs consumes significant CPU and memory,
+    which makes them impractical in many scenarios, for example local
+    development of multi-tier applications, and large-scale deployment
+    of cpu and memory-intensive applications on large numbers of
+    machines.
+  * *Portability*: competing VM environments don't play well with each
+     other. Although conversion tools do exist, they are limited and
+     add even more overhead.
+  * *Hardware-centric*: VMs were designed with machine operators in
+    mind, not software developers. As a result, they offer very
+    limited tooling for what developers need most: building, testing
+    and running their software. For example, VMs offer no facilities
+    for application versioning, monitoring, configuration, logging or
+    service discovery.
+
+By contrast, Docker relies on a different sandboxing method known as
+*containerization*. Unlike traditional virtualization,
+containerization takes place at the kernel level. Most modern
+operating system kernels now support the primitives necessary for
+containerization, including Linux with [openvz](http://openvz.org),
+[vserver](http://linux-vserver.org) and more recently
+[lxc](http://lxc.sourceforge.net), Solaris with
+[zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc)
+and FreeBSD with
+[Jails](http://www.freebsd.org/doc/handbook/jails.html).
+
+Docker builds on top of these low-level primitives to offer developers
+a portable format and runtime environment that solves all 4
+problems. Docker containers are small (and their transfer can be
+optimized with layers), they have basically zero memory and cpu
+overhead, they are completely portable and are designed from the
+ground up with an application-centric design.
+
+The best part: because ``docker`` operates at the OS level, it can
+still be run inside a VM!
 
 ## Plays well with others
 
-Docker does not require that you buy into a particular programming language, framework, packaging system or configuration language.
+Docker does not require that you buy into a particular programming
+language, framework, packaging system or configuration language.
 
-Is your application a unix process? Does it use files, tcp connections, environment variables, standard unix streams and command-line
-arguments as inputs and outputs? Then docker can run it.
+Is your application a Unix process? Does it use files, tcp
+connections, environment variables, standard Unix streams and
+command-line arguments as inputs and outputs? Then ``docker`` can run
+it.
 
-Can your application's build be expressed as a sequence of such commands? Then docker can build it.
+Can your application's build be expressed as a sequence of such
+commands? Then ``docker`` can build it.
 
 
 ## Escape dependency hell
 
-A common problem for developers is the difficulty of managing all their application's dependencies in a simple and automated way.
+A common problem for developers is the difficulty of managing all
+their application's dependencies in a simple and automated way.
 
 This is usually difficult for several reasons:
 
-  * *Cross-platform dependencies*. Modern applications often depend on a combination of system libraries and binaries, language-specific packages, framework-specific modules,
-    internal components developed for another project, etc. These dependencies live in different "worlds" and require different tools - these tools typically don't work
-    well with each other, requiring awkward custom integrations.
-
-  * Conflicting dependencies. Different applications may depend on different versions of the same dependency. Packaging tools handle these situations with various degrees of ease -
-    but they all handle them in different and incompatible ways, which again forces the developer to do extra work.
+  * *Cross-platform dependencies*. Modern applications often depend on
+    a combination of system libraries and binaries, language-specific
+    packages, framework-specific modules, internal components
+    developed for another project, etc. These dependencies live in
+    different "worlds" and require different tools - these tools
+    typically don't work well with each other, requiring awkward
+    custom integrations.
+
+  * Conflicting dependencies. Different applications may depend on
+    different versions of the same dependency. Packaging tools handle
+    these situations with various degrees of ease - but they all
+    handle them in different and incompatible ways, which again forces
+    the developer to do extra work.
   
-  * Custom dependencies. A developer may need to prepare a custom version of their application's dependency. Some packaging systems can handle custom versions of a dependency,
-    others can't - and all of them handle it differently.
+  * Custom dependencies. A developer may need to prepare a custom
+    version of their application's dependency. Some packaging systems
+    can handle custom versions of a dependency, others can't - and all
+    of them handle it differently.
 
 
-Docker solves dependency hell by giving the developer a simple way to express *all* their application's dependencies in one place,
-and streamline the process of assembling them. If this makes you think of [XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
-*replace* your favorite packaging systems. It simply orchestrates their use in a simple and repeatable way. How does it do that? With layers.
+Docker solves dependency hell by giving the developer a simple way to
+express *all* their application's dependencies in one place, and
+streamline the process of assembling them. If this makes you think of
+[XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
+*replace* your favorite packaging systems. It simply orchestrates
+their use in a simple and repeatable way. How does it do that? With
+layers.
 
-Docker defines a build as running a sequence of unix commands, one after the other, in the same container. Build commands modify the contents of the container
-(usually by installing new files on the filesystem), the next command modifies it some more, etc. Since each build command inherits the result of the previous
-commands, the *order* in which the commands are executed expresses *dependencies*.
+Docker defines a build as running a sequence of Unix commands, one
+after the other, in the same container. Build commands modify the
+contents of the container (usually by installing new files on the
+filesystem), the next command modifies it some more, etc. Since each
+build command inherits the result of the previous commands, the
+*order* in which the commands are executed expresses *dependencies*.
 
-Here's a typical docker build process:
+Here's a typical Docker build process:
 
 ```bash
 from ubuntu:12.10
@@ -87,7 +136,8 @@ run curl -L https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xz
 run cd helloflask-master && pip install -r requirements.txt
 ```
 
-Note that Docker doesn't care *how* dependencies are built - as long as they can be built by running a unix command in a container.
+Note that Docker doesn't care *how* dependencies are built - as long
+as they can be built by running a Unix command in a container.
 
 
 Install instructions
@@ -103,8 +153,9 @@ curl get.docker.io | sudo sh -x
 Binary installs
 ----------------
 
-Docker supports the following binary installation methods.
-Note that some methods are community contributions and not yet officially supported.
+Docker supports the following binary installation methods.  Note that
+some methods are community contributions and not yet officially
+supported.
 
 * [Ubuntu 12.04 and 12.10 (officially supported)](http://docs.docker.io/en/latest/installation/ubuntulinux/)
 * [Arch Linux](http://docs.docker.io/en/latest/installation/archlinux/)
@@ -115,15 +166,15 @@ Note that some methods are community contributions and not yet officially suppor
 Installing from source
 ----------------------
 
-1. Make sure you have a [Go language](http://golang.org/doc/install) compiler and [git](http://git-scm.com) installed.
-
+1. Make sure you have a [Go language](http://golang.org/doc/install)
+compiler >= 1.1 and [git](http://git-scm.com) installed.
 2. Checkout the source code
 
    ```bash
    git clone http://github.com/dotcloud/docker
    ```
 
-3. Build the docker binary
+3. Build the ``docker`` binary
 
    ```bash
    cd docker
@@ -134,17 +185,20 @@ Installing from source
 Usage examples
 ==============
 
-First run the docker daemon
----------------------------
+First run the ``docker`` daemon
+-------------------------------
 
-All the examples assume your machine is running the docker daemon. To run the docker daemon in the background, simply type:
+All the examples assume your machine is running the ``docker``
+daemon. To run the ``docker`` daemon in the background, simply type:
 
 ```bash
 # On a production system you want this running in an init script
 sudo docker -d &
 ```
 
-Now you can run docker in client mode: all commands will be forwarded to the docker daemon, so the client can run from any account.
+Now you can run ``docker`` in client mode: all commands will be
+forwarded to the ``docker`` daemon, so the client can run from any
+account.
 
 ```bash
 # Now you can run docker commands from any account.
@@ -152,7 +206,7 @@ docker help
 ```
 
 
-Throwaway shell in a base ubuntu image
+Throwaway shell in a base Ubuntu image
 --------------------------------------
 
 ```bash
@@ -202,7 +256,8 @@ docker commit -m "Installed curl" $CONTAINER $USER/betterbase
 docker push $USER/betterbase
 ```
 
-A list of publicly available images is [available here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
+A list of publicly available images is [available
+here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
 
 Expose a service on a TCP port
 ------------------------------
@@ -229,32 +284,40 @@ Under the hood
 
 Under the hood, Docker is built on the following components:
 
-
-* The [cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c) and [namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part) capabilities of the Linux kernel;
-
-* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union filesystem with copy-on-write capabilities;
-
+* The
+  [cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c)
+  and
+  [namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part)
+  capabilities of the Linux kernel;
+* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union
+  filesystem with copy-on-write capabilities;
 * The [Go](http://golang.org) programming language;
-
-* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to simplify the creation of linux containers.
+* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to
+  simplify the creation of Linux containers.
 
 
 
 Contributing to Docker
 ======================
 
-Want to hack on Docker? Awesome! There are instructions to get you started on the website: http://docs.docker.io/en/latest/contributing/contributing/
+Want to hack on Docker? Awesome! There are instructions to get you
+started on the website:
+http://docs.docker.io/en/latest/contributing/contributing/
 
-They are probably not perfect, please let us know if anything feels wrong or incomplete.
+They are probably not perfect, please let us know if anything feels
+wrong or incomplete.
 
 
 Note
 ----
 
-We also keep the documentation in this repository. The website documentation is generated using sphinx using these sources.
-Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/tree/master/docs/README.md
+We also keep the documentation in this repository. The website
+documentation is generated using Sphinx using these sources.  Please
+find it under docs/sources/ and read more about it
+https://github.com/dotcloud/docker/tree/master/docs/README.md
 
-Please feel free to fix / update the documentation and send us pull requests. More tutorials are also welcome.
+Please feel free to fix / update the documentation and send us pull
+requests. More tutorials are also welcome.
 
 
 Setting up a dev environment
@@ -289,93 +352,104 @@ Run the `go install` command (above) to recompile docker.
 What is a Standard Container?
 =============================
 
-Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
-a format that is self-describing and portable, so that any compliant runtime can run it without extra dependencies, regardless of the underlying machine and the contents of the container.
+Docker defines a unit of software delivery called a Standard
+Container. The goal of a Standard Container is to encapsulate a
+software component and all its dependencies in a format that is
+self-describing and portable, so that any compliant runtime can run it
+without extra dependencies, regardless of the underlying machine and
+the contents of the container.
 
-The spec for Standard Containers is currently a work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
+The spec for Standard Containers is currently a work in progress, but
+it is very straightforward. It mostly defines 1) an image format, 2) a
+set of standard operations, and 3) an execution environment.
 
-A great analogy for this is the shipping container. Just like how Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
+A great analogy for this is the shipping container. Just like how
+Standard Containers are a fundamental unit of software delivery,
+shipping containers are a fundamental unit of physical delivery.
 
 ### 1. STANDARD OPERATIONS
 
-Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
+Just like shipping containers, Standard Containers define a set of
+STANDARD OPERATIONS. Shipping containers can be lifted, stacked,
+locked, loaded, unloaded and labelled. Similarly, Standard Containers
+can be started, stopped, copied, snapshotted, downloaded, uploaded and
+tagged.
 
 
 ### 2. CONTENT-AGNOSTIC
 
-Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
+Just like shipping containers, Standard Containers are
+CONTENT-AGNOSTIC: all standard operations have the same effect
+regardless of the contents. A shipping container will be stacked in
+exactly the same way whether it contains Vietnamese powder coffee or
+spare Maserati parts. Similarly, Standard Containers are started or
+uploaded in the same way whether they contain a postgres database, a
+php application with its dependencies and application server, or Java
+build artifacts.
 
 
 ### 3. INFRASTRUCTURE-AGNOSTIC
 
-Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
+Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be
+transported to thousands of facilities around the world, and
+manipulated by a wide variety of equipment. A shipping container can
+be packed in a factory in Ukraine, transported by truck to the nearest
+routing center, stacked onto a train, loaded into a German boat by an
+Australian-built crane, stored in a warehouse at a US facility,
+etc. Similarly, a standard container can be bundled on my laptop,
+uploaded to S3, downloaded, run and snapshotted by a build server at
+Equinix in Virginia, uploaded to 10 staging servers in a home-made
+Openstack cluster, then sent to 30 production instances across 3 EC2
+regions.
 
 
 ### 4. DESIGNED FOR AUTOMATION
 
-Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
-
-Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
-
-Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
+Because they offer the same standard operations regardless of content
+and infrastructure, Standard Containers, just like their physical
+counterparts, are extremely well-suited for automation. In fact, you
+could say automation is their secret weapon.
+
+Many things that once required time-consuming and error-prone human
+effort can now be programmed. Before shipping containers, a bag of
+powder coffee was hauled, dragged, dropped, rolled and stacked by 10
+different people in 10 different locations by the time it reached its
+destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The
+process was slow, inefficient and cost a fortune - and was entirely
+different depending on the facility and the type of goods.
+
+Similarly, before Standard Containers, by the time a software
+component ran in production, it had been individually built,
+configured, bundled, documented, patched, vendored, templated, tweaked
+and instrumented by 10 different people on 10 different
+computers. Builds failed, libraries conflicted, mirrors crashed,
+post-it notes were lost, logs were misplaced, cluster updates were
+half-broken. The process was slow, inefficient and cost a fortune -
+and was entirely different depending on the language and
+infrastructure provider.
 
 
 ### 5. INDUSTRIAL-GRADE DELIVERY
 
-There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded onto the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
-
-With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
-
-
-
-
-Standard Container Specification
---------------------------------
-
-(TODO)
-
-### Image format
-
-
-### Standard operations
-
-* Copy
-* Run
-* Stop
-* Wait
-* Commit
-* Attach standard streams
-* List filesystem changes
-* ...
-
-### Execution environment
-
-#### Root filesystem
-
-#### Environment variables
-
-#### Process arguments
-
-#### Networking
-
-#### Process namespacing
-
-#### Resource limits
-
-#### Process monitoring
-
-#### Logging
-
-#### Signals
+There are 17 million shipping containers in existence, packed with
+every physical good imaginable. Every single one of them can be loaded
+onto the same boats, by the same cranes, in the same facilities, and
+sent anywhere in the World with incredible efficiency. It is
+embarrassing to think that a 30 ton shipment of coffee can safely
+travel half-way across the World in *less time* than it takes a
+software team to deliver its code from one datacenter to another
+sitting 10 miles away.
 
-#### Pseudo-terminal allocation
+With Standard Containers we can put an end to that embarrassment, by
+making INDUSTRIAL-GRADE DELIVERY of software a reality.
 
-#### Security
 
 ### Legal
 
-Transfers of Docker shall be in accordance with applicable export controls of any country and all other applicable
-legal requirements.  Docker shall not be distributed or downloaded to or in Cuba, Iran, North Korea, Sudan or Syria
-and shall not be distributed or downloaded to any person on the Denied Persons List administered by the U.S.
+Transfers of Docker shall be in accordance with applicable export
+controls of any country and all other applicable legal requirements.
+Docker shall not be distributed or downloaded to or in Cuba, Iran,
+North Korea, Sudan or Syria and shall not be distributed or downloaded
+to any person on the Denied Persons List administered by the U.S.
 Department of Commerce.
 

+ 2 - 0
Vagrantfile

@@ -20,6 +20,8 @@ Vagrant::Config.run do |config|
     pkg_cmd = "apt-get update -qq; apt-get install -q -y python-software-properties; " \
       "add-apt-repository -y ppa:dotcloud/lxc-docker; apt-get update -qq; " \
       "apt-get install -q -y lxc-docker; "
+    # Listen on all interfaces so that the daemon is accessible from the host
+    pkg_cmd << "sed -i -E 's|    /usr/bin/docker -d|    /usr/bin/docker -d -H 0.0.0.0|' /etc/init/docker.conf;"
     # Add X.org Ubuntu backported 3.8 kernel
     pkg_cmd << "add-apt-repository -y ppa:ubuntu-x-swat/r-lts-backport; " \
       "apt-get update -qq; apt-get install -q -y linux-image-3.8.0-19-generic; "

+ 9 - 2
api.go

@@ -17,7 +17,7 @@ import (
 	"strings"
 )
 
-const APIVERSION = 1.3
+const APIVERSION = 1.4
 const DEFAULTHTTPHOST string = "127.0.0.1"
 const DEFAULTHTTPPORT int = 4243
 
@@ -271,11 +271,18 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r
 }
 
 func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if version < 1.4 {
+		return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
+	}
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
 	name := vars["name"]
-	procsStr, err := srv.ContainerTop(name)
+	ps_args := r.Form.Get("ps_args")
+	procsStr, err := srv.ContainerTop(name, ps_args)
 	if err != nil {
 		return err
 	}

+ 9 - 9
api_params.go

@@ -20,18 +20,18 @@ type APIInfo struct {
 	Debug           bool
 	Containers      int
 	Images          int
-	NFd             int  `json:",omitempty"`
-	NGoroutines     int  `json:",omitempty"`
-	MemoryLimit     bool `json:",omitempty"`
-	SwapLimit       bool `json:",omitempty"`
-	NEventsListener int  `json:",omitempty"`
+	NFd             int    `json:",omitempty"`
+	NGoroutines     int    `json:",omitempty"`
+	MemoryLimit     bool   `json:",omitempty"`
+	SwapLimit       bool   `json:",omitempty"`
+	LXCVersion      string `json:",omitempty"`
+	NEventsListener int    `json:",omitempty"`
+	KernelVersion   string `json:",omitempty"`
 }
 
 type APITop struct {
-	PID  string
-	Tty  string
-	Time string
-	Cmd  string
+	Titles    []string
+	Processes [][]string
 }
 
 type APIRmi struct {

+ 25 - 10
api_test.go

@@ -482,24 +482,33 @@ func TestGetContainersTop(t *testing.T) {
 	}
 
 	r := httptest.NewRecorder()
-	if err := getContainersTop(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil {
+	req, err := http.NewRequest("GET", "/"+container.ID+"/top?ps_args=u", bytes.NewReader([]byte{}))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := getContainersTop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
 		t.Fatal(err)
 	}
-	procs := []APITop{}
+	procs := APITop{}
 	if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil {
 		t.Fatal(err)
 	}
 
-	if len(procs) != 2 {
-		t.Fatalf("Expected 2 processes, found %d.", len(procs))
+	if len(procs.Titles) != 11 {
+		t.Fatalf("Expected 11 titles, found %d.", len(procs.Titles))
 	}
-
-	if procs[0].Cmd != "sh" && procs[0].Cmd != "busybox" {
-		t.Fatalf("Expected `busybox` or `sh`, found %s.", procs[0].Cmd)
+	if procs.Titles[0] != "USER" || procs.Titles[10] != "COMMAND" {
+		t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.Titles[0], procs.Titles[10])
 	}
 
-	if procs[1].Cmd != "sh" && procs[1].Cmd != "busybox" {
-		t.Fatalf("Expected `busybox` or `sh`, found %s.", procs[1].Cmd)
+	if len(procs.Processes) != 2 {
+		t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes))
+	}
+	if procs.Processes[0][10] != "/bin/sh" && procs.Processes[0][10] != "sleep" {
+		t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[0][10])
+	}
+	if procs.Processes[1][10] != "/bin/sh" && procs.Processes[1][10] != "sleep" {
+		t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[1][10])
 	}
 }
 
@@ -895,6 +904,12 @@ func TestPostContainersAttach(t *testing.T) {
 	stdin, stdinPipe := io.Pipe()
 	stdout, stdoutPipe := io.Pipe()
 
+	// Try to avoid the timeoout in destroy. Best effort, don't check error
+	defer func() {
+		closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
+		container.Kill()
+	}()
+
 	// Attach to it
 	c1 := make(chan struct{})
 	go func() {
@@ -934,7 +949,7 @@ func TestPostContainersAttach(t *testing.T) {
 	}
 
 	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
-	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
+	setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
 		<-c1
 	})
 

+ 10 - 5
auth/auth.go

@@ -116,14 +116,19 @@ func SaveConfig(configFile *ConfigFile) error {
 		os.Remove(confFile)
 		return nil
 	}
+
+	configs := make(map[string]AuthConfig, len(configFile.Configs))
 	for k, authConfig := range configFile.Configs {
-		authConfig.Auth = encodeAuth(&authConfig)
-		authConfig.Username = ""
-		authConfig.Password = ""
-		configFile.Configs[k] = authConfig
+		authCopy := authConfig
+
+		authCopy.Auth = encodeAuth(&authCopy)
+		authCopy.Username = ""
+		authCopy.Password = ""
+
+		configs[k] = authCopy
 	}
 
-	b, err := json.Marshal(configFile.Configs)
+	b, err := json.Marshal(configs)
 	if err != nil {
 		return err
 	}

+ 38 - 1
auth/auth_test.go

@@ -3,6 +3,7 @@ package auth
 import (
 	"crypto/rand"
 	"encoding/hex"
+	"io/ioutil"
 	"os"
 	"strings"
 	"testing"
@@ -51,7 +52,7 @@ func TestCreateAccount(t *testing.T) {
 	}
 	token := hex.EncodeToString(tokenBuffer)[:12]
 	username := "ut" + token
-	authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+"+token+"@example.com"}
+	authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
 	status, err := Login(authConfig)
 	if err != nil {
 		t.Fatal(err)
@@ -73,3 +74,39 @@ func TestCreateAccount(t *testing.T) {
 		t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
 	}
 }
+
+func TestSameAuthDataPostSave(t *testing.T) {
+	root, err := ioutil.TempDir("", "docker-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	configFile := &ConfigFile{
+		rootPath: root,
+		Configs:  make(map[string]AuthConfig, 1),
+	}
+
+	configFile.Configs["testIndex"] = AuthConfig{
+		Username: "docker-user",
+		Password: "docker-pass",
+		Email:    "docker@docker.io",
+	}
+
+	err = SaveConfig(configFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	authConfig := configFile.Configs["testIndex"]
+	if authConfig.Username != "docker-user" {
+		t.Fail()
+	}
+	if authConfig.Password != "docker-pass" {
+		t.Fail()
+	}
+	if authConfig.Email != "docker@docker.io" {
+		t.Fail()
+	}
+	if authConfig.Auth != "" {
+		t.Fail()
+	}
+}

+ 61 - 10
buildfile.go

@@ -11,6 +11,7 @@ import (
 	"os"
 	"path"
 	"reflect"
+	"regexp"
 	"strings"
 )
 
@@ -67,6 +68,9 @@ func (b *buildFile) CmdFrom(name string) error {
 	}
 	b.image = image.ID
 	b.config = &Config{}
+	if b.config.Env == nil || len(b.config.Env) == 0 {
+		b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
+	}
 	return nil
 }
 
@@ -112,6 +116,40 @@ func (b *buildFile) CmdRun(args string) error {
 	return nil
 }
 
+func (b *buildFile) FindEnvKey(key string) int {
+	for k, envVar := range b.config.Env {
+		envParts := strings.SplitN(envVar, "=", 2)
+		if key == envParts[0] {
+			return k
+		}
+	}
+	return -1
+}
+
+func (b *buildFile) ReplaceEnvMatches(value string) (string, error) {
+	exp, err := regexp.Compile("(\\\\\\\\+|[^\\\\]|\\b|\\A)\\$({?)([[:alnum:]_]+)(}?)")
+	if err != nil {
+		return value, err
+	}
+	matches := exp.FindAllString(value, -1)
+	for _, match := range matches {
+		match = match[strings.Index(match, "$"):]
+		matchKey := strings.Trim(match, "${}")
+
+		for _, envVar := range b.config.Env {
+			envParts := strings.SplitN(envVar, "=", 2)
+			envKey := envParts[0]
+			envValue := envParts[1]
+
+			if envKey == matchKey {
+				value = strings.Replace(value, match, envValue, -1)
+				break
+			}
+		}
+	}
+	return value, nil
+}
+
 func (b *buildFile) CmdEnv(args string) error {
 	tmp := strings.SplitN(args, " ", 2)
 	if len(tmp) != 2 {
@@ -120,14 +158,19 @@ func (b *buildFile) CmdEnv(args string) error {
 	key := strings.Trim(tmp[0], " \t")
 	value := strings.Trim(tmp[1], " \t")
 
-	for i, elem := range b.config.Env {
-		if strings.HasPrefix(elem, key+"=") {
-			b.config.Env[i] = key + "=" + value
-			return nil
-		}
+	envKey := b.FindEnvKey(key)
+	replacedValue, err := b.ReplaceEnvMatches(value)
+	if err != nil {
+		return err
 	}
-	b.config.Env = append(b.config.Env, key+"="+value)
-	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
+	replacedVar := fmt.Sprintf("%s=%s", key, replacedValue)
+
+	if envKey >= 0 {
+		b.config.Env[envKey] = replacedVar
+		return nil
+	}
+	b.config.Env = append(b.config.Env, replacedVar)
+	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s", replacedVar))
 }
 
 func (b *buildFile) CmdCmd(args string) error {
@@ -242,7 +285,7 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
 	} else if err := UntarPath(origPath, destPath); err != nil {
 		utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
 		// If that fails, just copy it as a regular file
-		if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
+		if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
 			return err
 		}
 		if err := CopyWithTar(origPath, destPath); err != nil {
@@ -260,8 +303,16 @@ func (b *buildFile) CmdAdd(args string) error {
 	if len(tmp) != 2 {
 		return fmt.Errorf("Invalid ADD format")
 	}
-	orig := strings.Trim(tmp[0], " \t")
-	dest := strings.Trim(tmp[1], " \t")
+
+	orig, err := b.ReplaceEnvMatches(strings.Trim(tmp[0], " \t"))
+	if err != nil {
+		return err
+	}
+
+	dest, err := b.ReplaceEnvMatches(strings.Trim(tmp[1], " \t"))
+	if err != nil {
+		return err
+	}
 
 	cmd := b.config.Cmd
 	b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}

+ 40 - 2
buildfile_test.go

@@ -129,6 +129,38 @@ CMD Hello world
 		nil,
 		nil,
 	},
+
+	{
+		`
+from {IMAGE}
+env    FOO /foo/baz
+env    BAR /bar
+env    BAZ $BAR
+env    FOOPATH $PATH:$FOO
+run    [ "$BAR" = "$BAZ" ]
+run    [ "$FOOPATH" = "$PATH:/foo/baz" ]
+`,
+		nil,
+		nil,
+	},
+
+	{
+		`
+from {IMAGE}
+env    FOO /bar
+env    TEST testdir
+env    BAZ /foobar
+add    testfile $BAZ/
+add    $TEST $FOO
+run    [ "$(cat /foobar/testfile)" = "test1" ]
+run    [ "$(cat /bar/withfile)" = "test2" ]
+`,
+		[][2]string{
+			{"testfile", "test1"},
+			{"testdir/withfile", "test2"},
+		},
+		nil,
+	},
 }
 
 // FIXME: test building with 2 successive overlapping ADD commands
@@ -242,8 +274,14 @@ func TestBuildEnv(t *testing.T) {
         env port 4243
         `,
 		nil, nil}, t)
-
-	if img.Config.Env[0] != "port=4243" {
+	hasEnv := false
+	for _, envVar := range img.Config.Env {
+		if envVar == "port=4243" {
+			hasEnv = true
+			break
+		}
+	}
+	if !hasEnv {
 		t.Fail()
 	}
 }

+ 32 - 16
commands.go

@@ -314,13 +314,21 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 		email    string
 	)
 
+	var promptDefault = func(prompt string, configDefault string) {
+		if configDefault == "" {
+			fmt.Fprintf(cli.out, "%s: ", prompt)
+		} else {
+			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
+		}
+	}
+
 	authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
 	if !ok {
 		authconfig = auth.AuthConfig{}
 	}
 
 	if *flUsername == "" {
-		fmt.Fprintf(cli.out, "Username (%s): ", authconfig.Username)
+		promptDefault("Username", authconfig.Username)
 		username = readAndEchoString(cli.in, cli.out)
 		if username == "" {
 			username = authconfig.Username
@@ -340,7 +348,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 		}
 
 		if *flEmail == "" {
-			fmt.Fprintf(cli.out, "Email (%s): ", authconfig.Email)
+			promptDefault("Email", authconfig.Email)
 			email = readAndEchoString(cli.in, cli.out)
 			if email == "" {
 				email = authconfig.Email
@@ -471,7 +479,9 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 		fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
 		fmt.Fprintf(cli.out, "Fds: %d\n", out.NFd)
 		fmt.Fprintf(cli.out, "Goroutines: %d\n", out.NGoroutines)
+		fmt.Fprintf(cli.out, "LXC Version: %s\n", out.LXCVersion)
 		fmt.Fprintf(cli.out, "EventsListeners: %d\n", out.NEventsListener)
+		fmt.Fprintf(cli.out, "Kernel Version: %s\n", out.KernelVersion)
 	}
 	if !out.MemoryLimit {
 		fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
@@ -594,23 +604,28 @@ func (cli *DockerCli) CmdTop(args ...string) error {
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	if cmd.NArg() != 1 {
+	if cmd.NArg() == 0 {
 		cmd.Usage()
 		return nil
 	}
-	body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top", nil)
+	val := url.Values{}
+	if cmd.NArg() > 1 {
+		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
+	}
+
+	body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil)
 	if err != nil {
 		return err
 	}
-	var procs []APITop
+	procs := APITop{}
 	err = json.Unmarshal(body, &procs)
 	if err != nil {
 		return err
 	}
 	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
-	fmt.Fprintln(w, "PID\tTTY\tTIME\tCMD")
-	for _, proc := range procs {
-		fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", proc.PID, proc.Tty, proc.Time, proc.Cmd)
+	fmt.Fprintln(w, strings.Join(procs.Titles, "\t"))
+	for _, proc := range procs.Processes {
+		fmt.Fprintln(w, strings.Join(proc, "\t"))
 	}
 	w.Flush()
 	return nil
@@ -765,7 +780,7 @@ func (cli *DockerCli) CmdKill(args ...string) error {
 }
 
 func (cli *DockerCli) CmdImport(args ...string) error {
-	cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
+	cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
@@ -1407,7 +1422,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
 		if config.Tty {
 			if err := cli.monitorTtySize(runResult.ID); err != nil {
-				return err
+				utils.Debugf("Error monitoring TTY size: %s\n", err)
 			}
 		}
 
@@ -1569,6 +1584,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
 
 	receiveStdout := utils.Go(func() error {
 		_, err := io.Copy(out, br)
+		utils.Debugf("[hijack] End of stdout")
 		return err
 	})
 
@@ -1583,6 +1599,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
 	sendStdin := utils.Go(func() error {
 		if in != nil {
 			io.Copy(rwc, in)
+			utils.Debugf("[hijack] End of stdin")
 		}
 		if tcpc, ok := rwc.(*net.TCPConn); ok {
 			if err := tcpc.CloseWrite(); err != nil {
@@ -1645,13 +1662,12 @@ func (cli *DockerCli) monitorTtySize(id string) error {
 	}
 	cli.resizeTty(id)
 
-	c := make(chan os.Signal, 1)
-	signal.Notify(c, syscall.SIGWINCH)
+	sigchan := make(chan os.Signal, 1)
+	signal.Notify(sigchan, syscall.SIGWINCH)
 	go func() {
-		for sig := range c {
-			if sig == syscall.SIGWINCH {
-				cli.resizeTty(id)
-			}
+		for {
+			<-sigchan
+			cli.resizeTty(id)
 		}
 	}()
 	return nil

+ 222 - 1
commands_test.go

@@ -73,7 +73,7 @@ func TestRunHostname(t *testing.T) {
 			t.Fatal(err)
 		}
 	}()
-	utils.Debugf("--")
+
 	setTimeout(t, "Reading command output time out", 2*time.Second, func() {
 		cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
 		if err != nil {
@@ -90,6 +90,157 @@ func TestRunHostname(t *testing.T) {
 
 }
 
+func TestRunExit(t *testing.T) {
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	c1 := make(chan struct{})
+	go func() {
+		cli.CmdRun("-i", unitTestImageID, "/bin/cat")
+		close(c1)
+	}()
+
+	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	container := globalRuntime.List()[0]
+
+	// Closing /bin/cat stdin, expect it to exit
+	if err := stdin.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// as the process exited, CmdRun must finish and unblock. Wait for it
+	setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
+		<-c1
+
+		go func() {
+			cli.CmdWait(container.ID)
+		}()
+
+		if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// Make sure that the client has been disconnected
+	setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
+		// Expecting pipe i/o error, just check that read does not block
+		stdin.Read([]byte{})
+	})
+
+	// Cleanup pipes
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// Expected behaviour: the process dies when the client disconnects
+func TestRunDisconnect(t *testing.T) {
+
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	c1 := make(chan struct{})
+	go func() {
+		// We're simulating a disconnect so the return value doesn't matter. What matters is the
+		// fact that CmdRun returns.
+		cli.CmdRun("-i", unitTestImageID, "/bin/cat")
+		close(c1)
+	}()
+
+	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// Close pipes (simulate disconnect)
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
+		t.Fatal(err)
+	}
+
+	// as the pipes are close, we expect the process to die,
+	// therefore CmdRun to unblock. Wait for CmdRun
+	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
+		<-c1
+	})
+
+	// Client disconnect after run -i should cause stdin to be closed, which should
+	// cause /bin/cat to exit.
+	setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
+		container := globalRuntime.List()[0]
+		container.Wait()
+		if container.State.Running {
+			t.Fatalf("/bin/cat is still running after closing stdin")
+		}
+	})
+}
+
+// Expected behaviour: the process dies when the client disconnects
+func TestRunDisconnectTty(t *testing.T) {
+
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	c1 := make(chan struct{})
+	go func() {
+		// We're simulating a disconnect so the return value doesn't matter. What matters is the
+		// fact that CmdRun returns.
+		if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil {
+			utils.Debugf("Error CmdRun: %s\n", err)
+		}
+
+		close(c1)
+	}()
+
+	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
+		for {
+			// Client disconnect after run -i should keep stdin out in TTY mode
+			l := globalRuntime.List()
+			if len(l) == 1 && l[0].State.Running {
+				break
+			}
+			time.Sleep(10 * time.Millisecond)
+		}
+	})
+
+	// Client disconnect after run -i should keep stdin out in TTY mode
+	container := globalRuntime.List()[0]
+
+	setTimeout(t, "Read/Write assertion timed out", 2000*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// Close pipes (simulate disconnect)
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
+		t.Fatal(err)
+	}
+
+	// In tty mode, we expect the process to stay alive even after client's stdin closes.
+	// Do not wait for run to finish
+
+	// Give some time to monitor to do his thing
+	container.WaitTimeout(500 * time.Millisecond)
+	if !container.State.Running {
+		t.Fatalf("/bin/cat should  still be running after closing stdin (tty mode)")
+	}
+}
+
 // TestAttachStdin checks attaching to stdin without stdout and stderr.
 // 'docker run -i -a stdin' should sends the client's stdin to the command,
 // then detach from it and print the container id.
@@ -157,3 +308,73 @@ func TestRunAttachStdin(t *testing.T) {
 		}
 	}
 }
+
+// Expected behaviour, the process stays alive when the client disconnects
+func TestAttachDisconnect(t *testing.T) {
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	go func() {
+		// Start a process in daemon mode
+		if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
+			utils.Debugf("Error CmdRun: %s\n", err)
+		}
+	}()
+
+	setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
+		if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
+		for {
+			l := globalRuntime.List()
+			if len(l) == 1 && l[0].State.Running {
+				break
+			}
+			time.Sleep(10 * time.Millisecond)
+		}
+	})
+
+	container := globalRuntime.List()[0]
+
+	// Attach to it
+	c1 := make(chan struct{})
+	go func() {
+		// We're simulating a disconnect so the return value doesn't matter. What matters is the
+		// fact that CmdAttach returns.
+		cli.CmdAttach(container.ID)
+		close(c1)
+	}()
+
+	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+	// Close pipes (client disconnects)
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
+		t.Fatal(err)
+	}
+
+	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
+	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
+		<-c1
+	})
+
+	// We closed stdin, expect /bin/cat to still be running
+	// Wait a little bit to make sure container.monitor() did his thing
+	err := container.WaitTimeout(500 * time.Millisecond)
+	if err == nil || !container.State.Running {
+		t.Fatalf("/bin/cat is not running after closing stdin")
+	}
+
+	// Try to avoid the timeoout in destroy. Best effort, don't check error
+	cStdin, _ := container.StdinPipe()
+	cStdin.Close()
+	container.Wait()
+}

+ 9 - 8
container.go

@@ -52,7 +52,7 @@ type Container struct {
 
 	waitLock chan struct{}
 	Volumes  map[string]string
-	// Store rw/ro in a separate structure to preserve reserve-compatibility on-disk.
+	// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
 	// Easier than migrating older container configs :)
 	VolumesRW map[string]bool
 }
@@ -100,7 +100,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 
 	flHostname := cmd.String("h", "", "Container host name")
 	flUser := cmd.String("u", "", "Username or UID")
-	flDetach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
+	flDetach := cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
 	flAttach := NewAttachOpts()
 	cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
 	flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
@@ -379,14 +379,15 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
 				utils.Debugf("[start] attach stdin\n")
 				defer utils.Debugf("[end] attach stdin\n")
 				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
-				if cStdout != nil {
-					defer cStdout.Close()
-				}
-				if cStderr != nil {
-					defer cStderr.Close()
-				}
 				if container.Config.StdinOnce && !container.Config.Tty {
 					defer cStdin.Close()
+				} else {
+					if cStdout != nil {
+						defer cStdout.Close()
+					}
+					if cStderr != nil {
+						defer cStderr.Close()
+					}
 				}
 				if container.Config.Tty {
 					_, err = utils.CopyEscapable(cStdin, stdin)

+ 16 - 3
docs/sources/api/docker_remote_api.rst

@@ -26,23 +26,35 @@ Docker Remote API
 2. Versions
 ===========
 
-The current verson of the API is 1.3 
+The current verson of the API is 1.4
 
 Calling /images/<name>/insert is the same as calling
-/v1.3/images/<name>/insert 
+/v1.4/images/<name>/insert 
 
 You can still call an old version of the api using
 /v1.0/images/<name>/insert
 
+:doc:`docker_remote_api_v1.4`
+*****************************
+
+What's new
+----------
+
+.. http:get:: /containers/(id)/top
+
+   **New!** You can now use ps args with docker top, like `docker top <container_id> aux`
+
 :doc:`docker_remote_api_v1.3`
 *****************************
 
+docker v0.5.0 51f6c4a_
+
 What's new
 ----------
 
 .. http:get:: /containers/(id)/top
 
-   **New!** List the processes running inside a container.
+   List the processes running inside a container.
 
 .. http:get:: /events:
 
@@ -138,6 +150,7 @@ Initial version
 .. _a8ae398: https://github.com/dotcloud/docker/commit/a8ae398bf52e97148ee7bd0d5868de2e15bd297f
 .. _8d73740: https://github.com/dotcloud/docker/commit/8d73740343778651c09160cde9661f5f387b36f4
 .. _2e7649b: https://github.com/dotcloud/docker/commit/2e7649beda7c820793bd46766cbc2cfeace7b168
+.. _51f6c4a: https://github.com/dotcloud/docker/commit/51f6c4a7372450d164c61e0054daf0223ddbd909
 
 ==================================
 Docker Remote API Client Libraries

+ 4 - 1
docs/sources/api/docker_remote_api_v1.3.rst

@@ -989,7 +989,10 @@ Display system-wide information
 		"NFd": 11,
 		"NGoroutines":21,
 		"MemoryLimit":true,
-		"SwapLimit":false
+		"SwapLimit":false,
+		"EventsListeners":"0",
+		"LXCVersion":"0.7.5",
+		"KernelVersion":"3.8.0-19-generic"
 	   }
 
         :statuscode 200: no error

+ 1093 - 0
docs/sources/api/docker_remote_api_v1.4.rst

@@ -0,0 +1,1093 @@
+:title: Remote API v1.4
+:description: API Documentation for Docker
+:keywords: API, Docker, rcli, REST, documentation
+
+======================
+Docker Remote API v1.4
+======================
+
+.. contents:: Table of Contents
+
+1. Brief introduction
+=====================
+
+- The Remote API is replacing rcli
+- Default port in the docker deamon is 4243 
+- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
+
+2. Endpoints
+============
+
+2.1 Containers
+--------------
+
+List containers
+***************
+
+.. http:get:: /containers/json
+
+	List containers
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+	   
+	   [
+		{
+			"Id": "8dfafdbc3a40",
+			"Image": "base:latest",
+			"Command": "echo 1",
+			"Created": 1367854155,
+			"Status": "Exit 0",
+			"Ports":"",
+			"SizeRw":12288,
+			"SizeRootFs":0
+		},
+		{
+			"Id": "9cd87474be90",
+			"Image": "base:latest",
+			"Command": "echo 222222",
+			"Created": 1367854155,
+			"Status": "Exit 0",
+			"Ports":"",
+			"SizeRw":12288,
+			"SizeRootFs":0
+		},
+		{
+			"Id": "3176a2479c92",
+			"Image": "base:latest",
+			"Command": "echo 3333333333333333",
+			"Created": 1367854154,
+			"Status": "Exit 0",
+			"Ports":"",
+			"SizeRw":12288,
+			"SizeRootFs":0
+		},
+		{
+			"Id": "4cb07b47f9fb",
+			"Image": "base:latest",
+			"Command": "echo 444444444444444444444444444444444",
+			"Created": 1367854152,
+			"Status": "Exit 0",
+			"Ports":"",
+			"SizeRw":12288,
+			"SizeRootFs":0
+		}
+	   ]
+ 
+	:query all: 1/True/true or 0/False/false, Show all containers. Only running containers are shown by default
+	:query limit: Show ``limit`` last created containers, include non-running ones.
+	:query since: Show only containers created since Id, include non-running ones.
+	:query before: Show only containers created before Id, include non-running ones.
+	:query size: 1/True/true or 0/False/false, Show the containers sizes
+	:statuscode 200: no error
+	:statuscode 400: bad parameter
+	:statuscode 500: server error
+
+
+Create a container
+******************
+
+.. http:post:: /containers/create
+
+	Create a container
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/create HTTP/1.1
+	   Content-Type: application/json
+
+	   {
+		"Hostname":"",
+		"User":"",
+		"Memory":0,
+		"MemorySwap":0,
+		"AttachStdin":false,
+		"AttachStdout":true,
+		"AttachStderr":true,
+		"PortSpecs":null,
+		"Tty":false,
+		"OpenStdin":false,
+		"StdinOnce":false,
+		"Env":null,
+		"Cmd":[
+			"date"
+		],
+		"Dns":null,
+		"Image":"base",
+		"Volumes":{},
+		"VolumesFrom":""
+	   }
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 201 OK
+	   Content-Type: application/json
+
+	   {
+		"Id":"e90e34656806"
+		"Warnings":[]
+	   }
+	
+	:jsonparam config: the container's configuration
+	:statuscode 201: no error
+	:statuscode 404: no such container
+	:statuscode 406: impossible to attach (container not running)
+	:statuscode 500: server error
+
+
+Inspect a container
+*******************
+
+.. http:get:: /containers/(id)/json
+
+	Return low-level information on the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /containers/4fa6e0f0c678/json HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {
+			"Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
+			"Created": "2013-05-07T14:51:42.041847+02:00",
+			"Path": "date",
+			"Args": [],
+			"Config": {
+				"Hostname": "4fa6e0f0c678",
+				"User": "",
+				"Memory": 0,
+				"MemorySwap": 0,
+				"AttachStdin": false,
+				"AttachStdout": true,
+				"AttachStderr": true,
+				"PortSpecs": null,
+				"Tty": false,
+				"OpenStdin": false,
+				"StdinOnce": false,
+				"Env": null,
+				"Cmd": [
+					"date"
+				],
+				"Dns": null,
+				"Image": "base",
+				"Volumes": {},
+				"VolumesFrom": ""
+			},
+			"State": {
+				"Running": false,
+				"Pid": 0,
+				"ExitCode": 0,
+				"StartedAt": "2013-05-07T14:51:42.087658+02:01360",
+				"Ghost": false
+			},
+			"Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
+			"NetworkSettings": {
+				"IpAddress": "",
+				"IpPrefixLen": 0,
+				"Gateway": "",
+				"Bridge": "",
+				"PortMapping": null
+			},
+			"SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker",
+			"ResolvConfPath": "/etc/resolv.conf",
+			"Volumes": {}
+	   }
+
+	:statuscode 200: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+List processes running inside a container
+*****************************************
+
+.. http:get:: /containers/(id)/top
+
+	List processes running inside the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /containers/4fa6e0f0c678/top HTTP/1.1
+
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {
+		"Titles":[
+			"USER",
+			"PID",
+			"%CPU",
+			"%MEM",
+			"VSZ",
+			"RSS",
+			"TTY",
+			"STAT",
+			"START",
+			"TIME",
+			"COMMAND"
+			],
+		"Processes":[
+			["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"],
+			["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"]
+		]
+	   }
+
+	:query ps_args: ps arguments to use (eg. aux)
+	:statuscode 200: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Inspect changes on a container's filesystem
+*******************************************
+
+.. http:get:: /containers/(id)/changes
+
+	Inspect changes on container ``id`` 's filesystem
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /containers/4fa6e0f0c678/changes HTTP/1.1
+
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+	   
+	   [
+		{
+			"Path":"/dev",
+			"Kind":0
+		},
+		{
+			"Path":"/dev/kmsg",
+			"Kind":1
+		},
+		{
+			"Path":"/test",
+			"Kind":1
+		}
+	   ]
+
+	:statuscode 200: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Export a container
+******************
+
+.. http:get:: /containers/(id)/export
+
+	Export the contents of container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /containers/4fa6e0f0c678/export HTTP/1.1
+
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/octet-stream
+	   
+	   {{ STREAM }}
+
+	:statuscode 200: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Start a container
+*****************
+
+.. http:post:: /containers/(id)/start
+
+        Start the container ``id``
+
+        **Example request**:
+
+        .. sourcecode:: http
+
+           POST /containers/(id)/start HTTP/1.1
+           Content-Type: application/json
+
+           {
+                "Binds":["/tmp:/tmp"]
+           }
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 204 No Content
+           Content-Type: text/plain
+
+        :jsonparam hostConfig: the container's host configuration (optional)
+        :statuscode 200: no error
+        :statuscode 404: no such container
+        :statuscode 500: server error
+
+
+Stop a contaier
+***************
+
+.. http:post:: /containers/(id)/stop
+
+	Stop the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/e90e34656806/stop?t=5 HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 204 OK
+	   	
+	:query t: number of seconds to wait before killing the container
+	:statuscode 204: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Restart a container
+*******************
+
+.. http:post:: /containers/(id)/restart
+
+	Restart the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/e90e34656806/restart?t=5 HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 204 OK
+	   	
+	:query t: number of seconds to wait before killing the container
+	:statuscode 204: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Kill a container
+****************
+
+.. http:post:: /containers/(id)/kill
+
+	Kill the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/e90e34656806/kill HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 204 OK
+	   	
+	:statuscode 204: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Attach to a container
+*********************
+
+.. http:post:: /containers/(id)/attach
+
+	Attach to the container ``id``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/vnd.docker.raw-stream
+
+	   {{ STREAM }}
+	   	
+	:query logs: 1/True/true or 0/False/false, return logs. Default false
+	:query stream: 1/True/true or 0/False/false, return stream. Default false
+	:query stdin: 1/True/true or 0/False/false, if stream=true, attach to stdin. Default false
+	:query stdout: 1/True/true or 0/False/false, if logs=true, return stdout log, if stream=true, attach to stdout. Default false
+	:query stderr: 1/True/true or 0/False/false, if logs=true, return stderr log, if stream=true, attach to stderr. Default false
+	:statuscode 200: no error
+	:statuscode 400: bad parameter
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Wait a container
+****************
+
+.. http:post:: /containers/(id)/wait
+
+	Block until container ``id`` stops, then returns the exit code
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   POST /containers/16253994b7c4/wait HTTP/1.1
+	   
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {"StatusCode":0}
+	   	
+	:statuscode 200: no error
+	:statuscode 404: no such container
+	:statuscode 500: server error
+
+
+Remove a container
+*******************
+
+.. http:delete:: /containers/(id)
+
+	Remove the container ``id`` from the filesystem
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+	   HTTP/1.1 204 OK
+
+	:query v: 1/True/true or 0/False/false, Remove the volumes associated to the container. Default false
+        :statuscode 204: no error
+	:statuscode 400: bad parameter
+        :statuscode 404: no such container
+        :statuscode 500: server error
+
+
+2.2 Images
+----------
+
+List Images
+***********
+
+.. http:get:: /images/(format)
+
+	List images ``format`` could be json or viz (json default)
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /images/json?all=0 HTTP/1.1
+
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+	   
+	   [
+		{
+			"Repository":"base",
+			"Tag":"ubuntu-12.10",
+			"Id":"b750fe79269d",
+			"Created":1364102658,
+			"Size":24653,
+			"VirtualSize":180116135
+		},
+		{
+			"Repository":"base",
+			"Tag":"ubuntu-quantal",
+			"Id":"b750fe79269d",
+			"Created":1364102658,
+			"Size":24653,
+			"VirtualSize":180116135
+		}
+	   ]
+
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /images/viz HTTP/1.1
+
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: text/plain
+
+	   digraph docker {
+	   "d82cbacda43a" -> "074be284591f"
+	   "1496068ca813" -> "08306dc45919"
+	   "08306dc45919" -> "0e7893146ac2"
+	   "b750fe79269d" -> "1496068ca813"
+	   base -> "27cf78414709" [style=invis]
+	   "f71189fff3de" -> "9a33b36209ed"
+	   "27cf78414709" -> "b750fe79269d"
+	   "0e7893146ac2" -> "d6434d954665"
+	   "d6434d954665" -> "d82cbacda43a"
+	   base -> "e9aa60c60128" [style=invis]
+	   "074be284591f" -> "f71189fff3de"
+	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   base [style=invisible]
+	   }
+ 
+	:query all: 1/True/true or 0/False/false, Show all containers. Only running containers are shown by default
+	:statuscode 200: no error
+	:statuscode 400: bad parameter
+	:statuscode 500: server error
+
+
+Create an image
+***************
+
+.. http:post:: /images/create
+
+	Create an image, either by pull it from the registry or by importing it
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           POST /images/create?fromImage=base HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {"status":"Pulling..."}
+	   {"status":"Pulling", "progress":"1/? (n/a)"}
+	   {"error":"Invalid..."}
+	   ...
+
+        :query fromImage: name of the image to pull
+	:query fromSrc: source to import, - means stdin
+        :query repo: repository
+	:query tag: tag
+	:query registry: the registry to pull from
+        :statuscode 200: no error
+        :statuscode 500: server error
+
+
+Insert a file in a image
+************************
+
+.. http:post:: /images/(name)/insert
+
+	Insert a file from ``url`` in the image ``name`` at ``path``
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           POST /images/test/insert?path=/usr&url=myurl HTTP/1.1
+
+	**Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {"status":"Inserting..."}
+	   {"status":"Inserting", "progress":"1/? (n/a)"}
+	   {"error":"Invalid..."}
+	   ...
+
+	:statuscode 200: no error
+        :statuscode 500: server error
+
+
+Inspect an image
+****************
+
+.. http:get:: /images/(name)/json
+
+	Return low-level information on the image ``name``
+
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   GET /images/base/json HTTP/1.1
+
+	**Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {
+		"id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
+		"parent":"27cf784147099545",
+		"created":"2013-03-23T22:24:18.818426-07:00",
+		"container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0",
+		"container_config":
+			{
+				"Hostname":"",
+				"User":"",
+				"Memory":0,
+				"MemorySwap":0,
+				"AttachStdin":false,
+				"AttachStdout":false,
+				"AttachStderr":false,
+				"PortSpecs":null,
+				"Tty":true,
+				"OpenStdin":true,
+				"StdinOnce":false,
+				"Env":null,
+				"Cmd": ["/bin/bash"]
+				,"Dns":null,
+				"Image":"base",
+				"Volumes":null,
+				"VolumesFrom":""
+			},
+		"Size": 6824592
+	   }
+
+	:statuscode 200: no error
+	:statuscode 404: no such image
+        :statuscode 500: server error
+
+
+Get the history of an image
+***************************
+
+.. http:get:: /images/(name)/history
+
+        Return the history of the image ``name``
+
+        **Example request**:
+
+        .. sourcecode:: http
+
+           GET /images/base/history HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   [
+		{
+			"Id":"b750fe79269d",
+			"Created":1364102658,
+			"CreatedBy":"/bin/bash"
+		},
+		{
+			"Id":"27cf78414709",
+			"Created":1364068391,
+			"CreatedBy":""
+		}
+	   ]
+
+        :statuscode 200: no error
+        :statuscode 404: no such image
+        :statuscode 500: server error
+
+
+Push an image on the registry
+*****************************
+
+.. http:post:: /images/(name)/push
+
+	Push the image ``name`` on the registry
+
+	 **Example request**:
+
+	 .. sourcecode:: http
+
+	    POST /images/test/push HTTP/1.1
+	    {{ authConfig }}
+
+	 **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {"status":"Pushing..."}
+	   {"status":"Pushing", "progress":"1/? (n/a)"}
+	   {"error":"Invalid..."}
+	   ...
+
+	:query registry: the registry you wan to push, optional
+	:statuscode 200: no error
+        :statuscode 404: no such image
+        :statuscode 500: server error
+
+
+Tag an image into a repository
+******************************
+
+.. http:post:: /images/(name)/tag
+
+	Tag the image ``name`` into a repository
+
+        **Example request**:
+
+        .. sourcecode:: http
+			
+	   POST /images/test/tag?repo=myrepo&force=0 HTTP/1.1
+
+	**Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+
+	:query repo: The repository to tag in
+	:query force: 1/True/true or 0/False/false, default false
+	:statuscode 200: no error
+	:statuscode 400: bad parameter
+	:statuscode 404: no such image
+	:statuscode 409: conflict
+        :statuscode 500: server error
+
+
+Remove an image
+***************
+
+.. http:delete:: /images/(name)
+
+	Remove the image ``name`` from the filesystem 
+	
+	**Example request**:
+
+	.. sourcecode:: http
+
+	   DELETE /images/test HTTP/1.1
+
+	**Example response**:
+
+        .. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-type: application/json
+
+	   [
+	    {"Untagged":"3e2f21a89f"},
+	    {"Deleted":"3e2f21a89f"},
+	    {"Deleted":"53b4f83ac9"}
+	   ]
+
+	:statuscode 200: no error
+        :statuscode 404: no such image
+	:statuscode 409: conflict
+        :statuscode 500: server error
+
+
+Search images
+*************
+
+.. http:get:: /images/search
+
+	Search for an image in the docker index
+	
+	**Example request**:
+
+        .. sourcecode:: http
+
+           GET /images/search?term=sshd HTTP/1.1
+
+	**Example response**:
+
+	.. sourcecode:: http
+
+	   HTTP/1.1 200 OK
+	   Content-Type: application/json
+	   
+	   [
+		{
+			"Name":"cespare/sshd",
+			"Description":""
+		},
+		{
+			"Name":"johnfuller/sshd",
+			"Description":""
+		},
+		{
+			"Name":"dhrp/mongodb-sshd",
+			"Description":""
+		}
+	   ]
+
+	   :query term: term to search
+	   :statuscode 200: no error
+	   :statuscode 500: server error
+
+
+2.3 Misc
+--------
+
+Build an image from Dockerfile via stdin
+****************************************
+
+.. http:post:: /build
+
+	Build an image from Dockerfile via stdin
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           POST /build HTTP/1.1
+	   
+	   {{ STREAM }}
+
+	**Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   
+	   {{ STREAM }}
+
+
+        The stream must be a tar archive compressed with one of the following algorithms:
+        identity (no compression), gzip, bzip2, xz. The archive must include a file called
+        `Dockerfile` at its root. It may include any number of other files, which will be
+        accessible in the build context (See the ADD build command).
+
+        The Content-type header should be set to "application/tar".
+
+	:query t: tag to be applied to the resulting image in case of success
+	:query q: suppress verbose build output
+	:statuscode 200: no error
+        :statuscode 500: server error
+
+
+Check auth configuration
+************************
+
+.. http:post:: /auth
+
+        Get the default username and email
+
+        **Example request**:
+
+        .. sourcecode:: http
+
+           POST /auth HTTP/1.1
+	   Content-Type: application/json
+
+	   {
+		"username":"hannibal",
+		"password:"xxxx",
+		"email":"hannibal@a-team.com"
+	   }
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+
+        :statuscode 200: no error
+        :statuscode 204: no error
+        :statuscode 500: server error
+
+
+Display system-wide information
+*******************************
+
+.. http:get:: /info
+
+	Display system-wide information
+	
+	**Example request**:
+
+        .. sourcecode:: http
+
+           GET /info HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {
+		"Containers":11,
+		"Images":16,
+		"Debug":false,
+		"NFd": 11,
+		"NGoroutines":21,
+		"MemoryLimit":true,
+		"SwapLimit":false
+	   }
+
+        :statuscode 200: no error
+        :statuscode 500: server error
+
+
+Show the docker version information
+***********************************
+
+.. http:get:: /version
+
+	Show the docker version information
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           GET /version HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 200 OK
+	   Content-Type: application/json
+
+	   {
+		"Version":"0.2.2",
+		"GitCommit":"5a2a5cc+CHANGES",
+		"GoVersion":"go1.0.3"
+	   }
+
+        :statuscode 200: no error
+	:statuscode 500: server error
+
+
+Create a new image from a container's changes
+*********************************************
+
+.. http:post:: /commit
+
+	Create a new image from a container's changes
+
+	**Example request**:
+
+        .. sourcecode:: http
+
+           POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
+
+        **Example response**:
+
+        .. sourcecode:: http
+
+           HTTP/1.1 201 OK
+	   Content-Type: application/vnd.docker.raw-stream
+
+           {"Id":"596069db4bf5"}
+
+	:query container: source container
+	:query repo: repository
+	:query tag: tag
+	:query m: commit message
+	:query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
+	:query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
+        :statuscode 201: no error
+	:statuscode 404: no such container
+        :statuscode 500: server error
+
+
+3. Going further
+================
+
+3.1 Inside 'docker run'
+-----------------------
+
+Here are the steps of 'docker run' :
+
+* Create the container
+* If the status code is 404, it means the image doesn't exists:
+        * Try to pull it
+        * Then retry to create the container
+* Start the container
+* If you are not in detached mode:
+        * Attach to the container, using logs=1 (to have stdout and stderr from the container's start) and stream=1
+* If in detached mode or only stdin is attached:
+	* Display the container's id
+
+
+3.2 Hijacking
+-------------
+
+In this version of the API, /attach, uses hijacking to transport stdin, stdout and stderr on the same socket. This might change in the future.
+
+3.3 CORS Requests
+-----------------
+
+To enable cross origin requests to the remote api add the flag "-api-enable-cors" when running docker in daemon mode.
+    
+    docker -d -H="192.168.1.9:4243" -api-enable-cors
+

+ 4 - 3
docs/sources/commandline/command/import.rst

@@ -12,8 +12,9 @@
 
     Create a new filesystem image from the contents of a tarball
 
-At this time, the URL must start with ``http`` and point to a single file archive (.tar, .tar.gz, .bzip) 
-containing a root filesystem. If you would like to import from a local directory or archive, 
+At this time, the URL must start with ``http`` and point to a single file archive
+(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
+containing a root filesystem. If you would like to import from a local directory or archive,
 you can use the ``-`` parameter to take the data from standard in.
 
 Examples
@@ -30,7 +31,7 @@ Import from a local file
 Import to docker via pipe and standard in
 
 ``$ cat exampleimage.tgz | docker import - exampleimagelocal``
-  
+
 Import from a local directory
 .............................
 

+ 1 - 1
docs/sources/commandline/command/run.rst

@@ -15,7 +15,7 @@
       -a=map[]: Attach to stdin, stdout or stderr.
       -c=0: CPU shares (relative weight)
       -cidfile="": Write the container ID to the file
-      -d=false: Detached mode: leave the container running in the background
+      -d=false: Detached mode: Run container in the background, print new container id
       -e=[]: Set environment variables
       -h="": Container host name
       -i=false: Keep stdin open even if not attached

+ 0 - 61
docs/sources/concepts/manifesto.rst

@@ -4,10 +4,6 @@
 
 .. _dockermanifesto:
 
-*(This was our original Welcome page, but it is a bit forward-looking
-for docs, and maybe not enough vision for a true manifesto. We'll
-reveal more vision in the future to make it more Manifesto-y.)*
-
 Docker Manifesto
 ----------------
 
@@ -131,60 +127,3 @@ sitting 10 miles away.
 
 With Standard Containers we can put an end to that embarrassment, by
 making INDUSTRIAL-GRADE DELIVERY of software a reality.
-
-Standard Container Specification
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-(TODO)
-
-Image format
-~~~~~~~~~~~~
-
-Standard operations
-~~~~~~~~~~~~~~~~~~~
-
--  Copy
--  Run
--  Stop
--  Wait
--  Commit
--  Attach standard streams
--  List filesystem changes
--  ...
-
-Execution environment
-~~~~~~~~~~~~~~~~~~~~~
-
-Root filesystem
-^^^^^^^^^^^^^^^
-
-Environment variables
-^^^^^^^^^^^^^^^^^^^^^
-
-Process arguments
-^^^^^^^^^^^^^^^^^
-
-Networking
-^^^^^^^^^^
-
-Process namespacing
-^^^^^^^^^^^^^^^^^^^
-
-Resource limits
-^^^^^^^^^^^^^^^
-
-Process monitoring
-^^^^^^^^^^^^^^^^^^
-
-Logging
-^^^^^^^
-
-Signals
-^^^^^^^
-
-Pseudo-terminal allocation
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Security
-^^^^^^^^
-

+ 2 - 2
docs/sources/examples/couchdb_data_volumes.rst

@@ -39,7 +39,7 @@ This time, we're requesting shared access to $COUCH1's volumes.
 
 .. code-block:: bash
 
-    COUCH2=$(docker run -d -volumes-from $COUCH1) shykes/couchdb:2013-05-03)
+    COUCH2=$(docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
 
 Browse data on the second database
 ----------------------------------
@@ -48,6 +48,6 @@ Browse data on the second database
 
     HOST=localhost
     URL="http://$HOST:$(docker port $COUCH2 5984)/_utils/"
-    echo "Navigate to $URL in your browser. You should see the same data as in the first database!"
+    echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
 
 Congratulations, you are running 2 Couchdb containers, completely isolated from each other *except* for their data.

+ 1 - 1
docs/theme/MAINTAINERS

@@ -1 +1 @@
-Thatcher Penskens <thatcher@dotcloud.com>
+Thatcher Peskens <thatcher@dotcloud.com>

+ 4 - 4
docs/theme/docker/layout.html

@@ -68,12 +68,12 @@
 
             <div style="float: right" class="pull-right">
                 <ul class="nav">
-                    <li id="nav-introduction"><a href="http://www.docker.io/">Home</a></li>
-                    <li id="nav-about"><a href="http://www.docker.io/">About</a></li>
-                    <li id="nav-community"><a href="http://www.docker.io/">Community</a></li>
+                    <li id="nav-introduction"><a href="http://www.docker.io/" title="Docker Homepage">Home</a></li>
+                    <li id="nav-about"><a href="http://www.docker.io/about/" title="About">About</a></li>
+                    <li id="nav-community"><a href="http://www.docker.io/community/" title="Community">Community</a></li>
                     <li id="nav-gettingstarted"><a href="http://www.docker.io/gettingstarted/">Getting started</a></li>
                     <li id="nav-documentation" class="active"><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
-                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
+                    <li id="nav-blog"><a href="http://blog.docker.io/" title="Docker Blog">Blog</a></li>
                     <li id="nav-index"><a href="http://index.docker.io/" title="Docker Image Index, find images here">INDEX <img class="inline-icon" src="{{ pathto('_static/img/external-link-icon.png', 1) }}" title="external link"> </a></li>
                 </ul>
             </div>

+ 0 - 1
docs/website/MAINTAINERS

@@ -1 +0,0 @@
-Thatcher Penskens <thatcher@dotcloud.com>

+ 0 - 2
docs/website/dotcloud.yml

@@ -1,2 +0,0 @@
-www:
-  type: static

+ 0 - 220
docs/website/gettingstarted/index.html

@@ -1,220 +0,0 @@
-<!DOCTYPE html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!-->
-<html class="no-js" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
-<head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <title>Docker - the Linux container runtime</title>
-
-    <meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
-    <meta name="viewport" content="width=device-width">
-
-    <!-- twitter bootstrap -->
-    <link rel="stylesheet" href="../static/css/bootstrap.min.css">
-    <link rel="stylesheet" href="../static/css/bootstrap-responsive.min.css">
-
-    <!-- main style file -->
-    <link rel="stylesheet" href="../static/css/main.css">
-
-    <!-- vendor scripts -->
-    <script src="../static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
-    <script src="../static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
-
-</head>
-
-
-<body>
-
-<div class="navbar navbar-fixed-top">
-    <div class="navbar-dotcloud">
-        <div class="container" style="text-align: center;">
-
-            <div style="float: right" class="pull-right">
-                <ul class="nav">
-                    <li id="nav-introduction"><a href="../">Introduction</a></li>
-                    <li id="nav-gettingstarted" class="active"><a href="">Getting started</a></li>
-                    <li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
-                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
-                </ul>
-            </div>
-
-            <div style="margin-left: -12px; float: left;">
-                <a href="../index.html"><img style="margin-top: 12px; height: 38px" src="../static/img/docker-letters-logo.gif"></a>
-            </div>
-        </div>
-    </div>
-</div>
-
-
-<div class="container">
-    <div class="row">
-
-        <div class="span12 titlebar">
-
-            <div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
-                <a  href="http://github.com/dotcloud/docker/"><img src="../static/img/fork-us.png"> Fork us on Github</a>
-            </div>
-
-            <h1 class="pageheader"> GETTING STARTED</h1>
-        </div>
-
-    </div>
-
-</div>
-
-<div class="container">
-    <div class="alert alert-info" style="margin-bottom: 0;">
-        <strong>Docker is still under heavy development.</strong> It should not yet be used in production. Check <a href="http://github.com/dotcloud/docker">the repo</a> for recent progress.
-    </div>
-    <div class="row">
-        <div class="span6">
-            <section class="contentblock">
-                <h2>
-                    <a name="installing-on-ubuntu-1204-and-1210" class="anchor" href="#installing-on-ubuntu-1204-and-1210"><span class="mini-icon mini-icon-link"></span>
-                    </a>Installing on Ubuntu</h2>
-
-                    <p><strong>Requirements</strong></p>
-                    <ul>
-                        <li>Ubuntu 12.04 (LTS) (64-bit)</li>
-                        <li> or Ubuntu 12.10 (quantal) (64-bit)</li>
-                        <li>The 3.8 Linux Kernel</li>
-                    </ul>
-                <ol>
-                    <li>
-                    <p><strong>Install dependencies</strong></p>
-                    The linux-image-extra package is only needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module.
-                    <pre>sudo apt-get install linux-image-extra-`uname -r`</pre>
-
-
-                    </li>
-                    <li>
-                        <p><strong>Install Docker</strong></p>
-                        <p>Add the Ubuntu PPA (Personal Package Archive) sources to your apt sources list, update and install.</p>
-                        <p>This may import a new GPG key (key 63561DC6: public key "Launchpad PPA for dotcloud team" imported).</p>
-                        <div class="highlight">
-                            <pre>sudo apt-get install software-properties-common</pre>
-                            <pre>sudo add-apt-repository ppa:dotcloud/lxc-docker</pre>
-                            <pre>sudo apt-get update</pre>
-                            <pre>sudo apt-get install lxc-docker</pre>
-                        </div>
-
-
-                    </li>
-
-                    <li>
-                        <p><strong>Run!</strong></p>
-
-                        <div class="highlight">
-                            <pre>docker run -i -t ubuntu /bin/bash</pre>
-                        </div>
-                    </li>
-                    Continue with the <a href="http://docs.docker.io/en/latest/examples/hello_world/">Hello world</a> example.<br>
-                    Or check <a href="http://docs.docker.io/en/latest/installation/ubuntulinux/">more detailed installation instructions</a>
-                </ol>
-            </section>
-
-            <section class="contentblock">
-                <h2>Contributing to Docker</h2>
-
-                <p>Want to hack on Docker? Awesome! We have some <a href="http://docs.docker.io/en/latest/contributing/contributing/">instructions to get you started</a>. They are probably not perfect, please let us know if anything feels wrong or incomplete.</p>
-            </section>
-
-        </div>
-        <div class="span6">
-            <section class="contentblock">
-                <h2>Quick install on other operating systems</h2>
-                <p><strong>For other operating systems we recommend and provide a streamlined install with virtualbox,
-                    vagrant and an Ubuntu virtual machine.</strong></p>
-
-                <ul>
-                    <li><a href="http://docs.docker.io/en/latest/installation/vagrant/">Mac OS X and other linuxes</a></li>
-                    <li><a href="http://docs.docker.io/en/latest/installation/windows/">Windows</a></li>
-                </ul>
-
-            </section>
-
-            <section class="contentblock">
-                <h2>Questions? Want to get in touch?</h2>
-                <p>There are several ways to get in touch:</p>
-                <p><strong>Join the discussion on IRC.</strong> We can be found in the <a href="irc://chat.freenode.net#docker">#docker</a> channel on chat.freenode.net</p>
-                <p><strong>Discussions</strong> happen on our google group: <a href="https://groups.google.com/d/forum/docker-club">docker-club at googlegroups.com</a></p>
-                <p>All our <strong>development and decisions</strong> are made out in the open on Github <a href="http://www.github.com/dotcloud/docker">github.com/dotcloud/docker</a></p>
-                <p><strong>Get help on using Docker</strong> by asking on <a href="http://stackoverflow.com/tags/docker/">Stackoverflow</a></p>
-                <p>And of course, <strong>tweet</strong> your tweets to <a href="http://twitter.com/getdocker/">twitter.com/getdocker</a></p>
-            </section>
-
-
-            <section class="contentblock">
-                <div id="wufoo-z7x3p3">
-                    Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
-                </div>
-                <script type="text/javascript">var z7x3p3;(function(d, t) {
-                    var s = d.createElement(t), options = {
-                        'userName':'dotclouddocker',
-                        'formHash':'z7x3p3',
-                        'autoResize':true,
-                        'height':'577',
-                        'async':true,
-                        'header':'show'};
-                    s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
-                    s.onload = s.onreadystatechange = function() {
-                        var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
-                        try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
-                    var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
-                })(document, 'script');</script>
-            </section>
-
-        </div>
-    </div>
-</div>
-
-
-<div class="container">
-    <footer id="footer" class="footer">
-        <div class="row">
-            <div class="span12 social">
-                <div class="tbox textright forceleftmargin social links pull-right">
-                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
-                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
-                </div>
-                Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
-
-            </div>
-        </div>
-
-        <div class="row">
-            <div class="emptyspace" style="height: 40px">
-
-            </div>
-        </div>
-
-    </footer>
-</div>
-
-
-<!-- bootstrap javascipts -->
-<script src="../static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
-
-<!-- Google analytics -->
-<script type="text/javascript">
-
-    var _gaq = _gaq || [];
-    _gaq.push(['_setAccount', 'UA-6096819-11']);
-    _gaq.push(['_setDomainName', 'docker.io']);
-    _gaq.push(['_setAllowLinker', true]);
-    _gaq.push(['_trackPageview']);
-
-    (function() {
-        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-    })();
-
-</script>
-
-
-</body>
-</html>

+ 0 - 359
docs/website/index.html

@@ -1,359 +0,0 @@
-<!DOCTYPE html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!-->
-<html class="no-js" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
-<head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="google-site-verification" content="UxV66EKuPe87dgnH1sbrldrx6VsoWMrx5NjwkgUFxXI" />
-    <title>Docker - the Linux container engine</title>
-
-    <meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
-    <meta name="viewport" content="width=device-width">
-
-    <!-- twitter bootstrap -->
-    <link rel="stylesheet" href="static/css/bootstrap.min.css">
-    <link rel="stylesheet" href="static/css/bootstrap-responsive.min.css">
-
-    <!-- main style file -->
-    <link rel="stylesheet" href="static/css/main.css">
-
-    <!-- vendor scripts -->
-    <script src="static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
-    <script src="static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
-
-    <style>
-        .indexlabel {
-            float: left;
-            width: 150px;
-            display: block;
-            padding: 10px 20px 10px;
-            font-size: 20px;
-            font-weight: 200;
-            background-color: #a30000;
-            color: white;
-            height: 22px;
-        }
-        .searchbutton {
-            font-size: 20px;
-            height: 40px;
-        }
-
-        .debug {
-            border: 1px red dotted;
-        }
-        .twitterblock {
-            min-height: 75px;
-        }
-
-        .twitterblock img {
-            float: left;
-            margin-right: 10px;
-        }
-
-    </style>
-
-
-</head>
-
-
-<body>
-
-<div class="navbar navbar-fixed-top">
-    <div class="navbar-dotcloud">
-        <div class="container" style="text-align: center;">
-
-
-            <div class="pull-left" id="fork-us" style="margin-top: 16px;">
-                <a  href="http://github.com/dotcloud/docker/"><img src="static/img/fork-us.png" alt="fork-icon"> Fork us on Github</a>
-            </div>
-
-            <div class="pull-right" >
-                <ul class="nav">
-                    <li id="nav-introduction" class="active"><a href="/">Introduction</a></li>
-                    <li id="nav-gettingstarted"><a href="gettingstarted">Getting started</a></li>
-                    <li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
-                    <li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
-                </ul>
-            </div>
-        </div>
-    </div>
-</div>
-
-
-<div class="container" style="margin-top: 30px;">
-    <div class="row">
-
-        <div class="span12">
-            <section class="contentblock header">
-
-                <div class="span5" style="margin-bottom: 15px;">
-                    <div style="text-align: center;" >
-                        <img src="static/img/docker_letters_500px.png" alt="docker letters">
-
-                        <h2>The Linux container engine</h2>
-                    </div>
-
-                    <div style="display: block; text-align: center; margin-top: 20px;">
-
-                        <h5>
-                            Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers which are independent of hardware, language, framework, packaging system and hosting provider.
-                        </h5>
-
-                    </div>
-
-
-                    <div style="display: block; text-align: center; margin-top: 30px;">
-                        <a class="btn btn-custom btn-large" href="gettingstarted/">Let's get started</a>
-                    </div>
-
-                </div>
-
-                <div class="span6" >
-                    <div class="js-video" >
-                        <iframe width="600" height="360" src="http://www.youtube.com/embed/wW9CAH9nSLs?feature=player_detailpage&rel=0&modestbranding=1&start=11" frameborder="0" allowfullscreen></iframe>
-                    </div>
-                </div>
-
-                <br style="clear: both"/>
-            </section>
-        </div>
-    </div>
-</div>
-
-<div class="container">
-    <div class="row">
-
-        <div class="span6">
-            <section class="contentblock">
-                <h4>Heterogeneous payloads</h4>
-                <p>Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.</p>
-                <h4>Any server</h4>
-                <p>Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.</p>
-                <h4>Isolation</h4>
-                <p>Docker isolates processes from each other and from the underlying host, using lightweight containers.</p>
-                <h4>Repeatability</h4>
-                <p>Because each container is isolated in its own filesystem, they behave the same regardless of where, when, and alongside what they run.</p>
-            </section>
-            <section class="contentblock">
-                <div class="container">
-                <div class="span2" style="margin-left: 0" >
-                    <a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description"><img src="static/img/hiring_graphic.png" alt="we're hiring" width="140" style="margin-top: 25px"></a>
-                </div>
-                <div class="span4" style="margin-left: 0">
-                    <h4>Do you think it is cool to hack on docker? Join us!</h4>
-                    <ul>
-                        <li>Work on open source</li>
-                        <li>Program in Go</li>
-                    </ul>
-                    <a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description">read more</a>
-                </div>
-                </div>
-
-            </section>
-        </div>
-        <div class="span6">
-            <section class="contentblock">
-                <h1>New! Docker Index</h1>
-                On the Docker Index you can find and explore pre-made container images. It allows you to share your images and download them.
-
-                <br><br>
-                <a href="https://index.docker.io" target="_blank">
-                    <div class="indexlabel">
-                        DOCKER index
-                    </div>
-                </a>
-                &nbsp;
-                <input type="button" class="searchbutton" value="Search images"
-                       onClick="window.open('https://index.docker.io')" />
-
-            </section>
-            <section class="contentblock">
-                <div id="wufoo-z7x3p3">
-                    Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
-                </div>
-                <script type="text/javascript">var z7x3p3;(function(d, t) {
-                    var s = d.createElement(t), options = {
-                        'userName':'dotclouddocker',
-                        'formHash':'z7x3p3',
-                        'autoResize':true,
-                        'height':'577',
-                        'async':true,
-                        'header':'show'};
-                    s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
-                    s.onload = s.onreadystatechange = function() {
-                        var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
-                        try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
-                    var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
-                })(document, 'script');</script>
-            </section>
-        </div>
-    </div>
-
-</div>
-
-<div class="container">
-
-    <div class="row">
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/2707460527/252a64411a339184ff375a96fb68dcb0_bigger.png">
-                <em>Mitchell Hashimoto ‏@mitchellh:</em> Docker launched today. It is incredible. They’re also working RIGHT NOW on a Vagrant provider. LXC is COMING!!
-            </section>
-        </div>
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/1108290260/Adam_Jacob-114x150_original_bigger.jpg">
-                <em>Adam Jacob ‏@adamhjk:</em> Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think.
-            </section>
-        </div>
-    </div>
-    <div class="row">
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/14872832/twitter_pic_bigger.jpg">
-                <em>Matt Townsend ‏@mtownsend:</em> I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego.
-            </section>
-        </div>
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/1312352395/rupert-259x300_bigger.jpg">
-                <em>Rob Harrop ‏@robertharrop:</em> Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter.
-            </section>
-        </div>
-    </div>
-    <div class="row">
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://twimg0-a.akamaihd.net/profile_images/2491994496/rbevyyq6ykp6bnoby2je_bigger.jpeg">
-                <em>John Willis @botchagalupe:</em> IMHO docker is to paas what chef was to Iaas 4 years ago
-            </section>
-        </div>
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://twimg0-a.akamaihd.net/profile_images/3348427561/9d7f08f1e103a16c8debd169301b9944_bigger.jpeg">
-                <em>John Feminella ‏@superninjarobot:</em> So, @getdocker is pure excellence. If you've ever wished for arbitrary, PaaS-agnostic, lxc/aufs Linux containers, this is your jam!
-            </section>
-        </div>
-    </div>
-    <div class="row">
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/3408403010/4496ccdd14e9b7285eca04c31a740207_bigger.jpeg">
-                <em>David Romulan ‏@destructuring:</em> I haven't had this much fun since AWS
-            </section>
-        </div>
-        <div class="span6">
-            <section class="contentblock twitterblock">
-                <img src="https://si0.twimg.com/profile_images/780893320/My_Avatar_bigger.jpg">
-                <em>Ricardo Gladwell ‏@rgladwell:</em> wow @getdocker is either amazing or totally stupid
-            </section>
-        </div>
-
-    </div>
-</div>
-
-<div class="container">
-    <div class="row">
-        <div class="span6">
-
-            <section class="contentblock">
-
-                <h2>Notable features</h2>
-
-                <ul>
-                    <li>Filesystem isolation: each process container runs in a completely separate root filesystem.</li>
-                    <li>Resource isolation: system resources like cpu and memory can be allocated differently to each process container, using cgroups.</li>
-                    <li>Network isolation: each process container runs in its own network namespace, with a virtual interface and IP address of its own.</li>
-                    <li>Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremely fast, memory-cheap and disk-cheap.</li>
-                    <li>Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval.</li>
-                    <li>Change management: changes to a container's filesystem can be committed into a new image and re-used to create more containers. No templating or manual configuration required.</li>
-                    <li>Interactive shell: docker can allocate a pseudo-tty and attach to the standard input of any container, for example to run a throwaway interactive shell.</li>
-                </ul>
-
-                <h2>Under the hood</h2>
-
-                <p>Under the hood, Docker is built on the following components:</p>
-
-                <ul>
-                    <li>The <a href="http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c">cgroup</a> and <a href="http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part">namespacing</a> capabilities of the Linux kernel;</li>
-                    <li><a href="http://aufs.sourceforge.net/aufs.html">AUFS</a>, a powerful union filesystem with copy-on-write capabilities;</li>
-                    <li>The <a href="http://golang.org">Go</a> programming language;</li>
-                    <li><a href="http://lxc.sourceforge.net/">lxc</a>, a set of convenience scripts to simplify the creation of linux containers.</li>
-                </ul>
-
-                <h2>Who started it</h2>
-                <p>
-                    Docker is an open-source implementation of the deployment engine which powers <a href="http://dotcloud.com">dotCloud</a>, a popular Platform-as-a-Service.</p>
-
-                <p>It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
-                    of applications and databases.
-                </p>
-
-            </section>
-        </div>
-
-        <div class="span6">
-
-
-            <section class="contentblock">
-                <h3 id="twitter">Twitter</h3>
-                <a class="twitter-timeline" href="https://twitter.com/getdocker" data-widget-id="312730839718957056">Tweets by @getdocker</a>
-                <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
-            </section>
-
-        </div>
-    </div>
-
-</div> <!-- end container -->
-
-
-<div class="container">
-    <footer id="footer" class="footer">
-        <div class="row">
-            <div class="span12">
-                <div class="tbox textright forceleftmargin social links pull-right">
-                    <a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
-                    <a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
-                </div>
-                Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
-
-            </div>
-        </div>
-
-        <div class="row">
-            <div class="emptyspace" style="height: 40px">
-
-            </div>
-        </div>
-
-    </footer>
-</div>
-
-
-
-<!-- bootstrap javascipts -->
-<script src="static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
-
-<!-- Google analytics -->
-<script type="text/javascript">
-
-    var _gaq = _gaq || [];
-    _gaq.push(['_setAccount', 'UA-6096819-11']);
-    _gaq.push(['_setDomainName', 'docker.io']);
-    _gaq.push(['_setAllowLinker', true]);
-    _gaq.push(['_trackPageview']);
-
-    (function() {
-        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-    })();
-
-</script>
-
-
-</body>
-</html>

+ 0 - 6
docs/website/nginx.conf

@@ -1,6 +0,0 @@
-
-# rule to redirect original links created when hosted on github pages
-rewrite ^/documentation/(.*).html http://docs.docker.io/en/latest/$1/ permanent;
-
-# rewrite the stuff which was on the current page
-rewrite ^/gettingstarted.html$ /gettingstarted/ permanent;

+ 0 - 1
docs/website/static

@@ -1 +0,0 @@
-../theme/docker/static

+ 1 - 1
image.go

@@ -68,7 +68,7 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
 	}
 	// Store the layer
 	layer := layerPath(root)
-	if err := os.MkdirAll(layer, 0700); err != nil {
+	if err := os.MkdirAll(layer, 0755); err != nil {
 		return err
 	}
 

+ 6 - 0
packaging/debian/lxc-docker.1

@@ -923,6 +923,12 @@ List images
 Usage: docker import [OPTIONS] URL|\- [REPOSITORY [TAG]]
 .sp
 Create a new filesystem image from the contents of a tarball
+
+At this time, the URL must start with ``http`` and point to a single file archive
+(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
+containing a root filesystem. If you would like to import from a local directory or archive,
+you can use the ``-`` parameter to take the data from standard in.
+
 .SS info
 .sp
 .nf

+ 4 - 5
packaging/ubuntu/docker.upstart

@@ -1,9 +1,8 @@
 description     "Run docker"
 
-start on runlevel [2345]
-stop on starting rc RUNLEVEL=[016]
+start on filesystem or runlevel [2345]
+stop on runlevel [!2345]
+
 respawn
 
-script
-    /usr/bin/docker -d
-end script
+exec /usr/bin/docker -d

+ 13 - 9
registry/registry.go

@@ -109,7 +109,14 @@ func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
 	for _, cookie := range c.Jar.Cookies(req.URL) {
 		req.AddCookie(cookie)
 	}
-	return c.Do(req)
+	res, err := c.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	if len(res.Cookies()) > 0 {
+		c.Jar.SetCookies(req.URL, res.Cookies())
+	}
+	return res, err
 }
 
 // Set the user agent field in the header based on the versions provided
@@ -135,7 +142,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s
 	}
 	req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
 	r.setUserAgent(req)
-	res, err := r.client.Do(req)
+	res, err := doWithCookies(r.client, req)
 	if err != nil || res.StatusCode != 200 {
 		if res != nil {
 			return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID)
@@ -182,7 +189,7 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([
 	}
 	req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
 	r.setUserAgent(req)
-	res, err := r.client.Do(req)
+	res, err := doWithCookies(r.client, req)
 	if err != nil {
 		return nil, -1, fmt.Errorf("Failed to download json: %s", err)
 	}
@@ -210,7 +217,7 @@ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) (
 	}
 	req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
 	r.setUserAgent(req)
-	res, err := r.client.Do(req)
+	res, err := doWithCookies(r.client, req)
 	if err != nil {
 		return nil, err
 	}
@@ -231,7 +238,7 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
 		}
 		req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
 		r.setUserAgent(req)
-		res, err := r.client.Do(req)
+		res, err := doWithCookies(r.client, req)
 		if err != nil {
 			return nil, err
 		}
@@ -326,7 +333,7 @@ func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, e
 // Push a local image to the registry
 func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
 	// FIXME: try json with UTF8
-	req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", strings.NewReader(string(jsonRaw)))
+	req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", bytes.NewReader(jsonRaw))
 	if err != nil {
 		return err
 	}
@@ -341,9 +348,6 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
 		return fmt.Errorf("Failed to upload metadata: %s", err)
 	}
 	defer res.Body.Close()
-	if len(res.Cookies()) > 0 {
-		r.client.Jar.SetCookies(req.URL, res.Cookies())
-	}
 	if res.StatusCode != 200 {
 		errBody, err := ioutil.ReadAll(res.Body)
 		if err != nil {

+ 13 - 6
runtime_test.go

@@ -8,6 +8,7 @@ import (
 	"log"
 	"net"
 	"os"
+	"runtime"
 	"strconv"
 	"strings"
 	"sync"
@@ -25,7 +26,11 @@ const (
 	testDaemonProto       = "tcp"
 )
 
-var globalRuntime *Runtime
+var (
+	globalRuntime   *Runtime
+	startFds        int
+	startGoroutines int
+)
 
 func nuke(runtime *Runtime) error {
 	var wg sync.WaitGroup
@@ -80,21 +85,21 @@ func init() {
 	NetworkBridgeIface = unitTestNetworkBridge
 
 	// Make it our Store root
-	runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false)
-	if err != nil {
+	if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil {
 		panic(err)
+	} else {
+		globalRuntime = runtime
 	}
-	globalRuntime = runtime
 
 	// Create the "Server"
 	srv := &Server{
-		runtime:     runtime,
+		runtime:     globalRuntime,
 		enableCors:  false,
 		pullingPool: make(map[string]struct{}),
 		pushingPool: make(map[string]struct{}),
 	}
 	// If the unit test is not found, try to download it.
-	if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
+	if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
 		// Retrieve the Image
 		if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
 			panic(err)
@@ -109,6 +114,8 @@ func init() {
 
 	// Give some time to ListenAndServer to actually start
 	time.Sleep(time.Second)
+
+	startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
 }
 
 // FIXME: test that ImagePull(json=true) send correct json output

+ 31 - 15
server.go

@@ -252,6 +252,18 @@ func (srv *Server) DockerInfo() *APIInfo {
 	} else {
 		imgcount = len(images)
 	}
+	lxcVersion := ""
+	if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil {
+		outputStr := string(output)
+		if len(strings.SplitN(outputStr, ":", 2)) == 2 {
+			lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1])
+		}
+	}
+	kernelVersion := "<unknown>"
+	if kv, err := utils.GetKernelVersion(); err == nil {
+		kernelVersion = kv.String()
+	}
+
 	return &APIInfo{
 		Containers:      len(srv.runtime.List()),
 		Images:          imgcount,
@@ -260,7 +272,9 @@ func (srv *Server) DockerInfo() *APIInfo {
 		Debug:           os.Getenv("DEBUG") != "",
 		NFd:             utils.GetTotalUsedFds(),
 		NGoroutines:     runtime.NumGoroutine(),
+		LXCVersion:      lxcVersion,
 		NEventsListener: len(srv.events),
+		KernelVersion:   kernelVersion,
 	}
 }
 
@@ -295,35 +309,34 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
 
 }
 
-func (srv *Server) ContainerTop(name string) ([]APITop, error) {
+func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
 	if container := srv.runtime.Get(name); container != nil {
-		output, err := exec.Command("lxc-ps", "--name", container.ID).CombinedOutput()
+		output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
 		if err != nil {
 			return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output)
 		}
-		var procs []APITop
+		procs := APITop{}
 		for i, line := range strings.Split(string(output), "\n") {
-			if i == 0 || len(line) == 0 {
+			if len(line) == 0 {
 				continue
 			}
-			proc := APITop{}
+			words := []string{}
 			scanner := bufio.NewScanner(strings.NewReader(line))
 			scanner.Split(bufio.ScanWords)
 			if !scanner.Scan() {
 				return nil, fmt.Errorf("Error trying to use lxc-ps")
 			}
 			// no scanner.Text because we skip container id
-			scanner.Scan()
-			proc.PID = scanner.Text()
-			scanner.Scan()
-			proc.Tty = scanner.Text()
-			scanner.Scan()
-			proc.Time = scanner.Text()
-			scanner.Scan()
-			proc.Cmd = scanner.Text()
-			procs = append(procs, proc)
+			for scanner.Scan() {
+				words = append(words, scanner.Text())
+			}
+			if i == 0 {
+				procs.Titles = words
+			} else {
+				procs.Processes = append(procs.Processes, words)
+			}
 		}
-		return procs, nil
+		return &procs, nil
 
 	}
 	return nil, fmt.Errorf("No such container: %s", name)
@@ -994,6 +1007,9 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
 			parsedRepo := strings.Split(repoAndTag, ":")[0]
 			if strings.Contains(img.ID, repoName) {
 				repoName = parsedRepo
+				if len(srv.runtime.repositories.ByID()[img.ID]) == 1 && len(strings.Split(repoAndTag, ":")) > 1 {
+					tag = strings.Split(repoAndTag, ":")[1]
+				}
 			} else if repoName != parsedRepo {
 				// the id belongs to multiple repos, like base:latest and user:test,
 				// in that case return conflict

+ 86 - 0
server_test.go

@@ -2,6 +2,7 @@ package docker
 
 import (
 	"github.com/dotcloud/docker/utils"
+	"strings"
 	"testing"
 	"time"
 )
@@ -203,3 +204,88 @@ func TestLogEvent(t *testing.T) {
 	})
 
 }
+
+func TestRmi(t *testing.T) {
+	runtime := mkRuntime(t)
+	defer nuke(runtime)
+	srv := &Server{runtime: runtime}
+
+	initialImages, err := srv.Images(false, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	containerID, err := srv.ContainerCreate(config)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	//To remove
+	err = srv.ContainerStart(containerID, hostConfig)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	imageID, err := srv.ContainerCommit(containerID, "test", "", "", "", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = srv.ContainerTag(imageID, "test", "0.1", false)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	containerID, err = srv.ContainerCreate(config)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	//To remove
+	err = srv.ContainerStart(containerID, hostConfig)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = srv.ContainerCommit(containerID, "test", "", "", "", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	images, err := srv.Images(false, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(images)-len(initialImages) != 2 {
+		t.Fatalf("Expected 2 new images, found %d.", len(images)-len(initialImages))
+	}
+
+	_, err = srv.ImageDelete(imageID, true)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	images, err = srv.Images(false, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(images)-len(initialImages) != 1 {
+		t.Fatalf("Expected 1 new image, found %d.", len(images)-len(initialImages))
+	}
+
+	for _, image := range images {
+		if strings.Contains(unitTestImageID, image.ID) {
+			continue
+		}
+		if image.Repository == "" {
+			t.Fatalf("Expected tagged image, got untagged one.")
+		}
+	}
+}

+ 6 - 3
utils/utils.go

@@ -609,11 +609,11 @@ type JSONMessage struct {
 	Status   string `json:"status,omitempty"`
 	Progress string `json:"progress,omitempty"`
 	Error    string `json:"error,omitempty"`
-	ID	 string `json:"id,omitempty"`
-	Time	 int64 `json:"time,omitempty"`
+	ID       string `json:"id,omitempty"`
+	Time     int64  `json:"time,omitempty"`
 }
 
-func (jm *JSONMessage) Display(out io.Writer) (error) {
+func (jm *JSONMessage) Display(out io.Writer) error {
 	if jm.Error != "" {
 		return fmt.Errorf(jm.Error)
 	}
@@ -635,6 +635,7 @@ func (jm *JSONMessage) Display(out io.Writer) (error) {
 	return nil
 }
 
+
 func DisplayJSONMessagesStream(in io.Reader, out io.Writer) error {
 	dec := json.NewDecoder(in)
 	jm := JSONMessage{}
@@ -669,6 +670,8 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer) error {
 	return nil
 }
 
+=======
+>>>>>>> master
 type StreamFormatter struct {
 	json bool
 	used bool

+ 6 - 1
z_final_test.go

@@ -6,7 +6,12 @@ import (
 	"testing"
 )
 
+func displayFdGoroutines(t *testing.T) {
+	t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
+}
+
 func TestFinal(t *testing.T) {
 	cleanup(globalRuntime)
-	t.Logf("Fds: %d, Goroutines: %d", utils.GetTotalUsedFds(), runtime.NumGoroutine())
+	t.Logf("Start Fds: %d, Start Goroutines: %d", startFds, startGoroutines)
+	displayFdGoroutines(t)
 }