From 8ff60ddef488b8145c6afc2711656c44a11c11a0 Mon Sep 17 00:00:00 2001 From: Don Spaulding Date: Thu, 21 Mar 2013 08:39:52 -0500 Subject: [PATCH 01/12] Typos in the README --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c1c155ac73..bc3b57ee71 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ Docker: the Linux container runtime =================================== -Docker complements LXC with a high-level API with operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers. +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. -Is is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc. +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. @@ -27,7 +27,7 @@ Notable features * Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremeley fast, memory-cheap and disk-cheap. -* Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval. +* Logging: the standard streams (stdout/stderr/stdin) of each process container are collected and logged for real-time or batch retrieval. * 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. @@ -195,10 +195,10 @@ Contribution guidelines We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it. -If your pull request is not accepted on the first try, don't be discouraged! If there's a problen with the implementation, hopefully you received feedback on what to improve. +If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve. We're trying very hard to keep Docker lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature. -However there might be a way to implement that feature *on top of* docker. +However, there might be a way to implement that feature *on top of* docker. ### Discuss your design on the mailing list @@ -207,7 +207,7 @@ you in the right direction, give feedback on your design, and maybe point out if ### Create issues... -Any significant improvement should be documented as a github issue before anybody start working on it. +Any significant improvement should be documented as [a github issue](https://github.com/dotcloud/docker/issues) before anybody starts working on it. ### ...but check for existing issues first! @@ -224,7 +224,7 @@ Golang has a great testing suite built in: use it! Take a look at existing tests Setting up a dev environment ---------------------------- -Instructions that is verified to work on Ubuntu 12.10, +Instructions that have been verified to work on Ubuntu 12.10, ``` sudo apt-get -y install lxc wget bsdtar curl libsqlite3-dev golang git pkg-config @@ -254,9 +254,9 @@ 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 dependency, regardless of the underlying machine and the contents of the container. +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 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 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. From 3aefed2dc250bd41502bdaa11624f1f974ed80b6 Mon Sep 17 00:00:00 2001 From: shin- Date: Thu, 21 Mar 2013 09:19:22 -0700 Subject: [PATCH 02/12] When lxcbr0 has several associated IPs, default to first one found --- network.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network.go b/network.go index 01d84379a2..cce4c88d37 100644 --- a/network.go +++ b/network.go @@ -95,7 +95,8 @@ func getIfaceAddr(name string) (net.Addr, error) { case len(addrs4) == 0: return nil, fmt.Errorf("Interface %v has no IP addresses", name) case len(addrs4) > 1: - return nil, fmt.Errorf("Interface %v has more than 1 IPv4 address", name) + fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n", + name, (addrs4[0].(*net.IPNet)).IP) } return addrs4[0], nil } From 7566006d0de5d1da0ea7f0fa906483425391fbf8 Mon Sep 17 00:00:00 2001 From: Caleb Spare Date: Thu, 21 Mar 2013 18:18:34 -0700 Subject: [PATCH 03/12] Markdown fixes in the readme. --- README.md | 78 +++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index c1c155ac73..68473ce383 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ Installing on Ubuntu 12.04 and 12.10 1. Install dependencies: ```bash - sudo apt-get install lxc wget bsdtar curl - sudo apt-get install linux-image-extra-`uname -r` +sudo apt-get install lxc wget bsdtar curl +sudo apt-get install linux-image-extra-`uname -r` ``` The `linux-image-extra` package is needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module. @@ -68,15 +68,15 @@ The `linux-image-extra` package is needed on standard Ubuntu EC2 AMIs in order t 2. Install the latest docker binary: ```bash - wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz - tar -xf docker-master.tgz +wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz +tar -xf docker-master.tgz ``` 3. Run your first container! ```bash - cd docker-master - sudo ./docker run -a -i -t base /bin/bash +cd docker-master +sudo ./docker run -a -i -t base /bin/bash ``` Consider adding docker to your `PATH` for simplicity. @@ -99,12 +99,12 @@ with VirtualBox as well as on Amazon EC2. Vagrant 1.1 is required for EC2, but deploying is as simple as: ```bash - $ export AWS_ACCESS_KEY_ID=xxx \ - AWS_SECRET_ACCESS_KEY=xxx \ - AWS_KEYPAIR_NAME=xxx \ - AWS_SSH_PRIVKEY=xxx - $ vagrant plugin install vagrant-aws - $ vagrant up --provider=aws +$ export AWS_ACCESS_KEY_ID=xxx \ + AWS_SECRET_ACCESS_KEY=xxx \ + AWS_KEYPAIR_NAME=xxx \ + AWS_SSH_PRIVKEY=xxx +$ vagrant plugin install vagrant-aws +$ vagrant up --provider=aws ``` The environment variables are: @@ -115,11 +115,11 @@ The environment variables are: * `AWS_SSH_PRIVKEY` - The path to the private key for the named keypair For VirtualBox, you can simply ignore setting any of the environment -variables and omit the ``provider`` flag. VirtualBox is still supported with -Vagrant <= 1.1: +variables and omit the `provider` flag. VirtualBox is still supported with +Vagrant <= 1.1: ```bash - $ vagrant up +$ vagrant up ``` @@ -131,12 +131,12 @@ Running an interactive shell ---------------------------- ```bash - # Download a base image - docker import base +# Download a base image +docker import base - # Run an interactive shell in the base image, - # allocate a tty, attach stdin and stdout - docker run -a -i -t base /bin/bash +# Run an interactive shell in the base image, +# allocate a tty, attach stdin and stdout +docker run -a -i -t base /bin/bash ``` @@ -144,17 +144,17 @@ Starting a long-running worker process -------------------------------------- ```bash - # Run docker in daemon mode - (docker -d || echo "Docker daemon already running") & +# Run docker in daemon mode +(docker -d || echo "Docker daemon already running") & - # Start a very useful long-running process - JOB=$(docker run base /bin/sh -c "while true; do echo Hello world; sleep 1; done") +# Start a very useful long-running process +JOB=$(docker run base /bin/sh -c "while true; do echo Hello world; sleep 1; done") - # Collect the output of the job so far - docker logs $JOB +# Collect the output of the job so far +docker logs $JOB - # Kill the job - docker kill $JOB +# Kill the job +docker kill $JOB ``` @@ -162,7 +162,7 @@ Listing all running containers ------------------------------ ```bash - docker ps +docker ps ``` @@ -170,17 +170,17 @@ Expose a service on a TCP port ------------------------------ ```bash - # Expose port 4444 of this container, and tell netcat to listen on it - JOB=$(docker run -p 4444 base /bin/nc -l -p 4444) +# Expose port 4444 of this container, and tell netcat to listen on it +JOB=$(docker run -p 4444 base /bin/nc -l -p 4444) - # Which public port is NATed to my container? - PORT=$(docker port $JOB 4444) +# Which public port is NATed to my container? +PORT=$(docker port $JOB 4444) - # Connect to the public port via the host's public address - echo hello world | nc $(hostname) $PORT +# Connect to the public port via the host's public address +echo hello world | nc $(hostname) $PORT - # Verify that the network connection worked - echo "Daemon received: $(docker logs $JOB)" +# Verify that the network connection worked +echo "Daemon received: $(docker logs $JOB)" ``` Contributing to Docker @@ -226,7 +226,7 @@ Setting up a dev environment Instructions that is verified to work on Ubuntu 12.10, -``` +```bash sudo apt-get -y install lxc wget bsdtar curl libsqlite3-dev golang git pkg-config export GOPATH=~/go/ @@ -243,7 +243,7 @@ go install -v github.com/dotcloud/docker/... Then run the docker daemon, -``` +```bash sudo $GOPATH/bin/docker -d ``` From d515e2b06c70a4132343da69a6a763ef626e7376 Mon Sep 17 00:00:00 2001 From: Caleb Spare Date: Thu, 21 Mar 2013 21:46:00 -0700 Subject: [PATCH 04/12] Fix numbering in README markdown. --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 68473ce383..1b167273c1 100644 --- a/README.md +++ b/README.md @@ -58,28 +58,28 @@ Installing on Ubuntu 12.04 and 12.10 1. Install dependencies: -```bash -sudo apt-get install lxc wget bsdtar curl -sudo apt-get install linux-image-extra-`uname -r` -``` + ```bash + sudo apt-get install lxc wget bsdtar curl + sudo apt-get install linux-image-extra-`uname -r` + ``` -The `linux-image-extra` package is needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module. + The `linux-image-extra` package is needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module. 2. Install the latest docker binary: -```bash -wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz -tar -xf docker-master.tgz -``` + ```bash + wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz + tar -xf docker-master.tgz + ``` 3. Run your first container! -```bash -cd docker-master -sudo ./docker run -a -i -t base /bin/bash -``` + ```bash + cd docker-master + sudo ./docker run -a -i -t base /bin/bash + ``` -Consider adding docker to your `PATH` for simplicity. + Consider adding docker to your `PATH` for simplicity. Installing on other Linux distributions --------------------------------------- From 13e597a5adf7e700757ee2b8ec40fe6712ebc99e Mon Sep 17 00:00:00 2001 From: dhrp Date: Thu, 21 Mar 2013 21:47:14 -0700 Subject: [PATCH 05/12] create README.md at this place for preview. --- docs/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..2abaac9393 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,4 @@ +Docs readme +=========== + +Let's see if this file shows up as we hope it does. From 6295a022750627d433c5c44872393ede4f1d8051 Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Thu, 21 Mar 2013 17:23:23 -0700 Subject: [PATCH 06/12] vagrant; issue #113: Make Vagrantfile backward compatible with versions < 1.1 --- Vagrantfile | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index e847659848..25b27302e1 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,7 +1,7 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -Vagrant.configure("1") do |config| +def v10(config) # All Vagrant configuration is done here. The most common configuration # options are documented and commented below. For a complete reference, # please see the online documentation at vagrantup.com. @@ -20,7 +20,7 @@ Vagrant.configure("1") do |config| # via the IP. Host-only networks can talk to the host machine as well as # any other machines on the same network, but cannot be accessed (through this # network interface) by any external networks. - # config.vm.network :hostonly, "192.168.33.10" + config.vm.network :hostonly, "192.168.33.10" # Assign this VM to a bridged network, allowing you to connect directly to a # network using the host's network device. This makes the VM appear as another @@ -34,6 +34,9 @@ Vagrant.configure("1") do |config| # Share an additional folder to the guest VM. The first argument is # an identifier, the second is the path on the guest to mount the # folder, and the third is the path on the host to the actual folder. + if not File.exist? File.expand_path '~/docker' + Dir.mkdir(File.expand_path '~/docker') + end config.vm.share_folder "v-data", "~/docker", "~/docker" # Enable provisioning with Puppet stand alone. Puppet manifests @@ -99,7 +102,15 @@ Vagrant.configure("1") do |config| # chef.validation_client_name = "ORGNAME-validator" end -Vagrant.configure("2") do |config| +"#{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 + +"#{Vagrant::VERSION}" >= "1.1.0" and Vagrant.configure("2") do |config| config.vm.provider :aws do |aws| config.vm.box = "dummy" config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box" From 45df6f7801554ccb24ba8ccf42ec5a847262b9ca Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Thu, 21 Mar 2013 22:26:18 -0700 Subject: [PATCH 07/12] vagrant; issue #113: normalize whitespaces --- Vagrantfile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 25b27302e1..4cf5f0a0e5 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -112,19 +112,19 @@ end "#{Vagrant::VERSION}" >= "1.1.0" and Vagrant.configure("2") do |config| config.vm.provider :aws do |aws| - config.vm.box = "dummy" - config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box" + config.vm.box = "dummy" + config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box" aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"] - aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"] - aws.keypair_name = ENV["AWS_KEYPAIR_NAME"] - aws.ssh_private_key_path = ENV["AWS_SSH_PRIVKEY"] - aws.region = "us-east-1" + aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"] + aws.keypair_name = ENV["AWS_KEYPAIR_NAME"] + aws.ssh_private_key_path = ENV["AWS_SSH_PRIVKEY"] + aws.region = "us-east-1" aws.ami = "ami-1c1e8075" aws.ssh_username = "vagrant" - aws.instance_type = "t1.micro" + aws.instance_type = "t1.micro" end config.vm.provider :virtualbox do |vb| - config.vm.box = "quantal64_3.5.0-25" - config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box" - end + config.vm.box = "quantal64_3.5.0-25" + config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box" + end end From b00ff47963bb236d9f94fbcd759e4f3fba021d05 Mon Sep 17 00:00:00 2001 From: shin- Date: Fri, 22 Mar 2013 04:24:03 -0700 Subject: [PATCH 08/12] Fixing newlines in attached mode --- term/term.go | 21 --------------------- term/termios_darwin.go | 26 +++++++++++++++++++++++++- term/termios_linux.go | 26 +++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/term/term.go b/term/term.go index fdbe3b9984..39b77dcc59 100644 --- a/term/term.go +++ b/term/term.go @@ -114,27 +114,6 @@ func IsTerminal(fd int) bool { return err == 0 } -// MakeRaw put the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -func MakeRaw(fd int) (*State, error) { - var oldState State - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { - return nil, err - } - - newState := oldState.termios - newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF - newState.Iflag |= ICRNL - newState.Oflag |= ONLCR - newState.Lflag &^= ECHO | ICANON | ISIG - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { - return nil, err - } - - return &oldState, nil -} - // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, state *State) error { diff --git a/term/termios_darwin.go b/term/termios_darwin.go index 26d17b3bb8..4365b60339 100644 --- a/term/termios_darwin.go +++ b/term/termios_darwin.go @@ -1,8 +1,32 @@ package term -import "syscall" +import ( + "syscall" + "unsafe" +) const ( getTermios = syscall.TIOCGETA setTermios = syscall.TIOCSETA ) + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState.termios + newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF + newState.Iflag |= ICRNL + newState.Oflag |= ONLCR + newState.Lflag &^= ECHO | ICANON | ISIG + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} \ No newline at end of file diff --git a/term/termios_linux.go b/term/termios_linux.go index 1ea26fa5c4..933ef84c4d 100644 --- a/term/termios_linux.go +++ b/term/termios_linux.go @@ -1,8 +1,32 @@ package term -import "syscall" +import ( + "syscall" + "unsafe" +) const ( getTermios = syscall.TCGETS setTermios = syscall.TCSETS ) + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState.termios + newState.Iflag &^= ISTRIP | IXON | IXOFF + newState.Iflag |= ICRNL + newState.Oflag |= ONLCR + newState.Lflag &^= ECHO | ICANON | ISIG + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} \ No newline at end of file From 9542876d2f22e73a52b4957d1a8ca6b17d5c83e7 Mon Sep 17 00:00:00 2001 From: Shawn Siefkas Date: Fri, 22 Mar 2013 08:48:50 -0500 Subject: [PATCH 09/12] Waiting to start docker until the fresh binaries have been copied in --- puppet/modules/docker/manifests/init.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppet/modules/docker/manifests/init.pp b/puppet/modules/docker/manifests/init.pp index 1862c524b8..6f8d249ff7 100644 --- a/puppet/modules/docker/manifests/init.pp +++ b/puppet/modules/docker/manifests/init.pp @@ -80,7 +80,7 @@ class docker { owner => "root", group => "root", content => template("docker/dockerd.conf"), - require => Exec["fetch-docker"], + require => Exec["copy-docker-bin"], } file { "/home/vagrant": From cff01ec5ec3210f2faec3715bf1b07182bcc571c Mon Sep 17 00:00:00 2001 From: Shawn Siefkas Date: Fri, 22 Mar 2013 08:49:28 -0500 Subject: [PATCH 10/12] Redirecting docker daemon stdout/stderr to /var/log/dockerd --- puppet/modules/docker/templates/dockerd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppet/modules/docker/templates/dockerd.conf b/puppet/modules/docker/templates/dockerd.conf index 2d77c301f0..f88d5c347f 100644 --- a/puppet/modules/docker/templates/dockerd.conf +++ b/puppet/modules/docker/templates/dockerd.conf @@ -8,5 +8,5 @@ respawn script test -f /etc/default/locale && . /etc/default/locale || true - LANG=$LANG LC_ALL=$LANG /usr/local/bin/docker -d + LANG=$LANG LC_ALL=$LANG /usr/local/bin/docker -d >> /var/log/dockerd 2>&1 end script From 3c6b8bb8882fcd2083d1c489df3cc40062b4896c Mon Sep 17 00:00:00 2001 From: Shawn Siefkas Date: Fri, 22 Mar 2013 09:06:14 -0500 Subject: [PATCH 11/12] Fixing Issue #98: Adding DOCKER to output chain during iptables setup --- network.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/network.go b/network.go index cce4c88d37..73cb1709af 100644 --- a/network.go +++ b/network.go @@ -124,6 +124,9 @@ func (mapper *PortMapper) setup() error { if err := iptables("-t", "nat", "-A", "PREROUTING", "-j", "DOCKER"); err != nil { return errors.New("Unable to setup port networking: Failed to inject docker in PREROUTING chain") } + if err := iptables("-t", "nat", "-A", "OUTPUT", "-j", "DOCKER"); err != nil { + return errors.New("Unable to setup port networking: Failed to inject docker in OUTPUT chain") + } return nil } From bf7602bc098888994eb28a2a6c9acd949a227448 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 22 Mar 2013 18:27:18 -0700 Subject: [PATCH 12/12] 'docker tag': assign a repository+tag to an image --- commands.go | 15 ++++++++++++++- registry.go | 2 +- runtime.go | 2 +- tags.go | 11 +++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/commands.go b/commands.go index 1d782bf96c..4e512d8dda 100644 --- a/commands.go +++ b/commands.go @@ -389,7 +389,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri // Optionally register the image at REPO/TAG if repository := cmd.Arg(1); repository != "" { tag := cmd.Arg(2) // Repository will handle an empty tag properly - if err := srv.runtime.repositories.Set(repository, tag, img.Id); err != nil { + if err := srv.runtime.repositories.Set(repository, tag, img.Id, true); err != nil { return err } } @@ -760,6 +760,19 @@ func (p *ports) Set(value string) error { return nil } +func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) error { + cmd := rcli.Subcmd(stdout, "tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository") + force := cmd.Bool("f", false, "Force") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 2 { + cmd.Usage() + return nil + } + return srv.runtime.repositories.Set(cmd.Arg(1), cmd.Arg(2), cmd.Arg(0), *force) +} + func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error { cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container") fl_user := cmd.String("u", "", "Username or UID") diff --git a/registry.go b/registry.go index da1186ee54..96c32ea2ef 100644 --- a/registry.go +++ b/registry.go @@ -175,7 +175,7 @@ func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories if err = graph.PullImage(rev, authConfig); err != nil { return err } - if err = repositories.Set(repoName, tag, rev); err != nil { + if err = repositories.Set(repoName, tag, rev, true); err != nil { return err } } diff --git a/runtime.go b/runtime.go index bb59c7787a..21e1466f51 100644 --- a/runtime.go +++ b/runtime.go @@ -201,7 +201,7 @@ func (runtime *Runtime) Commit(id, repository, tag string) (*Image, error) { } // Register the image if needed if repository != "" { - if err := runtime.repositories.Set(repository, tag, img.Id); err != nil { + if err := runtime.repositories.Set(repository, tag, img.Id, true); err != nil { return img, err } } diff --git a/tags.go b/tags.go index ae8c1030cd..9f0a215b46 100644 --- a/tags.go +++ b/tags.go @@ -83,7 +83,11 @@ func (store *TagStore) LookupImage(name string) (*Image, error) { return img, nil } -func (store *TagStore) Set(repoName, tag, revision string) error { +func (store *TagStore) Set(repoName, tag, imageName string, force bool) error { + img, err := store.LookupImage(imageName) + if err != nil { + return err + } if tag == "" { tag = DEFAULT_TAG } @@ -101,9 +105,12 @@ func (store *TagStore) Set(repoName, tag, revision string) error { repo = r } else { repo = make(map[string]string) + if old, exists := store.Repositories[repoName]; exists && !force { + return fmt.Errorf("Tag %s:%s is already set to %s", repoName, tag, old) + } store.Repositories[repoName] = repo } - repo[tag] = revision + repo[tag] = img.Id return store.Save() }