Sfoglia il codice sorgente

Merge pull request #1972 from dotcloud/bump_0.6.3

Bump to version v0.6.3
Michael Crosby 11 anni fa
parent
commit
648d759517

+ 13 - 0
CHANGELOG.md

@@ -1,5 +1,18 @@
 # Changelog
 
+## 0.6.3 (2013-09-23)
+* Packaging: Update tar vendor dependency
+- Client: Fix detach issue
+- Runtime: Only copy and change permissions on non-bindmount volumes
+- Registry: Update regular expression to match index
+* Runtime: Allow multiple volumes-from
+* Packaging: Download apt key over HTTPS
+* Documentation: Update section on extracting the docker binary after build
+* Documentation: Update development environment docs for new build process
+* Documentation: Remove 'base' image from documentation
+* Packaging: Add 'docker' group on install for ubuntu package
+- Runtime: Fix HTTP imports from STDIN
+
 ## 0.6.2 (2013-09-17)
 + Hack: Vendor all dependencies
 + Builder: Add -rm option in order to remove intermediate containers

+ 1 - 1
VERSION

@@ -1 +1 @@
-0.6.2
+0.6.3

+ 37 - 10
commands.go

@@ -6,6 +6,7 @@ import (
 	"bytes"
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"flag"
 	"fmt"
 	"github.com/dotcloud/docker/auth"
@@ -36,6 +37,10 @@ var (
 	VERSION   string
 )
 
+var (
+	ErrConnectionRefused = errors.New("Can't connect to docker daemon. Is 'docker -d' running on this host?")
+)
+
 func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
 	methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
 	return reflect.TypeOf(cli).MethodByName(methodName)
@@ -795,11 +800,13 @@ func (cli *DockerCli) CmdImport(args ...string) error {
 	v.Set("tag", tag)
 	v.Set("fromSrc", src)
 
-	err := cli.stream("POST", "/images/create?"+v.Encode(), cli.in, cli.out, nil)
-	if err != nil {
-		return err
+	var in io.Reader
+
+	if src == "-" {
+		in = cli.in
 	}
-	return nil
+
+	return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
 }
 
 func (cli *DockerCli) CmdPush(args ...string) error {
@@ -1256,7 +1263,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
 
 	if container.Config.Tty {
 		if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
-			return err
+			utils.Debugf("Error monitoring tty size: %s", err)
 		}
 	}
 
@@ -1565,12 +1572,12 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 		// Detached mode
 		<-wait
 	} else {
-		status, err := waitForExit(cli, runResult.ID)
+		status, err := getExitCode(cli, runResult.ID)
 		if err != nil {
 			return err
 		}
 		if status != 0 {
-			return &utils.StatusError{status}
+			return &utils.StatusError{Status: status}
 		}
 	}
 
@@ -1636,7 +1643,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
 	dial, err := net.Dial(cli.proto, cli.addr)
 	if err != nil {
 		if strings.Contains(err.Error(), "connection refused") {
-			return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
+			return nil, -1, ErrConnectionRefused
 		}
 		return nil, -1, err
 	}
@@ -1645,7 +1652,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int,
 	defer clientconn.Close()
 	if err != nil {
 		if strings.Contains(err.Error(), "connection refused") {
-			return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?")
+			return nil, -1, ErrConnectionRefused
 		}
 		return nil, -1, err
 	}
@@ -1864,7 +1871,11 @@ func (cli *DockerCli) LoadConfigFile() (err error) {
 func waitForExit(cli *DockerCli, containerId string) (int, error) {
 	body, _, err := cli.call("POST", "/containers/"+containerId+"/wait", nil)
 	if err != nil {
-		return -1, err
+		// If we can't connect, then the daemon probably died.
+		if err != ErrConnectionRefused {
+			return -1, err
+		}
+		return -1, nil
 	}
 
 	var out APIWait
@@ -1874,6 +1885,22 @@ func waitForExit(cli *DockerCli, containerId string) (int, error) {
 	return out.StatusCode, nil
 }
 
+func getExitCode(cli *DockerCli, containerId string) (int, error) {
+	body, _, err := cli.call("GET", "/containers/"+containerId+"/json", nil)
+	if err != nil {
+		// If we can't connect, then the daemon probably died.
+		if err != ErrConnectionRefused {
+			return -1, err
+		}
+		return -1, nil
+	}
+	c := &Container{}
+	if err := json.Unmarshal(body, c); err != nil {
+		return -1, err
+	}
+	return c.State.ExitCode, nil
+}
+
 func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
 	var (
 		isTerminal = false

+ 104 - 0
commands_test.go

@@ -369,6 +369,110 @@ func TestRunAttachStdin(t *testing.T) {
 	}
 }
 
+// TestRunDetach checks attaching and detaching with the escape sequence.
+func TestRunDetach(t *testing.T) {
+
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	ch := make(chan struct{})
+	go func() {
+		defer close(ch)
+		cli.CmdRun("-i", "-t", unitTestImageID, "cat")
+	}()
+
+	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	container := globalRuntime.List()[0]
+
+	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
+		stdinPipe.Write([]byte{'', ''})
+		if err := stdinPipe.Close(); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// wait for CmdRun to return
+	setTimeout(t, "Waiting for CmdRun timed out", 5*time.Second, func() {
+		<-ch
+	})
+
+	time.Sleep(500 * time.Millisecond)
+	if !container.State.Running {
+		t.Fatal("The detached container should be still running")
+	}
+
+	setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
+		container.Kill()
+		container.Wait()
+	})
+}
+
+// TestAttachDetach checks that attach in tty mode can be detached
+func TestAttachDetach(t *testing.T) {
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+	defer cleanup(globalRuntime)
+
+	go stdout.Read(make([]byte, 1024))
+	setTimeout(t, "Starting container timed out", 2*time.Second, func() {
+		if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	container := globalRuntime.List()[0]
+
+	stdin, stdinPipe = io.Pipe()
+	stdout, stdoutPipe = io.Pipe()
+	cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
+
+	ch := make(chan struct{})
+	go func() {
+		defer close(ch)
+		if err := cli.CmdAttach(container.ShortID()); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
+		stdinPipe.Write([]byte{'', ''})
+		if err := stdinPipe.Close(); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// wait for CmdRun to return
+	setTimeout(t, "Waiting for CmdAttach timed out", 5*time.Second, func() {
+		<-ch
+	})
+
+	time.Sleep(500 * time.Millisecond)
+	if !container.State.Running {
+		t.Fatal("The detached container should be still running")
+	}
+
+	setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
+		container.Kill()
+		container.Wait()
+	})
+}
+
 // Expected behaviour, the process stays alive when the client disconnects
 func TestAttachDisconnect(t *testing.T) {
 	stdin, stdinPipe := io.Pipe()

+ 51 - 35
container.go

@@ -146,7 +146,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 	flVolumes := NewPathOpts()
 	cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
 
-	flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
+	var flVolumesFrom ListOpts
+	cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container")
+
 	flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
 
 	var flLxcOpts ListOpts
@@ -231,7 +233,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 		Dns:             flDns,
 		Image:           image,
 		Volumes:         flVolumes,
-		VolumesFrom:     *flVolumesFrom,
+		VolumesFrom:     strings.Join(flVolumesFrom, ","),
 		Entrypoint:      entrypoint,
 		Privileged:      *flPrivileged,
 		WorkingDir:      *flWorkingDir,
@@ -639,21 +641,25 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 
 	// Apply volumes from another container if requested
 	if container.Config.VolumesFrom != "" {
-		c := container.runtime.Get(container.Config.VolumesFrom)
-		if c == nil {
-			return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
-		}
-		for volPath, id := range c.Volumes {
-			if _, exists := container.Volumes[volPath]; exists {
-				continue
+		volumes := strings.Split(container.Config.VolumesFrom, ",")
+		for _, v := range volumes {
+			c := container.runtime.Get(v)
+			if c == nil {
+				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
 			}
-			if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
-				return err
-			}
-			container.Volumes[volPath] = id
-			if isRW, exists := c.VolumesRW[volPath]; exists {
-				container.VolumesRW[volPath] = isRW
+			for volPath, id := range c.Volumes {
+				if _, exists := container.Volumes[volPath]; exists {
+					continue
+				}
+				if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
+					return err
+				}
+				container.Volumes[volPath] = id
+				if isRW, exists := c.VolumesRW[volPath]; exists {
+					container.VolumesRW[volPath] = isRW
+				}
 			}
+
 		}
 	}
 
@@ -665,9 +671,11 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 			continue
 		}
 		var srcPath string
+		var isBindMount bool
 		srcRW := false
 		// If an external bind is defined for this volume, use that as a source
 		if bindMap, exists := binds[volPath]; exists {
+			isBindMount = true
 			srcPath = bindMap.SrcPath
 			if strings.ToLower(bindMap.Mode) == "rw" {
 				srcRW = true
@@ -691,7 +699,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 		if err := os.MkdirAll(rootVolPath, 0755); err != nil {
 			return nil
 		}
-		if srcRW {
+
+		// Do not copy or change permissions if we are mounting from the host
+		if srcRW && !isBindMount {
 			volList, err := ioutil.ReadDir(rootVolPath)
 			if err != nil {
 				return err
@@ -702,22 +712,26 @@ func (container *Container) Start(hostConfig *HostConfig) error {
 					return err
 				}
 				if len(srcList) == 0 {
+					// If the source volume is empty copy files from the root into the volume
 					if err := CopyWithTar(rootVolPath, srcPath); err != nil {
 						return err
 					}
-				}
-			}
-			var stat syscall.Stat_t
-			if err := syscall.Stat(rootVolPath, &stat); err != nil {
-				return err
-			}
-			var srcStat syscall.Stat_t
-			if err := syscall.Stat(srcPath, &srcStat); err != nil {
-				return err
-			}
-			if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
-				if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
-					return err
+
+					var stat syscall.Stat_t
+					if err := syscall.Stat(rootVolPath, &stat); err != nil {
+						return err
+					}
+					var srcStat syscall.Stat_t
+					if err := syscall.Stat(srcPath, &srcStat); err != nil {
+						return err
+					}
+					// Change the source volume's ownership if it differs from the root
+					// files that where just copied
+					if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
+						if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
+							return err
+						}
+					}
 				}
 			}
 		}
@@ -950,14 +964,19 @@ func (container *Container) monitor() {
 		}
 	}
 	utils.Debugf("Process finished")
-	if container.runtime != nil && container.runtime.srv != nil {
-		container.runtime.srv.LogEvent("die", container.ShortID(), container.runtime.repositories.ImageName(container.Image))
-	}
+
 	exitCode := -1
 	if container.cmd != nil {
 		exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
 	}
 
+	// Report status back
+	container.State.setStopped(exitCode)
+
+	if container.runtime != nil && container.runtime.srv != nil {
+		container.runtime.srv.LogEvent("die", container.ShortID(), container.runtime.repositories.ImageName(container.Image))
+	}
+
 	// Cleanup
 	container.releaseNetwork()
 	if container.Config.OpenStdin {
@@ -987,9 +1006,6 @@ func (container *Container) monitor() {
 		container.stdin, container.stdinPipe = io.Pipe()
 	}
 
-	// Report status back
-	container.State.setStopped(exitCode)
-
 	// Release the lock
 	close(container.waitLock)
 

+ 80 - 28
container_test.go

@@ -1202,7 +1202,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
 	defer nuke(r)
 
 	// Add directory not owned by root
-	container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && chown daemon.daemon /hello"}, t)
+	container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
 	defer r.Destroy(container1)
 
 	if container1.State.Running {
@@ -1227,18 +1227,10 @@ func TestCopyVolumeUidGid(t *testing.T) {
 	// Test that the uid and gid is copied from the image to the volume
 	tmpDir1 := tempDir(t)
 	defer os.RemoveAll(tmpDir1)
-	stdout1, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello", tmpDir1), img.ID, "stat", "-c", "%U %G", "/hello"}, t)
+	stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "stat", "-c", "%U %G", "/hello"}, t)
 	if !strings.Contains(stdout1, "daemon daemon") {
 		t.Fatal("Container failed to transfer uid and gid to volume")
 	}
-
-	// Test that the uid and gid is not copied from the image when the volume is read only
-	tmpDir2 := tempDir(t)
-	defer os.RemoveAll(tmpDir1)
-	stdout2, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:ro", tmpDir2), img.ID, "stat", "-c", "%U %G", "/hello"}, t)
-	if strings.Contains(stdout2, "daemon daemon") {
-		t.Fatal("Container transfered uid and gid to volume")
-	}
 }
 
 // Test for #1582
@@ -1272,27 +1264,10 @@ func TestCopyVolumeContent(t *testing.T) {
 	// Test that the content is copied from the image to the volume
 	tmpDir1 := tempDir(t)
 	defer os.RemoveAll(tmpDir1)
-	stdout1, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello", tmpDir1), img.ID, "find", "/hello"}, t)
+	stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "find", "/hello"}, t)
 	if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
 		t.Fatal("Container failed to transfer content to volume")
 	}
