mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-19 12:16:30 +00:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e34e44e8e6 | |||
| 13d9e26edd | |||
| 0a3131554c | |||
| 521ce07859 | |||
| f02950965e | |||
| 16f6daa5be | |||
| ca6cd5b557 | |||
| c4cd224d90 | |||
| 7b0e96f1f4 | |||
| fc72a809c1 | |||
| 2a47df0202 | |||
| 468fb90117 | |||
| ac49a797b4 | |||
| 1ec6c223c9 | |||
| db08705e3c | |||
| fdf3308260 | |||
| c2c72bcfd7 | |||
| cdf90bb04b | |||
| 45809e9a05 | |||
| 1967c8342a | |||
| 7673afc843 | |||
| b1fbebb4a3 | |||
| 3527291b47 | |||
| 57d31c9777 | |||
| a2f5a56143 | |||
| 343ed6b53f | |||
| 22893429ed | |||
| c1703c2b68 | |||
| a8c15477d9 | |||
| 9d03b2bb62 | |||
| 8987bd5832 | |||
| f226842aa1 | |||
| b14164879b | |||
| bb22cd492e | |||
| 27be5aec74 | |||
| 048f9f4974 | |||
| fb0b375be7 | |||
| 79d934bfb0 | |||
| 54dfedc516 | |||
| 0eb7157b6f | |||
| 2de953490d | |||
| 3ba44d2d5f | |||
| 313d13ea01 | |||
| e68c04b722 | |||
| c902c43766 | |||
| c105049f7e | |||
| 17136d58f2 | |||
| 8ea1e9126f | |||
| 6dc4c74b5a | |||
| 9d1fd2317d | |||
| 1f9f5eed5d | |||
| 5e1a975b48 | |||
| 97f48e59fc | |||
| e41fd24542 | |||
| 8bd192fb16 | |||
| 8c3331dc97 | |||
| f507188ddc | |||
| 76b7b2adf7 | |||
| a1f54cad6c | |||
| 9f83b9df22 | |||
| 4ab241c930 | |||
| f731835e45 | |||
| 418ef43fbb | |||
| 8f15c423e6 | |||
| e99541e637 |
@@ -14,3 +14,6 @@ Joffrey F <joffrey@dotcloud.com>
|
||||
<joffrey@dotcloud.com> <f.joffrey@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
<kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
<victor.vieux@dotcloud.com> <victor@dotcloud.com>
|
||||
<dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
|
||||
@@ -10,6 +10,8 @@ Daniel Robinson <gottagetmac@gmail.com>
|
||||
Dominik Honnef <dominik@honnef.co>
|
||||
Don Spaulding <donspauldingii@gmail.com>
|
||||
ezbercih <cem.ezberci@gmail.com>
|
||||
Flavio Castelli <fcastelli@suse.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
||||
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
|
||||
Hunter Blanks <hunter@twilio.com>
|
||||
@@ -23,10 +25,13 @@ Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
||||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Kevin J. Lynagh <kevin@keminglabs.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Maxim Treskin <zerthurd@gmail.com>
|
||||
Mikhail Sobolev <mss@mawhrin.net>
|
||||
Nelson Chen <crazysim@gmail.com>
|
||||
Niall O'Higgins <niallo@unworkable.org>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Piotr Bogdan <ppbogdan@gmail.com>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Sam Alba <sam.alba@gmail.com>
|
||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||
Silas Sewell <silas@sewell.org>
|
||||
@@ -35,4 +40,6 @@ Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Thatcher Peskens <thatcher@dotcloud.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Troy Howard <thoward37@gmail.com>
|
||||
unclejack <unclejacksons@gmail.com>
|
||||
Victor Vieux <victor.vieux@dotcloud.com>
|
||||
Vivek Agarwal <me@vivek.im>
|
||||
|
||||
@@ -13,7 +13,10 @@ endif
|
||||
GIT_COMMIT = $(shell git rev-parse --short HEAD)
|
||||
GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES")
|
||||
|
||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS)"
|
||||
NO_MEMORY_LIMIT ?= 0
|
||||
export NO_MEMORY_LIMIT
|
||||
|
||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS) -X main.NO_MEMORY_LIMIT $(NO_MEMORY_LIMIT)"
|
||||
|
||||
SRC_DIR := $(GOPATH)/src
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ Installing on Ubuntu 12.04 and 12.10
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
sudo apt-get install lxc wget bsdtar curl
|
||||
sudo apt-get install lxc bsdtar
|
||||
sudo apt-get install linux-image-extra-`uname -r`
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
## Spec for data volumes
|
||||
|
||||
Spec owner: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
Data volumes (issue #111) are a much-requested feature which trigger much discussion and debate. Below is the current authoritative spec for implementing data volumes.
|
||||
This spec will be deprecated once the feature is fully implemented.
|
||||
|
||||
Discussion, requests, trolls, demands, offerings, threats and other forms of supplications concerning this spec should be addressed to Solomon here: https://github.com/dotcloud/docker/issues/111
|
||||
|
||||
|
||||
### 1. Creating data volumes
|
||||
|
||||
At container creation, parts of a container's filesystem can be mounted as separate data volumes. Volumes are defined with the -v flag.
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
$ docker run -v /var/lib/postgres -v /var/log postgres /usr/bin/postgres
|
||||
```
|
||||
|
||||
In this example, a new container is created from the 'postgres' image. At the same time, docker creates 2 new data volumes: one will be mapped to the container at /var/lib/postgres, the other at /var/log.
|
||||
|
||||
2 important notes:
|
||||
|
||||
1) Volumes don't have top-level names. At no point does the user provide a name, or is a name given to him. Volumes are identified by the path at which they are mounted inside their container.
|
||||
|
||||
2) The user doesn't choose the source of the volume. Docker only mounts volumes it created itself, in the same way that it only runs containers that it created itself. That is by design.
|
||||
|
||||
|
||||
### 2. Sharing data volumes
|
||||
|
||||
Instead of creating its own volumes, a container can share another container's volumes. For example:
|
||||
|
||||
```bash
|
||||
$ docker run --volumes-from $OTHER_CONTAINER_ID postgres /usr/local/bin/postgres-backup
|
||||
```
|
||||
|
||||
In this example, a new container is created from the 'postgres' example. At the same time, docker will *re-use* the 2 data volumes created in the previous example. One volume will be mounted on the /var/lib/postgres of *both* containers, and the other will be mounted on the /var/log of both containers.
|
||||
|
||||
### 3. Under the hood
|
||||
|
||||
Docker stores volumes in /var/lib/docker/volumes. Each volume receives a globally unique ID at creation, and is stored at /var/lib/docker/volumes/ID.
|
||||
|
||||
At creation, volumes are attached to a single container - the source of truth for this mapping will be the container's configuration.
|
||||
|
||||
Mounting a volume consists of calling "mount --bind" from the volume's directory to the appropriate sub-directory of the container mountpoint. This may be done by Docker itself, or farmed out to lxc (which supports mount-binding) if possible.
|
||||
|
||||
|
||||
### 4. Backups, transfers and other volume operations
|
||||
|
||||
Volumes sometimes need to be backed up, transfered between hosts, synchronized, etc. These operations typically are application-specific or site-specific, eg. rsync vs. S3 upload vs. replication vs...
|
||||
|
||||
Rather than attempting to implement all these scenarios directly, Docker will allow for custom implementations using an extension mechanism.
|
||||
|
||||
### 5. Custom volume handlers
|
||||
|
||||
Docker allows for arbitrary code to be executed against a container's volumes, to implement any custom action: backup, transfer, synchronization across hosts, etc.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```bash
|
||||
$ DB=$(docker run -d -v /var/lib/postgres -v /var/log postgres /usr/bin/postgres)
|
||||
|
||||
$ BACKUP_JOB=$(docker run -d --volumes-from $DB shykes/backuper /usr/local/bin/backup-postgres --s3creds=$S3CREDS)
|
||||
|
||||
$ docker wait $BACKUP_JOB
|
||||
```
|
||||
|
||||
Congratulations, you just implemented a custom volume handler, using Docker's built-in ability to 1) execute arbitrary code and 2) share volumes between containers.
|
||||
|
||||
+57
-30
@@ -18,9 +18,12 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const VERSION = "0.1.4"
|
||||
const VERSION = "0.1.5"
|
||||
|
||||
var GIT_COMMIT string
|
||||
var (
|
||||
GIT_COMMIT string
|
||||
NO_MEMORY_LIMIT bool
|
||||
)
|
||||
|
||||
func (srv *Server) Name() string {
|
||||
return "docker"
|
||||
@@ -79,7 +82,7 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ..
|
||||
n, err := stdin.Read(char)
|
||||
if n > 0 {
|
||||
if char[0] == '\r' || char[0] == '\n' {
|
||||
stdout.Write([]byte{'\n'})
|
||||
stdout.Write([]byte{'\r', '\n'})
|
||||
break
|
||||
} else if char[0] == 127 || char[0] == '\b' {
|
||||
if i > 0 {
|
||||
@@ -99,7 +102,7 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ..
|
||||
}
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
fmt.Fprintf(stdout, "Read error: %v\n", err)
|
||||
fmt.Fprintf(stdout, "Read error: %v\r\n", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -149,7 +152,7 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ..
|
||||
newAuthConfig := auth.NewAuthConfig(username, password, email, srv.runtime.root)
|
||||
status, err := auth.Login(newAuthConfig)
|
||||
if err != nil {
|
||||
fmt.Fprintln(stdout, "Error:", err)
|
||||
fmt.Fprintf(stdout, "Error: %s\r\n", err)
|
||||
} else {
|
||||
srv.runtime.authConfig = newAuthConfig
|
||||
}
|
||||
@@ -161,7 +164,7 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ..
|
||||
|
||||
// 'docker wait': block until a container stops
|
||||
func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "wait", "[OPTIONS] NAME", "Block until a container stops, then print its exit code.")
|
||||
cmd := rcli.Subcmd(stdout, "wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -183,6 +186,9 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
fmt.Fprintf(stdout, "Version:%s\n", VERSION)
|
||||
fmt.Fprintf(stdout, "Git Commit:%s\n", GIT_COMMIT)
|
||||
if NO_MEMORY_LIMIT {
|
||||
fmt.Fprintf(stdout, "Memory limit disabled\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -217,7 +223,7 @@ func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
}
|
||||
|
||||
func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "stop", "[OPTIONS] NAME", "Stop a running container")
|
||||
cmd := rcli.Subcmd(stdout, "stop", "CONTAINER [CONTAINER...]", "Stop a running container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -239,7 +245,7 @@ func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
}
|
||||
|
||||
func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "restart", "[OPTIONS] NAME", "Restart a running container")
|
||||
cmd := rcli.Subcmd(stdout, "restart", "CONTAINER [CONTAINER...]", "Restart a running container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -261,7 +267,7 @@ func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||
}
|
||||
|
||||
func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "start", "[OPTIONS] NAME", "Start a stopped container")
|
||||
cmd := rcli.Subcmd(stdout, "start", "CONTAINER [CONTAINER...]", "Start a stopped container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -283,7 +289,7 @@ func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...strin
|
||||
}
|
||||
|
||||
func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "inspect", "[OPTIONS] CONTAINER", "Return low-level information on a container")
|
||||
cmd := rcli.Subcmd(stdout, "inspect", "CONTAINER", "Return low-level information on a container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -318,7 +324,7 @@ func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||
}
|
||||
|
||||
func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "port", "[OPTIONS] CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
|
||||
cmd := rcli.Subcmd(stdout, "port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -340,9 +346,9 @@ func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
return nil
|
||||
}
|
||||
|
||||
// 'docker rmi NAME' removes all images with the name NAME
|
||||
// 'docker rmi IMAGE' removes all images with the name IMAGE
|
||||
func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) (err error) {
|
||||
cmd := rcli.Subcmd(stdout, "rmimage", "[OPTIONS] IMAGE", "Remove an image")
|
||||
cmd := rcli.Subcmd(stdout, "rmimage", "IMAGE [IMAGE...]", "Remove an image")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -351,7 +357,11 @@ func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||
return nil
|
||||
}
|
||||
for _, name := range cmd.Args() {
|
||||
if err := srv.runtime.graph.Delete(name); err != nil {
|
||||
img, err := srv.runtime.repositories.LookupImage(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := srv.runtime.graph.Delete(img.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -359,7 +369,7 @@ func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||
}
|
||||
|
||||
func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "history", "[OPTIONS] IMAGE", "Show the history of an image")
|
||||
cmd := rcli.Subcmd(stdout, "history", "IMAGE", "Show the history of an image")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -385,10 +395,14 @@ func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||
}
|
||||
|
||||
func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "rm", "[OPTIONS] CONTAINER", "Remove a container")
|
||||
cmd := rcli.Subcmd(stdout, "rm", "CONTAINER [CONTAINER...]", "Remove a container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if cmd.NArg() < 1 {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
for _, name := range cmd.Args() {
|
||||
container := srv.runtime.Get(name)
|
||||
if container == nil {
|
||||
@@ -403,10 +417,14 @@ func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||
|
||||
// 'docker kill NAME' kills a running container
|
||||
func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container")
|
||||
cmd := rcli.Subcmd(stdout, "kill", "CONTAINER [CONTAINER...]", "Kill a running container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if cmd.NArg() < 1 {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
for _, name := range cmd.Args() {
|
||||
container := srv.runtime.Get(name)
|
||||
if container == nil {
|
||||
@@ -421,17 +439,19 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
|
||||
func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
|
||||
stdout.Flush()
|
||||
cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
|
||||
cmd := rcli.Subcmd(stdout, "import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
|
||||
var archive io.Reader
|
||||
var resp *http.Response
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if cmd.NArg() < 1 {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
src := cmd.Arg(0)
|
||||
if src == "" {
|
||||
return fmt.Errorf("Not enough arguments")
|
||||
} else if src == "-" {
|
||||
if src == "-" {
|
||||
archive = stdin
|
||||
} else {
|
||||
u, err := url.Parse(src)
|
||||
@@ -569,7 +589,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||
}
|
||||
w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
|
||||
if !*quiet {
|
||||
fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tPARENT")
|
||||
fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
|
||||
}
|
||||
var allImages map[string]*Image
|
||||
var err error
|
||||
@@ -598,7 +618,6 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||
/* TAG */ tag,
|
||||
/* ID */ TruncateId(id),
|
||||
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
||||
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
||||
} {
|
||||
if idx == 0 {
|
||||
w.Write([]byte(field))
|
||||
@@ -621,7 +640,6 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||
/* TAG */ "<none>",
|
||||
/* ID */ TruncateId(id),
|
||||
/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
|
||||
/* PARENT */ srv.runtime.repositories.ImageName(image.Parent),
|
||||
} {
|
||||
if idx == 0 {
|
||||
w.Write([]byte(field))
|
||||
@@ -647,17 +665,25 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||
quiet := cmd.Bool("q", false, "Only display numeric IDs")
|
||||
flAll := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.")
|
||||
flFull := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
latest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.")
|
||||
nLast := cmd.Int("n", -1, "Show n last created containers, include non-running ones.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if *nLast == -1 && *latest {
|
||||
*nLast = 1
|
||||
}
|
||||
w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0)
|
||||
if !*quiet {
|
||||
fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT")
|
||||
}
|
||||
for _, container := range srv.runtime.List() {
|
||||
if !container.State.Running && !*flAll {
|
||||
for i, container := range srv.runtime.List() {
|
||||
if !container.State.Running && !*flAll && *nLast == -1 {
|
||||
continue
|
||||
}
|
||||
if i == *nLast {
|
||||
break
|
||||
}
|
||||
if !*quiet {
|
||||
command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
|
||||
if !*flFull {
|
||||
@@ -733,13 +759,14 @@ func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||
|
||||
func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout,
|
||||
"diff", "CONTAINER [OPTIONS]",
|
||||
"diff", "CONTAINER",
|
||||
"Inspect changes on a container's filesystem")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if cmd.NArg() < 1 {
|
||||
return fmt.Errorf("Not enough arguments")
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
if container := srv.runtime.Get(cmd.Arg(0)); container == nil {
|
||||
return fmt.Errorf("No such container")
|
||||
@@ -756,7 +783,7 @@ func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||
}
|
||||
|
||||
func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
cmd := rcli.Subcmd(stdout, "logs", "[OPTIONS] CONTAINER", "Fetch the logs of a container")
|
||||
cmd := rcli.Subcmd(stdout, "logs", "CONTAINER", "Fetch the logs of a container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -904,7 +931,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s
|
||||
if err != nil {
|
||||
// If container not found, try to pull it
|
||||
if srv.runtime.graph.IsNotExist(err) {
|
||||
fmt.Fprintf(stdout, "Image %s not found, trying to pull it from registry.\n", config.Image)
|
||||
fmt.Fprintf(stdout, "Image %s not found, trying to pull it from registry.\r\n", config.Image)
|
||||
if err = srv.CmdPull(stdin, stdout, config.Image); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -59,6 +59,20 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdWait(srv *Server, container *Container) error {
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
go func() {
|
||||
srv.CmdWait(nil, stdoutPipe, container.Id)
|
||||
}()
|
||||
|
||||
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
// Cleanup pipes
|
||||
return closeWrap(stdout, stdoutPipe)
|
||||
}
|
||||
|
||||
// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
|
||||
func TestRunHostname(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
@@ -89,7 +103,9 @@ func TestRunHostname(t *testing.T) {
|
||||
|
||||
setTimeout(t, "CmdRun timed out", 2*time.Second, func() {
|
||||
<-c
|
||||
cmdWait(srv, srv.runtime.List()[0])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRunExit(t *testing.T) {
|
||||
@@ -129,6 +145,7 @@ func TestRunExit(t *testing.T) {
|
||||
// as the process exited, CmdRun must finish and unblock. Wait for it
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
|
||||
<-c1
|
||||
cmdWait(srv, container)
|
||||
})
|
||||
|
||||
// Make sure that the client has been disconnected
|
||||
|
||||
+60
-21
@@ -33,13 +33,14 @@ type Container struct {
|
||||
network *NetworkInterface
|
||||
NetworkSettings *NetworkSettings
|
||||
|
||||
SysInitPath string
|
||||
cmd *exec.Cmd
|
||||
stdout *writeBroadcaster
|
||||
stderr *writeBroadcaster
|
||||
stdin io.ReadCloser
|
||||
stdinPipe io.WriteCloser
|
||||
SysInitPath string
|
||||
ResolvConfPath string
|
||||
|
||||
cmd *exec.Cmd
|
||||
stdout *writeBroadcaster
|
||||
stderr *writeBroadcaster
|
||||
stdin io.ReadCloser
|
||||
stdinPipe io.WriteCloser
|
||||
ptyMaster io.Closer
|
||||
|
||||
runtime *Runtime
|
||||
@@ -61,6 +62,7 @@ type Config struct {
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string
|
||||
Cmd []string
|
||||
Dns []string
|
||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||
}
|
||||
|
||||
@@ -79,12 +81,20 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
||||
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
||||
|
||||
if *flMemory > 0 && NO_MEMORY_LIMIT {
|
||||
fmt.Fprintf(stdout, "WARNING: This version of docker has been compiled without memory limit support. Discarding -m.")
|
||||
*flMemory = 0
|
||||
}
|
||||
|
||||
var flPorts ListOpts
|
||||
cmd.Var(&flPorts, "p", "Expose a container's port to the host (use 'docker port' to see the actual mapping)")
|
||||
|
||||
var flEnv ListOpts
|
||||
cmd.Var(&flEnv, "e", "Set environment variables")
|
||||
|
||||
var flDns ListOpts
|
||||
cmd.Var(&flDns, "dns", "Set custom dns servers")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,6 +132,7 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||
AttachStderr: flAttach.Get("stderr"),
|
||||
Env: flEnv,
|
||||
Cmd: runCmd,
|
||||
Dns: flDns,
|
||||
Image: image,
|
||||
}
|
||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||
@@ -355,6 +366,12 @@ func (container *Container) Start() error {
|
||||
if err := container.allocateNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if container.Config.Memory > 0 && NO_MEMORY_LIMIT {
|
||||
log.Printf("WARNING: This version of docker has been compiled without memory limit support. Discarding the limit.")
|
||||
container.Config.Memory = 0
|
||||
}
|
||||
|
||||
if err := container.generateLXCConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -373,21 +390,26 @@ func (container *Container) Start() error {
|
||||
params = append(params, "-u", container.Config.User)
|
||||
}
|
||||
|
||||
if container.Config.Tty {
|
||||
params = append(params, "-e", "TERM=xterm")
|
||||
}
|
||||
|
||||
// Setup environment
|
||||
params = append(params,
|
||||
"-e", "HOME=/",
|
||||
"-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
)
|
||||
|
||||
for _, elem := range container.Config.Env {
|
||||
params = append(params, "-e", elem)
|
||||
}
|
||||
|
||||
// Program
|
||||
params = append(params, "--", container.Path)
|
||||
params = append(params, container.Args...)
|
||||
|
||||
container.cmd = exec.Command("lxc-start", params...)
|
||||
|
||||
// Setup environment
|
||||
container.cmd.Env = append(
|
||||
[]string{
|
||||
"HOME=/",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
},
|
||||
container.Config.Env...,
|
||||
)
|
||||
|
||||
// Setup logging of stdout and stderr to disk
|
||||
if err := container.runtime.LogToDisk(container.stdout, container.logPath("stdout")); err != nil {
|
||||
return err
|
||||
@@ -398,10 +420,6 @@ func (container *Container) Start() error {
|
||||
|
||||
var err error
|
||||
if container.Config.Tty {
|
||||
container.cmd.Env = append(
|
||||
[]string{"TERM=xterm"},
|
||||
container.cmd.Env...,
|
||||
)
|
||||
err = container.startPty()
|
||||
} else {
|
||||
err = container.start()
|
||||
@@ -550,9 +568,21 @@ func (container *Container) kill() error {
|
||||
if !container.State.Running || container.cmd == nil {
|
||||
return nil
|
||||
}
|
||||
if err := container.cmd.Process.Kill(); err != nil {
|
||||
return err
|
||||
|
||||
// Sending SIGKILL to the process via lxc
|
||||
output, err := exec.Command("lxc-kill", "-n", container.Id, "9").CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("error killing container %s (%s, %s)", container.Id, output, err)
|
||||
}
|
||||
|
||||
// 2. Wait for the process to die, in last resort, try to kill the process directly
|
||||
if err := container.WaitTimeout(10 * time.Second); err != nil {
|
||||
log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.Id)
|
||||
if err := container.cmd.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the container to be actually stopped
|
||||
container.Wait()
|
||||
return nil
|
||||
@@ -561,6 +591,12 @@ func (container *Container) kill() error {
|
||||
func (container *Container) Kill() error {
|
||||
container.State.lock()
|
||||
defer container.State.unlock()
|
||||
if !container.State.Running {
|
||||
return nil
|
||||
}
|
||||
if container.State.Ghost {
|
||||
return fmt.Errorf("Can't kill ghost container")
|
||||
}
|
||||
return container.kill()
|
||||
}
|
||||
|
||||
@@ -570,6 +606,9 @@ func (container *Container) Stop() error {
|
||||
if !container.State.Running {
|
||||
return nil
|
||||
}
|
||||
if container.State.Ghost {
|
||||
return fmt.Errorf("Can't stop ghot container")
|
||||
}
|
||||
|
||||
// 1. Send a SIGTERM
|
||||
if output, err := exec.Command("lxc-kill", "-n", container.Id, "15").CombinedOutput(); err != nil {
|
||||
|
||||
@@ -324,6 +324,54 @@ func TestOutput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestKillDifferentUser(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
container, err := runtime.Create(&Config{
|
||||
Image: GetTestImage(runtime).Id,
|
||||
Cmd: []string{"tail", "-f", "/etc/resolv.conf"},
|
||||
User: "daemon",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if container.State.Running {
|
||||
t.Errorf("Container shouldn't be running")
|
||||
}
|
||||
if err := container.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Give some time to lxc to spawn the process (setuid might take some time)
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
|
||||
if !container.State.Running {
|
||||
t.Errorf("Container should be running")
|
||||
}
|
||||
|
||||
if err := container.Kill(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if container.State.Running {
|
||||
t.Errorf("Container shouldn't be running")
|
||||
}
|
||||
container.Wait()
|
||||
if container.State.Running {
|
||||
t.Errorf("Container shouldn't be running")
|
||||
}
|
||||
// Try stopping twice
|
||||
if err := container.Kill(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKill(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
@@ -346,6 +394,10 @@ func TestKill(t *testing.T) {
|
||||
if err := container.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Give some time to lxc to spawn the process
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
|
||||
if !container.State.Running {
|
||||
t.Errorf("Container should be running")
|
||||
}
|
||||
@@ -657,6 +709,10 @@ func TestMultipleContainers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Make sure they are running before trying to kill them
|
||||
container1.WaitTimeout(250 * time.Millisecond)
|
||||
container2.WaitTimeout(250 * time.Millisecond)
|
||||
|
||||
// If we are here, both containers should be running
|
||||
if !container1.State.Running {
|
||||
t.Fatal("Container not running")
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DOCKER_PATH = "/home/creack/dotcloud/docker/docker/docker"
|
||||
|
||||
func runDaemon() (*exec.Cmd, error) {
|
||||
os.Remove("/var/run/docker.pid")
|
||||
cmd := exec.Command(DOCKER_PATH, "-d")
|
||||
outPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
errPipe, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
io.Copy(os.Stdout, outPipe)
|
||||
}()
|
||||
go func() {
|
||||
io.Copy(os.Stderr, errPipe)
|
||||
}()
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func crashTest() error {
|
||||
if err := exec.Command("/bin/bash", "-c", "while true; do true; done").Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
daemon, err := runDaemon()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// time.Sleep(5000 * time.Millisecond)
|
||||
var stop bool
|
||||
go func() error {
|
||||
stop = false
|
||||
for i := 0; i < 100 && !stop; i++ {
|
||||
func() error {
|
||||
cmd := exec.Command(DOCKER_PATH, "run", "base", "echo", "hello", "world")
|
||||
log.Printf("%d", i)
|
||||
outPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inPipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
io.Copy(os.Stdout, outPipe)
|
||||
}()
|
||||
// Expecting error, do not check
|
||||
inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
||||
inPipe.Close()
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
outPipe.Close()
|
||||
return nil
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
time.Sleep(20 * time.Second)
|
||||
stop = true
|
||||
if err := daemon.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := crashTest(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
# docker-build: build your software with docker
|
||||
|
||||
## Description
|
||||
|
||||
docker-build is a script to build docker images from source. It will be deprecated once the 'build' feature is incorporated into docker itself (See https://github.com/dotcloud/docker/issues/278)
|
||||
|
||||
Author: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
docker-builder requires:
|
||||
|
||||
1) A reasonably recent Python setup (tested on 2.7.2).
|
||||
|
||||
2) A running docker daemon at version 0.1.4 or more recent (http://www.docker.io/gettingstarted)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
First create a valid Changefile, which defines a sequence of changes to apply to a base image.
|
||||
|
||||
$ cat Changefile
|
||||
# Start build from a know base image
|
||||
from base:ubuntu-12.10
|
||||
# Update ubuntu sources
|
||||
run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
# Install system packages
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# Insert files from the host (./myscript must be present in the current directory)
|
||||
copy myscript /usr/local/bin/myscript
|
||||
|
||||
|
||||
Run docker-build, and pass the contents of your Changefile as standard input.
|
||||
|
||||
$ IMG=$(./docker-build < Changefile)
|
||||
|
||||
This will take a while: for each line of the changefile, docker-build will:
|
||||
|
||||
1. Create a new container to execute the given command or insert the given file
|
||||
2. Wait for the container to complete execution
|
||||
3. Commit the resulting changes as a new image
|
||||
4. Use the resulting image as the input of the next step
|
||||
|
||||
|
||||
If all the steps succeed, the result will be an image containing the combined results of each build step.
|
||||
You can trace back those build steps by inspecting the image's history:
|
||||
|
||||
$ docker history $IMG
|
||||
ID CREATED CREATED BY
|
||||
1e9e2045de86 A few seconds ago /bin/sh -c cat > /usr/local/bin/myscript; chmod +x /usr/local/bin/git
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
77db140aa62a A few seconds ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
83e85d155451 A few seconds ago /bin/sh -c apt-get update
|
||||
bfd53b36d9d3 A few seconds ago /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
base 2 weeks ago /bin/bash
|
||||
27cf78414709 2 weeks ago
|
||||
|
||||
|
||||
Note that your build started from 'base', as instructed by your Changefile. But that base image itself seems to have been built in 2 steps - hence the extra step in the history.
|
||||
|
||||
|
||||
You can use this build technique to create any image you want: a database, a web application, or anything else that can be build by a sequence of unix commands - in other words, anything else.
|
||||
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# docker-build is a script to build docker images from source.
|
||||
# It will be deprecated once the 'build' feature is incorporated into docker itself.
|
||||
# (See https://github.com/dotcloud/docker/issues/278)
|
||||
#
|
||||
# Author: Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
|
||||
|
||||
# First create a valid Changefile, which defines a sequence of changes to apply to a base image.
|
||||
#
|
||||
# $ cat Changefile
|
||||
# # Start build from a know base image
|
||||
# from base:ubuntu-12.10
|
||||
# # Update ubuntu sources
|
||||
# run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
# run apt-get update
|
||||
# # Install system packages
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
# run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# # Insert files from the host (./myscript must be present in the current directory)
|
||||
# copy myscript /usr/local/bin/myscript
|
||||
#
|
||||
#
|
||||
# Run docker-build, and pass the contents of your Changefile as standard input.
|
||||
#
|
||||
# $ IMG=$(./docker-build < Changefile)
|
||||
#
|
||||
# This will take a while: for each line of the changefile, docker-build will:
|
||||
#
|
||||
# 1. Create a new container to execute the given command or insert the given file
|
||||
# 2. Wait for the container to complete execution
|
||||
# 3. Commit the resulting changes as a new image
|
||||
# 4. Use the resulting image as the input of the next step
|
||||
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
def docker(args, stdin=None):
|
||||
print "# docker " + " ".join(args)
|
||||
p = subprocess.Popen(["docker"] + list(args), stdin=stdin, stdout=subprocess.PIPE)
|
||||
return p.stdout
|
||||
|
||||
def image_exists(img):
|
||||
return docker(["inspect", img]).read().strip() != ""
|
||||
|
||||
def run_and_commit(img_in, cmd, stdin=None):
|
||||
run_id = docker(["run"] + (["-i", "-a", "stdin"] if stdin else ["-d"]) + [img_in, "/bin/sh", "-c", cmd], stdin=stdin).read().rstrip()
|
||||
print "---> Waiting for " + run_id
|
||||
result=int(docker(["wait", run_id]).read().rstrip())
|
||||
if result != 0:
|
||||
print "!!! '{}' return non-zero exit code '{}'. Aborting.".format(cmd, result)
|
||||
sys.exit(1)
|
||||
return docker(["commit", run_id]).read().rstrip()
|
||||
|
||||
def insert(base, src, dst):
|
||||
print "COPY {} to {} in {}".format(src, dst, base)
|
||||
if dst == "":
|
||||
raise Exception("Missing destination path")
|
||||
stdin = file(src)
|
||||
stdin.seek(0)
|
||||
return run_and_commit(base, "cat > {0}; chmod +x {0}".format(dst), stdin=stdin)
|
||||
|
||||
|
||||
def main():
|
||||
base=""
|
||||
steps = []
|
||||
try:
|
||||
for line in sys.stdin.readlines():
|
||||
line = line.strip()
|
||||
# Skip comments and empty lines
|
||||
if line == "" or line[0] == "#":
|
||||
continue
|
||||
op, param = line.split(" ", 1)
|
||||
if op == "from":
|
||||
print "FROM " + param
|
||||
base = param
|
||||
steps.append(base)
|
||||
elif op == "run":
|
||||
print "RUN " + param
|
||||
result = run_and_commit(base, param)
|
||||
steps.append(result)
|
||||
base = result
|
||||
print "===> " + base
|
||||
elif op == "copy":
|
||||
src, dst = param.split(" ", 1)
|
||||
result = insert(base, src, dst)
|
||||
steps.append(result)
|
||||
base = result
|
||||
print "===> " + base
|
||||
else:
|
||||
print "Skipping uknown op " + op
|
||||
except:
|
||||
docker(["rmi"] + steps)
|
||||
raise
|
||||
print base
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,11 @@
|
||||
# Start build from a know base image
|
||||
from base:ubuntu-12.10
|
||||
# Update ubuntu sources
|
||||
run echo 'deb http://archive.ubuntu.com/ubuntu quantal main universe multiverse' > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
# Install system packages
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl
|
||||
run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang
|
||||
# Insert files from the host (./myscript must be present in the current directory)
|
||||
copy myscript /usr/local/bin/myscript
|
||||
+1
-1
@@ -45,7 +45,7 @@ then
|
||||
echo "Upstart script already exists."
|
||||
else
|
||||
echo "Creating /etc/init/dockerd.conf..."
|
||||
echo "exec /usr/local/bin/docker -d" > /etc/init/dockerd.conf
|
||||
echo "exec env LANG=\"en_US.UTF-8\" /usr/local/bin/docker -d" > /etc/init/dockerd.conf
|
||||
fi
|
||||
|
||||
echo "Starting dockerd..."
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../Makefile
|
||||
@@ -1 +0,0 @@
|
||||
../README.md
|
||||
@@ -1,5 +0,0 @@
|
||||
dotcloud-docker (1) precise; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- dotCloud <ops@dotcloud.com> Mon, 14 Mar 2013 04:43:21 -0700
|
||||
@@ -1,10 +0,0 @@
|
||||
description "Run docker"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on starting rc RUNLEVEL=[016]
|
||||
respawn
|
||||
|
||||
script
|
||||
test -f /etc/default/locale && . /etc/default/locale || true
|
||||
LANG=$LANG LC_ALL=$LANG /usr/bin/docker -d
|
||||
end script
|
||||
+51
-12
@@ -2,15 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/rcli"
|
||||
"github.com/dotcloud/docker/term"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var GIT_COMMIT string
|
||||
var (
|
||||
GIT_COMMIT string
|
||||
NO_MEMORY_LIMIT string
|
||||
)
|
||||
|
||||
func main() {
|
||||
if docker.SelfPath() == "/sbin/init" {
|
||||
@@ -22,6 +28,7 @@ func main() {
|
||||
flDaemon := flag.Bool("d", false, "Daemon mode")
|
||||
flDebug := flag.Bool("D", false, "Debug mode")
|
||||
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
|
||||
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
|
||||
flag.Parse()
|
||||
if *bridgeName != "" {
|
||||
docker.NetworkBridgeIface = *bridgeName
|
||||
@@ -32,12 +39,16 @@ func main() {
|
||||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
docker.GIT_COMMIT = GIT_COMMIT
|
||||
docker.NO_MEMORY_LIMIT = NO_MEMORY_LIMIT == "1"
|
||||
if *flDaemon {
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if err := daemon(); err != nil {
|
||||
if NO_MEMORY_LIMIT == "1" {
|
||||
log.Printf("WARNING: This version of docker has been compiled without memory limit support.")
|
||||
}
|
||||
if err := daemon(*pidfile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
@@ -47,7 +58,43 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func daemon() error {
|
||||
func createPidFile(pidfile string) error {
|
||||
if _, err := os.Stat(pidfile); err == nil {
|
||||
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
||||
}
|
||||
|
||||
file, err := os.Create(pidfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = fmt.Fprintf(file, "%d", os.Getpid())
|
||||
return err
|
||||
}
|
||||
|
||||
func removePidFile(pidfile string) {
|
||||
if err := os.Remove(pidfile); err != nil {
|
||||
log.Printf("Error removing %s: %s", pidfile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func daemon(pidfile string) error {
|
||||
if err := createPidFile(pidfile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer removePidFile(pidfile)
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Printf("Received signal '%v', exiting\n", sig)
|
||||
removePidFile(pidfile)
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
service, err := docker.NewServer()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -91,15 +138,7 @@ func runCommand(args []string) error {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
service, err := docker.NewServer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dockerConn := rcli.NewDockerLocalConn(os.Stdout)
|
||||
defer dockerConn.Close()
|
||||
if err := rcli.LocalCall(service, os.Stdin, dockerConn, args...); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,4 +16,5 @@ Contents:
|
||||
hello_world
|
||||
hello_world_daemon
|
||||
python_web_app
|
||||
running_redis_service
|
||||
running_ssh_service
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
:title: Running a Redis service
|
||||
:description: Installing and running an redis service
|
||||
:keywords: docker, example, package installation, networking, redis
|
||||
|
||||
.. _running_redis_service:
|
||||
|
||||
Create a redis service
|
||||
======================
|
||||
|
||||
.. include:: example_header.inc
|
||||
|
||||
Very simple, no frills, redis service.
|
||||
|
||||
Open a docker container
|
||||
-----------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -i -t base /bin/bash
|
||||
|
||||
Building your image
|
||||
-------------------
|
||||
|
||||
Update your docker container, install the redis server. Once installed, exit out of docker.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get update
|
||||
apt-get install redis-server
|
||||
exit
|
||||
|
||||
Snapshot the installation
|
||||
-------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps -a # grab the container id (this will be the last one in the list)
|
||||
docker commit <container_id> <your username>/redis
|
||||
|
||||
Run the service
|
||||
---------------
|
||||
|
||||
Running the service with `-d` runs the container in detached mode, leaving the
|
||||
container running in the background. Use your snapshot.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -d -p 6379 <your username>/redis /usr/bin/redis-server
|
||||
|
||||
Test 1
|
||||
++++++
|
||||
|
||||
Connect to the container with the redis-cli.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps # grab the new container id
|
||||
docker inspect <container_id> # grab the ipaddress of the container
|
||||
redis-cli -h <ipaddress> -p 6379
|
||||
redis 10.0.3.32:6379> set docker awesome
|
||||
OK
|
||||
redis 10.0.3.32:6379> get docker
|
||||
"awesome"
|
||||
redis 10.0.3.32:6379> exit
|
||||
|
||||
Test 2
|
||||
++++++
|
||||
|
||||
Connect to the host os with the redis-cli.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker ps # grab the new container id
|
||||
docker port <container_id> 6379 # grab the external port
|
||||
ifconfig # grab the host ip address
|
||||
redis-cli -h <host ipaddress> -p <external port>
|
||||
redis 192.168.0.1:49153> set docker awesome
|
||||
OK
|
||||
redis 192.168.0.1:49153> get docker
|
||||
"awesome"
|
||||
redis 192.168.0.1:49153> exit
|
||||
@@ -0,0 +1,43 @@
|
||||
.. _arch_linux:
|
||||
|
||||
Arch Linux
|
||||
==========
|
||||
|
||||
Installing on Arch Linux is not officially supported but can be handled via
|
||||
either of the following AUR packages:
|
||||
|
||||
* `dotcloud-docker <https://aur.archlinux.org/packages/dotcloud-docker/>`_
|
||||
* `dotcloud-docker-git <https://aur.archlinux.org/packages/dotcloud-docker-git/>`_
|
||||
|
||||
The dotcloud-docker package will install the latest tagged version of docker.
|
||||
The dotcloud-docker-git package will build from the current master branch.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
Docker depends on several packages which will be installed automatically with
|
||||
either AUR package.
|
||||
|
||||
* aufs3
|
||||
* bridge-utils
|
||||
* go
|
||||
* iproute2
|
||||
* linux-aufs_friendly
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The instructions here assume **yaourt** is installed. See
|
||||
`Arch User Repository <https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages>`_
|
||||
for information on building and installing packages from the AUR if you have not
|
||||
done so before.
|
||||
|
||||
Keep in mind that if **linux-aufs_friendly** is not already installed that a
|
||||
new kernel will be compiled and this can take quite a while.
|
||||
|
||||
::
|
||||
|
||||
yaourt -S dotcloud-docker-git
|
||||
|
||||
Prior to starting docker modify your bootloader to use the
|
||||
**linux-aufs_friendly** kernel and reboot your system.
|
||||
@@ -13,6 +13,7 @@ Contents:
|
||||
:maxdepth: 1
|
||||
|
||||
ubuntulinux
|
||||
archlinux
|
||||
macos
|
||||
windows
|
||||
amazon
|
||||
|
||||
@@ -111,7 +111,7 @@ func (graph *Graph) Register(layerData Archive, img *Image) error {
|
||||
if graph.Exists(img.Id) {
|
||||
return fmt.Errorf("Image %s already exists", img.Id)
|
||||
}
|
||||
tmp, err := graph.Mktemp(img.Id)
|
||||
tmp, err := graph.Mktemp("")
|
||||
defer os.RemoveAll(tmp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Mktemp failed: %s", err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package docker
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -26,6 +27,32 @@ func TestInit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Register can be interrupted cleanly without side effects
|
||||
func TestInterruptedRegister(t *testing.T) {
|
||||
graph := tempGraph(t)
|
||||
defer os.RemoveAll(graph.Root)
|
||||
badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
|
||||
image := &Image{
|
||||
Id: GenerateId(),
|
||||
Comment: "testing",
|
||||
Created: time.Now(),
|
||||
}
|
||||
go graph.Register(badArchive, image)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
w.CloseWithError(errors.New("But I'm not a tarball!")) // (Nobody's perfect, darling)
|
||||
if _, err := graph.Get(image.Id); err == nil {
|
||||
t.Fatal("Image should not exist after Register is interrupted")
|
||||
}
|
||||
// Registering the same image again should succeed if the first register was interrupted
|
||||
goodArchive, err := fakeTar()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := graph.Register(goodArchive, image); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Do more extensive tests (ex: create multiple, delete, recreate;
|
||||
// create multiple, check the amount of images and paths, etc..)
|
||||
func TestGraphCreate(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This directory contains material helpful for hacking on docker.
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This pre-commit hook will abort if a committed file doesn't pass gofmt.
|
||||
# By Even Shaw <edsrzf@gmail.com>
|
||||
# http://github.com/edsrzf/gofmt-git-hook
|
||||
|
||||
test_fmt() {
|
||||
hash gofmt 2>&- || { echo >&2 "gofmt not in PATH."; exit 1; }
|
||||
IFS='
|
||||
'
|
||||
for file in `git diff --cached --name-only --diff-filter=ACM | grep '\.go$'`
|
||||
do
|
||||
output=`git cat-file -p :$file | gofmt -l 2>&1`
|
||||
if test $? -ne 0
|
||||
then
|
||||
output=`echo "$output" | sed "s,<standard input>,$file,"`
|
||||
syntaxerrors="${list}${output}\n"
|
||||
elif test -n "$output"
|
||||
then
|
||||
list="${list}${file}\n"
|
||||
fi
|
||||
done
|
||||
exitcode=0
|
||||
if test -n "$syntaxerrors"
|
||||
then
|
||||
echo >&2 "gofmt found syntax errors:"
|
||||
printf "$syntaxerrors"
|
||||
exitcode=1
|
||||
fi
|
||||
if test -n "$list"
|
||||
then
|
||||
echo >&2 "gofmt needs to format these files (run gofmt -w and git add):"
|
||||
printf "$list"
|
||||
exitcode=1
|
||||
fi
|
||||
exit $exitcode
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
--about )
|
||||
echo "Check Go code formatting"
|
||||
;;
|
||||
* )
|
||||
test_fmt
|
||||
;;
|
||||
esac
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -92,7 +94,19 @@ func MountAUFS(ro []string, rw string, target string) error {
|
||||
roBranches += fmt.Sprintf("%v=ro:", layer)
|
||||
}
|
||||
branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
|
||||
return mount("none", target, "aufs", 0, branches)
|
||||
|
||||
//if error, try to load aufs kernel module
|
||||
if err := mount("none", target, "aufs", 0, branches); err != nil {
|
||||
log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
|
||||
if err := exec.Command("modprobe", "aufs").Run(); err != nil {
|
||||
return fmt.Errorf("Unable to load the AUFS module")
|
||||
}
|
||||
log.Printf("...module loaded.")
|
||||
if err := mount("none", target, "aufs", 0, branches); err != nil {
|
||||
return fmt.Errorf("Unable to mount using aufs")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (image *Image) Mount(root, rw string) error {
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ lxc.mount.entry = devpts {{$ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,no
|
||||
lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/sbin/init none bind,ro 0 0
|
||||
|
||||
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
|
||||
lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
||||
lxc.mount.entry = {{.ResolvConfPath}} {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
||||
|
||||
|
||||
# drop linux capabilities (apply mainly to the user root in the container)
|
||||
|
||||
+1
-1
@@ -293,7 +293,7 @@ func (alloc *PortAllocator) Acquire(port int) (int, error) {
|
||||
|
||||
func newPortAllocator() (*PortAllocator, error) {
|
||||
allocator := &PortAllocator{
|
||||
inUse: make(map[int]struct{}),
|
||||
inUse: make(map[int]struct{}),
|
||||
fountain: make(chan int),
|
||||
}
|
||||
go allocator.runFountain()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Docker packaging
|
||||
================
|
||||
|
||||
This directory has one subdirectory per packaging distribution.
|
||||
At minimum, each of these subdirectories should contain a
|
||||
README.$DISTRIBUTION explaining how to create the native
|
||||
docker package and how to install it.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
PKG_NAME=lxc-docker
|
||||
DOCKER_VERSION=$(shell head -1 changelog | awk 'match($$0, /\(.+\)/) {print substr($$0, RSTART+1, RLENGTH-4)}')
|
||||
GITHUB_PATH=github.com/dotcloud/docker
|
||||
SOURCE_PKG=$(PKG_NAME)_$(DOCKER_VERSION).orig.tar.gz
|
||||
BUILD_SRC=${CURDIR}/../../build_src
|
||||
|
||||
all:
|
||||
# Compile docker. Used by debian dpkg-buildpackage.
|
||||
cd src/${GITHUB_PATH}/docker; GOPATH=${CURDIR} go build
|
||||
|
||||
install:
|
||||
# Used by debian dpkg-buildpackage
|
||||
mkdir -p $(DESTDIR)/usr/bin
|
||||
mkdir -p $(DESTDIR)/etc/init.d
|
||||
install -m 0755 src/${GITHUB_PATH}/docker/docker $(DESTDIR)/usr/bin
|
||||
install -o root -m 0755 debian/docker.initd $(DESTDIR)/etc/init.d/docker
|
||||
|
||||
debian:
|
||||
# This Makefile will compile the github master branch of dotcloud/docker
|
||||
# Retrieve docker project and its go structure from internet
|
||||
rm -rf ${BUILD_SRC}
|
||||
GOPATH=${BUILD_SRC} go get ${GITHUB_PATH}
|
||||
# Add debianization
|
||||
mkdir ${BUILD_SRC}/debian
|
||||
cp Makefile ${BUILD_SRC}
|
||||
cp -r * ${BUILD_SRC}/debian
|
||||
cp ../../README.md ${BUILD_SRC}
|
||||
# Cleanup
|
||||
for d in `find ${BUILD_SRC} -name '.git*'`; do rm -rf $$d; done
|
||||
rm -rf ${BUILD_SRC}/../${SOURCE_PKG}
|
||||
rm -rf ${BUILD_SRC}/pkg
|
||||
# Create docker debian files
|
||||
cd ${BUILD_SRC}; tar czf ../${SOURCE_PKG} .
|
||||
cd ${BUILD_SRC}; dpkg-buildpackage
|
||||
rm -rf ${BUILD_SRC}
|
||||
@@ -0,0 +1,31 @@
|
||||
Docker on Debian
|
||||
================
|
||||
|
||||
Docker has been built and tested on Wheezy. All docker functionality works
|
||||
out of the box, except for memory limitation as the stock debian kernel
|
||||
does not support it yet.
|
||||
|
||||
|
||||
Building docker package
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Building Dependencies: debhelper, autotools-dev and golang
|
||||
|
||||
|
||||
Assuming you have a wheezy system up and running
|
||||
|
||||
# Download a fresh copy of the docker project
|
||||
git clone https://github.com/dotcloud/docker.git
|
||||
cd docker
|
||||
|
||||
# Get building dependencies
|
||||
sudo apt-get update ; sudo apt-get install -y debhelper autotools-dev golang
|
||||
|
||||
# Make the debian package, with no memory limitation support
|
||||
(cd packaging/debian; make debian NO_MEMORY_LIMIT=1)
|
||||
|
||||
|
||||
Install docker package
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sudo dpkg -i lxc-docker_0.1.4-1_amd64.deb; sudo apt-get install -f -y
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
$BUILDBOT_IP = '192.168.33.31'
|
||||
|
||||
def v10(config)
|
||||
config.vm.box = 'debian'
|
||||
config.vm.share_folder 'v-data', '/data/docker', File.dirname(__FILE__) + '/../..'
|
||||
config.vm.network :hostonly, $BUILDBOT_IP
|
||||
|
||||
# Install debian packaging dependencies and create debian packages
|
||||
config.vm.provision :shell, :inline => 'apt-get -qq update; apt-get install -y debhelper autotools-dev golang'
|
||||
config.vm.provision :shell, :inline => 'cd /data/docker/packaging/debian; make debian'
|
||||
end
|
||||
|
||||
Vagrant::VERSION < '1.1.0' and Vagrant::Config.run do |config|
|
||||
v10(config)
|
||||
end
|
||||
|
||||
Vagrant::VERSION >= '1.1.0' and Vagrant.configure('1') do |config|
|
||||
v10(config)
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
lxc-docker (0.1.4-1) unstable; urgency=low
|
||||
|
||||
Improvements [+], Updates [*], Bug fixes [-]:
|
||||
* Changed default bridge interface do 'docker0'
|
||||
- Fix a race condition when running the port allocator
|
||||
|
||||
-- Daniel Mizyrycki <daniel@dotcloud.com> Wed, 10 Apr 2013 18:06:21 -0700
|
||||
|
||||
|
||||
lxc-docker (0.1.0-1) unstable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Daniel Mizyrycki <daniel@dotcloud.com> Mon, 29 Mar 2013 18:09:55 -0700
|
||||
@@ -0,0 +1 @@
|
||||
9
|
||||
@@ -0,0 +1,19 @@
|
||||
Source: lxc-docker
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Daniel Mizyrycki <daniel@dotcloud.com>
|
||||
Build-Depends: debhelper (>= 9),autotools-dev,golang
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://github.com/dotcloud/docker
|
||||
|
||||
Package: lxc-docker
|
||||
Architecture: linux-any
|
||||
Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar
|
||||
Conflicts: docker
|
||||
Description: lxc-docker is a Linux container runtime
|
||||
Docker complements LXC with a high-level API which operates at the process
|
||||
level. It runs unix processes with strong guarantees of isolation and
|
||||
repeatability across servers.
|
||||
Docker is a great building block for automating distributed systems:
|
||||
large-scale web deployments, database clusters, continuous deployment systems,
|
||||
private PaaS, service-oriented architectures, etc.
|
||||
@@ -0,0 +1,237 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: docker
|
||||
Upstream-Contact: DotCloud Inc <opensource@dotcloud.com>
|
||||
Source: http://github.com/dotcloud/docker
|
||||
|
||||
Files: *
|
||||
Copyright: 2012, DotCloud Inc <opensource@dotcloud.com>
|
||||
License: Apache-2.0
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2012 DotCloud Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Files: src/github.com/kr/pty/*
|
||||
Copyright: Copyright (c) 2011 Keith Rarick
|
||||
License: Expat
|
||||
Copyright (c) 2011 Keith Rarick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall
|
||||
be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: docker
|
||||
# Required-Start: $local_fs
|
||||
# Required-Stop: $local_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: docker
|
||||
# Description: docker daemon
|
||||
### END INIT INFO
|
||||
|
||||
DOCKER=/usr/bin/docker
|
||||
PIDFILE=/var/run/docker.pid
|
||||
|
||||
# Check docker is present
|
||||
[ -x $DOCKER ] || log_success_msg "Docker not present"
|
||||
|
||||
# Get lsb functions
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_begin_msg "Starting docker..."
|
||||
start-stop-daemon --start --background --exec "$DOCKER" -- -d
|
||||
log_end_msg $?
|
||||
;;
|
||||
stop)
|
||||
log_begin_msg "Stopping docker..."
|
||||
docker_pid=`pgrep -f "$DOCKER -d"`
|
||||
[ -n "$docker_pid" ] && kill $docker_pid
|
||||
log_end_msg $?
|
||||
;;
|
||||
status)
|
||||
docker_pid=`pgrep -f "$DOCKER -d"`
|
||||
if [ -z "$docker_pid" ] ; then
|
||||
echo "docker not running"
|
||||
else
|
||||
echo "docker running (pid $docker_pid)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/docker {start|stop|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Ensure cgroup is mounted
|
||||
if [ -z "`/bin/egrep -e '^cgroup' /etc/fstab`" ]; then
|
||||
/bin/echo 'cgroup /sys/fs/cgroup cgroup defaults 0 0' >>/etc/fstab
|
||||
fi
|
||||
if [ -z "`/bin/mount | /bin/egrep -e '^cgroup'`" ]; then
|
||||
/bin/mount /sys/fs/cgroup
|
||||
fi
|
||||
|
||||
# Start docker
|
||||
/usr/sbin/update-rc.d docker defaults
|
||||
/etc/init.d/docker start
|
||||
@@ -0,0 +1,16 @@
|
||||
Maintainer duty
|
||||
===============
|
||||
|
||||
The Debian project specifies the role of a 'maintainer' which is the person
|
||||
making the Debian package of the program. This role requires an 'sponsor' to
|
||||
upload the package. As a maintainer you should follow the guide
|
||||
http://www.debian.org/doc/manuals/maint-guide . Your sponsor will be there
|
||||
helping you succeed.
|
||||
|
||||
The most relevant information to update is the changelog file:
|
||||
Each new release should create a new first paragraph with new release version,
|
||||
changes, and the maintainer information.
|
||||
|
||||
After this is done, follow README.debian to generate the actual source
|
||||
packages and talk with your sponsor to upload them into the official Debian
|
||||
package archive.
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
%:
|
||||
dh ${@} --with autotools_dev
|
||||
@@ -1,4 +1,4 @@
|
||||
PKG_NAME=dotcloud-docker
|
||||
PKG_NAME=lxc-docker
|
||||
PKG_ARCH=amd64
|
||||
PKG_VERSION=1
|
||||
ROOT_PATH:=$(PWD)
|
||||
@@ -0,0 +1,5 @@
|
||||
lxc-docker (1) precise; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- dotCloud <ops@dotcloud.com> Mon, 25 Mar 2013 05:51:12 -0700
|
||||
@@ -1,16 +1,15 @@
|
||||
Source: dotcloud-docker
|
||||
Source: lxc-docker
|
||||
Section: misc
|
||||
Priority: extra
|
||||
Homepage: https://github.com/dotcloud/docker
|
||||
Homepage: http://docker.io
|
||||
Maintainer: Daniel Mizyrycki <daniel@dotcloud.com>
|
||||
Build-Depends: debhelper (>= 8.0.0), git, golang
|
||||
Vcs-Git: https://github.com/dotcloud/docker.git
|
||||
Standards-Version: 3.9.2
|
||||
Build-Depends: debhelper (>= 8.0.0), pkg-config, git, golang, libsqlite3-dev
|
||||
Vcs-Git: http://github.com/dotcloud/docker.git
|
||||
Standards-Version: 3.9.3
|
||||
|
||||
Package: dotcloud-docker
|
||||
Package: lxc-docker
|
||||
Architecture: amd64
|
||||
Provides: dotcloud-docker
|
||||
Depends: lxc, wget, bsdtar, curl
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, wget, bsdtar, curl, sqlite3
|
||||
Conflicts: docker
|
||||
Description: A process manager with superpowers
|
||||
It encapsulates heterogeneous payloads in Standard Containers, and runs
|
||||
@@ -1,5 +1,5 @@
|
||||
Format: http://dep.debian.net/deps/dep5
|
||||
Upstream-Name: dotcloud-docker
|
||||
Upstream-Name: docker
|
||||
Source: https://github.com/dotcloud/docker
|
||||
|
||||
Files: *
|
||||
@@ -0,0 +1 @@
|
||||
README.md
|
||||
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
+3
-3
@@ -138,7 +138,8 @@ func ListenAndServe(proto, addr string, service Service) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
go func(conn DockerConn) {
|
||||
defer conn.Close()
|
||||
if DEBUG_FLAG {
|
||||
CLIENT_SOCKET = conn
|
||||
}
|
||||
@@ -146,8 +147,7 @@ func ListenAndServe(proto, addr string, service Service) error {
|
||||
log.Println("Error:", err.Error())
|
||||
fmt.Fprintln(conn, "Error:", err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
}(conn)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
+10
-10
@@ -97,7 +97,7 @@ func (graph *Graph) LookupRemoteImage(imgId string, authConfig *auth.AuthConfig)
|
||||
func (graph *Graph) getRemoteImage(stdout io.Writer, imgId string, authConfig *auth.AuthConfig) (*Image, Archive, error) {
|
||||
client := &http.Client{}
|
||||
|
||||
fmt.Fprintf(stdout, "Pulling %s metadata\n", imgId)
|
||||
fmt.Fprintf(stdout, "Pulling %s metadata\r\n", imgId)
|
||||
// Get the Json
|
||||
req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/json", nil)
|
||||
if err != nil {
|
||||
@@ -125,7 +125,7 @@ func (graph *Graph) getRemoteImage(stdout io.Writer, imgId string, authConfig *a
|
||||
img.Id = imgId
|
||||
|
||||
// Get the layer
|
||||
fmt.Fprintf(stdout, "Pulling %s fs layer\n", imgId)
|
||||
fmt.Fprintf(stdout, "Pulling %s fs layer\r\n", imgId)
|
||||
req, err = http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/layer", nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
||||
@@ -164,7 +164,7 @@ func (graph *Graph) PullImage(stdout io.Writer, imgId string, authConfig *auth.A
|
||||
func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, repositories *TagStore, authConfig *auth.AuthConfig) error {
|
||||
client := &http.Client{}
|
||||
|
||||
fmt.Fprintf(stdout, "Pulling repository %s\n", remote)
|
||||
fmt.Fprintf(stdout, "Pulling repository %s\r\n", remote)
|
||||
|
||||
var repositoryTarget string
|
||||
// If we are asking for 'root' repository, lookup on the Library's registry
|
||||
@@ -196,7 +196,7 @@ func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, re
|
||||
return err
|
||||
}
|
||||
for tag, rev := range t {
|
||||
fmt.Fprintf(stdout, "Pulling tag %s:%s\n", remote, tag)
|
||||
fmt.Fprintf(stdout, "Pulling tag %s:%s\r\n", remote, tag)
|
||||
if err = graph.PullImage(stdout, rev, authConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -223,7 +223,7 @@ func (graph *Graph) PushImage(stdout io.Writer, imgOrig *Image, authConfig *auth
|
||||
return fmt.Errorf("Error while retreiving the path for {%s}: %s", img.Id, err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(stdout, "Pushing %s metadata\n", img.Id)
|
||||
fmt.Fprintf(stdout, "Pushing %s metadata\r\n", img.Id)
|
||||
|
||||
// FIXME: try json with UTF8
|
||||
jsonData := strings.NewReader(string(jsonRaw))
|
||||
@@ -253,7 +253,7 @@ func (graph *Graph) PushImage(stdout io.Writer, imgOrig *Image, authConfig *auth
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(stdout, "Pushing %s fs layer\n", img.Id)
|
||||
fmt.Fprintf(stdout, "Pushing %s fs layer\r\n", img.Id)
|
||||
req2, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/layer", nil)
|
||||
req2.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
res2, err := client.Do(req2)
|
||||
@@ -375,15 +375,15 @@ func (graph *Graph) pushPrimitive(stdout io.Writer, remote, tag, imgId string, a
|
||||
// Check if the local impage exists
|
||||
img, err := graph.Get(imgId)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stdout, "Skipping tag %s:%s: %s does not exist\n", remote, tag, imgId)
|
||||
fmt.Fprintf(stdout, "Skipping tag %s:%s: %s does not exist\r\n", remote, tag, imgId)
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintf(stdout, "Pushing tag %s:%s\n", remote, tag)
|
||||
fmt.Fprintf(stdout, "Pushing tag %s:%s\r\n", remote, tag)
|
||||
// Push the image
|
||||
if err = graph.PushImage(stdout, img, authConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(stdout, "Registering tag %s:%s\n", remote, tag)
|
||||
fmt.Fprintf(stdout, "Registering tag %s:%s\r\n", remote, tag)
|
||||
// And then the tag
|
||||
if err = graph.pushTag(remote, imgId, tag, authConfig); err != nil {
|
||||
return err
|
||||
@@ -399,7 +399,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re
|
||||
return fmt.Errorf("Permission denied on repository %s\n", remote)
|
||||
}
|
||||
|
||||
fmt.Fprintf(stdout, "Pushing repository %s (%d tags)\n", remote, len(localRepo))
|
||||
fmt.Fprintf(stdout, "Pushing repository %s (%d tags)\r\n", remote, len(localRepo))
|
||||
// For each image within the repo, push them
|
||||
for tag, imgId := range localRepo {
|
||||
if err := graph.pushPrimitive(stdout, remote, tag, imgId, authConfig); err != nil {
|
||||
|
||||
+33
@@ -82,6 +82,7 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
|
||||
if config.Hostname == "" {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
|
||||
container := &Container{
|
||||
// FIXME: we should generate the ID here instead of receiving it as an argument
|
||||
Id: id,
|
||||
@@ -100,6 +101,24 @@ func (runtime *Runtime) Create(config *Config) (*Container, error) {
|
||||
if err := os.Mkdir(container.root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If custom dns exists, then create a resolv.conf for the container
|
||||
if len(config.Dns) > 0 {
|
||||
container.ResolvConfPath = path.Join(container.root, "resolv.conf")
|
||||
f, err := os.Create(container.ResolvConfPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
for _, dns := range config.Dns {
|
||||
if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
container.ResolvConfPath = "/etc/resolv.conf"
|
||||
}
|
||||
|
||||
// Step 2: save the container json
|
||||
if err := container.ToDisk(); err != nil {
|
||||
return nil, err
|
||||
@@ -119,6 +138,9 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
|
||||
if container.Id != id {
|
||||
return container, fmt.Errorf("Container %s is stored at %s", container.Id, id)
|
||||
}
|
||||
if container.State.Running {
|
||||
container.State.Ghost = true
|
||||
}
|
||||
if err := runtime.Register(container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -134,6 +156,9 @@ func (runtime *Runtime) Register(container *Container) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// init the wait lock
|
||||
container.waitLock = make(chan struct{})
|
||||
|
||||
// FIXME: if the container is supposed to be running but is not, auto restart it?
|
||||
// if so, then we need to restart monitor and init a new lock
|
||||
// If the container is supposed to be running, make sure of it
|
||||
@@ -150,6 +175,14 @@ func (runtime *Runtime) Register(container *Container) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the container is not running or just has been flagged not running
|
||||
// then close the wait lock chan (will be reset upon start)
|
||||
if !container.State.Running {
|
||||
close(container.waitLock)
|
||||
}
|
||||
|
||||
// Even if not running, we init the lock (prevents races in start/stop/kill)
|
||||
container.State.initLock()
|
||||
|
||||
container.runtime = runtime
|
||||
|
||||
+4
-12
@@ -12,12 +12,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// FIXME: this is no longer needed
|
||||
const testLayerPath string = "/var/lib/docker/docker-ut.tar"
|
||||
const unitTestImageName string = "docker-ut"
|
||||
|
||||
var unitTestStoreBase string
|
||||
var srv *Server
|
||||
const unitTestStoreBase string = "/var/lib/docker/unit-tests"
|
||||
|
||||
func nuke(runtime *Runtime) error {
|
||||
var wg sync.WaitGroup
|
||||
@@ -49,6 +46,8 @@ func layerArchive(tarfile string) (io.Reader, error) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
NO_MEMORY_LIMIT = os.Getenv("NO_MEMORY_LIMIT") == "1"
|
||||
|
||||
// Hack to run sys init during unit testing
|
||||
if SelfPath() == "/sbin/init" {
|
||||
SysInit()
|
||||
@@ -61,15 +60,8 @@ func init() {
|
||||
panic("docker tests needs to be run as root")
|
||||
}
|
||||
|
||||
// Create a temp directory
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
unitTestStoreBase = root
|
||||
|
||||
// Make it our Store root
|
||||
runtime, err := NewRuntimeFromDirectory(root)
|
||||
runtime, err := NewRuntimeFromDirectory(unitTestStoreBase)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -12,11 +12,15 @@ type State struct {
|
||||
ExitCode int
|
||||
StartedAt time.Time
|
||||
l *sync.Mutex
|
||||
Ghost bool
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the state
|
||||
func (s *State) String() string {
|
||||
if s.Running {
|
||||
if s.Ghost {
|
||||
return fmt.Sprintf("Ghost")
|
||||
}
|
||||
return fmt.Sprintf("Up %s", HumanDuration(time.Now().Sub(s.StartedAt)))
|
||||
}
|
||||
return fmt.Sprintf("Exit %d", s.ExitCode)
|
||||
|
||||
+6
-5
@@ -17,8 +17,7 @@ func setupNetworking(gw string) {
|
||||
if gw == "" {
|
||||
return
|
||||
}
|
||||
cmd := exec.Command("/sbin/route", "add", "default", "gw", gw)
|
||||
if err := cmd.Run(); err != nil {
|
||||
if _, err := ip("route", "add", "default", "via", gw); err != nil {
|
||||
log.Fatalf("Unable to set up networking: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -54,8 +53,7 @@ func changeUser(u string) {
|
||||
}
|
||||
|
||||
// Clear environment pollution introduced by lxc-start
|
||||
func cleanupEnv() {
|
||||
env := os.Environ()
|
||||
func cleanupEnv(env ListOpts) {
|
||||
os.Clearenv()
|
||||
for _, kv := range env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
@@ -92,10 +90,13 @@ func SysInit() {
|
||||
var u = flag.String("u", "", "username or uid")
|
||||
var gw = flag.String("g", "", "gateway address")
|
||||
|
||||
var flEnv ListOpts
|
||||
flag.Var(&flEnv, "e", "Set environment variables")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
cleanupEnv(flEnv)
|
||||
setupNetworking(*gw)
|
||||
cleanupEnv()
|
||||
changeUser(*u)
|
||||
executeProgram(flag.Arg(0), flag.Args())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user