-
-	// Test that the content is not copied when the volume is readonly
-	tmpDir2 := tempDir(t)
-	defer os.RemoveAll(tmpDir2)
-	stdout2, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:ro", tmpDir2), img.ID, "find", "/hello"}, t)
-	if strings.Contains(stdout2, "/hello/local/world") || strings.Contains(stdout2, "/hello/local") {
-		t.Fatal("Container transfered content to readonly volume")
-	}
-
-	// Test that the content is not copied when the volume is non-empty
-	tmpDir3 := tempDir(t)
-	defer os.RemoveAll(tmpDir3)
-	writeFile(path.Join(tmpDir3, "touch-me"), "", t)
-	stdout3, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/hello:rw", tmpDir3), img.ID, "find", "/hello"}, t)
-	if strings.Contains(stdout3, "/hello/local/world") || strings.Contains(stdout3, "/hello/local") || !strings.Contains(stdout3, "/hello/touch-me") {
-		t.Fatal("Container transfered content to non-empty volume")
-	}
 }
 
 func TestBindMounts(t *testing.T) {
@@ -1549,3 +1524,80 @@ func TestPrivilegedCannotMount(t *testing.T) {
 		t.Fatal("Could mount into secure container")
 	}
 }
+
+func TestMultipleVolumesFrom(t *testing.T) {
+	runtime := mkRuntime(t)
+	defer nuke(runtime)
+
+	container, err := runtime.Create(&Config{
+		Image:   GetTestImage(runtime).ID,
+		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
+		Volumes: map[string]struct{}{"/test": {}},
+	},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container)
+
+	for key := range container.Config.Volumes {
+		if key != "/test" {
+			t.Fail()
+		}
+	}
+
+	_, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	expected := container.Volumes["/test"]
+	if expected == "" {
+		t.Fail()
+	}
+
+	container2, err := runtime.Create(
+		&Config{
+			Image:   GetTestImage(runtime).ID,
+			Cmd:     []string{"sh", "-c", "echo -n bar > /other/foo"},
+			Volumes: map[string]struct{}{"/other": {}},
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container2)
+
+	for key := range container2.Config.Volumes {
+		if key != "/other" {
+			t.FailNow()
+		}
+	}
+	if _, err := container2.Output(); err != nil {
+		t.Fatal(err)
+	}
+
+	container3, err := runtime.Create(
+		&Config{
+			Image:       GetTestImage(runtime).ID,
+			Cmd:         []string{"/bin/echo", "-n", "foobar"},
+			VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
+		})
+
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container3)
+
+	if _, err := container3.Output(); err != nil {
+		t.Fatal(err)
+	}
+
+	t.Log(container3.Volumes)
+	if container3.Volumes["/test"] != container.Volumes["/test"] {
+		t.Fail()
+	}
+	if container3.Volumes["/other"] != container2.Volumes["/other"] {
+		t.Fail()
+	}
+}

+ 2 - 1
contrib/MAINTAINERS

@@ -1 +1,2 @@
-Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
+Kawsar Saiyeed <kawsar.saiyeed@projiris.com> (@KSid)
+Tianon Gravi <admwiggin@gmail.com> (@tianon)

+ 1 - 1
contrib/crashTest.go

@@ -77,7 +77,7 @@ func crashTest() error {
 			stop = false
 			for i := 0; i < 100 && !stop; {
 				func() error {
-					cmd := exec.Command(DOCKERPATH, "run", "base", "echo", fmt.Sprintf("%d", totalTestCount))
+					cmd := exec.Command(DOCKERPATH, "run", "ubuntu", "echo", fmt.Sprintf("%d", totalTestCount))
 					i++
 					totalTestCount++
 					outPipe, err := cmd.StdoutPipe()

+ 19 - 19
docs/sources/api/docker_remote_api_v1.0.rst

@@ -49,28 +49,28 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0"
@@ -117,7 +117,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":""
 	   }
@@ -183,7 +183,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": ""
 			},
@@ -490,14 +490,14 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658
 		}
@@ -529,9 +529,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -552,7 +552,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -572,8 +572,8 @@ Create an image
         :statuscode 500: server error
 
 
-Insert a file in a image
-************************
+Insert a file in an image
+*************************
 
 .. http:post:: /images/(name)/insert
 
@@ -608,7 +608,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -638,7 +638,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":""
 			}
@@ -660,7 +660,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 

+ 19 - 19
docs/sources/api/docker_remote_api_v1.1.rst

@@ -49,28 +49,28 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0"
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0"
@@ -117,7 +117,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":""
 	   }
@@ -183,7 +183,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": ""
 			},
@@ -490,14 +490,14 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658
 		}
@@ -529,9 +529,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -552,7 +552,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -575,8 +575,8 @@ Create an image
         :statuscode 500: server error
 
 
-Insert a file in a image
-************************
+Insert a file in an image
+*************************
 
 .. http:post:: /images/(name)/insert
 
@@ -615,7 +615,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -645,7 +645,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":""
 			}
@@ -667,7 +667,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 

+ 20 - 20
docs/sources/api/docker_remote_api_v1.2.rst

@@ -49,7 +49,7 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -59,7 +59,7 @@ List containers
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -69,7 +69,7 @@ List containers
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0",
@@ -79,7 +79,7 @@ List containers
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0",
@@ -129,7 +129,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":""
 	   }
@@ -195,7 +195,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": ""
 			},
@@ -502,16 +502,16 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
 			"VirtualSize":180116135
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
@@ -545,9 +545,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -568,7 +568,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -591,8 +591,8 @@ Create an image
         :statuscode 500: server error
 
 
-Insert a file in a image
-************************
+Insert a file in an image
+*************************
 
 .. http:post:: /images/(name)/insert
 
@@ -631,7 +631,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -661,7 +661,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":""
 			},
@@ -684,7 +684,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 
@@ -696,7 +696,7 @@ Get the history of an image
 	   [
 		{
 			"Id":"b750fe79269d",
-			"Tag":["base:latest"],
+			"Tag":["ubuntu:latest"],
 			"Created":1364102658,
 			"CreatedBy":"/bin/bash"
 		},

+ 19 - 19
docs/sources/api/docker_remote_api_v1.3.rst

@@ -49,7 +49,7 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -59,7 +59,7 @@ List containers
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -69,7 +69,7 @@ List containers
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0",
@@ -79,7 +79,7 @@ List containers
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0",
@@ -130,7 +130,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":""
 	   }
@@ -196,7 +196,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": ""
 			},
@@ -550,16 +550,16 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
 			"VirtualSize":180116135
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
@@ -593,9 +593,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -616,7 +616,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -639,8 +639,8 @@ Create an image
         :statuscode 500: server error
 
 
-Insert a file in a image
-************************
+Insert a file in an image
+*************************
 
 .. http:post:: /images/(name)/insert
 
@@ -679,7 +679,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -709,7 +709,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":""
 			},
@@ -732,7 +732,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 

+ 21 - 21
docs/sources/api/docker_remote_api_v1.4.rst

@@ -46,7 +46,7 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -56,7 +56,7 @@ List containers
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -66,7 +66,7 @@ List containers
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0",
@@ -76,7 +76,7 @@ List containers
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0",
@@ -128,7 +128,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":"",
 		"WorkingDir":""
@@ -196,7 +196,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": "",
 				"WorkingDir":""
@@ -592,16 +592,16 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
 			"VirtualSize":180116135
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
@@ -635,9 +635,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -658,7 +658,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -721,7 +721,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -751,7 +751,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":"",
 				"WorkingDir":""
@@ -776,7 +776,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 
@@ -1126,10 +1126,10 @@ Monitor Docker's events
            HTTP/1.1 200 OK
 	   Content-Type: application/json
 
-	   {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
-	   {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
-	   {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966}
-	   {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970}
+	   {"status":"create","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
+	   {"status":"start","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
+	   {"status":"stop","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067966}
+	   {"status":"destroy","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067970}
 
 	:query since: timestamp used for polling
         :statuscode 200: no error

+ 21 - 21
docs/sources/api/docker_remote_api_v1.5.rst

@@ -46,7 +46,7 @@ List containers
 	   [
 		{
 			"Id": "8dfafdbc3a40",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 1",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -56,7 +56,7 @@ List containers
 		},
 		{
 			"Id": "9cd87474be90",
-			"Image": "base:latest",
+			"Image": "ubuntu:latest",
 			"Command": "echo 222222",
 			"Created": 1367854155,
 			"Status": "Exit 0",
@@ -66,7 +66,7 @@ List containers
 		},
 		{
 			"Id": "3176a2479c92",
-			"Image": "base:latest",
+			"Image": "centos:latest",
 			"Command": "echo 3333333333333333",
 			"Created": 1367854154,
 			"Status": "Exit 0",
@@ -76,7 +76,7 @@ List containers
 		},
 		{
 			"Id": "4cb07b47f9fb",
-			"Image": "base:latest",
+			"Image": "fedora:latest",
 			"Command": "echo 444444444444444444444444444444444",
 			"Created": 1367854152,
 			"Status": "Exit 0",
@@ -128,7 +128,7 @@ Create a container
 			"date"
 		],
 		"Dns":null,
-		"Image":"base",
+		"Image":"ubuntu",
 		"Volumes":{},
 		"VolumesFrom":"",
 		"WorkingDir":""
@@ -196,7 +196,7 @@ Inspect a container
 					"date"
 				],
 				"Dns": null,
-				"Image": "base",
+				"Image": "ubuntu",
 				"Volumes": {},
 				"VolumesFrom": "",
 				"WorkingDir":""
@@ -591,16 +591,16 @@ List Images
 	   
 	   [
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-12.10",
+			"Repository":"ubuntu",
+			"Tag":"precise",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
 			"VirtualSize":180116135
 		},
 		{
-			"Repository":"base",
-			"Tag":"ubuntu-quantal",
+			"Repository":"ubuntu",
+			"Tag":"12.04",
 			"Id":"b750fe79269d",
 			"Created":1364102658,
 			"Size":24653,
@@ -634,9 +634,9 @@ List Images
 	   "d6434d954665" -> "d82cbacda43a"
 	   base -> "e9aa60c60128" [style=invis]
 	   "074be284591f" -> "f71189fff3de"
-	   "b750fe79269d" [label="b750fe79269d\nbase",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "e9aa60c60128" [label="e9aa60c60128\nbase2",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
-	   "9a33b36209ed" [label="9a33b36209ed\ntest",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "b750fe79269d" [label="b750fe79269d\nubuntu",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "e9aa60c60128" [label="e9aa60c60128\ncentos",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
+	   "9a33b36209ed" [label="9a33b36209ed\nfedora",shape=box,fillcolor="paleturquoise",style="filled,rounded"];
 	   base [style=invisible]
 	   }
  
@@ -657,7 +657,7 @@ Create an image
 
         .. sourcecode:: http
 
-           POST /images/create?fromImage=base HTTP/1.1
+           POST /images/create?fromImage=ubuntu HTTP/1.1
 
         **Example response**:
 
@@ -724,7 +724,7 @@ Inspect an image
 
 	.. sourcecode:: http
 
-	   GET /images/base/json HTTP/1.1
+	   GET /images/centos/json HTTP/1.1
 
 	**Example response**:
 
@@ -754,7 +754,7 @@ Inspect an image
 				"Env":null,
 				"Cmd": ["/bin/bash"]
 				,"Dns":null,
-				"Image":"base",
+				"Image":"centos",
 				"Volumes":null,
 				"VolumesFrom":"",
 				"WorkingDir":""
@@ -778,7 +778,7 @@ Get the history of an image
 
         .. sourcecode:: http
 
-           GET /images/base/history HTTP/1.1
+           GET /images/fedora/history HTTP/1.1
 
         **Example response**:
 
@@ -1131,10 +1131,10 @@ Monitor Docker's events
            HTTP/1.1 200 OK
 	   Content-Type: application/json
 
-	   {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
-	   {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
-	   {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966}
-	   {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970}
+	   {"status":"create","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
+	   {"status":"start","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067924}
+	   {"status":"stop","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067966}
+	   {"status":"destroy","id":"dfdf82bd3881","from":"ubuntu:latest","time":1374067970}
 
 	:query since: timestamp used for polling
         :statuscode 200: no error

+ 4 - 3
docs/sources/api/index_api.rst

@@ -541,10 +541,11 @@ Search
       Content-Type: application/json
 
       {"query":"search_term",
-        "num_results": 2,
+        "num_results": 3,
         "results" : [
-           {"name": "dotcloud/base", "description": "A base ubuntu64  image..."},
-           {"name": "base2", "description": "A base ubuntu64  image..."},
+           {"name": "ubuntu", "description": "An ubuntu image..."},
+           {"name": "centos", "description": "A centos image..."},
+           {"name": "fedora", "description": "A fedora image..."}
          ]
        }
 

+ 1 - 0
docs/sources/examples/index.rst

@@ -3,6 +3,7 @@
 :keywords: docker, hello world, node, nodejs, python, couch, couchdb, redis, ssh, sshd, examples, postgresql
 
 
+.. _example_list:
 
 Examples
 ========

+ 1 - 1
docs/sources/examples/running_ssh_service.rst

@@ -47,7 +47,7 @@ The password is 'screencast'
          # I had it so it was quick
          # now let's connect using -i for interactive and with -t for terminal 
          # we execute /bin/bash to get a prompt.
-         $ docker run -i -t base /bin/bash
+         $ docker run -i -t ubuntu /bin/bash
          # yes! we are in!
          # now lets install openssh
          $ apt-get update

+ 0 - 2
docs/sources/use/baseimages.rst

@@ -37,7 +37,5 @@ There are more example scripts for creating base images in the
 Docker Github Repo:
 
 * `BusyBox <https://github.com/dotcloud/docker/blob/master/contrib/mkimage-busybox.sh>`_
-* `CentOS
-  <https://github.com/dotcloud/docker/blob/master/contrib/mkimage-centos.sh>`_
 * `Debian
   <https://github.com/dotcloud/docker/blob/master/contrib/mkimage-debian.sh>`_

+ 55 - 23
docs/sources/use/workingwithrepository.rst

@@ -52,31 +52,58 @@ repositories in these examples.
 * User images are not checked, it is therefore up to you whether or
   not you trust the creator of this image.
 
-Find public images available on the Central Index
--------------------------------------------------
+.. _searching_central_index:
 
-Search by name, namespace or description
+Find Public Images on the Central Index
+---------------------------------------
+
+You can search the Central Index `online <https://index.docker.io>`_
+or by the CLI. Searching can find images by name, user name or
+description:
 
 .. code-block:: bash
 
-    sudo docker search <value>
+    $ sudo docker help search
+    Usage: docker search NAME
 
+    Search the docker index for images
 
-Download them simply by their name
+      -notrunc=false: Don't truncate output
+    $ sudo docker search centos
+    Found 25 results matching your query ("centos")
+    NAME                             DESCRIPTION
+    centos                           
+    slantview/centos-chef-solo       CentOS 6.4 with chef-solo.
+    ...
 
-.. code-block:: bash
+There you can see two example results: ``centos`` and
+``slantview/centos-chef-solo``. The second result shows that it comes
+from the public repository of a user, ``slantview/``, while the first
+result (``centos``) doesn't explicitly list a repository so it comes
+from the trusted Central Repository. The ``/`` character separates a
+user's repository and the image name.
 
-    sudo docker pull <value>
+Once you have found the image name, you can download it:
 
+.. code-block:: bash
 
-Very similarly you can search for and browse the index online on
-https://index.docker.io
+    # sudo docker pull <value>
+    $ sudo docker pull centos
+    Pulling repository centos
+    539c0211cd76: Download complete
 
+What can you do with that image? Check out the :ref:`example_list`
+and, when you're ready with your own image, come back here to learn
+how to share it.
 
-Connecting to the Central Registry
-----------------------------------
+Contributing to the Central Registry
+------------------------------------
 
-You can create a user on the central Docker Index online, or by running
+Anyone can pull public images from the Central Registry, but if you
+would like to share one of your own images, then you must register a
+unique user name first. You can create your username and login on the
+`central Docker Index online
+<https://index.docker.io/account/signup/>`_, or by running
 
 .. code-block:: bash
 
@@ -85,22 +112,27 @@ You can create a user on the central Docker Index online, or by running
 This will prompt you for a username, which will become a public
 namespace for your public repositories.
 
-If your username does not exist it will prompt you to also enter a
-password and your e-mail address. It will then automatically log you
-in.
+If your username is available then ``docker`` will also prompt you to
+enter a password and your e-mail address. It will then automatically
+log you in. Now you're ready to commit and push your own images!
 
 .. _container_commit:
 
-Committing a container to a named image
+Committing a Container to a Named Image
 ---------------------------------------
 
-In order to commit to the repository it is required to have committed
-your container to an image within your username namespace.
+When you make changes to an existing image, those changes get saved to
+a container's file system. You can then promote that container to
+become an image by making a ``commit``. In addition to converting the
+container to an image, this is also your opportunity to name the
+image, specifically a name that includes your user name from the
+Central Docker Index (as you did a ``login`` above) and a meaningful
+name for the image.
 
 .. code-block:: bash
 
-    # for example docker commit $CONTAINER_ID dhrp/kickassapp
-    sudo docker commit <container_id> <username>/<repo_name>
+    # format is "sudo docker commit <container_id> <username>/<imagename>"
+    $ sudo docker commit $CONTAINER_ID myname/kickassapp
 
 .. _image_push:
 
@@ -115,15 +147,15 @@ or tag.
 
 .. code-block:: bash
 
-    # for example docker push dhrp/kickassapp
-    sudo docker push <username>/<repo_name>
+    # format is "docker push <username>/<repo_name>"
+    $ sudo docker push myname/kickassapp
 
 .. _using_private_repositories:
 
 Private Repositories
 --------------------
 
-Right now (version 0.5), private repositories are only possible by
+Right now (version 0.6), private repositories are only possible by
 hosting `your own registry
 <https://github.com/dotcloud/docker-registry>`_.  To push or pull to a
 repository on your own registry, you must prefix the tag with the

+ 2 - 0
hack/make/ubuntu

@@ -51,11 +51,13 @@ bundle_ubuntu() {
 	cat >/tmp/postinstall <<EOF
 #!/bin/sh
 /sbin/stop docker || true
+/bin/grep -q "^docker:" /etc/group || /usr/sbin/addgroup --system docker || true
 /sbin/start docker
 EOF
 	cat >/tmp/prerm <<EOF
 #!/bin/sh
 /sbin/stop docker || true
+/usr/sbin/delgroup docker || true
 EOF
 	chmod +x /tmp/postinstall /tmp/prerm
 

+ 1 - 1
hack/vendor.sh

@@ -27,7 +27,7 @@ git_clone github.com/gorilla/context/ 708054d61e5
 
 git_clone github.com/gorilla/mux/ 9b36453141c
 
-git_clone github.com/dotcloud/tar/ d06045a6d9
+git_clone github.com/dotcloud/tar/ e5ea6bb21a
 
 # Docker requires code.google.com/p/go.net/websocket
 PKG=code.google.com/p/go.net REV=84a4013f96e0

+ 1 - 1
registry/registry.go

@@ -70,7 +70,7 @@ func validateRepositoryName(repositoryName string) error {
 	if !validNamespace.MatchString(namespace) {
 		return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", namespace)
 	}
-	validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
+	validRepo := regexp.MustCompile(`^([a-z0-9-_.]+)$`)
 	if !validRepo.MatchString(name) {
 		return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", name)
 	}

+ 12 - 2
registry/registry_test.go

@@ -159,11 +159,11 @@ func TestPushRegistryTag(t *testing.T) {
 func TestPushImageJSONIndex(t *testing.T) {
 	r := spawnTestRegistry(t)
 	imgData := []*ImgData{
-		&ImgData{
+		{
 			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
 			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
 		},
-		&ImgData{
+		{
 			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
 			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
 		},
@@ -196,3 +196,13 @@ func TestSearchRepositories(t *testing.T) {
 	}
 	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
 }
+
+func TestValidRepositoryName(t *testing.T) {
+	if err := validateRepositoryName("docker/docker"); err != nil {
+		t.Fatal(err)
+	}
+	if err := validateRepositoryName("docker/Docker"); err == nil {
+		t.Log("Repository name should be invalid")
+		t.Fail()
+	}
+}

+ 24 - 35
vendor/src/github.com/dotcloud/tar/common.go

@@ -177,18 +177,19 @@ const (
 
 // Keywords for the PAX Extended Header
 const (
-	PAX_ATIME    = "atime"
-	PAX_CHARSET  = "charset"
-	PAX_COMMENT  = "comment"
-	PAX_CTIME    = "ctime" // please note that ctime is not a valid pax header.
-	PAX_GID      = "gid"
-	PAX_GNAME    = "gname"
-	PAX_LINKPATH = "linkpath"
-	PAX_MTIME    = "mtime"
-	PAX_PATH     = "path"
-	PAX_SIZE     = "size"
-	PAX_UID      = "uid"
-	PAX_UNAME    = "uname"
+	paxAtime    = "atime"
+	paxCharset  = "charset"
+	paxComment  = "comment"
+	paxCtime    = "ctime" // please note that ctime is not a valid pax header.
+	paxGid      = "gid"
+	paxGname    = "gname"
+	paxLinkpath = "linkpath"
+	paxMtime    = "mtime"
+	paxPath     = "path"
+	paxSize     = "size"
+	paxUid      = "uid"
+	paxUname    = "uname"
+	paxNone     = ""
 )
 
 // FileInfoHeader creates a partially-populated Header from fi.
@@ -275,36 +276,24 @@ func (sp *slicer) next(n int) (b []byte) {
 	return
 }
 
-func isASCII7Bit(s string) bool {
-	for _, character := range s {
-		if (character & 0x7f) != character {
+func isASCII(s string) bool {
+	for _, c := range s {
+		if c >= 0x80 {
 			return false
 		}
 	}
 	return true
 }
 
-func stripTo7Bits(s string) string {
-	var buffer bytes.Buffer
-	for _, character := range s {
-		if (character & 0x7f) == character {
-			buffer.WriteRune(character)
-		}
+func toASCII(s string) string {
+	if isASCII(s) {
+		return s
 	}
-	return buffer.String()
-}
-
-func stripTo7BitsAndShorten(s string, maxLen int) string {
-	var buffer bytes.Buffer
-	count := 0
-	for _, character := range s {
-		if count == maxLen {
-			break
-		}
-		if (character & 0x7f) == character {
-			buffer.WriteRune(character)
-			count++
+	var buf bytes.Buffer
+	for _, c := range s {
+		if c < 0x80 {
+			buf.WriteByte(byte(c))
 		}
 	}
-	return buffer.String()
+	return buf.String()
 }

+ 19 - 17
vendor/src/github.com/dotcloud/tar/reader.go

@@ -95,45 +95,45 @@ func (tr *Reader) Next() (*Header, error) {
 func mergePAX(hdr *Header, headers map[string]string) error {
 	for k, v := range headers {
 		switch k {
-		case PAX_PATH:
+		case paxPath:
 			hdr.Name = v
-		case PAX_LINKPATH:
+		case paxLinkpath:
 			hdr.Linkname = v
-		case PAX_GNAME:
+		case paxGname:
 			hdr.Gname = v
-		case PAX_UNAME:
+		case paxUname:
 			hdr.Uname = v
-		case PAX_UID:
+		case paxUid:
 			uid, err := strconv.ParseInt(v, 10, 0)
 			if err != nil {
 				return err
 			}
 			hdr.Uid = int(uid)
-		case PAX_GID:
+		case paxGid:
 			gid, err := strconv.ParseInt(v, 10, 0)
 			if err != nil {
 				return err
 			}
 			hdr.Gid = int(gid)
-		case PAX_ATIME:
+		case paxAtime:
 			t, err := parsePAXTime(v)
 			if err != nil {
 				return err
 			}
 			hdr.AccessTime = t
-		case PAX_MTIME:
+		case paxMtime:
 			t, err := parsePAXTime(v)
 			if err != nil {
 				return err
 			}
 			hdr.ModTime = t
-		case PAX_CTIME:
+		case paxCtime:
 			t, err := parsePAXTime(v)
 			if err != nil {
 				return err
 			}
 			hdr.ChangeTime = t
-		case PAX_SIZE:
+		case paxSize:
 			size, err := strconv.ParseInt(v, 10, 0)
 			if err != nil {
 				return err
@@ -243,13 +243,15 @@ func (tr *Reader) octal(b []byte) int64 {
 		return x
 	}
 
-	// Removing leading spaces.
-	for len(b) > 0 && b[0] == ' ' {
-		b = b[1:]
-	}
-	// Removing trailing NULs and spaces.
-	for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
-		b = b[0 : len(b)-1]
+	// Because unused fields are filled with NULs, we need
+	// to skip leading NULs. Fields may also be padded with
+	// spaces or NULs.
+	// So we remove leading and trailing NULs and spaces to
+	// be sure.
+	b = bytes.Trim(b, " \x00")
+
+	if len(b) == 0 {
+		return 0
 	}
 	x, err := strconv.ParseUint(cString(b), 8, 64)
 	if err != nil {

+ 20 - 1
vendor/src/github.com/dotcloud/tar/reader_test.go

@@ -142,6 +142,25 @@ var untarTests = []*untarTest{
 			},
 		},
 	},
+	{
+		file: "testdata/nil-uid.tar", // golang.org/issue/5290
+		headers: []*Header{
+			{
+				Name:     "P1050238.JPG.log",
+				Mode:     0664,
+				Uid:      0,
+				Gid:      0,
+				Size:     14,
+				ModTime:  time.Unix(1365454838, 0),
+				Typeflag: TypeReg,
+				Linkname: "",
+				Uname:    "eyefi",
+				Gname:    "eyefi",
+				Devmajor: 0,
+				Devminor: 0,
+			},
+		},
+	},
 }
 
 func TestReader(t *testing.T) {
@@ -152,6 +171,7 @@ testLoop:
 			t.Errorf("test %d: Unexpected error: %v", i, err)
 			continue
 		}
+		defer f.Close()
 		tr := NewReader(f)
 		for j, header := range test.headers {
 			hdr, err := tr.Next()
@@ -172,7 +192,6 @@ testLoop:
 		if hdr != nil || err != nil {
 			t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
 		}
-		f.Close()
 	}
 }
 

BIN
vendor/src/github.com/dotcloud/tar/testdata/nil-uid.tar


+ 76 - 89
vendor/src/github.com/dotcloud/tar/writer.go

@@ -20,11 +20,11 @@ import (
 )
 
 var (
-	ErrWriteTooLong        = errors.New("archive/tar: write too long")
-	ErrFieldTooLong        = errors.New("archive/tar: header field too long")
-	ErrWriteAfterClose     = errors.New("archive/tar: write after close")
-	errNameTooLong         = errors.New("archive/tar: name too long")
-	errFieldTooLongNoAscii = errors.New("archive/tar: header field too long or contains invalid values")
+	ErrWriteTooLong    = errors.New("archive/tar: write too long")
+	ErrFieldTooLong    = errors.New("archive/tar: header field too long")
+	ErrWriteAfterClose = errors.New("archive/tar: write after close")
+	errNameTooLong     = errors.New("archive/tar: name too long")
+	errInvalidHeader   = errors.New("archive/tar: header field too long or contains invalid values")
 )
 
 // A Writer provides sequential writing of a tar archive in POSIX.1 format.
@@ -67,29 +67,23 @@ func (tw *Writer) Flush() error {
 }
 
 // Write s into b, terminating it with a NUL if there is room.
-func (tw *Writer) cString(b []byte, s string) {
+// If the value is too long for the field and allowPax is true add a paxheader record instead
+func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
+	needsPaxHeader := allowPax && len(s) > len(b) || !isASCII(s)
+	if needsPaxHeader {
+		paxHeaders[paxKeyword] = s
+		return
+	}
 	if len(s) > len(b) {
 		if tw.err == nil {
 			tw.err = ErrFieldTooLong
 		}
 		return
 	}
-	copy(b, s)
-	if len(s) < len(b) {
-		b[len(s)] = 0
-	}
-}
-
-// Write s into b, terminating it with a NUL if there is room. If the value is too long for the field add a paxheader record instead
-func (tw *Writer) fillHeaderField(b []byte, paxHeader map[string]string, paxKeyword string, s string) {
-	needsPaxHeader := len(s) > len(b) || !isASCII7Bit(s)
-	if needsPaxHeader {
-		paxHeader[paxKeyword] = s
-		return
-	}
-	copy(b, stripTo7BitsAndShorten(s, len(b)))
-	if len(s) < len(b) {
-		b[len(s)] = 0
+	ascii := toASCII(s)
+	copy(b, ascii)
+	if len(ascii) < len(b) {
+		b[len(ascii)] = 0
 	}
 }
 
@@ -100,17 +94,27 @@ func (tw *Writer) octal(b []byte, x int64) {
 	for len(s)+1 < len(b) {
 		s = "0" + s
 	}
-	tw.cString(b, s)
+	tw.cString(b, s, false, paxNone, nil)
 }
 
 // Write x into b, either as octal or as binary (GNUtar/star extension).
-func (tw *Writer) numeric(b []byte, x int64) {
+// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead
+func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
 	// Try octal first.
 	s := strconv.FormatInt(x, 8)
 	if len(s) < len(b) {
 		tw.octal(b, x)
 		return
 	}
+
+	// If it is too long for octal, and pax is preferred, use a pax header
+	if allowPax && tw.preferPax {
+		tw.octal(b, 0)
+		s := strconv.FormatInt(x, 10)
+		paxHeaders[paxKeyword] = s
+		return
+	}
+
 	// Too big: use binary (big-endian).
 	tw.usedBinary = true
 	for i := len(b) - 1; x > 0 && i >= 0; i-- {
@@ -120,28 +124,6 @@ func (tw *Writer) numeric(b []byte, x int64) {
 	b[0] |= 0x80 // highest bit indicates binary format
 }
 
-// Write x into b, if it is smaller than 2097151. If the value is too long for the field add a paxheader record instead
-func (tw *Writer) fillNumericHeaderField(b []byte, paxHeader map[string]string, paxKeyword string, x int64) {
-	if tw.preferPax && x > 2097151 {
-		s := strconv.FormatInt(x, 10)
-		paxHeader[paxKeyword] = s
-		tw.numeric(b, 0)
-	} else {
-		tw.numeric(b, x)
-	}
-}
-
-// Write x into b, if it is smaller than 2097151. If the value is too long for the field add a paxheader record instead
-func (tw *Writer) fillNumericLongHeaderField(b []byte, paxHeader map[string]string, paxKeyword string, x int64) {
-	if tw.preferPax && x > 8589934591 {
-		s := strconv.FormatInt(x, 10)
-		paxHeader[paxKeyword] = s
-		tw.numeric(b, 0)
-	} else {
-		tw.numeric(b, x)
-	}
-}
-
 var (
 	minTime = time.Unix(0, 0)
 	// There is room for 11 octal digits (33 bits) of mtime.
@@ -158,7 +140,7 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
 // WriteHeader writes hdr and prepares to accept the file's contents.
 // WriteHeader calls Flush if it is not the first header.
 // Calling after a Close will return ErrWriteAfterClose.
-//  As this method is called internally by writePax header it allows to
+// As this method is called internally by writePax header to allow it to
 // suppress writing the pax header.
 func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 	if tw.closed {
@@ -172,7 +154,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 	}
 
 	// a map to hold pax header records, if any are needed
-	paxHeaderRecords := make(map[string]string)
+	paxHeaders := make(map[string]string)
 
 	// TODO(shanemhansen): we might want to use PAX headers for
 	// subsecond time resolution, but for now let's just capture
@@ -184,7 +166,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 	// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
 	pathHeaderBytes := s.next(fileNameSize)
 
-	tw.fillHeaderField(pathHeaderBytes, paxHeaderRecords, PAX_PATH, hdr.Name)
+	tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders)
 
 	// Handle out of range ModTime carefully.
 	var modTime int64
@@ -192,48 +174,48 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 		modTime = hdr.ModTime.Unix()
 	}
 
-	tw.octal(s.next(8), hdr.Mode)                                                   // 100:108
-	tw.fillNumericHeaderField(s.next(8), paxHeaderRecords, PAX_UID, int64(hdr.Uid)) // 108:116
-	tw.fillNumericHeaderField(s.next(8), paxHeaderRecords, PAX_GID, int64(hdr.Gid)) // 116:124
-	tw.fillNumericLongHeaderField(s.next(12), paxHeaderRecords, PAX_SIZE, hdr.Size) // 124:136
-	tw.numeric(s.next(12), modTime)                                                 // 136:148 --- consider using pax for finer granularity
-	s.next(8)                                                                       // chksum (148:156)
-	s.next(1)[0] = hdr.Typeflag                                                     // 156:157
+	tw.octal(s.next(8), hdr.Mode)                                   // 100:108
+	tw.numeric(s.next(8), int64(hdr.Uid), true, paxUid, paxHeaders) // 108:116
+	tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124
+	tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders)     // 124:136
+	tw.numeric(s.next(12), modTime, false, paxNone, nil)            // 136:148 --- consider using pax for finer granularity
+	s.next(8)                                                       // chksum (148:156)
+	s.next(1)[0] = hdr.Typeflag                                     // 156:157
 
-	tw.fillHeaderField(s.next(100), paxHeaderRecords, PAX_LINKPATH, hdr.Linkname)
+	tw.cString(s.next(100), hdr.Linkname, true, paxLinkpath, paxHeaders)
 
-	copy(s.next(8), []byte("ustar\x0000"))                                 // 257:265
-	tw.fillHeaderField(s.next(32), paxHeaderRecords, PAX_UNAME, hdr.Uname) // 265:297
-	tw.fillHeaderField(s.next(32), paxHeaderRecords, PAX_GNAME, hdr.Gname) // 297:329
-	tw.numeric(s.next(8), hdr.Devmajor)                                    // 329:337
-	tw.numeric(s.next(8), hdr.Devminor)                                    // 337:345
+	copy(s.next(8), []byte("ustar\x0000"))                        // 257:265
+	tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297
+	tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329
+	tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil)      // 329:337
+	tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil)      // 337:345
 
 	// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
 	prefixHeaderBytes := s.next(155)
-	tw.cString(prefixHeaderBytes, "") // 345:500  prefix
+	tw.cString(prefixHeaderBytes, "", false, paxNone, nil) // 345:500  prefix
 
 	// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
 	if tw.usedBinary {
 		copy(header[257:265], []byte("ustar  \x00"))
 	}
 
-	_, paxPathUsed := paxHeaderRecords[PAX_PATH]
+	_, paxPathUsed := paxHeaders[paxPath]
 	// try to use a ustar header when only the name is too long
-	if !tw.preferPax && len(paxHeaderRecords) == 1 && paxPathUsed {
+	if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
 		suffix := hdr.Name
 		prefix := ""
-		if len(hdr.Name) > fileNameSize && isASCII7Bit(hdr.Name) {
+		if len(hdr.Name) > fileNameSize && isASCII(hdr.Name) {
 			var err error
 			prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
 			if err == nil {
 				// ok we can use a ustar long name instead of pax, now correct the fields
 
 				// remove the path field from the pax header. this will suppress the pax header
-				delete(paxHeaderRecords, PAX_PATH)
+				delete(paxHeaders, paxPath)
 
 				// update the path fields
-				tw.cString(pathHeaderBytes, suffix)
-				tw.cString(prefixHeaderBytes, prefix)
+				tw.cString(pathHeaderBytes, suffix, false, paxNone, nil)
+				tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
 
 				// Use the ustar magic if we used ustar long names.
 				if len(prefix) > 0 {
@@ -254,17 +236,16 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 		return tw.err
 	}
 
-	if len(paxHeaderRecords) > 0 {
-		if allowPax {
-			if err := tw.writePAXHeader(hdr, paxHeaderRecords); err != nil {
-				return err
-			}
-		} else {
-			return errFieldTooLongNoAscii
+	if len(paxHeaders) > 0 {
+		if !allowPax {
+			return errInvalidHeader
+		}
+		if err := tw.writePAXHeader(hdr, paxHeaders); err != nil {
+			return err
 		}
 	}
 	tw.nb = int64(hdr.Size)
-	tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
+	tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
 
 	_, tw.err = tw.w.Write(header)
 	return tw.err
@@ -282,8 +263,11 @@ func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err er
 		length--
 	}
 	i := strings.LastIndex(name[:length], "/")
-	nlen := length - i - 1
-	if i <= 0 || nlen > fileNameSize || nlen == 0 {
+	// nlen contains the resulting length in the name field.
+	// plen contains the resulting length in the prefix field.
+	nlen := len(name) - i - 1
+	plen := i
+	if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
 		err = errNameTooLong
 		return
 	}
@@ -293,7 +277,7 @@ func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err er
 
 // writePaxHeader writes an extended pax header to the
 // archive.
-func (tw *Writer) writePAXHeader(hdr *Header, paxHeaderRecords map[string]string) error {
+func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error {
 	// Prepare extended header
 	ext := new(Header)
 	ext.Typeflag = TypeXHeader
@@ -307,12 +291,16 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaderRecords map[string]string
 	fullName := path.Join(dir,
 		fmt.Sprintf("PaxHeaders.%d", pid), file)
 
-	ext.Name = stripTo7BitsAndShorten(fullName, 100)
+	ascii := toASCII(fullName)
+	if len(ascii) > 100 {
+		ascii = ascii[:100]
+	}
+	ext.Name = ascii
 	// Construct the body
 	var buf bytes.Buffer
 
-	for k, v := range paxHeaderRecords {
-		fmt.Fprint(&buf, paxHeader(k, v))
+	for k, v := range paxHeaders {
+		fmt.Fprint(&buf, paxHeader(k+"="+v))
 	}
 
 	ext.Size = int64(len(buf.Bytes()))
@@ -329,17 +317,16 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaderRecords map[string]string
 }
 
 // paxHeader formats a single pax record, prefixing it with the appropriate length
-func paxHeader(keyword string, value string) string {
-
-	const padding = 3 // Extra padding for space and newline
-	size := len(keyword) + len(value) + padding
+func paxHeader(msg string) string {
+	const padding = 2 // Extra padding for space and newline
+	size := len(msg) + padding
 	size += len(strconv.Itoa(size))
-	record := fmt.Sprintf("%d %s=%s\n", size, keyword, value)
+	record := fmt.Sprintf("%d %s\n", size, msg)
 	if len(record) != size {
 		// Final adjustment if adding size increased
 		// the number of digits in size
 		size = len(record)
-		record = fmt.Sprintf("%d %s=%s\n", size, keyword, value)
+		record = fmt.Sprintf("%d %s\n", size, msg)
 	}
 	return record
 }

+ 44 - 8
vendor/src/github.com/dotcloud/tar/writer_test.go

@@ -341,17 +341,53 @@ func TestPaxNonAscii(t *testing.T) {
 func TestPAXHeader(t *testing.T) {
 	medName := strings.Repeat("CD", 50)
 	longName := strings.Repeat("AB", 100)
-	paxTests := [][3]string{
-		{PAX_PATH, "/etc/hosts", "19 path=/etc/hosts\n"},
-		{"a", "b", "6 a=b\n"},          // Single digit length
-		{"a", "names", "11 a=names\n"}, // Test case involving carries
-		{PAX_PATH, longName, fmt.Sprintf("210 path=%s\n", longName)},
-		{PAX_PATH, medName, fmt.Sprintf("110 path=%s\n", medName)}}
+	paxTests := [][2]string{
+		{paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
+		{"a=b", "6 a=b\n"},          // Single digit length
+		{"a=names", "11 a=names\n"}, // Test case involving carries
+		{paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
+		{paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
 
 	for _, test := range paxTests {
-		field, key, expected := test[0], test[1], test[2]
-		if result := paxHeader(field, key); result != expected {
+		key, expected := test[0], test[1]
+		if result := paxHeader(key); result != expected {
 			t.Fatalf("paxHeader: got %s, expected %s", result, expected)
 		}
 	}
 }
+
+func TestUSTARLongName(t *testing.T) {
+	// Create an archive with a path that failed to split with USTAR extension in previous versions.
+	fileinfo, err := os.Stat("testdata/small.txt")
+	if err != nil {
+		t.Fatal(err)
+	}
+	hdr, err := FileInfoHeader(fileinfo, "")
+	hdr.Typeflag = TypeDir
+	if err != nil {
+		t.Fatalf("os.Stat:1 %v", err)
+	}
+	// Force a PAX long name to be written. The name was taken from a practical example
+	// that fails and replaced ever char through numbers to anonymize the sample.
+	longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
+	hdr.Name = longName
+
+	hdr.Size = 0
+	var buf bytes.Buffer
+	writer := NewWriter(&buf)
+	if err := writer.WriteHeader(hdr); err != nil {
+		t.Fatal(err)
+	}
+	if err := writer.Close(); err != nil {
+		t.Fatal(err)
+	}
+	// Test that we can get a long name back out of the archive.
+	reader := NewReader(&buf)
+	hdr, err = reader.Next()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if hdr.Name != longName {
+		t.Fatal("Couldn't recover long name")
+	}
+}