From a7e181c8576e0413da888bea95fb7155173714ea Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Sat, 22 Mar 2014 12:02:30 +0900 Subject: [PATCH 001/167] Add a test for mount.GetMounts Because mount.parseInfoFile is only available on Linux Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) --- pkg/mount/mount_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/mount/mount_test.go b/pkg/mount/mount_test.go index 6edc31d41..9272504a7 100644 --- a/pkg/mount/mount_test.go +++ b/pkg/mount/mount_test.go @@ -108,3 +108,21 @@ func TestMountReadonly(t *testing.T) { t.Fatal("Should not be able to open a ro file as rw") } } + +func TestGetMounts(t *testing.T) { + mounts, err := GetMounts() + if err != nil { + t.Fatal(err) + } + + root := false + for _, entry := range mounts { + if entry.Mountpoint == "/" { + root = true + } + } + + if !root { + t.Fatal("/ should be mounted at least") + } +} From ca7a0e6d6e31c02baf692315d2481ef35a7e9134 Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Sat, 22 Mar 2014 12:03:09 +0900 Subject: [PATCH 002/167] FreeBSD's nullfs doesn't support file mount FreeBSD doesn't have "bind" mount, but nullfs might be a similar feature. However nullfs can mount only directories. Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) --- pkg/mount/mount_test.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/mount/mount_test.go b/pkg/mount/mount_test.go index 9272504a7..94552dbea 100644 --- a/pkg/mount/mount_test.go +++ b/pkg/mount/mount_test.go @@ -31,10 +31,15 @@ func TestMounted(t *testing.T) { defer os.RemoveAll(tmp) var ( - sourcePath = path.Join(tmp, "sourcefile.txt") - targetPath = path.Join(tmp, "targetfile.txt") + sourceDir = path.Join(tmp, "source") + targetDir = path.Join(tmp, "target") + sourcePath = path.Join(sourceDir, "file.txt") + targetPath = path.Join(targetDir, "file.txt") ) + os.Mkdir(sourceDir, 0777) + os.Mkdir(targetDir, 0777) + f, err := os.Create(sourcePath) if err != nil { t.Fatal(err) @@ -48,23 +53,23 @@ func TestMounted(t *testing.T) { } f.Close() - if err := Mount(sourcePath, targetPath, "none", "bind,rw"); err != nil { + if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { t.Fatal(err) } defer func() { - if err := Unmount(targetPath); err != nil { + if err := Unmount(targetDir); err != nil { t.Fatal(err) } }() - mounted, err := Mounted(targetPath) + mounted, err := Mounted(targetDir) if err != nil { t.Fatal(err) } if !mounted { - t.Fatalf("Expected %s to be mounted", targetPath) + t.Fatalf("Expected %s to be mounted", targetDir) } - if _, err := os.Stat(targetPath); err != nil { + if _, err := os.Stat(targetDir); err != nil { t.Fatal(err) } } @@ -77,10 +82,15 @@ func TestMountReadonly(t *testing.T) { defer os.RemoveAll(tmp) var ( - sourcePath = path.Join(tmp, "sourcefile.txt") - targetPath = path.Join(tmp, "targetfile.txt") + sourceDir = path.Join(tmp, "source") + targetDir = path.Join(tmp, "target") + sourcePath = path.Join(sourceDir, "file.txt") + targetPath = path.Join(targetDir, "file.txt") ) + os.Mkdir(sourceDir, 0777) + os.Mkdir(targetDir, 0777) + f, err := os.Create(sourcePath) if err != nil { t.Fatal(err) @@ -94,7 +104,7 @@ func TestMountReadonly(t *testing.T) { } f.Close() - if err := Mount(sourcePath, targetPath, "none", "bind,ro"); err != nil { + if err := Mount(sourceDir, targetDir, "none", "bind,ro"); err != nil { t.Fatal(err) } defer func() { From 3754fdd7caae423b606c6fb5160683534a830a1a Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Fri, 21 Mar 2014 00:52:12 +0900 Subject: [PATCH 003/167] Support FreeBSD on pkg/mount Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) --- pkg/mount/flags.go | 62 ++++++++++++++++ pkg/mount/flags_freebsd.go | 28 +++++++ pkg/mount/flags_linux.go | 73 +++++-------------- pkg/mount/flags_unsupported.go | 23 +++++- pkg/mount/mount_test.go | 7 +- pkg/mount/mounter_freebsd.go | 59 +++++++++++++++ pkg/mount/mounter_unsupported.go | 2 +- pkg/mount/mountinfo.go | 72 ------------------ pkg/mount/mountinfo_freebsd.go | 38 ++++++++++ pkg/mount/mountinfo_linux.go | 73 +++++++++++++++++++ ...ntinfo_test.go => mountinfo_test_linux.go} | 0 pkg/mount/mountinfo_unsupported.go | 12 +++ 12 files changed, 312 insertions(+), 137 deletions(-) create mode 100644 pkg/mount/flags.go create mode 100644 pkg/mount/flags_freebsd.go create mode 100644 pkg/mount/mounter_freebsd.go create mode 100644 pkg/mount/mountinfo_freebsd.go create mode 100644 pkg/mount/mountinfo_linux.go rename pkg/mount/{mountinfo_test.go => mountinfo_test_linux.go} (100%) create mode 100644 pkg/mount/mountinfo_unsupported.go diff --git a/pkg/mount/flags.go b/pkg/mount/flags.go new file mode 100644 index 000000000..742698e8d --- /dev/null +++ b/pkg/mount/flags.go @@ -0,0 +1,62 @@ +package mount + +import ( + "strings" +) + +// Parse fstab type mount options into mount() flags +// and device specific data +func parseOptions(options string) (int, string) { + var ( + flag int + data []string + ) + + flags := map[string]struct { + clear bool + flag int + }{ + "defaults": {false, 0}, + "ro": {false, RDONLY}, + "rw": {true, RDONLY}, + "suid": {true, NOSUID}, + "nosuid": {false, NOSUID}, + "dev": {true, NODEV}, + "nodev": {false, NODEV}, + "exec": {true, NOEXEC}, + "noexec": {false, NOEXEC}, + "sync": {false, SYNCHRONOUS}, + "async": {true, SYNCHRONOUS}, + "dirsync": {false, DIRSYNC}, + "remount": {false, REMOUNT}, + "mand": {false, MANDLOCK}, + "nomand": {true, MANDLOCK}, + "atime": {true, NOATIME}, + "noatime": {false, NOATIME}, + "diratime": {true, NODIRATIME}, + "nodiratime": {false, NODIRATIME}, + "bind": {false, BIND}, + "rbind": {false, RBIND}, + "private": {false, PRIVATE}, + "relatime": {false, RELATIME}, + "norelatime": {true, RELATIME}, + "strictatime": {false, STRICTATIME}, + "nostrictatime": {true, STRICTATIME}, + } + + for _, o := range strings.Split(options, ",") { + // If the option does not exist in the flags table or the flag + // is not supported on the platform, + // then it is a data value for a specific fs type + if f, exists := flags[o]; exists && f.flag != 0 { + if f.clear { + flag &= ^f.flag + } else { + flag |= f.flag + } + } else { + data = append(data, o) + } + } + return flag, strings.Join(data, ",") +} diff --git a/pkg/mount/flags_freebsd.go b/pkg/mount/flags_freebsd.go new file mode 100644 index 000000000..4ddf4d709 --- /dev/null +++ b/pkg/mount/flags_freebsd.go @@ -0,0 +1,28 @@ +// +build freebsd,cgo + +package mount + +/* +#include +*/ +import "C" + +const ( + RDONLY = C.MNT_RDONLY + NOSUID = C.MNT_NOSUID + NOEXEC = C.MNT_NOEXEC + SYNCHRONOUS = C.MNT_SYNCHRONOUS + NOATIME = C.MNT_NOATIME + + BIND = 0 + DIRSYNC = 0 + MANDLOCK = 0 + NODEV = 0 + NODIRATIME = 0 + PRIVATE = 0 + RBIND = 0 + RELATIVE = 0 + RELATIME = 0 + REMOUNT = 0 + STRICTATIME = 0 +) diff --git a/pkg/mount/flags_linux.go b/pkg/mount/flags_linux.go index b7124b1df..19c882fcd 100644 --- a/pkg/mount/flags_linux.go +++ b/pkg/mount/flags_linux.go @@ -3,62 +3,23 @@ package mount import ( - "strings" "syscall" ) -// Parse fstab type mount options into mount() flags -// and device specific data -func parseOptions(options string) (int, string) { - var ( - flag int - data []string - ) - - flags := map[string]struct { - clear bool - flag int - }{ - "defaults": {false, 0}, - "ro": {false, syscall.MS_RDONLY}, - "rw": {true, syscall.MS_RDONLY}, - "suid": {true, syscall.MS_NOSUID}, - "nosuid": {false, syscall.MS_NOSUID}, - "dev": {true, syscall.MS_NODEV}, - "nodev": {false, syscall.MS_NODEV}, - "exec": {true, syscall.MS_NOEXEC}, - "noexec": {false, syscall.MS_NOEXEC}, - "sync": {false, syscall.MS_SYNCHRONOUS}, - "async": {true, syscall.MS_SYNCHRONOUS}, - "dirsync": {false, syscall.MS_DIRSYNC}, - "remount": {false, syscall.MS_REMOUNT}, - "mand": {false, syscall.MS_MANDLOCK}, - "nomand": {true, syscall.MS_MANDLOCK}, - "atime": {true, syscall.MS_NOATIME}, - "noatime": {false, syscall.MS_NOATIME}, - "diratime": {true, syscall.MS_NODIRATIME}, - "nodiratime": {false, syscall.MS_NODIRATIME}, - "bind": {false, syscall.MS_BIND}, - "rbind": {false, syscall.MS_BIND | syscall.MS_REC}, - "private": {false, syscall.MS_PRIVATE}, - "relatime": {false, syscall.MS_RELATIME}, - "norelatime": {true, syscall.MS_RELATIME}, - "strictatime": {false, syscall.MS_STRICTATIME}, - "nostrictatime": {true, syscall.MS_STRICTATIME}, - } - - for _, o := range strings.Split(options, ",") { - // If the option does not exist in the flags table then it is a - // data value for a specific fs type - if f, exists := flags[o]; exists { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else { - data = append(data, o) - } - } - return flag, strings.Join(data, ",") -} +const ( + RDONLY = syscall.MS_RDONLY + NOSUID = syscall.MS_NOSUID + NODEV = syscall.MS_NODEV + NOEXEC = syscall.MS_NOEXEC + SYNCHRONOUS = syscall.MS_SYNCHRONOUS + DIRSYNC = syscall.MS_DIRSYNC + REMOUNT = syscall.MS_REMOUNT + MANDLOCK = syscall.MS_MANDLOCK + NOATIME = syscall.MS_NOATIME + NODIRATIME = syscall.MS_NODIRATIME + BIND = syscall.MS_BIND + RBIND = syscall.MS_BIND | syscall.MS_REC + PRIVATE = syscall.MS_PRIVATE + RELATIME = syscall.MS_RELATIME + STRICTATIME = syscall.MS_STRICTATIME +) diff --git a/pkg/mount/flags_unsupported.go b/pkg/mount/flags_unsupported.go index c894efe5b..e59835415 100644 --- a/pkg/mount/flags_unsupported.go +++ b/pkg/mount/flags_unsupported.go @@ -1,7 +1,22 @@ -// +build !linux !amd64 +// +build !linux,!freebsd linux,!amd64 freebsd,!cgo package mount -func parseOptions(options string) (int, string) { - panic("Not implemented") -} +const ( + BIND = 0 + DIRSYNC = 0 + MANDLOCK = 0 + NOATIME = 0 + NODEV = 0 + NODIRATIME = 0 + NOEXEC = 0 + NOSUID = 0 + PRIVATE = 0 + RBIND = 0 + RELATIME = 0 + RELATIVE = 0 + REMOUNT = 0 + STRICTATIME = 0 + SYNCHRONOUS = 0 + RDONLY = 0 +) diff --git a/pkg/mount/mount_test.go b/pkg/mount/mount_test.go index 94552dbea..5c7f1b86a 100644 --- a/pkg/mount/mount_test.go +++ b/pkg/mount/mount_test.go @@ -3,12 +3,11 @@ package mount import ( "os" "path" - "syscall" "testing" ) func TestMountOptionsParsing(t *testing.T) { - options := "bind,ro,size=10k" + options := "noatime,ro,size=10k" flag, data := parseOptions(options) @@ -16,7 +15,7 @@ func TestMountOptionsParsing(t *testing.T) { t.Fatalf("Expected size=10 got %s", data) } - expectedFlag := syscall.MS_BIND | syscall.MS_RDONLY + expectedFlag := NOATIME | RDONLY if flag != expectedFlag { t.Fatalf("Expected %d got %d", expectedFlag, flag) @@ -108,7 +107,7 @@ func TestMountReadonly(t *testing.T) { t.Fatal(err) } defer func() { - if err := Unmount(targetPath); err != nil { + if err := Unmount(targetDir); err != nil { t.Fatal(err) } }() diff --git a/pkg/mount/mounter_freebsd.go b/pkg/mount/mounter_freebsd.go new file mode 100644 index 000000000..bb870e6f5 --- /dev/null +++ b/pkg/mount/mounter_freebsd.go @@ -0,0 +1,59 @@ +package mount + +/* +#include +#include +#include +#include +#include +#include +*/ +import "C" + +import ( + "fmt" + "strings" + "syscall" + "unsafe" +) + +func allocateIOVecs(options []string) []C.struct_iovec { + out := make([]C.struct_iovec, len(options)) + for i, option := range options { + out[i].iov_base = unsafe.Pointer(C.CString(option)) + out[i].iov_len = C.size_t(len(option) + 1) + } + return out +} + +func mount(device, target, mType string, flag uintptr, data string) error { + isNullFS := false + + xs := strings.Split(data, ",") + for _, x := range xs { + if x == "bind" { + isNullFS = true + } + } + + options := []string{"fspath", target} + if isNullFS { + options = append(options, "fstype", "nullfs", "target", device) + } else { + options = append(options, "fstype", mType, "from", device) + } + rawOptions := allocateIOVecs(options) + for _, rawOption := range rawOptions { + defer C.free(rawOption.iov_base) + } + + if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { + reason := C.GoString(C.strerror(*C.__error())) + return fmt.Errorf("Failed to call nmount: %s", reason) + } + return nil +} + +func unmount(target string, flag int) error { + return syscall.Unmount(target, flag) +} diff --git a/pkg/mount/mounter_unsupported.go b/pkg/mount/mounter_unsupported.go index ee27b35f8..06f2ac00b 100644 --- a/pkg/mount/mounter_unsupported.go +++ b/pkg/mount/mounter_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux !amd64 +// +build !linux,!freebsd linux,!amd64 freebsd,!cgo package mount diff --git a/pkg/mount/mountinfo.go b/pkg/mount/mountinfo.go index 32996f05c..78b83ced4 100644 --- a/pkg/mount/mountinfo.go +++ b/pkg/mount/mountinfo.go @@ -1,79 +1,7 @@ package mount -import ( - "bufio" - "fmt" - "io" - "os" - "strings" -) - -const ( - /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - - (1) mount ID: unique identifier of the mount (may be reused after umount) - (2) parent ID: ID of parent (or of self for the top of the mount tree) - (3) major:minor: value of st_dev for files on filesystem - (4) root: root of the mount within the filesystem - (5) mount point: mount point relative to the process's root - (6) mount options: per mount options - (7) optional fields: zero or more fields of the form "tag[:value]" - (8) separator: marks the end of the optional fields - (9) filesystem type: name of filesystem of the form "type[.subtype]" - (10) mount source: filesystem specific information or "none" - (11) super options: per super block options*/ - mountinfoFormat = "%d %d %d:%d %s %s %s " -) - type MountInfo struct { Id, Parent, Major, Minor int Root, Mountpoint, Opts string Fstype, Source, VfsOpts string } - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts -func parseMountTable() ([]*MountInfo, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} - -func parseInfoFile(r io.Reader) ([]*MountInfo, error) { - var ( - s = bufio.NewScanner(r) - out = []*MountInfo{} - ) - - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - - var ( - p = &MountInfo{} - text = s.Text() - ) - - if _, err := fmt.Sscanf(text, mountinfoFormat, - &p.Id, &p.Parent, &p.Major, &p.Minor, - &p.Root, &p.Mountpoint, &p.Opts); err != nil { - return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) - } - // Safe as mountinfo encodes mountpoints with spaces as \040. - index := strings.Index(text, " - ") - postSeparatorFields := strings.Fields(text[index+3:]) - if len(postSeparatorFields) != 3 { - return nil, fmt.Errorf("Error did not find 3 fields post '-' in '%s'", text) - } - p.Fstype = postSeparatorFields[0] - p.Source = postSeparatorFields[1] - p.VfsOpts = postSeparatorFields[2] - out = append(out, p) - } - return out, nil -} diff --git a/pkg/mount/mountinfo_freebsd.go b/pkg/mount/mountinfo_freebsd.go new file mode 100644 index 000000000..a16bdb84f --- /dev/null +++ b/pkg/mount/mountinfo_freebsd.go @@ -0,0 +1,38 @@ +package mount + +/* +#include +#include +#include +*/ +import "C" + +import ( + "fmt" + "reflect" + "unsafe" +) + +// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts +func parseMountTable() ([]*MountInfo, error) { + var rawEntries *C.struct_statfs + + count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) + if count == 0 { + return nil, fmt.Errorf("Failed to call getmntinfo") + } + + var entries []C.struct_statfs + header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) + header.Cap = count + header.Len = count + header.Data = uintptr(unsafe.Pointer(rawEntries)) + + var out []*MountInfo + for _, entry := range entries { + var mountinfo MountInfo + mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) + out = append(out, &mountinfo) + } + return out, nil +} diff --git a/pkg/mount/mountinfo_linux.go b/pkg/mount/mountinfo_linux.go new file mode 100644 index 000000000..01c954fff --- /dev/null +++ b/pkg/mount/mountinfo_linux.go @@ -0,0 +1,73 @@ +package mount + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" +) + +const ( + /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + + (1) mount ID: unique identifier of the mount (may be reused after umount) + (2) parent ID: ID of parent (or of self for the top of the mount tree) + (3) major:minor: value of st_dev for files on filesystem + (4) root: root of the mount within the filesystem + (5) mount point: mount point relative to the process's root + (6) mount options: per mount options + (7) optional fields: zero or more fields of the form "tag[:value]" + (8) separator: marks the end of the optional fields + (9) filesystem type: name of filesystem of the form "type[.subtype]" + (10) mount source: filesystem specific information or "none" + (11) super options: per super block options*/ + mountinfoFormat = "%d %d %d:%d %s %s %s " +) + +// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts +func parseMountTable() ([]*MountInfo, error) { + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return nil, err + } + defer f.Close() + + return parseInfoFile(f) +} + +func parseInfoFile(r io.Reader) ([]*MountInfo, error) { + var ( + s = bufio.NewScanner(r) + out = []*MountInfo{} + ) + + for s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + + var ( + p = &MountInfo{} + text = s.Text() + ) + + if _, err := fmt.Sscanf(text, mountinfoFormat, + &p.Id, &p.Parent, &p.Major, &p.Minor, + &p.Root, &p.Mountpoint, &p.Opts); err != nil { + return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) + } + // Safe as mountinfo encodes mountpoints with spaces as \040. + index := strings.Index(text, " - ") + postSeparatorFields := strings.Fields(text[index+3:]) + if len(postSeparatorFields) != 3 { + return nil, fmt.Errorf("Error did not find 3 fields post '-' in '%s'", text) + } + p.Fstype = postSeparatorFields[0] + p.Source = postSeparatorFields[1] + p.VfsOpts = postSeparatorFields[2] + out = append(out, p) + } + return out, nil +} diff --git a/pkg/mount/mountinfo_test.go b/pkg/mount/mountinfo_test_linux.go similarity index 100% rename from pkg/mount/mountinfo_test.go rename to pkg/mount/mountinfo_test_linux.go diff --git a/pkg/mount/mountinfo_unsupported.go b/pkg/mount/mountinfo_unsupported.go new file mode 100644 index 000000000..352336b9a --- /dev/null +++ b/pkg/mount/mountinfo_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux,!freebsd freebsd,!cgo + +package mount + +import ( + "fmt" + "runtime" +) + +func parseMountTable() ([]*MountInfo, error) { + return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} From 05e9574cf34b4615030d23a0f816cc309aa2e949 Mon Sep 17 00:00:00 2001 From: Sam Bailey Date: Sat, 31 May 2014 20:58:58 +1000 Subject: [PATCH 004/167] add mkimage support for mageia using urpmi Docker-DCO-1.1-Signed-off-by: Sam Bailey (github: thatsamguy) --- contrib/mkimage.sh | 2 + contrib/mkimage/mageia-urpmi | 79 ++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100755 contrib/mkimage/mageia-urpmi diff --git a/contrib/mkimage.sh b/contrib/mkimage.sh index db4815c20..ab8f71a30 100755 --- a/contrib/mkimage.sh +++ b/contrib/mkimage.sh @@ -9,6 +9,8 @@ usage() { echo >&2 " $mkimg -t someuser/ubuntu debootstrap --include=ubuntu-minimal trusty" echo >&2 " $mkimg -t someuser/busybox busybox-static" echo >&2 " $mkimg -t someuser/centos:5 rinse --distribution centos-5" + echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4" + echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4 --mirror=http://somemirror/" exit 1 } diff --git a/contrib/mkimage/mageia-urpmi b/contrib/mkimage/mageia-urpmi new file mode 100755 index 000000000..252e82787 --- /dev/null +++ b/contrib/mkimage/mageia-urpmi @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# +# Needs to be run from Mageia 4 or greater for kernel support for docker. +# +# Mageia 4 does not have docker available in official repos, so please +# install and run the docker binary manually. +# +# Tested working versions are for Mageia 2 onwards (inc. cauldron). +# +set -e + +rootfsDir="$1" +shift + +optTemp=$(getopt --options '+v:,m:' --longoptions 'version:,mirror:' --name mageia-urpmi -- "$@") +eval set -- "$optTemp" +unset optTemp + +installversion= +mirror= +while true; do + case "$1" in + -v|--version) installversion="$2" ; shift 2 ;; + -m|--mirror) mirror="$2" ; shift 2 ;; + --) shift ; break ;; + esac +done + +if [ -z $installversion ]; then + # Attempt to match host version + if [ -r /etc/mageia-release ]; then + installversion="$(sed 's/^[^0-9\]*\([0-9.]\+\).*$/\1/' /etc/mageia-release)" + else + echo "Error: no version supplied and unable to detect host mageia version" + exit 1 + fi +fi + +if [ -z $mirror ]; then + # No mirror provided, default to mirrorlist + mirror="--mirrorlist https://mirrors.mageia.org/api/mageia.$installversion.x86_64.list" +fi + +( + set -x + urpmi.addmedia --distrib \ + $mirror \ + --urpmi-root "$rootfsDir" + urpmi basesystem-minimal urpmi \ + --auto \ + --no-suggests \ + --urpmi-root "$rootfsDir" \ + --root "$rootfsDir" +) + +( + # Clean cruft to reduce image size - stolen and modifed from .febootstrap-minimize + set -x + cd "$rootfsDir" + # locales + rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive} + # docs + rm -rf usr/share/{man,doc,info,gnome/help} + # cracklib + rm -rf usr/share/cracklib + # i18n + rm -rf usr/share/i18n + # sln + rm -rf sbin/sln + # ldconfig + #rm -rf sbin/ldconfig + rm -rf etc/ld.so.cache var/cache/ldconfig + mkdir -p --mode=0755 var/cache/ldconfig +) + +if [ -d "$rootfsDir/etc/sysconfig" ]; then + # allow networking init scripts inside the container to work without extra steps + echo 'NETWORKING=yes' > "$rootfsDir/etc/sysconfig/network" +fi From d9885abdc4a7e028092fc18715b69075bb7c2f8d Mon Sep 17 00:00:00 2001 From: Sam Bailey Date: Tue, 3 Jun 2014 20:41:32 +1000 Subject: [PATCH 005/167] reuse the febootstrap-minimize from rinse Docker-DCO-1.1-Signed-off-by: Sam Bailey (github: thatsamguy) --- contrib/mkimage/.febootstrap-minimize | 2 +- contrib/mkimage/mageia-urpmi | 20 +------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/contrib/mkimage/.febootstrap-minimize b/contrib/mkimage/.febootstrap-minimize index 7dab4eb8b..8a71f5ed6 100755 --- a/contrib/mkimage/.febootstrap-minimize +++ b/contrib/mkimage/.febootstrap-minimize @@ -13,7 +13,7 @@ shift # docs rm -rf usr/share/{man,doc,info,gnome/help} # cracklib - #rm -rf usr/share/cracklib + rm -rf usr/share/cracklib # i18n rm -rf usr/share/i18n # yum cache diff --git a/contrib/mkimage/mageia-urpmi b/contrib/mkimage/mageia-urpmi index 252e82787..93fb289ca 100755 --- a/contrib/mkimage/mageia-urpmi +++ b/contrib/mkimage/mageia-urpmi @@ -53,25 +53,7 @@ fi --root "$rootfsDir" ) -( - # Clean cruft to reduce image size - stolen and modifed from .febootstrap-minimize - set -x - cd "$rootfsDir" - # locales - rm -rf usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive} - # docs - rm -rf usr/share/{man,doc,info,gnome/help} - # cracklib - rm -rf usr/share/cracklib - # i18n - rm -rf usr/share/i18n - # sln - rm -rf sbin/sln - # ldconfig - #rm -rf sbin/ldconfig - rm -rf etc/ld.so.cache var/cache/ldconfig - mkdir -p --mode=0755 var/cache/ldconfig -) +"$(dirname "$BASH_SOURCE")/.febootstrap-minimize" "$rootfsDir" if [ -d "$rootfsDir/etc/sysconfig" ]; then # allow networking init scripts inside the container to work without extra steps From c11fadb282ea7e96eef2280a5e422fd2c94e8c45 Mon Sep 17 00:00:00 2001 From: Joe Beda Date: Tue, 3 Jun 2014 16:28:06 -0700 Subject: [PATCH 006/167] Make debian init work when called quickly. We use the start-stop-daemon pid creation mechanism in addition the intrinsic built into docker. This means the pid file is guaranteed to be written out by the time the script exits. See #6184. Docker-DCO-1.1-Signed-off-by: Joe Beda (github: jbeda) --- contrib/init/sysvinit-debian/docker | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contrib/init/sysvinit-debian/docker b/contrib/init/sysvinit-debian/docker index 9b50fad44..a3b935375 100755 --- a/contrib/init/sysvinit-debian/docker +++ b/contrib/init/sysvinit-debian/docker @@ -22,7 +22,10 @@ BASE=$(basename $0) # modify these in /etc/default/$BASE (/etc/default/docker) DOCKER=/usr/bin/$BASE +# This is the pid file managed by docker itself DOCKER_PIDFILE=/var/run/$BASE.pid +# This is the pid file created/managed by start-stop-daemon +DOCKER_SSD_PIDFILE=/var/run/$BASE-ssd.pid DOCKER_LOGFILE=/var/log/$BASE.log DOCKER_OPTS= DOCKER_DESC="Docker" @@ -89,7 +92,8 @@ case "$1" in start-stop-daemon --start --background \ --no-close \ --exec "$DOCKER" \ - --pidfile "$DOCKER_PIDFILE" \ + --pidfile "$DOCKER_SSD_PIDFILE" \ + --make-pidfile \ -- \ -d -p "$DOCKER_PIDFILE" \ $DOCKER_OPTS \ @@ -100,13 +104,13 @@ case "$1" in stop) fail_unless_root log_begin_msg "Stopping $DOCKER_DESC: $BASE" - start-stop-daemon --stop --pidfile "$DOCKER_PIDFILE" + start-stop-daemon --stop --pidfile "$DOCKER_SSD_PIDFILE" log_end_msg $? ;; restart) fail_unless_root - docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null` + docker_pid=`cat "$DOCKER_SSD_PIDFILE" 2>/dev/null` [ -n "$docker_pid" ] \ && ps -p $docker_pid > /dev/null 2>&1 \ && $0 stop @@ -119,7 +123,7 @@ case "$1" in ;; status) - status_of_proc -p "$DOCKER_PIDFILE" "$DOCKER" docker + status_of_proc -p "$DOCKER_SSD_PIDFILE" "$DOCKER" docker ;; *) From 338e87f6b34f36dcbb68db3b2999ce2bce5b40da Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Wed, 11 Jun 2014 14:35:16 -0700 Subject: [PATCH 007/167] api/server/MAINTAINERS: add proppy and vieux Docker-DCO-1.1-Signed-off-by: Johan Euphrosine (github: proppy) --- api/server/MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 api/server/MAINTAINERS diff --git a/api/server/MAINTAINERS b/api/server/MAINTAINERS new file mode 100644 index 000000000..c92a06114 --- /dev/null +++ b/api/server/MAINTAINERS @@ -0,0 +1,2 @@ +Victor Vieux (@vieux) +Johan Euphrosine (@proppy) From e02cf69789d12e8d44c8168e1515f43f39be6461 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Sat, 14 Jun 2014 01:59:52 -0600 Subject: [PATCH 008/167] Fix contrib/man/md/docker-import.1.md warning ("macro `tar.gz,' not defined") Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/man/md/docker-import.1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/man/md/docker-import.1.md b/contrib/man/md/docker-import.1.md index a0db89eef..6b76d191f 100644 --- a/contrib/man/md/docker-import.1.md +++ b/contrib/man/md/docker-import.1.md @@ -9,8 +9,8 @@ of the tarball into it. **docker import** URL|- [REPOSITORY[:TAG]] # DESCRIPTION -Create a new filesystem image from the contents of a tarball (.tar, -.tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it. +Create a new filesystem image from the contents of a tarball (`.tar`, +`.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it. # EXAMPLES From 06248d745a6a69b14595a699e0e5b3e883d8ea3a Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 5 Jun 2014 18:05:49 +0000 Subject: [PATCH 009/167] update MAINTAINERS files Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- daemon/execdriver/MAINTAINERS | 1 + pkg/mflag/MAINTAINERS | 2 +- pkg/networkfs/MAINTAINERS | 2 +- pkg/sysinfo/MAINTAINERS | 1 + pkg/system/MAINTAINERS | 1 + server/MAINTAINERS | 2 +- 6 files changed, 6 insertions(+), 3 deletions(-) diff --git a/daemon/execdriver/MAINTAINERS b/daemon/execdriver/MAINTAINERS index 1e998f8ac..68a97d2fc 100644 --- a/daemon/execdriver/MAINTAINERS +++ b/daemon/execdriver/MAINTAINERS @@ -1 +1,2 @@ Michael Crosby (@crosbymichael) +Victor Vieux (@vieux) diff --git a/pkg/mflag/MAINTAINERS b/pkg/mflag/MAINTAINERS index ceeb0cfd1..e0f18f14f 100644 --- a/pkg/mflag/MAINTAINERS +++ b/pkg/mflag/MAINTAINERS @@ -1 +1 @@ -Victor Vieux (@vieux) +Victor Vieux (@vieux) diff --git a/pkg/networkfs/MAINTAINERS b/pkg/networkfs/MAINTAINERS index ceeb0cfd1..e0f18f14f 100644 --- a/pkg/networkfs/MAINTAINERS +++ b/pkg/networkfs/MAINTAINERS @@ -1 +1 @@ -Victor Vieux (@vieux) +Victor Vieux (@vieux) diff --git a/pkg/sysinfo/MAINTAINERS b/pkg/sysinfo/MAINTAINERS index 1e998f8ac..68a97d2fc 100644 --- a/pkg/sysinfo/MAINTAINERS +++ b/pkg/sysinfo/MAINTAINERS @@ -1 +1,2 @@ Michael Crosby (@crosbymichael) +Victor Vieux (@vieux) diff --git a/pkg/system/MAINTAINERS b/pkg/system/MAINTAINERS index 1e998f8ac..68a97d2fc 100644 --- a/pkg/system/MAINTAINERS +++ b/pkg/system/MAINTAINERS @@ -1 +1,2 @@ Michael Crosby (@crosbymichael) +Victor Vieux (@vieux) diff --git a/server/MAINTAINERS b/server/MAINTAINERS index 3564d3db4..e35518a6d 100644 --- a/server/MAINTAINERS +++ b/server/MAINTAINERS @@ -1,2 +1,2 @@ Solomon Hykes (@shykes) -Victor Vieux (@vieux) \ No newline at end of file +Victor Vieux (@vieux) From 3e4e8636c1b05626cae720b47ef99109077e1d3a Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 17 Jun 2014 00:06:21 +0000 Subject: [PATCH 010/167] do not alter json in docker save Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/server/server.go | 4 ++-- daemon/inspect.go | 2 +- graph/service.go | 2 +- server/server.go | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/server/server.go b/api/server/server.go index 61407b264..c6275177b 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -855,7 +855,7 @@ func getContainersByName(eng *engine.Engine, version version.Version, w http.Res } var job = eng.Job("container_inspect", vars["name"]) if version.LessThan("1.12") { - job.SetenvBool("dirty", true) + job.SetenvBool("raw", true) } streamJSON(job, w, false) return job.Run() @@ -867,7 +867,7 @@ func getImagesByName(eng *engine.Engine, version version.Version, w http.Respons } var job = eng.Job("image_inspect", vars["name"]) if version.LessThan("1.12") { - job.SetenvBool("dirty", true) + job.SetenvBool("raw", true) } streamJSON(job, w, false) return job.Run() diff --git a/daemon/inspect.go b/daemon/inspect.go index af6d4520f..6c4b74d6f 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -15,7 +15,7 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status { if container := daemon.Get(name); container != nil { container.Lock() defer container.Unlock() - if job.GetenvBool("dirty") { + if job.GetenvBool("raw") { b, err := json.Marshal(&struct { *Container HostConfig *runconfig.HostConfig diff --git a/graph/service.go b/graph/service.go index 4bce6b564..ebdb88160 100644 --- a/graph/service.go +++ b/graph/service.go @@ -135,7 +135,7 @@ func (s *TagStore) CmdLookup(job *engine.Job) engine.Status { } name := job.Args[0] if image, err := s.LookupImage(name); err == nil && image != nil { - if job.GetenvBool("dirty") { + if job.GetenvBool("raw") { b, err := json.Marshal(image) if err != nil { return job.Error(err) diff --git a/server/server.go b/server/server.go index 76a51e796..b054911ed 100644 --- a/server/server.go +++ b/server/server.go @@ -433,6 +433,7 @@ func (srv *Server) exportImage(eng *engine.Engine, name, tempdir string) error { return err } job := eng.Job("image_inspect", n) + job.SetenvBool("raw", true) job.Stdout.Add(json) if err := job.Run(); err != nil { return err From 614c57c52161c0440247a4e4e36808116214770e Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 17 Jun 2014 00:59:51 +0000 Subject: [PATCH 011/167] improve test Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- integration-cli/docker_cli_save_load_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go index d728c7de9..3dc5b8d01 100644 --- a/integration-cli/docker_cli_save_load_test.go +++ b/integration-cli/docker_cli_save_load_test.go @@ -25,6 +25,10 @@ func TestSaveAndLoadRepo(t *testing.T) { out, _, err = runCommandWithOutput(commitCmd) errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err)) + inspectCmd = exec.Command(dockerBinary, "inspect", repoName) + before, _, err := runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err)) + saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar` saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName) saveCmd := exec.Command("bash", "-c", saveCmdFinal) @@ -39,8 +43,12 @@ func TestSaveAndLoadRepo(t *testing.T) { errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err)) inspectCmd = exec.Command(dockerBinary, "inspect", repoName) - out, _, err = runCommandWithOutput(inspectCmd) - errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", out, err)) + after, _, err := runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err)) + + if before != after { + t.Fatalf("inspect is not the same after a save / load") + } deleteContainer(cleanedContainerID) deleteImages(repoName) From 6228761f67bb5f2af6c3105de556fa3fedb12069 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 17 Jun 2014 01:01:38 +0000 Subject: [PATCH 012/167] add a test using the flags Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- integration-cli/docker_cli_save_load_test.go | 60 ++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go index 3dc5b8d01..fb94cad9d 100644 --- a/integration-cli/docker_cli_save_load_test.go +++ b/integration-cli/docker_cli_save_load_test.go @@ -7,8 +7,8 @@ import ( "testing" ) -// save a repo and try to load it -func TestSaveAndLoadRepo(t *testing.T) { +// save a repo and try to load it using stdout +func TestSaveAndLoadRepoStdout(t *testing.T) { runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") out, _, err := runCommandWithOutput(runCmd) errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err)) @@ -55,6 +55,58 @@ func TestSaveAndLoadRepo(t *testing.T) { os.Remove("/tmp/foobar-save-load-test.tar") - logDone("save - save a repo") - logDone("load - load a repo") + logDone("save - save a repo using stdout") + logDone("load - load a repo using stdout") +} + +// save a repo and try to load it using flags +func TestSaveAndLoadRepoFlags(t *testing.T) { + runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") + out, _, err := runCommandWithOutput(runCmd) + errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err)) + + cleanedContainerID := stripTrailingCharacters(out) + + repoName := "foobar-save-load-test" + + inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID) + out, _, err = runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err)) + + commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName) + out, _, err = runCommandWithOutput(commitCmd) + errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err)) + + inspectCmd = exec.Command(dockerBinary, "inspect", repoName) + before, _, err := runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("the repo should exist before saving it: %v %v", before, err)) + + saveCmdTemplate := `%v save -o /tmp/foobar-save-load-test.tar %v` + saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName) + saveCmd := exec.Command("bash", "-c", saveCmdFinal) + out, _, err = runCommandWithOutput(saveCmd) + errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err)) + + deleteImages(repoName) + + loadCmdFinal := `docker load -i /tmp/foobar-save-load-test.tar` + loadCmd := exec.Command("bash", "-c", loadCmdFinal) + out, _, err = runCommandWithOutput(loadCmd) + errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err)) + + inspectCmd = exec.Command(dockerBinary, "inspect", repoName) + after, _, err := runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", after, err)) + + if before != after { + t.Fatalf("inspect is not the same after a save / load") + } + + deleteContainer(cleanedContainerID) + deleteImages(repoName) + + os.Remove("/tmp/foobar-save-load-test.tar") + + logDone("save - save a repo using -o") + logDone("load - load a repo using -i") } From 962e1186f9a0a43344e19dcf70bac159f0eafb4e Mon Sep 17 00:00:00 2001 From: NikolaMandic Date: Wed, 18 Jun 2014 19:23:39 +0200 Subject: [PATCH 013/167] removed expect from mkimage-arch since it was not working Docker-DCO-1.1-Signed-off-by: NikolaMandic (github: NikolaMandic) --- contrib/mkimage-arch.sh | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/contrib/mkimage-arch.sh b/contrib/mkimage-arch.sh index dc2106747..0a77a1179 100755 --- a/contrib/mkimage-arch.sh +++ b/contrib/mkimage-arch.sh @@ -9,31 +9,13 @@ hash pacstrap &>/dev/null || { exit 1 } -hash expect &>/dev/null || { - echo "Could not find expect. Run pacman -S expect" - exit 1 -} - ROOTFS=$(mktemp -d /tmp/rootfs-archlinux-XXXXXXXXXX) chmod 755 $ROOTFS # packages to ignore for space savings PKGIGNORE=linux,jfsutils,lvm2,cryptsetup,groff,man-db,man-pages,mdadm,pciutils,pcmciautils,reiserfsprogs,s-nail,xfsprogs -expect < Date: Wed, 18 Jun 2014 15:08:33 +0400 Subject: [PATCH 014/167] More verbose error for parallel pull Partially fixes #6484 Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- server/server.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/server.go b/server/server.go index 620c8b20b..66c2d7a28 100644 --- a/server/server.go +++ b/server/server.go @@ -1238,9 +1238,10 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName break } if !success { - out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Error pulling image (%s) from %s, %s", img.Tag, localName, lastErr), nil)) + err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, localName, lastErr) + out.Write(sf.FormatProgress(utils.TruncateID(img.ID), err.Error(), nil)) if parallel { - errors <- fmt.Errorf("Could not find repository on any of the indexed registries.") + errors <- err return } } From 216b4c9cf6cbdc9cd620de4edfbcd754a2184559 Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Wed, 18 Jun 2014 23:11:04 +0400 Subject: [PATCH 015/167] Validate that one of streams choosen in logs on api side Fixes #6506 There is the bug, that very hard to fix: When we return job.Errorf in "logs" job it writes to job.Stderr, to which connected ResponseWriter and on this write w.WriteHeader(http.StatusOK) is called. So, we get 200 on error from "logs" job. Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- api/server/server.go | 27 ++++++---- api/server/server_unit_test.go | 99 +++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 13 deletions(-) diff --git a/api/server/server.go b/api/server/server.go index ce1bdbd39..5feeaf922 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -370,13 +370,23 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo } var ( - job = eng.Job("container_inspect", vars["name"]) - c, err = job.Stdout.AddEnv() + inspectJob = eng.Job("container_inspect", vars["name"]) + logsJob = eng.Job("logs", vars["name"]) + c, err = inspectJob.Stdout.AddEnv() ) if err != nil { return err } - if err = job.Run(); err != nil { + logsJob.Setenv("follow", r.Form.Get("follow")) + logsJob.Setenv("stdout", r.Form.Get("stdout")) + logsJob.Setenv("stderr", r.Form.Get("stderr")) + logsJob.Setenv("timestamps", r.Form.Get("timestamps")) + // Validate args here, because we can't return not StatusOK after job.Run() call + stdout, stderr := logsJob.GetenvBool("stdout"), logsJob.GetenvBool("stderr") + if !(stdout || stderr) { + return fmt.Errorf("Bad parameters: you must choose at least one stream") + } + if err = inspectJob.Run(); err != nil { return err } @@ -390,14 +400,9 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo errStream = outStream } - job = eng.Job("logs", vars["name"]) - job.Setenv("follow", r.Form.Get("follow")) - job.Setenv("stdout", r.Form.Get("stdout")) - job.Setenv("stderr", r.Form.Get("stderr")) - job.Setenv("timestamps", r.Form.Get("timestamps")) - job.Stdout.Add(outStream) - job.Stderr.Set(errStream) - if err := job.Run(); err != nil { + logsJob.Stdout.Add(outStream) + logsJob.Stderr.Set(errStream) + if err := logsJob.Run(); err != nil { fmt.Fprintf(outStream, "Error running logs job: %s\n", err) } return nil diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index 32f8e42b1..1116a0e56 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -4,12 +4,14 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/dotcloud/docker/api" - "github.com/dotcloud/docker/engine" "io" "net/http" "net/http/httptest" + "strings" "testing" + + "github.com/dotcloud/docker/api" + "github.com/dotcloud/docker/engine" ) func TestGetBoolParam(t *testing.T) { @@ -151,6 +153,99 @@ func TestGetContainersByName(t *testing.T) { } } +func TestLogs(t *testing.T) { + eng := engine.New() + var inspect bool + var logs bool + eng.Register("container_inspect", func(job *engine.Job) engine.Status { + inspect = true + if len(job.Args) == 0 { + t.Fatal("Job arguments is empty") + } + if job.Args[0] != "test" { + t.Fatalf("Container name %s, must be test", job.Args[0]) + } + return engine.StatusOK + }) + expected := "logs" + eng.Register("logs", func(job *engine.Job) engine.Status { + logs = true + if len(job.Args) == 0 { + t.Fatal("Job arguments is empty") + } + if job.Args[0] != "test" { + t.Fatalf("Container name %s, must be test", job.Args[0]) + } + follow := job.Getenv("follow") + if follow != "1" { + t.Fatalf("follow: %s, must be 1", follow) + } + stdout := job.Getenv("stdout") + if stdout != "1" { + t.Fatalf("stdout %s, must be 1", stdout) + } + stderr := job.Getenv("stderr") + if stderr != "" { + t.Fatalf("stderr %s, must be empty", stderr) + } + timestamps := job.Getenv("timestamps") + if timestamps != "1" { + t.Fatalf("timestamps %s, must be 1", timestamps) + } + job.Stdout.Write([]byte(expected)) + return engine.StatusOK + }) + r := serveRequest("GET", "/containers/test/logs?follow=1&stdout=1×tamps=1", nil, eng, t) + if r.Code != http.StatusOK { + t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK) + } + if !inspect { + t.Fatal("container_inspect job was not called") + } + if !logs { + t.Fatal("logs job was not called") + } + res := r.Body.String() + if res != expected { + t.Fatalf("Output %s, expected %s", res, expected) + } +} + +func TestLogsNoStreams(t *testing.T) { + eng := engine.New() + var inspect bool + var logs bool + eng.Register("container_inspect", func(job *engine.Job) engine.Status { + inspect = true + if len(job.Args) == 0 { + t.Fatal("Job arguments is empty") + } + if job.Args[0] != "test" { + t.Fatalf("Container name %s, must be test", job.Args[0]) + } + return engine.StatusOK + }) + eng.Register("logs", func(job *engine.Job) engine.Status { + logs = true + return engine.StatusOK + }) + r := serveRequest("GET", "/containers/test/logs", nil, eng, t) + if r.Code != http.StatusBadRequest { + t.Fatalf("Got status %d, expected %d", r.Code, http.StatusBadRequest) + } + if inspect { + t.Fatal("container_inspect job was called, but it shouldn't") + } + if logs { + t.Fatal("logs job was called, but it shouldn't") + } + res := strings.TrimSpace(r.Body.String()) + expected := "Bad parameters: you must choose at least one stream" + if !strings.Contains(res, expected) { + t.Fatalf("Output %s, expected %s in it", res, expected) + } +} + func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder { r := httptest.NewRecorder() req, err := http.NewRequest(method, target, body) From 80bc06f1cf0833479d59078dc2a73c40711f3980 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Thu, 19 Jun 2014 11:25:14 +0200 Subject: [PATCH 016/167] Fix flag names --- docs/sources/reference/run.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 5cb050c02..b379f24c0 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -103,7 +103,7 @@ interactive cases. ## Container Identification -### Name (–name) +### Name (–-name) The operator can identify a container in three ways: @@ -190,7 +190,7 @@ localhost interface. $ # use the redis container's network stack to access localhost $ docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1 -## Clean Up (–rm) +## Clean Up (–-rm) By default a container's file system persists even after the container exits. This makes debugging a lot easier (since you can inspect the From 40966fa0966b3acd1893852a5297526374b690f2 Mon Sep 17 00:00:00 2001 From: lalyos Date: Thu, 19 Jun 2014 13:00:45 +0200 Subject: [PATCH 017/167] Fix installation docs to use the new boot2docker command: ip Docker-DCO-1.1-Signed-off-by: Lajos Papp (github: lalyos) --- docs/sources/installation/mac.md | 4 ++-- docs/sources/installation/windows.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/installation/mac.md b/docs/sources/installation/mac.md index a982c5984..4677005cc 100644 --- a/docs/sources/installation/mac.md +++ b/docs/sources/installation/mac.md @@ -78,7 +78,7 @@ If you run a container with an exposed port, then you should be able to access that Nginx server using the IP address reported by: - $ boot2docker ssh ip addr show dev eth1 + $ boot2docker ip Typically, it is 192.168.59.103, but it could get changed by Virtualbox's DHCP implementation. @@ -91,7 +91,7 @@ The Boot2Docker management tool provides several commands: $ ./boot2docker Usage: ./boot2docker [] - {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|delete|download|version} + {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|ip|delete|download|version} [] Continue with the [User Guide](/userguide/). diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 447d8b280..a1c910ee6 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -63,7 +63,7 @@ This will download the small busybox image and print "hello world". The Boot2Docker management tool provides several commands: $ ./boot2docker - Usage: ./boot2docker [] {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|delete|download|version} [] + Usage: ./boot2docker [] {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|ip|delete|download|version} [] ## Container port redirection From 10eae16fa70ac04191401bf2872ffa6688f79b82 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Thu, 19 Jun 2014 07:44:41 -0500 Subject: [PATCH 018/167] Updated SSH example to ensure it continues working Docker-DCO-1.1-Signed-off-by: James Turnbull (github: jamtur01) --- docs/sources/examples/running_ssh_service.Dockerfile | 2 +- docs/sources/examples/running_ssh_service.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/examples/running_ssh_service.Dockerfile b/docs/sources/examples/running_ssh_service.Dockerfile index 978e61042..57baf88ce 100644 --- a/docs/sources/examples/running_ssh_service.Dockerfile +++ b/docs/sources/examples/running_ssh_service.Dockerfile @@ -2,7 +2,7 @@ # # VERSION 0.0.1 -FROM debian +FROM ubuntu:12.04 MAINTAINER Thatcher R. Peskens "thatcher@dotcloud.com" # make sure the package repository is up to date diff --git a/docs/sources/examples/running_ssh_service.md b/docs/sources/examples/running_ssh_service.md index 27439f998..579d372ba 100644 --- a/docs/sources/examples/running_ssh_service.md +++ b/docs/sources/examples/running_ssh_service.md @@ -12,7 +12,7 @@ quick access to a test container. # # VERSION 0.0.1 - FROM debian + FROM ubuntu:12.04 MAINTAINER Thatcher R. Peskens "thatcher@dotcloud.com" # make sure the package repository is up to date From d7e5fdfb58d5829344486b7a6171f7e866f0378b Mon Sep 17 00:00:00 2001 From: "Kevin \"qwazerty\" Houdebert" Date: Thu, 19 Jun 2014 09:11:26 +0200 Subject: [PATCH 019/167] Fix minor typo Docker-DCO-1.1-Signed-off-by: Kevin Houdebert kevin.houdebert@gmail.com (github: qwazerty) --- runconfig/parse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runconfig/parse.go b/runconfig/parse.go index 5bb065421..fd3e4a50a 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -65,7 +65,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container") flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)") flCpuset = cmd.String([]string{"-cpuset"}, "", "CPUs in which to allow execution (0-3, 0,1)") - flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:': reuses another container network stack\n'host': use the host network stack inside the contaner. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.") + flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:': reuses another container network stack\n'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.") // For documentation purpose _ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)") _ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container") From d17c92965937bbc3181b73bb8a4e21ecee217e5f Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Thu, 19 Jun 2014 21:42:55 +0400 Subject: [PATCH 020/167] Fix stdcopy when reads large frame at once Fixes TestLogsContainerMuchBiggerThanPage with go 1.3(#6520) Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- utils/stdcopy.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/utils/stdcopy.go b/utils/stdcopy.go index ab8759f4e..bb9d63266 100644 --- a/utils/stdcopy.go +++ b/utils/stdcopy.go @@ -82,13 +82,17 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) for nr < StdWriterPrefixLen { var nr2 int nr2, er = src.Read(buf[nr:]) - // Don't exit on EOF, because we can have some more input - if er != nil && er != io.EOF { - return 0, er - } nr += nr2 - if nr == 0 { - return written, nil + if er == io.EOF { + if nr < StdWriterPrefixLen { + Debugf("Corrupted prefix: %v", buf[:nr]) + return written, nil + } + break + } + if er != nil { + Debugf("Error reading header: %s", er) + return 0, er } } @@ -123,21 +127,22 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) for nr < frameSize+StdWriterPrefixLen { var nr2 int nr2, er = src.Read(buf[nr:]) + nr += nr2 if er == io.EOF { - return written, nil + if nr < frameSize+StdWriterPrefixLen { + Debugf("Corrupted frame: %v", buf[StdWriterPrefixLen:nr]) + return written, nil + } + break } if er != nil { Debugf("Error reading frame: %s", er) return 0, er } - nr += nr2 } // Write the retrieved frame (without header) nw, ew = out.Write(buf[StdWriterPrefixLen : frameSize+StdWriterPrefixLen]) - if nw > 0 { - written += int64(nw) - } if ew != nil { Debugf("Error writing frame: %s", ew) return 0, ew @@ -147,6 +152,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) Debugf("Error Short Write: (%d on %d)", nw, frameSize) return 0, io.ErrShortWrite } + written += int64(nw) // Move the rest of the buffer to the beginning copy(buf, buf[frameSize+StdWriterPrefixLen:]) From 3f7909e9967ded9740fdf951c6f7e95f4aa9c963 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Thu, 19 Jun 2014 14:35:30 -0600 Subject: [PATCH 021/167] Disable netgo for dynbinary builds It's not necessary to use the netgo implementation for non-static builds. :) Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- hack/make/dynbinary | 1 + 1 file changed, 1 insertion(+) diff --git a/hack/make/dynbinary b/hack/make/dynbinary index 426b9cb56..74bb0dd36 100644 --- a/hack/make/dynbinary +++ b/hack/make/dynbinary @@ -40,5 +40,6 @@ fi ( export LDFLAGS_STATIC_DOCKER="-X github.com/dotcloud/docker/dockerversion.INITSHA1 \"$DOCKER_INITSHA1\" -X github.com/dotcloud/docker/dockerversion.INITPATH \"$DOCKER_INITPATH\"" + export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary source "$(dirname "$BASH_SOURCE")/binary" ) From bf69b773ec4c817dcc276e4471fc85f762f18f9f Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Thu, 19 Jun 2014 12:07:39 -0500 Subject: [PATCH 022/167] Fixed #6545 - Updated Security article Docker-DCO-1.1-Signed-off-by: James Turnbull (github: jamtur01) --- docs/sources/articles/security.md | 61 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/docs/sources/articles/security.md b/docs/sources/articles/security.md index cdf5fdddd..83704e434 100644 --- a/docs/sources/articles/security.md +++ b/docs/sources/articles/security.md @@ -17,15 +17,10 @@ There are three major areas to consider when reviewing Docker security: ## Kernel Namespaces -Docker containers are essentially LXC containers, and they come with the -same security features. When you start a container with -`docker run`, behind the scenes Docker uses -`lxc-start` to execute the Docker container. This -creates a set of namespaces and control groups for the container. Those -namespaces and control groups are not created by Docker itself, but by -`lxc-start`. This means that as the LXC userland -tools evolve (and provide additional namespaces and isolation features), -Docker will automatically make use of them. +Docker containers are very similar to LXC containers, and they come with +the similar security features. When you start a container with `docker +run`, behind the scenes Docker creates a set of namespaces and control +groups for the container. **Namespaces provide the first and most straightforward form of isolation**: processes running within a container cannot see, and even @@ -55,10 +50,9 @@ ago), namespace code has been exercised and scrutinized on a large number of production systems. And there is more: the design and inspiration for the namespaces code are even older. Namespaces are actually an effort to reimplement the features of [OpenVZ]( -http://en.wikipedia.org/wiki/OpenVZ) in such a way that they -could be merged within the mainstream kernel. And OpenVZ was initially -released in 2005, so both the design and the implementation are pretty -mature. +http://en.wikipedia.org/wiki/OpenVZ) in such a way that they could be +merged within the mainstream kernel. And OpenVZ was initially released +in 2005, so both the design and the implementation are pretty mature. ## Control Groups @@ -82,7 +76,7 @@ started in 2006, and initially merged in kernel 2.6.24. ## Docker Daemon Attack Surface Running containers (and applications) with Docker implies running the -Docker daemon. This daemon currently requires root privileges, and you +Docker daemon. This daemon currently requires `root` privileges, and you should therefore be aware of some important details. First of all, **only trusted users should be allowed to control your @@ -114,8 +108,9 @@ socket. You can also expose the REST API over HTTP if you explicitly decide so. However, if you do that, being aware of the above mentioned security implication, you should ensure that it will be reachable only from a -trusted network or VPN; or protected with e.g. `stunnel` -and client SSL certificates. +trusted network or VPN; or protected with e.g. `stunnel` and client SSL +certificates. You can also secure them with [HTTPS and +certificates](/articles/https/). Recent improvements in Linux namespaces will soon allow to run full-featured containers without root privileges, thanks to the new user @@ -199,15 +194,18 @@ container, it will be much harder to do serious damage, or to escalate to the host. This won't affect regular web apps; but malicious users will find that -the arsenal at their disposal has shrunk considerably! You can see [the -list of dropped capabilities in the Docker -code](https://github.com/dotcloud/docker/blob/v0.5.0/lxc_template.go#L97), -and a full list of available capabilities in [Linux +the arsenal at their disposal has shrunk considerably! By default Docker +drops all capabilities except [those +needed](https://github.com/dotcloud/docker/blob/master/daemon/execdriver/native/template/default_template.go), +a whitelist instead of a blacklist approach. You can see a full list of +available capabilities in [Linux manpages](http://man7.org/linux/man-pages/man7/capabilities.7.html). Of course, you can always enable extra capabilities if you really need them (for instance, if you want to use a FUSE-based filesystem), but by -default, Docker containers will be locked down to ensure maximum safety. +default, Docker containers use only a +[whitelist](https://github.com/dotcloud/docker/blob/master/daemon/execdriver/native/template/default_template.go) +of kernel capabilities by default. ## Other Kernel Security Features @@ -222,17 +220,16 @@ harden a Docker host. Here are a few examples. - You can run a kernel with GRSEC and PAX. This will add many safety checks, both at compile-time and run-time; it will also defeat many - exploits, thanks to techniques like address randomization. It - doesn't require Docker-specific configuration, since those security - features apply system-wide, independently of containers. - - If your distribution comes with security model templates for LXC - containers, you can use them out of the box. For instance, Ubuntu - comes with AppArmor templates for LXC, and those templates provide - an extra safety net (even though it overlaps greatly with - capabilities). + exploits, thanks to techniques like address randomization. It doesn't + require Docker-specific configuration, since those security features + apply system-wide, independently of containers. + - If your distribution comes with security model templates for + Docker containers, you can use them out of the box. For instance, we + ship a template that works with AppArmor and Red Hat comes with SELinux + policies for Docker. These templates provide an extra safety net (even + though it overlaps greatly with capabilities). - You can define your own policies using your favorite access control - mechanism. Since Docker containers are standard LXC containers, - there is nothing “magic” or specific to Docker. + mechanism. Just like there are many third-party tools to augment Docker containers with e.g. special network topologies or shared filesystems, you can @@ -243,7 +240,7 @@ affecting Docker's core. Docker containers are, by default, quite secure; especially if you take care of running your processes inside the containers as non-privileged -users (i.e. non root). +users (i.e. non-`root`). You can add an extra layer of safety by enabling Apparmor, SELinux, GRSEC, or your favorite hardening solution. From 49376ec4483c241167f7623ccc0260486ce8d4a3 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 20 Jun 2014 01:06:48 +0000 Subject: [PATCH 023/167] Change version to 1.0.1-dev Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7dea76edb..3f60217db 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1 +1.0.1-dev From 4efe02b3df67af544d398e435fbe567502bf0dea Mon Sep 17 00:00:00 2001 From: Adam Singer Date: Thu, 19 Jun 2014 22:01:10 -0700 Subject: [PATCH 024/167] full url to GCE image Docker-DCO-1.1-Signed-off-by: Adam Singer (github: financeCoding) --- docs/sources/installation/google.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/installation/google.md b/docs/sources/installation/google.md index c91d13612..79d40c07d 100644 --- a/docs/sources/installation/google.md +++ b/docs/sources/installation/google.md @@ -21,7 +21,7 @@ page_keywords: Docker, Docker documentation, installation, google, Google Comput (select a zone close to you and the desired instance size) $ gcloud compute instances create docker-playground \ - --image projects/google-containers/global/images/container-vm-v20140522 \ + --image https://www.googleapis.com/compute/v1/projects/google-containers/global/images/container-vm-v20140522 \ --zone us-central1-a \ --machine-type f1-micro From db9bf744ab93f1e688bf986794c852abc40b873e Mon Sep 17 00:00:00 2001 From: shaunol Date: Fri, 20 Jun 2014 19:23:35 +1200 Subject: [PATCH 025/167] Update windows.md Update Program Files path description, the default install folder is "Boot2Docker", rather than "Docker" --- docs/sources/installation/windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 447d8b280..ff987054a 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -25,7 +25,7 @@ virtual machine and runs the Docker daemon. 2. Run the installer, which will install VirtualBox, MSYS-git, the boot2docker Linux ISO, and the Boot2Docker management tool. ![](/installation/images/windows-installer.png) -3. Run the `Boot2Docker Start` shell script from your Desktop or Program Files > Docker. +3. Run the `Boot2Docker Start` shell script from your Desktop or Program Files > Boot2Docker for Windows. The Start script will ask you to enter an ssh key passphrase - the simplest (but least secure) is to just hit [Enter]. From cbdce9912d9f904b237e29dd2a1196367337628b Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 20 Jun 2014 07:14:56 -0400 Subject: [PATCH 026/167] Fix typo in networking.md Minor typo fix --- docs/sources/articles/networking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/articles/networking.md b/docs/sources/articles/networking.md index 927cd8087..bf46b90ea 100644 --- a/docs/sources/articles/networking.md +++ b/docs/sources/articles/networking.md @@ -26,7 +26,7 @@ bridge* that automatically forwards packets between any other network interfaces that are attached to it. This lets containers communicate both with the host machine and with each other. Every time Docker creates a container, it creates a pair of “peer” interfaces that are -like opposite ends of a pipe — a packet send on one will be received on +like opposite ends of a pipe — a packet sent on one will be received on the other. It gives one of the peers to the container to become its `eth0` interface and keeps the other peer, with a unique name like `vethAQI2QT`, out in the namespace of the host machine. By binding From 66bccf3064effd910e47405dc738ba08a8d14b12 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 20 Jun 2014 07:49:22 -0400 Subject: [PATCH 027/167] Minor typo/format fixes This fixes a code block typo so it renders as a code block. Additionally synchronizes the variable prefix examples from 'DB' and 'DB1_' to 'DB_' and 'DB1_' --- docs/sources/userguide/dockerlinks.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md index 833f4aed9..5a81cd573 100644 --- a/docs/sources/userguide/dockerlinks.md +++ b/docs/sources/userguide/dockerlinks.md @@ -173,6 +173,7 @@ child container in two ways: Let's look first at the environment variables Docker sets. Let's run the `env` command to list the container's environment variables. + $ sudo docker run --rm --name web2 --link db:db training/webapp env . . . DB_NAME=/web2/db @@ -190,7 +191,7 @@ command to list the container's environment variables. We can see that Docker has created a series of environment variables with useful information about our `db` container. Each variables is prefixed with -`DB` which is populated from the `alias` we specified above. If our `alias` +`DB_` which is populated from the `alias` we specified above. If our `alias` were `db1` the variables would be prefixed with `DB1_`. You can use these environment variables to configure your applications to connect to the database on the `db` container. The connection will be secure, private and only the From a206186f8427c74fbf9625e4140bf84461a67eec Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Fri, 20 Jun 2014 10:04:48 -0600 Subject: [PATCH 028/167] Add a ton of simple improvements to contrib/mkimage/debootstrap, especially comments in the extra files put inside the image This also adds support for squeeze-lts. :) Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/mkimage.sh | 2 +- contrib/mkimage/debootstrap | 81 +++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/contrib/mkimage.sh b/contrib/mkimage.sh index db4815c20..dc82145ac 100755 --- a/contrib/mkimage.sh +++ b/contrib/mkimage.sh @@ -6,7 +6,7 @@ mkimg="$(basename "$0")" usage() { echo >&2 "usage: $mkimg [-d dir] [-t tag] script [script-args]" echo >&2 " ie: $mkimg -t someuser/debian debootstrap --variant=minbase jessie" - echo >&2 " $mkimg -t someuser/ubuntu debootstrap --include=ubuntu-minimal trusty" + echo >&2 " $mkimg -t someuser/ubuntu debootstrap --include=ubuntu-minimal --components main,universe trusty" echo >&2 " $mkimg -t someuser/busybox busybox-static" echo >&2 " $mkimg -t someuser/centos:5 rinse --distribution centos-5" exit 1 diff --git a/contrib/mkimage/debootstrap b/contrib/mkimage/debootstrap index 4747a84d3..d5aeae2b9 100755 --- a/contrib/mkimage/debootstrap +++ b/contrib/mkimage/debootstrap @@ -23,9 +23,14 @@ shift # now for some Docker-specific tweaks # prevent init scripts from running during install/update -echo >&2 "+ cat > '$rootfsDir/usr/sbin/policy-rc.d'" +echo >&2 "+ echo exit 101 > '$rootfsDir/usr/sbin/policy-rc.d'" cat > "$rootfsDir/usr/sbin/policy-rc.d" <<'EOF' #!/bin/sh + +# For most Docker users, "apt-get install" only happens during "docker build", +# where starting services doesn't work and often fails in humorous ways. This +# prevents those failures by stopping the services from attempting to start. + exit 101 EOF chmod +x "$rootfsDir/usr/sbin/policy-rc.d" @@ -34,17 +39,25 @@ chmod +x "$rootfsDir/usr/sbin/policy-rc.d" ( set -x chroot "$rootfsDir" dpkg-divert --local --rename --add /sbin/initctl - ln -sf /bin/true "$rootfsDir/sbin/initctl" + cp -a "$rootfsDir/usr/sbin/policy-rc.d" "$rootfsDir/sbin/initctl" + sed -i 's/^exit.*/exit 0/' "$rootfsDir/sbin/initctl" ) -# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB) +# shrink a little, since apt makes us cache-fat (wheezy: ~157.5MB vs ~120MB) ( set -x; chroot "$rootfsDir" apt-get clean ) # Ubuntu 10.04 sucks... :) if strings "$rootfsDir/usr/bin/dpkg" | grep -q unsafe-io; then # force dpkg not to call sync() after package extraction (speeding up installs) echo >&2 "+ echo force-unsafe-io > '$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup'" - echo 'force-unsafe-io' > "$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup" + cat > "$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup" <<-'EOF' + # For most Docker users, package installs happen during "docker build", which + # doesn't survive power loss and gets restarted clean afterwards anyhow, so + # this minor tweak gives us a nice speedup (much nicer on spinning disks, + # obviously). + + force-unsafe-io + EOF fi if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then @@ -52,16 +65,36 @@ if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";' echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-clean'" cat > "$rootfsDir/etc/apt/apt.conf.d/docker-clean" <<-EOF + # Since for most Docker users, package installs happen in "docker build" steps, + # they essentially become individual layers due to the way Docker handles + # layering, especially using CoW filesystems. What this means for us is that + # the caches that APT keeps end up just wasting space in those layers, making + # our layers unnecessarily large (especially since we'll normally never use + # these caches again and will instead just "docker build" again and make a brand + # new image). + + # Ideally, these would just be invoking "apt-get clean", but in our testing, + # that ended up being cyclic and we got stuck on APT's lock, so we get this fun + # creation that's essentially just "apt-get clean". DPkg::Post-Invoke { ${aptGetClean} }; APT::Update::Post-Invoke { ${aptGetClean} }; Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache ""; + + # Note that we do realize this isn't the ideal way to do this, and are always + # open to better suggestions (https://github.com/dotcloud/docker/issues). EOF # remove apt-cache translations for fast "apt-get update" - echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-no-languages'" - echo 'Acquire::Languages "none";' > "$rootfsDir/etc/apt/apt.conf.d/docker-no-languages" + echo >&2 "+ echo Acquire::Languages 'none' > '$rootfsDir/etc/apt/apt.conf.d/docker-no-languages'" + cat > "$rootfsDir/etc/apt/apt.conf.d/docker-no-languages" <<-'EOF' + # In Docker, we don't often need the "Translations" files, so we're just wasting + # time and space by downloading them, and this inhibits that. For users that do + # need them, it's a simple matter to delete this file and "apt-get update". :) + + Acquire::Languages "none"; + EOF fi if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then @@ -76,39 +109,53 @@ if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then if [ -z "$lsbDist" -a -r "$rootfsDir/etc/debian_version" ]; then lsbDist='Debian' fi + # normalize to lowercase for easier matching + lsbDist="$(echo "$lsbDist" | tr '[:upper:]' '[:lower:]')" case "$lsbDist" in - debian|Debian) + debian) # updates and security! if [ "$suite" != 'sid' -a "$suite" != 'unstable' ]; then ( set -x - sed -i "p; s/ $suite main$/ ${suite}-updates main/" "$rootfsDir/etc/apt/sources.list" + sed -i " + p; + s/ $suite / ${suite}-updates / + " "$rootfsDir/etc/apt/sources.list" echo "deb http://security.debian.org $suite/updates main" >> "$rootfsDir/etc/apt/sources.list" + # LTS + if [ "$suite" = 'squeeze' ]; then + head -1 "$rootfsDir/etc/apt/sources.list" \ + | sed "s/ $suite / ${suite}-lts /" \ + >> "$rootfsDir/etc/apt/sources.list" + fi ) fi ;; - ubuntu|Ubuntu) - # add the universe, updates, and security repositories + ubuntu) + # add the updates and security repositories ( set -x sed -i " - s/ $suite main$/ $suite main universe/; p; - s/ $suite main/ ${suite}-updates main/; p; - s/ $suite-updates main/ ${suite}-security main/ + p; + s/ $suite / ${suite}-updates /; p; + s/ $suite-updates / ${suite}-security / " "$rootfsDir/etc/apt/sources.list" ) ;; - tanglu|Tanglu) + tanglu) # add the updates repository if [ "$suite" != 'devel' ]; then ( set -x - sed -i "p; s/ $suite main$/ ${suite}-updates main/" "$rootfsDir/etc/apt/sources.list" + sed -i " + p; + s/ $suite / ${suite}-updates / + " "$rootfsDir/etc/apt/sources.list" ) fi ;; - steamos|SteamOS) - # add contrib and non-free + steamos) + # add contrib and non-free if "main" is the only component ( set -x sed -i "s/ $suite main$/ $suite main contrib non-free/" "$rootfsDir/etc/apt/sources.list" From d3bc787bca62edff384e06a12224be2d982353da Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Tue, 17 Jun 2014 09:05:29 -0400 Subject: [PATCH 029/167] docker save: raw json Docker-DCO-1.1-Signed-off-by: Vincent Batts (github: vbatts) --- graph/service.go | 3 +-- image/image.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/graph/service.go b/graph/service.go index ebdb88160..3201d6b99 100644 --- a/graph/service.go +++ b/graph/service.go @@ -1,7 +1,6 @@ package graph import ( - "encoding/json" "io" "github.com/dotcloud/docker/engine" @@ -136,7 +135,7 @@ func (s *TagStore) CmdLookup(job *engine.Job) engine.Status { name := job.Args[0] if image, err := s.LookupImage(name); err == nil && image != nil { if job.GetenvBool("raw") { - b, err := json.Marshal(image) + b, err := image.RawJson() if err != nil { return job.Error(err) } diff --git a/image/image.go b/image/image.go index b56cbf08e..5c250947c 100644 --- a/image/image.go +++ b/image/image.go @@ -149,6 +149,22 @@ func jsonPath(root string) string { return path.Join(root, "json") } +func (img *Image) RawJson() ([]byte, error) { + root, err := img.root() + if err != nil { + return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err) + } + fh, err := os.Open(jsonPath(root)) + if err != nil { + return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err) + } + buf, err := ioutil.ReadAll(fh) + if err != nil { + return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err) + } + return buf, nil +} + // TarLayer returns a tar archive of the image's filesystem layer. func (img *Image) TarLayer() (arch archive.Archive, err error) { if img.graph == nil { From 6d14e9f1acc3d5927cbd4f4b3c7ea0c691dea7bc Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Thu, 19 Jun 2014 01:29:40 -0700 Subject: [PATCH 030/167] be consistent in capitalization of Docker Docker-DCO-1.1-Signed-off-by: Jonathan Boulle (github: jonboulle) --- docker/docker.go | 10 +++++----- docs/sources/reference/commandline/cli.md | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docker/docker.go b/docker/docker.go index 56bcb04e4..a89eff454 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -47,7 +47,7 @@ func main() { bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking") bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") - flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the docker runtime") + flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime") flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") flDns = opts.NewListOpts(opts.ValidateIp4Address) @@ -56,8 +56,8 @@ func main() { flEnableIpForward = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports") flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication") - flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the docker runtime to use a specific storage driver") - flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the docker runtime to use a specific exec driver") + flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver") + flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver") flHosts = opts.NewListOpts(api.ValidateHost) flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available") flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags") @@ -67,7 +67,7 @@ func main() { flKey = flag.String([]string{"-tlskey"}, dockerConfDir+defaultKeyFile, "Path to TLS key file") flSelinuxEnabled = flag.Bool([]string{"-selinux-enabled"}, false, "Enable selinux support") ) - flag.Var(&flDns, []string{"#dns", "-dns"}, "Force docker to use specific DNS servers") + flag.Var(&flDns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers") flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains") flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") flag.Var(&flGraphOpts, []string{"-storage-opt"}, "Set storage driver options") @@ -259,7 +259,7 @@ func showVersion() { func checkKernelAndArch() error { // Check for unsupported architectures if runtime.GOARCH != "amd64" { - return fmt.Errorf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) + return fmt.Errorf("The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) } // Check for unsupported kernel versions // FIXME: it would be cleaner to not test for specific versions, but rather diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index e496ce425..b92eeb3fb 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -58,10 +58,10 @@ expect an integer, and they can only be specified once. -D, --debug=false Enable debug mode --dns=[] Force docker to use specific DNS servers --dns-search=[] Force Docker to use specific DNS search domains - -e, --exec-driver="native" Force the docker runtime to use a specific exec driver + -e, --exec-driver="native" Force the Docker runtime to use a specific exec driver -G, --group="docker" Group to assign the unix socket specified by -H when running in daemon mode use '' (the empty string) to disable setting of a group - -g, --graph="/var/lib/docker" Path to use as the root of the docker runtime + -g, --graph="/var/lib/docker" Path to use as the root of the Docker runtime -H, --host=[] The socket(s) to bind to in daemon mode specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd. --icc=true Enable inter-container communication @@ -72,7 +72,7 @@ expect an integer, and they can only be specified once. if no value is provided: default to the default route MTU or 1500 if no default route is available -p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file -r, --restart=true Restart previously running containers - -s, --storage-driver="" Force the docker runtime to use a specific storage driver + -s, --storage-driver="" Force the Docker runtime to use a specific storage driver --storage-opt=[] Set storage driver options --selinux-enabled=false Enable selinux support --tls=false Use TLS; implied by tls-verify flags From 1bcc37caec07c01ab385f562ffa56d2b2bb0a7d8 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Fri, 20 Jun 2014 22:18:37 +0100 Subject: [PATCH 031/167] Fix minor typo and improve wording --- docs/sources/reference/builder.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/builder.md b/docs/sources/reference/builder.md index 8717eb7bf..a10cac00e 100644 --- a/docs/sources/reference/builder.md +++ b/docs/sources/reference/builder.md @@ -15,7 +15,7 @@ To [*build*](../commandline/cli/#cli-build) an image from a source repository, create a description file called Dockerfile at the root of your repository. This file will describe the steps to assemble the image. -Then call `docker build` with the path of you source repository as argument +Then call `docker build` with the path of your source repository as the argument (for example, `.`): $ sudo docker build . From 5266d6fa7bc367ac4c7472550b7220c4eb06731f Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Fri, 20 Jun 2014 22:36:31 +0100 Subject: [PATCH 032/167] Clean up some uses on 'an' in builder docs --- docs/sources/reference/builder.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/reference/builder.md b/docs/sources/reference/builder.md index a10cac00e..82b91a5b4 100644 --- a/docs/sources/reference/builder.md +++ b/docs/sources/reference/builder.md @@ -239,13 +239,13 @@ In the case where `` is a remote file URL, the destination will have permis > **Note**: > If you build using STDIN (`docker build - < somefile`), there is no -> build context, so the Dockerfile can only contain an URL based ADD +> build context, so the Dockerfile can only contain a URL based ADD > statement. > **Note**: > If your URL files are protected using authentication, you will need to -> use an `RUN wget` , `RUN curl` -> or other tool from within the container as ADD does not support +> use `RUN wget` , `RUN curl` +> or use another tool from within the container as ADD does not support > authentication. The copy obeys the following rules: From c70fbae3ed44090fffc9e5b81d2a6410e6008fcc Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Fri, 20 Jun 2014 17:10:20 -0700 Subject: [PATCH 033/167] Revised and fixed links on dockerrepo.md Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- docs/sources/userguide/dockerrepos.md | 136 ++++++++++++-------------- 1 file changed, 63 insertions(+), 73 deletions(-) diff --git a/docs/sources/userguide/dockerrepos.md b/docs/sources/userguide/dockerrepos.md index 5babfc76f..2e5abbba1 100644 --- a/docs/sources/userguide/dockerrepos.md +++ b/docs/sources/userguide/dockerrepos.md @@ -1,37 +1,49 @@ page_title: Working with Docker Hub -page_description: Learning how to use Docker Hub to manage images and work flow +page_description: Learn how to use the Docker Hub to manage Docker images and work flow page_keywords: repo, Docker Hub, Docker Hub, registry, index, repositories, usage, pull image, push image, image, documentation # Working with Docker Hub -So far we've seen a lot about how to use Docker on the command line and -your local host. We've seen [how to pull down -images](/userguide/usingdocker/) that you can run your containers from -and we've seen how to [create your own images](/userguide/dockerimages). +So far you've learned how to use the command line to run Docker on your local host. +You've learned how to [pull down images](/userguide/usingdocker/) to build containers +from existing images and you've learned how to [create your own images](/userguide/dockerimages). -Now we're going to learn a bit more about -[Docker Hub](https://hub.docker.com) and how you can use it to enhance -your Docker work flows. +Next, you're going to learn how to use the [Docker Hub](https://hub.docker.com) to +simplify and enhance your Docker workflows. -[Docker Hub](https://hub.docker.com) is the public registry that Docker -Inc maintains. It contains a huge collection of images, over 15,000, -that you can download and use to build your containers. It also provides -authentication, structure (you can setup teams and organizations), work -flow tools like webhooks and build triggers as well as privacy features -like private repositories for storing images you don't want to publicly -share. +The [Docker Hub](https://hub.docker.com) is a public registry maintained by Docker, +Inc. It contains over 15,000 images you can download and use to build containers. It also +provides authentication, work group structure, workflow tools like webhooks and build +triggers, and privacy tools like private repositories for storing images you don't want +to share publicly. ## Docker commands and Docker Hub -Docker acts as a client for these services via the `docker search`, -`pull`, `login` and `push` commands. +Docker itself provides access to Docker Hub services via the `docker search`, +`pull`, `login`, and `push` commands. This page will show you how these commands work. + +### Account creation and login +Typically, you'll want to start by creating an account on Docker Hub (if you haven't +already) and logging in. You can create your account directly on +[Docker Hub](https://hub.docker.com/account/signup/), or by running: + + $ sudo docker login + +This will prompt you for a user name, which will become the public namespace for your +public repositories. +If your user name is available, Docker will prompt you to enter a password and your +e-mail address. It will then automatically log you in. You can now commit and +push your own images up to your repos on Docker Hub. + +> **Note:** +> Your authentication credentials will be stored in the [`.dockercfg` +> authentication file](#authentication-file) in your home directory. ## Searching for images -As we've already seen we can search the -[Docker Hub](https://hub.docker.com) registry via it's search interface -or using the command line interface. Searching can find images by name, -user name or description: +You can search the [Docker Hub](https://hub.docker.com) registry via it's search +interface or by using the command line interface. Searching can find images by image +name, user name, or description: $ sudo docker search centos NAME DESCRIPTION STARS OFFICIAL TRUSTED @@ -41,12 +53,12 @@ user name or description: There you can see two example results: `centos` and `tianon/centos`. The second result shows that it comes from -the public repository of a user, `tianon/`, while the first result, -`centos`, doesn't explicitly list a repository so it comes from the +the public repository of a user, named `tianon/`, while the first result, +`centos`, doesn't explicitly list a repository which means that it comes from the trusted top-level namespace. The `/` character separates a user's -repository and the image name. +repository from the image name. -Once you have found the image you want, you can download it: +Once you've found the image you want, you can download it with `docker pull `: $ sudo docker pull centos Pulling repository centos @@ -55,84 +67,63 @@ Once you have found the image you want, you can download it: 511136ea3c5a: Download complete 7064731afe90: Download complete -The image is now available to run a container from. +You now have an image from which you can run containers. ## Contributing to Docker Hub Anyone can pull public images from the [Docker Hub](https://hub.docker.com) registry, but if you would like to share your own images, then you must -register a user first as we saw in the [first section of the Docker User +register first, as we saw in the [first section of the Docker User Guide](/userguide/dockerhub/). -To refresh your memory, you can create your user name and login to -[Docker Hub](https://hub.docker.com/account/signup/), or by running: - - $ sudo docker login - -This will prompt you for a user name, which will become a public -namespace for your public repositories, for example: - - training/webapp - -Here `training` is the user name and `webapp` is a repository owned by -that user. - -If your user name 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! - -> **Note:** -> Your authentication credentials will be stored in the [`.dockercfg` -> authentication file](#authentication-file) in your home directory. - ## Pushing a repository to Docker Hub -In order to push an repository to its registry you need to have named an image, +In order to push a repository to its registry, you need to have named an image or committed your container to a named image as we saw [here](/userguide/dockerimages). -Now you can push this repository to the registry designated by its name -or tag. +Now you can push this repository to the registry designated by its name or tag. $ sudo docker push yourname/newimage -The image will then be uploaded and available for use. +The image will then be uploaded and available for use by your team-mates and/or the +community. ## Features of Docker Hub -Now let's look at some of the features of Docker Hub. You can find more -information [here](/docker-io/). +Let's take a closer look at some of the features of Docker Hub. You can find more +information [here](http://docs.docker.com/docker-hub/). * Private repositories * Organizations and teams * Automated Builds * Webhooks -## Private Repositories +### Private Repositories Sometimes you have images you don't want to make public and share with everyone. So Docker Hub allows you to have private repositories. You can sign up for a plan [here](https://registry.hub.docker.com/plans/). -## Organizations and teams +### Organizations and teams One of the useful aspects of private repositories is that you can share them only with members of your organization or team. Docker Hub lets you create organizations where you can collaborate with your colleagues and -manage private repositories. You can create and manage an organization +manage private repositories. You can learn how to create and manage an organization [here](https://registry.hub.docker.com/account/organizations/). -## Automated Builds +### Automated Builds -Automated Builds automate the building and updating of images from [GitHub](https://www.github.com) -or [BitBucket](http://bitbucket.com), directly on Docker Hub. It works by adding a commit hook to -your selected GitHub or BitBucket repository, triggering a build and update when you push a -commit. +Automated Builds automate the building and updating of images from +[GitHub](https://www.github.com) or [BitBucket](http://bitbucket.com), directly on Docker +Hub. It works by adding a commit hook to your selected GitHub or BitBucket repository, +triggering a build and update when you push a commit. -### To setup an Automated Build +#### To setup an Automated Build 1. Create a [Docker Hub account](https://hub.docker.com/) and login. -2. Link your GitHub or BitBucket account through the [`Link Accounts`](https://registry.hub.docker.com/account/accounts/) menu. +2. Link your GitHub or BitBucket account through the ["Link Accounts"](https://registry.hub.docker.com/account/accounts/) menu. 3. [Configure an Automated Build](https://registry.hub.docker.com/builds/). 4. Pick a GitHub or BitBucket project that has a `Dockerfile` that you want to build. 5. Pick the branch you want to build (the default is the `master` branch). @@ -141,33 +132,32 @@ commit. 8. Specify where the `Dockerfile` is located. The default is `/`. Once the Automated Build is configured it will automatically trigger a -build, and in a few minutes, if there are no errors, you will see your -new Automated Build on the [Docker Hub](https://hub.docker.com) Registry. -It will stay in sync with your GitHub and BitBucket repository until you +build and, in a few minutes, you should see your new Automated Build on the [Docker Hub](https://hub.docker.com) +Registry. It will stay in sync with your GitHub and BitBucket repository until you deactivate the Automated Build. -If you want to see the status of your Automated Builds you can go to your +If you want to see the status of your Automated Builds, you can go to your [Automated Builds page](https://registry.hub.docker.com/builds/) on the Docker Hub, -and it will show you the status of your builds, and the build history. +and it will show you the status of your builds and their build history. Once you've created an Automated Build you can deactivate or delete it. You -cannot however push to an Automated Build with the `docker push` command. +cannot, however, push to an Automated Build with the `docker push` command. You can only manage it by committing code to your GitHub or BitBucket repository. You can create multiple Automated Builds per repository and configure them to point to specific `Dockerfile`'s or Git branches. -### Build Triggers +#### Build Triggers Automated Builds can also be triggered via a URL on Docker Hub. This allows you to rebuild an Automated build image on demand. -## Webhooks +### Webhooks Webhooks are attached to your repositories and allow you to trigger an event when an image or updated image is pushed to the repository. With -a webhook you can specify a target URL and a JSON payload will be +a webhook you can specify a target URL and a JSON payload that will be delivered when the image is pushed. ## Next steps From ab0fc77ebe73e0dededad1d47dc3788191cb966c Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Fri, 20 Jun 2014 17:52:30 -0700 Subject: [PATCH 034/167] Fixed a typo Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- docs/sources/userguide/dockerrepos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerrepos.md b/docs/sources/userguide/dockerrepos.md index 2e5abbba1..a73c4b783 100644 --- a/docs/sources/userguide/dockerrepos.md +++ b/docs/sources/userguide/dockerrepos.md @@ -41,7 +41,7 @@ push your own images up to your repos on Docker Hub. ## Searching for images -You can search the [Docker Hub](https://hub.docker.com) registry via it's search +You can search the [Docker Hub](https://hub.docker.com) registry via its search interface or by using the command line interface. Searching can find images by image name, user name, or description: From 00469957ad0e17adf60a486740f4132a503e7309 Mon Sep 17 00:00:00 2001 From: Kato Kazuyoshi Date: Sat, 21 Jun 2014 17:32:39 +0900 Subject: [PATCH 035/167] Fatal() doesn't take a format string like Fatalf() Docker-DCO-1.1-Signed-off-by: Kato Kazuyoshi (github: kzys) --- runconfig/parse_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runconfig/parse_test.go b/runconfig/parse_test.go index 88fa0dd54..94cea493f 100644 --- a/runconfig/parse_test.go +++ b/runconfig/parse_test.go @@ -25,26 +25,26 @@ func TestParseLxcConfOpt(t *testing.T) { func TestNetHostname(t *testing.T) { if _, _, _, err := Parse([]string{"-h=name", "img", "cmd"}, nil); err != nil { - t.Fatal("Unexpected error: %s", err) + t.Fatalf("Unexpected error: %s", err) } if _, _, _, err := Parse([]string{"--net=host", "img", "cmd"}, nil); err != nil { - t.Fatal("Unexpected error: %s", err) + t.Fatalf("Unexpected error: %s", err) } if _, _, _, err := Parse([]string{"-h=name", "--net=bridge", "img", "cmd"}, nil); err != nil { - t.Fatal("Unexpected error: %s", err) + t.Fatalf("Unexpected error: %s", err) } if _, _, _, err := Parse([]string{"-h=name", "--net=none", "img", "cmd"}, nil); err != nil { - t.Fatal("Unexpected error: %s", err) + t.Fatalf("Unexpected error: %s", err) } if _, _, _, err := Parse([]string{"-h=name", "--net=host", "img", "cmd"}, nil); err != ErrConflictNetworkHostname { - t.Fatal("Expected error ErrConflictNetworkHostname, got: %s", err) + t.Fatalf("Expected error ErrConflictNetworkHostname, got: %s", err) } if _, _, _, err := Parse([]string{"-h=name", "--net=container:other", "img", "cmd"}, nil); err != ErrConflictNetworkHostname { - t.Fatal("Expected error ErrConflictNetworkHostname, got: %s", err) + t.Fatalf("Expected error ErrConflictNetworkHostname, got: %s", err) } } From ba7245f07271d5ccba70ef659b3e88424cf36887 Mon Sep 17 00:00:00 2001 From: Robert Bachmann Date: Sat, 21 Jun 2014 23:12:10 +0200 Subject: [PATCH 036/167] Windows needs hardware virtualization VirtualBox needs hardware virtualization for 64-bit guests. Docker-DCO-1.1-Signed-off-by: Robert Bachmann (github: robertbachmann) --- docs/sources/installation/windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 7cc2b991d..9908c053d 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -5,7 +5,7 @@ page_keywords: Docker, Docker documentation, Windows, requirements, virtualbox, # Windows > **Note:** > Docker has been tested on Windows 7.1 and 8; it may also run on older versions. - +> Your processor needs to support hardware virtualization. The Docker Engine uses Linux-specific kernel features, so to run it on Windows we need to use a lightweight virtual machine (vm). You use the Windows Docker client to From 51d032737c812347c766bf7a3df43c18ec708b9e Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Sun, 22 Jun 2014 15:59:47 -0700 Subject: [PATCH 037/167] one last missing redirect Docker-DCO-1.1-Signed-off-by: Sven Dowideit (github: SvenDowideit) --- docs/s3_website.json | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/s3_website.json b/docs/s3_website.json index 8a6f99beb..224ba816e 100644 --- a/docs/s3_website.json +++ b/docs/s3_website.json @@ -27,6 +27,7 @@ { "Condition": { "KeyPrefixEquals": "docker-io/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "docker-hub/" } }, { "Condition": { "KeyPrefixEquals": "examples/cfengine_process_management/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/cfengine_process_management/" } }, { "Condition": { "KeyPrefixEquals": "examples/https/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/https/" } }, + { "Condition": { "KeyPrefixEquals": "examples/ambassador_pattern_linking/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/ambassador_pattern_linking/" } }, { "Condition": { "KeyPrefixEquals": "examples/using_supervisord/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "articles/using_supervisord/" } }, { "Condition": { "KeyPrefixEquals": "reference/api/registry_index_spec/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "reference/api/hub_registry_spec/" } }, { "Condition": { "KeyPrefixEquals": "use/" }, "Redirect": { "HostName": "$BUCKET", "ReplaceKeyPrefixWith": "examples/" } } From 1e847bff7af8ae722318cc7d448f46be955496c3 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Sun, 22 Jun 2014 17:34:04 -0700 Subject: [PATCH 038/167] Remove mention of SSH passphrase, it was only present in v0.12 Docker-DCO-1.1-Signed-off-by: Sven Dowideit (github: SvenDowideit) --- docs/sources/installation/mac.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/sources/installation/mac.md b/docs/sources/installation/mac.md index 4677005cc..b6253de12 100644 --- a/docs/sources/installation/mac.md +++ b/docs/sources/installation/mac.md @@ -31,16 +31,12 @@ virtual machine and runs the Docker daemon. 3. Run the `Boot2Docker` app in the `Applications` folder: ![](/installation/images/osx-Boot2Docker-Start-app.png) - Or, to initiate Boot2Docker manually, open a terminal and run: + Or, to initialize Boot2Docker manually, open a terminal and run: $ boot2docker init $ boot2docker start $ export DOCKER_HOST=tcp://$(boot2docker ip 2>/dev/null):2375 - The `boot2docker init` command will ask you to enter an SSH key passphrase - the simplest - (but least secure) is to just hit [Enter]. This passphrase is used by the - `boot2docker ssh` command. - Once you have an initialized virtual machine, you can control it with `boot2docker stop` and `boot2docker start`. From 9559f57463f8cd4c1af726514ae744a646fdd462 Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Tue, 17 Jun 2014 14:52:52 +0300 Subject: [PATCH 039/167] Update fedora.md Docker-DCO-1.1-Signed-off-by: Alexander Shopov (github: alshopov) Squashed by Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) replaces #6478 Docker-DCO-1.1-Signed-off-by: Alexander Shopov (github: ) --- docs/sources/installation/fedora.md | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/sources/installation/fedora.md b/docs/sources/installation/fedora.md index bcd54e6bd..a230aa6cf 100644 --- a/docs/sources/installation/fedora.md +++ b/docs/sources/installation/fedora.md @@ -48,6 +48,44 @@ Now let's verify that Docker is working. $ sudo docker run -i -t fedora /bin/bash +## Granting rights to users to use Docker + +Fedora 19 and 20 shipped with Docker 0.11. The package has already been updated +to 1.0 in Fedora 20. If you are still using the 0.11 version you will need to +grant rights to users of Docker. + +The `docker` command line tool contacts the `docker` daemon process via a +socket file `/var/run/docker.sock` owned by group `docker`. One must be +member of that group in order to contact the `docker -d` process. + + $ usermod -a -G docker login_name + +Adding users to the `docker` group is *not* necessary for Docker versions 1.0 +and above. + +## HTTP Proxy + +If you are behind a HTTP proxy server, for example in corporate settings, +you will need to add this configuration in the Docker *systemd service file*. + +Edit file `/lib/systemd/system/docker.service`. Add the following to +section `[Service]` : + + Environment="HTTP_PROXY=http://proxy.example.com:80/" + +If you have internal Docker registries that you need to contact without +proxying you can specify them via the `NO_PROXY` environment variable: + + Environment="HTTP_PROXY=http://proxy.example.com:80/" "NO_PROXY=localhost,127.0.0.0/8,docker-registry.somecorporation.com" + +Flush changes: + + $ systemctl daemon-reload + +Restart Docker: + + $ systemctl start docker + ## What next? Continue with the [User Guide](/userguide/). From 4d7e28a7d701c3c3ee331f2d6f4fce62fdd20d93 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Mon, 23 Jun 2014 14:50:11 +1000 Subject: [PATCH 040/167] Remove `$` leaders from examples of editing text in a file not everything that is indented is a commandline example Closes #6591 Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/sources/installation/ubuntulinux.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sources/installation/ubuntulinux.md b/docs/sources/installation/ubuntulinux.md index f1ba4971e..5d1b6c3fb 100644 --- a/docs/sources/installation/ubuntulinux.md +++ b/docs/sources/installation/ubuntulinux.md @@ -244,18 +244,18 @@ To install the latest version of docker, use the standard If you want to enable memory and swap accounting, you must add the following command-line parameters to your kernel: - $ cgroup_enable=memory swapaccount=1 + cgroup_enable=memory swapaccount=1 On systems using GRUB (which is the default for Ubuntu), you can add those parameters by editing `/etc/default/grub` and extending `GRUB_CMDLINE_LINUX`. Look for the following line: - $ GRUB_CMDLINE_LINUX="" + GRUB_CMDLINE_LINUX="" And replace it by the following one: - $ GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1" + GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1" Then run `sudo update-grub`, and reboot. @@ -283,7 +283,7 @@ forwarding: # Change: # DEFAULT_FORWARD_POLICY="DROP" # to - $ DEFAULT_FORWARD_POLICY="ACCEPT" + DEFAULT_FORWARD_POLICY="ACCEPT" Then reload UFW: @@ -316,7 +316,7 @@ Docker daemon for the containers: $ sudo nano /etc/default/docker --- # Add: - $ DOCKER_OPTS="--dns 8.8.8.8" + DOCKER_OPTS="--dns 8.8.8.8" # 8.8.8.8 could be replaced with a local DNS server, such as 192.168.1.1 # multiple DNS servers can be specified: --dns 8.8.8.8 --dns 192.168.1.1 From 3ce5fde7ab86bb5307129b77fa09225ca07b1128 Mon Sep 17 00:00:00 2001 From: Ivan Fraixedes Date: Mon, 23 Jun 2014 16:08:34 +0100 Subject: [PATCH 041/167] Update dockervolumes.md Missed double hyphen in `--volumes-from` option --- docs/sources/userguide/dockervolumes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockervolumes.md b/docs/sources/userguide/dockervolumes.md index 0c2f6cfac..7b3494920 100644 --- a/docs/sources/userguide/dockervolumes.md +++ b/docs/sources/userguide/dockervolumes.md @@ -90,7 +90,7 @@ And another: $ docker run -d --volumes-from dbdata --name db2 training/postgres -You can use multiple `-volumes-from` parameters to bring together multiple data +You can use multiple `--volumes-from` parameters to bring together multiple data volumes from multiple containers. You can also extend the chain by mounting the volume that came from the From 8228d0e2bbd3a42755a84e11455b51a5caf61a94 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 23 Jun 2014 17:52:03 +0000 Subject: [PATCH 042/167] Remove old tag format Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/client/commands.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 0cdf3f1ac..08ca0495a 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1829,21 +1829,15 @@ func (cli *DockerCli) CmdTag(args ...string) error { if err := cmd.Parse(args); err != nil { return nil } - if cmd.NArg() != 2 && cmd.NArg() != 3 { + if cmd.NArg() != 2 { cmd.Usage() return nil } - var repository, tag string - - if cmd.NArg() == 3 { - fmt.Fprintf(cli.err, "[DEPRECATED] The format 'IMAGE [REPOSITORY [TAG]]' as been deprecated. Please use IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]]\n") - repository, tag = cmd.Arg(1), cmd.Arg(2) - } else { + var ( repository, tag = utils.ParseRepositoryTag(cmd.Arg(1)) - } - - v := url.Values{} + v = url.Values{} + ) //Check if the given image name can be resolved if _, _, err := registry.ResolveRepositoryName(repository); err != nil { From 386d1ecc6e2489401aac685eb11da15d21c4b0a7 Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Mon, 23 Jun 2014 22:19:52 +0400 Subject: [PATCH 043/167] Move sorter_test from integration to integration-cli TestServerListOrderedImagesByCreationDateAndTag was redundant and broken Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- integration-cli/docker_cli_images_test.go | 42 +++++++++++++++++ integration/sorter_test.go | 56 ----------------------- 2 files changed, 42 insertions(+), 56 deletions(-) delete mode 100644 integration/sorter_test.go diff --git a/integration-cli/docker_cli_images_test.go b/integration-cli/docker_cli_images_test.go index b27bc870f..2cf2bbfcf 100644 --- a/integration-cli/docker_cli_images_test.go +++ b/integration-cli/docker_cli_images_test.go @@ -5,6 +5,7 @@ import ( "os/exec" "strings" "testing" + "time" ) func TestImagesEnsureImageIsListed(t *testing.T) { @@ -56,3 +57,44 @@ func TestCLIImageTagRemove(t *testing.T) { } logDone("tag,rmi- tagging the same images multiple times then removing tags") } + +func TestImagesOrderedByCreationDate(t *testing.T) { + defer deleteImages("order:test_a") + defer deleteImages("order:test_c") + defer deleteImages("order:test_b") + id1, err := buildImage("order:test_a", + `FROM scratch + MAINTAINER dockerio1`, true) + if err != nil { + t.Fatal(err) + } + time.Sleep(time.Second) + id2, err := buildImage("order:test_c", + `FROM scratch + MAINTAINER dockerio2`, true) + if err != nil { + t.Fatal(err) + } + time.Sleep(time.Second) + id3, err := buildImage("order:test_b", + `FROM scratch + MAINTAINER dockerio3`, true) + if err != nil { + t.Fatal(err) + } + + out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "images", "-q", "--no-trunc")) + errorOut(err, t, fmt.Sprintf("listing images failed with errors: %v", err)) + imgs := strings.Split(out, "\n") + if imgs[0] != id3 { + t.Fatalf("First image must be %s, got %s", id3, imgs[0]) + } + if imgs[1] != id2 { + t.Fatalf("Second image must be %s, got %s", id2, imgs[1]) + } + if imgs[2] != id1 { + t.Fatalf("Third image must be %s, got %s", id1, imgs[2]) + } + + logDone("images - ordering by creation date") +} diff --git a/integration/sorter_test.go b/integration/sorter_test.go deleted file mode 100644 index 610fe9b3a..000000000 --- a/integration/sorter_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package docker - -import ( - "github.com/dotcloud/docker/engine" - "testing" - "time" -) - -func TestServerListOrderedImagesByCreationDate(t *testing.T) { - eng := NewTestEngine(t) - defer mkDaemonFromEngine(eng, t).Nuke() - - if err := generateImage("", eng); err != nil { - t.Fatal(err) - } - - images := getImages(eng, t, true, "") - - if images.Data[0].GetInt("Created") < images.Data[1].GetInt("Created") { - t.Error("Expected images to be ordered by most recent creation date.") - } -} - -func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) { - eng := NewTestEngine(t) - defer mkDaemonFromEngine(eng, t).Nuke() - - err := generateImage("bar", eng) - if err != nil { - t.Fatal(err) - } - - time.Sleep(time.Second) - - err = generateImage("zed", eng) - if err != nil { - t.Fatal(err) - } - - images := getImages(eng, t, true, "") - - if repoTags := images.Data[0].GetList("RepoTags"); repoTags[0] != "repo:zed" && repoTags[0] != "repo:bar" { - t.Errorf("Expected Images to be ordered by most recent creation date.") - } -} - -func generateImage(name string, eng *engine.Engine) error { - archive, err := fakeTar() - if err != nil { - return err - } - job := eng.Job("import", "-", "repo", name) - job.Stdin.Add(archive) - job.SetenvBool("json", true) - return job.Run() -} From edf16383c60c8c05549a97a0fb909c2387f69bce Mon Sep 17 00:00:00 2001 From: "Roberto G. Hashioka" Date: Mon, 23 Jun 2014 18:35:15 +0000 Subject: [PATCH 044/167] Fix header and about Docker links --- docs/sources/index.md | 2 +- docs/theme/mkdocs/header.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 06e1ac6d5..ef5fe2c2c 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -6,7 +6,7 @@ page_keywords: docker, introduction, documentation, about, technology, understan **Develop, Ship and Run Any Application, Anywhere** -[**Docker**](https://www.docker.io) is a platform for developers and sysadmins +[**Docker**](https://www.docker.com) is a platform for developers and sysadmins to develop, ship, and run applications. Docker lets you quickly assemble applications from components and eliminates the friction that can come when shipping code. Docker lets you get your code tested and deployed into production diff --git a/docs/theme/mkdocs/header.html b/docs/theme/mkdocs/header.html index 785797f0d..351c1583e 100644 --- a/docs/theme/mkdocs/header.html +++ b/docs/theme/mkdocs/header.html @@ -25,8 +25,8 @@
- {% include "version.html" %} + {% include "beta_warning.html" %} {{ content }}
From 3fcb0d880aad65690cac304c30f72d0688a801d2 Mon Sep 17 00:00:00 2001 From: Trent Ogren Date: Mon, 9 Jun 2014 13:33:55 -0500 Subject: [PATCH 084/167] Add missing parenthesis in docs for -author switch Docker-DCO-1.1-Signed-off-by: Trent Ogren (github: misfo) Docker-DCO-1.1-Signed-off-by: Trent Ogren (github: SvenDowideit) --- api/client/commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/client/commands.go b/api/client/commands.go index 46a465f69..83bf09a7e 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1520,7 +1520,7 @@ func (cli *DockerCli) CmdPs(args ...string) error { func (cli *DockerCli) CmdCommit(args ...string) error { cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") - flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith \"") + flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith \")") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. flConfig := cmd.String([]string{"#run", "#-run"}, "", "this option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") if err := cmd.Parse(args); err != nil { From 389916bf9ae62ded0e497512da22faba75d0cf2d Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Wed, 25 Jun 2014 16:50:35 -0700 Subject: [PATCH 085/167] Add the missing paren to the documentation for docker commit too Docker-DCO-1.1-Signed-off-by: Sven Dowideit (github: SvenDowideit) --- docs/sources/reference/commandline/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 47dd0a992..1b67b216f 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -306,7 +306,7 @@ schema. Create a new image from a container's changes - -a, --author="" Author (eg. "John Hannibal Smith " + -a, --author="" Author (eg. "John Hannibal Smith ") -m, --message="" Commit message It can be useful to commit a container's file changes or settings into a From c42b5575e5dff5b3a117462e32eda0095528e3b2 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Wed, 25 Jun 2014 19:07:39 -0600 Subject: [PATCH 086/167] Update contrib/mkimage/debootstrap to remove /var/lib/apt/lists (trimming at least 40MB and forcing "apt-get update" in dependent images before packages can be installed) Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/mkimage/debootstrap | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/mkimage/debootstrap b/contrib/mkimage/debootstrap index d5aeae2b9..96d22dddd 100755 --- a/contrib/mkimage/debootstrap +++ b/contrib/mkimage/debootstrap @@ -164,9 +164,13 @@ if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then esac fi -# make sure we're fully up-to-date, too ( set -x - chroot "$rootfsDir" apt-get update - chroot "$rootfsDir" apt-get dist-upgrade -y + + # make sure we're fully up-to-date + chroot "$rootfsDir" bash -c 'apt-get update && apt-get dist-upgrade -y' + + # delete all the apt list files since they're big and get stale quickly + rm -rf "$rootfsDir/var/lib/apt/lists"/* + # this forces "apt-get update" in dependent images, which is also good ) From 5e256799ddd6a297e22756363fc5eb079af0f07e Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Wed, 25 Jun 2014 22:12:25 -0600 Subject: [PATCH 087/167] Add bash completion for "docker rm -f" and complete on all containers instead of just stopped containers when "-f" is specified Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/completion/bash/docker | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index f75b85ca8..89395560f 100755 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -458,10 +458,21 @@ _docker_rm() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "-v --volumes -l --link" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "-f --force -l --link -v --volumes" -- "$cur" ) ) + return ;; *) + local force= + for arg in "${COMP_WORDS[@]}"; do + case "$arg" in + -f|--force) + __docker_containers_all + return + ;; + esac + done __docker_containers_stopped + return ;; esac } From 6bb6e422b5cd9e9ee97c5855a94b5776323a5626 Mon Sep 17 00:00:00 2001 From: leeplay Date: Thu, 26 Jun 2014 15:14:18 +0900 Subject: [PATCH 088/167] Update examples/nodejs_web_app Docker-DCO-1.1-Signed-off-by: Hyeongkyu Lee (github: leeplay) --- docs/sources/examples/nodejs_web_app.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/examples/nodejs_web_app.md b/docs/sources/examples/nodejs_web_app.md index cf00e88be..cc3ea061a 100644 --- a/docs/sources/examples/nodejs_web_app.md +++ b/docs/sources/examples/nodejs_web_app.md @@ -137,9 +137,9 @@ Your image will now be listed by Docker: $ sudo docker images # Example - REPOSITORY TAG ID CREATED - centos 6.4 539c0211cd76 8 weeks ago - gasi/centos-node-hello latest d64d3505b0d2 2 hours ago + REPOSITORY TAG ID CREATED + centos 6.4 539c0211cd76 8 weeks ago + /centos-node-hello latest d64d3505b0d2 2 hours ago ## Run the image From 714c1bd8ca49c6fc5e7939d6a7abf6a54d56b06a Mon Sep 17 00:00:00 2001 From: "O.S. Tezer" Date: Sun, 22 Jun 2014 22:15:26 -0700 Subject: [PATCH 089/167] Anglicanisms: Grammatical correction (pos. adj. apost.) Docker-DCO-1.1-Signed-off-by: O.S. Tezer (github: ostezer) --- api/client/commands.go | 2 +- contrib/completion/fish/docker.fish | 2 +- docs/man/docker-cp.1.md | 2 +- docs/man/docker.1.md | 2 +- docs/sources/reference/commandline/cli.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 46a465f69..2c03a6d02 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -55,7 +55,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { {"attach", "Attach to a running container"}, {"build", "Build an image from a Dockerfile"}, {"commit", "Create a new image from a container's changes"}, - {"cp", "Copy files/folders from the containers filesystem to the host path"}, + {"cp", "Copy files/folders from a container's filesystem to the host path"}, {"diff", "Inspect changes on a container's filesystem"}, {"events", "Get real time events from the server"}, {"export", "Stream the contents of a container as a tar archive"}, diff --git a/contrib/completion/fish/docker.fish b/contrib/completion/fish/docker.fish index 00255bc0a..a1eac31df 100644 --- a/contrib/completion/fish/docker.fish +++ b/contrib/completion/fish/docker.fish @@ -85,7 +85,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l run -d 'Conf complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container" # cp -complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d 'Copy files/folders from the containers filesystem to the host path' +complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d 'Copy files/folders from a container's filesystem to the host path' # diff complete -c docker -f -n '__fish_docker_no_subcommand' -a diff -d "Inspect changes on a container's filesystem" diff --git a/docs/man/docker-cp.1.md b/docs/man/docker-cp.1.md index f78719866..1801e7318 100644 --- a/docs/man/docker-cp.1.md +++ b/docs/man/docker-cp.1.md @@ -8,7 +8,7 @@ docker-cp - Copy files/folders from the PATH to the HOSTPATH **docker cp** CONTAINER:PATH HOSTPATH # DESCRIPTION -Copy files/folders from the containers filesystem to the host +Copy files/folders from a container's filesystem to the host path. Paths are relative to the root of the filesystem. Files can be copied from a running or stopped container. diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index ab5b67d11..ae5efff87 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -87,7 +87,7 @@ unix://[/path/to/socket] to use. Create a new image from a container's changes **docker-cp(1)** - Copy files/folders from the containers filesystem to the host at path + Copy files/folders from a container's filesystem to the host at path **docker-diff(1)** Inspect changes on a container's filesystem diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 47dd0a992..77f868e97 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -329,7 +329,7 @@ maintainable way. ## cp -Copy files/folders from the containers filesystem to the host +Copy files/folders from a container's filesystem to the host path. Paths are relative to the root of the filesystem. Usage: docker cp CONTAINER:PATH HOSTPATH From e0dad305791a7406cf819a27fa5a079a46a62acc Mon Sep 17 00:00:00 2001 From: unclejack Date: Wed, 25 Jun 2014 01:24:02 +0300 Subject: [PATCH 090/167] refactor TruncIndex to use a trie & vendor deps Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- daemon/daemon.go | 8 +- hack/vendor.sh | 2 + pkg/truncindex/truncindex.go | 98 ++- pkg/truncindex/truncindex_test.go | 15 +- .../github.com/tchap/go-patricia/.gitignore | 25 + .../github.com/tchap/go-patricia/.travis.yml | 9 + .../src/github.com/tchap/go-patricia/AUTHORS | 3 + .../src/github.com/tchap/go-patricia/LICENSE | 20 + .../github.com/tchap/go-patricia/README.md | 112 +++ .../tchap/go-patricia/patricia/children.go | 231 ++++++ .../tchap/go-patricia/patricia/patricia.go | 432 ++++++++++++ .../patricia/patricia_dense_test.go | 161 +++++ .../patricia/patricia_sparse_test.go | 659 ++++++++++++++++++ .../go-patricia/patricia/patricia_test.go | 78 +++ 14 files changed, 1795 insertions(+), 58 deletions(-) create mode 100644 vendor/src/github.com/tchap/go-patricia/.gitignore create mode 100644 vendor/src/github.com/tchap/go-patricia/.travis.yml create mode 100644 vendor/src/github.com/tchap/go-patricia/AUTHORS create mode 100644 vendor/src/github.com/tchap/go-patricia/LICENSE create mode 100644 vendor/src/github.com/tchap/go-patricia/README.md create mode 100644 vendor/src/github.com/tchap/go-patricia/patricia/children.go create mode 100644 vendor/src/github.com/tchap/go-patricia/patricia/patricia.go create mode 100644 vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go create mode 100644 vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go create mode 100644 vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go diff --git a/daemon/daemon.go b/daemon/daemon.go index e4078fdfe..3536678d2 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -182,11 +182,7 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool, con // don't update the Suffixarray if we're starting up // we'll waste time if we update it for every container - if updateSuffixarray { - daemon.idIndex.Add(container.ID) - } else { - daemon.idIndex.AddWithoutSuffixarrayUpdate(container.ID) - } + daemon.idIndex.Add(container.ID) // FIXME: if the container is supposed to be running but is not, auto restart it? // if so, then we need to restart monitor and init a new lock @@ -377,8 +373,6 @@ func (daemon *Daemon) restore() error { } } - daemon.idIndex.UpdateSuffixarray() - for _, container := range containersToStart { utils.Debugf("Starting container %d", container.ID) if err := container.Start(); err != nil { diff --git a/hack/vendor.sh b/hack/vendor.sh index c4494ffa7..630998e20 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -47,6 +47,8 @@ clone git github.com/gorilla/mux 136d54f81f clone git github.com/syndtr/gocapability 3c85049eae +clone git github.com/tchap/go-patricia v1.0.0 + clone hg code.google.com/p/go.net 84a4013f96e0 clone hg code.google.com/p/gosqlite 74691fb6f837 diff --git a/pkg/truncindex/truncindex.go b/pkg/truncindex/truncindex.go index 78512047a..811f60666 100644 --- a/pkg/truncindex/truncindex.go +++ b/pkg/truncindex/truncindex.go @@ -1,31 +1,34 @@ package truncindex import ( + "errors" "fmt" - "index/suffixarray" "strings" "sync" + + "github.com/tchap/go-patricia/patricia" +) + +var ( + ErrNoID = errors.New("prefix can't be empty") ) // TruncIndex allows the retrieval of string identifiers by any of their unique prefixes. // This is used to retrieve image and container IDs by more convenient shorthand prefixes. type TruncIndex struct { sync.RWMutex - index *suffixarray.Index - ids map[string]bool - bytes []byte + trie *patricia.Trie + ids map[string]struct{} } func NewTruncIndex(ids []string) (idx *TruncIndex) { idx = &TruncIndex{ - ids: make(map[string]bool), - bytes: []byte{' '}, + ids: make(map[string]struct{}), + trie: patricia.NewTrie(), } for _, id := range ids { - idx.ids[id] = true - idx.bytes = append(idx.bytes, []byte(id+" ")...) + idx.addId(id) } - idx.index = suffixarray.New(idx.bytes) return } @@ -33,11 +36,16 @@ func (idx *TruncIndex) addId(id string) error { if strings.Contains(id, " ") { return fmt.Errorf("Illegal character: ' '") } - if _, exists := idx.ids[id]; exists { - return fmt.Errorf("Id already exists: %s", id) + if id == "" { + return ErrNoID + } + if _, exists := idx.ids[id]; exists { + return fmt.Errorf("Id already exists: '%s'", id) + } + idx.ids[id] = struct{}{} + if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted { + return fmt.Errorf("Failed to insert id: %s", id) } - idx.ids[id] = true - idx.bytes = append(idx.bytes, []byte(id+" ")...) return nil } @@ -47,56 +55,46 @@ func (idx *TruncIndex) Add(id string) error { if err := idx.addId(id); err != nil { return err } - idx.index = suffixarray.New(idx.bytes) return nil } -func (idx *TruncIndex) AddWithoutSuffixarrayUpdate(id string) error { - idx.Lock() - defer idx.Unlock() - return idx.addId(id) -} - -func (idx *TruncIndex) UpdateSuffixarray() { - idx.Lock() - defer idx.Unlock() - idx.index = suffixarray.New(idx.bytes) -} - func (idx *TruncIndex) Delete(id string) error { idx.Lock() defer idx.Unlock() - if _, exists := idx.ids[id]; !exists { - return fmt.Errorf("No such id: %s", id) - } - before, after, err := idx.lookup(id) - if err != nil { - return err + if _, exists := idx.ids[id]; !exists || id == "" { + return fmt.Errorf("No such id: '%s'", id) } delete(idx.ids, id) - idx.bytes = append(idx.bytes[:before], idx.bytes[after:]...) - idx.index = suffixarray.New(idx.bytes) - return nil -} - -func (idx *TruncIndex) lookup(s string) (int, int, error) { - offsets := idx.index.Lookup([]byte(" "+s), -1) - //log.Printf("lookup(%s): %v (index bytes: '%s')\n", s, offsets, idx.index.Bytes()) - if offsets == nil || len(offsets) == 0 || len(offsets) > 1 { - return -1, -1, fmt.Errorf("No such id: %s", s) + if deleted := idx.trie.Delete(patricia.Prefix(id)); !deleted { + return fmt.Errorf("No such id: '%s'", id) } - offsetBefore := offsets[0] + 1 - offsetAfter := offsetBefore + strings.Index(string(idx.bytes[offsetBefore:]), " ") - return offsetBefore, offsetAfter, nil + return nil } func (idx *TruncIndex) Get(s string) (string, error) { idx.RLock() defer idx.RUnlock() - before, after, err := idx.lookup(s) - //log.Printf("Get(%s) bytes=|%s| before=|%d| after=|%d|\n", s, idx.bytes, before, after) - if err != nil { - return "", err + var ( + id string + ) + if s == "" { + return "", ErrNoID } - return string(idx.bytes[before:after]), err + subTreeVisitFunc := func(prefix patricia.Prefix, item patricia.Item) error { + if id != "" { + // we haven't found the ID if there are two or more IDs + id = "" + return fmt.Errorf("we've found two entries") + } + id = string(prefix) + return nil + } + + if err := idx.trie.VisitSubtree(patricia.Prefix(s), subTreeVisitFunc); err != nil { + return "", fmt.Errorf("No such id: %s", s) + } + if id != "" { + return id, nil + } + return "", fmt.Errorf("No such id: %s", s) } diff --git a/pkg/truncindex/truncindex_test.go b/pkg/truncindex/truncindex_test.go index 5e2a386d7..f88d667d5 100644 --- a/pkg/truncindex/truncindex_test.go +++ b/pkg/truncindex/truncindex_test.go @@ -26,8 +26,16 @@ func TestTruncIndex(t *testing.T) { if err := index.Add(id); err != nil { t.Fatal(err) } + + // Add an empty id (should fail) + if err := index.Add(""); err == nil { + t.Fatalf("Adding an empty id should return an error") + } + // Get a non-existing id assertIndexGet(t, index, "abracadabra", "", true) + // Get an empty id + assertIndexGet(t, index, "", "", true) // Get the exact id assertIndexGet(t, index, id, id, false) // The first letter should match @@ -60,6 +68,11 @@ func TestTruncIndex(t *testing.T) { t.Fatalf("Deleting a non-existing id should return an error") } + // Deleting an empty id should return an error + if err := index.Delete(""); err == nil { + t.Fatal("Deleting an empty id should return an error") + } + // Deleting id2 should remove conflicts if err := index.Delete(id2); err != nil { t.Fatal(err) @@ -84,7 +97,7 @@ func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult strin if result, err := index.Get(input); err != nil && !expectError { t.Fatalf("Unexpected error getting '%s': %s", input, err) } else if err == nil && expectError { - t.Fatalf("Getting '%s' should return an error", input) + t.Fatalf("Getting '%s' should return an error, not '%s'", input, result) } else if result != expectedResult { t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult) } diff --git a/vendor/src/github.com/tchap/go-patricia/.gitignore b/vendor/src/github.com/tchap/go-patricia/.gitignore new file mode 100644 index 000000000..b3971c067 --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/.gitignore @@ -0,0 +1,25 @@ +# Swap files. +*.swp + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/src/github.com/tchap/go-patricia/.travis.yml b/vendor/src/github.com/tchap/go-patricia/.travis.yml new file mode 100644 index 000000000..66183e2ad --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.2 + - tip + +branches: + exclude: + - wip diff --git a/vendor/src/github.com/tchap/go-patricia/AUTHORS b/vendor/src/github.com/tchap/go-patricia/AUTHORS new file mode 100644 index 000000000..e640b0bf5 --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/AUTHORS @@ -0,0 +1,3 @@ +This is the complete list of go-patricia copyright holders: + +Ondřej Kupka diff --git a/vendor/src/github.com/tchap/go-patricia/LICENSE b/vendor/src/github.com/tchap/go-patricia/LICENSE new file mode 100644 index 000000000..e50d398e9 --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 The AUTHORS + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/tchap/go-patricia/README.md b/vendor/src/github.com/tchap/go-patricia/README.md new file mode 100644 index 000000000..635e2b8ea --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/README.md @@ -0,0 +1,112 @@ +# go-patricia # + +**Documentation**: [GoDoc](http://godoc.org/github.com/tchap/go-patricia/patricia)
+**Build Status**: [![Build Status](https://travis-ci.org/tchap/go-patricia.png?branch=master)](https://travis-ci.org/tchap/go-patricia)
+**Test Coverage**: Comming as soon as Drone.io people update their Go. + +## About ## + +A generic patricia trie (also called radix tree) implemented in Go (Golang). + +The patricia trie as implemented in this library enables fast visiting of items +in some particular ways: + +1. visit all items saved in the tree, +2. visit all items matching particular prefix (visit subtree), or +3. given a string, visit all items matching some prefix of that string. + +`[]byte` type is used for keys, `interface{}` for values. + +`Trie` is not thread safe. Synchronize the access yourself. + +### State of the Project ### + +Apparently some people are using this, so the API should not change often. +Any ideas on how to make the library better are still welcome. + +More (unit) testing would be cool as well... + +## Usage ## + +Import the package from GitHub first. + +```go +import "github.com/tchap/go-patricia/patricia" +``` + +Then you can start having fun. + +```go +printItem := func(prefix patricia.Prefix, item patricia.Item) error { + fmt.Printf("%q: %v\n", prefix, item) + return nil +} + +// Create a new tree. +trie := NewTrie() + +// Insert some items. +trie.Insert(Prefix("Pepa Novak"), 1) +trie.Insert(Prefix("Pepa Sindelar"), 2) +trie.Insert(Prefix("Karel Macha"), 3) +trie.Insert(Prefix("Karel Hynek Macha"), 4) + +// Just check if some things are present in the tree. +key := Prefix("Pepa Novak") +fmt.Printf("%q present? %v\n", key, trie.Match(key)) +// "Pepa Novak" present? true +key = Prefix("Karel") +fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key)) +// Anybody called "Karel" here? true + +// Walk the tree. +trie.Visit(printItem) +// "Pepa Novak": 1 +// "Pepa Sindelar": 2 +// "Karel Macha": 3 +// "Karel Hynek Macha": 4 + +// Walk a subtree. +trie.VisitSubtree(Prefix("Pepa"), printItem) +// "Pepa Novak": 1 +// "Pepa Sindelar": 2 + +// Modify an item, then fetch it from the tree. +trie.Set(Prefix("Karel Hynek Macha"), 10) +key = Prefix("Karel Hynek Macha") +fmt.Printf("%q: %v\n", key, trie.Get(key)) +// "Karel Hynek Macha": 10 + +// Walk prefixes. +prefix := Prefix("Karel Hynek Macha je kouzelnik") +trie.VisitPrefixes(prefix, printItem) +// "Karel Hynek Macha": 10 + +// Delete some items. +trie.Delete(Prefix("Pepa Novak")) +trie.Delete(Prefix("Karel Macha")) + +// Walk again. +trie.Visit(printItem) +// "Pepa Sindelar": 2 +// "Karel Hynek Macha": 10 + +// Delete a subtree. +trie.DeleteSubtree(Prefix("Pepa")) + +// Print what is left. +trie.Visit(printItem) +// "Karel Hynek Macha": 10 +``` + +## License ## + +MIT, check the `LICENSE` file. + +[![Gittip +Badge](http://img.shields.io/gittip/alanhamlett.png)](https://www.gittip.com/tchap/ +"Gittip Badge") + +[![Bitdeli +Badge](https://d2weczhvl823v0.cloudfront.net/tchap/go-patricia/trend.png)](https://bitdeli.com/free +"Bitdeli Badge") diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/children.go b/vendor/src/github.com/tchap/go-patricia/patricia/children.go new file mode 100644 index 000000000..42b0547de --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/patricia/children.go @@ -0,0 +1,231 @@ +// Copyright (c) 2014 The go-patricia AUTHORS +// +// Use of this source code is governed by The MIT License +// that can be found in the LICENSE file. + +package patricia + +const ( + // Max prefix length that is kept in a single trie node. + MaxPrefixPerNode = 10 + // Max children to keep in a node in the sparse mode. + MaxChildrenPerSparseNode = 8 +) + +type childList interface { + length() int + head() *Trie + add(child *Trie) childList + replace(b byte, child *Trie) + remove(child *Trie) + next(b byte) *Trie + walk(prefix *Prefix, visitor VisitorFunc) error +} + +type sparseChildList struct { + children []*Trie +} + +func newSparseChildList() childList { + return &sparseChildList{ + children: make([]*Trie, 0, MaxChildrenPerSparseNode), + } +} + +func (list *sparseChildList) length() int { + return len(list.children) +} + +func (list *sparseChildList) head() *Trie { + return list.children[0] +} + +func (list *sparseChildList) add(child *Trie) childList { + // Search for an empty spot and insert the child if possible. + if len(list.children) != cap(list.children) { + list.children = append(list.children, child) + return list + } + + // Otherwise we have to transform to the dense list type. + return newDenseChildList(list, child) +} + +func (list *sparseChildList) replace(b byte, child *Trie) { + // Seek the child and replace it. + for i, node := range list.children { + if node.prefix[0] == b { + list.children[i] = child + return + } + } +} + +func (list *sparseChildList) remove(child *Trie) { + for i, node := range list.children { + if node.prefix[0] == child.prefix[0] { + list.children = append(list.children[:i], list.children[i+1:]...) + return + } + } + + // This is not supposed to be reached. + panic("removing non-existent child") +} + +func (list *sparseChildList) next(b byte) *Trie { + for _, child := range list.children { + if child.prefix[0] == b { + return child + } + } + return nil +} + +func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error { + for _, child := range list.children { + *prefix = append(*prefix, child.prefix...) + if child.item != nil { + err := visitor(*prefix, child.item) + if err != nil { + if err == SkipSubtree { + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + continue + } + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + return err + } + } + + err := child.children.walk(prefix, visitor) + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + if err != nil { + return err + } + } + + return nil +} + +type denseChildList struct { + min int + max int + children []*Trie +} + +func newDenseChildList(list *sparseChildList, child *Trie) childList { + var ( + min int = 255 + max int = 0 + ) + for _, child := range list.children { + b := int(child.prefix[0]) + if b < min { + min = b + } + if b > max { + max = b + } + } + + b := int(child.prefix[0]) + if b < min { + min = b + } + if b > max { + max = b + } + + children := make([]*Trie, max-min+1) + for _, child := range list.children { + children[int(child.prefix[0])-min] = child + } + children[int(child.prefix[0])-min] = child + + return &denseChildList{min, max, children} +} + +func (list *denseChildList) length() int { + return list.max - list.min + 1 +} + +func (list *denseChildList) head() *Trie { + return list.children[0] +} + +func (list *denseChildList) add(child *Trie) childList { + b := int(child.prefix[0]) + + switch { + case list.min <= b && b <= list.max: + if list.children[b-list.min] != nil { + panic("dense child list collision detected") + } + list.children[b-list.min] = child + + case b < list.min: + children := make([]*Trie, list.max-b+1) + children[0] = child + copy(children[list.min-b:], list.children) + list.children = children + list.min = b + + default: // b > list.max + children := make([]*Trie, b-list.min+1) + children[b-list.min] = child + copy(children, list.children) + list.children = children + list.max = b + } + + return list +} + +func (list *denseChildList) replace(b byte, child *Trie) { + list.children[int(b)-list.min] = nil + list.children[int(child.prefix[0])-list.min] = child +} + +func (list *denseChildList) remove(child *Trie) { + i := int(child.prefix[0]) - list.min + if list.children[i] == nil { + // This is not supposed to be reached. + panic("removing non-existent child") + } + list.children[i] = nil +} + +func (list *denseChildList) next(b byte) *Trie { + i := int(b) + if i < list.min || list.max < i { + return nil + } + return list.children[i-list.min] +} + +func (list *denseChildList) walk(prefix *Prefix, visitor VisitorFunc) error { + for _, child := range list.children { + if child == nil { + continue + } + *prefix = append(*prefix, child.prefix...) + if child.item != nil { + if err := visitor(*prefix, child.item); err != nil { + if err == SkipSubtree { + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + continue + } + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + return err + } + } + + err := child.children.walk(prefix, visitor) + *prefix = (*prefix)[:len(*prefix)-len(child.prefix)] + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go new file mode 100644 index 000000000..8fcbcdf42 --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia.go @@ -0,0 +1,432 @@ +// Copyright (c) 2014 The go-patricia AUTHORS +// +// Use of this source code is governed by The MIT License +// that can be found in the LICENSE file. + +package patricia + +import ( + "errors" +) + +//------------------------------------------------------------------------------ +// Trie +//------------------------------------------------------------------------------ + +type ( + Prefix []byte + Item interface{} + VisitorFunc func(prefix Prefix, item Item) error +) + +// Trie is a generic patricia trie that allows fast retrieval of items by prefix. +// and other funky stuff. +// +// Trie is not thread-safe. +type Trie struct { + prefix Prefix + item Item + + children childList +} + +// Public API ------------------------------------------------------------------ + +// Trie constructor. +func NewTrie() *Trie { + return &Trie{ + children: newSparseChildList(), + } +} + +// Item returns the item stored in the root of this trie. +func (trie *Trie) Item() Item { + return trie.item +} + +// Insert inserts a new item into the trie using the given prefix. Insert does +// not replace existing items. It returns false if an item was already in place. +func (trie *Trie) Insert(key Prefix, item Item) (inserted bool) { + return trie.put(key, item, false) +} + +// Set works much like Insert, but it always sets the item, possibly replacing +// the item previously inserted. +func (trie *Trie) Set(key Prefix, item Item) { + trie.put(key, item, true) +} + +// Get returns the item located at key. +// +// This method is a bit dangerous, because Get can as well end up in an internal +// node that is not really representing any user-defined value. So when nil is +// a valid value being used, it is not possible to tell if the value was inserted +// into the tree by the user or not. A possible workaround for this is not to use +// nil interface as a valid value, even using zero value of any type is enough +// to prevent this bad behaviour. +func (trie *Trie) Get(key Prefix) (item Item) { + _, node, found, leftover := trie.findSubtree(key) + if !found || len(leftover) != 0 { + return nil + } + return node.item +} + +// Match returns what Get(prefix) != nil would return. The same warning as for +// Get applies here as well. +func (trie *Trie) Match(prefix Prefix) (matchedExactly bool) { + return trie.Get(prefix) != nil +} + +// MatchSubtree returns true when there is a subtree representing extensions +// to key, that is if there are any keys in the tree which have key as prefix. +func (trie *Trie) MatchSubtree(key Prefix) (matched bool) { + _, _, matched, _ = trie.findSubtree(key) + return +} + +// Visit calls visitor on every node containing a non-nil item. +// +// If an error is returned from visitor, the function stops visiting the tree +// and returns that error, unless it is a special error - SkipSubtree. In that +// case Visit skips the subtree represented by the current node and continues +// elsewhere. +func (trie *Trie) Visit(visitor VisitorFunc) error { + return trie.walk(nil, visitor) +} + +// VisitSubtree works much like Visit, but it only visits nodes matching prefix. +func (trie *Trie) VisitSubtree(prefix Prefix, visitor VisitorFunc) error { + // Nil prefix not allowed. + if prefix == nil { + panic(ErrNilPrefix) + } + + // Empty trie must be handled explicitly. + if trie.prefix == nil { + return nil + } + + // Locate the relevant subtree. + _, root, found, leftover := trie.findSubtree(prefix) + if !found { + return nil + } + prefix = append(prefix, leftover...) + + // Visit it. + return root.walk(prefix, visitor) +} + +// VisitPrefixes visits only nodes that represent prefixes of key. +// To say the obvious, returning SkipSubtree from visitor makes no sense here. +func (trie *Trie) VisitPrefixes(key Prefix, visitor VisitorFunc) error { + // Nil key not allowed. + if key == nil { + panic(ErrNilPrefix) + } + + // Empty trie must be handled explicitly. + if trie.prefix == nil { + return nil + } + + // Walk the path matching key prefixes. + node := trie + prefix := key + offset := 0 + for { + // Compute what part of prefix matches. + common := node.longestCommonPrefixLength(key) + key = key[common:] + offset += common + + // Partial match means that there is no subtree matching prefix. + if common < len(node.prefix) { + return nil + } + + // Call the visitor. + if item := node.item; item != nil { + if err := visitor(prefix[:offset], item); err != nil { + return err + } + } + + if len(key) == 0 { + // This node represents key, we are finished. + return nil + } + + // There is some key suffix left, move to the children. + child := node.children.next(key[0]) + if child == nil { + // There is nowhere to continue, return. + return nil + } + + node = child + } +} + +// Delete deletes the item represented by the given prefix. +// +// True is returned if the matching node was found and deleted. +func (trie *Trie) Delete(key Prefix) (deleted bool) { + // Nil prefix not allowed. + if key == nil { + panic(ErrNilPrefix) + } + + // Empty trie must be handled explicitly. + if trie.prefix == nil { + return false + } + + // Find the relevant node. + parent, node, _, leftover := trie.findSubtree(key) + if len(leftover) != 0 { + return false + } + + // If the item is already set to nil, there is nothing to do. + if node.item == nil { + return false + } + + // Delete the item. + node.item = nil + + // Compact since that might be possible now. + if compacted := node.compact(); compacted != node { + if parent == nil { + *node = *compacted + } else { + parent.children.replace(node.prefix[0], compacted) + *parent = *parent.compact() + } + } + + return true +} + +// DeleteSubtree finds the subtree exactly matching prefix and deletes it. +// +// True is returned if the subtree was found and deleted. +func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) { + // Nil prefix not allowed. + if prefix == nil { + panic(ErrNilPrefix) + } + + // Empty trie must be handled explicitly. + if trie.prefix == nil { + return false + } + + // Locate the relevant subtree. + parent, root, found, _ := trie.findSubtree(prefix) + if !found { + return false + } + + // If we are in the root of the trie, reset the trie. + if parent == nil { + root.prefix = nil + root.children = newSparseChildList() + return true + } + + // Otherwise remove the root node from its parent. + parent.children.remove(root) + return true +} + +// Internal helper methods ----------------------------------------------------- + +func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) { + // Nil prefix not allowed. + if key == nil { + panic(ErrNilPrefix) + } + + var ( + common int + node *Trie = trie + child *Trie + ) + + if node.prefix == nil { + if len(key) <= MaxPrefixPerNode { + node.prefix = key + goto InsertItem + } + node.prefix = key[:MaxPrefixPerNode] + key = key[MaxPrefixPerNode:] + goto AppendChild + } + + for { + // Compute the longest common prefix length. + common = node.longestCommonPrefixLength(key) + key = key[common:] + + // Only a part matches, split. + if common < len(node.prefix) { + goto SplitPrefix + } + + // common == len(node.prefix) since never (common > len(node.prefix)) + // common == len(former key) <-> 0 == len(key) + // -> former key == node.prefix + if len(key) == 0 { + goto InsertItem + } + + // Check children for matching prefix. + child = node.children.next(key[0]) + if child == nil { + goto AppendChild + } + node = child + } + +SplitPrefix: + // Split the prefix if necessary. + child = new(Trie) + *child = *node + *node = *NewTrie() + node.prefix = child.prefix[:common] + child.prefix = child.prefix[common:] + child = child.compact() + node.children = node.children.add(child) + +AppendChild: + // Keep appending children until whole prefix is inserted. + // This loop starts with empty node.prefix that needs to be filled. + for len(key) != 0 { + child := NewTrie() + if len(key) <= MaxPrefixPerNode { + child.prefix = key + node.children = node.children.add(child) + node = child + goto InsertItem + } else { + child.prefix = key[:MaxPrefixPerNode] + key = key[MaxPrefixPerNode:] + node.children = node.children.add(child) + node = child + } + } + +InsertItem: + // Try to insert the item if possible. + if replace || node.item == nil { + node.item = item + return true + } + return false +} + +func (trie *Trie) compact() *Trie { + // Only a node with a single child can be compacted. + if trie.children.length() != 1 { + return trie + } + + child := trie.children.head() + + // If any item is set, we cannot compact since we want to retain + // the ability to do searching by key. This makes compaction less usable, + // but that simply cannot be avoided. + if trie.item != nil || child.item != nil { + return trie + } + + // Make sure the combined prefixes fit into a single node. + if len(trie.prefix)+len(child.prefix) > MaxPrefixPerNode { + return trie + } + + // Concatenate the prefixes, move the items. + child.prefix = append(trie.prefix, child.prefix...) + if trie.item != nil { + child.item = trie.item + } + + return child +} + +func (trie *Trie) findSubtree(prefix Prefix) (parent *Trie, root *Trie, found bool, leftover Prefix) { + // Find the subtree matching prefix. + root = trie + for { + // Compute what part of prefix matches. + common := root.longestCommonPrefixLength(prefix) + prefix = prefix[common:] + + // We used up the whole prefix, subtree found. + if len(prefix) == 0 { + found = true + leftover = root.prefix[common:] + return + } + + // Partial match means that there is no subtree matching prefix. + if common < len(root.prefix) { + leftover = root.prefix[common:] + return + } + + // There is some prefix left, move to the children. + child := root.children.next(prefix[0]) + if child == nil { + // There is nowhere to continue, there is no subtree matching prefix. + return + } + + parent = root + root = child + } +} + +func (trie *Trie) walk(actualRootPrefix Prefix, visitor VisitorFunc) error { + var prefix Prefix + // Allocate a bit more space for prefix at the beginning. + if actualRootPrefix == nil { + prefix = make(Prefix, 32+len(trie.prefix)) + copy(prefix, trie.prefix) + prefix = prefix[:len(trie.prefix)] + } else { + prefix = make(Prefix, 32+len(actualRootPrefix)) + copy(prefix, actualRootPrefix) + prefix = prefix[:len(actualRootPrefix)] + } + + // Visit the root first. Not that this works for empty trie as well since + // in that case item == nil && len(children) == 0. + if trie.item != nil { + if err := visitor(prefix, trie.item); err != nil { + if err == SkipSubtree { + return nil + } + return err + } + } + + // Then continue to the children. + return trie.children.walk(&prefix, visitor) +} + +func (trie *Trie) longestCommonPrefixLength(prefix Prefix) (i int) { + for ; i < len(prefix) && i < len(trie.prefix) && prefix[i] == trie.prefix[i]; i++ { + } + return +} + +// Errors ---------------------------------------------------------------------- + +var ( + SkipSubtree = errors.New("Skip this subtree") + ErrNilPrefix = errors.New("Nil prefix passed into a method call") +) diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go new file mode 100644 index 000000000..346e9a66c --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_dense_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2014 The go-patricia AUTHORS +// +// Use of this source code is governed by The MIT License +// that can be found in the LICENSE file. + +package patricia + +import ( + "testing" +) + +// Tests ----------------------------------------------------------------------- + +func TestTrie_InsertDense(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"aba", 0, success}, + {"abb", 1, success}, + {"abc", 2, success}, + {"abd", 3, success}, + {"abe", 4, success}, + {"abf", 5, success}, + {"abg", 6, success}, + {"abh", 7, success}, + {"abi", 8, success}, + {"abj", 9, success}, + {"abk", 0, success}, + {"abl", 1, success}, + {"abm", 2, success}, + {"abn", 3, success}, + {"abo", 4, success}, + {"abp", 5, success}, + {"abq", 6, success}, + {"abr", 7, success}, + {"abs", 8, success}, + {"abt", 9, success}, + {"abu", 0, success}, + {"abv", 1, success}, + {"abw", 2, success}, + {"abx", 3, success}, + {"aby", 4, success}, + {"abz", 5, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestTrie_InsertDensePreceeding(t *testing.T) { + trie := NewTrie() + start := byte(70) + // create a dense node + for i := byte(0); i <= MaxChildrenPerSparseNode; i++ { + if !trie.Insert(Prefix([]byte{start + i}), true) { + t.Errorf("insert failed, prefix=%v", start+i) + } + } + // insert some preceeding keys + for i := byte(1); i < start; i *= i + 1 { + if !trie.Insert(Prefix([]byte{start - i}), true) { + t.Errorf("insert failed, prefix=%v", start-i) + } + } +} + +func TestTrie_InsertDenseDuplicatePrefixes(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"aba", 0, success}, + {"abb", 1, success}, + {"abc", 2, success}, + {"abd", 3, success}, + {"abe", 4, success}, + {"abf", 5, success}, + {"abg", 6, success}, + {"abh", 7, success}, + {"abi", 8, success}, + {"abj", 9, success}, + {"abk", 0, success}, + {"abl", 1, success}, + {"abm", 2, success}, + {"abn", 3, success}, + {"abo", 4, success}, + {"abp", 5, success}, + {"abq", 6, success}, + {"abr", 7, success}, + {"abs", 8, success}, + {"abt", 9, success}, + {"abu", 0, success}, + {"abv", 1, success}, + {"abw", 2, success}, + {"abx", 3, success}, + {"aby", 4, success}, + {"abz", 5, success}, + {"aba", 0, failure}, + {"abb", 1, failure}, + {"abc", 2, failure}, + {"abd", 3, failure}, + {"abe", 4, failure}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestTrie_DeleteDense(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"aba", 0, success}, + {"abb", 1, success}, + {"abc", 2, success}, + {"abd", 3, success}, + {"abe", 4, success}, + {"abf", 5, success}, + {"abg", 6, success}, + {"abh", 7, success}, + {"abi", 8, success}, + {"abj", 9, success}, + {"abk", 0, success}, + {"abl", 1, success}, + {"abm", 2, success}, + {"abn", 3, success}, + {"abo", 4, success}, + {"abp", 5, success}, + {"abq", 6, success}, + {"abr", 7, success}, + {"abs", 8, success}, + {"abt", 9, success}, + {"abu", 0, success}, + {"abv", 1, success}, + {"abw", 2, success}, + {"abx", 3, success}, + {"aby", 4, success}, + {"abz", 5, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range data { + t.Logf("DELETE word=%v, success=%v", v.key, v.retVal) + if ok := trie.Delete([]byte(v.key)); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go new file mode 100644 index 000000000..27f3c878b --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_sparse_test.go @@ -0,0 +1,659 @@ +// Copyright (c) 2014 The go-patricia AUTHORS +// +// Use of this source code is governed by The MIT License +// that can be found in the LICENSE file. + +package patricia + +import ( + "bytes" + "errors" + "fmt" + "strings" + "testing" +) + +const ( + success = true + failure = false +) + +type testData struct { + key string + value interface{} + retVal bool +} + +// Tests ----------------------------------------------------------------------- + +func TestTrie_InsertDifferentPrefixes(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepaneeeeeeeeeeeeee", "Pepan Zdepan", success}, + {"Honzooooooooooooooo", "Honza Novak", success}, + {"Jenikuuuuuuuuuuuuuu", "Jenik Poustevnicek", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestTrie_InsertDuplicatePrefixes(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Pepan", "Pepan Zdepan", failure}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestTrie_InsertVariousPrefixes(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Pepin", "Pepin Omacka", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + {"Pepan", "Pepan Dupan", failure}, + {"Karel", "Karel Pekar", success}, + {"Jenik", "Jenik Poustevnicek", failure}, + {"Pepanek", "Pepanek Zemlicka", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestTrie_InsertAndMatchPrefix(t *testing.T) { + trie := NewTrie() + t.Log("INSERT prefix=by week") + trie.Insert(Prefix("by week"), 2) + t.Log("INSERT prefix=by") + trie.Insert(Prefix("by"), 1) + + if !trie.Match(Prefix("by")) { + t.Error("MATCH prefix=by, expected=true, got=false") + } +} + +func TestTrie_SetGet(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Pepin", "Pepin Omacka", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + {"Pepan", "Pepan Dupan", failure}, + {"Karel", "Karel Pekar", success}, + {"Jenik", "Jenik Poustevnicek", failure}, + {"Pepanek", "Pepanek Zemlicka", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range data { + t.Logf("SET %q to 10", v.key) + trie.Set(Prefix(v.key), 10) + } + + for _, v := range data { + value := trie.Get(Prefix(v.key)) + t.Logf("GET %q => %v", v.key, value) + if value.(int) != 10 { + t.Errorf("Unexpected return value, != 10", value) + } + } + + if value := trie.Get(Prefix("random crap")); value != nil { + t.Errorf("Unexpected return value, %v != ", value) + } +} + +func TestTrie_Match(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Pepin", "Pepin Omacka", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + {"Pepan", "Pepan Dupan", failure}, + {"Karel", "Karel Pekar", success}, + {"Jenik", "Jenik Poustevnicek", failure}, + {"Pepanek", "Pepanek Zemlicka", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range data { + matched := trie.Match(Prefix(v.key)) + t.Logf("MATCH %q => %v", v.key, matched) + if !matched { + t.Errorf("Inserted key %q was not matched", v.key) + } + } + + if trie.Match(Prefix("random crap")) { + t.Errorf("Key that was not inserted matched: %q", "random crap") + } +} + +func TestTrie_MatchFalsePositive(t *testing.T) { + trie := NewTrie() + + if ok := trie.Insert(Prefix("A"), 1); !ok { + t.Fatal("INSERT prefix=A, item=1 not ok") + } + + resultMatchSubtree := trie.MatchSubtree(Prefix("A extra")) + resultMatch := trie.Match(Prefix("A extra")) + + if resultMatchSubtree != false { + t.Error("MatchSubtree returned false positive") + } + + if resultMatch != false { + t.Error("Match returned false positive") + } +} + +func TestTrie_MatchSubtree(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Pepin", "Pepin Omacka", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + {"Pepan", "Pepan Dupan", failure}, + {"Karel", "Karel Pekar", success}, + {"Jenik", "Jenik Poustevnicek", failure}, + {"Pepanek", "Pepanek Zemlicka", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range data { + key := Prefix(v.key[:3]) + matched := trie.MatchSubtree(key) + t.Logf("MATCH_SUBTREE %q => %v", key, matched) + if !matched { + t.Errorf("Subtree %q was not matched", v.key) + } + } +} + +func TestTrie_Visit(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepa", 0, success}, + {"Pepa Zdepa", 1, success}, + {"Pepa Kuchar", 2, success}, + {"Honza", 3, success}, + {"Jenik", 4, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + if err := trie.Visit(func(prefix Prefix, item Item) error { + name := data[item.(int)].key + t.Logf("VISITING prefix=%q, item=%v", prefix, item) + if !strings.HasPrefix(string(prefix), name) { + t.Errorf("Unexpected prefix encountered, %q not a prefix of %q", prefix, name) + } + return nil + }); err != nil { + t.Fatal(err) + } +} + +func TestTrie_VisitSkipSubtree(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepa", 0, success}, + {"Pepa Zdepa", 1, success}, + {"Pepa Kuchar", 2, success}, + {"Honza", 3, success}, + {"Jenik", 4, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + if err := trie.Visit(func(prefix Prefix, item Item) error { + t.Logf("VISITING prefix=%q, item=%v", prefix, item) + if item.(int) == 0 { + t.Logf("SKIP %q", prefix) + return SkipSubtree + } + if strings.HasPrefix(string(prefix), "Pepa") { + t.Errorf("Unexpected prefix encountered, %q", prefix) + } + return nil + }); err != nil { + t.Fatal(err) + } +} + +func TestTrie_VisitReturnError(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepa", 0, success}, + {"Pepa Zdepa", 1, success}, + {"Pepa Kuchar", 2, success}, + {"Honza", 3, success}, + {"Jenik", 4, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + someErr := errors.New("Something exploded") + if err := trie.Visit(func(prefix Prefix, item Item) error { + t.Logf("VISITING prefix=%q, item=%v", prefix, item) + if item.(int) == 0 { + return someErr + } + if item.(int) != 0 { + t.Errorf("Unexpected prefix encountered, %q", prefix) + } + return nil + }); err != nil && err != someErr { + t.Fatal(err) + } +} + +func TestTrie_VisitSubtree(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepa", 0, success}, + {"Pepa Zdepa", 1, success}, + {"Pepa Kuchar", 2, success}, + {"Honza", 3, success}, + {"Jenik", 4, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + var counter int + subtreePrefix := []byte("Pep") + t.Log("VISIT Pep") + if err := trie.VisitSubtree(subtreePrefix, func(prefix Prefix, item Item) error { + t.Logf("VISITING prefix=%q, item=%v", prefix, item) + if !bytes.HasPrefix(prefix, subtreePrefix) { + t.Errorf("Unexpected prefix encountered, %q does not extend %q", + prefix, subtreePrefix) + } + if len(prefix) > len(data[item.(int)].key) { + t.Fatalf("Something is rather fishy here, prefix=%q", prefix) + } + counter++ + return nil + }); err != nil { + t.Fatal(err) + } + + if counter != 3 { + t.Error("Unexpected number of nodes visited") + } +} + +func TestTrie_VisitPrefixes(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"P", 0, success}, + {"Pe", 1, success}, + {"Pep", 2, success}, + {"Pepa", 3, success}, + {"Pepa Zdepa", 4, success}, + {"Pepa Kuchar", 5, success}, + {"Honza", 6, success}, + {"Jenik", 7, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + var counter int + word := []byte("Pepa") + if err := trie.VisitPrefixes(word, func(prefix Prefix, item Item) error { + t.Logf("VISITING prefix=%q, item=%v", prefix, item) + if !bytes.HasPrefix(word, prefix) { + t.Errorf("Unexpected prefix encountered, %q is not a prefix of %q", + prefix, word) + } + counter++ + return nil + }); err != nil { + t.Fatal(err) + } + + if counter != 4 { + t.Error("Unexpected number of nodes visited") + } +} + +func TestParticiaTrie_Delete(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range data { + t.Logf("DELETE word=%v, success=%v", v.key, v.retVal) + if ok := trie.Delete([]byte(v.key)); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestParticiaTrie_DeleteNonExistent(t *testing.T) { + trie := NewTrie() + + insertData := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Honza", "Honza Novak", success}, + {"Jenik", "Jenik Poustevnicek", success}, + } + deleteData := []testData{ + {"Pepan", "Pepan Zdepan", success}, + {"Honza", "Honza Novak", success}, + {"Pepan", "Pepan Zdepan", failure}, + {"Jenik", "Jenik Poustevnicek", success}, + {"Honza", "Honza Novak", failure}, + } + + for _, v := range insertData { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range deleteData { + t.Logf("DELETE word=%v, success=%v", v.key, v.retVal) + if ok := trie.Delete([]byte(v.key)); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +func TestParticiaTrie_DeleteSubtree(t *testing.T) { + trie := NewTrie() + + insertData := []testData{ + {"P", 0, success}, + {"Pe", 1, success}, + {"Pep", 2, success}, + {"Pepa", 3, success}, + {"Pepa Zdepa", 4, success}, + {"Pepa Kuchar", 5, success}, + {"Honza", 6, success}, + {"Jenik", 7, success}, + } + deleteData := []testData{ + {"Pe", -1, success}, + {"Pe", -1, failure}, + {"Honzik", -1, failure}, + {"Honza", -1, success}, + {"Honza", -1, failure}, + {"Pep", -1, failure}, + {"P", -1, success}, + {"Nobody", -1, failure}, + {"", -1, success}, + } + + for _, v := range insertData { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + for _, v := range deleteData { + t.Logf("DELETE_SUBTREE prefix=%v, success=%v", v.key, v.retVal) + if ok := trie.DeleteSubtree([]byte(v.key)); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } +} + +/* +func TestTrie_Dump(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"Honda", nil, success}, + {"Honza", nil, success}, + {"Jenik", nil, success}, + {"Pepan", nil, success}, + {"Pepin", nil, success}, + } + + for i, v := range data { + if _, ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal { + t.Logf("INSERT %v %v", v.key, v.value) + t.Fatalf("Unexpected return value, expected=%v, got=%v", i, ok) + } + } + + dump := ` ++--+--+ Hon +--+--+ da + | | + | +--+ za + | + +--+ Jenik + | + +--+ Pep +--+--+ an + | + +--+ in +` + + var buf bytes.Buffer + trie.Dump(buf) + + if !bytes.Equal(buf.Bytes(), dump) { + t.Logf("DUMP") + t.Fatalf("Unexpected dump generated, expected\n\n%v\ngot\n\n%v", dump, buf.String()) + } +} +*/ + +func TestTrie_compact(t *testing.T) { + trie := NewTrie() + + trie.Insert(Prefix("a"), 0) + trie.Insert(Prefix("ab"), 0) + trie.Insert(Prefix("abc"), 0) + trie.Insert(Prefix("abcd"), 0) + trie.Insert(Prefix("abcde"), 0) + trie.Insert(Prefix("abcdef"), 0) + trie.Insert(Prefix("abcdefg"), 0) + trie.Insert(Prefix("abcdefgi"), 0) + trie.Insert(Prefix("abcdefgij"), 0) + trie.Insert(Prefix("abcdefgijk"), 0) + + trie.Delete(Prefix("abcdef")) + trie.Delete(Prefix("abcde")) + trie.Delete(Prefix("abcdefg")) + + trie.Delete(Prefix("a")) + trie.Delete(Prefix("abc")) + trie.Delete(Prefix("ab")) + + trie.Visit(func(prefix Prefix, item Item) error { + // 97 ~~ 'a', + for ch := byte(97); ch <= 107; ch++ { + if c := bytes.Count(prefix, []byte{ch}); c > 1 { + t.Errorf("%q appeared in %q %v times", ch, prefix, c) + } + } + return nil + }) +} + +func TestTrie_longestCommonPrefixLenght(t *testing.T) { + trie := NewTrie() + trie.prefix = []byte("1234567890") + + switch { + case trie.longestCommonPrefixLength([]byte("")) != 0: + t.Fail() + case trie.longestCommonPrefixLength([]byte("12345")) != 5: + t.Fail() + case trie.longestCommonPrefixLength([]byte("123789")) != 3: + t.Fail() + case trie.longestCommonPrefixLength([]byte("12345678901")) != 10: + t.Fail() + } +} + +// Examples -------------------------------------------------------------------- + +func ExampleTrie() { + // Create a new tree. + trie := NewTrie() + + // Insert some items. + trie.Insert(Prefix("Pepa Novak"), 1) + trie.Insert(Prefix("Pepa Sindelar"), 2) + trie.Insert(Prefix("Karel Macha"), 3) + trie.Insert(Prefix("Karel Hynek Macha"), 4) + + // Just check if some things are present in the tree. + key := Prefix("Pepa Novak") + fmt.Printf("%q present? %v\n", key, trie.Match(key)) + key = Prefix("Karel") + fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key)) + + // Walk the tree. + trie.Visit(printItem) + // "Pepa Novak": 1 + // "Pepa Sindelar": 2 + // "Karel Macha": 3 + // "Karel Hynek Macha": 4 + + // Walk a subtree. + trie.VisitSubtree(Prefix("Pepa"), printItem) + // "Pepa Novak": 1 + // "Pepa Sindelar": 2 + + // Modify an item, then fetch it from the tree. + trie.Set(Prefix("Karel Hynek Macha"), 10) + key = Prefix("Karel Hynek Macha") + fmt.Printf("%q: %v\n", key, trie.Get(key)) + // "Karel Hynek Macha": 10 + + // Walk prefixes. + prefix := Prefix("Karel Hynek Macha je kouzelnik") + trie.VisitPrefixes(prefix, printItem) + // "Karel Hynek Macha": 10 + + // Delete some items. + trie.Delete(Prefix("Pepa Novak")) + trie.Delete(Prefix("Karel Macha")) + + // Walk again. + trie.Visit(printItem) + // "Pepa Sindelar": 2 + // "Karel Hynek Macha": 10 + + // Delete a subtree. + trie.DeleteSubtree(Prefix("Pepa")) + + // Print what is left. + trie.Visit(printItem) + // "Karel Hynek Macha": 10 + + // Output: + // "Pepa Novak" present? true + // Anybody called "Karel" here? true + // "Pepa Novak": 1 + // "Pepa Sindelar": 2 + // "Karel Macha": 3 + // "Karel Hynek Macha": 4 + // "Pepa Novak": 1 + // "Pepa Sindelar": 2 + // "Karel Hynek Macha": 10 + // "Karel Hynek Macha": 10 + // "Pepa Sindelar": 2 + // "Karel Hynek Macha": 10 + // "Karel Hynek Macha": 10 +} + +// Helpers --------------------------------------------------------------------- + +func printItem(prefix Prefix, item Item) error { + fmt.Printf("%q: %v\n", prefix, item) + return nil +} diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go new file mode 100644 index 000000000..ce5ae378f --- /dev/null +++ b/vendor/src/github.com/tchap/go-patricia/patricia/patricia_test.go @@ -0,0 +1,78 @@ +// Copyright (c) 2014 The go-patricia AUTHORS +// +// Use of this source code is governed by The MIT License +// that can be found in the LICENSE file. + +package patricia + +import ( + "crypto/rand" + "reflect" + "testing" +) + +// Tests ----------------------------------------------------------------------- + +func TestTrie_GetNonexistentPrefix(t *testing.T) { + trie := NewTrie() + + data := []testData{ + {"aba", 0, success}, + } + + for _, v := range data { + t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal) + if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal { + t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok) + } + } + + t.Logf("GET prefix=baa, expect item=nil") + if item := trie.Get(Prefix("baa")); item != nil { + t.Errorf("Unexpected return value, expected=, got=%v", item) + } +} + +func TestTrie_RandomKitchenSink(t *testing.T) { + if testing.Short() { + t.Skip() + } + const count, size = 750000, 16 + b := make([]byte, count+size+1) + if _, err := rand.Read(b); err != nil { + t.Fatal("error generating random bytes", err) + } + m := make(map[string]string) + for i := 0; i < count; i++ { + m[string(b[i:i+size])] = string(b[i+1 : i+size+1]) + } + trie := NewTrie() + getAndDelete := func(k, v string) { + i := trie.Get(Prefix(k)) + if i == nil { + t.Fatalf("item not found, prefix=%v", []byte(k)) + } else if s, ok := i.(string); !ok { + t.Fatalf("unexpected item type, expecting=%v, got=%v", reflect.TypeOf(k), reflect.TypeOf(i)) + } else if s != v { + t.Fatalf("unexpected item, expecting=%v, got=%v", []byte(k), []byte(s)) + } else if !trie.Delete(Prefix(k)) { + t.Fatalf("delete failed, prefix=%v", []byte(k)) + } else if i = trie.Get(Prefix(k)); i != nil { + t.Fatalf("unexpected item, expecting=, got=%v", i) + } else if trie.Delete(Prefix(k)) { + t.Fatalf("extra delete succeeded, prefix=%v", []byte(k)) + } + } + for k, v := range m { + if !trie.Insert(Prefix(k), v) { + t.Fatalf("insert failed, prefix=%v", []byte(k)) + } + if byte(k[size/2]) < 128 { + getAndDelete(k, v) + delete(m, k) + } + } + for k, v := range m { + getAndDelete(k, v) + } +} From 7606412d53b522774b2b7cea93fa2618b784e886 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 26 Jun 2014 09:54:12 -0400 Subject: [PATCH 091/167] Remove integration tests moved to integration-cli(dups) integration/commands_test.go/TestRunHostname == integration-cli/docker_cli_run_tests.go/TestModeHostname integration/commands_test.go/TestRunWorkdir == integration-cli/docker_cli_run_tests.go/TestDockerRunWorkingDirectory integration/commands_test.go/TestRunWorkdirExists == integration-cli/docker_cli_run_tests.go/TestDockerRunWorkingDirectory integration/commands_test.go/TestAttachstdIn == integration-cli/docker_cli_run_tests.go/TestRunStdinPipe integration/commands_test.go/TestCmdLogs == integration-cli/docker_cli_logs_tests.go integration/commands_test.go/TestCmdKill == integration-cli/docker_cli_kill_test.go Docker-DCO-1.1-Signed-off-by: Brian Goff (github: cpuguy83) --- integration/commands_test.go | 292 +---------------------------------- 1 file changed, 2 insertions(+), 290 deletions(-) diff --git a/integration/commands_test.go b/integration/commands_test.go index 4ad225bb4..55c822bbe 100644 --- a/integration/commands_test.go +++ b/integration/commands_test.go @@ -8,9 +8,7 @@ import ( "os" "path" "regexp" - "strconv" "strings" - "syscall" "testing" "time" @@ -118,141 +116,6 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error return nil } -// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname -func TestRunHostname(t *testing.T) { - stdout, stdoutPipe := io.Pipe() - - cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - defer cleanup(globalEngine, t) - - c := make(chan struct{}) - go func() { - defer close(c) - if err := cli.CmdRun("-h", "foobar", unitTestImageID, "hostname"); err != nil { - t.Fatal(err) - } - }() - - setTimeout(t, "Reading command output time out", 2*time.Second, func() { - cmdOutput, err := bufio.NewReader(stdout).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if cmdOutput != "foobar\n" { - t.Fatalf("'hostname' should display '%s', not '%s'", "foobar\n", cmdOutput) - } - }) - - container := globalDaemon.List()[0] - - setTimeout(t, "CmdRun timed out", 10*time.Second, func() { - <-c - - go func() { - cli.CmdWait(container.ID) - }() - - if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil { - t.Fatal(err) - } - }) - - // Cleanup pipes - if err := closeWrap(stdout, stdoutPipe); err != nil { - t.Fatal(err) - } -} - -// TestRunWorkdir checks that 'docker run -w' correctly sets a custom working directory -func TestRunWorkdir(t *testing.T) { - stdout, stdoutPipe := io.Pipe() - - cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - defer cleanup(globalEngine, t) - - c := make(chan struct{}) - go func() { - defer close(c) - if err := cli.CmdRun("-w", "/foo/bar", unitTestImageID, "pwd"); err != nil { - t.Fatal(err) - } - }() - - setTimeout(t, "Reading command output time out", 2*time.Second, func() { - cmdOutput, err := bufio.NewReader(stdout).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if cmdOutput != "/foo/bar\n" { - t.Fatalf("'pwd' should display '%s', not '%s'", "/foo/bar\n", cmdOutput) - } - }) - - container := globalDaemon.List()[0] - - setTimeout(t, "CmdRun timed out", 10*time.Second, func() { - <-c - - go func() { - cli.CmdWait(container.ID) - }() - - if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil { - t.Fatal(err) - } - }) - - // Cleanup pipes - if err := closeWrap(stdout, stdoutPipe); err != nil { - t.Fatal(err) - } -} - -// TestRunWorkdirExists checks that 'docker run -w' correctly sets a custom working directory, even if it exists -func TestRunWorkdirExists(t *testing.T) { - stdout, stdoutPipe := io.Pipe() - - cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - defer cleanup(globalEngine, t) - - c := make(chan struct{}) - go func() { - defer close(c) - if err := cli.CmdRun("-w", "/proc", unitTestImageID, "pwd"); err != nil { - t.Fatal(err) - } - }() - - setTimeout(t, "Reading command output time out", 2*time.Second, func() { - cmdOutput, err := bufio.NewReader(stdout).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if cmdOutput != "/proc\n" { - t.Fatalf("'pwd' should display '%s', not '%s'", "/proc\n", cmdOutput) - } - }) - - container := globalDaemon.List()[0] - - setTimeout(t, "CmdRun timed out", 5*time.Second, func() { - <-c - - go func() { - cli.CmdWait(container.ID) - }() - - if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil { - t.Fatal(err) - } - }) - - // Cleanup pipes - if err := closeWrap(stdout, stdoutPipe); err != nil { - t.Fatal(err) - } -} - // TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected func TestRunWorkdirExistsAndIsFile(t *testing.T) { @@ -419,72 +282,6 @@ func TestRunDisconnectTty(t *testing.T) { } } -// TestAttachStdin checks attaching to stdin without stdout and stderr. -// 'docker run -i -a stdin' should sends the client's stdin to the command, -// then detach from it and print the container id. -func TestRunAttachStdin(t *testing.T) { - - stdin, stdinPipe := io.Pipe() - stdout, stdoutPipe := io.Pipe() - - cli := client.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - defer cleanup(globalEngine, t) - - ch := make(chan struct{}) - go func() { - defer close(ch) - cli.CmdRun("-i", "-a", "stdin", unitTestImageID, "sh", "-c", "echo hello && cat && sleep 5") - }() - - // Send input to the command, close stdin - setTimeout(t, "Write timed out", 10*time.Second, func() { - if _, err := stdinPipe.Write([]byte("hi there\n")); err != nil { - t.Fatal(err) - } - if err := stdinPipe.Close(); err != nil { - t.Fatal(err) - } - }) - - container := globalDaemon.List()[0] - - // Check output - setTimeout(t, "Reading command output time out", 10*time.Second, func() { - cmdOutput, err := bufio.NewReader(stdout).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if cmdOutput != container.ID+"\n" { - t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ID+"\n", cmdOutput) - } - }) - - // wait for CmdRun to return - setTimeout(t, "Waiting for CmdRun timed out", 5*time.Second, func() { - <-ch - }) - - setTimeout(t, "Waiting for command to exit timed out", 10*time.Second, func() { - container.Wait() - }) - - // Check logs - if cmdLogs, err := container.ReadLog("json"); err != nil { - t.Fatal(err) - } else { - if output, err := ioutil.ReadAll(cmdLogs); err != nil { - t.Fatal(err) - } else { - expectedLogs := []string{"{\"log\":\"hello\\n\",\"stream\":\"stdout\"", "{\"log\":\"hi there\\n\",\"stream\":\"stdout\""} - for _, expectedLog := range expectedLogs { - if !strings.Contains(string(output), expectedLog) { - t.Fatalf("Unexpected logs: should contains '%s', it is not '%s'\n", expectedLog, output) - } - } - } - } -} - // TestRunDetach checks attaching and detaching with the escape sequence. func TestRunDetach(t *testing.T) { @@ -787,23 +584,6 @@ func TestRunAutoRemove(t *testing.T) { } } -func TestCmdLogs(t *testing.T) { - t.Skip("Test not impemented") - cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - defer cleanup(globalEngine, t) - - if err := cli.CmdRun(unitTestImageID, "sh", "-c", "ls -l"); err != nil { - t.Fatal(err) - } - if err := cli.CmdRun("-t", unitTestImageID, "sh", "-c", "ls -l"); err != nil { - t.Fatal(err) - } - - if err := cli.CmdLogs(globalDaemon.List()[0].ID); err != nil { - t.Fatal(err) - } -} - // Expected behaviour: error out when attempting to bind mount non-existing source paths func TestRunErrorBindNonExistingSource(t *testing.T) { @@ -825,6 +605,7 @@ func TestRunErrorBindNonExistingSource(t *testing.T) { } func TestImagesViz(t *testing.T) { + t.Skip("Image viz is deprecated") stdout, stdoutPipe := io.Pipe() cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) @@ -875,6 +656,7 @@ func TestImagesViz(t *testing.T) { } func TestImagesTree(t *testing.T) { + t.Skip("Image tree is deprecated") stdout, stdoutPipe := io.Pipe() cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) @@ -1095,73 +877,3 @@ func TestContainerOrphaning(t *testing.T) { } } - -func TestCmdKill(t *testing.T) { - var ( - stdin, stdinPipe = io.Pipe() - stdout, stdoutPipe = io.Pipe() - cli = client.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - cli2 = client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr, nil) - ) - defer cleanup(globalEngine, t) - - ch := make(chan struct{}) - go func() { - defer close(ch) - cli.CmdRun("-i", "-t", unitTestImageID, "sh", "-c", "trap 'echo SIGUSR1' USR1; trap 'echo SIGUSR2' USR2; echo Ready; while true; do read; done") - }() - - container := waitContainerStart(t, 10*time.Second) - - setTimeout(t, "Read Ready timed out", 3*time.Second, func() { - if err := expectPipe("Ready", stdout); err != nil { - t.Fatal(err) - } - }) - - setTimeout(t, "SIGUSR1 timed out", 2*time.Second, func() { - for i := 0; i < 10; i++ { - if err := cli2.CmdKill("-s", strconv.Itoa(int(syscall.SIGUSR1)), container.ID); err != nil { - t.Fatal(err) - } - if err := expectPipe("SIGUSR1", stdout); err != nil { - t.Fatal(err) - } - } - }) - - setTimeout(t, "SIGUSR2 timed out", 2*time.Second, func() { - for i := 0; i < 20; i++ { - sig := "USR2" - if i%2 != 0 { - // Swap to testing "SIGUSR2" for every odd iteration - sig = "SIGUSR2" - } - if err := cli2.CmdKill("--signal="+sig, container.ID); err != nil { - t.Fatal(err) - } - if err := expectPipe("SIGUSR2", stdout); err != nil { - t.Fatal(err) - } - } - }) - - stdout.Close() - time.Sleep(500 * time.Millisecond) - if !container.State.IsRunning() { - t.Fatal("The container should be still running") - } - - setTimeout(t, "Waiting for container timedout", 5*time.Second, func() { - if err := cli2.CmdKill(container.ID); err != nil { - t.Fatal(err) - } - - <-ch - if err := cli2.CmdWait(container.ID); err != nil { - t.Fatal(err) - } - }) - - closeWrap(stdin, stdinPipe, stdout, stdoutPipe) -} From e39b8eade1f42503b6b7217e72eff4c8fdc13cb6 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 26 Jun 2014 10:50:18 -0700 Subject: [PATCH 092/167] Allow / as source of -v We discussed this at the docker plumbers meetup and for tools and working on the system for things like boot2docker and coreos this is needed. You can already bypass this check so we felt it is ok to start allowing this feature. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- integration-cli/docker_cli_run_test.go | 11 +++++++++++ runconfig/parse.go | 4 ++-- server/server.go | 10 +--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 9e5a90bed..a0c390306 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -960,3 +960,14 @@ func TestRootWorkdir(t *testing.T) { logDone("run - workdir /") } + +func TestAllowBindMountingRoot(t *testing.T) { + s, _, err := cmd(t, "run", "-v", "/:/host", "busybox", "ls", "/host") + if err != nil { + t.Fatal(s, err) + } + + deleteAllContainers() + + logDone("run - bind mount / as volume") +} diff --git a/runconfig/parse.go b/runconfig/parse.go index fd3e4a50a..f057f311c 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -132,8 +132,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf // add any bind targets to the list of container volumes for bind := range flVolumes.GetMap() { if arr := strings.Split(bind, ":"); len(arr) > 1 { - if arr[0] == "/" { - return nil, nil, cmd, fmt.Errorf("Invalid bind mount: source can't be '/'") + if arr[1] == "/" { + return nil, nil, cmd, fmt.Errorf("Invalid bind mount: desination can't be '/'") } // after creating the bind mount we want to delete it from the flVolumes values because // we do not want bind mounts being committed to image configs diff --git a/server/server.go b/server/server.go index fa695adfe..76b3a8397 100644 --- a/server/server.go +++ b/server/server.go @@ -2055,19 +2055,11 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status { if len(job.Environ()) > 0 { hostConfig := runconfig.ContainerHostConfigFromJob(job) // Validate the HostConfig binds. Make sure that: - // 1) the source of a bind mount isn't / - // The bind mount "/:/foo" isn't allowed. - // 2) Check that the source exists - // The source to be bind mounted must exist. + // the source exists for _, bind := range hostConfig.Binds { splitBind := strings.Split(bind, ":") source := splitBind[0] - // refuse to bind mount "/" to the container - if source == "/" { - return job.Errorf("Invalid bind mount '%s' : source can't be '/'", bind) - } - // ensure the source exists on the host _, err := os.Stat(source) if err != nil && os.IsNotExist(err) { From fa3ac2d37032583a7c1171c24d71fbf93e330acc Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 25 Jun 2014 12:04:59 -0400 Subject: [PATCH 093/167] Fixed manpage generation script and README Update md2man script to generate manpages inside docs/man/ directory. Update usage documentation in the readme to point to the new docs/man path. Update Ubuntu makefile to use new path to manpages Docker-DCO-1.1-Signed-off-by: Matthew Heon (github: mheon) --- docs/man/README.md | 8 ++++---- docs/man/md2man-all.sh | 4 ++-- hack/make/ubuntu | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/man/README.md b/docs/man/README.md index d49b39b7a..d04d82454 100644 --- a/docs/man/README.md +++ b/docs/man/README.md @@ -51,7 +51,7 @@ saving you from dealing with Pandoc and dependencies on your own computer. ## Building the Fedora / Pandoc image -There is a Dockerfile provided in the `docker/contrib/man/md` directory. +There is a Dockerfile provided in the `docker/docs/man` directory. Using this Dockerfile, create a Docker image tagged `fedora/pandoc`: @@ -61,11 +61,11 @@ Using this Dockerfile, create a Docker image tagged `fedora/pandoc`: Once the image is built, run a container using the image with *volumes*: - docker run -v //docker/contrib/man:/pandoc:rw \ - -w /pandoc -i fedora/pandoc /pandoc/md/md2man-all.sh + docker run -v //docker/docs/man:/pandoc:rw \ + -w /pandoc -i fedora/pandoc /pandoc/md2man-all.sh The Pandoc Docker container will process the Markdown files and generate -the man pages inside the `docker/contrib/man/man1` directory using +the man pages inside the `docker/docs/man/man1` directory using Docker volumes. For more information on Docker volumes see the man page for `docker run` and also look at the article [Sharing Directories via Volumes] (http://docs.docker.io/use/working_with_volumes/). diff --git a/docs/man/md2man-all.sh b/docs/man/md2man-all.sh index def876f47..12d84de23 100755 --- a/docs/man/md2man-all.sh +++ b/docs/man/md2man-all.sh @@ -17,6 +17,6 @@ for FILE in *.md; do # skip files that aren't of the format xxxx.N.md (like README.md) continue fi - mkdir -p "../man${num}" - pandoc -s -t man "$FILE" -o "../man${num}/${name}" + mkdir -p "./man${num}" + pandoc -s -t man "$FILE" -o "./man${num}/${name}" done diff --git a/hack/make/ubuntu b/hack/make/ubuntu index 75202eace..c55123fb7 100644 --- a/hack/make/ubuntu +++ b/hack/make/ubuntu @@ -50,7 +50,7 @@ bundle_ubuntu() { docs/man/md2man-all.sh -q manRoot="$DIR/usr/share/man" mkdir -p "$manRoot" - for manDir in docs/man?; do + for manDir in docs/man/man?; do manBase="$(basename "$manDir")" # "man1" for manFile in "$manDir"/*; do manName="$(basename "$manFile")" # "docker-build.1" From 55691e5fdc78b5c3015c7a481371e482878c14d2 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 25 Jun 2014 22:24:14 +0000 Subject: [PATCH 094/167] add links to inspect for 'linking' containers Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- daemon/inspect.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daemon/inspect.go b/daemon/inspect.go index 6c4b74d6f..b93aec505 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -2,6 +2,7 @@ package daemon import ( "encoding/json" + "fmt" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/runconfig" @@ -46,7 +47,16 @@ func (daemon *Daemon) ContainerInspect(job *engine.Job) engine.Status { out.Set("ProcessLabel", container.ProcessLabel) out.SetJson("Volumes", container.Volumes) out.SetJson("VolumesRW", container.VolumesRW) + + if children, err := daemon.Children(container.Name); err == nil { + for linkAlias, child := range children { + container.hostConfig.Links = append(container.hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias)) + } + } + out.SetJson("HostConfig", container.hostConfig) + + container.hostConfig.Links = nil if _, err := out.WriteTo(job.Stdout); err != nil { return job.Error(err) } From af025f2a95090974eaaf3d8792d5f467d0a637be Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 26 Jun 2014 15:39:45 -0700 Subject: [PATCH 095/167] Remove api test for bind mount / Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- integration/api_test.go | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/integration/api_test.go b/integration/api_test.go index 620d6ecaa..2d1b80368 100644 --- a/integration/api_test.go +++ b/integration/api_test.go @@ -672,42 +672,6 @@ func TestPostContainersStart(t *testing.T) { containerKill(eng, containerID, t) } -// Expected behaviour: using / as a bind mount source should throw an error -func TestRunErrorBindMountRootSource(t *testing.T) { - eng := NewTestEngine(t) - defer mkDaemonFromEngine(eng, t).Nuke() - - containerID := createTestContainer( - eng, - &runconfig.Config{ - Image: unitTestImageID, - Cmd: []string{"/bin/cat"}, - OpenStdin: true, - }, - t, - ) - - hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{ - Binds: []string{"/:/tmp"}, - }) - - req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON)) - if err != nil { - t.Fatal(err) - } - - req.Header.Set("Content-Type", "application/json") - - r := httptest.NewRecorder() - if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil { - t.Fatal(err) - } - if r.Code != http.StatusInternalServerError { - containerKill(eng, containerID, t) - t.Fatal("should have failed to run when using / as a source for the bind mount") - } -} - func TestPostContainersStop(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() From 111ab125b954c8d28503e1922e742eb271cc5d04 Mon Sep 17 00:00:00 2001 From: Travis Cline Date: Thu, 13 Feb 2014 16:05:36 -0800 Subject: [PATCH 096/167] Change misnamed TarFilter to TarWithOptions Docker-DCO-1.1-Signed-off-by: Travis Cline (github: tmc) --- archive/archive.go | 29 ++++++++++---- archive/archive_test.go | 68 ++++++++++++++++++++++++--------- daemon/container.go | 2 +- daemon/graphdriver/aufs/aufs.go | 2 +- 4 files changed, 73 insertions(+), 28 deletions(-) diff --git a/archive/archive.go b/archive/archive.go index 628d425ea..65a5b495e 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -27,6 +27,7 @@ type ( Compression int TarOptions struct { Includes []string + Excludes []string Compression Compression NoLchown bool } @@ -286,7 +287,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L // Tar creates an archive from the directory at `path`, and returns it as a // stream of bytes. func Tar(path string, compression Compression) (io.ReadCloser, error) { - return TarFilter(path, &TarOptions{Compression: compression}) + return TarWithOptions(path, &TarOptions{Compression: compression}) } func escapeName(name string) string { @@ -305,12 +306,9 @@ func escapeName(name string) string { return string(escaped) } -// TarFilter creates an archive from the directory at `srcPath` with `options`, and returns it as a -// stream of bytes. -// -// Files are included according to `options.Includes`, default to including all files. -// Stream is compressed according to `options.Compression', default to Uncompressed. -func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) { +// TarWithOptions creates an archive from the directory at `path`, only including files whose relative +// paths are included in `options.Includes` (if non-nil) or not in `options.Excludes`. +func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) { pipeReader, pipeWriter := io.Pipe() compressWriter, err := CompressStream(pipeWriter, options.Compression) @@ -342,6 +340,21 @@ func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) { return nil } + for _, exclude := range options.Excludes { + matched, err := filepath.Match(exclude, relFilePath) + if err != nil { + utils.Errorf("Error matching: %s (pattern: %s)\n", relFilePath, exclude) + return err + } + if matched { + utils.Debugf("Skipping excluded path: %s\n", relFilePath) + if f.IsDir() { + return filepath.SkipDir + } + return nil + } + } + if err := addTarFile(filePath, relFilePath, tw); err != nil { utils.Debugf("Can't add file %s to tar: %s\n", srcPath, err) } @@ -482,7 +495,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { // TarUntar aborts and returns the error. func TarUntar(src string, dst string) error { utils.Debugf("TarUntar(%s %s)", src, dst) - archive, err := TarFilter(src, &TarOptions{Compression: Uncompressed}) + archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed}) if err != nil { return err } diff --git a/archive/archive_test.go b/archive/archive_test.go index 8c9ed6e55..b9051fe6a 100644 --- a/archive/archive_test.go +++ b/archive/archive_test.go @@ -63,8 +63,8 @@ func TestCmdStreamGood(t *testing.T) { } } -func tarUntar(t *testing.T, origin string, compression Compression) error { - archive, err := Tar(origin, compression) +func tarUntar(t *testing.T, origin string, options *TarOptions) ([]Change, error) { + archive, err := TarWithOptions(origin, options) if err != nil { t.Fatal(err) } @@ -72,37 +72,29 @@ func tarUntar(t *testing.T, origin string, compression Compression) error { buf := make([]byte, 10) if _, err := archive.Read(buf); err != nil { - return err + return nil, err } wrap := io.MultiReader(bytes.NewReader(buf), archive) detectedCompression := DetectCompression(buf) + compression := options.Compression if detectedCompression.Extension() != compression.Extension() { - return fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension()) + return nil, fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension()) } tmp, err := ioutil.TempDir("", "docker-test-untar") if err != nil { - return err + return nil, err } defer os.RemoveAll(tmp) if err := Untar(wrap, tmp, nil); err != nil { - return err + return nil, err } if _, err := os.Stat(tmp); err != nil { - return err + return nil, err } - changes, err := ChangesDirs(origin, tmp) - if err != nil { - return err - } - - if len(changes) != 0 { - t.Fatalf("Unexpected differences after tarUntar: %v", changes) - } - - return nil + return ChangesDirs(origin, tmp) } func TestTarUntar(t *testing.T) { @@ -122,9 +114,49 @@ func TestTarUntar(t *testing.T) { Uncompressed, Gzip, } { - if err := tarUntar(t, origin, c); err != nil { + changes, err := tarUntar(t, origin, &TarOptions{ + Compression: c, + }) + + if err != nil { t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err) } + + if len(changes) != 0 { + t.Fatalf("Unexpected differences after tarUntar: %v", changes) + } + } +} + +func TestTarWithOptions(t *testing.T) { + origin, err := ioutil.TempDir("", "docker-test-untar-origin") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(origin) + if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { + t.Fatal(err) + } + + cases := []struct { + opts *TarOptions + numChanges int + }{ + {&TarOptions{Includes: []string{"1"}}, 1}, + {&TarOptions{Excludes: []string{"2"}}, 1}, + } + for _, testCase := range cases { + changes, err := tarUntar(t, origin, testCase.opts) + if err != nil { + t.Fatalf("Error tar/untar when testing inclusion/exclusion: %s", err) + } + if len(changes) != testCase.numChanges { + t.Errorf("Expected %d changes, got %d for %+v:", + testCase.numChanges, len(changes), testCase.opts) + } } } diff --git a/daemon/container.go b/daemon/container.go index 2fd827eb9..d9c809cee 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -813,7 +813,7 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) { basePath = path.Dir(basePath) } - archive, err := archive.TarFilter(basePath, &archive.TarOptions{ + archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, Includes: filter, }) diff --git a/daemon/graphdriver/aufs/aufs.go b/daemon/graphdriver/aufs/aufs.go index eb8ff77cd..0206b92e1 100644 --- a/daemon/graphdriver/aufs/aufs.go +++ b/daemon/graphdriver/aufs/aufs.go @@ -295,7 +295,7 @@ func (a *Driver) Put(id string) { // Returns an archive of the contents for the id func (a *Driver) Diff(id string) (archive.Archive, error) { - return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ + return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ Compression: archive.Uncompressed, }) } From 9189db3aff3e9d72b215b5e204cfac018b2acc5d Mon Sep 17 00:00:00 2001 From: Travis Cline Date: Sat, 15 Feb 2014 10:38:48 -0800 Subject: [PATCH 097/167] Add .dockerignore support Fixes #2224 Docker-DCO-1.1-Signed-off-by: Travis Cline (github: tmc) --- .dockerignore | 2 + api/client/commands.go | 20 ++++++++- docs/sources/reference/commandline/cli.md | 30 ++++++++++++++ integration-cli/docker_cli_build_test.go | 50 +++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..37abdef44 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +bundles +.gopath diff --git a/api/client/commands.go b/api/client/commands.go index dcd882470..c386e7a09 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -13,6 +13,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "runtime" "strconv" "strings" @@ -163,7 +164,24 @@ func (cli *DockerCli) CmdBuild(args ...string) error { if err = utils.ValidateContextDirectory(root); err != nil { return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err) } - context, err = archive.Tar(root, archive.Uncompressed) + options := &archive.TarOptions{ + Compression: archive.Uncompressed, + } + ignoreFile := path.Join(root, ".dockerignore") + if ignore, err := ioutil.ReadFile(ignoreFile); err == nil { + for _, pattern := range strings.Split(string(ignore), "\n") { + ok, err := filepath.Match(pattern, "Dockerfile") + if err != nil { + utils.Errorf("Bad .dockerignore pattern: '%s', error: %s", pattern, err) + continue + } + if ok { + return fmt.Errorf("Dockerfile was excluded by .dockerignore pattern '%s'", pattern) + } + options.Excludes = append(options.Excludes, pattern) + } + } + context, err = archive.TarWithOptions(root, options) } var body io.Reader // Setup an upload progress bar diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 600a89b68..cb5d39d93 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -215,6 +215,12 @@ temporary directory on your local host, and then this is sent to the Docker daemon as the context. This way, your local user credentials and vpn's etc can be used to access private repositories. +If a file named ``.dockerignore`` exists in the root of ``PATH`` then it is +interpreted as a newline-separated list of exclusion patterns. Exclusion +patterns match files or directories relative to ``PATH`` that will be excluded +from the context. Globbing is done using Go's +[filepath.Match](http://golang.org/pkg/path/filepath#Match) rules. + See also: [*Dockerfile Reference*](/reference/builder/#dockerbuilder). @@ -266,6 +272,30 @@ If you wish to keep the intermediate containers after the build is complete, you must use `--rm=false`. This does not affect the build cache. + $ docker build . + Uploading context 18.829 MB + Uploading context + Step 0 : FROM busybox + ---> 769b9341d937 + Step 1 : CMD echo Hello World + ---> Using cache + ---> 99cc1ad10469 + Successfully built 99cc1ad10469 + $ echo ".git" > .dockerignore + $ docker build . + Uploading context 6.76 MB + Uploading context + Step 0 : FROM busybox + ---> 769b9341d937 + Step 1 : CMD echo Hello World + ---> Using cache + ---> 99cc1ad10469 + Successfully built 99cc1ad10469 + +This example shows the use of the ``.dockerignore`` file to exclude the ``.git`` +directory the context. Its effect can be seen in the changed size of the +uploaded context. + $ sudo docker build -t vieux/apache:2.0 . This will build like the previous example, but it will then tag the diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 6086258d1..2f2f2b6e0 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -1514,3 +1514,53 @@ docker.com>" logDone("build - validate escaping whitespace") } + +func TestDockerignore(t *testing.T) { + name := "testbuilddockerignore" + defer deleteImages(name) + dockerfile := ` + FROM busybox + ADD . /bla + RUN [[ -f /bla/src/x.go ]] + RUN [[ -f /bla/Makefile ]] + RUN [[ ! -e /bla/src/_vendor ]] + RUN [[ ! -e /bla/.gitignore ]] + RUN [[ ! -e /bla/README.md ]] + RUN [[ ! -e /bla/.git ]]` + ctx, err := fakeContext(dockerfile, map[string]string{ + "Makefile": "all:", + ".git/HEAD": "ref: foo", + "src/x.go": "package main", + "src/_vendor/v.go": "package main", + ".gitignore": "", + "README.md": "readme", + ".dockerignore": ".git\npkg\n.gitignore\nsrc/_vendor\n*.md", + }) + defer ctx.Close() + if err != nil { + t.Fatal(err) + } + if _, err := buildImageFromContext(name, ctx, true); err != nil { + t.Fatal(err) + } + logDone("build - test .dockerignore") +} + +func TestDockerignoringDockerfile(t *testing.T) { + name := "testbuilddockerignoredockerfile" + defer deleteImages(name) + dockerfile := ` + FROM scratch` + ctx, err := fakeContext(dockerfile, map[string]string{ + "Dockerfile": "FROM scratch", + ".dockerignore": "Dockerfile\n", + }) + defer ctx.Close() + if err != nil { + t.Fatal(err) + } + if _, err = buildImageFromContext(name, ctx, true); err == nil { + t.Fatalf("Didn't get expected error from ignoring Dockerfile") + } + logDone("build - test .dockerignore of Dockerfile") +} From 42ca8a064b0e315c983997dbdb2560c40397eb0e Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 20 Jun 2014 23:08:27 +0000 Subject: [PATCH 098/167] add @tianon as maintainer of .dockerignore Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 059ff79f0..2947eb355 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6,3 +6,4 @@ Michael Crosby (@crosbymichael) AUTHORS: Tianon Gravi (@tianon) Dockerfile: Tianon Gravi (@tianon) Makefile: Tianon Gravi (@tianon) +.dockerignore: Tianon Gravi (@tianon) From 0098360726e3df99e8f76dce9221a85dd89c2065 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 26 Jun 2014 02:12:18 +0000 Subject: [PATCH 099/167] abort on error and fix debug Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/client/commands.go | 5 +++-- archive/archive.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index c386e7a09..61ef42638 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -167,8 +167,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error { options := &archive.TarOptions{ Compression: archive.Uncompressed, } - ignoreFile := path.Join(root, ".dockerignore") - if ignore, err := ioutil.ReadFile(ignoreFile); err == nil { + if ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore")); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("Error reading .dockerignore: '%s'", err) + } else if err == nil { for _, pattern := range strings.Split(string(ignore), "\n") { ok, err := filepath.Match(pattern, "Dockerfile") if err != nil { diff --git a/archive/archive.go b/archive/archive.go index 65a5b495e..b9701b58a 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -343,11 +343,11 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) for _, exclude := range options.Excludes { matched, err := filepath.Match(exclude, relFilePath) if err != nil { - utils.Errorf("Error matching: %s (pattern: %s)\n", relFilePath, exclude) + utils.Errorf("Error matching: %s (pattern: %s)", relFilePath, exclude) return err } if matched { - utils.Debugf("Skipping excluded path: %s\n", relFilePath) + utils.Debugf("Skipping excluded path: %s", relFilePath) if f.IsDir() { return filepath.SkipDir } From 8162dc031246c55e34530d2b35ff7087f143d1c2 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 26 Jun 2014 22:51:47 +0000 Subject: [PATCH 100/167] fix rebase Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- archive/archive_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archive/archive_test.go b/archive/archive_test.go index b9051fe6a..e05cd72e4 100644 --- a/archive/archive_test.go +++ b/archive/archive_test.go @@ -177,7 +177,7 @@ func TestTarUntarFile(t *testing.T) { t.Fatal(err) } - tar, err := TarFilter(path.Join(origin, "before"), &TarOptions{Compression: Uncompressed, Includes: []string{"file"}}) + tar, err := TarWithOptions(path.Join(origin, "before"), &TarOptions{Compression: Uncompressed, Includes: []string{"file"}}) if err != nil { t.Fatal(err) } From 250b0d070c7d8fce3d75bafc02c31ab3e356ba2e Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 26 Jun 2014 23:36:29 +0000 Subject: [PATCH 101/167] add doc Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- docs/sources/reference/api/docker_remote_api.md | 5 +++++ docs/sources/reference/api/docker_remote_api_v1.13.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/sources/reference/api/docker_remote_api.md b/docs/sources/reference/api/docker_remote_api.md index b623167c4..ff337b379 100644 --- a/docs/sources/reference/api/docker_remote_api.md +++ b/docs/sources/reference/api/docker_remote_api.md @@ -34,6 +34,11 @@ You can still call an old version of the API using ### What's new +`GET /containers/(name)/json` + +**New!** +The `HostConfig.Links` field is now filled correctly + **New!** `Sockets` parameter added to the `/info` endpoint listing all the sockets the daemon is configured to listen on. diff --git a/docs/sources/reference/api/docker_remote_api_v1.13.md b/docs/sources/reference/api/docker_remote_api_v1.13.md index e92b130fa..286c7e185 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.13.md +++ b/docs/sources/reference/api/docker_remote_api_v1.13.md @@ -240,7 +240,7 @@ Return low-level information on the container `id` } ] }, - "Links": null, + "Links": ["/name:alias"], "PublishAllPorts": false } } From 41e75232914df5f5075d5d04cc2891fee9417067 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 26 Jun 2014 15:18:50 -0700 Subject: [PATCH 102/167] Update libcontainer to 53cfe0a1eba9145bf5329abbb52 Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- hack/vendor.sh | 2 +- .../github.com/docker/libcontainer/README.md | 41 ++-- .../src/github.com/docker/libcontainer/api.go | 23 ++ .../libcontainer/cgroups/fs/notify_linux.go | 82 ++++++++ .../cgroups/fs/notify_linux_test.go | 86 ++++++++ .../docker/libcontainer/container.go | 17 +- .../docker/libcontainer/container_test.go | 52 ++++- .../docker/libcontainer/mount/init.go | 4 +- .../docker/libcontainer/mount/types.go | 1 + .../docker/libcontainer/namespaces/exec.go | 49 +++-- .../docker/libcontainer/namespaces/execin.go | 8 +- .../docker/libcontainer/namespaces/init.go | 30 ++- .../docker/libcontainer/namespaces/pid.go | 28 --- .../libcontainer/namespaces/sync_pipe.go | 60 ++++-- .../namespaces/sync_pipe_linux.go | 20 ++ .../libcontainer/namespaces/sync_pipe_test.go | 61 ++++++ .../docker/libcontainer/network/loopback.go | 4 +- .../docker/libcontainer/network/netns.go | 13 +- .../docker/libcontainer/network/stats.go | 68 ++++++ .../docker/libcontainer/network/strategy.go | 4 +- .../docker/libcontainer/network/types.go | 11 + .../docker/libcontainer/network/veth.go | 18 +- .../docker/libcontainer/nsinit/exec.go | 11 +- .../docker/libcontainer/nsinit/stats.go | 12 +- .../docker/libcontainer/nsinit/utils.go | 16 -- .../libcontainer/sample_configs/apparmor.json | 196 +++++++++++++++++ .../sample_configs/attach_to_bridge.json | 6 +- .../libcontainer/sample_configs/minimal.json | 6 +- .../libcontainer/sample_configs/selinux.json | 197 ++++++++++++++++++ .../github.com/docker/libcontainer/state.go | 55 +++++ .../github.com/docker/libcontainer/types.go | 11 + 31 files changed, 1026 insertions(+), 166 deletions(-) create mode 100644 vendor/src/github.com/docker/libcontainer/api.go create mode 100644 vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux.go create mode 100644 vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux_test.go delete mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/pid.go create mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go create mode 100644 vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go create mode 100644 vendor/src/github.com/docker/libcontainer/network/stats.go create mode 100644 vendor/src/github.com/docker/libcontainer/sample_configs/apparmor.json create mode 100644 vendor/src/github.com/docker/libcontainer/sample_configs/selinux.json create mode 100644 vendor/src/github.com/docker/libcontainer/state.go create mode 100644 vendor/src/github.com/docker/libcontainer/types.go diff --git a/hack/vendor.sh b/hack/vendor.sh index 630998e20..b17ea0b3a 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -63,4 +63,4 @@ mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar clone git github.com/godbus/dbus v1 clone git github.com/coreos/go-systemd v2 -clone git github.com/docker/libcontainer 5210a236b92a8022a673108f3471fed0a046bd05 +clone git github.com/docker/libcontainer 53cfe0a1eba9145bf5329abbb52b0072ccab8a00 diff --git a/vendor/src/github.com/docker/libcontainer/README.md b/vendor/src/github.com/docker/libcontainer/README.md index e4cf36f37..ee14a57ce 100644 --- a/vendor/src/github.com/docker/libcontainer/README.md +++ b/vendor/src/github.com/docker/libcontainer/README.md @@ -6,39 +6,44 @@ Please bear with us while we work on making the libcontainer API stable and some #### Background -libcontainer specifies configuration options for what a container is. It provides a native Go implementation -for using Linux namespaces with no external dependencies. libcontainer provides many convenience functions for working with namespaces, networking, and management. +libcontainer specifies configuration options for what a container is. It provides a native Go implementation for using Linux namespaces with no external dependencies. libcontainer provides many convenience functions for working with namespaces, networking, and management. #### Container -A container is a self contained directory that is able to run one or more processes without -affecting the host system. The directory is usually a full system tree. Inside the directory -a `container.json` file is placed with the runtime configuration for how the processes -should be contained and run. Environment, networking, and different capabilities for the -process are specified in this file. The configuration is used for each process executed inside the container. +A container is a self contained execution environment that shares the kernel of the host system and which is (optionally) isolated from other containers in the system. -See the `sample_configs` folder for examples of what the container configuration should look like. +libcontainer may be used to execute a process in a container. If a user tries to run a new process inside an existing container, the new process is added to the processes executing in the container. -Using this configuration and the current directory holding the rootfs for a process, one can use libcontainer to exec the container. Running the life of the namespace, a `pid` file -is written to the current directory with the pid of the namespaced process to the external world. A client can use this pid to wait, kill, or perform other operation with the container. If a user tries to run a new process inside an existing container with a live namespace, the namespace will be joined by the new process. -You may also specify an alternate root place where the `container.json` file is read and where the `pid` file will be saved. +#### Root file system + +A container runs with a directory known as its *root file system*, or *rootfs*, mounted as the file system root. The rootfs is usually a full system tree. + + +#### Configuration + +A container is initially configured by supplying configuration data when the container is created. + #### nsinit -`nsinit` is a cli application used as the reference implementation of libcontainer. It is able to -spawn or join new containers giving the current directory. To use `nsinit` cd into a Linux -rootfs and copy a `container.json` file into the directory with your specified configuration. +`nsinit` is a cli application which demonstrates the use of libcontainer. It is able to spawn new containers or join existing containers, based on the current directory. -To execute `/bin/bash` in the current directory as a container just run: +To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into the directory with your specified configuration. Environment, networking, and different capabilities for the container are specified in this file. The configuration is used for each process executed inside the container. + +See the `sample_configs` folder for examples of what the container configuration should look like. + +To execute `/bin/bash` in the current directory as a container just run the following **as root**: ```bash nsinit exec /bin/bash ``` -If you wish to spawn another process inside the container while your current bash session is -running just run the exact same command again to get another bash shell or change the command. If the original process dies, PID 1, all other processes spawned inside the container will also be killed and the namespace will be removed. +If you wish to spawn another process inside the container while your current bash session is running, run the same command again to get another bash shell (or change the command). If the original process (PID 1) dies, all other processes spawned inside the container will be killed and the namespace will be removed. + +You can identify if a process is running in a container by looking to see if `state.json` is in the root of the directory. + +You may also specify an alternate root place where the `container.json` file is read and where the `state.json` file will be saved. -You can identify if a process is running in a container by looking to see if `pid` is in the root of the directory. #### Future See the [roadmap](ROADMAP.md). diff --git a/vendor/src/github.com/docker/libcontainer/api.go b/vendor/src/github.com/docker/libcontainer/api.go new file mode 100644 index 000000000..310f06e81 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/api.go @@ -0,0 +1,23 @@ +package libcontainer + +import ( + "github.com/docker/libcontainer/cgroups/fs" + "github.com/docker/libcontainer/network" +) + +// Returns all available stats for the given container. +func GetStats(container *Config, state *State) (*ContainerStats, error) { + var containerStats ContainerStats + stats, err := fs.GetStats(container.Cgroups) + if err != nil { + return &containerStats, err + } + containerStats.CgroupStats = stats + networkStats, err := network.GetStats(&state.NetworkState) + if err != nil { + return &containerStats, err + } + containerStats.NetworkStats = networkStats + + return &containerStats, nil +} diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux.go new file mode 100644 index 000000000..d92063bad --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux.go @@ -0,0 +1,82 @@ +// +build linux + +package fs + +import ( + "fmt" + "os" + "path/filepath" + "syscall" + + "github.com/docker/libcontainer/cgroups" +) + +// NotifyOnOOM sends signals on the returned channel when the cgroup reaches +// its memory limit. The channel is closed when the cgroup is removed. +func NotifyOnOOM(c *cgroups.Cgroup) (<-chan struct{}, error) { + d, err := getCgroupData(c, 0) + if err != nil { + return nil, err + } + + return notifyOnOOM(d) +} + +func notifyOnOOM(d *data) (<-chan struct{}, error) { + dir, err := d.path("memory") + if err != nil { + return nil, err + } + + fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0) + if syserr != 0 { + return nil, syserr + } + + eventfd := os.NewFile(fd, "eventfd") + + oomControl, err := os.Open(filepath.Join(dir, "memory.oom_control")) + if err != nil { + eventfd.Close() + return nil, err + } + + var ( + eventControlPath = filepath.Join(dir, "cgroup.event_control") + data = fmt.Sprintf("%d %d", eventfd.Fd(), oomControl.Fd()) + ) + + if err := writeFile(dir, "cgroup.event_control", data); err != nil { + eventfd.Close() + oomControl.Close() + return nil, err + } + + ch := make(chan struct{}) + + go func() { + defer func() { + close(ch) + eventfd.Close() + oomControl.Close() + }() + + buf := make([]byte, 8) + + for { + if _, err := eventfd.Read(buf); err != nil { + return + } + + // When a cgroup is destroyed, an event is sent to eventfd. + // So if the control path is gone, return instead of notifying. + if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) { + return + } + + ch <- struct{}{} + } + }() + + return ch, nil +} diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux_test.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux_test.go new file mode 100644 index 000000000..a11880cb6 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/notify_linux_test.go @@ -0,0 +1,86 @@ +// +build linux + +package fs + +import ( + "encoding/binary" + "fmt" + "syscall" + "testing" + "time" +) + +func TestNotifyOnOOM(t *testing.T) { + helper := NewCgroupTestUtil("memory", t) + defer helper.cleanup() + + helper.writeFileContents(map[string]string{ + "memory.oom_control": "", + "cgroup.event_control": "", + }) + + var eventFd, oomControlFd int + + ooms, err := notifyOnOOM(helper.CgroupData) + if err != nil { + t.Fatal("expected no error, got:", err) + } + + memoryPath, _ := helper.CgroupData.path("memory") + data, err := readFile(memoryPath, "cgroup.event_control") + if err != nil { + t.Fatal("couldn't read event control file:", err) + } + + if _, err := fmt.Sscanf(data, "%d %d", &eventFd, &oomControlFd); err != nil { + t.Fatalf("invalid control data %q: %s", data, err) + } + + // re-open the eventfd + efd, err := syscall.Dup(eventFd) + if err != nil { + t.Fatal("unable to reopen eventfd:", err) + } + defer syscall.Close(efd) + + if err != nil { + t.Fatal("unable to dup event fd:", err) + } + + buf := make([]byte, 8) + binary.LittleEndian.PutUint64(buf, 1) + + if _, err := syscall.Write(efd, buf); err != nil { + t.Fatal("unable to write to eventfd:", err) + } + + select { + case <-ooms: + case <-time.After(100 * time.Millisecond): + t.Fatal("no notification on oom channel after 100ms") + } + + // simulate what happens when a cgroup is destroyed by cleaning up and then + // writing to the eventfd. + helper.cleanup() + if _, err := syscall.Write(efd, buf); err != nil { + t.Fatal("unable to write to eventfd:", err) + } + + // give things a moment to shut down + select { + case _, ok := <-ooms: + if ok { + t.Fatal("expected no oom to be triggered") + } + case <-time.After(100 * time.Millisecond): + } + + if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(oomControlFd), syscall.F_GETFD, 0); err != syscall.EBADF { + t.Error("expected oom control to be closed") + } + + if _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(eventFd), syscall.F_GETFD, 0); err != syscall.EBADF { + t.Error("expected event fd to be closed") + } +} diff --git a/vendor/src/github.com/docker/libcontainer/container.go b/vendor/src/github.com/docker/libcontainer/container.go index 95be4f9ec..8fe95c24f 100644 --- a/vendor/src/github.com/docker/libcontainer/container.go +++ b/vendor/src/github.com/docker/libcontainer/container.go @@ -51,12 +51,17 @@ type Config struct { // placed into to limit the resources the container has available Cgroups *cgroups.Cgroup `json:"cgroups,omitempty"` - // Context is a generic key value format that allows for additional settings to be passed - // on the container's creation - // This is commonly used to specify apparmor profiles, selinux labels, and different restrictions - // placed on the container's processes - // TODO(vishh): Avoid overloading this field with params for different subsystems. Strongtype this. - Context map[string]string `json:"context,omitempty"` + // AppArmorProfile specifies the profile to apply to the process running in the container and is + // change at the time the process is execed + AppArmorProfile string `json:"apparmor_profile,omitempty"` + + // ProcessLabel specifies the label to apply to the process running in the container. It is + // commonly used by selinux + ProcessLabel string `json:"process_label,omitempty"` + + // RestrictSys will remount /proc/sys, /sys, and mask over sysrq-trigger as well as /proc/irq and + // /proc/bus + RestrictSys bool `json:"restrict_sys,omitempty"` } // Routes can be specified to create entries in the route table as the container is started diff --git a/vendor/src/github.com/docker/libcontainer/container_test.go b/vendor/src/github.com/docker/libcontainer/container_test.go index e98b38feb..598128115 100644 --- a/vendor/src/github.com/docker/libcontainer/container_test.go +++ b/vendor/src/github.com/docker/libcontainer/container_test.go @@ -3,6 +3,7 @@ package libcontainer import ( "encoding/json" "os" + "path/filepath" "testing" "github.com/docker/libcontainer/devices" @@ -32,17 +33,27 @@ func containsDevice(expected *devices.Device, values []*devices.Device) bool { return false } -func TestConfigJsonFormat(t *testing.T) { - f, err := os.Open("sample_configs/attach_to_bridge.json") +func loadConfig(name string) (*Config, error) { + f, err := os.Open(filepath.Join("sample_configs", name)) if err != nil { - t.Fatal("Unable to open container.json") + return nil, err } defer f.Close() var container *Config if err := json.NewDecoder(f).Decode(&container); err != nil { - t.Fatalf("failed to decode container config: %s", err) + return nil, err } + + return container, nil +} + +func TestConfigJsonFormat(t *testing.T) { + container, err := loadConfig("attach_to_bridge.json") + if err != nil { + t.Fatal(err) + } + if container.Hostname != "koye" { t.Log("hostname is not set") t.Fail() @@ -111,8 +122,39 @@ func TestConfigJsonFormat(t *testing.T) { for _, d := range devices.DefaultSimpleDevices { if !containsDevice(d, container.MountConfig.DeviceNodes) { - t.Logf("expected defice configuration for %s", d.Path) + t.Logf("expected device configuration for %s", d.Path) t.Fail() } } + + if !container.RestrictSys { + t.Log("expected restrict sys to be true") + t.Fail() + } +} + +func TestApparmorProfile(t *testing.T) { + container, err := loadConfig("apparmor.json") + if err != nil { + t.Fatal(err) + } + + if container.AppArmorProfile != "docker-default" { + t.Fatalf("expected apparmor profile to be docker-default but received %q", container.AppArmorProfile) + } +} + +func TestSelinuxLabels(t *testing.T) { + container, err := loadConfig("selinux.json") + if err != nil { + t.Fatal(err) + } + label := "system_u:system_r:svirt_lxc_net_t:s0:c164,c475" + + if container.ProcessLabel != label { + t.Fatalf("expected process label %q but received %q", label, container.ProcessLabel) + } + if container.MountConfig.MountLabel != label { + t.Fatalf("expected mount label %q but received %q", label, container.MountConfig.MountLabel) + } } diff --git a/vendor/src/github.com/docker/libcontainer/mount/init.go b/vendor/src/github.com/docker/libcontainer/mount/init.go index bc839e325..34fad6dd1 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/init.go +++ b/vendor/src/github.com/docker/libcontainer/mount/init.go @@ -25,8 +25,8 @@ type mount struct { data string } -// InitializeMountNamespace setups up the devices, mount points, and filesystems for use inside a -// new mount namepsace +// InitializeMountNamespace sets up the devices, mount points, and filesystems for use inside a +// new mount namespace. func InitializeMountNamespace(rootfs, console string, mountConfig *MountConfig) error { var ( err error diff --git a/vendor/src/github.com/docker/libcontainer/mount/types.go b/vendor/src/github.com/docker/libcontainer/mount/types.go index 9a0083705..a2659e582 100644 --- a/vendor/src/github.com/docker/libcontainer/mount/types.go +++ b/vendor/src/github.com/docker/libcontainer/mount/types.go @@ -2,6 +2,7 @@ package mount import ( "errors" + "github.com/docker/libcontainer/devices" ) diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go index 10238536e..0aa2bb9c7 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go @@ -17,7 +17,7 @@ import ( // TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work. // Move this to libcontainer package. -// Exec performes setup outside of a namespace so that a container can be +// Exec performs setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { var ( @@ -32,6 +32,7 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string if err != nil { return -1, err } + defer syncPipe.Close() if container.Tty { master, console, err = system.CreateMasterAndConsole() @@ -52,16 +53,13 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string return -1, err } + // Now we passed the pipe to the child, close our side + syncPipe.CloseChild() + started, err := system.GetProcessStartTime(command.Process.Pid) if err != nil { return -1, err } - if err := WritePid(dataPath, command.Process.Pid, started); err != nil { - command.Process.Kill() - command.Wait() - return -1, err - } - defer DeletePid(dataPath) // Do this before syncing with child so that no children // can escape the cgroup @@ -75,14 +73,32 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string defer cleaner.Cleanup() } - if err := InitializeNetworking(container, command.Process.Pid, syncPipe); err != nil { + var networkState network.NetworkState + if err := InitializeNetworking(container, command.Process.Pid, syncPipe, &networkState); err != nil { command.Process.Kill() command.Wait() return -1, err } + state := &libcontainer.State{ + InitPid: command.Process.Pid, + InitStartTime: started, + NetworkState: networkState, + } + + if err := libcontainer.SaveState(dataPath, state); err != nil { + command.Process.Kill() + command.Wait() + return -1, err + } + defer libcontainer.DeleteState(dataPath) + // Sync with child - syncPipe.Close() + if err := syncPipe.ReadFromChild(); err != nil { + command.Process.Kill() + command.Wait() + return -1, err + } if startCallback != nil { startCallback() @@ -101,10 +117,10 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string // args provided // // console: the /dev/console to setup inside the container -// init: the progam executed inside the namespaces +// init: the program executed inside the namespaces // root: the path to the container json file and information -// pipe: sync pipe to syncronize the parent and child processes -// args: the arguemnts to pass to the container to run as the user's program +// pipe: sync pipe to synchronize the parent and child processes +// args: the arguments to pass to the container to run as the user's program func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { // get our binary name from arg0 so we can always reexec ourself env := []string{ @@ -135,7 +151,7 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP return command } -// SetupCgroups applies the cgroup restrictions to the process running in the contaienr based +// SetupCgroups applies the cgroup restrictions to the process running in the container based // on the container's configuration func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgroup, error) { if container.Cgroups != nil { @@ -150,18 +166,17 @@ func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgro // InitializeNetworking creates the container's network stack outside of the namespace and moves // interfaces into the container's net namespaces if necessary -func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *SyncPipe) error { - context := map[string]string{} +func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *SyncPipe, networkState *network.NetworkState) error { for _, config := range container.Networks { strategy, err := network.GetStrategy(config.Type) if err != nil { return err } - if err := strategy.Create((*network.Network)(config), nspid, context); err != nil { + if err := strategy.Create((*network.Network)(config), nspid, networkState); err != nil { return err } } - return pipe.SendToChild(context) + return pipe.SendToChild(networkState) } // GetNamespaceFlags parses the container's Namespaces options to set the correct diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go index cd33025af..d349282e8 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/execin.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/execin.go @@ -13,7 +13,7 @@ import ( ) // ExecIn uses an existing pid and joins the pid's namespaces with the new command. -func ExecIn(container *libcontainer.Config, nspid int, args []string) error { +func ExecIn(container *libcontainer.Config, state *libcontainer.State, args []string) error { // TODO(vmarmol): If this gets too long, send it over a pipe to the child. // Marshall the container into JSON since it won't be available in the namespace. containerJson, err := json.Marshal(container) @@ -22,7 +22,7 @@ func ExecIn(container *libcontainer.Config, nspid int, args []string) error { } // Enter the namespace and then finish setup - finalArgs := []string{os.Args[0], "nsenter", "--nspid", strconv.Itoa(nspid), "--containerjson", string(containerJson), "--"} + finalArgs := []string{os.Args[0], "nsenter", "--nspid", strconv.Itoa(state.InitPid), "--containerjson", string(containerJson), "--"} finalArgs = append(finalArgs, args...) if err := system.Execv(finalArgs[0], finalArgs[0:], os.Environ()); err != nil { return err @@ -41,8 +41,8 @@ func NsEnter(container *libcontainer.Config, nspid int, args []string) error { return err } - if process_label, ok := container.Context["process_label"]; ok { - if err := label.SetProcessLabel(process_label); err != nil { + if container.ProcessLabel != "" { + if err := label.SetProcessLabel(container.ProcessLabel); err != nil { return err } } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/init.go b/vendor/src/github.com/docker/libcontainer/namespaces/init.go index e916ca289..53d2611b8 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/init.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/init.go @@ -27,7 +27,13 @@ import ( // Move this to libcontainer package. // Init is the init process that first runs inside a new namespace to setup mounts, users, networking, // and other options required for the new container. -func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { +func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) (err error) { + defer func() { + if err != nil { + syncPipe.ReportChildError(err) + } + }() + rootfs, err := utils.ResolveRootfs(uncleanRootfs) if err != nil { return err @@ -40,12 +46,10 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn } // We always read this as it is a way to sync with the parent as well - context, err := syncPipe.ReadFromParent() + networkState, err := syncPipe.ReadFromParent() if err != nil { - syncPipe.Close() return err } - syncPipe.Close() if consolePath != "" { if err := console.OpenAndDup(consolePath); err != nil { @@ -60,7 +64,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn return fmt.Errorf("setctty %s", err) } } - if err := setupNetwork(container, context); err != nil { + if err := setupNetwork(container, networkState); err != nil { return fmt.Errorf("setup networking %s", err) } if err := setupRoute(container); err != nil { @@ -74,6 +78,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn (*mount.MountConfig)(container.MountConfig)); err != nil { return fmt.Errorf("setup mount namespace %s", err) } + if container.Hostname != "" { if err := system.Sethostname(container.Hostname); err != nil { return fmt.Errorf("sethostname %s", err) @@ -82,13 +87,16 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn runtime.LockOSThread() - if err := apparmor.ApplyProfile(container.Context["apparmor_profile"]); err != nil { - return fmt.Errorf("set apparmor profile %s: %s", container.Context["apparmor_profile"], err) + if err := apparmor.ApplyProfile(container.AppArmorProfile); err != nil { + return fmt.Errorf("set apparmor profile %s: %s", container.AppArmorProfile, err) } - if err := label.SetProcessLabel(container.Context["process_label"]); err != nil { + + if err := label.SetProcessLabel(container.ProcessLabel); err != nil { return fmt.Errorf("set process label %s", err) } - if container.Context["restrictions"] != "" { + + // TODO: (crosbymichael) make this configurable at the Config level + if container.RestrictSys { if err := restrict.Restrict("proc/sys", "proc/sysrq-trigger", "proc/irq", "proc/bus", "sys"); err != nil { return err } @@ -161,14 +169,14 @@ func SetupUser(u string) error { // setupVethNetwork uses the Network config if it is not nil to initialize // the new veth interface inside the container for use by changing the name to eth0 // setting the MTU and IP address along with the default gateway -func setupNetwork(container *libcontainer.Config, context map[string]string) error { +func setupNetwork(container *libcontainer.Config, networkState *network.NetworkState) error { for _, config := range container.Networks { strategy, err := network.GetStrategy(config.Type) if err != nil { return err } - err1 := strategy.Initialize((*network.Network)(config), context) + err1 := strategy.Initialize((*network.Network)(config), networkState) if err1 != nil { return err1 } diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/pid.go b/vendor/src/github.com/docker/libcontainer/namespaces/pid.go deleted file mode 100644 index 8d97ec146..000000000 --- a/vendor/src/github.com/docker/libcontainer/namespaces/pid.go +++ /dev/null @@ -1,28 +0,0 @@ -package namespaces - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" -) - -// WritePid writes the namespaced processes pid to pid and it's start time -// to the path specified -func WritePid(path string, pid int, startTime string) error { - err := ioutil.WriteFile(filepath.Join(path, "pid"), []byte(fmt.Sprint(pid)), 0655) - if err != nil { - return err - } - return ioutil.WriteFile(filepath.Join(path, "start"), []byte(startTime), 0655) -} - -// DeletePid removes the pid and started file from disk when the container's process -// dies and the container is cleanly removed -func DeletePid(path string) error { - err := os.Remove(filepath.Join(path, "pid")) - if serr := os.Remove(filepath.Join(path, "start")); err == nil { - err = serr - } - return err -} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go index 210ee5fbd..dcb5d9749 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe.go @@ -5,6 +5,9 @@ import ( "fmt" "io/ioutil" "os" + "syscall" + + "github.com/docker/libcontainer/network" ) // SyncPipe allows communication to and from the child processes @@ -14,24 +17,17 @@ type SyncPipe struct { parent, child *os.File } -func NewSyncPipe() (s *SyncPipe, err error) { - s = &SyncPipe{} - s.child, s.parent, err = os.Pipe() - if err != nil { - return nil, err - } - return s, nil -} - -func NewSyncPipeFromFd(parendFd, childFd uintptr) (*SyncPipe, error) { +func NewSyncPipeFromFd(parentFd, childFd uintptr) (*SyncPipe, error) { s := &SyncPipe{} - if parendFd > 0 { - s.parent = os.NewFile(parendFd, "parendPipe") + + if parentFd > 0 { + s.parent = os.NewFile(parentFd, "parentPipe") } else if childFd > 0 { s.child = os.NewFile(childFd, "childPipe") } else { return nil, fmt.Errorf("no valid sync pipe fd specified") } + return s, nil } @@ -43,36 +39,64 @@ func (s *SyncPipe) Parent() *os.File { return s.parent } -func (s *SyncPipe) SendToChild(context map[string]string) error { - data, err := json.Marshal(context) +func (s *SyncPipe) SendToChild(networkState *network.NetworkState) error { + data, err := json.Marshal(networkState) if err != nil { return err } + s.parent.Write(data) + + return syscall.Shutdown(int(s.parent.Fd()), syscall.SHUT_WR) +} + +func (s *SyncPipe) ReadFromChild() error { + data, err := ioutil.ReadAll(s.parent) + if err != nil { + return err + } + + if len(data) > 0 { + return fmt.Errorf("%s", data) + } + return nil } -func (s *SyncPipe) ReadFromParent() (map[string]string, error) { +func (s *SyncPipe) ReadFromParent() (*network.NetworkState, error) { data, err := ioutil.ReadAll(s.child) if err != nil { return nil, fmt.Errorf("error reading from sync pipe %s", err) } - var context map[string]string + var networkState *network.NetworkState if len(data) > 0 { - if err := json.Unmarshal(data, &context); err != nil { + if err := json.Unmarshal(data, &networkState); err != nil { return nil, err } } - return context, nil + return networkState, nil +} +func (s *SyncPipe) ReportChildError(err error) { + s.child.Write([]byte(err.Error())) + s.CloseChild() } func (s *SyncPipe) Close() error { if s.parent != nil { s.parent.Close() } + if s.child != nil { s.child.Close() } + return nil } + +func (s *SyncPipe) CloseChild() { + if s.child != nil { + s.child.Close() + s.child = nil + } +} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go new file mode 100644 index 000000000..ad61e75d2 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_linux.go @@ -0,0 +1,20 @@ +package namespaces + +import ( + "os" + "syscall" +) + +func NewSyncPipe() (s *SyncPipe, err error) { + s = &SyncPipe{} + + fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0) + if err != nil { + return nil, err + } + + s.child = os.NewFile(uintptr(fds[0]), "child syncpipe") + s.parent = os.NewFile(uintptr(fds[1]), "parent syncpipe") + + return s, nil +} diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go new file mode 100644 index 000000000..69bd0abbf --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/namespaces/sync_pipe_test.go @@ -0,0 +1,61 @@ +package namespaces + +import ( + "fmt" + "testing" + + "github.com/docker/libcontainer/network" +) + +func TestSendErrorFromChild(t *testing.T) { + pipe, err := NewSyncPipe() + if err != nil { + t.Fatal(err) + } + defer func() { + if err := pipe.Close(); err != nil { + t.Fatal(err) + } + }() + + expected := "something bad happened" + + pipe.ReportChildError(fmt.Errorf(expected)) + + childError := pipe.ReadFromChild() + if childError == nil { + t.Fatal("expected an error to be returned but did not receive anything") + } + + if childError.Error() != expected { + t.Fatalf("expected %q but received error message %q", expected, childError.Error()) + } +} + +func TestSendPayloadToChild(t *testing.T) { + pipe, err := NewSyncPipe() + if err != nil { + t.Fatal(err) + } + + defer func() { + if err := pipe.Close(); err != nil { + t.Fatal(err) + } + }() + + expected := "libcontainer" + + if err := pipe.SendToChild(&network.NetworkState{VethHost: expected}); err != nil { + t.Fatal(err) + } + + payload, err := pipe.ReadFromParent() + if err != nil { + t.Fatal(err) + } + + if payload.VethHost != expected { + t.Fatalf("expected veth host %q but received %q", expected, payload.VethHost) + } +} diff --git a/vendor/src/github.com/docker/libcontainer/network/loopback.go b/vendor/src/github.com/docker/libcontainer/network/loopback.go index 0d36c4f8c..46a1fa8c8 100644 --- a/vendor/src/github.com/docker/libcontainer/network/loopback.go +++ b/vendor/src/github.com/docker/libcontainer/network/loopback.go @@ -10,11 +10,11 @@ import ( type Loopback struct { } -func (l *Loopback) Create(n *Network, nspid int, context map[string]string) error { +func (l *Loopback) Create(n *Network, nspid int, networkState *NetworkState) error { return nil } -func (l *Loopback) Initialize(config *Network, context map[string]string) error { +func (l *Loopback) Initialize(config *Network, networkState *NetworkState) error { if err := SetMtu("lo", config.Mtu); err != nil { return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err) } diff --git a/vendor/src/github.com/docker/libcontainer/network/netns.go b/vendor/src/github.com/docker/libcontainer/network/netns.go index e2121cb08..64544476b 100644 --- a/vendor/src/github.com/docker/libcontainer/network/netns.go +++ b/vendor/src/github.com/docker/libcontainer/network/netns.go @@ -14,17 +14,16 @@ import ( type NetNS struct { } -func (v *NetNS) Create(n *Network, nspid int, context map[string]string) error { - context["nspath"] = n.NsPath +func (v *NetNS) Create(n *Network, nspid int, networkState *NetworkState) error { + networkState.NsPath = n.NsPath return nil } -func (v *NetNS) Initialize(config *Network, context map[string]string) error { - nspath, exists := context["nspath"] - if !exists { - return fmt.Errorf("nspath does not exist in network context") +func (v *NetNS) Initialize(config *Network, networkState *NetworkState) error { + if networkState.NsPath == "" { + return fmt.Errorf("nspath does is not specified in NetworkState") } - f, err := os.OpenFile(nspath, os.O_RDONLY, 0) + f, err := os.OpenFile(networkState.NsPath, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace fd: %v", err) } diff --git a/vendor/src/github.com/docker/libcontainer/network/stats.go b/vendor/src/github.com/docker/libcontainer/network/stats.go new file mode 100644 index 000000000..b69fa9185 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/network/stats.go @@ -0,0 +1,68 @@ +package network + +import ( + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" +) + +type NetworkStats struct { + RxBytes uint64 `json:"rx_bytes,omitempty"` + RxPackets uint64 `json:"rx_packets,omitempty"` + RxErrors uint64 `json:"rx_errors,omitempty"` + RxDropped uint64 `json:"rx_dropped,omitempty"` + TxBytes uint64 `json:"tx_bytes,omitempty"` + TxPackets uint64 `json:"tx_packets,omitempty"` + TxErrors uint64 `json:"tx_errors,omitempty"` + TxDropped uint64 `json:"tx_dropped,omitempty"` +} + +// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. +func GetStats(networkState *NetworkState) (NetworkStats, error) { + // This can happen if the network runtime information is missing - possible if the container was created by an old version of libcontainer. + if networkState.VethHost == "" { + return NetworkStats{}, nil + } + data, err := readSysfsNetworkStats(networkState.VethHost) + if err != nil { + return NetworkStats{}, err + } + + return NetworkStats{ + RxBytes: data["rx_bytes"], + RxPackets: data["rx_packets"], + RxErrors: data["rx_errors"], + RxDropped: data["rx_dropped"], + TxBytes: data["tx_bytes"], + TxPackets: data["tx_packets"], + TxErrors: data["tx_errors"], + TxDropped: data["tx_dropped"], + }, nil +} + +// Reads all the statistics available under /sys/class/net//statistics as a map with file name as key and data as integers. +func readSysfsNetworkStats(ethInterface string) (map[string]uint64, error) { + out := make(map[string]uint64) + + fullPath := filepath.Join("/sys/class/net", ethInterface, "statistics/") + err := filepath.Walk(fullPath, func(path string, _ os.FileInfo, _ error) error { + // skip fullPath. + if path == fullPath { + return nil + } + base := filepath.Base(path) + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + value, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) + if err != nil { + return err + } + out[base] = value + return nil + }) + return out, err +} diff --git a/vendor/src/github.com/docker/libcontainer/network/strategy.go b/vendor/src/github.com/docker/libcontainer/network/strategy.go index 358fb4152..be5ec93b7 100644 --- a/vendor/src/github.com/docker/libcontainer/network/strategy.go +++ b/vendor/src/github.com/docker/libcontainer/network/strategy.go @@ -19,8 +19,8 @@ var strategies = map[string]NetworkStrategy{ // NetworkStrategy represents a specific network configuration for // a container's networking stack type NetworkStrategy interface { - Create(*Network, int, map[string]string) error - Initialize(*Network, map[string]string) error + Create(*Network, int, *NetworkState) error + Initialize(*Network, *NetworkState) error } // GetStrategy returns the specific network strategy for the diff --git a/vendor/src/github.com/docker/libcontainer/network/types.go b/vendor/src/github.com/docker/libcontainer/network/types.go index 14463ab71..0f1df30e8 100644 --- a/vendor/src/github.com/docker/libcontainer/network/types.go +++ b/vendor/src/github.com/docker/libcontainer/network/types.go @@ -27,3 +27,14 @@ type Network struct { // container's interfaces if a pair is created, specifically in the case of type veth Mtu int `json:"mtu,omitempty"` } + +// Struct describing the network specific runtime state that will be maintained by libcontainer for all running containers +// Do not depend on it outside of libcontainer. +type NetworkState struct { + // The name of the veth interface on the Host. + VethHost string `json:"veth_host,omitempty"` + // The name of the veth interface created inside the container for the child. + VethChild string `json:"veth_child,omitempty"` + // Net namespace path. + NsPath string `json:"ns_path,omitempty"` +} diff --git a/vendor/src/github.com/docker/libcontainer/network/veth.go b/vendor/src/github.com/docker/libcontainer/network/veth.go index 20bc9e506..fcafd85cc 100644 --- a/vendor/src/github.com/docker/libcontainer/network/veth.go +++ b/vendor/src/github.com/docker/libcontainer/network/veth.go @@ -16,7 +16,7 @@ type Veth struct { const defaultDevice = "eth0" -func (v *Veth) Create(n *Network, nspid int, context map[string]string) error { +func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error { var ( bridge = n.Bridge prefix = n.VethPrefix @@ -31,8 +31,6 @@ func (v *Veth) Create(n *Network, nspid int, context map[string]string) error { if err != nil { return err } - context["veth-host"] = name1 - context["veth-child"] = name2 if err := SetInterfaceMaster(name1, bridge); err != nil { return err } @@ -45,16 +43,16 @@ func (v *Veth) Create(n *Network, nspid int, context map[string]string) error { if err := SetInterfaceInNamespacePid(name2, nspid); err != nil { return err } + networkState.VethHost = name1 + networkState.VethChild = name2 + return nil } -func (v *Veth) Initialize(config *Network, context map[string]string) error { - var ( - vethChild string - exists bool - ) - if vethChild, exists = context["veth-child"]; !exists { - return fmt.Errorf("vethChild does not exist in network context") +func (v *Veth) Initialize(config *Network, networkState *NetworkState) error { + var vethChild = networkState.VethChild + if vethChild == "" { + return fmt.Errorf("vethChild is not specified") } if err := InterfaceDown(vethChild); err != nil { return fmt.Errorf("interface down %s %s", vethChild, err) diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go index deaf963fd..c58c30664 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go @@ -19,19 +19,20 @@ var execCommand = cli.Command{ } func execAction(context *cli.Context) { - var nspid, exitCode int + var exitCode int container, err := loadContainer() if err != nil { log.Fatal(err) } - if nspid, err = readPid(); err != nil && !os.IsNotExist(err) { - log.Fatalf("unable to read pid: %s", err) + state, err := libcontainer.GetState(dataPath) + if err != nil && !os.IsNotExist(err) { + log.Fatalf("unable to read state.json: %s", err) } - if nspid > 0 { - err = namespaces.ExecIn(container, nspid, []string(context.Args())) + if state != nil { + err = namespaces.ExecIn(container, state, []string(context.Args())) } else { term := namespaces.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty) exitCode, err = startContainer(container, term, dataPath, []string(context.Args())) diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/stats.go b/vendor/src/github.com/docker/libcontainer/nsinit/stats.go index 41301bedf..eae983380 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/stats.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/stats.go @@ -7,7 +7,6 @@ import ( "github.com/codegangsta/cli" "github.com/docker/libcontainer" - "github.com/docker/libcontainer/cgroups/fs" ) var statsCommand = cli.Command{ @@ -22,7 +21,12 @@ func statsAction(context *cli.Context) { log.Fatal(err) } - stats, err := getContainerStats(container) + runtimeCkpt, err := libcontainer.GetState(dataPath) + if err != nil { + log.Fatal(err) + } + + stats, err := getStats(container, runtimeCkpt) if err != nil { log.Fatalf("Failed to get stats - %v\n", err) } @@ -31,8 +35,8 @@ func statsAction(context *cli.Context) { } // returns the container stats in json format. -func getContainerStats(container *libcontainer.Config) (string, error) { - stats, err := fs.GetStats(container.Cgroups) +func getStats(container *libcontainer.Config, state *libcontainer.State) (string, error) { + stats, err := libcontainer.GetStats(container, state) if err != nil { return "", err } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/utils.go b/vendor/src/github.com/docker/libcontainer/nsinit/utils.go index fb672521f..44194d885 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/utils.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/utils.go @@ -2,11 +2,9 @@ package main import ( "encoding/json" - "io/ioutil" "log" "os" "path/filepath" - "strconv" "github.com/docker/libcontainer" ) @@ -26,20 +24,6 @@ func loadContainer() (*libcontainer.Config, error) { return container, nil } -func readPid() (int, error) { - data, err := ioutil.ReadFile(filepath.Join(dataPath, "pid")) - if err != nil { - return -1, err - } - - pid, err := strconv.Atoi(string(data)) - if err != nil { - return -1, err - } - - return pid, nil -} - func openLog(name string) error { f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/sample_configs/apparmor.json b/vendor/src/github.com/docker/libcontainer/sample_configs/apparmor.json new file mode 100644 index 000000000..f739df100 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/sample_configs/apparmor.json @@ -0,0 +1,196 @@ +{ + "capabilities": [ + "CHOWN", + "DAC_OVERRIDE", + "FOWNER", + "MKNOD", + "NET_RAW", + "SETGID", + "SETUID", + "SETFCAP", + "SETPCAP", + "NET_BIND_SERVICE", + "SYS_CHROOT", + "KILL" + ], + "cgroups": { + "allowed_devices": [ + { + "cgroup_permissions": "m", + "major_number": -1, + "minor_number": -1, + "type": 99 + }, + { + "cgroup_permissions": "m", + "major_number": -1, + "minor_number": -1, + "type": 98 + }, + { + "cgroup_permissions": "rwm", + "major_number": 5, + "minor_number": 1, + "path": "/dev/console", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 4, + "path": "/dev/tty0", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 4, + "minor_number": 1, + "path": "/dev/tty1", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 136, + "minor_number": -1, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 5, + "minor_number": 2, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 10, + "minor_number": 200, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 3, + "path": "/dev/null", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 5, + "path": "/dev/zero", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 7, + "path": "/dev/full", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 5, + "path": "/dev/tty", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 9, + "path": "/dev/urandom", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 8, + "path": "/dev/random", + "type": 99 + } + ], + "name": "docker-koye", + "parent": "docker" + }, + "restrict_sys": true, + "apparmor_profile": "docker-default", + "mount_config": { + "device_nodes": [ + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 3, + "path": "/dev/null", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 5, + "path": "/dev/zero", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 7, + "path": "/dev/full", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 5, + "path": "/dev/tty", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 9, + "path": "/dev/urandom", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 8, + "path": "/dev/random", + "type": 99 + } + ] + }, + "environment": [ + "HOME=/", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=koye", + "TERM=xterm" + ], + "hostname": "koye", + "namespaces": { + "NEWIPC": true, + "NEWNET": true, + "NEWNS": true, + "NEWPID": true, + "NEWUTS": true + }, + "networks": [ + { + "address": "127.0.0.1/0", + "gateway": "localhost", + "mtu": 1500, + "type": "loopback" + } + ], + "tty": true, + "user": "daemon" +} diff --git a/vendor/src/github.com/docker/libcontainer/sample_configs/attach_to_bridge.json b/vendor/src/github.com/docker/libcontainer/sample_configs/attach_to_bridge.json index 9b1e627d9..0795e6c14 100644 --- a/vendor/src/github.com/docker/libcontainer/sample_configs/attach_to_bridge.json +++ b/vendor/src/github.com/docker/libcontainer/sample_configs/attach_to_bridge.json @@ -116,11 +116,7 @@ "name": "docker-koye", "parent": "docker" }, - "context": { - "mount_label": "", - "process_label": "", - "restrictions": "true" - }, + "restrict_sys": true, "mount_config": { "device_nodes": [ { diff --git a/vendor/src/github.com/docker/libcontainer/sample_configs/minimal.json b/vendor/src/github.com/docker/libcontainer/sample_configs/minimal.json index 3e1a01ad0..c08c99679 100644 --- a/vendor/src/github.com/docker/libcontainer/sample_configs/minimal.json +++ b/vendor/src/github.com/docker/libcontainer/sample_configs/minimal.json @@ -116,11 +116,7 @@ "name": "docker-koye", "parent": "docker" }, - "context": { - "mount_label": "", - "process_label": "", - "restrictions": "true" - }, + "restrict_sys": true, "mount_config": { "device_nodes": [ { diff --git a/vendor/src/github.com/docker/libcontainer/sample_configs/selinux.json b/vendor/src/github.com/docker/libcontainer/sample_configs/selinux.json new file mode 100644 index 000000000..ce383e2cc --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/sample_configs/selinux.json @@ -0,0 +1,197 @@ +{ + "capabilities": [ + "CHOWN", + "DAC_OVERRIDE", + "FOWNER", + "MKNOD", + "NET_RAW", + "SETGID", + "SETUID", + "SETFCAP", + "SETPCAP", + "NET_BIND_SERVICE", + "SYS_CHROOT", + "KILL" + ], + "cgroups": { + "allowed_devices": [ + { + "cgroup_permissions": "m", + "major_number": -1, + "minor_number": -1, + "type": 99 + }, + { + "cgroup_permissions": "m", + "major_number": -1, + "minor_number": -1, + "type": 98 + }, + { + "cgroup_permissions": "rwm", + "major_number": 5, + "minor_number": 1, + "path": "/dev/console", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 4, + "path": "/dev/tty0", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 4, + "minor_number": 1, + "path": "/dev/tty1", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 136, + "minor_number": -1, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 5, + "minor_number": 2, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "major_number": 10, + "minor_number": 200, + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 3, + "path": "/dev/null", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 5, + "path": "/dev/zero", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 7, + "path": "/dev/full", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 5, + "path": "/dev/tty", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 9, + "path": "/dev/urandom", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 8, + "path": "/dev/random", + "type": 99 + } + ], + "name": "docker-koye", + "parent": "docker" + }, + "restrict_sys": true, + "process_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475", + "mount_config": { + "mount_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475", + "device_nodes": [ + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 3, + "path": "/dev/null", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 5, + "path": "/dev/zero", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 7, + "path": "/dev/full", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 5, + "path": "/dev/tty", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 9, + "path": "/dev/urandom", + "type": 99 + }, + { + "cgroup_permissions": "rwm", + "file_mode": 438, + "major_number": 1, + "minor_number": 8, + "path": "/dev/random", + "type": 99 + } + ] + }, + "environment": [ + "HOME=/", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=koye", + "TERM=xterm" + ], + "hostname": "koye", + "namespaces": { + "NEWIPC": true, + "NEWNET": true, + "NEWNS": true, + "NEWPID": true, + "NEWUTS": true + }, + "networks": [ + { + "address": "127.0.0.1/0", + "gateway": "localhost", + "mtu": 1500, + "type": "loopback" + } + ], + "tty": true, + "user": "daemon" +} diff --git a/vendor/src/github.com/docker/libcontainer/state.go b/vendor/src/github.com/docker/libcontainer/state.go new file mode 100644 index 000000000..a055bb0ff --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/state.go @@ -0,0 +1,55 @@ +package libcontainer + +import ( + "encoding/json" + "os" + "path/filepath" + + "github.com/docker/libcontainer/network" +) + +// State represents a running container's state +type State struct { + // InitPid is the init process id in the parent namespace + InitPid int `json:"init_pid,omitempty"` + // InitStartTime is the init process start time + InitStartTime string `json:"init_start_time,omitempty"` + // Network runtime state. + NetworkState network.NetworkState `json:"network_state,omitempty"` +} + +// The name of the runtime state file +const stateFile = "state.json" + +// SaveState writes the container's runtime state to a state.json file +// in the specified path +func SaveState(basePath string, state *State) error { + f, err := os.Create(filepath.Join(basePath, stateFile)) + if err != nil { + return err + } + defer f.Close() + + return json.NewEncoder(f).Encode(state) +} + +// GetState reads the state.json file for a running container +func GetState(basePath string) (*State, error) { + f, err := os.Open(filepath.Join(basePath, stateFile)) + if err != nil { + return nil, err + } + defer f.Close() + + var state *State + if err := json.NewDecoder(f).Decode(&state); err != nil { + return nil, err + } + + return state, nil +} + +// DeleteState deletes the state.json file +func DeleteState(basePath string) error { + return os.Remove(filepath.Join(basePath, stateFile)) +} diff --git a/vendor/src/github.com/docker/libcontainer/types.go b/vendor/src/github.com/docker/libcontainer/types.go new file mode 100644 index 000000000..5095dca66 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/types.go @@ -0,0 +1,11 @@ +package libcontainer + +import ( + "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/network" +) + +type ContainerStats struct { + NetworkStats network.NetworkStats `json:"network_stats, omitempty"` + CgroupStats *cgroups.Stats `json:"cgroup_stats, omitempty"` +} From c9fdb08bdafb90b76cfa804b079d2e446a3503e4 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 26 Jun 2014 12:23:53 -0700 Subject: [PATCH 103/167] Update libcontainer Context changes Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/configuration/parse.go | 2 +- daemon/execdriver/native/configuration/parse_test.go | 5 +++-- daemon/execdriver/native/create.go | 10 +++++----- daemon/execdriver/native/template/default_template.go | 3 +-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/daemon/execdriver/native/configuration/parse.go b/daemon/execdriver/native/configuration/parse.go index a923f2a3c..8fb1b452b 100644 --- a/daemon/execdriver/native/configuration/parse.go +++ b/daemon/execdriver/native/configuration/parse.go @@ -54,7 +54,7 @@ func systemdSlice(container *libcontainer.Config, context interface{}, value str } func apparmorProfile(container *libcontainer.Config, context interface{}, value string) error { - container.Context["apparmor_profile"] = value + container.AppArmorProfile = value return nil } diff --git a/daemon/execdriver/native/configuration/parse_test.go b/daemon/execdriver/native/configuration/parse_test.go index 886a42cf8..0401d7b37 100644 --- a/daemon/execdriver/native/configuration/parse_test.go +++ b/daemon/execdriver/native/configuration/parse_test.go @@ -84,8 +84,9 @@ func TestAppArmorProfile(t *testing.T) { if err := ParseConfiguration(container, nil, opts); err != nil { t.Fatal(err) } - if expected := "koye-the-protector"; container.Context["apparmor_profile"] != expected { - t.Fatalf("expected profile %s got %s", expected, container.Context["apparmor_profile"]) + + if expected := "koye-the-protector"; container.AppArmorProfile != expected { + t.Fatalf("expected profile %s got %s", expected, container.AppArmorProfile) } } diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index e577bd2b8..f28507b04 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -32,7 +32,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e // check to see if we are running in ramdisk to disable pivot root container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" - container.Context["restrictions"] = "true" + container.RestrictSys = true if err := d.createNetwork(container, c); err != nil { return nil, err @@ -127,10 +127,10 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) { } container.MountConfig.DeviceNodes = hostDeviceNodes - delete(container.Context, "restrictions") + container.RestrictSys = false if apparmor.IsEnabled() { - container.Context["apparmor_profile"] = "unconfined" + container.AppArmorProfile = "unconfined" } return nil @@ -163,8 +163,8 @@ func (d *driver) setupMounts(container *libcontainer.Config, c *execdriver.Comma } func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error { - container.Context["process_label"] = c.Config["process_label"][0] - container.Context["mount_label"] = c.Config["mount_label"][0] + container.ProcessLabel = c.Config["process_label"][0] + container.MountConfig.MountLabel = c.Config["mount_label"][0] return nil } diff --git a/daemon/execdriver/native/template/default_template.go b/daemon/execdriver/native/template/default_template.go index 5dbcbb558..d0894a0c9 100644 --- a/daemon/execdriver/native/template/default_template.go +++ b/daemon/execdriver/native/template/default_template.go @@ -35,11 +35,10 @@ func New() *libcontainer.Config { AllowAllDevices: false, }, MountConfig: &libcontainer.MountConfig{}, - Context: make(map[string]string), } if apparmor.IsEnabled() { - container.Context["apparmor_profile"] = "docker-default" + container.AppArmorProfile = "docker-default" } return container From 012091a28f8c2a96ad937f8c84992687e804ab71 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Thu, 26 Jun 2014 17:09:41 -0700 Subject: [PATCH 104/167] Fix sleep command in tests Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- integration-cli/docker_cli_diff_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-cli/docker_cli_diff_test.go b/integration-cli/docker_cli_diff_test.go index 478ebd2df..416f9421b 100644 --- a/integration-cli/docker_cli_diff_test.go +++ b/integration-cli/docker_cli_diff_test.go @@ -66,7 +66,7 @@ func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) { } func TestDiffEnsureOnlyKmsgAndPtmx(t *testing.T) { - runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep 0") + runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep", "0") cid, _, err := runCommandWithOutput(runCmd) errorOut(err, t, fmt.Sprintf("%s", err)) cleanCID := stripTrailingCharacters(cid) From e817681581f433b37a8ab214a73edf5fb2a35473 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Fri, 27 Jun 2014 11:10:20 +1000 Subject: [PATCH 105/167] Yes, ok, not-Sam Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/sources/docker-hub/accounts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/docker-hub/accounts.md b/docs/sources/docker-hub/accounts.md index 7e951448d..304010fb5 100644 --- a/docs/sources/docker-hub/accounts.md +++ b/docs/sources/docker-hub/accounts.md @@ -36,8 +36,8 @@ page. Also available on the Docker Hub are organizations and groups that allow you to collaborate across your organization or team. You can see what -organizations [you belong to and add new organizations](Sam Alba -) from the Account +organizations [you belong to and add new organizations]( +https://hub.docker.com/account/organizations/) from the Account tab. ![organizations](/docker-hub/orgs.png) From 748aaf3530b943449d61952e06eb9aeab4a455ac Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Thu, 26 Jun 2014 11:49:29 +0100 Subject: [PATCH 106/167] Remove superfluous reptition from usingdocker.md Clarify wording about default docker ps options Fix typo in dockerlinks.md Docker-DCO-1.1-Signed-off-by: Paul Weaver (github: ch3pjw) --- docs/sources/userguide/dockerlinks.md | 2 +- docs/sources/userguide/usingdocker.md | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md index d928cc140..711fd979c 100644 --- a/docs/sources/userguide/dockerlinks.md +++ b/docs/sources/userguide/dockerlinks.md @@ -192,7 +192,7 @@ command to list the container's environment variables. > will scrub them when spawning shells for connection. We can see that Docker has created a series of environment variables with -useful information about our `db` container. Each variables is prefixed with +useful information about our `db` container. Each variable is prefixed with `DB_` which is populated from the `alias` we specified above. If our `alias` were `db1` the variables would be prefixed with `DB1_`. You can use these environment variables to configure your applications to connect to the database diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index 54c094bfa..c1f524f89 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -87,11 +87,6 @@ This will display the help text and all available flags: --no-stdin=false: Do not attach stdin --sig-proxy=true: Proxify all received signal to the process (even in non-tty mode) - -None of the containers we've run did anything particularly useful -though. So let's build on that experience by running an example web -application in Docker. - > **Note:** > You can see a full list of Docker's commands > [here](/reference/commandline/cli/). @@ -140,8 +135,8 @@ command. This tells the `docker ps` command to return the details of the *last* container started. > **Note:** -> The `docker ps` command only shows running containers. If you want to -> see stopped containers too use the `-a` flag. +> By default, the `docker ps` command only shows information about running +> containers. If you want to see stopped containers too use the `-a` flag. We can see the same details we saw [when we first Dockerized a container](/userguide/dockerizing) with one important addition in the `PORTS` From d14cfc8d435dbef0d70b6444b275a025e60ac171 Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Fri, 16 May 2014 16:40:27 -0700 Subject: [PATCH 107/167] sort flags with the same name in a consistent order Docker-DCO-1.1-Signed-off-by: Jonathan Boulle (github: jonboulle) --- pkg/mflag/flag.go | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/pkg/mflag/flag.go b/pkg/mflag/flag.go index ad23e540f..52f786e45 100644 --- a/pkg/mflag/flag.go +++ b/pkg/mflag/flag.go @@ -305,12 +305,10 @@ type flagSlice []string func (p flagSlice) Len() int { return len(p) } func (p flagSlice) Less(i, j int) bool { - pi, pj := strings.ToLower(p[i]), strings.ToLower(p[j]) - if pi[0] == '-' { - pi = pi[1:] - } - if pj[0] == '-' { - pj = pj[1:] + pi, pj := strings.TrimPrefix(p[i], "-"), strings.TrimPrefix(p[j], "-") + lpi, lpj := strings.ToLower(pi), strings.ToLower(pj) + if lpi != lpj { + return lpi < lpj } return pi < pj } @@ -443,8 +441,6 @@ func (f *FlagSet) PrintDefaults() { } fmt.Fprintln(writer, "\t", line) } - // start := fmt.Sprintf(format, strings.Join(names, ", -"), flag.DefValue) - // fmt.Fprintln(f.out(), start, strings.Replace(flag.Usage, "\n", "\n"+strings.Repeat(" ", len(start)+1), -1)) } }) writer.Flush() @@ -833,14 +829,12 @@ func (f *FlagSet) parseOne() (bool, string, error) { f.args = f.args[1:] has_value := false value := "" - for i := 1; i < len(name); i++ { // equals cannot be first - if name[i] == '=' { - value = trimQuotes(name[i+1:]) - has_value = true - name = name[0:i] - break - } + if i := strings.Index(name, "="); i != -1 { + value = trimQuotes(name[i+1:]) + has_value = true + name = name[:i] } + m := f.formal flag, alreadythere := m[name] // BUG if !alreadythere { From 15ea1ca1f0d5190645b2ec0c0971daa3cdee30df Mon Sep 17 00:00:00 2001 From: leeplay Date: Fri, 27 Jun 2014 11:39:58 +0900 Subject: [PATCH 108/167] Update nodejs_web_app.md Docker-DCO-1.1-Signed-off-by: Hyeongkyu Lee (github: leeplay) --- docs/sources/examples/nodejs_web_app.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/examples/nodejs_web_app.md b/docs/sources/examples/nodejs_web_app.md index cc3ea061a..5fb0300f5 100644 --- a/docs/sources/examples/nodejs_web_app.md +++ b/docs/sources/examples/nodejs_web_app.md @@ -167,8 +167,8 @@ To test your app, get the the port of your app that Docker mapped: $ sudo docker ps # Example - ID IMAGE COMMAND ... PORTS - ecce33b30ebf gasi/centos-node-hello:latest node /src/index.js 49160->8080 + ID IMAGE COMMAND ... PORTS + ecce33b30ebf /centos-node-hello:latest node /src/index.js 49160->8080 In the example above, Docker mapped the `8080` port of the container to `49160`. From 0bfa14a70aa7dda06d769c5dd55354b13b417c94 Mon Sep 17 00:00:00 2001 From: Mike Chelen Date: Fri, 27 Jun 2014 02:34:47 -0400 Subject: [PATCH 109/167] Update dockerizing.md fix typo --- docs/sources/userguide/dockerizing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerizing.md b/docs/sources/userguide/dockerizing.md index afe18ce8d..ed927df08 100644 --- a/docs/sources/userguide/dockerizing.md +++ b/docs/sources/userguide/dockerizing.md @@ -131,7 +131,7 @@ world` daemon. Firstly let's make sure our container is running. We can do that with the `docker ps` command. The `docker ps` command queries -the Docker daemon for information about all the container it knows +the Docker daemon for information about all the containers it knows about. $ sudo docker ps From 47065b904559f36e83b924007c375f2de0f31af0 Mon Sep 17 00:00:00 2001 From: Alexandr Morozov Date: Fri, 6 Jun 2014 15:28:12 +0400 Subject: [PATCH 110/167] State refactoring and add waiting functions Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- daemon/state.go | 115 ++++++++++++++++++++++++++++++++++--------- daemon/state_test.go | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 23 deletions(-) create mode 100644 daemon/state_test.go diff --git a/daemon/state.go b/daemon/state.go index 7ee8fc48c..b9ef35056 100644 --- a/daemon/state.go +++ b/daemon/state.go @@ -16,6 +16,13 @@ type State struct { ExitCode int StartedAt time.Time FinishedAt time.Time + waitChan chan struct{} +} + +func NewState() *State { + return &State{ + waitChan: make(chan struct{}), + } } // String returns a human-readable description of the state @@ -35,56 +42,118 @@ func (s *State) String() string { return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) } +func wait(waitChan <-chan struct{}, timeout time.Duration) error { + if timeout < 0 { + <-waitChan + return nil + } + select { + case <-time.After(timeout): + return fmt.Errorf("Timed out: %v", timeout) + case <-waitChan: + return nil + } +} + +// WaitRunning waits until state is running. If state already running it returns +// immediatly. If you want wait forever you must supply negative timeout. +// Returns pid, that was passed to SetRunning +func (s *State) WaitRunning(timeout time.Duration) (int, error) { + s.RLock() + if s.IsRunning() { + pid := s.Pid + s.RUnlock() + return pid, nil + } + waitChan := s.waitChan + s.RUnlock() + if err := wait(waitChan, timeout); err != nil { + return -1, err + } + return s.GetPid(), nil +} + +// WaitStop waits until state is stopped. If state already stopped it returns +// immediatly. If you want wait forever you must supply negative timeout. +// Returns exit code, that was passed to SetRunning +func (s *State) WaitStop(timeout time.Duration) (int, error) { + s.RLock() + if !s.Running { + exitCode := s.ExitCode + s.RUnlock() + return exitCode, nil + } + waitChan := s.waitChan + s.RUnlock() + if err := wait(waitChan, timeout); err != nil { + return -1, err + } + return s.GetExitCode(), nil +} + func (s *State) IsRunning() bool { s.RLock() - defer s.RUnlock() + res := s.Running + s.RUnlock() + return res +} - return s.Running +func (s *State) GetPid() int { + s.RLock() + res := s.Pid + s.RUnlock() + return res } func (s *State) GetExitCode() int { s.RLock() - defer s.RUnlock() - - return s.ExitCode + res := s.ExitCode + s.RUnlock() + return res } func (s *State) SetRunning(pid int) { s.Lock() - defer s.Unlock() - - s.Running = true - s.Paused = false - s.ExitCode = 0 - s.Pid = pid - s.StartedAt = time.Now().UTC() + if !s.Running { + s.Running = true + s.Paused = false + s.ExitCode = 0 + s.Pid = pid + s.StartedAt = time.Now().UTC() + close(s.waitChan) // fire waiters for start + s.waitChan = make(chan struct{}) + } + s.Unlock() } func (s *State) SetStopped(exitCode int) { s.Lock() - defer s.Unlock() - - s.Running = false - s.Pid = 0 - s.FinishedAt = time.Now().UTC() - s.ExitCode = exitCode + if s.Running { + s.Running = false + s.Pid = 0 + s.FinishedAt = time.Now().UTC() + s.ExitCode = exitCode + close(s.waitChan) // fire waiters for stop + s.waitChan = make(chan struct{}) + } + s.Unlock() } func (s *State) SetPaused() { s.Lock() - defer s.Unlock() s.Paused = true + s.Unlock() } func (s *State) SetUnpaused() { s.Lock() - defer s.Unlock() s.Paused = false + s.Unlock() } func (s *State) IsPaused() bool { s.RLock() - defer s.RUnlock() - - return s.Paused + res := s.Paused + s.RUnlock() + return res } diff --git a/daemon/state_test.go b/daemon/state_test.go new file mode 100644 index 000000000..7b02f3aea --- /dev/null +++ b/daemon/state_test.go @@ -0,0 +1,102 @@ +package daemon + +import ( + "sync/atomic" + "testing" + "time" +) + +func TestStateRunStop(t *testing.T) { + s := NewState() + for i := 1; i < 3; i++ { // full lifecycle two times + started := make(chan struct{}) + var pid int64 + go func() { + runPid, _ := s.WaitRunning(-1 * time.Second) + atomic.StoreInt64(&pid, int64(runPid)) + close(started) + }() + s.SetRunning(i + 100) + if !s.IsRunning() { + t.Fatal("State not running") + } + if s.Pid != i+100 { + t.Fatalf("Pid %v, expected %v", s.Pid, i+100) + } + if s.ExitCode != 0 { + t.Fatalf("ExitCode %v, expected 0", s.ExitCode) + } + select { + case <-time.After(100 * time.Millisecond): + t.Fatal("Start callback doesn't fire in 100 milliseconds") + case <-started: + t.Log("Start callback fired") + } + runPid := int(atomic.LoadInt64(&pid)) + if runPid != i+100 { + t.Fatalf("Pid %v, expected %v", runPid, i+100) + } + if pid, err := s.WaitRunning(-1 * time.Second); err != nil || pid != i+100 { + t.Fatal("WaitRunning returned pid: %v, err: %v, expected pid: %v, err: %v", pid, err, i+100, nil) + } + + stopped := make(chan struct{}) + var exit int64 + go func() { + exitCode, _ := s.WaitStop(-1 * time.Second) + atomic.StoreInt64(&exit, int64(exitCode)) + close(stopped) + }() + s.SetStopped(i) + if s.IsRunning() { + t.Fatal("State is running") + } + if s.ExitCode != i { + t.Fatalf("ExitCode %v, expected %v", s.ExitCode, i) + } + if s.Pid != 0 { + t.Fatalf("Pid %v, expected 0", s.Pid) + } + select { + case <-time.After(100 * time.Millisecond): + t.Fatal("Stop callback doesn't fire in 100 milliseconds") + case <-stopped: + t.Log("Stop callback fired") + } + exitCode := int(atomic.LoadInt64(&exit)) + if exitCode != i { + t.Fatalf("ExitCode %v, expected %v", exitCode, i) + } + if exitCode, err := s.WaitStop(-1 * time.Second); err != nil || exitCode != i { + t.Fatal("WaitStop returned exitCode: %v, err: %v, expected exitCode: %v, err: %v", exitCode, err, i, nil) + } + } +} + +func TestStateTimeoutWait(t *testing.T) { + s := NewState() + started := make(chan struct{}) + go func() { + s.WaitRunning(100 * time.Millisecond) + close(started) + }() + select { + case <-time.After(200 * time.Millisecond): + t.Fatal("Start callback doesn't fire in 100 milliseconds") + case <-started: + t.Log("Start callback fired") + } + s.SetRunning(42) + stopped := make(chan struct{}) + go func() { + s.WaitRunning(100 * time.Millisecond) + close(stopped) + }() + select { + case <-time.After(200 * time.Millisecond): + t.Fatal("Start callback doesn't fire in 100 milliseconds") + case <-stopped: + t.Log("Start callback fired") + } + +} From 57d86a5619adae5e08e0e28fba99f6a7c2f5ee54 Mon Sep 17 00:00:00 2001 From: Alexandr Morozov Date: Fri, 6 Jun 2014 15:30:04 +0400 Subject: [PATCH 111/167] Use State waiting functions Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- daemon/container.go | 75 +++++++++++------------------------ daemon/daemon.go | 11 ++--- daemon/state.go | 2 +- integration/commands_test.go | 8 ++-- integration/container_test.go | 15 +++---- integration/runtime_test.go | 4 +- integration/utils_test.go | 8 ++-- server/buildfile.go | 3 +- server/server.go | 4 +- 9 files changed, 51 insertions(+), 79 deletions(-) diff --git a/daemon/container.go b/daemon/container.go index d9c809cee..5b4143868 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -53,7 +53,7 @@ type Container struct { Args []string Config *runconfig.Config - State State + State *State Image string NetworkSettings *NetworkSettings @@ -74,8 +74,7 @@ type Container struct { daemon *Daemon MountLabel, ProcessLabel string - waitLock chan struct{} - Volumes map[string]string + Volumes map[string]string // Store rw/ro in a separate structure to preserve reverse-compatibility on-disk. // Easier than migrating older container configs :) VolumesRW map[string]bool @@ -284,7 +283,6 @@ func (container *Container) Start() (err error) { if err := container.startLoggingToDisk(); err != nil { return err } - container.waitLock = make(chan struct{}) return container.waitForStart() } @@ -293,7 +291,7 @@ func (container *Container) Run() error { if err := container.Start(); err != nil { return err } - container.Wait() + container.State.WaitStop(-1 * time.Second) return nil } @@ -307,7 +305,7 @@ func (container *Container) Output() (output []byte, err error) { return nil, err } output, err = ioutil.ReadAll(pipe) - container.Wait() + container.State.WaitStop(-1 * time.Second) return output, err } @@ -467,6 +465,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { if err != nil { utils.Errorf("Error running container: %s", err) } + container.State.SetStopped(exitCode) // Cleanup container.cleanup() @@ -475,28 +474,17 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { if container.Config.OpenStdin { container.stdin, container.stdinPipe = io.Pipe() } - if container.daemon != nil && container.daemon.srv != nil { container.daemon.srv.LogEvent("die", container.ID, container.daemon.repositories.ImageName(container.Image)) } - - close(container.waitLock) - if container.daemon != nil && container.daemon.srv != nil && container.daemon.srv.IsRunning() { - container.State.SetStopped(exitCode) - - // FIXME: there is a race condition here which causes this to fail during the unit tests. - // If another goroutine was waiting for Wait() to return before removing the container's root - // from the filesystem... At this point it may already have done so. - // This is because State.setStopped() has already been called, and has caused Wait() - // to return. - // FIXME: why are we serializing running state to disk in the first place? - //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err) + // FIXME: here is race condition between two RUN instructions in Dockerfile + // because they share same runconfig and change image. Must be fixed + // in server/buildfile.go if err := container.ToDisk(); err != nil { - utils.Errorf("Error dumping container state to disk: %s\n", err) + utils.Errorf("Error dumping container %s state to disk: %s\n", container.ID, err) } } - return err } @@ -532,6 +520,7 @@ func (container *Container) cleanup() { } func (container *Container) KillSig(sig int) error { + utils.Debugf("Sending %d to %s", sig, container.ID) container.Lock() defer container.Unlock() @@ -577,9 +566,9 @@ func (container *Container) Kill() error { } // 2. Wait for the process to die, in last resort, try to kill the process directly - if err := container.WaitTimeout(10 * time.Second); err != nil { + if _, err := container.State.WaitStop(10 * time.Second); err != nil { // Ensure that we don't kill ourselves - if pid := container.State.Pid; pid != 0 { + if pid := container.State.GetPid(); pid != 0 { log.Printf("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID)) if err := syscall.Kill(pid, 9); err != nil { return err @@ -587,7 +576,7 @@ func (container *Container) Kill() error { } } - container.Wait() + container.State.WaitStop(-1 * time.Second) return nil } @@ -605,11 +594,11 @@ func (container *Container) Stop(seconds int) error { } // 2. Wait for the process to exit on its own - if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil { + if _, err := container.State.WaitStop(time.Duration(seconds) * time.Second); err != nil { log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds) // 3. If it doesn't, then send SIGKILL if err := container.Kill(); err != nil { - container.Wait() + container.State.WaitStop(-1 * time.Second) return err } } @@ -630,12 +619,6 @@ func (container *Container) Restart(seconds int) error { return container.Start() } -// Wait blocks until the container stops running, then returns its exit code. -func (container *Container) Wait() int { - <-container.waitLock - return container.State.GetExitCode() -} - func (container *Container) Resize(h, w int) error { return container.command.Terminal.Resize(h, w) } @@ -678,21 +661,6 @@ func (container *Container) Export() (archive.Archive, error) { nil } -func (container *Container) WaitTimeout(timeout time.Duration) error { - done := make(chan bool, 1) - go func() { - container.Wait() - done <- true - }() - - select { - case <-time.After(timeout): - return fmt.Errorf("Timed Out") - case <-done: - return nil - } -} - func (container *Container) Mount() error { return container.daemon.Mount(container) } @@ -1103,9 +1071,7 @@ func (container *Container) startLoggingToDisk() error { } func (container *Container) waitForStart() error { - callbackLock := make(chan struct{}) callback := func(command *execdriver.Command) { - container.State.SetRunning(command.Pid()) if command.Tty { // The callback is called after the process Start() // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace @@ -1117,16 +1083,23 @@ func (container *Container) waitForStart() error { if err := container.ToDisk(); err != nil { utils.Debugf("%s", err) } - close(callbackLock) + container.State.SetRunning(command.Pid()) } // We use a callback here instead of a goroutine and an chan for // syncronization purposes cErr := utils.Go(func() error { return container.monitor(callback) }) + waitStart := make(chan struct{}) + + go func() { + container.State.WaitRunning(-1 * time.Second) + close(waitStart) + }() + // Start should not return until the process is actually running select { - case <-callbackLock: + case <-waitStart: case err := <-cErr: return err } diff --git a/daemon/daemon.go b/daemon/daemon.go index 3536678d2..aa8d2bad3 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -138,7 +138,7 @@ func (daemon *Daemon) containerRoot(id string) string { // Load reads the contents of a container from disk // This is typically done at startup. func (daemon *Daemon) load(id string) (*Container, error) { - container := &Container{root: daemon.containerRoot(id)} + container := &Container{root: daemon.containerRoot(id), State: NewState()} if err := container.FromDisk(); err != nil { return nil, err } @@ -236,12 +236,6 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool, con } } } - } else { - // When the container is not running, we still initialize the waitLock - // chan and close it. Receiving on nil chan blocks whereas receiving on a - // closed chan does not. In this case we do not want to block. - container.waitLock = make(chan struct{}) - close(container.waitLock) } return nil } @@ -588,6 +582,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i Name: name, Driver: daemon.driver.String(), ExecDriver: daemon.execDriver.Name(), + State: NewState(), } container.root = daemon.containerRoot(container.ID) @@ -900,7 +895,7 @@ func (daemon *Daemon) shutdown() error { if err := c.KillSig(15); err != nil { utils.Debugf("kill 15 error for %s - %s", c.ID, err) } - c.Wait() + c.State.WaitStop(-1 * time.Second) utils.Debugf("container stopped %s", c.ID) }() } diff --git a/daemon/state.go b/daemon/state.go index b9ef35056..3f904d782 100644 --- a/daemon/state.go +++ b/daemon/state.go @@ -75,7 +75,7 @@ func (s *State) WaitRunning(timeout time.Duration) (int, error) { // WaitStop waits until state is stopped. If state already stopped it returns // immediatly. If you want wait forever you must supply negative timeout. -// Returns exit code, that was passed to SetRunning +// Returns exit code, that was passed to SetStopped func (s *State) WaitStop(timeout time.Duration) (int, error) { s.RLock() if !s.Running { diff --git a/integration/commands_test.go b/integration/commands_test.go index 55c822bbe..47e986005 100644 --- a/integration/commands_test.go +++ b/integration/commands_test.go @@ -224,7 +224,7 @@ func TestRunDisconnect(t *testing.T) { // cause /bin/cat to exit. setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() { container := globalDaemon.List()[0] - container.Wait() + container.State.WaitStop(-1 * time.Second) if container.State.IsRunning() { t.Fatalf("/bin/cat is still running after closing stdin") } @@ -276,7 +276,7 @@ func TestRunDisconnectTty(t *testing.T) { // In tty mode, we expect the process to stay alive even after client's stdin closes. // Give some time to monitor to do his thing - container.WaitTimeout(500 * time.Millisecond) + container.State.WaitStop(500 * time.Millisecond) if !container.State.IsRunning() { t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)") } @@ -535,7 +535,7 @@ func TestAttachDisconnect(t *testing.T) { // We closed stdin, expect /bin/cat to still be running // Wait a little bit to make sure container.monitor() did his thing - err := container.WaitTimeout(500 * time.Millisecond) + _, err := container.State.WaitStop(500 * time.Millisecond) if err == nil || !container.State.IsRunning() { t.Fatalf("/bin/cat is not running after closing stdin") } @@ -543,7 +543,7 @@ func TestAttachDisconnect(t *testing.T) { // Try to avoid the timeout in destroy. Best effort, don't check error cStdin, _ := container.StdinPipe() cStdin.Close() - container.Wait() + container.State.WaitStop(-1 * time.Second) } // Expected behaviour: container gets deleted automatically after exit diff --git a/integration/container_test.go b/integration/container_test.go index 8fe52a3cd..31a57df77 100644 --- a/integration/container_test.go +++ b/integration/container_test.go @@ -2,7 +2,6 @@ package docker import ( "fmt" - "github.com/dotcloud/docker/runconfig" "io" "io/ioutil" "os" @@ -10,6 +9,8 @@ import ( "strings" "testing" "time" + + "github.com/dotcloud/docker/runconfig" ) func TestKillDifferentUser(t *testing.T) { @@ -60,7 +61,7 @@ func TestKillDifferentUser(t *testing.T) { if container.State.IsRunning() { t.Errorf("Container shouldn't be running") } - container.Wait() + container.State.WaitStop(-1 * time.Second) if container.State.IsRunning() { t.Errorf("Container shouldn't be running") } @@ -134,7 +135,7 @@ func TestRestartStdin(t *testing.T) { if err := stdin.Close(); err != nil { t.Fatal(err) } - container.Wait() + container.State.WaitStop(-1 * time.Second) output, err := ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) @@ -164,7 +165,7 @@ func TestRestartStdin(t *testing.T) { if err := stdin.Close(); err != nil { t.Fatal(err) } - container.Wait() + container.State.WaitStop(-1 * time.Second) output, err = ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) @@ -212,7 +213,7 @@ func TestStdin(t *testing.T) { if err := stdin.Close(); err != nil { t.Fatal(err) } - container.Wait() + container.State.WaitStop(-1 * time.Second) output, err := ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) @@ -257,7 +258,7 @@ func TestTty(t *testing.T) { if err := stdin.Close(); err != nil { t.Fatal(err) } - container.Wait() + container.State.WaitStop(-1 * time.Second) output, err := ioutil.ReadAll(stdout) if err != nil { t.Fatal(err) @@ -366,7 +367,7 @@ func BenchmarkRunParallel(b *testing.B) { complete <- err return } - if err := container.WaitTimeout(15 * time.Second); err != nil { + if _, err := container.State.WaitStop(15 * time.Second); err != nil { complete <- err return } diff --git a/integration/runtime_test.go b/integration/runtime_test.go index 96df15be6..754146c5f 100644 --- a/integration/runtime_test.go +++ b/integration/runtime_test.go @@ -496,7 +496,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daem }) // Even if the state is running, lets give some time to lxc to spawn the process - container.WaitTimeout(500 * time.Millisecond) + container.State.WaitStop(500 * time.Millisecond) strPort = container.NetworkSettings.Ports[p][0].HostPort return daemon, container, strPort @@ -611,7 +611,7 @@ func TestRestore(t *testing.T) { // Simulate a crash/manual quit of dockerd: process dies, states stays 'Running' cStdin, _ := container2.StdinPipe() cStdin.Close() - if err := container2.WaitTimeout(2 * time.Second); err != nil { + if _, err := container2.State.WaitStop(2 * time.Second); err != nil { t.Fatal(err) } container2.State.SetRunning(42) diff --git a/integration/utils_test.go b/integration/utils_test.go index d8101dfb1..7be7f13ee 100644 --- a/integration/utils_test.go +++ b/integration/utils_test.go @@ -96,11 +96,13 @@ func containerAttach(eng *engine.Engine, id string, t utils.Fataler) (io.WriteCl } func containerWait(eng *engine.Engine, id string, t utils.Fataler) int { - return getContainer(eng, id, t).Wait() + ex, _ := getContainer(eng, id, t).State.WaitStop(-1 * time.Second) + return ex } func containerWaitTimeout(eng *engine.Engine, id string, t utils.Fataler) error { - return getContainer(eng, id, t).WaitTimeout(500 * time.Millisecond) + _, err := getContainer(eng, id, t).State.WaitStop(500 * time.Millisecond) + return err } func containerKill(eng *engine.Engine, id string, t utils.Fataler) { @@ -307,7 +309,7 @@ func runContainer(eng *engine.Engine, r *daemon.Daemon, args []string, t *testin return "", err } - container.Wait() + container.State.WaitStop(-1 * time.Second) data, err := ioutil.ReadAll(stdout) if err != nil { return "", err diff --git a/server/buildfile.go b/server/buildfile.go index f10cc0dbc..f5ef6e0d2 100644 --- a/server/buildfile.go +++ b/server/buildfile.go @@ -17,6 +17,7 @@ import ( "sort" "strings" "syscall" + "time" "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/daemon" @@ -696,7 +697,7 @@ func (b *buildFile) run(c *daemon.Container) error { } // Wait for it to finish - if ret := c.Wait(); ret != 0 { + if ret, _ := c.State.WaitStop(-1 * time.Second); ret != 0 { err := &utils.JSONError{ Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.config.Cmd, ret), Code: ret, diff --git a/server/server.go b/server/server.go index fa695adfe..164102317 100644 --- a/server/server.go +++ b/server/server.go @@ -2123,7 +2123,7 @@ func (srv *Server) ContainerWait(job *engine.Job) engine.Status { } name := job.Args[0] if container := srv.daemon.Get(name); container != nil { - status := container.Wait() + status, _ := container.State.WaitStop(-1 * time.Second) job.Printf("%d\n", status) return engine.StatusOK } @@ -2336,7 +2336,7 @@ func (srv *Server) ContainerAttach(job *engine.Job) engine.Status { // If we are in stdinonce mode, wait for the process to end // otherwise, simply return if container.Config.StdinOnce && !container.Config.Tty { - container.Wait() + container.State.WaitStop(-1 * time.Second) } } return engine.StatusOK From 287e604a8f53e569d355b1b6c75f6736f4927281 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Fri, 27 Jun 2014 14:43:12 +0200 Subject: [PATCH 112/167] mkimage: use /var/tmp by default instead of /tmp Additionally, this can be overridden by setting the TMPDIR variable, like this was already the case for the generic `mkimage.sh` script. As explained in #6456, the rationale to use `/var/tmp` instead of `/tmp` is that `/tmp` is often a small tmpfs filesystem with more restricted rights. Docker-DCO-1.1-Signed-off-by: Vincent Bernat (github: vincentbernat) --- contrib/mkimage-alpine.sh | 4 ++-- contrib/mkimage-arch.sh | 2 +- contrib/mkimage-busybox.sh | 2 +- contrib/mkimage-crux.sh | 6 +++--- contrib/mkimage-debootstrap.sh | 2 +- contrib/mkimage-rinse.sh | 2 +- contrib/mkimage-unittest.sh | 2 +- contrib/mkimage.sh | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/contrib/mkimage-alpine.sh b/contrib/mkimage-alpine.sh index 7444ffafb..0bf328efa 100755 --- a/contrib/mkimage-alpine.sh +++ b/contrib/mkimage-alpine.sh @@ -13,8 +13,8 @@ usage() { } tmp() { - TMP=$(mktemp -d /tmp/alpine-docker-XXXXXXXXXX) - ROOTFS=$(mktemp -d /tmp/alpine-docker-rootfs-XXXXXXXXXX) + TMP=$(mktemp -d ${TMPDIR:-/var/tmp}/alpine-docker-XXXXXXXXXX) + ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/alpine-docker-rootfs-XXXXXXXXXX) trap "rm -rf $TMP $ROOTFS" EXIT TERM INT } diff --git a/contrib/mkimage-arch.sh b/contrib/mkimage-arch.sh index dc2106747..27c6ac6a3 100755 --- a/contrib/mkimage-arch.sh +++ b/contrib/mkimage-arch.sh @@ -14,7 +14,7 @@ hash expect &>/dev/null || { exit 1 } -ROOTFS=$(mktemp -d /tmp/rootfs-archlinux-XXXXXXXXXX) +ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-archlinux-XXXXXXXXXX) chmod 755 $ROOTFS # packages to ignore for space savings diff --git a/contrib/mkimage-busybox.sh b/contrib/mkimage-busybox.sh index cbaa56783..b11a6bb26 100755 --- a/contrib/mkimage-busybox.sh +++ b/contrib/mkimage-busybox.sh @@ -14,7 +14,7 @@ BUSYBOX=$(which busybox) } set -e -ROOTFS=/tmp/rootfs-busybox-$$-$RANDOM +ROOTFS=${TMPDIR:-/var/tmp}/rootfs-busybox-$$-$RANDOM mkdir $ROOTFS cd $ROOTFS diff --git a/contrib/mkimage-crux.sh b/contrib/mkimage-crux.sh index 074c334bb..3f0bdcae3 100755 --- a/contrib/mkimage-crux.sh +++ b/contrib/mkimage-crux.sh @@ -14,9 +14,9 @@ die () { ISO=${1} -ROOTFS=$(mktemp -d /tmp/rootfs-crux-XXXXXXXXXX) -CRUX=$(mktemp -d /tmp/crux-XXXXXXXXXX) -TMP=$(mktemp -d /tmp/XXXXXXXXXX) +ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-crux-XXXXXXXXXX) +CRUX=$(mktemp -d ${TMPDIR:-/var/tmp}/crux-XXXXXXXXXX) +TMP=$(mktemp -d ${TMPDIR:-/var/tmp}/XXXXXXXXXX) VERSION=$(basename --suffix=.iso $ISO | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') diff --git a/contrib/mkimage-debootstrap.sh b/contrib/mkimage-debootstrap.sh index 808f39354..0a3df140d 100755 --- a/contrib/mkimage-debootstrap.sh +++ b/contrib/mkimage-debootstrap.sh @@ -118,7 +118,7 @@ fi # will be filled in later, if [ -z "$skipDetection" ] lsbDist='' -target="/tmp/docker-rootfs-debootstrap-$suite-$$-$RANDOM" +target="${TMPDIR:-/var/tmp}/docker-rootfs-debootstrap-$suite-$$-$RANDOM" cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" returnTo="$(pwd -P)" diff --git a/contrib/mkimage-rinse.sh b/contrib/mkimage-rinse.sh index 0692ae179..69a8bc8fe 100755 --- a/contrib/mkimage-rinse.sh +++ b/contrib/mkimage-rinse.sh @@ -39,7 +39,7 @@ if [ ! "$repo" ] || [ ! "$distro" ]; then exit 1 fi -target="/tmp/docker-rootfs-rinse-$distro-$$-$RANDOM" +target="${TMPDIR:-/var/tmp}/docker-rootfs-rinse-$distro-$$-$RANDOM" cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" returnTo="$(pwd -P)" diff --git a/contrib/mkimage-unittest.sh b/contrib/mkimage-unittest.sh index a33f23884..feebb17b0 100755 --- a/contrib/mkimage-unittest.sh +++ b/contrib/mkimage-unittest.sh @@ -15,7 +15,7 @@ SOCAT=$(which socat) shopt -s extglob set -ex -ROOTFS=`mktemp -d /tmp/rootfs-busybox.XXXXXXXXXX` +ROOTFS=`mktemp -d ${TMPDIR:-/var/tmp}/rootfs-busybox.XXXXXXXXXX` trap "rm -rf $ROOTFS" INT QUIT TERM cd $ROOTFS diff --git a/contrib/mkimage.sh b/contrib/mkimage.sh index 522e9a284..803d1627d 100755 --- a/contrib/mkimage.sh +++ b/contrib/mkimage.sh @@ -50,7 +50,7 @@ fi delDir= if [ -z "$dir" ]; then - dir="$(mktemp -d ${TMPDIR:-/tmp}/docker-mkimage.XXXXXXXXXX)" + dir="$(mktemp -d ${TMPDIR:-/var/tmp}/docker-mkimage.XXXXXXXXXX)" delDir=1 fi From 2fcbfb5a66249739ef04d414307be01371190bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C5=BDupka?= Date: Fri, 27 Jun 2014 15:55:20 +0200 Subject: [PATCH 113/167] Adds check if default ip address is correct format. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It avoids hidden error when ports are redirected from container to host using -p host_port:guest_port. Docker-DCO-1.1-Signed-off-by: Jiří Župka (github: jzupka) --- docker/docker.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker/docker.go b/docker/docker.go index 6932d3277..30d43bc6a 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "log" + "net" "os" "runtime" "strings" @@ -99,6 +100,10 @@ func main() { log.Fatal("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.") } + if net.ParseIP(*flDefaultIp) == nil { + log.Fatalf("Specified --ip=%s is not in correct format \"0.0.0.0\".", *flDefaultIp) + } + if *flDebug { os.Setenv("DEBUG", "1") } From 4361366783bbb4c9e4bd87e1c16da5a0988ed0bd Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 25 Jun 2014 11:25:54 -0400 Subject: [PATCH 114/167] Document memory limit sizing in manpages The -m flag permits the setting of a memory limit when running a Docker container. The actual limit set must be a multiple of page size on Linux, so whatever number the uses passes in will be rounded up if needed. Document this behavior to prevent confusion. Also fixed several small formatting and grammar issues in the docker run manpage. Docker-DCO-1.1-Signed-off-by: Matthew Heon (github: mheon) --- docs/man/docker-run.1.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index 447d9e13c..2ef7f5048 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -103,8 +103,10 @@ container can be started with the **--link**. **-m**, **-memory**=*memory-limit* Allows you to constrain the memory available to a container. If the host supports swap memory, then the -m memory setting can be larger than physical -RAM. If a limit of 0 is specified, the container's memory is not limited. The -memory limit format: , where unit = b, k, m or g. +RAM. If a limit of 0 is specified, the container's memory is not limited. The +actual limit may be rounded up to a multiple of the operating system's page +size, if it is not already. The memory limit should be formatted as follows: +``, where unit = b, k, m or g. **-P**, **-publish-all**=*true*|*false* When set to true publish all exposed ports to the host interfaces. The From 815279c240e27478aa7ddde349761546a5c474fc Mon Sep 17 00:00:00 2001 From: Mike Chelen Date: Fri, 27 Jun 2014 11:09:09 -0400 Subject: [PATCH 115/167] Update dockerimages.md fix typo --- docs/sources/userguide/dockerimages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerimages.md b/docs/sources/userguide/dockerimages.md index b58be9044..ffcc39ddb 100644 --- a/docs/sources/userguide/dockerimages.md +++ b/docs/sources/userguide/dockerimages.md @@ -239,7 +239,7 @@ Let's create a directory and a `Dockerfile` first. $ cd sinatra $ touch Dockerfile -Each instructions creates a new layer of the image. Let's look at a simple +Each instruction creates a new layer of the image. Let's look at a simple example now for building our own Sinatra image for our development team. # This is a comment From a1b6f350e806c43225b724530e563d6ff66e6b8a Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 27 Jun 2014 19:49:40 +0300 Subject: [PATCH 116/167] correct typo - desination -> destination Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- runconfig/parse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runconfig/parse.go b/runconfig/parse.go index f057f311c..01662fd01 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -133,7 +133,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf for bind := range flVolumes.GetMap() { if arr := strings.Split(bind, ":"); len(arr) > 1 { if arr[1] == "/" { - return nil, nil, cmd, fmt.Errorf("Invalid bind mount: desination can't be '/'") + return nil, nil, cmd, fmt.Errorf("Invalid bind mount: destination can't be '/'") } // after creating the bind mount we want to delete it from the flVolumes values because // we do not want bind mounts being committed to image configs From 38b005ec69e62d93453ac4013fe6bfa2fccebc5d Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 27 Jun 2014 19:51:24 +0300 Subject: [PATCH 117/167] integcli: add test to ensure -v /:/ isn't allowed Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- integration-cli/docker_cli_run_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index a0c390306..eda1b3f0a 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -971,3 +971,15 @@ func TestAllowBindMountingRoot(t *testing.T) { logDone("run - bind mount / as volume") } + +func TestDisallowBindMountingRootToRoot(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-v", "/:/", "busybox", "ls", "/host") + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal(out, err) + } + + deleteAllContainers() + + logDone("run - bind mount /:/ as volume should fail") +} From dafddf461eeabd792d9ced6caced75ad6961c1d7 Mon Sep 17 00:00:00 2001 From: Arnaud Porterie Date: Thu, 19 Jun 2014 23:33:51 +0200 Subject: [PATCH 118/167] Restrict portallocator to Docker allocated ports Port allocation status is stored in a global map: a port detected in use will remain as such for the lifetime of the daemon. Change the behavior to only mark as allocated ports which are claimed by Docker itself (which we can trust to properly remove from the allocation map once released). Ports allocated by other applications will always be retried to account for the eventually of the port having been released. Docker-DCO-1.1-Signed-off-by: Arnaud Porterie (github: icecrime) --- daemon/networkdriver/bridge/driver.go | 78 ++++++------- daemon/networkdriver/bridge/driver_test.go | 106 ++++++++++++++++++ daemon/networkdriver/portmapper/mapper.go | 84 +++++++++++--- .../networkdriver/portmapper/mapper_test.go | 24 +++- 4 files changed, 227 insertions(+), 65 deletions(-) create mode 100644 daemon/networkdriver/bridge/driver_test.go diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index 8c5db9f84..8da7a0457 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -11,7 +11,6 @@ import ( "github.com/docker/libcontainer/netlink" "github.com/dotcloud/docker/daemon/networkdriver" "github.com/dotcloud/docker/daemon/networkdriver/ipallocator" - "github.com/dotcloud/docker/daemon/networkdriver/portallocator" "github.com/dotcloud/docker/daemon/networkdriver/portmapper" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/pkg/iptables" @@ -354,9 +353,6 @@ func Release(job *engine.Job) engine.Status { var ( id = job.Args[0] containerInterface = currentInterfaces.Get(id) - ip net.IP - port int - proto string ) if containerInterface == nil { @@ -367,22 +363,6 @@ func Release(job *engine.Job) engine.Status { if err := portmapper.Unmap(nat); err != nil { log.Printf("Unable to unmap port %s: %s", nat, err) } - - // this is host mappings - switch a := nat.(type) { - case *net.TCPAddr: - proto = "tcp" - ip = a.IP - port = a.Port - case *net.UDPAddr: - proto = "udp" - ip = a.IP - port = a.Port - } - - if err := portallocator.ReleasePort(ip, proto, port); err != nil { - log.Printf("Unable to release port %s", nat) - } } if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil { @@ -399,7 +379,7 @@ func AllocatePort(job *engine.Job) engine.Status { ip = defaultBindingIP id = job.Args[0] hostIP = job.Getenv("HostIP") - origHostPort = job.GetenvInt("HostPort") + hostPort = job.GetenvInt("HostPort") containerPort = job.GetenvInt("ContainerPort") proto = job.Getenv("Proto") network = currentInterfaces.Get(id) @@ -409,11 +389,16 @@ func AllocatePort(job *engine.Job) engine.Status { ip = net.ParseIP(hostIP) } - var ( - hostPort int - container net.Addr - host net.Addr - ) + // host ip, proto, and host port + var container net.Addr + switch proto { + case "tcp": + container = &net.TCPAddr{IP: network.IP, Port: containerPort} + case "udp": + container = &net.UDPAddr{IP: network.IP, Port: containerPort} + default: + return job.Errorf("unsupported address type %s", proto) + } /* Try up to 10 times to get a port that's not already allocated. @@ -421,27 +406,22 @@ func AllocatePort(job *engine.Job) engine.Status { In the event of failure to bind, return the error that portmapper.Map yields. */ + + var host net.Addr for i := 0; i < 10; i++ { - // host ip, proto, and host port - hostPort, err = portallocator.RequestPort(ip, proto, origHostPort) - - if err != nil { - return job.Error(err) - } - - if proto == "tcp" { - host = &net.TCPAddr{IP: ip, Port: hostPort} - container = &net.TCPAddr{IP: network.IP, Port: containerPort} - } else { - host = &net.UDPAddr{IP: ip, Port: hostPort} - container = &net.UDPAddr{IP: network.IP, Port: containerPort} - } - - if err = portmapper.Map(container, ip, hostPort); err == nil { + if host, err = portmapper.Map(container, ip, hostPort); err == nil { break } - job.Logf("Failed to bind %s:%d for container address %s:%d. Trying another port.", ip.String(), hostPort, network.IP.String(), containerPort) + // There is no point in immediately retrying to map an explicitely + // chosen port. + if hostPort != 0 { + job.Logf("Failed to bind %s for container address %s", host.String(), container.String()) + break + } + + // Automatically chosen 'free' port failed to bind: move on the next. + job.Logf("Failed to bind %s for container address %s. Trying another port.", host.String(), container.String()) } if err != nil { @@ -451,12 +431,18 @@ func AllocatePort(job *engine.Job) engine.Status { network.PortMappings = append(network.PortMappings, host) out := engine.Env{} - out.Set("HostIP", ip.String()) - out.SetInt("HostPort", hostPort) - + switch netAddr := host.(type) { + case *net.TCPAddr: + out.Set("HostIP", netAddr.IP.String()) + out.SetInt("HostPort", netAddr.Port) + case *net.UDPAddr: + out.Set("HostIP", netAddr.IP.String()) + out.SetInt("HostPort", netAddr.Port) + } if _, err := out.WriteTo(job.Stdout); err != nil { return job.Error(err) } + return engine.StatusOK } diff --git a/daemon/networkdriver/bridge/driver_test.go b/daemon/networkdriver/bridge/driver_test.go new file mode 100644 index 000000000..f8ddd4c64 --- /dev/null +++ b/daemon/networkdriver/bridge/driver_test.go @@ -0,0 +1,106 @@ +package bridge + +import ( + "fmt" + "net" + "strconv" + "testing" + + "github.com/dotcloud/docker/engine" +) + +func findFreePort(t *testing.T) int { + l, err := net.Listen("tcp", ":0") + if err != nil { + t.Fatal("Failed to find a free port") + } + defer l.Close() + + result, err := net.ResolveTCPAddr("tcp", l.Addr().String()) + if err != nil { + t.Fatal("Failed to resolve address to identify free port") + } + return result.Port +} + +func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) { + strPort := strconv.Itoa(port) + + job = eng.Job("allocate_port", "container_id") + job.Setenv("HostIP", "127.0.0.1") + job.Setenv("HostPort", strPort) + job.Setenv("Proto", "tcp") + job.Setenv("ContainerPort", strPort) + return +} + +func TestAllocatePortDetection(t *testing.T) { + eng := engine.New() + eng.Logging = false + + freePort := findFreePort(t) + + // Init driver + job := eng.Job("initdriver") + if res := InitDriver(job); res != engine.StatusOK { + t.Fatal("Failed to initialize network driver") + } + + // Allocate interface + job = eng.Job("allocate_interface", "container_id") + if res := Allocate(job); res != engine.StatusOK { + t.Fatal("Failed to allocate network interface") + } + + // Allocate same port twice, expect failure on second call + job = newPortAllocationJob(eng, freePort) + if res := AllocatePort(job); res != engine.StatusOK { + t.Fatal("Failed to find a free port to allocate") + } + if res := AllocatePort(job); res == engine.StatusOK { + t.Fatal("Duplicate port allocation granted by AllocatePort") + } +} + +func TestAllocatePortReclaim(t *testing.T) { + eng := engine.New() + eng.Logging = false + + freePort := findFreePort(t) + + // Init driver + job := eng.Job("initdriver") + if res := InitDriver(job); res != engine.StatusOK { + t.Fatal("Failed to initialize network driver") + } + + // Allocate interface + job = eng.Job("allocate_interface", "container_id") + if res := Allocate(job); res != engine.StatusOK { + t.Fatal("Failed to allocate network interface") + } + + // Occupy port + listenAddr := fmt.Sprintf(":%d", freePort) + tcpListenAddr, err := net.ResolveTCPAddr("tcp", listenAddr) + if err != nil { + t.Fatalf("Failed to resolve TCP address '%s'", listenAddr) + } + + l, err := net.ListenTCP("tcp", tcpListenAddr) + if err != nil { + t.Fatalf("Fail to listen on port %d", freePort) + } + + // Allocate port, expect failure + job = newPortAllocationJob(eng, freePort) + if res := AllocatePort(job); res == engine.StatusOK { + t.Fatal("Successfully allocated currently used port") + } + + // Reclaim port, retry allocation + l.Close() + if res := AllocatePort(job); res != engine.StatusOK { + t.Fatal("Failed to allocate previously reclaimed port") + } +} diff --git a/daemon/networkdriver/portmapper/mapper.go b/daemon/networkdriver/portmapper/mapper.go index e29959a24..880cfb298 100644 --- a/daemon/networkdriver/portmapper/mapper.go +++ b/daemon/networkdriver/portmapper/mapper.go @@ -3,10 +3,12 @@ package portmapper import ( "errors" "fmt" - "github.com/dotcloud/docker/pkg/iptables" - "github.com/dotcloud/docker/pkg/proxy" "net" "sync" + + "github.com/dotcloud/docker/daemon/networkdriver/portallocator" + "github.com/dotcloud/docker/pkg/iptables" + "github.com/dotcloud/docker/pkg/proxy" ) type mapping struct { @@ -31,47 +33,87 @@ var ( ErrPortNotMapped = errors.New("port is not mapped") ) +type genericAddr struct { + IP net.IP + Port int +} + +func (g *genericAddr) Network() string { + return "" +} + +func (g *genericAddr) String() string { + return fmt.Sprintf("%s:%d", g.IP.String(), g.Port) +} + func SetIptablesChain(c *iptables.Chain) { chain = c } -func Map(container net.Addr, hostIP net.IP, hostPort int) error { +func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { lock.Lock() defer lock.Unlock() - var m *mapping + var ( + m *mapping + err error + proto string + allocatedHostPort int + ) + switch container.(type) { case *net.TCPAddr: + proto = "tcp" + if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { + return &net.TCPAddr{IP: hostIP, Port: hostPort}, err + } m = &mapping{ - proto: "tcp", - host: &net.TCPAddr{IP: hostIP, Port: hostPort}, + proto: proto, + host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } case *net.UDPAddr: + proto = "udp" + if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { + return &net.UDPAddr{IP: hostIP, Port: hostPort}, err + } m = &mapping{ - proto: "udp", - host: &net.UDPAddr{IP: hostIP, Port: hostPort}, + proto: proto, + host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } default: - return ErrUnknownBackendAddressType + // Always return a proper net.Addr for proper reporting. + return &genericAddr{IP: hostIP, Port: hostPort}, ErrUnknownBackendAddressType } + // When binding fails: + // - for a specifically requested port: it might be locked by some other + // process, so we want to allow for an ulterior retry + // - for an automatically allocated port: it falls in the Docker range of + // ports, so we'll just remember it as used and try the next free one + defer func() { + if err != nil && hostPort != 0 { + portallocator.ReleasePort(hostIP, proto, allocatedHostPort) + } + }() + key := getKey(m.host) if _, exists := currentMappings[key]; exists { - return ErrPortMappedForIP + err = ErrPortMappedForIP + return m.host, err } containerIP, containerPort := getIPAndPort(m.container) - if err := forward(iptables.Add, m.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { - return err + if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { + return m.host, err } p, err := newProxy(m.host, m.container) if err != nil { // need to undo the iptables rules before we reutrn - forward(iptables.Delete, m.proto, hostIP, hostPort, containerIP.String(), containerPort) - return err + forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) + return m.host, err } m.userlandProxy = p @@ -79,7 +121,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) error { go p.Run() - return nil + return m.host, nil } func Unmap(host net.Addr) error { @@ -100,6 +142,18 @@ func Unmap(host net.Addr) error { if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { return err } + + switch a := host.(type) { + case *net.TCPAddr: + if err := portallocator.ReleasePort(a.IP, "tcp", a.Port); err != nil { + return err + } + case *net.UDPAddr: + if err := portallocator.ReleasePort(a.IP, "udp", a.Port); err != nil { + return err + } + } + return nil } diff --git a/daemon/networkdriver/portmapper/mapper_test.go b/daemon/networkdriver/portmapper/mapper_test.go index 4c09f3c65..881ea028f 100644 --- a/daemon/networkdriver/portmapper/mapper_test.go +++ b/daemon/networkdriver/portmapper/mapper_test.go @@ -44,20 +44,36 @@ func TestMapPorts(t *testing.T) { srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")} srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")} - if err := Map(srcAddr1, dstIp1, 80); err != nil { + addrEqual := func(addr1, addr2 net.Addr) bool { + return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String()) + } + + if host, err := Map(srcAddr1, dstIp1, 80); err != nil { t.Fatalf("Failed to allocate port: %s", err) + } else if !addrEqual(dstAddr1, host) { + t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", + dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if Map(srcAddr1, dstIp1, 80) == nil { + if host, err := Map(srcAddr1, dstIp1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") + } else if !addrEqual(dstAddr1, host) { + t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", + dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if Map(srcAddr2, dstIp1, 80) == nil { + if host, err := Map(srcAddr2, dstIp1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") + } else if !addrEqual(dstAddr1, host) { + t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", + dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if err := Map(srcAddr2, dstIp2, 80); err != nil { + if host, err := Map(srcAddr2, dstIp2, 80); err != nil { t.Fatalf("Failed to allocate port: %s", err) + } else if !addrEqual(dstAddr2, host) { + t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", + dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } if Unmap(dstAddr1) != nil { From ffd68badc0a3d70fbd063903702355a387621b10 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Wed, 25 Jun 2014 13:17:20 -0700 Subject: [PATCH 119/167] Make ErrPortAlreadyAllocated an error interface with a few extras, adjust tests to fit. Docker-DCO-1.1-Signed-off-by: Erik Hollensbe (github: erikh) --- daemon/networkdriver/bridge/driver.go | 22 ++++++++---- .../portallocator/portallocator.go | 36 ++++++++++++++++--- .../portallocator/portallocator_test.go | 7 ++-- daemon/networkdriver/portmapper/mapper.go | 23 +++--------- .../networkdriver/portmapper/mapper_test.go | 15 ++------ 5 files changed, 60 insertions(+), 43 deletions(-) diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index 8da7a0457..16439d2ac 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -11,6 +11,7 @@ import ( "github.com/docker/libcontainer/netlink" "github.com/dotcloud/docker/daemon/networkdriver" "github.com/dotcloud/docker/daemon/networkdriver/ipallocator" + "github.com/dotcloud/docker/daemon/networkdriver/portallocator" "github.com/dotcloud/docker/daemon/networkdriver/portmapper" "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/pkg/iptables" @@ -413,15 +414,22 @@ func AllocatePort(job *engine.Job) engine.Status { break } - // There is no point in immediately retrying to map an explicitely - // chosen port. - if hostPort != 0 { - job.Logf("Failed to bind %s for container address %s", host.String(), container.String()) + switch allocerr := err.(type) { + case portallocator.ErrPortAlreadyAllocated: + // There is no point in immediately retrying to map an explicitly + // chosen port. + if hostPort != 0 { + job.Logf("Failed to bind %s for container address %s: %s", allocerr.IPPort(), container.String(), allocerr.Error()) + break + } + + // Automatically chosen 'free' port failed to bind: move on the next. + job.Logf("Failed to bind %s for container address %s. Trying another port.", allocerr.IPPort(), container.String()) + default: + // some other error during mapping + job.Logf("Received an unexpected error during port allocation: %s", err.Error()) break } - - // Automatically chosen 'free' port failed to bind: move on the next. - job.Logf("Failed to bind %s for container address %s. Trying another port.", host.String(), container.String()) } if err != nil { diff --git a/daemon/networkdriver/portallocator/portallocator.go b/daemon/networkdriver/portallocator/portallocator.go index 251ab9447..3b01e28a3 100644 --- a/daemon/networkdriver/portallocator/portallocator.go +++ b/daemon/networkdriver/portallocator/portallocator.go @@ -2,6 +2,7 @@ package portallocator import ( "errors" + "fmt" "net" "sync" ) @@ -18,9 +19,8 @@ const ( ) var ( - ErrAllPortsAllocated = errors.New("all ports are allocated") - ErrPortAlreadyAllocated = errors.New("port has already been allocated") - ErrUnknownProtocol = errors.New("unknown protocol") + ErrAllPortsAllocated = errors.New("all ports are allocated") + ErrUnknownProtocol = errors.New("unknown protocol") ) var ( @@ -30,6 +30,34 @@ var ( globalMap = ipMapping{} ) +type ErrPortAlreadyAllocated struct { + ip string + port int +} + +func NewErrPortAlreadyAllocated(ip string, port int) ErrPortAlreadyAllocated { + return ErrPortAlreadyAllocated{ + ip: ip, + port: port, + } +} + +func (e ErrPortAlreadyAllocated) IP() string { + return e.ip +} + +func (e ErrPortAlreadyAllocated) Port() int { + return e.port +} + +func (e ErrPortAlreadyAllocated) IPPort() string { + return fmt.Sprintf("%s:%d", e.ip, e.port) +} + +func (e ErrPortAlreadyAllocated) Error() string { + return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port) +} + func RequestPort(ip net.IP, proto string, port int) (int, error) { mutex.Lock() defer mutex.Unlock() @@ -47,7 +75,7 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) { mapping[proto][port] = true return port, nil } else { - return 0, ErrPortAlreadyAllocated + return 0, NewErrPortAlreadyAllocated(ip.String(), port) } } else { port, err := findPort(ip, proto) diff --git a/daemon/networkdriver/portallocator/portallocator_test.go b/daemon/networkdriver/portallocator/portallocator_test.go index 5a4765ddd..9869c332e 100644 --- a/daemon/networkdriver/portallocator/portallocator_test.go +++ b/daemon/networkdriver/portallocator/portallocator_test.go @@ -83,8 +83,11 @@ func TestReleaseUnreadledPort(t *testing.T) { } port, err = RequestPort(defaultIP, "tcp", 5000) - if err != ErrPortAlreadyAllocated { - t.Fatalf("Expected error %s got %s", ErrPortAlreadyAllocated, err) + + switch err.(type) { + case ErrPortAlreadyAllocated: + default: + t.Fatalf("Expected port allocation error got %s", err) } } diff --git a/daemon/networkdriver/portmapper/mapper.go b/daemon/networkdriver/portmapper/mapper.go index 880cfb298..d4469cd6d 100644 --- a/daemon/networkdriver/portmapper/mapper.go +++ b/daemon/networkdriver/portmapper/mapper.go @@ -33,19 +33,6 @@ var ( ErrPortNotMapped = errors.New("port is not mapped") ) -type genericAddr struct { - IP net.IP - Port int -} - -func (g *genericAddr) Network() string { - return "" -} - -func (g *genericAddr) String() string { - return fmt.Sprintf("%s:%d", g.IP.String(), g.Port) -} - func SetIptablesChain(c *iptables.Chain) { chain = c } @@ -65,7 +52,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { case *net.TCPAddr: proto = "tcp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { - return &net.TCPAddr{IP: hostIP, Port: hostPort}, err + return nil, err } m = &mapping{ proto: proto, @@ -75,7 +62,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { case *net.UDPAddr: proto = "udp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { - return &net.UDPAddr{IP: hostIP, Port: hostPort}, err + return nil, err } m = &mapping{ proto: proto, @@ -83,8 +70,8 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { container: container, } default: - // Always return a proper net.Addr for proper reporting. - return &genericAddr{IP: hostIP, Port: hostPort}, ErrUnknownBackendAddressType + err = ErrUnknownBackendAddressType + return nil, err } // When binding fails: @@ -111,7 +98,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { p, err := newProxy(m.host, m.container) if err != nil { - // need to undo the iptables rules before we reutrn + // need to undo the iptables rules before we return forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) return m.host, err } diff --git a/daemon/networkdriver/portmapper/mapper_test.go b/daemon/networkdriver/portmapper/mapper_test.go index 881ea028f..cae74ebb8 100644 --- a/daemon/networkdriver/portmapper/mapper_test.go +++ b/daemon/networkdriver/portmapper/mapper_test.go @@ -55,25 +55,16 @@ func TestMapPorts(t *testing.T) { dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if host, err := Map(srcAddr1, dstIp1, 80); err == nil { + if _, err := Map(srcAddr1, dstIp1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") - } else if !addrEqual(dstAddr1, host) { - t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", - dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if host, err := Map(srcAddr2, dstIp1, 80); err == nil { + if _, err := Map(srcAddr2, dstIp1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") - } else if !addrEqual(dstAddr1, host) { - t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", - dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } - if host, err := Map(srcAddr2, dstIp2, 80); err != nil { + if _, err := Map(srcAddr2, dstIp2, 80); err != nil { t.Fatalf("Failed to allocate port: %s", err) - } else if !addrEqual(dstAddr2, host) { - t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s", - dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network()) } if Unmap(dstAddr1) != nil { From e77729c2e081c5ce55aa1d4f316b7c7703e5de96 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Thu, 26 Jun 2014 00:09:19 -0700 Subject: [PATCH 120/167] Use last allocated port logic in port allocator Docker-DCO-1.1-Signed-off-by: Erik Hollensbe (github: erikh) --- daemon/networkdriver/bridge/driver.go | 17 ++++--- .../portallocator/portallocator.go | 49 ++++++++++++------- daemon/networkdriver/portmapper/mapper.go | 24 ++++----- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index 16439d2ac..a843da049 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -20,7 +20,8 @@ import ( ) const ( - DefaultNetworkBridge = "docker0" + DefaultNetworkBridge = "docker0" + MaxAllocatedPortAttempts = 10 ) // Network interface represents the networking stack of a container @@ -401,15 +402,15 @@ func AllocatePort(job *engine.Job) engine.Status { return job.Errorf("unsupported address type %s", proto) } - /* - Try up to 10 times to get a port that's not already allocated. - - In the event of failure to bind, return the error that portmapper.Map - yields. - */ + // + // Try up to 10 times to get a port that's not already allocated. + // + // In the event of failure to bind, return the error that portmapper.Map + // yields. + // var host net.Addr - for i := 0; i < 10; i++ { + for i := 0; i < MaxAllocatedPortAttempts; i++ { if host, err = portmapper.Map(container, ip, hostPort); err == nil { break } diff --git a/daemon/networkdriver/portallocator/portallocator.go b/daemon/networkdriver/portallocator/portallocator.go index 3b01e28a3..c722ba98b 100644 --- a/daemon/networkdriver/portallocator/portallocator.go +++ b/daemon/networkdriver/portallocator/portallocator.go @@ -7,9 +7,13 @@ import ( "sync" ) +type portMap struct { + p map[int]struct{} + last int +} + type ( - portMap map[int]bool - protocolMap map[string]portMap + protocolMap map[string]*portMap ipMapping map[string]protocolMap ) @@ -71,8 +75,8 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) { mapping := getOrCreate(ip) if port > 0 { - if !mapping[proto][port] { - mapping[proto][port] = true + if _, ok := mapping[proto].p[port]; !ok { + mapping[proto].p[port] = struct{}{} return port, nil } else { return 0, NewErrPortAlreadyAllocated(ip.String(), port) @@ -94,8 +98,8 @@ func ReleasePort(ip net.IP, proto string, port int) error { ip = getDefault(ip) - mapping := getOrCreate(ip) - delete(mapping[proto], port) + mapping := getOrCreate(ip)[proto] + delete(mapping.p, port) return nil } @@ -114,8 +118,8 @@ func getOrCreate(ip net.IP) protocolMap { if _, ok := globalMap[ipstr]; !ok { globalMap[ipstr] = protocolMap{ - "tcp": portMap{}, - "udp": portMap{}, + "tcp": &portMap{p: map[int]struct{}{}, last: 0}, + "udp": &portMap{p: map[int]struct{}{}, last: 0}, } } @@ -123,21 +127,28 @@ func getOrCreate(ip net.IP) protocolMap { } func findPort(ip net.IP, proto string) (int, error) { - port := BeginPortRange + mapping := getOrCreate(ip)[proto] - mapping := getOrCreate(ip) - - for mapping[proto][port] { - port++ - - if port > EndPortRange { - return 0, ErrAllPortsAllocated - } + if mapping.last == 0 { + mapping.p[BeginPortRange] = struct{}{} + mapping.last = BeginPortRange + return BeginPortRange, nil } - mapping[proto][port] = true + for port := mapping.last + 1; port != mapping.last; port++ { + if port > EndPortRange { + port = BeginPortRange + } - return port, nil + if _, ok := mapping.p[port]; !ok { + mapping.p[port] = struct{}{} + mapping.last = port + return port, nil + } + + } + + return 0, ErrAllPortsAllocated } func getDefault(ip net.IP) net.IP { diff --git a/daemon/networkdriver/portmapper/mapper.go b/daemon/networkdriver/portmapper/mapper.go index d4469cd6d..1bd332271 100644 --- a/daemon/networkdriver/portmapper/mapper.go +++ b/daemon/networkdriver/portmapper/mapper.go @@ -48,6 +48,13 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { allocatedHostPort int ) + // release the port on any error during return. + defer func() { + if err != nil { + portallocator.ReleasePort(hostIP, proto, allocatedHostPort) + } + }() + switch container.(type) { case *net.TCPAddr: proto = "tcp" @@ -74,33 +81,22 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { return nil, err } - // When binding fails: - // - for a specifically requested port: it might be locked by some other - // process, so we want to allow for an ulterior retry - // - for an automatically allocated port: it falls in the Docker range of - // ports, so we'll just remember it as used and try the next free one - defer func() { - if err != nil && hostPort != 0 { - portallocator.ReleasePort(hostIP, proto, allocatedHostPort) - } - }() - key := getKey(m.host) if _, exists := currentMappings[key]; exists { err = ErrPortMappedForIP - return m.host, err + return nil, err } containerIP, containerPort := getIPAndPort(m.container) if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { - return m.host, err + return nil, err } p, err := newProxy(m.host, m.container) if err != nil { // need to undo the iptables rules before we return forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) - return m.host, err + return nil, err } m.userlandProxy = p From 08182da5d829762366b9bff9cb27b25a010ad1dd Mon Sep 17 00:00:00 2001 From: Alexandr Morozov Date: Fri, 27 Jun 2014 12:26:02 +0400 Subject: [PATCH 121/167] Integration cli tests on Links in inspect Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- integration-cli/docker_cli_links_test.go | 33 +++++++++++++++++++++++- integration-cli/docker_utils.go | 4 +++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go index 0480183bc..d2616475c 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -2,12 +2,13 @@ package main import ( "fmt" - "github.com/dotcloud/docker/pkg/iptables" "io/ioutil" "os" "os/exec" "strings" "testing" + + "github.com/dotcloud/docker/pkg/iptables" ) func TestEtcHostsRegularFile(t *testing.T) { @@ -90,3 +91,33 @@ func TestIpTablesRulesWhenLinkAndUnlink(t *testing.T) { logDone("link - verify iptables when link and unlink") } + +func TestInspectLinksStarted(t *testing.T) { + defer deleteAllContainers() + cmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10") + cmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10") + cmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sleep", "10") + links, err := inspectField("testinspectlink", "HostConfig.Links") + if err != nil { + t.Fatal(err) + } + if expected := "[/container1:/testinspectlink/alias1 /container2:/testinspectlink/alias2]"; links != expected { + t.Fatalf("Links %s, but expected %s", links, expected) + } + logDone("link - links in started container inspect") +} + +func TestInspectLinksStopped(t *testing.T) { + defer deleteAllContainers() + cmd(t, "run", "-d", "--name", "container1", "busybox", "sleep", "10") + cmd(t, "run", "-d", "--name", "container2", "busybox", "sleep", "10") + cmd(t, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true") + links, err := inspectField("testinspectlink", "HostConfig.Links") + if err != nil { + t.Fatal(err) + } + if expected := "[/container1:/testinspectlink/alias1 /container2:/testinspectlink/alias2]"; links != expected { + t.Fatalf("Links %s, but expected %s", links, expected) + } + logDone("link - links in stopped container inspect") +} diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index c1e306f2e..cc4501243 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -16,6 +16,10 @@ import ( func deleteContainer(container string) error { container = strings.Replace(container, "\n", " ", -1) container = strings.Trim(container, " ") + killArgs := fmt.Sprintf("kill %v", container) + killSplitArgs := strings.Split(killArgs, " ") + killCmd := exec.Command(dockerBinary, killSplitArgs...) + runCommand(killCmd) rmArgs := fmt.Sprintf("rm %v", container) rmSplitArgs := strings.Split(rmArgs, " ") rmCmd := exec.Command(dockerBinary, rmSplitArgs...) From 0acec443745a917fb8e97d50609ff01b03888512 Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Fri, 27 Jun 2014 12:45:55 -0700 Subject: [PATCH 122/167] Changed add to group command to include -a (append) flag, for safety. In response to customer email. Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- docs/sources/installation/openSUSE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/openSUSE.md b/docs/sources/installation/openSUSE.md index 165f953b0..b8d912222 100644 --- a/docs/sources/installation/openSUSE.md +++ b/docs/sources/installation/openSUSE.md @@ -45,9 +45,9 @@ If we want Docker to start at boot, we should also: The docker package creates a new group named docker. Users, other than root user, need to be part of this group in order to interact with the -Docker daemon. +Docker daemon. You can add users with: - $ sudo usermod -G docker + $ sudo usermod -a -G docker **Done!** From 5a3d774e5651da772a065282a1fb1a31e19e911c Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Fri, 27 Jun 2014 14:53:35 -0400 Subject: [PATCH 123/167] allow overwrite in untar Docker-DCO-1.1-Signed-off-by: Tibor Vass (github: tiborvass) --- archive/archive.go | 15 +++++++++------ archive/archive_test.go | 3 +++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/archive/archive.go b/archive/archive.go index b9701b58a..8d8b7412c 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -383,7 +383,8 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) // identity (uncompressed), gzip, bzip2, xz. // If `dest` does not exist, it is created unless there are multiple entries in `archive`. // In the latter case, an error is returned. -// An other error is returned if `dest` exists but is not a directory, to prevent overwriting. +// If `dest` is an existing file, it gets overwritten. +// If `dest` is an existing directory, its files get merged (with overwrite for conflicting files). func Untar(archive io.Reader, dest string, options *TarOptions) error { if archive == nil { return fmt.Errorf("Empty archive") @@ -399,7 +400,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { var ( dirs []*tar.Header - destNotExist bool + create bool multipleEntries bool ) @@ -408,9 +409,10 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { return err } // destination does not exist, so it is assumed it has to be created. - destNotExist = true + create = true } else if !fi.IsDir() { - return fmt.Errorf("Trying to untar to `%s`: exists but not a directory", dest) + // destination exists and is not a directory, so it will be overwritten. + create = true } // Iterate through the files in the archive. @@ -425,7 +427,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { } // Return an error if destination needs to be created and there is more than 1 entry in the tar stream. - if destNotExist && multipleEntries { + if create && multipleEntries { return fmt.Errorf("Trying to untar an archive with multiple entries to an inexistant target `%s`: did you mean `%s` instead?", dest, filepath.Dir(dest)) } @@ -445,7 +447,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { } var path string - if destNotExist { + if create { path = dest // we are renaming hdr.Name to dest } else { path = filepath.Join(dest, hdr.Name) @@ -465,6 +467,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { } } } + if err := createTarFile(path, dest, hdr, tr, options == nil || !options.NoLchown); err != nil { return err } diff --git a/archive/archive_test.go b/archive/archive_test.go index e05cd72e4..1b5e14696 100644 --- a/archive/archive_test.go +++ b/archive/archive_test.go @@ -176,6 +176,9 @@ func TestTarUntarFile(t *testing.T) { if err := ioutil.WriteFile(path.Join(origin, "before", "file"), []byte("hello world"), 0700); err != nil { t.Fatal(err) } + if err := ioutil.WriteFile(path.Join(origin, "after", "file2"), []byte("please overwrite me"), 0700); err != nil { + t.Fatal(err) + } tar, err := TarWithOptions(path.Join(origin, "before"), &TarOptions{Compression: Uncompressed, Includes: []string{"file"}}) if err != nil { From 2cdcfc0c57e375955d3ed7c8e1487f9d4751b255 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Fri, 27 Jun 2014 15:57:20 -0700 Subject: [PATCH 124/167] portmapper: unit tests for remap problem Docker-DCO-1.1-Signed-off-by: Erik Hollensbe (github: erikh) --- .../networkdriver/portmapper/mapper_test.go | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/daemon/networkdriver/portmapper/mapper_test.go b/daemon/networkdriver/portmapper/mapper_test.go index cae74ebb8..6affdc544 100644 --- a/daemon/networkdriver/portmapper/mapper_test.go +++ b/daemon/networkdriver/portmapper/mapper_test.go @@ -1,6 +1,7 @@ package portmapper import ( + "github.com/dotcloud/docker/daemon/networkdriver/portallocator" "github.com/dotcloud/docker/pkg/iptables" "github.com/dotcloud/docker/pkg/proxy" "net" @@ -112,3 +113,40 @@ func TestGetUDPIPAndPort(t *testing.T) { t.Fatalf("expected port %d got %d", ep, port) } } + +func TestMapAllPortsSingleInterface(t *testing.T) { + dstIp1 := net.ParseIP("0.0.0.0") + srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")} + + hosts := []net.Addr{} + var host net.Addr + var err error + + defer func() { + for _, val := range hosts { + Unmap(val) + } + }() + + for i := 0; i < 10; i++ { + for i := portallocator.BeginPortRange; i < portallocator.EndPortRange; i++ { + if host, err = Map(srcAddr1, dstIp1, 0); err != nil { + t.Fatal(err) + } + + hosts = append(hosts, host) + } + + if _, err := Map(srcAddr1, dstIp1, portallocator.BeginPortRange); err == nil { + t.Fatal("Port %d should be bound but is not", portallocator.BeginPortRange) + } + + for _, val := range hosts { + if err := Unmap(val); err != nil { + t.Fatal(err) + } + } + + hosts = []net.Addr{} + } +} From a0b229071394e6534808f16c4570ed8fd9ff3a1c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 27 Jun 2014 20:22:18 +0000 Subject: [PATCH 125/167] remove deprecated syntax for docker commit Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/client/commands.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 61ef42638..76d079fc3 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1546,17 +1546,12 @@ func (cli *DockerCli) CmdCommit(args ...string) error { return nil } - var name, repository, tag string - - if cmd.NArg() == 3 { - fmt.Fprintf(cli.err, "[DEPRECATED] The format 'CONTAINER [REPOSITORY [TAG]]' as been deprecated. Please use CONTAINER [REPOSITORY[:TAG]]\n") - name, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2) - } else { - name = cmd.Arg(0) + var ( + name = cmd.Arg(0) repository, tag = utils.ParseRepositoryTag(cmd.Arg(1)) - } + ) - if name == "" { + if name == "" || len(cmd.Args()) > 2 { cmd.Usage() return nil } From 2edfb1e696d8f46ea4276b3952078b1553ea42eb Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Sat, 28 Jun 2014 12:20:31 +0400 Subject: [PATCH 126/167] Update go-patricia to v1.0.1 Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- hack/vendor.sh | 2 +- vendor/src/github.com/tchap/go-patricia/.travis.yml | 9 --------- vendor/src/github.com/tchap/go-patricia/README.md | 12 ++++++++++-- .../tchap/go-patricia/patricia/children.go | 11 +++++------ 4 files changed, 16 insertions(+), 18 deletions(-) delete mode 100644 vendor/src/github.com/tchap/go-patricia/.travis.yml diff --git a/hack/vendor.sh b/hack/vendor.sh index b17ea0b3a..e444a01c4 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -47,7 +47,7 @@ clone git github.com/gorilla/mux 136d54f81f clone git github.com/syndtr/gocapability 3c85049eae -clone git github.com/tchap/go-patricia v1.0.0 +clone git github.com/tchap/go-patricia v1.0.1 clone hg code.google.com/p/go.net 84a4013f96e0 diff --git a/vendor/src/github.com/tchap/go-patricia/.travis.yml b/vendor/src/github.com/tchap/go-patricia/.travis.yml deleted file mode 100644 index 66183e2ad..000000000 --- a/vendor/src/github.com/tchap/go-patricia/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.2 - - tip - -branches: - exclude: - - wip diff --git a/vendor/src/github.com/tchap/go-patricia/README.md b/vendor/src/github.com/tchap/go-patricia/README.md index 635e2b8ea..11ee4612d 100644 --- a/vendor/src/github.com/tchap/go-patricia/README.md +++ b/vendor/src/github.com/tchap/go-patricia/README.md @@ -1,8 +1,10 @@ # go-patricia # **Documentation**: [GoDoc](http://godoc.org/github.com/tchap/go-patricia/patricia)
-**Build Status**: [![Build Status](https://travis-ci.org/tchap/go-patricia.png?branch=master)](https://travis-ci.org/tchap/go-patricia)
-**Test Coverage**: Comming as soon as Drone.io people update their Go. +**Build Status**: [![Build +Status](https://drone.io/github.com/tchap/go-patricia/status.png)](https://drone.io/github.com/tchap/go-patricia/latest)
+**Test Coverage**: [![Coverage +Status](https://coveralls.io/repos/tchap/go-patricia/badge.png)](https://coveralls.io/r/tchap/go-patricia) ## About ## @@ -34,6 +36,12 @@ Import the package from GitHub first. import "github.com/tchap/go-patricia/patricia" ``` +You can as well use gopkg.in thingie: + +```go +import "gopkg.in/tchap/go-patricia.v1/patricia" +``` + Then you can start having fun. ```go diff --git a/vendor/src/github.com/tchap/go-patricia/patricia/children.go b/vendor/src/github.com/tchap/go-patricia/patricia/children.go index 42b0547de..07d332633 100644 --- a/vendor/src/github.com/tchap/go-patricia/patricia/children.go +++ b/vendor/src/github.com/tchap/go-patricia/patricia/children.go @@ -5,12 +5,11 @@ package patricia -const ( - // Max prefix length that is kept in a single trie node. - MaxPrefixPerNode = 10 - // Max children to keep in a node in the sparse mode. - MaxChildrenPerSparseNode = 8 -) +// Max prefix length that is kept in a single trie node. +var MaxPrefixPerNode = 10 + +// Max children to keep in a node in the sparse mode. +const MaxChildrenPerSparseNode = 8 type childList interface { length() int From 095cb7a81800512b99474aec7245bddddd1b2278 Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Sat, 28 Jun 2014 12:27:44 +0400 Subject: [PATCH 127/167] Increase patricia.MaxPrefixPerNode It allows to avoid redundant prefix splits Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- pkg/truncindex/truncindex.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/truncindex/truncindex.go b/pkg/truncindex/truncindex.go index 811f60666..89aa88d6b 100644 --- a/pkg/truncindex/truncindex.go +++ b/pkg/truncindex/truncindex.go @@ -13,6 +13,12 @@ var ( ErrNoID = errors.New("prefix can't be empty") ) +func init() { + // Change patricia max prefix per node length, + // because our len(ID) always 64 + patricia.MaxPrefixPerNode = 64 +} + // TruncIndex allows the retrieval of string identifiers by any of their unique prefixes. // This is used to retrieve image and container IDs by more convenient shorthand prefixes. type TruncIndex struct { From ea464ea212aa584dd0aa50820c78f7f60a77450d Mon Sep 17 00:00:00 2001 From: LK4D4 Date: Sat, 28 Jun 2014 12:38:29 +0400 Subject: [PATCH 128/167] Update gorilla/context Race condition was fixed recently Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- hack/vendor.sh | 2 +- .../src/github.com/gorilla/context/context.go | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/hack/vendor.sh b/hack/vendor.sh index b17ea0b3a..fd7ca5ef7 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -41,7 +41,7 @@ clone() { clone git github.com/kr/pty 67e2db24c8 -clone git github.com/gorilla/context b06ed15e1c +clone git github.com/gorilla/context 14f550f51a clone git github.com/gorilla/mux 136d54f81f diff --git a/vendor/src/github.com/gorilla/context/context.go b/vendor/src/github.com/gorilla/context/context.go index a7f7d85bb..81cb128b1 100644 --- a/vendor/src/github.com/gorilla/context/context.go +++ b/vendor/src/github.com/gorilla/context/context.go @@ -30,9 +30,10 @@ func Set(r *http.Request, key, val interface{}) { // Get returns a value stored for a given key in a given request. func Get(r *http.Request, key interface{}) interface{} { mutex.RLock() - if data[r] != nil { + if ctx := data[r]; ctx != nil { + value := ctx[key] mutex.RUnlock() - return data[r][key] + return value } mutex.RUnlock() return nil @@ -54,20 +55,28 @@ func GetOk(r *http.Request, key interface{}) (interface{}, bool) { func GetAll(r *http.Request) map[interface{}]interface{} { mutex.RLock() if context, ok := data[r]; ok { + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } mutex.RUnlock() - return context + return result } mutex.RUnlock() return nil } -// GetAllOk returns all stored values for the request as a map. It returns not -// ok if the request was never registered. +// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if +// the request was registered. func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { mutex.RLock() context, ok := data[r] + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } mutex.RUnlock() - return context, ok + return result, ok } // Delete removes a value stored for a given key in a given request. From 4a5f09387e17860ba748d94028cb2a307c9e0b11 Mon Sep 17 00:00:00 2001 From: Mike Chelen Date: Sat, 28 Jun 2014 12:01:16 -0400 Subject: [PATCH 129/167] missing `sudo` --- docs/sources/userguide/dockerimages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerimages.md b/docs/sources/userguide/dockerimages.md index ffcc39ddb..c3f5461c2 100644 --- a/docs/sources/userguide/dockerimages.md +++ b/docs/sources/userguide/dockerimages.md @@ -380,7 +380,7 @@ containers]( Let's delete the `training/sinatra` image as we don't need it anymore. - $ docker rmi training/sinatra + $ sudo docker rmi training/sinatra Untagged: training/sinatra:latest Deleted: 5bc342fa0b91cabf65246837015197eecfa24b2213ed6a51a8974ae250fedd8d Deleted: ed0fffdcdae5eb2c3a55549857a8be7fc8bc4241fb19ad714364cbfd7a56b22f From 0d2656ce6e8536fcdb6d68b5899febe867f59c70 Mon Sep 17 00:00:00 2001 From: Mike Chelen Date: Sat, 28 Jun 2014 12:26:36 -0400 Subject: [PATCH 130/167] fix typo --- docs/sources/userguide/dockerlinks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/dockerlinks.md b/docs/sources/userguide/dockerlinks.md index 711fd979c..20a5c1a17 100644 --- a/docs/sources/userguide/dockerlinks.md +++ b/docs/sources/userguide/dockerlinks.md @@ -94,7 +94,7 @@ yourself. This naming provides two useful functions: that makes it easier for you to remember them, for example naming a container with a web application in it `web`. -2. It provides Docker with reference point that allows it to refer to other +2. It provides Docker with a reference point that allows it to refer to other containers, for example link container `web` to container `db`. You can name your container by using the `--name` flag, for example: From 5c0819a0464624eba12b6a37462d549d7fed3be4 Mon Sep 17 00:00:00 2001 From: doug tangren Date: Sat, 28 Jun 2014 01:38:54 -0400 Subject: [PATCH 131/167] added linkage to tugboat, a scala client Docker-DCO-1.1-Signed-off-by: Doug Tangren (github: softprops) --- docs/sources/reference/api/remote_api_client_libraries.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/sources/reference/api/remote_api_client_libraries.md b/docs/sources/reference/api/remote_api_client_libraries.md index e299e6ed8..d1d26a1dd 100644 --- a/docs/sources/reference/api/remote_api_client_libraries.md +++ b/docs/sources/reference/api/remote_api_client_libraries.md @@ -123,12 +123,18 @@ will add the libraries here. Active + Scala + tugboat + https://github.com/softprops/tugboat + Active + + Scala reactive-docker https://github.com/almoehi/reactive-docker Active - + Java docker-client https://github.com/spotify/docker-client From 3be683a0bbf25f41e9f4b1652f8f0784cafbd05b Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Sun, 29 Jun 2014 19:45:08 -0300 Subject: [PATCH 132/167] Remove extra "Docker" from docs index --- docs/sources/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index ef5fe2c2c..57b971223 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -46,7 +46,7 @@ Docker consists of: * Since Docker runs on so many platforms, it's easy to move your applications around. You can easily move an application from a testing environment into the cloud and back whenever you need. - * Docker's lightweight containers Docker also make scaling up and + * Docker's lightweight containers also make scaling up and down fast and easy. You can quickly launch more containers when needed and then shut them down easily when they're no longer needed. From 9a2771eac22950fce43702896052f5187944de6d Mon Sep 17 00:00:00 2001 From: Adrien Folie Date: Mon, 30 Jun 2014 01:31:16 +0200 Subject: [PATCH 133/167] Migrate TestGetImagesHistory into unit and CLI test Docker-DCO-1.1-Signed-off-by: Adrien Folie (github: folieadrien) --- api/server/server_unit_test.go | 27 ++++++++++++++++++++++ integration-cli/docker_cli_history_test.go | 18 +++++++++++++++ integration/api_test.go | 25 -------------------- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index 914cb7c0d..4840a2526 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -289,6 +289,33 @@ func TestLogsNoStreams(t *testing.T) { } } +func TestGetImagesHistory(t *testing.T) { + eng := engine.New() + imageName := "docker-test-image" + var called bool + eng.Register("history", func(job *engine.Job) engine.Status { + called = true + if job.Args[0] != imageName { + t.Fatalf("name != '%s': %#v", imageName, job.Args[0]) + } + v := &engine.Env{} + if _, err := v.WriteTo(job.Stdout); err != nil { + return job.Error(err) + } + return engine.StatusOK + }) + r := serveRequest("GET", "/images/"+imageName+"/history", nil, eng, t) + if !called { + t.Fatalf("handler was not called") + } + if r.Code != http.StatusOK { + t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK) + } + if r.HeaderMap.Get("Content-Type") != "application/json" { + t.Fatalf("%#v\n", r) + } +} + func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder { r := httptest.NewRecorder() req, err := http.NewRequest(method, target, body) diff --git a/integration-cli/docker_cli_history_test.go b/integration-cli/docker_cli_history_test.go index 42edec2fd..59ad11712 100644 --- a/integration-cli/docker_cli_history_test.go +++ b/integration-cli/docker_cli_history_test.go @@ -41,3 +41,21 @@ func TestBuildHistory(t *testing.T) { deleteImages("testbuildhistory") } + +func TestHistoryExistentImage(t *testing.T) { + historyCmd := exec.Command(dockerBinary, "history", "busybox") + _, exitCode, err := runCommandWithOutput(historyCmd) + if err != nil || exitCode != 0 { + t.Fatal("failed to get image history") + } + logDone("history - history on existent image must not fail") +} + +func TestHistoryNonExistentImage(t *testing.T) { + historyCmd := exec.Command(dockerBinary, "history", "testHistoryNonExistentImage") + _, exitCode, err := runCommandWithOutput(historyCmd) + if err == nil || exitCode == 0 { + t.Fatal("history on a non-existent image didn't result in a non-zero exit status") + } + logDone("history - history on non-existent image must fail") +} diff --git a/integration/api_test.go b/integration/api_test.go index 2d1b80368..b2e44717a 100644 --- a/integration/api_test.go +++ b/integration/api_test.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "encoding/json" - "fmt" "io" "io/ioutil" "net" @@ -125,30 +124,6 @@ func TestGetImagesJSON(t *testing.T) { } } -func TestGetImagesHistory(t *testing.T) { - eng := NewTestEngine(t) - defer mkDaemonFromEngine(eng, t).Nuke() - - r := httptest.NewRecorder() - - req, err := http.NewRequest("GET", fmt.Sprintf("/images/%s/history", unitTestImageName), nil) - if err != nil { - t.Fatal(err) - } - if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil { - t.Fatal(err) - } - assertHttpNotError(r, t) - - outs := engine.NewTable("Created", 0) - if _, err := outs.ReadListFrom(r.Body.Bytes()); err != nil { - t.Fatal(err) - } - if len(outs.Data) != 1 { - t.Errorf("Expected 1 line, %d found", len(outs.Data)) - } -} - func TestGetImagesByName(t *testing.T) { eng := NewTestEngine(t) defer mkDaemonFromEngine(eng, t).Nuke() From 24bf8faa99ef7c80aca3ee3a6eac485f74e521ef Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Mon, 30 Jun 2014 11:46:09 +1000 Subject: [PATCH 134/167] use the official image for now - there's an opensuse image on its way Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/sources/installation/openSUSE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/openSUSE.md b/docs/sources/installation/openSUSE.md index 2affa81ef..f71479020 100644 --- a/docs/sources/installation/openSUSE.md +++ b/docs/sources/installation/openSUSE.md @@ -49,9 +49,9 @@ Docker daemon. To verify that everything has worked as expected: - $ sudo docker run -i -t b1systems/opensuse /bin/bash + $ sudo docker run --rm -i -t ubuntu /bin/bash -This should download and import the `opensuse` image, and then start `bash` in a container. To exit the container type `exit`. +This should download and import the `ubuntu` image, and then start `bash` in a container. To exit the container type `exit`. **Done!** From 8c765ae68a4a9aceb9886f4d92f2ded7af144e22 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Sun, 29 Jun 2014 22:25:12 -0400 Subject: [PATCH 135/167] Formatting and consistency fixes to CLI and RUN references * Removed double backticks. * Reformatted paragraphs. * Fixed consistent STDOUT/STDIN/STDERR references. * Fixed several broken URLs. * Fixed backtick mismatches. Docker-DCO-1.1-Signed-off-by: James Turnbull (github: jamtur01) --- docs/sources/reference/commandline/cli.md | 78 ++++---- docs/sources/reference/run.md | 223 +++++++++++----------- 2 files changed, 151 insertions(+), 150 deletions(-) diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index cb5d39d93..7277b4c97 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -199,26 +199,26 @@ To kill the container, use `docker kill`. --rm=true Remove intermediate containers after a successful build -t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success -Use this command to build Docker images from a Dockerfile -and a "context". +Use this command to build Docker images from a Dockerfile and a +"context". -The files at `PATH` or `URL` are called the "context" of the build. The build -process may refer to any of the files in the context, for example when using an -[*ADD*](/reference/builder/#dockerfile-add) instruction. When a single Dockerfile is -given as `URL` or is piped through STDIN (`docker build - < Dockerfile`), then -no context is set. +The files at `PATH` or `URL` are called the "context" of the build. The +build process may refer to any of the files in the context, for example +when using an [*ADD*](/reference/builder/#dockerfile-add) instruction. +When a single Dockerfile is given as `URL` or is piped through `STDIN` +(`docker build - < Dockerfile`), then no context is set. -When a Git repository is set as `URL`, then the -repository is used as the context. The Git repository is cloned with its -submodules (git clone –recursive). A fresh git clone occurs in a -temporary directory on your local host, and then this is sent to the -Docker daemon as the context. This way, your local user credentials and -vpn's etc can be used to access private repositories. +When a Git repository is set as `URL`, then the repository is used as +the context. The Git repository is cloned with its submodules (`git +clone -recursive`). A fresh `git clone` occurs in a temporary directory +on your local host, and then this is sent to the Docker daemon as the +context. This way, your local user credentials and VPN's etc can be +used to access private repositories. -If a file named ``.dockerignore`` exists in the root of ``PATH`` then it is -interpreted as a newline-separated list of exclusion patterns. Exclusion -patterns match files or directories relative to ``PATH`` that will be excluded -from the context. Globbing is done using Go's +If a file named `.dockerignore` exists in the root of `PATH` then it +is interpreted as a newline-separated list of exclusion patterns. +Exclusion patterns match files or directories relative to `PATH` that +will be excluded from the context. Globbing is done using Go's [filepath.Match](http://golang.org/pkg/path/filepath#Match) rules. See also: @@ -304,15 +304,14 @@ and the tag will be `2.0` $ sudo docker build - < Dockerfile -This will read a Dockerfile from STDIN without -context. Due to the lack of a context, no contents of any local -directory will be sent to the `docker` daemon. Since -there is no context, a Dockerfile `ADD` -only works if it refers to a remote URL. +This will read a Dockerfile from `STDIN` without context. Due to the +lack of a context, no contents of any local directory will be sent to +the Docker daemon. Since there is no context, a Dockerfile `ADD` only +works if it refers to a remote URL. $ sudo docker build - < context.tar.gz -This will build an image for a compressed context read from STDIN. +This will build an image for a compressed context read from `STDIN`. Supported formats are: bzip2, gzip and xz. $ sudo docker build github.com/creack/docker-firefox @@ -518,7 +517,7 @@ by default. ### Filtering -The filtering flag (-f or --filter) format is of "key=value". If there are more +The filtering flag (`-f` or `--filter`) format is of "key=value". If there are more than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`) Current filters: @@ -562,11 +561,10 @@ NOTE: Docker will warn you if any containers exist that are using these untagged Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it. -URLs must start with `http` and point to a single -file archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, or .txz) containing a -root filesystem. If you would like to import from a local directory or -archive, you can use the `-` parameter to take the -data from STDIN. +URLs must start with `http` and point to a single file archive (.tar, +.tar.gz, .tgz, .bzip, .tar.xz, or .txz) containing a root filesystem. If +you would like to import from a local directory or archive, you can use +the `-` parameter to take the data from `STDIN`. ### Examples @@ -578,7 +576,7 @@ This will create a new untagged image. **Import from a local file:** -Import to docker via pipe and STDIN. +Import to docker via pipe and `STDIN`. $ cat exampleimage.tgz | sudo docker import - exampleimagelocal:new @@ -681,7 +679,7 @@ contains complex json object, so to grab it as JSON, you use -s, --signal="KILL" Signal to send to the container -The main process inside the container will be sent SIGKILL, or any +The main process inside the container will be sent `SIGKILL`, or any signal specified with option `--signal`. ## load @@ -739,8 +737,8 @@ The `docker logs` command batch-retrieves all logs present at the time of execution. The ``docker logs --follow`` command will first return all logs from the -beginning and then continue streaming new output from the container's stdout -and stderr. +beginning and then continue streaming new output from the container's `STDOUT` +and `STDERR`. ## port @@ -1074,7 +1072,7 @@ This will create and run a new container with the container name being The `--link` flag will link the container named `/redis` into the newly created container with the alias `redis`. The new container can access the -network and environment of the redis container via environment variables. +network and environment of the `redis` container via environment variables. The `--name` flag will assign the name `console` to the newly created container. @@ -1087,19 +1085,19 @@ optionally suffixed with `:ro` or `:rw` to mount the volumes in read-only or read-write mode, respectively. By default, the volumes are mounted in the same mode (read write or read only) as the reference container. -The `-a` flag tells `docker run` to bind to the container's stdin, stdout or -stderr. This makes it possible to manipulate the output and input as needed. +The `-a` flag tells `docker run` to bind to the container's `STDIN`, `STDOUT` or +`STDERR`. This makes it possible to manipulate the output and input as needed. $ echo "test" | sudo docker run -i -a stdin ubuntu cat - This pipes data into a container and prints the container's ID by attaching -only to the container'sstdin. +only to the container's `STDIN`. $ sudo docker run -a stderr ubuntu echo test -This isn't going to print anything unless there's an error because We've -only attached to the stderr of the container. The container's logs still - store what's been written to stderr and stdout. +This isn't going to print anything unless there's an error because we've +only attached to the `STDERR` of the container. The container's logs +still store what's been written to `STDERR` and `STDOUT`. $ cat somefile | sudo docker run -i -a stdin mybuilder dobuild diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 80429d7e2..37dba587b 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -5,13 +5,13 @@ page_keywords: docker, run, configure, runtime # Docker Run Reference **Docker runs processes in isolated containers**. When an operator -executes `docker run`, she starts a process with its -own file system, its own networking, and its own isolated process tree. -The [*Image*](/terms/image/#image-def) which starts the process may -define defaults related to the binary to run, the networking to expose, -and more, but `docker run` gives final control to -the operator who starts the container from the image. That's the main -reason [*run*](/reference/commandline/cli/#cli-run) has more options than any +executes `docker run`, she starts a process with its own file system, +its own networking, and its own isolated process tree. The +[*Image*](/terms/image/#image-def) which starts the process may define +defaults related to the binary to run, the networking to expose, and +more, but `docker run` gives final control to the operator who starts +the container from the image. That's the main reason +[*run*](/reference/commandline/cli/#cli-run) has more options than any other `docker` command. ## General Form @@ -36,10 +36,10 @@ The list of `[OPTIONS]` breaks down into two groups: 2. Setting shared between operators and developers, where operators can override defaults developers set in images at build time. -Together, the `docker run [OPTIONS]` give complete -control over runtime behavior to the operator, allowing them to override -all defaults set by the developer during `docker build` -and nearly all the defaults set by the Docker runtime itself. +Together, the `docker run [OPTIONS]` give complete control over runtime +behavior to the operator, allowing them to override all defaults set by +the developer during `docker build` and nearly all the defaults set by +the Docker runtime itself. ## Operator Exclusive Options @@ -54,10 +54,8 @@ following options. - [PID Equivalent](#pid-equivalent) - [Network Settings](#network-settings) - [Clean Up (--rm)](#clean-up-rm) - - [Runtime Constraints on CPU and - Memory](#runtime-constraints-on-cpu-and-memory) - - [Runtime Privilege and LXC - Configuration](#runtime-privilege-and-lxc-configuration) + - [Runtime Constraints on CPU and Memory](#runtime-constraints-on-cpu-and-memory) + - [Runtime Privilege and LXC Configuration](#runtime-privilege-and-lxc-configuration) ## Detached vs Foreground @@ -78,28 +76,28 @@ container in the detached mode, then you cannot use the `--rm` option. ### Foreground -In foreground mode (the default when `-d` is not specified), `docker run` -can start the process in the container and attach the console to the process's -standard input, output, and standard error. It can even pretend to be a TTY -(this is what most command line executables expect) and pass along signals. All -of that is configurable: +In foreground mode (the default when `-d` is not specified), `docker +run` can start the process in the container and attach the console to +the process's standard input, output, and standard error. It can even +pretend to be a TTY (this is what most command line executables expect) +and pass along signals. All of that is configurable: - -a=[] : Attach to ``stdin``, ``stdout`` and/or ``stderr`` + -a=[] : Attach to `STDIN`, `STDOUT` and/or `STDERR` -t=false : Allocate a pseudo-tty --sig-proxy=true: Proxify all received signal to the process (even in non-tty mode) -i=false : Keep STDIN open even if not attached -If you do not specify `-a` then Docker will [attach everything (stdin,stdout,stderr)]( -https://github.com/dotcloud/docker/blob/ -75a7f4d90cde0295bcfb7213004abce8d4779b75/commands.go#L1797). You can specify to which -of the three standard streams (`stdin`, `stdout`, `stderr`) you'd like to connect -instead, as in: +If you do not specify `-a` then Docker will [attach all standard +streams]( https://github.com/dotcloud/docker/blob/ +75a7f4d90cde0295bcfb7213004abce8d4779b75/commands.go#L1797). You can +specify to which of the three standard streams (`STDIN`, `STDOUT`, +`STDERR`) you'd like to connect instead, as in: $ docker run -a stdin -a stdout -i -t ubuntu /bin/bash -For interactive processes (like a shell) you will typically want a tty as well as -persistent standard input (`stdin`), so you'll use `-i -t` together in most -interactive cases. +For interactive processes (like a shell) you will typically want a tty +as well as persistent standard input (`STDIN`), so you'll use `-i -t` +together in most interactive cases. ## Container Identification @@ -113,19 +111,18 @@ The operator can identify a container in three ways: - Name ("evil_ptolemy") The UUID identifiers come from the Docker daemon, and if you do not -assign a name to the container with `--name` then -the daemon will also generate a random string name too. The name can -become a handy way to add meaning to a container since you can use this -name when defining -[*links*](/userguide/dockerlinks/#working-with-links-names) -(or any other place you need to identify a container). This works for -both background and foreground Docker containers. +assign a name to the container with `--name` then the daemon will also +generate a random string name too. The name can become a handy way to +add meaning to a container since you can use this name when defining +[*links*](/userguide/dockerlinks/#working-with-links-names) (or any +other place you need to identify a container). This works for both +background and foreground Docker containers. -### PID Equivalent +### PID Equivalent -And finally, to help with automation, you can have Docker write the +Finally, to help with automation, you can have Docker write the container ID out to a file of your choosing. This is similar to how some -programs might write out their process ID to a file (you`ve seen them as +programs might write out their process ID to a file (you've seen them as PID files): --cidfile="": Write the container ID to the file @@ -141,14 +138,14 @@ PID files): By default, all containers have networking enabled and they can make any outgoing connections. The operator can completely disable networking -with `docker run --net none` which disables all incoming and -outgoing networking. In cases like this, you would perform I/O through -files or STDIN/STDOUT only. +with `docker run --net none` which disables all incoming and outgoing +networking. In cases like this, you would perform I/O through files or +`STDIN` and `STDOUT` only. Your container will use the same DNS servers as the host by default, but you can override this with `--dns`. -Supported networking modes are: +Supported networking modes are: * none - no networking in the container * bridge - (default) connect the container to the bridge via veth interfaces @@ -156,35 +153,40 @@ Supported networking modes are: * container - use another container's network stack #### Mode: none -With the networking mode set to `none` a container will not have a access to -any external routes. The container will still have a `loopback` interface -enabled in the container but it does not have any routes to external traffic. + +With the networking mode set to `none` a container will not have a +access to any external routes. The container will still have a +`loopback` interface enabled in the container but it does not have any +routes to external traffic. #### Mode: bridge -With the networking mode set to `bridge` a container will use docker's default -networking setup. A bridge is setup on the host, commonly named `docker0`, -and a pair of veth interfaces will be created for the container. One side of -the veth pair will remain on the host attached to the bridge while the other -side of the pair will be placed inside the container's namespaces in addition -to the `loopback` interface. An IP address will be allocated for containers -on the bridge's network and trafic will be routed though this bridge to the -container. + +With the networking mode set to `bridge` a container will use docker's +default networking setup. A bridge is setup on the host, commonly named +`docker0`, and a pair of `veth` interfaces will be created for the +container. One side of the `veth` pair will remain on the host attached +to the bridge while the other side of the pair will be placed inside the +container's namespaces in addition to the `loopback` interface. An IP +address will be allocated for containers on the bridge's network and +traffic will be routed though this bridge to the container. #### Mode: host + With the networking mode set to `host` a container will share the host's -network stack and all interfaces from the host will be available to the -container. The container's hostname will match the hostname on the host -system. Publishing ports and linking to other containers will not work -when sharing the host's network stack. +network stack and all interfaces from the host will be available to the +container. The container's hostname will match the hostname on the host +system. Publishing ports and linking to other containers will not work +when sharing the host's network stack. #### Mode: container -With the networking mode set to `container` a container will share the -network stack of another container. The other container's name must be + +With the networking mode set to `container` a container will share the +network stack of another container. The other container's name must be provided in the format of `--net container:`. -Example running a redis container with redis binding to localhost then -running the redis-cli and connecting to the redis server over the -localhost interface. +Example running a Redis container with Redis binding to `localhost` then +running the `redis-cli` command and connecting to the Redis server over the +`localhost` interface. $ docker run -d --name redis example/redis --bind 127.0.0.1 $ # use the redis container's network stack to access localhost @@ -211,15 +213,14 @@ container: -c=0 : CPU shares (relative weight) The operator can constrain the memory available to a container easily -with `docker run -m`. If the host supports swap -memory, then the `-m` memory setting can be larger -than physical RAM. +with `docker run -m`. If the host supports swap memory, then the `-m` +memory setting can be larger than physical RAM. Similarly the operator can increase the priority of this container with -the `-c` option. By default, all containers run at -the same priority and get the same proportion of CPU cycles, but you can -tell the kernel to give more shares of CPU time to one or more -containers when you start them via Docker. +the `-c` option. By default, all containers run at the same priority and +get the same proportion of CPU cycles, but you can tell the kernel to +give more shares of CPU time to one or more containers when you start +them via Docker. ## Runtime Privilege and LXC Configuration @@ -277,19 +278,20 @@ commandline: $ docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...] -This command is optional because the person who created the `IMAGE` may have -already provided a default `COMMAND` using the Dockerfile `CMD`. As the -operator (the person running a container from the image), you can override that -`CMD` just by specifying a new `COMMAND`. +This command is optional because the person who created the `IMAGE` may +have already provided a default `COMMAND` using the Dockerfile `CMD` +instruction. As the operator (the person running a container from the +image), you can override that `CMD` instruction just by specifying a new +`COMMAND`. -If the image also specifies an `ENTRYPOINT` then the `CMD` or `COMMAND` get -appended as arguments to the `ENTRYPOINT`. +If the image also specifies an `ENTRYPOINT` then the `CMD` or `COMMAND` +get appended as arguments to the `ENTRYPOINT`. ## ENTRYPOINT (Default Command to Execute at Runtime) --entrypoint="": Overwrite the default entrypoint set by the image -The ENTRYPOINT of an image is similar to a `COMMAND` because it +The `ENTRYPOINT` of an image is similar to a `COMMAND` because it specifies what executable to run when the container starts, but it is (purposely) more difficult to override. The `ENTRYPOINT` gives a container its default nature or behavior, so that when you set an @@ -310,10 +312,10 @@ or two examples of how to pass more parameters to that ENTRYPOINT: ## EXPOSE (Incoming Ports) -The Dockerfile doesn't give much control over networking, only providing the -`EXPOSE` instruction to give a hint to the operator about what incoming ports -might provide services. The following options work with or override the -Dockerfile's exposed defaults: +The Dockerfile doesn't give much control over networking, only providing +the `EXPOSE` instruction to give a hint to the operator about what +incoming ports might provide services. The following options work with +or override the Dockerfile's exposed defaults: --expose=[]: Expose a port from the container without publishing it to your host @@ -324,34 +326,34 @@ Dockerfile's exposed defaults: (use 'docker port' to see the actual mapping) --link="" : Add link to another container (name:alias) -As mentioned previously, `EXPOSE` (and `--expose`) make a port available **in** -a container for incoming connections. The port number on the inside of the -container (where the service listens) does not need to be the same number as the -port exposed on the outside of the container (where clients connect), so inside -the container you might have an HTTP service listening on port 80 (and so you -`EXPOSE 80` in the Dockerfile), but outside the container the port might be -42800. +As mentioned previously, `EXPOSE` (and `--expose`) make a port available +**in** a container for incoming connections. The port number on the +inside of the container (where the service listens) does not need to be +the same number as the port exposed on the outside of the container +(where clients connect), so inside the container you might have an HTTP +service listening on port 80 (and so you `EXPOSE 80` in the Dockerfile), +but outside the container the port might be 42800. -To help a new client container reach the server container's internal port -operator `--expose`'d by the operator or `EXPOSE`'d by the developer, the -operator has three choices: start the server container with `-P` or `-p,` or -start the client container with `--link`. +To help a new client container reach the server container's internal +port operator `--expose`'d by the operator or `EXPOSE`'d by the +developer, the operator has three choices: start the server container +with `-P` or `-p,` or start the client container with `--link`. If the operator uses `-P` or `-p` then Docker will make the exposed port -accessible on the host and the ports will be available to any client that -can reach the host. To find the map between the host ports and the exposed -ports, use `docker port`) +accessible on the host and the ports will be available to any client +that can reach the host. To find the map between the host ports and the +exposed ports, use `docker port`) -If the operator uses `--link` when starting the new client container, then the -client container can access the exposed port via a private networking interface. -Docker will set some environment variables in the client container to help -indicate which interface and port to use. +If the operator uses `--link` when starting the new client container, +then the client container can access the exposed port via a private +networking interface. Docker will set some environment variables in the +client container to help indicate which interface and port to use. ## ENV (Environment Variables) -The operator can **set any environment variable** in the container by using one -or more `-e` flags, even overriding those already defined by the developer with -a Dockerfile `ENV`: +The operator can **set any environment variable** in the container by +using one or more `-e` flags, even overriding those already defined by +the developer with a Dockerfile `ENV`: $ docker run -e "deep=purple" --rm ubuntu /bin/bash -c export declare -x HOME="/" @@ -420,18 +422,19 @@ mechanism to communicate with a linked container by its alias: If "container-dir" is missing, then docker creates a new volume. --volumes-from="": Mount all volumes from the given container(s) -The volumes commands are complex enough to have their own documentation in -section [*Share Directories via Volumes*](/userguide/dockervolumes/#volume-def). -A developer can define one or more `VOLUME's associated with an image, but only the -operator can give access from one container to another (or from a container to a +The volumes commands are complex enough to have their own documentation +in section [*Share Directories via +Volumes*](/userguide/dockervolumes/#volume-def). A developer can define +one or more `VOLUME`'s associated with an image, but only the operator +can give access from one container to another (or from a container to a volume mounted on the host). ## USER -The default user within a container is `root` (id = 0), but if the developer -created additional users, those are accessible too. The developer can set a -default user to run the first process with the `Dockerfile USER` command, -but the operator can override it: +The default user within a container is `root` (id = 0), but if the +developer created additional users, those are accessible too. The +developer can set a default user to run the first process with the +Dockerfile `USER` instruction, but the operator can override it: -u="": Username or UID From 26332fe339d4d939d91fe00a0df849d564026005 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Mon, 30 Jun 2014 14:19:16 +1000 Subject: [PATCH 136/167] Add the 1.13 API docs to the menu Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 5c3147a28..21b334197 100755 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -103,6 +103,7 @@ pages: - ['reference/api/registry_api.md', 'Reference', 'Docker Registry API'] - ['reference/api/hub_registry_spec.md', 'Reference', 'Docker Hub and Registry Spec'] - ['reference/api/docker_remote_api.md', 'Reference', 'Docker Remote API'] +- ['reference/api/docker_remote_api_v1.13.md', 'Reference', 'Docker Remote API v1.13'] - ['reference/api/docker_remote_api_v1.12.md', 'Reference', 'Docker Remote API v1.12'] - ['reference/api/docker_remote_api_v1.11.md', 'Reference', 'Docker Remote API v1.11'] - ['reference/api/docker_remote_api_v1.10.md', '**HIDDEN**'] From c2699d8d896d592dc02276d76dfdf544fd26d0dd Mon Sep 17 00:00:00 2001 From: Adrien Folie Date: Mon, 30 Jun 2014 09:36:46 +0000 Subject: [PATCH 137/167] Add missing test for full coverage Docker-DCO-1.1-Signed-off-by: Adrien Folie (github: folieadrien) --- api/server/server_unit_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index 4840a2526..2d14f8955 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -295,6 +295,9 @@ func TestGetImagesHistory(t *testing.T) { var called bool eng.Register("history", func(job *engine.Job) engine.Status { called = true + if len(job.Args) == 0 { + t.Fatal("Job arguments is empty") + } if job.Args[0] != imageName { t.Fatalf("name != '%s': %#v", imageName, job.Args[0]) } From eb1e8e884d92a7086af96663d0c658d838315490 Mon Sep 17 00:00:00 2001 From: unclejack Date: Mon, 30 Jun 2014 22:22:29 +0300 Subject: [PATCH 138/167] integration cli: add imageExists to docker utils Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- integration-cli/docker_utils.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index cc4501243..22217e2f0 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -66,6 +66,15 @@ func deleteImages(images string) error { return err } +func imageExists(image string) error { + inspectCmd := exec.Command(dockerBinary, "inspect", image) + exitCode, err := runCommand(inspectCmd) + if exitCode != 0 && err == nil { + err = fmt.Errorf("couldn't find image '%s'", image) + } + return err +} + func cmd(t *testing.T, args ...string) (string, int, error) { out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out)) From 63e28cc363c5f13288335e811f075e2423375b05 Mon Sep 17 00:00:00 2001 From: unclejack Date: Mon, 30 Jun 2014 22:25:50 +0300 Subject: [PATCH 139/167] make TestRemoveContainerRunning handle signals This lowers the test execution time by about 5 seconds. Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- integration-cli/docker_cli_rm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-cli/docker_cli_rm_test.go b/integration-cli/docker_cli_rm_test.go index e25c9991d..34b5df033 100644 --- a/integration-cli/docker_cli_rm_test.go +++ b/integration-cli/docker_cli_rm_test.go @@ -43,7 +43,7 @@ func TestRemoveContainerWithVolume(t *testing.T) { } func TestRemoveContainerRunning(t *testing.T) { - cmd := exec.Command(dockerBinary, "run", "-d", "--name", "foo", "busybox", "sleep", "300") + cmd := exec.Command(dockerBinary, "run", "-dt", "--name", "foo", "busybox", "top") if _, err := runCommand(cmd); err != nil { t.Fatal(err) } From 262d45e0fe483dbc6d27bc6af51590a8be42d55f Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Mon, 30 Jun 2014 18:27:15 -0400 Subject: [PATCH 140/167] Use new libcontainer.State API Docker-DCO-1.1-Signed-off-by: Tibor Vass (github: tiborvass) --- daemon/execdriver/native/driver.go | 12 ++---------- daemon/execdriver/native/info.go | 5 +++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 7cbb563ea..1f27ef77b 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -171,7 +171,7 @@ func (d *driver) Unpause(c *execdriver.Command) error { func (d *driver) Terminate(p *execdriver.Command) error { // lets check the start time for the process - started, err := d.readStartTime(p) + state, err := libcontainer.GetState(filepath.Join(d.root, p.ID)) if err != nil { // if we don't have the data on disk then we can assume the process is gone // because this is only removed after we know the process has stopped @@ -185,7 +185,7 @@ func (d *driver) Terminate(p *execdriver.Command) error { if err != nil { return err } - if started == currentStartTime { + if state.InitStartTime == currentStartTime { err = syscall.Kill(p.Process.Pid, 9) syscall.Wait4(p.Process.Pid, nil, 0, nil) } @@ -194,14 +194,6 @@ func (d *driver) Terminate(p *execdriver.Command) error { } -func (d *driver) readStartTime(p *execdriver.Command) (string, error) { - data, err := ioutil.ReadFile(filepath.Join(d.root, p.ID, "start")) - if err != nil { - return "", err - } - return string(data), nil -} - func (d *driver) Info(id string) execdriver.Info { return &info{ ID: id, diff --git a/daemon/execdriver/native/info.go b/daemon/execdriver/native/info.go index aef2f85c6..693a455a4 100644 --- a/daemon/execdriver/native/info.go +++ b/daemon/execdriver/native/info.go @@ -1,8 +1,9 @@ package native import ( - "os" "path/filepath" + + "github.com/docker/libcontainer" ) type info struct { @@ -14,7 +15,7 @@ type info struct { // pid file for a container. If the file exists then the // container is currently running func (i *info) IsRunning() bool { - if _, err := os.Stat(filepath.Join(i.driver.root, i.ID, "pid")); err == nil { + if _, err := libcontainer.GetState(filepath.Join(i.driver.root, i.ID)); err == nil { return true } return false From b44e13ae023816ed9d36b6dc6d74f089fc402cab Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Fri, 27 Jun 2014 13:32:01 +0200 Subject: [PATCH 141/167] Fixed typographical erros in the documentation Used the RETF rules provided by Wikipedia to fix some typographical errors in the Markdown files of the documentation with the following script: https://github.com/openstack/openstack-doc-tools/tree/master/cleanup/retf Docker-DCO-1.1-Signed-off-by: Christian Berendt (github: berendt) Docker-DCO-1.1-Signed-off-by: Christian Berendt (github: SvenDowideit) --- docs/man/Dockerfile.5.md | 2 +- docs/man/docker-commit.1.md | 2 +- docs/man/docker-run.1.md | 4 ++-- docs/sources/reference/api/docker_remote_api_v1.0.md | 6 +++--- docs/sources/reference/api/docker_remote_api_v1.1.md | 6 +++--- docs/sources/reference/api/docker_remote_api_v1.10.md | 6 +++--- docs/sources/reference/api/docker_remote_api_v1.11.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.12.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.13.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.2.md | 6 +++--- docs/sources/reference/api/docker_remote_api_v1.3.md | 6 +++--- docs/sources/reference/api/docker_remote_api_v1.4.md | 8 ++++---- docs/sources/reference/api/docker_remote_api_v1.5.md | 8 ++++---- docs/sources/reference/api/docker_remote_api_v1.6.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.7.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.8.md | 10 +++++----- docs/sources/reference/api/docker_remote_api_v1.9.md | 10 +++++----- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/docs/man/Dockerfile.5.md b/docs/man/Dockerfile.5.md index d66912210..73c1312b8 100644 --- a/docs/man/Dockerfile.5.md +++ b/docs/man/Dockerfile.5.md @@ -93,7 +93,7 @@ or they omit the executable, an ENTRYPOINT must be specified. When used in the shell or exec formats, the CMD instruction sets the command to be executed when running the image. - If you use the shell form of of the CMD, the executes in /bin/sh -c: + If you use the shell form of the CMD, the executes in /bin/sh -c: **FROM ubuntu** **CMD echo "This is a test." | wc -** If you run wihtout a shell, then you must express the command as a diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index 03bf17872..b72c385bf 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -14,7 +14,7 @@ Using an existing container's name or ID you can create a new image. # OPTIONS **-a, --author**="" - Author name. (eg. "John Hannibal Smith " + Author name. (e.g. "John Hannibal Smith " **-m, --message**="" Commit message diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index 1abcf03f2..bac64aa18 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -13,7 +13,7 @@ docker-run - Run a process in an isolated container [**--link**=*name*:*alias*] [**-e**|**--env**=*environment*] [**--entrypoint**=*command*] [**--expose**=*port*] [**-P**|**--publish-all**[=*false*]] -[**-p**|**--publish**=*port-mappping*] [**-h**|**--hostname**=*hostname*] +[**-p**|**--publish**=*port-mapping*] [**-h**|**--hostname**=*hostname*] [**--rm**[=*false*]] [**--privileged**[=*false*]] [**-i**|**--interactive**[=*false*]] [**-t**|**--tty**[=*false*]] [**--lxc-conf**=*options*] @@ -71,7 +71,7 @@ stopping the process by pressing the keys CTRL-P CTRL-Q. **--dns**=*IP-address* Set custom DNS servers. This option can be used to override the DNS configuration passed to the container. Typically this is necessary when the -host DNS configuration is invalid for the container (eg. 127.0.0.1). When this +host DNS configuration is invalid for the container (e.g. 127.0.0.1). When this is the case the **-dns** flags is necessary for every run. diff --git a/docs/sources/reference/api/docker_remote_api_v1.0.md b/docs/sources/reference/api/docker_remote_api_v1.0.md index 2f17b2a74..b5ca1b513 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.0.md +++ b/docs/sources/reference/api/docker_remote_api_v1.0.md @@ -605,8 +605,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"" @@ -935,7 +935,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.1.md b/docs/sources/reference/api/docker_remote_api_v1.1.md index e777901c6..70617a4a1 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.1.md +++ b/docs/sources/reference/api/docker_remote_api_v1.1.md @@ -612,8 +612,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"" @@ -946,7 +946,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.10.md b/docs/sources/reference/api/docker_remote_api_v1.10.md index 0292c1ab2..01a176d86 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.10.md +++ b/docs/sources/reference/api/docker_remote_api_v1.10.md @@ -286,7 +286,7 @@ List processes running inside the container `id`   - - **ps\_args** – ps arguments to use (eg. aux) + - **ps\_args** – ps arguments to use (e.g. aux) Status Codes: @@ -530,7 +530,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -1181,7 +1181,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.11.md b/docs/sources/reference/api/docker_remote_api_v1.11.md index 63444a83e..35abd35fb 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.11.md +++ b/docs/sources/reference/api/docker_remote_api_v1.11.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -570,7 +570,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -791,8 +791,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1223,7 +1223,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.12.md b/docs/sources/reference/api/docker_remote_api_v1.12.md index 51727be26..66408eb15 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.12.md +++ b/docs/sources/reference/api/docker_remote_api_v1.12.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -611,7 +611,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -865,8 +865,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1301,7 +1301,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.13.md b/docs/sources/reference/api/docker_remote_api_v1.13.md index 117052aeb..454aec530 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.13.md +++ b/docs/sources/reference/api/docker_remote_api_v1.13.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -613,7 +613,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -867,8 +867,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1304,7 +1304,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.2.md b/docs/sources/reference/api/docker_remote_api_v1.2.md index cecab5bb4..82084606e 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.2.md +++ b/docs/sources/reference/api/docker_remote_api_v1.2.md @@ -628,8 +628,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"" @@ -959,7 +959,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.3.md b/docs/sources/reference/api/docker_remote_api_v1.3.md index 1d60b4300..b28194d88 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.3.md +++ b/docs/sources/reference/api/docker_remote_api_v1.3.md @@ -678,8 +678,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"" @@ -1009,7 +1009,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.4.md b/docs/sources/reference/api/docker_remote_api_v1.4.md index f7d6e82c1..be5678d67 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.4.md +++ b/docs/sources/reference/api/docker_remote_api_v1.4.md @@ -264,7 +264,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -724,8 +724,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"", @@ -1055,7 +1055,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.5.md b/docs/sources/reference/api/docker_remote_api_v1.5.md index 53d970acc..08e7077c1 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.5.md +++ b/docs/sources/reference/api/docker_remote_api_v1.5.md @@ -261,7 +261,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -725,8 +725,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"centos", "Volumes":null, "VolumesFrom":"", @@ -1067,7 +1067,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.6.md b/docs/sources/reference/api/docker_remote_api_v1.6.md index 9b7cded33..e657252f1 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.6.md +++ b/docs/sources/reference/api/docker_remote_api_v1.6.md @@ -311,7 +311,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -558,7 +558,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -832,8 +832,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1163,7 +1163,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.7.md b/docs/sources/reference/api/docker_remote_api_v1.7.md index 3432e9bb2..66a93667a 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.7.md +++ b/docs/sources/reference/api/docker_remote_api_v1.7.md @@ -267,7 +267,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -507,7 +507,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -751,8 +751,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1112,7 +1112,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") - **run** – config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]}) diff --git a/docs/sources/reference/api/docker_remote_api_v1.8.md b/docs/sources/reference/api/docker_remote_api_v1.8.md index 184e107cd..4e1f02bed 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.8.md +++ b/docs/sources/reference/api/docker_remote_api_v1.8.md @@ -303,7 +303,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -549,7 +549,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -793,8 +793,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1157,7 +1157,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") - **run** – config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]}) diff --git a/docs/sources/reference/api/docker_remote_api_v1.9.md b/docs/sources/reference/api/docker_remote_api_v1.9.md index fc9f9b8d5..8551bed84 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.9.md +++ b/docs/sources/reference/api/docker_remote_api_v1.9.md @@ -303,7 +303,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (eg. aux) + - **ps_args** – ps arguments to use (e.g. aux) Status Codes: @@ -553,7 +553,7 @@ Attach to the container `id` `STREAM_TYPE` can be: - - 0: stdin (will be writen on stdout) + - 0: stdin (will be written on stdout) - 1: stdout - 2: stderr @@ -797,8 +797,8 @@ Return low-level information on the image `name` "OpenStdin":true, "StdinOnce":false, "Env":null, - "Cmd": ["/bin/bash"] - ,"Dns":null, + "Cmd": ["/bin/bash"], + "Dns":null, "Image":"base", "Volumes":null, "VolumesFrom":"", @@ -1194,7 +1194,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (eg. "John Hannibal Smith + - **author** – author (e.g. "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: From fde10cf87b9f0df6d8aa8683721a6f9d71dda516 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Mon, 30 Jun 2014 11:31:15 +1000 Subject: [PATCH 142/167] blindly make all uses of e\.?g\.? into e.g., Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/README.md | 2 +- docs/man/docker-commit.1.md | 2 +- docs/man/docker-images.1.md | 2 +- docs/man/docker-inspect.1.md | 2 +- docs/man/docker-pull.1.md | 2 +- docs/man/docker-run.1.md | 2 +- docs/man/docker-tag.1.md | 2 +- .../articles/cfengine_process_management.md | 2 +- docs/sources/articles/https.md | 2 +- docs/sources/articles/runmetrics.md | 8 ++++---- docs/sources/articles/security.md | 14 +++++++------- docs/sources/contributing/devenvironment.md | 2 +- docs/sources/installation/rackspace.md | 2 +- docs/sources/reference/api/docker_remote_api.md | 2 +- .../reference/api/docker_remote_api_v1.0.md | 2 +- .../reference/api/docker_remote_api_v1.1.md | 2 +- .../reference/api/docker_remote_api_v1.10.md | 4 ++-- .../reference/api/docker_remote_api_v1.11.md | 4 ++-- .../reference/api/docker_remote_api_v1.12.md | 4 ++-- .../reference/api/docker_remote_api_v1.13.md | 4 ++-- .../reference/api/docker_remote_api_v1.2.md | 2 +- .../reference/api/docker_remote_api_v1.3.md | 2 +- .../reference/api/docker_remote_api_v1.4.md | 4 ++-- .../reference/api/docker_remote_api_v1.5.md | 4 ++-- .../reference/api/docker_remote_api_v1.6.md | 4 ++-- .../reference/api/docker_remote_api_v1.7.md | 4 ++-- .../reference/api/docker_remote_api_v1.8.md | 4 ++-- .../reference/api/docker_remote_api_v1.9.md | 4 ++-- docs/sources/reference/api/hub_registry_spec.md | 4 ++-- docs/sources/reference/api/registry_api.md | 4 ++-- docs/sources/reference/commandline/cli.md | 6 +++--- docs/sources/terms/repository.md | 6 +++--- 32 files changed, 57 insertions(+), 57 deletions(-) diff --git a/docs/README.md b/docs/README.md index d74ec4ee8..99dc8712c 100755 --- a/docs/README.md +++ b/docs/README.md @@ -70,7 +70,7 @@ in their shell: ### Images -When you need to add images, try to make them as small as possible (e.g. as +When you need to add images, try to make them as small as possible (e.g., as gifs). Usually images should go in the same directory as the `.md` file which references them, or in a subdirectory if one already exists. diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index b72c385bf..e9f339338 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -14,7 +14,7 @@ Using an existing container's name or ID you can create a new image. # OPTIONS **-a, --author**="" - Author name. (e.g. "John Hannibal Smith " + Author name. (e.g., "John Hannibal Smith " **-m, --message**="" Commit message diff --git a/docs/man/docker-images.1.md b/docs/man/docker-images.1.md index a46679809..602ccf7c9 100644 --- a/docs/man/docker-images.1.md +++ b/docs/man/docker-images.1.md @@ -17,7 +17,7 @@ docker-images - List the images in the local repository This command lists the images stored in the local Docker repository. By default, intermediate images, used during builds, are not listed. Some of the -output, e.g. image ID, is truncated, for space reasons. However the truncated +output, e.g., image ID, is truncated, for space reasons. However the truncated image ID, and often the first few characters, are enough to be used in other Docker commands that use the image ID. The output includes repository, tag, image ID, date created and the virtual size. diff --git a/docs/man/docker-inspect.1.md b/docs/man/docker-inspect.1.md index a49e42138..a82c76a62 100644 --- a/docs/man/docker-inspect.1.md +++ b/docs/man/docker-inspect.1.md @@ -142,7 +142,7 @@ output: ## Getting information on an image -Use an image's ID or name (e.g. repository/name[:tag]) to get information +Use an image's ID or name (e.g., repository/name[:tag]) to get information on it. # docker inspect 58394af37342 diff --git a/docs/man/docker-pull.1.md b/docs/man/docker-pull.1.md index 40b7425f7..d8e177b2b 100644 --- a/docs/man/docker-pull.1.md +++ b/docs/man/docker-pull.1.md @@ -10,7 +10,7 @@ docker-pull - Pull an image or a repository from the registry # DESCRIPTION This command pulls down an image or a repository from the registry. If -there is more than one image for a repository (e.g. fedora) then all +there is more than one image for a repository (e.g., fedora) then all images for that repository name are pulled down including any tags. It is also possible to specify a non-default registry to pull from. diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index bac64aa18..ec9db8fd0 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -71,7 +71,7 @@ stopping the process by pressing the keys CTRL-P CTRL-Q. **--dns**=*IP-address* Set custom DNS servers. This option can be used to override the DNS configuration passed to the container. Typically this is necessary when the -host DNS configuration is invalid for the container (e.g. 127.0.0.1). When this +host DNS configuration is invalid for the container (e.g., 127.0.0.1). When this is the case the **-dns** flags is necessary for every run. diff --git a/docs/man/docker-tag.1.md b/docs/man/docker-tag.1.md index 0c4276990..01b5b9137 100644 --- a/docs/man/docker-tag.1.md +++ b/docs/man/docker-tag.1.md @@ -35,7 +35,7 @@ Note that here TAG is a part of the overall name or "tag". ## Giving an image a new alias -Here is an example of aliasing an image (e.g. 0e5574283393) as "httpd" and +Here is an example of aliasing an image (e.g., 0e5574283393) as "httpd" and tagging it into the "fedora" repository with "version1.0": docker tag 0e5574283393 fedora/httpd:version1.0 diff --git a/docs/sources/articles/cfengine_process_management.md b/docs/sources/articles/cfengine_process_management.md index ee5ba238a..6bb4df66a 100644 --- a/docs/sources/articles/cfengine_process_management.md +++ b/docs/sources/articles/cfengine_process_management.md @@ -87,7 +87,7 @@ The first two steps can be done as part of a Dockerfile, as follows. ENTRYPOINT ["/var/cfengine/bin/docker_processes_run.sh"] By saving this file as Dockerfile to a working directory, you can then build -your image with the docker build command, e.g. +your image with the docker build command, e.g., `docker build -t managed_image`. ### Testing the container diff --git a/docs/sources/articles/https.md b/docs/sources/articles/https.md index cc8c6a976..b6ae4ef37 100644 --- a/docs/sources/articles/https.md +++ b/docs/sources/articles/https.md @@ -29,7 +29,7 @@ keys: $ openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem Now that we have a CA, you can create a server key and certificate -signing request. Make sure that "Common Name (e.g. server FQDN or YOUR +signing request. Make sure that "Common Name (e.g., server FQDN or YOUR name)" matches the hostname you will use to connect to Docker or just use `\*` for a certificate valid for any hostname: diff --git a/docs/sources/articles/runmetrics.md b/docs/sources/articles/runmetrics.md index bf4fe21c4..9c871a24f 100644 --- a/docs/sources/articles/runmetrics.md +++ b/docs/sources/articles/runmetrics.md @@ -35,7 +35,7 @@ known to the system, the hierarchy they belong to, and how many groups they cont You can also look at `/proc//cgroup` to see which control groups a process belongs to. The control group will be shown as a path relative to the root of -the hierarchy mountpoint; e.g. `/` means “this process has not been assigned into +the hierarchy mountpoint; e.g., `/` means “this process has not been assigned into a particular group”, while `/lxc/pumpkin` means that the process is likely to be a member of a container named `pumpkin`. @@ -106,9 +106,9 @@ to the processes within the cgroup, excluding sub-cgroups. The second half (with the `total_` prefix) includes sub-cgroups as well. Some metrics are "gauges", i.e. values that can increase or decrease -(e.g. swap, the amount of swap space used by the members of the cgroup). +(e.g., swap, the amount of swap space used by the members of the cgroup). Some others are "counters", i.e. values that can only go up, because -they represent occurrences of a specific event (e.g. pgfault, which +they represent occurrences of a specific event (e.g., pgfault, which indicates the number of page faults which happened since the creation of the cgroup; this number can never decrease). @@ -410,7 +410,7 @@ used. Docker makes this difficult because it relies on `lxc-start`, which carefully cleans up after itself, but it is still possible. It is -usually easier to collect metrics at regular intervals (e.g. every +usually easier to collect metrics at regular intervals (e.g., every minute, with the collectd LXC plugin) and rely on that instead. But, if you'd still like to gather the stats when a container stops, diff --git a/docs/sources/articles/security.md b/docs/sources/articles/security.md index 83704e434..4c39c18a6 100644 --- a/docs/sources/articles/security.md +++ b/docs/sources/articles/security.md @@ -91,8 +91,8 @@ without any restriction. This sounds crazy? Well, you have to know that same way**. Nothing prevents you from sharing your root filesystem (or even your root block device) with a virtual machine. -This has a strong security implication: if you instrument Docker from -e.g. a web server to provision containers through an API, you should be +This has a strong security implication: for example, if you instrument Docker +from a web server to provision containers through an API, you should be even more careful than usual with parameter checking, to make sure that a malicious user cannot pass crafted parameters causing Docker to create arbitrary containers. @@ -108,7 +108,7 @@ socket. You can also expose the REST API over HTTP if you explicitly decide so. However, if you do that, being aware of the above mentioned security implication, you should ensure that it will be reachable only from a -trusted network or VPN; or protected with e.g. `stunnel` and client SSL +trusted network or VPN; or protected with e.g., `stunnel` and client SSL certificates. You can also secure them with [HTTPS and certificates](/articles/https/). @@ -136,7 +136,7 @@ Finally, if you run Docker on a server, it is recommended to run exclusively Docker in the server, and move all other services within containers controlled by Docker. Of course, it is fine to keep your favorite admin tools (probably at least an SSH server), as well as -existing monitoring/supervision processes (e.g. NRPE, collectd, etc). +existing monitoring/supervision processes (e.g., NRPE, collectd, etc). ## Linux Kernel Capabilities @@ -154,8 +154,8 @@ This means a lot for container security; let's see why! Your average server (bare metal or virtual machine) needs to run a bunch of processes as root. Those typically include SSH, cron, syslogd; -hardware management tools (to e.g. load modules), network configuration -tools (to handle e.g. DHCP, WPA, or VPNs), and much more. A container is +hardware management tools (e.g., load modules), network configuration +tools (e.g., to handle DHCP, WPA, or VPNs), and much more. A container is very different, because almost all of those tasks are handled by the infrastructure around the container: @@ -232,7 +232,7 @@ harden a Docker host. Here are a few examples. mechanism. Just like there are many third-party tools to augment Docker containers -with e.g. special network topologies or shared filesystems, you can +with e.g., special network topologies or shared filesystems, you can expect to see tools to harden existing Docker containers without affecting Docker's core. diff --git a/docs/sources/contributing/devenvironment.md b/docs/sources/contributing/devenvironment.md index 54b867cf4..9188031e3 100644 --- a/docs/sources/contributing/devenvironment.md +++ b/docs/sources/contributing/devenvironment.md @@ -113,7 +113,7 @@ something like this ok github.com/dotcloud/docker/utils 0.017s If $TESTFLAGS is set in the environment, it is passed as extra arguments -to `go test`. You can use this to select certain tests to run, e.g. +to `go test`. You can use this to select certain tests to run, e.g., $ TESTFLAGS=`-run \^TestBuild\$` make test diff --git a/docs/sources/installation/rackspace.md b/docs/sources/installation/rackspace.md index 1aa969d1e..9fddf5e45 100644 --- a/docs/sources/installation/rackspace.md +++ b/docs/sources/installation/rackspace.md @@ -15,7 +15,7 @@ will need to install it. And this is a little more difficult on Rackspace. Rackspace boots their servers using grub's `menu.lst` -and does not like non `virtual` packages (e.g. Xen compatible) +and does not like non `virtual` packages (e.g., Xen compatible) kernels there, although they do work. This results in `update-grub` not having the expected result, and you will need to set the kernel manually. diff --git a/docs/sources/reference/api/docker_remote_api.md b/docs/sources/reference/api/docker_remote_api.md index 3f61db721..c3cce3ea3 100644 --- a/docs/sources/reference/api/docker_remote_api.md +++ b/docs/sources/reference/api/docker_remote_api.md @@ -373,7 +373,7 @@ List containers (/containers/json): Start containers (/containers//start): - - You can now pass host-specific configuration (e.g. bind mounts) in + - You can now pass host-specific configuration (e.g., bind mounts) in the POST body for start calls ## v1.2 diff --git a/docs/sources/reference/api/docker_remote_api_v1.0.md b/docs/sources/reference/api/docker_remote_api_v1.0.md index b5ca1b513..b906298b8 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.0.md +++ b/docs/sources/reference/api/docker_remote_api_v1.0.md @@ -935,7 +935,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.1.md b/docs/sources/reference/api/docker_remote_api_v1.1.md index 70617a4a1..4e449bcce 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.1.md +++ b/docs/sources/reference/api/docker_remote_api_v1.1.md @@ -946,7 +946,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.10.md b/docs/sources/reference/api/docker_remote_api_v1.10.md index 01a176d86..264cdefc2 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.10.md +++ b/docs/sources/reference/api/docker_remote_api_v1.10.md @@ -286,7 +286,7 @@ List processes running inside the container `id`   - - **ps\_args** – ps arguments to use (e.g. aux) + - **ps\_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1181,7 +1181,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.11.md b/docs/sources/reference/api/docker_remote_api_v1.11.md index 35abd35fb..ae2daae40 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.11.md +++ b/docs/sources/reference/api/docker_remote_api_v1.11.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1223,7 +1223,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.12.md b/docs/sources/reference/api/docker_remote_api_v1.12.md index 66408eb15..19fb24fe4 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.12.md +++ b/docs/sources/reference/api/docker_remote_api_v1.12.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1301,7 +1301,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.13.md b/docs/sources/reference/api/docker_remote_api_v1.13.md index 454aec530..9eddb2105 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.13.md +++ b/docs/sources/reference/api/docker_remote_api_v1.13.md @@ -290,7 +290,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1304,7 +1304,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.2.md b/docs/sources/reference/api/docker_remote_api_v1.2.md index 82084606e..37a8e1c01 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.2.md +++ b/docs/sources/reference/api/docker_remote_api_v1.2.md @@ -959,7 +959,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.3.md b/docs/sources/reference/api/docker_remote_api_v1.3.md index b28194d88..b510f660f 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.3.md +++ b/docs/sources/reference/api/docker_remote_api_v1.3.md @@ -1009,7 +1009,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.4.md b/docs/sources/reference/api/docker_remote_api_v1.4.md index be5678d67..0e4940262 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.4.md +++ b/docs/sources/reference/api/docker_remote_api_v1.4.md @@ -264,7 +264,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1055,7 +1055,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.5.md b/docs/sources/reference/api/docker_remote_api_v1.5.md index 08e7077c1..33c1aeca1 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.5.md +++ b/docs/sources/reference/api/docker_remote_api_v1.5.md @@ -261,7 +261,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1067,7 +1067,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.6.md b/docs/sources/reference/api/docker_remote_api_v1.6.md index e657252f1..4500c1554 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.6.md +++ b/docs/sources/reference/api/docker_remote_api_v1.6.md @@ -311,7 +311,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1163,7 +1163,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/docker_remote_api_v1.7.md b/docs/sources/reference/api/docker_remote_api_v1.7.md index 66a93667a..402efa426 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.7.md +++ b/docs/sources/reference/api/docker_remote_api_v1.7.md @@ -267,7 +267,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1112,7 +1112,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") - **run** – config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]}) diff --git a/docs/sources/reference/api/docker_remote_api_v1.8.md b/docs/sources/reference/api/docker_remote_api_v1.8.md index 4e1f02bed..78fccaf28 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.8.md +++ b/docs/sources/reference/api/docker_remote_api_v1.8.md @@ -303,7 +303,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1157,7 +1157,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") - **run** – config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]}) diff --git a/docs/sources/reference/api/docker_remote_api_v1.9.md b/docs/sources/reference/api/docker_remote_api_v1.9.md index 8551bed84..741a9ac95 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.9.md +++ b/docs/sources/reference/api/docker_remote_api_v1.9.md @@ -303,7 +303,7 @@ List processes running inside the container `id`   - - **ps_args** – ps arguments to use (e.g. aux) + - **ps_args** – ps arguments to use (e.g., aux) Status Codes: @@ -1194,7 +1194,7 @@ Create a new image from a container's changes - **repo** – repository - **tag** – tag - **m** – commit message - - **author** – author (e.g. "John Hannibal Smith + - **author** – author (e.g., "John Hannibal Smith <[hannibal@a-team.com](mailto:hannibal%40a-team.com)>") Status Codes: diff --git a/docs/sources/reference/api/hub_registry_spec.md b/docs/sources/reference/api/hub_registry_spec.md index bb0e4ec7e..1a2cf9423 100644 --- a/docs/sources/reference/api/hub_registry_spec.md +++ b/docs/sources/reference/api/hub_registry_spec.md @@ -77,11 +77,11 @@ grasp the context, here are some examples of registries: > - local mount point; > - remote docker addressed through SSH. -The latter would only require two new commands in docker, e.g. +The latter would only require two new commands in docker, e.g., `registryget` and `registryput`, wrapping access to the local filesystem (and optionally doing consistency checks). Authentication and authorization are then delegated -to SSH (e.g. with public keys). +to SSH (e.g., with public keys). ### Docker diff --git a/docs/sources/reference/api/registry_api.md b/docs/sources/reference/api/registry_api.md index f8bdd6657..2840693fa 100644 --- a/docs/sources/reference/api/registry_api.md +++ b/docs/sources/reference/api/registry_api.md @@ -62,10 +62,10 @@ grasp the context, here are some examples of registries: > - local mount point; > - remote docker addressed through SSH. -The latter would only require two new commands in docker, e.g. +The latter would only require two new commands in docker, e.g., `registryget` and `registryput`, wrapping access to the local filesystem (and optionally doing consistency checks). Authentication and authorization -are then delegated to SSH (e.g. with public keys). +are then delegated to SSH (e.g., with public keys). # Endpoints diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 15640cff1..56e420204 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -335,7 +335,7 @@ schema. Create a new image from a container's changes - -a, --author="" Author (eg. "John Hannibal Smith ") + -a, --author="" Author (e.g., "John Hannibal Smith ") -m, --message="" Commit message It can be useful to commit a container's file changes or settings into a @@ -518,7 +518,7 @@ by default. ### Filtering The filtering flag (`-f` or `--filter`) format is of "key=value". If there are more -than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`) +than one filter, then pass multiple flags (e.g., `--filter "foo=bar" --filter "bif=baz"`) Current filters: * dangling (boolean - true or false) @@ -929,7 +929,7 @@ removed before the image is removed. --sig-proxy=true Proxify received signals to the process (even in non-tty mode). SIGCHLD is not proxied. -t, --tty=false Allocate a pseudo-tty -u, --user="" Username or UID - -v, --volume=[] Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container) + -v, --volume=[] Bind mount a volume (e.g., from the host: -v /host:/container, from docker: -v /container) --volumes-from=[] Mount volumes from the specified container(s) -w, --workdir="" Working directory inside the container diff --git a/docs/sources/terms/repository.md b/docs/sources/terms/repository.md index 52c83d45d..c4d1d4353 100644 --- a/docs/sources/terms/repository.md +++ b/docs/sources/terms/repository.md @@ -13,10 +13,10 @@ server. Images can be associated with a repository (or multiple) by giving them an image name using one of three different commands: -1. At build time (e.g. `sudo docker build -t IMAGENAME`), -2. When committing a container (e.g. +1. At build time (e.g., `sudo docker build -t IMAGENAME`), +2. When committing a container (e.g., `sudo docker commit CONTAINERID IMAGENAME`) or -3. When tagging an image id with an image name (e.g. +3. When tagging an image id with an image name (e.g., `sudo docker tag IMAGEID IMAGENAME`). A Fully Qualified Image Name (FQIN) can be made up of 3 parts: From 17d870bed5ef997c30da1e8b9843f4e84202f8d4 Mon Sep 17 00:00:00 2001 From: Eric Windisch Date: Sat, 7 Jun 2014 23:37:31 -0700 Subject: [PATCH 143/167] Pause/freeze containers during commit Initiates a pause before committing a container, adds a pause option to the commit command, defaulting to 'true'. Fixes bug: #6267 Fixes bug: #3675 Docker-DCO-1.1-Signed-off-by: Eric Windisch (github: ewindisch) --- api/client/commands.go | 6 +++++ api/common.go | 2 +- api/server/server.go | 6 +++++ daemon/daemon.go | 8 +++++-- docs/sources/reference/commandline/cli.md | 6 +++++ integration-cli/docker_cli_commit_test.go | 27 +++++++++++++++++++++++ integration/container_test.go | 6 ++--- integration/runtime_test.go | 2 +- server/buildfile.go | 2 +- server/server.go | 2 +- 10 files changed, 58 insertions(+), 9 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 2bf40a666..9580ddd91 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1538,6 +1538,7 @@ func (cli *DockerCli) CmdPs(args ...string) error { func (cli *DockerCli) CmdCommit(args ...string) error { cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes") + flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith \")") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. @@ -1569,6 +1570,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error { v.Set("tag", tag) v.Set("comment", *flComment) v.Set("author", *flAuthor) + + if *flPause != true { + v.Set("pause", "0") + } + var ( config *runconfig.Config env engine.Env diff --git a/api/common.go b/api/common.go index a20c5d7d1..e73705000 100644 --- a/api/common.go +++ b/api/common.go @@ -11,7 +11,7 @@ import ( ) const ( - APIVERSION version.Version = "1.12" + APIVERSION version.Version = "1.13" DEFAULTHTTPHOST = "127.0.0.1" DEFAULTUNIXSOCKET = "/var/run/docker.sock" ) diff --git a/api/server/server.go b/api/server/server.go index 6cb9fc872..0cb7134c6 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -439,6 +439,12 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit utils.Errorf("%s", err) } + if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") { + job.Setenv("pause", "1") + } else { + job.Setenv("pause", r.FormValue("pause")) + } + job.Setenv("repo", r.Form.Get("repo")) job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) diff --git a/daemon/daemon.go b/daemon/daemon.go index aa8d2bad3..9500526f9 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -620,8 +620,12 @@ func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error // Commit creates a new filesystem image from the current state of a container. // The image can optionally be tagged into a repository -func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) { - // FIXME: freeze the container before copying it to avoid data corruption? +func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, pause bool, config *runconfig.Config) (*image.Image, error) { + if pause { + container.Pause() + defer container.Unpause() + } + if err := container.Mount(); err != nil { return nil, err } diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 56e420204..ff41ec432 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -337,6 +337,7 @@ schema. -a, --author="" Author (e.g., "John Hannibal Smith ") -m, --message="" Commit message + -p, --pause=true Pause container during commit It can be useful to commit a container's file changes or settings into a new image. This allows you debug a container by running an interactive @@ -344,6 +345,11 @@ shell, or to export a working dataset to another server. Generally, it is better to use Dockerfiles to manage your images in a documented and maintainable way. +By default, the container being committed and its processes will be paused +during the process of committing the image. This reduces the likelihood of +encountering data corruption during the process of creating the commit. +If this behavior is undesired, set the 'p' option to false. + ### Commit an existing container $ sudo docker ps diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index c02c89cd3..3a76a0f38 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -34,6 +34,33 @@ func TestCommitAfterContainerIsDone(t *testing.T) { logDone("commit - echo foo and commit the image") } +func TestCommitWithoutPause(t *testing.T) { + runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo") + out, _, _, err := runCommandWithStdoutStderr(runCmd) + errorOut(err, t, fmt.Sprintf("failed to run container: %v %v", out, err)) + + cleanedContainerID := stripTrailingCharacters(out) + + waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID) + _, _, err = runCommandWithOutput(waitCmd) + errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out)) + + commitCmd := exec.Command(dockerBinary, "commit", "-p", "false", cleanedContainerID) + out, _, err = runCommandWithOutput(commitCmd) + errorOut(err, t, fmt.Sprintf("failed to commit container to image: %v %v", out, err)) + + cleanedImageID := stripTrailingCharacters(out) + + inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID) + out, _, err = runCommandWithOutput(inspectCmd) + errorOut(err, t, fmt.Sprintf("failed to inspect image: %v %v", out, err)) + + deleteContainer(cleanedContainerID) + deleteImages(cleanedImageID) + + logDone("commit - echo foo and commit the image") +} + func TestCommitNewFile(t *testing.T) { cmd := exec.Command(dockerBinary, "run", "--name", "commiter", "busybox", "/bin/sh", "-c", "echo koye > /foo") if _, err := runCommand(cmd); err != nil { diff --git a/integration/container_test.go b/integration/container_test.go index 31a57df77..48b3321a5 100644 --- a/integration/container_test.go +++ b/integration/container_test.go @@ -421,7 +421,7 @@ func TestCopyVolumeUidGid(t *testing.T) { t.Errorf("Container shouldn't be running") } - img, err := r.Commit(container1, "", "", "unit test commited image", "", nil) + img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil) if err != nil { t.Error(err) } @@ -447,7 +447,7 @@ func TestCopyVolumeUidGid(t *testing.T) { t.Errorf("Container shouldn't be running") } - img2, err := r.Commit(container2, "", "", "unit test commited image", "", nil) + img2, err := r.Commit(container2, "", "", "unit test commited image", "", true, nil) if err != nil { t.Error(err) } @@ -481,7 +481,7 @@ func TestCopyVolumeContent(t *testing.T) { t.Errorf("Container shouldn't be running") } - img, err := r.Commit(container1, "", "", "unit test commited image", "", nil) + img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil) if err != nil { t.Error(err) } diff --git a/integration/runtime_test.go b/integration/runtime_test.go index 754146c5f..4c0f636d6 100644 --- a/integration/runtime_test.go +++ b/integration/runtime_test.go @@ -334,7 +334,7 @@ func TestDaemonCreate(t *testing.T) { } container, _, err = daemon.Create(config, "") - _, err = daemon.Commit(container, "testrepo", "testtag", "", "", config) + _, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config) if err != nil { t.Error(err) } diff --git a/server/buildfile.go b/server/buildfile.go index f5ef6e0d2..71fed660b 100644 --- a/server/buildfile.go +++ b/server/buildfile.go @@ -752,7 +752,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error { autoConfig := *b.config autoConfig.Cmd = autoCmd // Commit the container - image, err := b.daemon.Commit(container, "", "", "", b.maintainer, &autoConfig) + image, err := b.daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig) if err != nil { return err } diff --git a/server/server.go b/server/server.go index 0bbb9f31c..a0ff5fe89 100644 --- a/server/server.go +++ b/server/server.go @@ -1038,7 +1038,7 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status { return job.Error(err) } - img, err := srv.daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &newConfig) + img, err := srv.daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), job.GetenvBool("pause"), &newConfig) if err != nil { return job.Error(err) } From ae1ff4dea311f8c6ff025b4835dc5d751f1b6261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Petazzoni?= Date: Tue, 1 Jul 2014 07:47:59 -0700 Subject: [PATCH 144/167] Add FAQ entry about bundled vs packaged libraries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docker-DCO-1.1-Signed-off-by: Jérôme Petazzoni (github: jpetazzo) --- docs/sources/faq.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/sources/faq.md b/docs/sources/faq.md index 2d38cf2ff..635caac89 100644 --- a/docs/sources/faq.md +++ b/docs/sources/faq.md @@ -187,6 +187,44 @@ Please read [our blog post]( http://blog.docker.io/2014/01/docker-code-contributions-require-developer-certificate-of-origin/) on the introduction of the DCO. +### When building an image, should I prefer system libraries or bundled ones? + +*This is a summary of a discussion on the [docker-dev mailing list]( +https://groups.google.com/forum/#!topic/docker-dev/L2RBSPDu1L0).* + +Virtually all programs depend on third-party libraries. Most frequently, +they will use dynamic linking and some kind of package dependency, so +that when multiple programs need the same library, it is installed only once. + +Some programs, however, will bundle their third-party libraries, because +they rely on very specific versions of those libraries. For instance, +Node.js bundles OpenSSL; MongoDB bundles V8 and Boost (among others). + +When creating a Docker image, is it better to use the bundled libraries, +or should you build those programs so that they use the default system +libraries instead? + +The key point about system libraries is not about saving disk or memory +space. It is about security. All major distributions handle security +seriously, by having dedicated security teams, following up closely +with published vulnerabilities, and disclosing advisories themselves. +(Look at the [Debian Security Information](https://www.debian.org/security/) +for an example of those procedures.) Upstream developers, however, +do not always implement similar practices. + +Before setting up a Docker image to compile a program from source, +if you want to use bundled libraries, you should check if the upstream +authors provide a convenient way to announce security vulnerabilities, +and if they update their bundled libraries in a timely manner. If they +don't, you are exposing yourself (and the users of your image) to +security vulnerabilities. + +Likewise, before using packages built by others, you should check if the +channels providing those packages implement similar security best practices. +Downloading and installing an "all-in-one" .deb or .rpm sounds great at first, +except if you have no way to figure out that it contains a copy of the +OpenSSL library vulnerable to the [Heartbleed](http://heartbleed.com/) bug. + ### Can I help by adding some questions and answers? Definitely! You can fork [the repo](https://github.com/dotcloud/docker) and From 957c510d729ac3dcbe892b145fb2d9ed766be2ca Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 1 Jul 2014 00:39:38 +0000 Subject: [PATCH 145/167] updated docs & tests Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- docs/man/docker-commit.1.md | 3 +++ docs/sources/reference/api/docker_remote_api.md | 5 +++++ docs/sources/reference/commandline/cli.md | 2 +- integration-cli/docker_cli_commit_test.go | 4 ++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index e9f339338..c0f2c734c 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -19,6 +19,9 @@ Using an existing container's name or ID you can create a new image. **-m, --message**="" Commit message +**-p, --pause**=true + Pause container during commit + # EXAMPLES ## Creating a new image from an existing container diff --git a/docs/sources/reference/api/docker_remote_api.md b/docs/sources/reference/api/docker_remote_api.md index c3cce3ea3..36f35383e 100644 --- a/docs/sources/reference/api/docker_remote_api.md +++ b/docs/sources/reference/api/docker_remote_api.md @@ -49,6 +49,11 @@ daemon is configured to listen on. **New!** `start` and `stop` will now return 304 if the container's status is not modified +`POST /commit` + +**New!** +Added a `pause` parameter (default `true`) to pause the container during commit + ## v1.12 ### Full Documentation diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index ff41ec432..770ac1177 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -346,7 +346,7 @@ is better to use Dockerfiles to manage your images in a documented and maintainable way. By default, the container being committed and its processes will be paused -during the process of committing the image. This reduces the likelihood of +while the image is committed. This reduces the likelihood of encountering data corruption during the process of creating the commit. If this behavior is undesired, set the 'p' option to false. diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 3a76a0f38..7caf3588c 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -45,7 +45,7 @@ func TestCommitWithoutPause(t *testing.T) { _, _, err = runCommandWithOutput(waitCmd) errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out)) - commitCmd := exec.Command(dockerBinary, "commit", "-p", "false", cleanedContainerID) + commitCmd := exec.Command(dockerBinary, "commit", "-p=false", cleanedContainerID) out, _, err = runCommandWithOutput(commitCmd) errorOut(err, t, fmt.Sprintf("failed to commit container to image: %v %v", out, err)) @@ -58,7 +58,7 @@ func TestCommitWithoutPause(t *testing.T) { deleteContainer(cleanedContainerID) deleteImages(cleanedImageID) - logDone("commit - echo foo and commit the image") + logDone("commit - echo foo and commit the image with --pause=false") } func TestCommitNewFile(t *testing.T) { From c21c55e0b6d0f9582e4ee168fbd518b57dacc8fb Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Tue, 1 Jul 2014 15:03:07 -0400 Subject: [PATCH 146/167] more docs for dockerignore Docker-DCO-1.1-Signed-off-by: Tibor Vass (github: tiborvass) --- docs/sources/reference/builder.md | 32 +++++++++++++++++++++++ docs/sources/reference/commandline/cli.md | 6 ++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/docs/sources/reference/builder.md b/docs/sources/reference/builder.md index cf729664e..91190933c 100644 --- a/docs/sources/reference/builder.md +++ b/docs/sources/reference/builder.md @@ -83,6 +83,38 @@ be treated as an argument. This allows statements like: Here is the set of instructions you can use in a Dockerfile for building images. +## .dockerignore + +If a file named `.dockerignore` exists in the source repository, then it +is interpreted as a newline-separated list of exclusion patterns. +Exclusion patterns match files or directories relative to the source repository +that will be excluded from the context. Globbing is done using Go's +[filepath.Match](http://golang.org/pkg/path/filepath#Match) rules. + +The following example shows the use of the `.dockerignore` file to exclude the +`.git` directory from the context. Its effect can be seen in the changed size of +the uploaded context. + + $ docker build . + Uploading context 18.829 MB + Uploading context + Step 0 : FROM busybox + ---> 769b9341d937 + Step 1 : CMD echo Hello World + ---> Using cache + ---> 99cc1ad10469 + Successfully built 99cc1ad10469 + $ echo ".git" > .dockerignore + $ docker build . + Uploading context 6.76 MB + Uploading context + Step 0 : FROM busybox + ---> 769b9341d937 + Step 1 : CMD echo Hello World + ---> Using cache + ---> 99cc1ad10469 + Successfully built 99cc1ad10469 + ## FROM FROM diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 770ac1177..93b97b02f 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -223,7 +223,7 @@ will be excluded from the context. Globbing is done using Go's See also: -[*Dockerfile Reference*](/reference/builder/#dockerbuilder). +[*Dockerfile Reference*](/reference/builder). ### Examples: @@ -292,8 +292,8 @@ affect the build cache. ---> 99cc1ad10469 Successfully built 99cc1ad10469 -This example shows the use of the ``.dockerignore`` file to exclude the ``.git`` -directory the context. Its effect can be seen in the changed size of the +This example shows the use of the `.dockerignore` file to exclude the `.git` +directory from the context. Its effect can be seen in the changed size of the uploaded context. $ sudo docker build -t vieux/apache:2.0 . From 1dc0caf9c0170ab8e7f5a2f77f2dbdacff322eff Mon Sep 17 00:00:00 2001 From: Alexandr Morozov Date: Tue, 3 Jun 2014 15:09:33 +0400 Subject: [PATCH 147/167] Implement tail for docker logs Fixes #4330 Docker-DCO-1.1-Signed-off-by: Alexandr Morozov (github: LK4D4) --- api/client/commands.go | 2 + api/server/server.go | 1 + .../reference/api/docker_remote_api_v1.13.md | 16 +- docs/sources/reference/commandline/cli.md | 12 +- integration-cli/docker_cli_logs_test.go | 44 ++++++ pkg/tailfile/tailfile.go | 61 ++++++++ pkg/tailfile/tailfile_test.go | 148 ++++++++++++++++++ server/server.go | 65 +++++--- 8 files changed, 317 insertions(+), 32 deletions(-) create mode 100644 pkg/tailfile/tailfile.go create mode 100644 pkg/tailfile/tailfile_test.go diff --git a/api/client/commands.go b/api/client/commands.go index 9580ddd91..7cdcd5ebe 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1693,6 +1693,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error { cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container") follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output") times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps") + tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs(all logs by default)") ) if err := cmd.Parse(args); err != nil { @@ -1726,6 +1727,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error { if *follow { v.Set("follow", "1") } + v.Set("tail", *tail) return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil) } diff --git a/api/server/server.go b/api/server/server.go index 0cb7134c6..b3a0590fd 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -378,6 +378,7 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo return err } logsJob.Setenv("follow", r.Form.Get("follow")) + logsJob.Setenv("tail", r.Form.Get("tail")) logsJob.Setenv("stdout", r.Form.Get("stdout")) logsJob.Setenv("stderr", r.Form.Get("stderr")) logsJob.Setenv("timestamps", r.Form.Get("timestamps")) diff --git a/docs/sources/reference/api/docker_remote_api_v1.13.md b/docs/sources/reference/api/docker_remote_api_v1.13.md index 9eddb2105..e0ad95794 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.13.md +++ b/docs/sources/reference/api/docker_remote_api_v1.13.md @@ -306,7 +306,7 @@ Get stdout and stderr logs from the container ``id`` **Example request**: - GET /containers/4fa6e0f0c678/logs?stderr=1&stdout=1×tamps=1&follow=1 HTTP/1.1 + GET /containers/4fa6e0f0c678/logs?stderr=1&stdout=1×tamps=1&follow=1&tail=10 HTTP/1.1 **Example response**: @@ -319,14 +319,12 @@ Get stdout and stderr logs from the container ``id``   - - **follow** – 1/True/true or 0/False/false, return stream. - Default false - - **stdout** – 1/True/true or 0/False/false, if logs=true, return - stdout log. Default false - - **stderr** – 1/True/true or 0/False/false, if logs=true, return - stderr log. Default false - - **timestamps** – 1/True/true or 0/False/false, if logs=true, print - timestamps for every log line. Default false + - **follow** – 1/True/true or 0/False/false, return stream. Default false + - **stdout** – 1/True/true or 0/False/false, show stdout log. Default false + - **stderr** – 1/True/true or 0/False/false, show stderr log. Default false + - **timestamps** – 1/True/true or 0/False/false, print timestamps for + every log line. Default false + - **tail** – Output specified number of lines at the end of logs: `all` or ``. Default all Status Codes: diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 770ac1177..912feddfa 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -738,13 +738,15 @@ specify this by adding the server name. -f, --follow=false Follow log output -t, --timestamps=false Show timestamps + --tail="all" Output the specified number of lines at the end of logs (all logs by default) -The `docker logs` command batch-retrieves all logs -present at the time of execution. +The `docker logs` command batch-retrieves logs present at the time of execution. -The ``docker logs --follow`` command will first return all logs from the -beginning and then continue streaming new output from the container's `STDOUT` -and `STDERR`. +The `docker logs --follow` command will continue streaming the new output from +the container's `STDOUT` and `STDERR`. + +Passing a negative number or a non-integer to --tail is invalid and the +value is set to all in that case. This behavior may change in the future. ## port diff --git a/integration-cli/docker_cli_logs_test.go b/integration-cli/docker_cli_logs_test.go index 75235b6bb..8b1d00662 100644 --- a/integration-cli/docker_cli_logs_test.go +++ b/integration-cli/docker_cli_logs_test.go @@ -169,3 +169,47 @@ func TestLogsStderrInStdout(t *testing.T) { logDone("logs - stderr in stdout (with pseudo-tty)") } + +func TestLogsTail(t *testing.T) { + testLen := 100 + runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen)) + + out, _, _, err := runCommandWithStdoutStderr(runCmd) + errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err)) + + cleanedContainerID := stripTrailingCharacters(out) + exec.Command(dockerBinary, "wait", cleanedContainerID).Run() + + logsCmd := exec.Command(dockerBinary, "logs", "--tail", "5", cleanedContainerID) + out, _, _, err = runCommandWithStdoutStderr(logsCmd) + errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err)) + + lines := strings.Split(out, "\n") + + if len(lines) != 6 { + t.Fatalf("Expected log %d lines, received %d\n", 6, len(lines)) + } + + logsCmd = exec.Command(dockerBinary, "logs", "--tail", "all", cleanedContainerID) + out, _, _, err = runCommandWithStdoutStderr(logsCmd) + errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err)) + + lines = strings.Split(out, "\n") + + if len(lines) != testLen+1 { + t.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines)) + } + + logsCmd = exec.Command(dockerBinary, "logs", "--tail", "random", cleanedContainerID) + out, _, _, err = runCommandWithStdoutStderr(logsCmd) + errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err)) + + lines = strings.Split(out, "\n") + + if len(lines) != testLen+1 { + t.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines)) + } + + deleteContainer(cleanedContainerID) + logDone("logs - logs tail") +} diff --git a/pkg/tailfile/tailfile.go b/pkg/tailfile/tailfile.go new file mode 100644 index 000000000..2ffd36d25 --- /dev/null +++ b/pkg/tailfile/tailfile.go @@ -0,0 +1,61 @@ +package tailfile + +import ( + "bytes" + "errors" + "os" +) + +const blockSize = 1024 + +var eol = []byte("\n") +var ErrNonPositiveLinesNumber = errors.New("Lines number must be positive") + +//TailFile returns last n lines of file f +func TailFile(f *os.File, n int) ([][]byte, error) { + if n <= 0 { + return nil, ErrNonPositiveLinesNumber + } + size, err := f.Seek(0, os.SEEK_END) + if err != nil { + return nil, err + } + block := -1 + var data []byte + var cnt int + for { + var b []byte + step := int64(block * blockSize) + left := size + step // how many bytes to beginning + if left < 0 { + if _, err := f.Seek(0, os.SEEK_SET); err != nil { + return nil, err + } + b = make([]byte, blockSize+left) + if _, err := f.Read(b); err != nil { + return nil, err + } + data = append(b, data...) + break + } else { + b = make([]byte, blockSize) + if _, err := f.Seek(step, os.SEEK_END); err != nil { + return nil, err + } + if _, err := f.Read(b); err != nil { + return nil, err + } + data = append(b, data...) + } + cnt += bytes.Count(b, eol) + if cnt > n { + break + } + block-- + } + lines := bytes.Split(data, eol) + if n < len(lines) { + return lines[len(lines)-n-1 : len(lines)-1], nil + } + return lines[:len(lines)-1], nil +} diff --git a/pkg/tailfile/tailfile_test.go b/pkg/tailfile/tailfile_test.go new file mode 100644 index 000000000..31217c036 --- /dev/null +++ b/pkg/tailfile/tailfile_test.go @@ -0,0 +1,148 @@ +package tailfile + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestTailFile(t *testing.T) { + f, err := ioutil.TempFile("", "tail-test") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer os.RemoveAll(f.Name()) + testFile := []byte(`first line +second line +third line +fourth line +fifth line +next first line +next second line +next third line +next fourth line +next fifth line +last first line +next first line +next second line +next third line +next fourth line +next fifth line +next first line +next second line +next third line +next fourth line +next fifth line +last second line +last third line +last fourth line +last fifth line +truncated line`) + if _, err := f.Write(testFile); err != nil { + t.Fatal(err) + } + if _, err := f.Seek(0, os.SEEK_SET); err != nil { + t.Fatal(err) + } + expected := []string{"last fourth line", "last fifth line"} + res, err := TailFile(f, 2) + if err != nil { + t.Fatal(err) + } + for i, l := range res { + t.Logf("%s", l) + if expected[i] != string(l) { + t.Fatalf("Expected line %s, got %s", expected[i], l) + } + } +} + +func TestTailFileManyLines(t *testing.T) { + f, err := ioutil.TempFile("", "tail-test") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer os.RemoveAll(f.Name()) + testFile := []byte(`first line +second line +truncated line`) + if _, err := f.Write(testFile); err != nil { + t.Fatal(err) + } + if _, err := f.Seek(0, os.SEEK_SET); err != nil { + t.Fatal(err) + } + expected := []string{"first line", "second line"} + res, err := TailFile(f, 10000) + if err != nil { + t.Fatal(err) + } + for i, l := range res { + t.Logf("%s", l) + if expected[i] != string(l) { + t.Fatalf("Expected line %s, got %s", expected[i], l) + } + } +} + +func TestTailEmptyFile(t *testing.T) { + f, err := ioutil.TempFile("", "tail-test") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer os.RemoveAll(f.Name()) + res, err := TailFile(f, 10000) + if err != nil { + t.Fatal(err) + } + if len(res) != 0 { + t.Fatal("Must be empty slice from empty file") + } +} + +func TestTailNegativeN(t *testing.T) { + f, err := ioutil.TempFile("", "tail-test") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer os.RemoveAll(f.Name()) + testFile := []byte(`first line +second line +truncated line`) + if _, err := f.Write(testFile); err != nil { + t.Fatal(err) + } + if _, err := f.Seek(0, os.SEEK_SET); err != nil { + t.Fatal(err) + } + if _, err := TailFile(f, -1); err != ErrNonPositiveLinesNumber { + t.Fatalf("Expected ErrNonPositiveLinesNumber, got %s", err) + } + if _, err := TailFile(f, 0); err != ErrNonPositiveLinesNumber { + t.Fatalf("Expected ErrNonPositiveLinesNumber, got %s", err) + } +} + +func BenchmarkTail(b *testing.B) { + f, err := ioutil.TempFile("", "tail-test") + if err != nil { + b.Fatal(err) + } + defer f.Close() + defer os.RemoveAll(f.Name()) + for i := 0; i < 10000; i++ { + if _, err := f.Write([]byte("tailfile pretty interesting line\n")); err != nil { + b.Fatal(err) + } + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := TailFile(f, 1000); err != nil { + b.Fatal(err) + } + } +} diff --git a/server/server.go b/server/server.go index a0ff5fe89..3e6de00c1 100644 --- a/server/server.go +++ b/server/server.go @@ -22,6 +22,7 @@ package server import ( + "bytes" "encoding/json" "fmt" "io" @@ -52,6 +53,7 @@ import ( "github.com/dotcloud/docker/image" "github.com/dotcloud/docker/pkg/graphdb" "github.com/dotcloud/docker/pkg/signal" + "github.com/dotcloud/docker/pkg/tailfile" "github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/runconfig" "github.com/dotcloud/docker/utils" @@ -2153,8 +2155,10 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status { name = job.Args[0] stdout = job.GetenvBool("stdout") stderr = job.GetenvBool("stderr") + tail = job.Getenv("tail") follow = job.GetenvBool("follow") times = job.GetenvBool("timestamps") + lines = -1 format string ) if !(stdout || stderr) { @@ -2163,6 +2167,9 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status { if times { format = time.StampMilli } + if tail == "" { + tail = "all" + } container := srv.daemon.Get(name) if container == nil { return job.Errorf("No such container: %s", name) @@ -2190,25 +2197,47 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status { } else if err != nil { utils.Errorf("Error reading logs (json): %s", err) } else { - dec := json.NewDecoder(cLog) - for { - l := &utils.JSONLog{} + if tail != "all" { + var err error + lines, err = strconv.Atoi(tail) + if err != nil { + utils.Errorf("Failed to parse tail %s, error: %v, show all logs", err) + lines = -1 + } + } + if lines != 0 { + if lines > 0 { + f := cLog.(*os.File) + ls, err := tailfile.TailFile(f, lines) + if err != nil { + return job.Error(err) + } + tmp := bytes.NewBuffer([]byte{}) + for _, l := range ls { + fmt.Fprintf(tmp, "%s\n", l) + } + cLog = tmp + } + dec := json.NewDecoder(cLog) + for { + l := &utils.JSONLog{} - if err := dec.Decode(l); err == io.EOF { - break - } else if err != nil { - utils.Errorf("Error streaming logs: %s", err) - break - } - logLine := l.Log - if times { - logLine = fmt.Sprintf("[%s] %s", l.Created.Format(format), logLine) - } - if l.Stream == "stdout" && stdout { - fmt.Fprintf(job.Stdout, "%s", logLine) - } - if l.Stream == "stderr" && stderr { - fmt.Fprintf(job.Stderr, "%s", logLine) + if err := dec.Decode(l); err == io.EOF { + break + } else if err != nil { + utils.Errorf("Error streaming logs: %s", err) + break + } + logLine := l.Log + if times { + logLine = fmt.Sprintf("[%s] %s", l.Created.Format(format), logLine) + } + if l.Stream == "stdout" && stdout { + fmt.Fprintf(job.Stdout, "%s", logLine) + } + if l.Stream == "stderr" && stderr { + fmt.Fprintf(job.Stderr, "%s", logLine) + } } } } From 5c344dca4be275fc4e85c5e2dfd35133aff5cb23 Mon Sep 17 00:00:00 2001 From: Andrew Weiss Date: Mon, 30 Jun 2014 15:35:30 -0400 Subject: [PATCH 148/167] add DSC article Docker-DCO-1.1-Signed-off-by: Andrew Weiss (github: anweiss) --- docs/mkdocs.yml | 1 + docs/sources/articles/dsc.md | 117 +++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 docs/sources/articles/dsc.md diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 21b334197..97dc8fc36 100755 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -87,6 +87,7 @@ pages: - ['articles/cfengine_process_management.md', 'Articles', 'Process management with CFEngine'] - ['articles/puppet.md', 'Articles', 'Using Puppet'] - ['articles/chef.md', 'Articles', 'Using Chef'] +- ['articles/dsc.md', 'Articles', 'Using PowerShell DSC'] - ['articles/ambassador_pattern_linking.md', 'Articles', 'Cross-Host linking using Ambassador Containers'] - ['articles/runmetrics.md', 'Articles', 'Runtime metrics'] - ['articles/baseimages.md', 'Articles', 'Creating a Base Image'] diff --git a/docs/sources/articles/dsc.md b/docs/sources/articles/dsc.md new file mode 100644 index 000000000..94f5e9d4d --- /dev/null +++ b/docs/sources/articles/dsc.md @@ -0,0 +1,117 @@ +page_title: PowerShell DSC Usage +page_description: Using DSC to configure a new Docker host +page_keywords: powershell, dsc, installation, usage, docker, documentation + +# Using PowerShell DSC + +Windows PowerShell Desired State Configuration (DSC) is a configuration +management tool that extends the existing functionality of Windows PowerShell. +DSC uses a declarative syntax to define the state in which a target should be +configured. More information about PowerShell DSC can be found at +http://technet.microsoft.com/en-us/library/dn249912.aspx. + +## Requirements + +To use this guide you'll need a Windows host with PowerShell v4.0 or newer. + +The included DSC configuration script also uses the official PPA so +only an Ubuntu target is supported. The Ubuntu target must already have the +required OMI Server and PowerShell DSC for Linux providers installed. More +information can be found at https://github.com/MSFTOSSMgmt/WPSDSCLinux. The +source repository listed below also includes PowerShell DSC for Linux +installation and init scripts along with more detailed installation information. + +## Installation + +The DSC configuration example source is available in the following repository: +https://github.com/anweiss/DockerClientDSC. It can be cloned with: + + $ git clone https://github.com/anweiss/DockerClientDSC.git + +## Usage + +The DSC configuration utilizes a set of shell scripts to determine whether or +not the specified Docker components are configured on the target node(s). The +source repository also includes a script (`RunDockerClientConfig.ps1`) that can +be used to establish the required CIM session(s) and execute the +`Set-DscConfiguration` cmdlet. + +More detailed usage information can be found at +https://github.com/anweiss/DockerClientDSC. + +### Run Configuration +The Docker installation configuration is equivalent to running: + +``` +apt-get install docker.io +ln -sf /usr/bin/docker.io /usr/local/bin/docker +sed -i '$acomplete -F _docker docker' /etc/bash_completion.d/docker.io +``` + +Ensure that your current working directory is set to the `DockerClientDSC` +source and load the DockerClient configuration into the current PowerShell +session + +```powershell +. .\DockerClient.ps1 +``` + +Generate the required DSC configuration .mof file for the targeted node + +```powershell +DockerClient -Hostname "myhost" +``` + +A sample DSC configuration data file has also been included and can be modified +and used in conjunction with or in place of the `Hostname` parameter: + +```powershell +DockerClient -ConfigurationData .\DockerConfigData.psd1 +``` + +Start the configuration application process on the targeted node + +```powershell +.\RunDockerClientConfig.ps1 -Hostname "myhost" +``` + +The `RunDockerClientConfig.ps1` script can also parse a DSC configuration data +file and execute configurations against multiple nodes as such: + +```powershell +.\RunDockerClientConfig.ps1 -ConfigurationData .\DockerConfigData.psd1 +``` + +### Images +Image configuration is equivalent to running: `docker pull [image]`. + +Using the same Run Configuration steps defined above, execute `DockerClient` +with the `Image` parameter: + +```powershell +DockerClient -Hostname "myhost" -Image node +``` + +The configuration process can be initiated as before: + +```powershell +.\RunDockerClientConfig.ps1 -Hostname "myhost" +``` + +### Containers +Container configuration is equivalent to running: +`docker run -d --name="[containername]" [image] '[command]'`. + +Using the same Run Configuration steps defined above, execute `DockerClient` +with the `Image`, `ContainerName`, and `Command` parameters: + +```powershell +DockerClient -Hostname "myhost" -Image node -ContainerName "helloworld" ` +-Command 'echo "Hello World!"' +``` + +The configuration process can be initiated as before: + +```powershell +.\RunDockerClientConfig.ps1 -Hostname "myhost" +``` From e06d533cc20c6aab10bf28a610445e7de6a8ef42 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 1 Jul 2014 21:33:33 +0000 Subject: [PATCH 149/167] update docs Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/client/commands.go | 2 +- docs/sources/reference/commandline/cli.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 7cdcd5ebe..2d9c74f43 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1693,7 +1693,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error { cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container") follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output") times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps") - tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs(all logs by default)") + tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)") ) if err := cmd.Parse(args); err != nil { diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 912feddfa..b79f2ac7c 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -738,15 +738,15 @@ specify this by adding the server name. -f, --follow=false Follow log output -t, --timestamps=false Show timestamps - --tail="all" Output the specified number of lines at the end of logs (all logs by default) + --tail="all" Output the specified number of lines at the end of logs (defaults to all logs) The `docker logs` command batch-retrieves logs present at the time of execution. The `docker logs --follow` command will continue streaming the new output from the container's `STDOUT` and `STDERR`. -Passing a negative number or a non-integer to --tail is invalid and the -value is set to all in that case. This behavior may change in the future. +Passing a negative number or a non-integer to `--tail` is invalid and the +value is set to `all` in that case. This behavior may change in the future. ## port From fc4c0d9de45da5ff5664fb9c914b68e176c626cd Mon Sep 17 00:00:00 2001 From: Tom Maaswinkel Date: Mon, 30 Jun 2014 10:16:49 +0200 Subject: [PATCH 150/167] Update usingdocker.md boot2docker on windows also uses an IP of its own. Docker-DCO-1.1-Signed-off-by: Tom Maaswinkel (github: SvenDowideit) --- docs/sources/userguide/usingdocker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index c1f524f89..f08b41d7d 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -179,7 +179,7 @@ see the application. Our Python application is live! > **Note:** -> If you have used boot2docker on OSX you'll need to get the IP of the virtual +> If you have used boot2docker on OSX, or Windows, you'll need to get the IP of the virtual > host instead of using localhost. You can do this by running the following in > the boot2docker shell. > From 84990731f79e4e94229a7ff2039f812e8b036643 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Tue, 1 Jul 2014 12:02:39 +1000 Subject: [PATCH 151/167] expand to 'used b2d vm on any of the platforms' Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/sources/userguide/usingdocker.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index f08b41d7d..16fdecc27 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -179,8 +179,9 @@ see the application. Our Python application is live! > **Note:** -> If you have used boot2docker on OSX, or Windows, you'll need to get the IP of the virtual -> host instead of using localhost. You can do this by running the following in +> If you have used the boot2docker virtual machine on OSX, Windows or Linux, +> you'll need to get the IP of the virtual host instead of using localhost. +> You can do this by running the following in > the boot2docker shell. > > $ boot2docker ip From 91c4fbb7bfe8851130f746911e34b9d190bb4572 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Tue, 1 Jul 2014 14:59:28 -0700 Subject: [PATCH 152/167] convert OSX into OS X Docker-DCO-1.1-Signed-off-by: Sven Dowideit (github: SvenDowideit) --- docs/sources/installation/binaries.md | 2 +- docs/sources/installation/mac.md | 4 ++-- docs/sources/userguide/usingdocker.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/installation/binaries.md b/docs/sources/installation/binaries.md index 97e2f93c4..f6eb44fa6 100644 --- a/docs/sources/installation/binaries.md +++ b/docs/sources/installation/binaries.md @@ -36,7 +36,7 @@ In general, a 3.8 Linux kernel (or higher) is preferred, as some of the prior versions have known issues that are triggered by Docker. Note that Docker also has a client mode, which can run on virtually any -Linux kernel (it even builds on OSX!). +Linux kernel (it even builds on OS X!). ## Get the docker binary: diff --git a/docs/sources/installation/mac.md b/docs/sources/installation/mac.md index b6253de12..2aff0e5b8 100644 --- a/docs/sources/installation/mac.md +++ b/docs/sources/installation/mac.md @@ -21,7 +21,7 @@ virtual machine and runs the Docker daemon. ## Installation -1. Download the latest release of the [Docker for OSX Installer]( +1. Download the latest release of the [Docker for OS X Installer]( https://github.com/boot2docker/osx-installer/releases) 2. Run the installer, which will install VirtualBox and the Boot2Docker management @@ -42,7 +42,7 @@ and `boot2docker start`. ## Upgrading -1. Download the latest release of the [Docker for OSX Installer]( +1. Download the latest release of the [Docker for OS X Installer]( https://github.com/boot2docker/osx-installer/releases) 2. Run the installer, which will update VirtualBox and the Boot2Docker management diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index 16fdecc27..7080e3ed4 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -179,7 +179,7 @@ see the application. Our Python application is live! > **Note:** -> If you have used the boot2docker virtual machine on OSX, Windows or Linux, +> If you have used the boot2docker virtual machine on OS X, Windows or Linux, > you'll need to get the IP of the virtual host instead of using localhost. > You can do this by running the following in > the boot2docker shell. From 3091d9a31e81be9b8a99aaae8f7d5c2e64043286 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Tue, 1 Jul 2014 11:56:35 +1000 Subject: [PATCH 153/167] removing the exclaimation mark from our hello-world examples, some users get trapped by the shell Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/sources/userguide/dockerhub.md | 2 +- docs/sources/userguide/dockerizing.md | 20 ++++++++++---------- docs/sources/userguide/index.md | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/sources/userguide/dockerhub.md b/docs/sources/userguide/dockerhub.md index 99e9a0a92..a46136843 100644 --- a/docs/sources/userguide/dockerhub.md +++ b/docs/sources/userguide/dockerhub.md @@ -65,7 +65,7 @@ Your Docker Hub account is now active and ready for you to use! ## Next steps -Next, let's start learning how to Dockerize applications with our "Hello World!" +Next, let's start learning how to Dockerize applications with our "Hello World" exercise. Go to [Dockerizing Applications](/userguide/dockerizing). diff --git a/docs/sources/userguide/dockerizing.md b/docs/sources/userguide/dockerizing.md index ed927df08..f9de877a7 100644 --- a/docs/sources/userguide/dockerizing.md +++ b/docs/sources/userguide/dockerizing.md @@ -1,20 +1,20 @@ -page_title: Dockerizing Applications: A "Hello World!" -page_description: A simple "Hello World!" exercise that introduced you to Docker. +page_title: Dockerizing Applications: A "Hello World" +page_description: A simple "Hello World" exercise that introduced you to Docker. page_keywords: docker guide, docker, docker platform, virtualization framework, how to, dockerize, dockerizing apps, dockerizing applications, container, containers -# Dockerizing Applications: A "Hello World!" +# Dockerizing Applications: A "Hello World" *So what's this Docker thing all about?* Docker allows you to run applications inside containers. Running an application inside a container takes a single command: `docker run`. -## Hello World! +## Hello World Let's try it now. $ sudo docker run ubuntu:14.04 /bin/echo 'Hello World' - Hello World! + Hello World And you just launched your first container! @@ -34,17 +34,17 @@ image registry: [Docker Hub](https://hub.docker.com). Next we told Docker what command to run inside our new container: - /bin/echo 'Hello World!' + /bin/echo 'Hello World' When our container was launched Docker created a new Ubuntu 14.04 environment and then executed the `/bin/echo` command inside it. We saw the result on the command line: - Hello World! + Hello World So what happened to our container after that? Well Docker containers only run as long as the command you specify is active. Here, as soon as -`Hello World!` was echoed, the container stopped. +`Hello World` was echoed, the container stopped. ## An Interactive Container @@ -88,7 +88,7 @@ use the `exit` command to finish. As with our previous container, once the Bash shell process has finished, the container is stopped. -## A Daemonized Hello World! +## A Daemonized Hello World Now a container that runs a command and then exits has some uses but it's not overly helpful. Let's create a container that runs as a daemon, @@ -99,7 +99,7 @@ Again we can do this with the `docker run` command: $ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147 -Wait what? Where's our "Hello World!" Let's look at what we've run here. +Wait what? Where's our "Hello World" Let's look at what we've run here. It should look pretty familiar. We ran `docker run` but this time we specified a flag: `-d`. The `-d` flag tells Docker to run the container and put it in the background, to daemonize it. diff --git a/docs/sources/userguide/index.md b/docs/sources/userguide/index.md index 87dab67cc..d8f8294c0 100644 --- a/docs/sources/userguide/index.md +++ b/docs/sources/userguide/index.md @@ -29,7 +29,7 @@ environment. To learn more; Go to [Using Docker Hub](/userguide/dockerhub). -## Dockerizing Applications: A "Hello World!" +## Dockerizing Applications: A "Hello World" *How do I run applications inside containers?* From a09f99b8b0e157e3bb72ad0c9dad8d83896c5182 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Tue, 1 Jul 2014 15:07:05 -0700 Subject: [PATCH 154/167] Lowercase world, because its not important. Docker-DCO-1.1-Signed-off-by: Sven Dowideit (github: SvenDowideit) --- docs/sources/examples/nodejs_web_app.md | 6 +++--- docs/sources/reference/commandline/cli.md | 6 +++--- docs/sources/userguide/dockerhub.md | 2 +- docs/sources/userguide/dockerizing.md | 22 +++++++++++----------- docs/sources/userguide/index.md | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/sources/examples/nodejs_web_app.md b/docs/sources/examples/nodejs_web_app.md index 5fb0300f5..a7b8eea7e 100644 --- a/docs/sources/examples/nodejs_web_app.md +++ b/docs/sources/examples/nodejs_web_app.md @@ -24,7 +24,7 @@ describes your app and its dependencies: "name": "docker-centos-hello", "private": true, "version": "0.0.1", - "description": "Node.js Hello World app on CentOS using docker", + "description": "Node.js Hello world app on CentOS using docker", "author": "Daniel Gasienica ", "dependencies": { "express": "3.2.4" @@ -42,7 +42,7 @@ app using the [Express.js](http://expressjs.com/) framework: // App var app = express(); app.get('/', function (req, res) { - res.send('Hello World\n'); + res.send('Hello world\n'); }); app.listen(PORT); @@ -184,7 +184,7 @@ Now you can call your app using `curl` (install if needed via: Date: Sun, 02 Jun 2013 03:53:22 GMT Connection: keep-alive - Hello World + Hello world We hope this tutorial helped you get up and running with Node.js and CentOS on Docker. You can get the full source code at diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 93b97b02f..bbcd00ed8 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -246,7 +246,7 @@ See also: drwxr-xr-x 2 root root 4.0K Mar 12 2013 tmp drwxr-xr-x 2 root root 4.0K Nov 15 23:34 usr ---> b35f4035db3f - Step 3 : CMD echo Hello World + Step 3 : CMD echo Hello world ---> Running in 02071fceb21b ---> f52f38b7823e Successfully built f52f38b7823e @@ -277,7 +277,7 @@ affect the build cache. Uploading context Step 0 : FROM busybox ---> 769b9341d937 - Step 1 : CMD echo Hello World + Step 1 : CMD echo Hello world ---> Using cache ---> 99cc1ad10469 Successfully built 99cc1ad10469 @@ -287,7 +287,7 @@ affect the build cache. Uploading context Step 0 : FROM busybox ---> 769b9341d937 - Step 1 : CMD echo Hello World + Step 1 : CMD echo Hello world ---> Using cache ---> 99cc1ad10469 Successfully built 99cc1ad10469 diff --git a/docs/sources/userguide/dockerhub.md b/docs/sources/userguide/dockerhub.md index a46136843..5bb1edec8 100644 --- a/docs/sources/userguide/dockerhub.md +++ b/docs/sources/userguide/dockerhub.md @@ -65,7 +65,7 @@ Your Docker Hub account is now active and ready for you to use! ## Next steps -Next, let's start learning how to Dockerize applications with our "Hello World" +Next, let's start learning how to Dockerize applications with our "Hello world" exercise. Go to [Dockerizing Applications](/userguide/dockerizing). diff --git a/docs/sources/userguide/dockerizing.md b/docs/sources/userguide/dockerizing.md index f9de877a7..02ac90306 100644 --- a/docs/sources/userguide/dockerizing.md +++ b/docs/sources/userguide/dockerizing.md @@ -1,20 +1,20 @@ -page_title: Dockerizing Applications: A "Hello World" -page_description: A simple "Hello World" exercise that introduced you to Docker. +page_title: Dockerizing Applications: A "Hello world" +page_description: A simple "Hello world" exercise that introduced you to Docker. page_keywords: docker guide, docker, docker platform, virtualization framework, how to, dockerize, dockerizing apps, dockerizing applications, container, containers -# Dockerizing Applications: A "Hello World" +# Dockerizing Applications: A "Hello world" *So what's this Docker thing all about?* Docker allows you to run applications inside containers. Running an application inside a container takes a single command: `docker run`. -## Hello World +## Hello world Let's try it now. - $ sudo docker run ubuntu:14.04 /bin/echo 'Hello World' - Hello World + $ sudo docker run ubuntu:14.04 /bin/echo 'Hello world' + Hello world And you just launched your first container! @@ -34,17 +34,17 @@ image registry: [Docker Hub](https://hub.docker.com). Next we told Docker what command to run inside our new container: - /bin/echo 'Hello World' + /bin/echo 'Hello world' When our container was launched Docker created a new Ubuntu 14.04 environment and then executed the `/bin/echo` command inside it. We saw the result on the command line: - Hello World + Hello world So what happened to our container after that? Well Docker containers only run as long as the command you specify is active. Here, as soon as -`Hello World` was echoed, the container stopped. +`Hello world` was echoed, the container stopped. ## An Interactive Container @@ -88,7 +88,7 @@ use the `exit` command to finish. As with our previous container, once the Bash shell process has finished, the container is stopped. -## A Daemonized Hello World +## A Daemonized Hello world Now a container that runs a command and then exits has some uses but it's not overly helpful. Let's create a container that runs as a daemon, @@ -99,7 +99,7 @@ Again we can do this with the `docker run` command: $ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147 -Wait what? Where's our "Hello World" Let's look at what we've run here. +Wait what? Where's our "Hello world" Let's look at what we've run here. It should look pretty familiar. We ran `docker run` but this time we specified a flag: `-d`. The `-d` flag tells Docker to run the container and put it in the background, to daemonize it. diff --git a/docs/sources/userguide/index.md b/docs/sources/userguide/index.md index d8f8294c0..e5c9ec272 100644 --- a/docs/sources/userguide/index.md +++ b/docs/sources/userguide/index.md @@ -29,7 +29,7 @@ environment. To learn more; Go to [Using Docker Hub](/userguide/dockerhub). -## Dockerizing Applications: A "Hello World" +## Dockerizing Applications: A "Hello world" *How do I run applications inside containers?* From cccb64e8633eee309e6ce33c3bb41614edd70d81 Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Tue, 1 Jul 2014 19:14:22 -0400 Subject: [PATCH 155/167] Add backwards READ compatibility for the old libcontainer API Docker-DCO-1.1-Signed-off-by: Tibor Vass (github: tiborvass) --- daemon/execdriver/native/driver.go | 19 ++++++++++++++----- daemon/execdriver/native/info.go | 6 ++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 1f27ef77b..b789cc072 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -173,12 +173,21 @@ func (d *driver) Terminate(p *execdriver.Command) error { // lets check the start time for the process state, err := libcontainer.GetState(filepath.Join(d.root, p.ID)) if err != nil { - // if we don't have the data on disk then we can assume the process is gone - // because this is only removed after we know the process has stopped - if os.IsNotExist(err) { - return nil + if !os.IsNotExist(err) { + return err } - return err + // TODO: Remove this part for version 1.2.0 + // This is added only to ensure smooth upgrades from pre 1.1.0 to 1.1.0 + data, err := ioutil.ReadAll(filepath.Join(d.root, p.ID, "start")) + if err != nil { + // if we don't have the data on disk then we can assume the process is gone + // because this is only removed after we know the process has stopped + if os.IsNotExist(err) { + return nil + } + return err + } + state.InitStartTime = string(data) } currentStartTime, err := system.GetProcessStartTime(p.Process.Pid) diff --git a/daemon/execdriver/native/info.go b/daemon/execdriver/native/info.go index 693a455a4..c34d0297b 100644 --- a/daemon/execdriver/native/info.go +++ b/daemon/execdriver/native/info.go @@ -1,6 +1,7 @@ package native import ( + "os" "path/filepath" "github.com/docker/libcontainer" @@ -18,5 +19,10 @@ func (i *info) IsRunning() bool { if _, err := libcontainer.GetState(filepath.Join(i.driver.root, i.ID)); err == nil { return true } + // TODO: Remove this part for version 1.2.0 + // This is added only to ensure smooth upgrades from pre 1.1.0 to 1.1.0 + if _, err := os.Stat(filepath.Join(i.driver.root, i.ID, "pid")); err == nil { + return true + } return false } From d403936818b8785b65ff55ebab0d266b4a871ef6 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 2 Jul 2014 00:54:08 +0000 Subject: [PATCH 156/167] fix compilation and panic Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- daemon/execdriver/native/driver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index b789cc072..90333703c 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -178,7 +178,7 @@ func (d *driver) Terminate(p *execdriver.Command) error { } // TODO: Remove this part for version 1.2.0 // This is added only to ensure smooth upgrades from pre 1.1.0 to 1.1.0 - data, err := ioutil.ReadAll(filepath.Join(d.root, p.ID, "start")) + data, err := ioutil.ReadFile(filepath.Join(d.root, p.ID, "start")) if err != nil { // if we don't have the data on disk then we can assume the process is gone // because this is only removed after we know the process has stopped @@ -187,7 +187,7 @@ func (d *driver) Terminate(p *execdriver.Command) error { } return err } - state.InitStartTime = string(data) + state = &libcontainer.State{InitStartTime: string(data)} } currentStartTime, err := system.GetProcessStartTime(p.Process.Pid) From 7abe70c0b1018729006fd5d614ada2dc67edb9b2 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Wed, 2 Jul 2014 09:36:57 -0600 Subject: [PATCH 157/167] Add NOFILE and NPROC ulimit settings to the OpenRC init script Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/init/openrc/docker.initd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/init/openrc/docker.initd b/contrib/init/openrc/docker.initd index 2d79a7397..a9d21b170 100755 --- a/contrib/init/openrc/docker.initd +++ b/contrib/init/openrc/docker.initd @@ -11,6 +11,9 @@ DOCKER_OPTS=${DOCKER_OPTS:-} start() { checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE" + ulimit -n 1048576 + ulimit -u 1048576 + ebegin "Starting docker daemon" start-stop-daemon --start --background \ --exec "$DOCKER_BINARY" \ From bae79c3e7285c170f97a0f7f331a48fb47f0f40e Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Wed, 2 Jul 2014 09:38:19 -0600 Subject: [PATCH 158/167] Add NOFILE and NPROC ulimit settings to the SysV init script Docker-DCO-1.1-Signed-off-by: Andrew Page (github: tianon) --- contrib/init/sysvinit-debian/docker | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/init/sysvinit-debian/docker b/contrib/init/sysvinit-debian/docker index a3b935375..6250cae05 100755 --- a/contrib/init/sysvinit-debian/docker +++ b/contrib/init/sysvinit-debian/docker @@ -88,6 +88,9 @@ case "$1" in touch "$DOCKER_LOGFILE" chgrp docker "$DOCKER_LOGFILE" + ulimit -n 1048576 + ulimit -u 1048576 + log_begin_msg "Starting $DOCKER_DESC: $BASE" start-stop-daemon --start --background \ --no-close \ From dad476803719ae2e86c703981caef0462e25260c Mon Sep 17 00:00:00 2001 From: unclejack Date: Mon, 30 Jun 2014 22:42:09 +0300 Subject: [PATCH 159/167] integcli: add & use pullImageIfNotExist for pulls This speeds up the tag cli integration tests by about 20 seconds. Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- integration-cli/docker_cli_tag_test.go | 22 +++++++--------------- integration-cli/docker_utils.go | 12 ++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/integration-cli/docker_cli_tag_test.go b/integration-cli/docker_cli_tag_test.go index ef51f6464..032927e22 100644 --- a/integration-cli/docker_cli_tag_test.go +++ b/integration-cli/docker_cli_tag_test.go @@ -8,16 +8,12 @@ import ( // tagging a named image in a new unprefixed repo should work func TestTagUnprefixedRepoByName(t *testing.T) { - pullCmd := exec.Command(dockerBinary, "pull", "busybox") - out, exitCode, err := runCommandWithOutput(pullCmd) - errorOut(err, t, fmt.Sprintf("%s %s", out, err)) - - if err != nil || exitCode != 0 { - t.Fatal("pulling the busybox image from the registry has failed") + if err := pullImageIfNotExist("busybox:latest"); err != nil { + t.Fatal("couldn't find the busybox:latest image locally and failed to pull it") } - tagCmd := exec.Command(dockerBinary, "tag", "busybox", "testfoobarbaz") - out, _, err = runCommandWithOutput(tagCmd) + tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", "testfoobarbaz") + out, _, err := runCommandWithOutput(tagCmd) errorOut(err, t, fmt.Sprintf("%v %v", out, err)) deleteImages("testfoobarbaz") @@ -62,18 +58,14 @@ func TestTagInvalidUnprefixedRepo(t *testing.T) { // ensure we allow the use of valid tags func TestTagValidPrefixedRepo(t *testing.T) { - pullCmd := exec.Command(dockerBinary, "pull", "busybox") - out, exitCode, err := runCommandWithOutput(pullCmd) - errorOut(err, t, fmt.Sprintf("%s %s", out, err)) - - if err != nil || exitCode != 0 { - t.Fatal("pulling the busybox image from the registry has failed") + if err := pullImageIfNotExist("busybox:latest"); err != nil { + t.Fatal("couldn't find the busybox:latest image locally and failed to pull it") } validRepos := []string{"fooo/bar", "fooaa/test"} for _, repo := range validRepos { - tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo) + tagCmd := exec.Command(dockerBinary, "tag", "busybox:latest", repo) _, _, err := runCommandWithOutput(tagCmd) if err != nil { t.Errorf("tag busybox %v should have worked: %s", repo, err) diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index 22217e2f0..74576ba48 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -75,6 +75,18 @@ func imageExists(image string) error { return err } +func pullImageIfNotExist(image string) (err error) { + if err := imageExists(image); err != nil { + pullCmd := exec.Command(dockerBinary, "pull", image) + _, exitCode, err := runCommandWithOutput(pullCmd) + + if err != nil || exitCode != 0 { + err = fmt.Errorf("image '%s' wasn't found locally and it couldn't be pulled: %s", image, err) + } + } + return +} + func cmd(t *testing.T, args ...string) (string, int, error) { out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out)) From 170ba7f8feea9b284d20ed85e9ea9c947be2941c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 2 Jul 2014 18:53:35 +0000 Subject: [PATCH 160/167] update release checklist and .gitignore Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- .gitignore | 1 + hack/RELEASE-CHECKLIST.md | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4f8f09c77..2a86e41ca 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ Vagrantfile docs/AWS_S3_BUCKET docs/GIT_BRANCH docs/VERSION +docs/GITCOMMIT diff --git a/hack/RELEASE-CHECKLIST.md b/hack/RELEASE-CHECKLIST.md index 6d7ed1529..2fe1a3ce9 100644 --- a/hack/RELEASE-CHECKLIST.md +++ b/hack/RELEASE-CHECKLIST.md @@ -138,11 +138,10 @@ make AWS_S3_BUCKET=beta-docs.docker.io docs-release ### 5. Commit and create a pull request to the "release" branch ```bash -export GITHUBUSER="YOUR_GITHUB_USER" git add VERSION CHANGELOG.md git commit -m "Bump version to $VERSION" git push $GITHUBUSER bump_$VERSION -echo "https://github.com/$GITHUBUSER/docker/compare/dotcloud:master...$GITHUBUSER:bump_$VERSION?expand=1" +echo "https://github.com/$GITHUBUSER/docker/compare/dotcloud:release...$GITHUBUSER:bump_$VERSION?expand=1" ``` That last command will give you the proper link to visit to ensure that you From d946cae36436a270b14d53585624e5567e590db2 Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Wed, 2 Jul 2014 16:33:13 -0700 Subject: [PATCH 161/167] Added Release Notes Release notes for v.1.1 have been added to the docs index.md page. Made some revisions to other content to make it shorter. Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- docs/sources/index.md | 90 +++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 57b971223..3ff9c8dde 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -22,8 +22,9 @@ Docker consists of: ## Why Docker? -- **Faster delivery of your applications** - * We want your environment to work better. Docker containers, +*Faster delivery of your applications* + +* We want your environment to work better. Docker containers, and the work flow that comes with them, help your developers, sysadmins, QA folks, and release engineers work together to get your code into production and make it useful. We've created a standard @@ -31,40 +32,42 @@ Docker consists of: inside containers while sysadmins and operators can work on running the container in your deployment. This separation of duties streamlines and simplifies the management and deployment of code. - * We make it easy to build new containers, enable rapid iteration of +* We make it easy to build new containers, enable rapid iteration of your applications, and increase the visibility of changes. This helps everyone in your organization understand how an application works and how it is built. - * Docker containers are lightweight and fast! Containers have +* Docker containers are lightweight and fast! Containers have sub-second launch times, reducing the cycle time of development, testing, and deployment. -- **Deploy and scale more easily** - * Docker containers run (almost) everywhere. You can deploy +*Deploy and scale more easily* + +* Docker containers run (almost) everywhere. You can deploy containers on desktops, physical servers, virtual machines, into data centers, and up to public and private clouds. - * Since Docker runs on so many platforms, it's easy to move your +* Since Docker runs on so many platforms, it's easy to move your applications around. You can easily move an application from a testing environment into the cloud and back whenever you need. - * Docker's lightweight containers also make scaling up and +* Docker's lightweight containers also make scaling up and down fast and easy. You can quickly launch more containers when needed and then shut them down easily when they're no longer needed. -- **Get higher density and run more workloads** - * Docker containers don't need a hypervisor, so you can pack more of +*Get higher density and run more workloads* + +* Docker containers don't need a hypervisor, so you can pack more of them onto your hosts. This means you get more value out of every server and can potentially reduce what you spend on equipment and licenses. -- **Faster deployment makes for easier management** - * As Docker speeds up your work flow, it gets easier to make lots +*Faster deployment makes for easier management* + +* As Docker speeds up your work flow, it gets easier to make lots of small changes instead of huge, big bang updates. Smaller changes mean reduced risk and more uptime. ## About this guide -First, the [Understanding Docker -section](introduction/understanding-docker.md) will help you: +The [Understanding Docker section](introduction/understanding-docker.md) will help you: - See how Docker works at a high level - Understand the architecture of Docker @@ -72,22 +75,59 @@ section](introduction/understanding-docker.md) will help you: - See how Docker compares to virtual machines - See some common use cases. -> [Click here to go to the Understanding -> Docker section](introduction/understanding-docker.md). - ### Installation Guides -Next, we'll show you how to install Docker on a variety of platforms in the -[installation](/installation/#installation) section. +The [installation section](/installation/#installation) will show you how to install +Docker on a variety of platforms. -> [Click here to go to the Installation -> section](/installation/#installation). ### Docker User Guide -Once you've gotten Docker installed we recommend you work through the -[Docker User Guide](/userguide/), to learn about Docker in more detail and -answer questions about usage and implementation. +To learn about Docker in more detail and to answer questions about usage and implementation, check out the [Docker User Guide](/userguide/). + +## Release Notes + +Version 1.1 + +### New Features + +*`.dockerignore` support* + +You can now add a `.dockerignore` file next to your `Dockerfile` and Docker will ignore files and directories specified in that file when sending the build context to the daemon. +Example: https://github.com/dotcloud/docker/blob/master/.dockerignore + +*Pause containers during commit* + +Doing a commit on a running container was not recommended because you could end up with files in an inconsistent state (for example, if they were being written during the commit). Containers are now paused when a commit is made to them. +You can disable this feature by doing a `docker commit --pause=false ` + +*Tailing logs* + +You can now tail the logs of a container. For example, you can get the last ten lines of a log by using `docker logs --tail 10 `. You can also follow the logs of a container without having to read the whole log file with `docker logs --tail 0 -f `. + +*Allow a tar file as context for docker build* + +You can now pass a tar archive to `docker build` as context. This can be used to automate docker builds, for example: `cat context.tar | docker build -` or `docker run builder_image | docker build -` + +*Bind mounting your whole filesystem in a container* + +`/` is now allowed as source of `--volumes`. This means you can bind-mount your whole system in a container if you need to. For example: `docker run -v /:/my_host ubuntu:ro ls /my_host`. However, it is now forbidden to mount to /. + + +### Other Improvements & Changes + +* Port allocation has been improved. In the previous release, Docker could prevent you from starting a container with previously allocated ports which seemed to be in use when in fact they were not. This has been fixed. + +* A bug in `docker save` was introduced in the last release. The `docker save` command could produce images with invalid metadata. The command now produces images with correct metadata. + +* Running `docker inspect` in a container now returns which containers it is linked to. + +* Parsing of the `docker commit` flag has improved validation, to better prevent you from committing an image with a name such as `-m`. Image names with dashes in them potentially conflict with command line flags. + +* The API now has Improved status codes for `start` and `stop`. Trying to start a running container will now return a 304 error. + +* Performance has been improved overall. Starting the daemon is faster than in previous releases. The daemon’s performance has also been improved when it is working with large numbers of images and containers. + +* Fixed an issue with white-spaces and multi-lines in Dockerfiles. -> [Click here to go to the Docker User Guide](/userguide/). From b59754bcb32fe5b8f416f407f71d2b50bb148c8a Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Sat, 28 Jun 2014 12:31:29 -0400 Subject: [PATCH 162/167] Fixed numerous inconsistencies in command help text * Replaced docker with Docker. * Consistently used STDIN, STDOUT, STDERR. * Consistently used TTY. * Fixed some grammar and spelling issues. * Fixed references to the index. Docker-DCO-1.1-Signed-off-by: James Turnbull (github: jamtur01) Docker-DCO-1.1-Signed-off-by: James Turnbull (github: SvenDowideit) --- api/client/commands.go | 58 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 2d9c74f43..6163f91c1 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -67,25 +67,25 @@ func (cli *DockerCli) CmdHelp(args ...string) error { {"inspect", "Return low-level information on a container"}, {"kill", "Kill a running container"}, {"load", "Load an image from a tar archive"}, - {"login", "Register or Login to the docker registry server"}, + {"login", "Register or log in to the Docker registry server"}, {"logs", "Fetch the logs of a container"}, - {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, + {"port", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT"}, {"pause", "Pause all processes within a container"}, {"ps", "List containers"}, - {"pull", "Pull an image or a repository from the docker registry server"}, - {"push", "Push an image or a repository to the docker registry server"}, + {"pull", "Pull an image or a repository from a Docker registry server"}, + {"push", "Push an image or a repository to a Docker registry server"}, {"restart", "Restart a running container"}, {"rm", "Remove one or more containers"}, {"rmi", "Remove one or more images"}, {"run", "Run a command in a new container"}, {"save", "Save an image to a tar archive"}, - {"search", "Search for an image in the docker index"}, + {"search", "Search for an image on the Docker Hub"}, {"start", "Start a stopped container"}, {"stop", "Stop a running container"}, {"tag", "Tag an image into a repository"}, {"top", "Lookup the running processes of a container"}, {"unpause", "Unpause a paused container"}, - {"version", "Show the docker version information"}, + {"version", "Show the Docker version information"}, {"wait", "Block until a container stops, then print its exit code"}, } { help += fmt.Sprintf(" %-10.10s%s\n", command[0], command[1]) @@ -123,12 +123,12 @@ func (cli *DockerCli) CmdBuild(args ...string) error { buf := bufio.NewReader(cli.in) magic, err := buf.Peek(tarHeaderSize) if err != nil && err != io.EOF { - return fmt.Errorf("failed to peek context header from stdin: %v", err) + return fmt.Errorf("failed to peek context header from STDIN: %v", err) } if !archive.IsArchive(magic) { dockerfile, err := ioutil.ReadAll(buf) if err != nil { - return fmt.Errorf("failed to read Dockerfile from stdin: %v", err) + return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err) } context, err = archive.Generate("Dockerfile", string(dockerfile)) } else { @@ -248,7 +248,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { // 'docker login': login / register a user to registry service. func (cli *DockerCli) CmdLogin(args ...string) error { - cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or Login to a docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.") + cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.") var username, password, email string @@ -374,7 +374,7 @@ func (cli *DockerCli) CmdWait(args ...string) error { // 'docker version': show version information func (cli *DockerCli) CmdVersion(args ...string) error { - cmd := cli.Subcmd("version", "", "Show the docker version information.") + cmd := cli.Subcmd("version", "", "Show the Docker version information.") if err := cmd.Parse(args); err != nil { return nil } @@ -497,8 +497,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error { } func (cli *DockerCli) CmdStop(args ...string) error { - cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container (Send SIGTERM, and then SIGKILL after grace period)") - nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it.") + cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period") + nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.") if err := cmd.Parse(args); err != nil { return nil } @@ -525,7 +525,7 @@ func (cli *DockerCli) CmdStop(args ...string) error { func (cli *DockerCli) CmdRestart(args ...string) error { cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container") - nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10") + nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.") if err := cmd.Parse(args); err != nil { return nil } @@ -582,8 +582,8 @@ func (cli *DockerCli) CmdStart(args ...string) error { tty bool cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container") - attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's stdout/stderr and forward all signals to the process") - openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's stdin") + attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process") + openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN") ) if err := cmd.Parse(args); err != nil { @@ -714,7 +714,7 @@ func (cli *DockerCli) CmdPause(args ...string) error { } func (cli *DockerCli) CmdInspect(args ...string) error { - cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image") + cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image") tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.") if err := cmd.Parse(args); err != nil { return nil @@ -794,7 +794,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error { } func (cli *DockerCli) CmdTop(args ...string) error { - cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Lookup the running processes of a container") + cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container") if err := cmd.Parse(args); err != nil { return nil } @@ -829,7 +829,7 @@ func (cli *DockerCli) CmdTop(args ...string) error { } func (cli *DockerCli) CmdPort(args ...string) error { - cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT") + cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT") if err := cmd.Parse(args); err != nil { return nil } @@ -877,7 +877,7 @@ func (cli *DockerCli) CmdPort(args ...string) error { func (cli *DockerCli) CmdRmi(args ...string) error { var ( cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images") - force = cmd.Bool([]string{"f", "-force"}, false, "Force") + force = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image") noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents") ) if err := cmd.Parse(args); err != nil { @@ -980,7 +980,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error { func (cli *DockerCli) CmdRm(args ...string) error { cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers") - v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container") + v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container") link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container") force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container") @@ -1017,7 +1017,7 @@ func (cli *DockerCli) CmdRm(args ...string) error { // 'docker kill NAME' kills a running container func (cli *DockerCli) CmdKill(args ...string) error { - cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container (send SIGKILL, or specified signal)") + cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal") signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container") if err := cmd.Parse(args); err != nil { @@ -1149,7 +1149,7 @@ func (cli *DockerCli) CmdPush(args ...string) error { func (cli *DockerCli) CmdPull(args ...string) error { cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry") - tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in repository") + tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in a repository") if err := cmd.Parse(args); err != nil { return nil } @@ -1542,7 +1542,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error { flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith \")") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. - flConfig := cmd.String([]string{"#run", "#-run"}, "", "this option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") + flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") if err := cmd.Parse(args); err != nil { return nil } @@ -1735,8 +1735,8 @@ func (cli *DockerCli) CmdLogs(args ...string) error { func (cli *DockerCli) CmdAttach(args ...string) error { var ( cmd = cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container") - noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach stdin") - proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify received signals to the process (even in non-tty mode). SIGCHLD is not proxied") + noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN") + proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signals to the process (even in non-TTY mode). SIGCHLD is not proxied.") ) if err := cmd.Parse(args); err != nil { @@ -1807,11 +1807,11 @@ func (cli *DockerCli) CmdAttach(args ...string) error { } func (cli *DockerCli) CmdSearch(args ...string) error { - cmd := cli.Subcmd("search", "TERM", "Search the docker index for images") + cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds") automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds") - stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least xxx stars") + stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars") if err := cmd.Parse(args); err != nil { return nil } @@ -1938,7 +1938,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } if cidFileInfo.Size() == 0 { if err := os.Remove(hostConfig.ContainerIDFile); err != nil { - fmt.Printf("failed to remove CID file '%s': %s \n", hostConfig.ContainerIDFile, err) + fmt.Printf("failed to remove Container ID file '%s': %s \n", hostConfig.ContainerIDFile, err) } } }() @@ -2188,7 +2188,7 @@ func (cli *DockerCli) CmdCp(args ...string) error { } func (cli *DockerCli) CmdSave(args ...string) error { - cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to stdout by default)") + cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to STDOUT by default)") outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT") if err := cmd.Parse(args); err != nil { From b07f193822d00e40580cd11320ed7e01b629f9d7 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Tue, 1 Jul 2014 12:58:04 +1000 Subject: [PATCH 163/167] Update cli.md and man pages to match current cli Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- api/client/commands.go | 2 +- contrib/completion/fish/docker.fish | 2 +- docs/docs-update.py | 214 ++++++++++++++++++++++ docs/man/docker-attach.1.md | 17 +- docs/man/docker-build.1.md | 42 +++-- docs/man/docker-commit.1.md | 20 +- docs/man/docker-cp.1.md | 14 +- docs/man/docker-diff.1.md | 15 +- docs/man/docker-events.1.md | 17 +- docs/man/docker-export.1.md | 16 +- docs/man/docker-history.1.md | 18 +- docs/man/docker-images.1.md | 39 ++-- docs/man/docker-import.1.md | 14 +- docs/man/docker-info.1.md | 8 +- docs/man/docker-inspect.1.md | 16 +- docs/man/docker-kill.1.md | 13 +- docs/man/docker-load.1.md | 12 +- docs/man/docker-login.1.md | 19 +- docs/man/docker-logs.1.md | 17 +- docs/man/docker-pause.1.md | 15 ++ docs/man/docker-port.1.md | 14 +- docs/man/docker-ps.1.md | 42 +++-- docs/man/docker-pull.1.md | 12 +- docs/man/docker-push.1.md | 13 +- docs/man/docker-restart.1.md | 15 +- docs/man/docker-rm.1.md | 29 ++- docs/man/docker-rmi.1.md | 21 ++- docs/man/docker-run.1.md | 115 +++++++----- docs/man/docker-save.1.md | 12 +- docs/man/docker-search.1.md | 31 ++-- docs/man/docker-start.1.md | 22 +-- docs/man/docker-stop.1.md | 17 +- docs/man/docker-tag.1.md | 16 +- docs/man/docker-top.1.md | 16 +- docs/man/docker-unpause.1.md | 15 ++ docs/man/docker-version.1.md | 15 ++ docs/man/docker-wait.1.md | 15 +- docs/man/docker.1.md | 8 +- docs/sources/reference/commandline/cli.md | 58 +++--- runconfig/parse.go | 2 +- 40 files changed, 687 insertions(+), 331 deletions(-) create mode 100755 docs/docs-update.py create mode 100644 docs/man/docker-pause.1.md create mode 100644 docs/man/docker-unpause.1.md create mode 100644 docs/man/docker-version.1.md diff --git a/api/client/commands.go b/api/client/commands.go index 6163f91c1..df2125f5f 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1540,7 +1540,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error { cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes") flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") - flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith \")") + flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith \")") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") if err := cmd.Parse(args); err != nil { diff --git a/contrib/completion/fish/docker.fish b/contrib/completion/fish/docker.fish index a1eac31df..a4a9365f9 100644 --- a/contrib/completion/fish/docker.fish +++ b/contrib/completion/fish/docker.fish @@ -79,7 +79,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d ' # commit complete -c docker -f -n '__fish_docker_no_subcommand' -a commit -d "Create a new image from a container's changes" -complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (eg. "John Hannibal Smith "' +complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (e.g., "John Hannibal Smith "' complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s m -l message -d 'Commit message' complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l run -d 'Config automatically applied when the image is run. (ex: -run=\'{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}\')' complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container" diff --git a/docs/docs-update.py b/docs/docs-update.py new file mode 100755 index 000000000..31bb47db3 --- /dev/null +++ b/docs/docs-update.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python + +# +# Sven's quick hack script to update the documentation +# +# call with: +# ./docs/update.py /usr/bin/docker +# + +import re +from sys import argv +import subprocess +import os +import os.path + +script, docker_cmd = argv + +def print_usage(outtext, docker_cmd, command): + help = "" + try: + #print "RUN ", "".join((docker_cmd, " ", command, " --help")) + help = subprocess.check_output("".join((docker_cmd, " ", command, " --help")), stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError, e: + help = e.output + for l in str(help).strip().split("\n"): + l = l.rstrip() + if l == '': + outtext.write("\n") + else: + # `docker --help` tells the user the path they called it with + l = re.sub(docker_cmd, "docker", l) + outtext.write(" "+l+"\n") + outtext.write("\n") + +# TODO: look for an complain about any missing commands +def update_cli_reference(): + originalFile = "docs/sources/reference/commandline/cli.md" + os.rename(originalFile, originalFile+".bak") + + intext = open(originalFile+".bak", "r") + outtext = open(originalFile, "w") + + mode = 'p' + space = " " + command = "" + # 2 mode line-by line parser + for line in intext: + if mode=='p': + # Prose + match = re.match("( \s*)Usage: docker ([a-z]+)", line) + if match: + # the begining of a Docker command usage block + space = match.group(1) + command = match.group(2) + mode = 'c' + else: + match = re.match("( \s*)Usage of .*docker.*:", line) + if match: + # the begining of the Docker --help usage block + space = match.group(1) + command = "" + mode = 'c' + else: + outtext.write(line) + else: + # command usage block + match = re.match("("+space+")(.*)|^$", line) + #print "CMD ", command + if not match: + # The end of the current usage block - Shell out to run docker to see the new output + print_usage(outtext, docker_cmd, command) + outtext.write(line) + mode = 'p' + if mode == 'c': + print_usage(outtext, docker_cmd, command) + +def update_man_pages(): + cmds = [] + try: + help = subprocess.check_output("".join((docker_cmd)), stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError, e: + help = e.output + for l in str(help).strip().split("\n"): + l = l.rstrip() + if l != "": + match = re.match(" (.*?) .*", l) + if match: + cmds.append(match.group(1)) + + desc_re = re.compile(r".*# DESCRIPTION(.*?)# (OPTIONS|EXAMPLES?).*", re.MULTILINE|re.DOTALL) + example_re = re.compile(r".*# EXAMPLES?(.*)# HISTORY.*", re.MULTILINE|re.DOTALL) + history_re = re.compile(r".*# HISTORY(.*)", re.MULTILINE|re.DOTALL) + + for command in cmds: + print "COMMAND: "+command + history = "" + description = "" + examples = "" + if os.path.isfile("docs/man/docker-"+command+".1.md"): + intext = open("docs/man/docker-"+command+".1.md", "r") + txt = intext.read() + intext.close() + match = desc_re.match(txt) + if match: + description = match.group(1) + match = example_re.match(txt) + if match: + examples = match.group(1) + match = history_re.match(txt) + if match: + history = match.group(1).strip() + + usage = "" + usage_description = "" + params = {} + key_params = {} + + help = "" + try: + help = subprocess.check_output("".join((docker_cmd, " ", command, " --help")), stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError, e: + help = e.output + last_key = "" + for l in str(help).split("\n"): + l = l.rstrip() + if l != "": + match = re.match("Usage: docker "+command+"(.*)", l) + if match: + usage = match.group(1).strip() + else: + #print ">>>>"+l + match = re.match(" (-+)(.*) \s+(.*)", l) + if match: + last_key = match.group(2).rstrip() + #print " found "+match.group(1) + key_params[last_key] = match.group(1)+last_key + params[last_key] = match.group(3) + else: + if last_key != "": + params[last_key] = params[last_key] + "\n" + l + else: + if usage_description != "": + usage_description = usage_description + "\n" + usage_description = usage_description + l + + # replace [OPTIONS] with the list of params + options = "" + match = re.match("\[OPTIONS\](.*)", usage) + if match: + usage = match.group(1) + + new_usage = "" + # TODO: sort without the `-`'s + for key in sorted(params.keys(), key=lambda s: s.lower()): + # split on commas, remove --?.*=.*, put in *'s mumble + ps = [] + opts = [] + for k in key_params[key].split(","): + #print "......"+k + match = re.match("(-+)([A-Za-z-0-9]*)(?:=(.*))?", k.lstrip()) + if match: + p = "**"+match.group(1)+match.group(2)+"**" + o = "**"+match.group(1)+match.group(2)+"**" + if match.group(3): + # if ="" then use UPPERCASE(group(2))" + val = match.group(3) + if val == "\"\"": + val = match.group(2).upper() + p = p+"[=*"+val+"*]" + val = match.group(3) + if val in ("true", "false"): + params[key] = params[key].rstrip() + if not params[key].endswith('.'): + params[key] = params[key]+ "." + params[key] = params[key] + " The default is *"+val+"*." + val = "*true*|*false*" + o = o+"="+val + ps.append(p) + opts.append(o) + else: + print "nomatch:"+k + new_usage = new_usage+ "\n["+"|".join(ps)+"]" + options = options + ", ".join(opts) + "\n "+ params[key]+"\n\n" + if new_usage != "": + new_usage = new_usage.strip() + "\n" + usage = new_usage + usage + + + outtext = open("docs/man/docker-"+command+".1.md", "w") + outtext.write("""% DOCKER(1) Docker User Manuals +% Docker Community +% JUNE 2014 +# NAME +""") + outtext.write("docker-"+command+" - "+usage_description+"\n\n") + outtext.write("# SYNOPSIS\n**docker "+command+"**\n"+usage+"\n\n") + if description != "": + outtext.write("# DESCRIPTION"+description) + if options == "": + options = "There are no available options.\n\n" + outtext.write("# OPTIONS\n"+options) + if examples != "": + outtext.write("# EXAMPLES"+examples) + outtext.write("# HISTORY\n") + if history != "": + outtext.write(history+"\n") + recent_history_re = re.compile(".*June 2014.*", re.MULTILINE|re.DOTALL) + if not recent_history_re.match(history): + outtext.write("June 2014, updated by Sven Dowideit \n") + outtext.close() + +# main +update_cli_reference() +update_man_pages() diff --git a/docs/man/docker-attach.1.md b/docs/man/docker-attach.1.md index 91188aaae..0ca979701 100644 --- a/docs/man/docker-attach.1.md +++ b/docs/man/docker-attach.1.md @@ -1,11 +1,14 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-attach - Attach to a running container # SYNOPSIS -**docker attach** **--no-stdin**[=*false*] **--sig-proxy**[=*true*] CONTAINER +**docker attach** +[**--no-stdin**[=*false*]] +[**--sig-proxy**[=*true*]] + CONTAINER # DESCRIPTION If you **docker run** a container in detached mode (**-d**), you can reattach to @@ -19,11 +22,10 @@ the client. # OPTIONS **--no-stdin**=*true*|*false* -When set to true, do not attach to stdin. The default is *false*. + Do not attach STDIN. The default is *false*. -**--sig-proxy**=*true*|*false*: -When set to true, proxify received signals to the process (even in non-tty -mode). SIGCHLD is not proxied. The default is *true*. +**--sig-proxy**=*true*|*false* + Proxify all received signals to the process (even in non-TTY mode). SIGCHLD is not proxied. The default is *true*. # EXAMPLES @@ -56,3 +58,4 @@ attach** command: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-build.1.md b/docs/man/docker-build.1.md index 3c031445a..2b426f1ce 100644 --- a/docs/man/docker-build.1.md +++ b/docs/man/docker-build.1.md @@ -1,12 +1,17 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-build - Build an image from a Dockerfile source at PATH +docker-build - Build a new image from the source code at PATH # SYNOPSIS -**docker build** [**--no-cache**[=*false*]] [**-q**|**--quiet**[=*false*]] - [**--rm**] [**-t**|**--tag**=TAG] PATH | URL | - +**docker build** +[**--force-rm**[=*false*]] +[**--no-cache**[=*false*]] +[**-q**|**--quiet**[=*false*]] +[**--rm**[=*true*]] +[**-t**|**--tag**[=*TAG*]] + PATH | URL | - # DESCRIPTION This will read the Dockerfile from the directory specified in **PATH**. @@ -25,22 +30,20 @@ When a Git repository is set as the **URL**, the repository is used as context. # OPTIONS - -**-q**, **--quiet**=*true*|*false* - When set to true, suppress verbose build output. Default is *false*. - -**--rm**=*true*|*false* - When true, remove intermediate containers that are created during the -build process. The default is true. - -**-t**, **--tag**=*tag* - The name to be applied to the resulting image on successful completion of -the build. `tag` in this context means the entire image name including the -optional TAG after the ':'. +**--force-rm**=*true*|*false* + Always remove intermediate containers, even after unsuccessful builds. The default is *false*. **--no-cache**=*true*|*false* - When set to true, do not use a cache when building the image. The -default is *false*. + Do not use cache when building the image. The default is *false*. + +**-q**, **--quiet**=*true*|*false* + Suppress the verbose output generated by the containers. The default is *false*. + +**--rm**=*true*|*false* + Remove intermediate containers after a successful build. The default is *true*. + +**-t**, **--tag**="" + Repository name (and optionally a tag) to be applied to the resulting image in case of success # EXAMPLES @@ -115,3 +118,4 @@ Note: You can set an arbitrary Git repository via the `git://` schema. # HISTORY March 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index c0f2c734c..5ec3808df 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -1,22 +1,23 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-commit - Create a new image from the changes to an existing -container +docker-commit - Create a new image from a container's changes # SYNOPSIS -**docker commit** **-a**|**--author**[=""] **-m**|**--message**[=""] -CONTAINER [REPOSITORY[:TAG]] +**docker commit** +[**-a**|**--author**[=*AUTHOR*]] +[**-m**|**--message**[=*MESSAGE*]] + CONTAINER [REPOSITORY[:TAG]] # DESCRIPTION Using an existing container's name or ID you can create a new image. # OPTIONS -**-a, --author**="" - Author name. (e.g., "John Hannibal Smith " +**-a**, **--author**="" + Author (e.g., "John Hannibal Smith ") -**-m, --message**="" +**-m**, **--message**="" Commit message **-p, --pause**=true @@ -35,3 +36,4 @@ create a new image run docker ps to find the container's ID and then run: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and in +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-cp.1.md b/docs/man/docker-cp.1.md index 1801e7318..750a6d1d5 100644 --- a/docs/man/docker-cp.1.md +++ b/docs/man/docker-cp.1.md @@ -1,18 +1,22 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-cp - Copy files/folders from the PATH to the HOSTPATH # SYNOPSIS -**docker cp** CONTAINER:PATH HOSTPATH +**docker cp** +CONTAINER:PATH HOSTPATH # DESCRIPTION Copy files/folders from a container's filesystem to the host path. Paths are relative to the root of the filesystem. Files can be copied from a running or stopped container. -# EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES An important shell script file, created in a bash shell, is copied from the exited container to the current dir on the host: @@ -21,4 +25,4 @@ the exited container to the current dir on the host: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-diff.1.md b/docs/man/docker-diff.1.md index 2053f2c3d..d7aae25f8 100644 --- a/docs/man/docker-diff.1.md +++ b/docs/man/docker-diff.1.md @@ -1,18 +1,22 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-diff - Inspect changes on a container's filesystem # SYNOPSIS -**docker diff** CONTAINER +**docker diff** +CONTAINER # DESCRIPTION Inspect changes on a container's filesystem. You can use the full or shortened container ID or the container name set using **docker run --name** option. -# EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES Inspect the changes to on a nginx container: # docker diff 1fdfd1f54c1b @@ -40,5 +44,4 @@ Inspect the changes to on a nginx container: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-events.1.md b/docs/man/docker-events.1.md index 2ebe9247d..ca8f63db5 100644 --- a/docs/man/docker-events.1.md +++ b/docs/man/docker-events.1.md @@ -1,10 +1,14 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-events - Get real time events from the server -**docker events** **--since**=""|*epoch-time* +# SYNOPSIS +**docker events** +[**--since**[=*SINCE*]] +[**--until**[=*UNTIL*]] + # DESCRIPTION Get event information from the Docker daemon. Information can include historical @@ -12,8 +16,10 @@ information and real-time information. # OPTIONS **--since**="" -Show previously created events and then stream. This can be in either -seconds since epoch, or date string. + Show all events created since timestamp + +**--until**="" + Stream events until this timestamp # EXAMPLES @@ -44,3 +50,4 @@ Again the output container IDs have been shortened for the purposes of this docu # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-export.1.md b/docs/man/docker-export.1.md index ab11aa126..efd884a79 100644 --- a/docs/man/docker-export.1.md +++ b/docs/man/docker-export.1.md @@ -1,19 +1,22 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-export - Export the contents of a filesystem as a tar archive to -STDOUT. +docker-export - Export the contents of a filesystem as a tar archive to STDOUT # SYNOPSIS -**docker export** CONTAINER +**docker export** +CONTAINER # DESCRIPTION Export the contents of a container's filesystem using the full or shortened container ID or container name. The output is exported to STDOUT and can be redirected to a tar file. -# EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES Export the contents of the container called angry_bell to a tar file called test.tar: @@ -24,3 +27,4 @@ called test.tar: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-history.1.md b/docs/man/docker-history.1.md index 1b3a9858b..ee58e03fc 100644 --- a/docs/man/docker-history.1.md +++ b/docs/man/docker-history.1.md @@ -1,11 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-history - Show the history of an image # SYNOPSIS -**docker history** **--no-trunc**[=*false*] [**-q**|**--quiet**[=*false*]] +**docker history** +[**--no-trunc**[=*false*]] +[**-q**|**--quiet**[=*false*]] IMAGE # DESCRIPTION @@ -13,14 +15,13 @@ docker-history - Show the history of an image Show the history of when and how an image was created. # OPTIONS - **--no-trunc**=*true*|*false* - When true don't truncate output. Default is false + Don't truncate output. The default is *false*. -**-q**, **--quiet=*true*|*false* - When true only show numeric IDs. Default is false. +**-q**, **--quiet**=*true*|*false* + Only show numeric IDs. The default is *false*. -# EXAMPLE +# EXAMPLES $ sudo docker history fedora IMAGE CREATED CREATED BY SIZE 105182bb5e8b 5 days ago /bin/sh -c #(nop) ADD file:71356d2ad59aa3119d 372.7 MB @@ -30,3 +31,4 @@ Show the history of when and how an image was created. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-images.1.md b/docs/man/docker-images.1.md index 602ccf7c9..a940192e9 100644 --- a/docs/man/docker-images.1.md +++ b/docs/man/docker-images.1.md @@ -1,17 +1,16 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-images - List the images in the local repository +docker-images - List images # SYNOPSIS **docker images** -[**-a**|**--all**=*false*] -[**--no-trunc**[=*false*] -[**-q**|**--quiet**[=*false*] -[**-t**|**--tree**=*false*] -[**-v**|**--viz**=*false*] -[NAME] +[**-a**|**--all**[=*false*]] +[**-f**|**--filter**[=*[]*]] +[**--no-trunc**[=*false*]] +[**-q**|**--quiet**[=*false*]] + [NAME] # DESCRIPTION This command lists the images stored in the local Docker repository. @@ -30,26 +29,17 @@ called fedora. It may be tagged with 18, 19, or 20, etc. to manage different versions. # OPTIONS - **-a**, **--all**=*true*|*false* - When set to true, also include all intermediate images in the list. The -default is false. + Show all images (by default filter out the intermediate image layers). The default is *false*. + +**-f**, **--filter**=[] + Provide filter values (i.e. 'dangling=true') **--no-trunc**=*true*|*false* - When set to true, list the full image ID and not the truncated ID. The -default is false. + Don't truncate output. The default is *false*. **-q**, **--quiet**=*true*|*false* - When set to true, list the complete image ID as part of the output. The -default is false. - -**-t**, **--tree**=*true*|*false* - When set to true, list the images in a tree dependency tree (hierarchy) -format. The default is false. - -**-v**, **--viz**=*true*|*false* - When set to true, list the graph in graphviz format. The default is -*false*. + Only show numeric IDs. The default is *false*. # EXAMPLES @@ -97,3 +87,4 @@ tools. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-import.1.md b/docs/man/docker-import.1.md index 6b76d191f..f320eafa2 100644 --- a/docs/man/docker-import.1.md +++ b/docs/man/docker-import.1.md @@ -1,17 +1,20 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-import - Create an empty filesystem image and import the contents -of the tarball into it. +docker-import - Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it. # SYNOPSIS -**docker import** URL|- [REPOSITORY[:TAG]] +**docker import** +URL|- [REPOSITORY[:TAG]] # DESCRIPTION Create a new filesystem image from the contents of a tarball (`.tar`, `.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it. +# OPTIONS +There are no available options. + # EXAMPLES ## Import from a remote location @@ -37,3 +40,4 @@ Import to docker via pipe and stdin: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-info.1.md b/docs/man/docker-info.1.md index 8c03945db..cae9a3290 100644 --- a/docs/man/docker-info.1.md +++ b/docs/man/docker-info.1.md @@ -1,12 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-info - Display system wide information +docker-info - Display system-wide information # SYNOPSIS **docker info** + # DESCRIPTION This command displays system wide information regarding the Docker installation. Information displayed includes the number of containers and images, pool name, @@ -44,3 +45,4 @@ Here is a sample output: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-inspect.1.md b/docs/man/docker-inspect.1.md index a82c76a62..29511fbe6 100644 --- a/docs/man/docker-inspect.1.md +++ b/docs/man/docker-inspect.1.md @@ -1,12 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-inspect - Return low-level information on a container/image +docker-inspect - Return low-level information on a container or image # SYNOPSIS -**docker inspect** [**-f**|**--format**="" CONTAINER|IMAGE -[CONTAINER|IMAGE...] +**docker inspect** +[**-f**|**--format**[=*FORMAT*]] +CONTAINER|IMAGE [CONTAINER|IMAGE...] # DESCRIPTION @@ -17,8 +18,7 @@ each result. # OPTIONS **-f**, **--format**="" - The text/template package of Go describes all the details of the -format. See examples section + Format the output using the given go template. # EXAMPLES @@ -224,6 +224,6 @@ Use an image's ID or name (e.g., repository/name[:tag]) to get information }] # HISTORY - April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-kill.1.md b/docs/man/docker-kill.1.md index 8175002d3..a454c432f 100644 --- a/docs/man/docker-kill.1.md +++ b/docs/man/docker-kill.1.md @@ -1,11 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-kill - Kill a running container (send SIGKILL, or specified signal) +docker-kill - Kill a running container using SIGKILL or a specified signal # SYNOPSIS -**docker kill** **--signal**[=*"KILL"*] CONTAINER [CONTAINER...] +**docker kill** +[**-s**|**--signal**[=*"KILL"*]] + CONTAINER [CONTAINER...] # DESCRIPTION @@ -13,9 +15,10 @@ The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal. # OPTIONS -**-s**, **--signal**=*"KILL"* +**-s**, **--signal**="KILL" Signal to send to the container # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-load.1.md b/docs/man/docker-load.1.md index 535b701cc..41ab5f64c 100644 --- a/docs/man/docker-load.1.md +++ b/docs/man/docker-load.1.md @@ -1,11 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-load - Load an image from a tar archive on STDIN # SYNOPSIS -**docker load** **--input**="" +**docker load** +[**-i**|**--input**[=*INPUT*]] + # DESCRIPTION @@ -13,11 +15,10 @@ Loads a tarred repository from a file or the standard input stream. Restores both images and tags. # OPTIONS - **-i**, **--input**="" Read from a tar archive file, instead of STDIN -# EXAMPLE +# EXAMPLES $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE @@ -34,3 +35,4 @@ Restores both images and tags. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-login.1.md b/docs/man/docker-login.1.md index 0a9cb283d..658334265 100644 --- a/docs/man/docker-login.1.md +++ b/docs/man/docker-login.1.md @@ -1,12 +1,15 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-login - Register or Login to a docker registry server. +docker-login - Register or log in to a Docker registry server, if no server is specified "https://index.docker.io/v1/" is the default. # SYNOPSIS -**docker login** [**-e**|**-email**=""] [**-p**|**--password**=""] - [**-u**|**--username**=""] [SERVER] +**docker login** +[**-e**|**--email**[=*EMAIL*]] +[**-p**|**--password**[=*PASSWORD*]] +[**-u**|**--username**[=*USERNAME*]] + [SERVER] # DESCRIPTION Register or Login to a docker registry server, if no server is @@ -15,7 +18,7 @@ login to a private registry you can specify this by adding the server name. # OPTIONS **-e**, **--email**="" - Email address + Email **-p**, **--password**="" Password @@ -23,7 +26,7 @@ login to a private registry you can specify this by adding the server name. **-u**, **--username**="" Username -# EXAMPLE +# EXAMPLES ## Login to a local registry @@ -32,4 +35,4 @@ login to a private registry you can specify this by adding the server name. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-logs.1.md b/docs/man/docker-logs.1.md index 0b9ce867e..5881b0512 100644 --- a/docs/man/docker-logs.1.md +++ b/docs/man/docker-logs.1.md @@ -1,11 +1,14 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-logs - Fetch the logs of a container # SYNOPSIS -**docker logs** **--follow**[=*false*] CONTAINER +**docker logs** +[**-f**|**--follow**[=*false*]] +[**-t**|**--timestamps**[=*false*]] +CONTAINER # DESCRIPTION The **docker logs** command batch-retrieves whatever logs are present for @@ -18,9 +21,13 @@ The **docker logs --follow** command combines commands **docker logs** and then continue streaming new output from the container’s stdout and stderr. # OPTIONS -**-f, --follow**=*true*|*false* - When *true*, follow log output. The default is false. +**-f**, **--follow**=*true*|*false* + Follow log output. The default is *false*. + +**-t**, **--timestamps**=*true*|*false* + Show timestamps. The default is *false*. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-pause.1.md b/docs/man/docker-pause.1.md new file mode 100644 index 000000000..e6c0c2455 --- /dev/null +++ b/docs/man/docker-pause.1.md @@ -0,0 +1,15 @@ +% DOCKER(1) Docker User Manuals +% Docker Community +% JUNE 2014 +# NAME +docker-pause - Pause all processes within a container + +# SYNOPSIS +**docker pause** +CONTAINER + +# OPTIONS +There are no available options. + +# HISTORY +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-port.1.md b/docs/man/docker-port.1.md index 9773e4d80..a92f75cd5 100644 --- a/docs/man/docker-port.1.md +++ b/docs/man/docker-port.1.md @@ -1,15 +1,17 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-port - Lookup the public-facing port which is NAT-ed to PRIVATE_PORT +docker-port - Lookup the public-facing port that is NAT-ed to PRIVATE_PORT # SYNOPSIS -**docker port** CONTAINER PRIVATE_PORT +**docker port** +CONTAINER PRIVATE_PORT -# DESCRIPTION -Lookup the public-facing port which is NAT-ed to PRIVATE_PORT +# OPTIONS +There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-ps.1.md b/docs/man/docker-ps.1.md index 60fce0213..454be74ad 100644 --- a/docs/man/docker-ps.1.md +++ b/docs/man/docker-ps.1.md @@ -1,14 +1,20 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-ps - List containers # SYNOPSIS -**docker ps** [**-a**|**--all**=*false*] [**--before**=""] -[**-l**|**--latest**=*false*] [**-n**=*-1*] [**--no-trunc**=*false*] -[**-q**|**--quiet**=*false*] [**-s**|**--size**=*false*] -[**--since**=""] +**docker ps** +[**-a**|**--all**[=*false*]] +[**--before**[=*BEFORE*]] +[**-l**|**--latest**[=*false*]] +[**-n**[=*-1*]] +[**--no-trunc**[=*false*]] +[**-q**|**--quiet**[=*false*]] +[**-s**|**--size**[=*false*]] +[**--since**[=*SINCE*]] + # DESCRIPTION @@ -16,36 +22,31 @@ List the containers in the local repository. By default this show only the running containers. # OPTIONS - **-a**, **--all**=*true*|*false* - When true show all containers. Only running containers are shown by -default. Default is false. + Show all containers. Only running containers are shown by default. The default is *false*. **--before**="" - Show only container created before Id or Name, include non-running -ones. + Show only container created before Id or Name, include non-running ones. **-l**, **--latest**=*true*|*false* - When true show only the latest created container, include non-running -ones. The default is false. + Show only the latest created container, include non-running ones. The default is *false*. -**-n**=NUM - Show NUM (integer) last created containers, include non-running ones. -The default is -1 (none) +**-n**=-1 + Show n last created containers, include non-running ones. **--no-trunc**=*true*|*false* - When true truncate output. Default is false. + Don't truncate output. The default is *false*. **-q**, **--quiet**=*true*|*false* - When false only display numeric IDs. Default is false. + Only display numeric IDs. The default is *false*. **-s**, **--size**=*true*|*false* - When true display container sizes. Default is false. + Display sizes. The default is *false*. **--since**="" Show only containers created since Id or Name, include non-running ones. -# EXAMPLE +# EXAMPLES # Display all containers, including non-running # docker ps -a @@ -66,3 +67,4 @@ The default is -1 (none) # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-pull.1.md b/docs/man/docker-pull.1.md index d8e177b2b..c397b42ea 100644 --- a/docs/man/docker-pull.1.md +++ b/docs/man/docker-pull.1.md @@ -1,11 +1,12 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-pull - Pull an image or a repository from the registry # SYNOPSIS -**docker pull** [REGISTRY_PATH/]NAME[:TAG] +**docker pull** +NAME[:TAG] # DESCRIPTION @@ -14,6 +15,9 @@ there is more than one image for a repository (e.g., fedora) then all images for that repository name are pulled down including any tags. It is also possible to specify a non-default registry to pull from. +# OPTIONS +There are no available options. + # EXAMPLES # Pull a repository with multiple images @@ -48,4 +52,4 @@ It is also possible to specify a non-default registry to pull from. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-push.1.md b/docs/man/docker-push.1.md index dbb6e7d1b..4b05b62a7 100644 --- a/docs/man/docker-push.1.md +++ b/docs/man/docker-push.1.md @@ -1,11 +1,12 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-push - Push an image or a repository to the registry # SYNOPSIS -**docker push** NAME[:TAG] +**docker push** +NAME[:TAG] # DESCRIPTION Push an image or a repository to a registry. The default registry is the Docker @@ -13,7 +14,10 @@ Index located at [index.docker.io](https://index.docker.io/v1/). However the image can be pushed to another, perhaps private, registry as demonstrated in the example below. -# EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES # Pushing a new image to a registry @@ -42,3 +46,4 @@ listed. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-restart.1.md b/docs/man/docker-restart.1.md index 44634f661..6374273cf 100644 --- a/docs/man/docker-restart.1.md +++ b/docs/man/docker-restart.1.md @@ -1,21 +1,22 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-restart - Restart a running container # SYNOPSIS -**docker restart** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...] +**docker restart** +[**-t**|**--time**[=*10*]] + CONTAINER [CONTAINER...] # DESCRIPTION Restart each container listed. # OPTIONS -**-t**, **--time**=NUM - Number of seconds to try to stop for before killing the container. Once -killed it will then be restarted. Default=10 +**-t**, **--time**=10 + Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-rm.1.md b/docs/man/docker-rm.1.md index ae85af527..f41a6edb1 100644 --- a/docs/man/docker-rm.1.md +++ b/docs/man/docker-rm.1.md @@ -1,16 +1,15 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 - +% Docker Community +% JUNE 2014 # NAME - -docker-rm - Remove one or more containers. +docker-rm - Remove one or more containers # SYNOPSIS - -**docker rm** [**-f**|**--force**[=*false*] [**-l**|**--link**[=*false*] [**-v**| -**--volumes**[=*false*] -CONTAINER [CONTAINER...] +**docker rm** +[**-f**|**--force**[=*false*]] +[**-l**|**--link**[=*false*]] +[**-v**|**--volumes**[=*false*]] + CONTAINER [CONTAINER...] # DESCRIPTION @@ -20,18 +19,14 @@ remove a running container unless you use the \fB-f\fR option. To see all containers on a host use the **docker ps -a** command. # OPTIONS - **-f**, **--force**=*true*|*false* - When set to true, force the removal of the container. The default is -*false*. + Force removal of running container. The default is *false*. **-l**, **--link**=*true*|*false* - When set to true, remove the specified link and not the underlying -container. The default is *false*. + Remove the specified link and not the underlying container. The default is *false*. **-v**, **--volumes**=*true*|*false* - When set to true, remove the volumes associated to the container. The -default is *false*. + Remove the volumes associated with the container. The default is *false*. # EXAMPLES @@ -51,6 +46,6 @@ command. The use that name as follows: docker rm hopeful_morse # HISTORY - April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-rmi.1.md b/docs/man/docker-rmi.1.md index b728dc16a..e03ecc4bc 100644 --- a/docs/man/docker-rmi.1.md +++ b/docs/man/docker-rmi.1.md @@ -1,12 +1,14 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-rmi \- Remove one or more images. +docker-rmi - Remove one or more images # SYNOPSIS - -**docker rmi** [**-f**|**--force**[=*false*] IMAGE [IMAGE...] +**docker rmi** +[**-f**|**--force**[=*false*]] +[**--no-prune**[=*false*]] +IMAGE [IMAGE...] # DESCRIPTION @@ -16,10 +18,11 @@ container unless you use the **-f** option. To see all images on a host use the **docker images** command. # OPTIONS - **-f**, **--force**=*true*|*false* - When set to true, force the removal of the image. The default is -*false*. + Force removal of the image. The default is *false*. + +**--no-prune**=*true*|*false* + Do not delete untagged parents. The default is *false*. # EXAMPLES @@ -30,6 +33,6 @@ Here is an example of removing and image: docker rmi fedora/httpd # HISTORY - April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index ec9db8fd0..1e1adbe55 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -1,26 +1,40 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-run - Run a process in an isolated container +docker-run - Run a command in a new container # SYNOPSIS **docker run** -[**-a**|**--attach**[=]] [**-c**|**--cpu-shares**[=0] -[**-m**|**--memory**=*memory-limit*] -[**--cidfile**=*file*] [**-d**|**--detach**[=*false*]] [**--dns**=*IP-address*] -[**--name**=*name*] [**-u**|**--user**=*username*|*uid*] -[**--link**=*name*:*alias*] -[**-e**|**--env**=*environment*] [**--entrypoint**=*command*] -[**--expose**=*port*] [**-P**|**--publish-all**[=*false*]] -[**-p**|**--publish**=*port-mapping*] [**-h**|**--hostname**=*hostname*] -[**--rm**[=*false*]] [**--privileged**[=*false*]] +[**-a**|**--attach**[=*[]*]] +[**-c**|**--cpu-shares**[=*0*]] +[**--cidfile**[=*CIDFILE*]] +[**--cpuset**[=*CPUSET*]] +[**-d**|**--detach**[=*false*]] +[**--dns-search**[=*[]*]] +[**--dns**[=*[]*]] +[**-e**|**--env**[=*[]*]] +[**--entrypoint**[=*ENTRYPOINT*]] +[**--env-file**[=*[]*]] +[**--expose**[=*[]*]] +[**-h**|**--hostname**[=*HOSTNAME*]] [**-i**|**--interactive**[=*false*]] -[**-t**|**--tty**[=*false*]] [**--lxc-conf**=*options*] -[**-n**|**--networking**[=*true*]] -[**-v**|**--volume**=*volume*] [**--volumes-from**=*container-id*] -[**-w**|**--workdir**=*directory*] [**--sig-proxy**[=*true*]] -IMAGE [COMMAND] [ARG...] +[**--link**[=*[]*]] +[**--lxc-conf**[=*[]*]] +[**-m**|**--memory**[=*MEMORY*]] +[**--name**[=*NAME*]] +[**--net**[=*"bridge"*]] +[**-P**|**--publish-all**[=*false*]] +[**-p**|**--publish**[=*[]*]] +[**--privileged**[=*false*]] +[**--rm**[=*false*]] +[**--sig-proxy**[=*true*]] +[**-t**|**--tty**[=*false*]] +[**-u**|**--user**[=*USER*]] +[**-v**|**--volume**[=*[]*]] +[**--volumes-from**[=*[]*]] +[**-w**|**--workdir**[=*WORKDIR*]] + IMAGE [COMMAND] [ARG...] # DESCRIPTION @@ -56,6 +70,8 @@ run**. **--cidfile**=*file* Write the container ID to the file specified. +**--cpuset**="" + CPUs in which to allow execution (0-3, 0,1) **-d**, **-detach**=*true*|*false* Detached mode. This runs the container in the background. It outputs the new @@ -67,6 +83,8 @@ the detached mode, then you cannot use the **-rm** option. When attached in the tty mode, you can detach from a running container without stopping the process by pressing the keys CTRL-P CTRL-Q. +**--dns-search**=[] + Set custom dns search domains **--dns**=*IP-address* Set custom DNS servers. This option can be used to override the DNS @@ -92,6 +110,8 @@ pass in more options via the COMMAND. But, sometimes an operator may want to run something else inside the container, so you can override the default ENTRYPOINT at runtime by using a **--entrypoint** and a string to specify the new ENTRYPOINT. +**--env-file**=[] + Read in a line delimited file of ENV variables **--expose**=*port* Expose a port from the container without publishing it to your host. A @@ -100,36 +120,12 @@ developer can expose the port using the EXPOSE parameter of the Dockerfile, 2) the operator can use the **--expose** option with **docker run**, or 3) the container can be started with the **--link**. -**-m**, **-memory**=*memory-limit* - Allows you to constrain the memory available to a container. If the host -supports swap memory, then the -m memory setting can be larger than physical -RAM. If a limit of 0 is specified, the container's memory is not limited. The -actual limit may be rounded up to a multiple of the operating system's page -size, if it is not already. The memory limit should be formatted as follows: -``, where unit = b, k, m or g. - -**-P**, **-publish-all**=*true*|*false* - When set to true publish all exposed ports to the host interfaces. The -default is false. If the operator uses -P (or -p) then Docker will make the -exposed port accessible on the host and the ports will be available to any -client that can reach the host. To find the map between the host ports and the -exposed ports, use **docker port**. - - -**-p**, **-publish**=[] - Publish a container's port to the host (format: ip:hostPort:containerPort | -ip::containerPort | hostPort:containerPort) (use **docker port** to see the -actual mapping) - - **-h**, **-hostname**=*hostname* Sets the container host name that is available inside the container. - **-i**, **-interactive**=*true*|*false* When set to true, keep stdin open even if not attached. The default is false. - **--link**=*name*:*alias* Add link to another container. The format is name:alias. If the operator uses **--link** when starting the new client container, then the client @@ -137,16 +133,16 @@ container can access the exposed port via a private networking interface. Docker will set some environment variables in the client container to help indicate which interface and port to use. +**--lxc-conf**=[] + (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" -**-n**, **-networking**=*true*|*false* - By default, all containers have networking enabled (true) and can make -outgoing connections. The operator can disable networking with **--networking** -to false. This disables all incoming and outgoing networking. In cases like this -, I/O can only be performed through files or by using STDIN/STDOUT. - -Also by default, the container will use the same DNS servers as the host. The -operator may override this with **-dns**. - +**-m**, **-memory**=*memory-limit* + Allows you to constrain the memory available to a container. If the host +supports swap memory, then the -m memory setting can be larger than physical +RAM. If a limit of 0 is specified, the container's memory is not limited. The +actual limit may be rounded up to a multiple of the operating system's page +size, if it is not already. The memory limit should be formatted as follows: +``, where unit = b, k, m or g. **--name**=*name* Assign a name to the container. The operator can identify a container in @@ -162,6 +158,24 @@ string name. The name is useful when defining links (see **--link**) (or any other place you need to identify a container). This works for both background and foreground Docker containers. +**--net**="bridge" + Set the Network mode for the container + 'bridge': creates a new network stack for the container on the docker bridge + 'none': no networking for this container + 'container:': reuses another container network stack + 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. + +**-P**, **-publish-all**=*true*|*false* + When set to true publish all exposed ports to the host interfaces. The +default is false. If the operator uses -P (or -p) then Docker will make the +exposed port accessible on the host and the ports will be available to any +client that can reach the host. To find the map between the host ports and the +exposed ports, use **docker port**. + +**-p**, **-publish**=[] + Publish a container's port to the host (format: ip:hostPort:containerPort | +ip::containerPort | hostPort:containerPort) (use **docker port** to see the +actual mapping) **--privileged**=*true*|*false* Give extended privileges to this container. By default, Docker containers are @@ -356,3 +370,4 @@ changes will also be reflected on the host in /var/db. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-save.1.md b/docs/man/docker-save.1.md index 126af6b15..a6546a044 100644 --- a/docs/man/docker-save.1.md +++ b/docs/man/docker-save.1.md @@ -1,11 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-save - Save an image to a tar archive (streamed to STDOUT by default) # SYNOPSIS -**docker save** [**-o**|**--output**=""] IMAGE +**docker save** +[**-o**|**--output**[=*OUTPUT*]] +IMAGE # DESCRIPTION Produces a tarred repository to the standard output stream. Contains all @@ -17,7 +19,7 @@ Stream to a file instead of STDOUT by using **-o**. **-o**, **--output**="" Write to an file, instead of STDOUT -# EXAMPLE +# EXAMPLES Save all fedora repository images to a fedora-all.tar and save the latest fedora image to a fedora-latest.tar: @@ -32,4 +34,4 @@ fedora image to a fedora-latest.tar: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-search.1.md b/docs/man/docker-search.1.md index 945dd34e5..e3103c65a 100644 --- a/docs/man/docker-search.1.md +++ b/docs/man/docker-search.1.md @@ -1,12 +1,15 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-search - Search the docker index for images +docker-search - Search the Docker Hub for images # SYNOPSIS -**docker search** **--no-trunc**[=*false*] **--automated**[=*false*] - **-s**|**--stars**[=*0*] TERM +**docker search** +[**--automated**[=*false*]] +[**--no-trunc**[=*false*]] +[**-s**|**--stars**[=*0*]] +TERM # DESCRIPTION @@ -16,17 +19,16 @@ number of stars awarded, whether the image is official, and whether it is automated. # OPTIONS -**--no-trunc**=*true*|*false* - When true display the complete description. The default is false. - -**-s**, **--stars**=NUM - Only displays with at least NUM (integer) stars. I.e. only those images -ranked >=NUM. - **--automated**=*true*|*false* - When true only show automated builds. The default is false. + Only show automated builds. The default is *false*. -# EXAMPLE +**--no-trunc**=*true*|*false* + Don't truncate output. The default is *false*. + +**-s**, **--stars**=0 + Only displays with at least x stars + +# EXAMPLES ## Search the registry for ranked images @@ -53,3 +55,4 @@ ranked 1 or higher: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-start.1.md b/docs/man/docker-start.1.md index 2815f1b07..a01e190b6 100644 --- a/docs/man/docker-start.1.md +++ b/docs/man/docker-start.1.md @@ -1,29 +1,27 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-start - Restart a stopped container # SYNOPSIS -**docker start** [**a**|**--attach**[=*false*]] [**-i**|**--interactive** -[=*true*] CONTAINER [CONTAINER...] +**docker start** +[**-a**|**--attach**[=*false*]] +[**-i**|**--interactive**[=*false*]] +CONTAINER [CONTAINER...] # DESCRIPTION Start a stopped container. -# OPTION +# OPTIONS **-a**, **--attach**=*true*|*false* - When true attach to container's stdout/stderr and forward all signals to -the process + Attach container's STDOUT and STDERR and forward all signals to the process. The default is *false*. **-i**, **--interactive**=*true*|*false* - When true attach to container's stdin - -# NOTES -If run on a started container, start takes no action and succeeds -unconditionally. + Attach container's STDIN. The default is *false*. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-stop.1.md b/docs/man/docker-stop.1.md index 6ec81cd47..224a2a511 100644 --- a/docs/man/docker-stop.1.md +++ b/docs/man/docker-stop.1.md @@ -1,22 +1,23 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-stop - Stop a running container - grace period) +docker-stop - Stop a running container by sending SIGTERM and then SIGKILL after a grace period # SYNOPSIS -**docker stop** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...] +**docker stop** +[**-t**|**--time**[=*10*]] + CONTAINER [CONTAINER...] # DESCRIPTION Stop a running container (Send SIGTERM, and then SIGKILL after grace period) # OPTIONS -**-t**, **--time**=NUM - Wait NUM number of seconds for the container to stop before killing it. -The default is 10 seconds. +**-t**, **--time**=10 + Number of seconds to wait for the container to stop before killing it. Default is 10 seconds. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-tag.1.md b/docs/man/docker-tag.1.md index 01b5b9137..fda6eb673 100644 --- a/docs/man/docker-tag.1.md +++ b/docs/man/docker-tag.1.md @@ -1,12 +1,13 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-tag - Tag an image in the repository +docker-tag - Tag an image into a repository # SYNOPSIS -**docker tag** [**-f**|**--force**[=*false*] -IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG] +**docker tag** +[**-f**|**--force**[=*false*]] + IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG] # DESCRIPTION This will give a new alias to an image in the repository. This refers to the @@ -31,6 +32,10 @@ separated by a ':' recommended to be used for a version to disinguish images with the same name. Note that here TAG is a part of the overall name or "tag". +# OPTIONS +**-f**, **--force**=*true*|*false* + Force. The default is *false*. + # EXAMPLES ## Giving an image a new alias @@ -50,3 +55,4 @@ registry you must tag it with the registry hostname and port (if needed). # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-top.1.md b/docs/man/docker-top.1.md index 2c00c527a..0d55d77d5 100644 --- a/docs/man/docker-top.1.md +++ b/docs/man/docker-top.1.md @@ -1,18 +1,22 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME -docker-top - Lookup the running processes of a container +docker-top - Display the running processes of a container # SYNOPSIS -**docker top** CONTAINER [ps-OPTION] +**docker top** +CONTAINER [ps OPTIONS] # DESCRIPTION Look up the running process of the container. ps-OPTION can be any of the options you would pass to a Linux ps command. -# EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES Run **docker top** with the ps option of -x: @@ -24,4 +28,4 @@ Run **docker top** with the ps option of -x: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-unpause.1.md b/docs/man/docker-unpause.1.md new file mode 100644 index 000000000..8949548b6 --- /dev/null +++ b/docs/man/docker-unpause.1.md @@ -0,0 +1,15 @@ +% DOCKER(1) Docker User Manuals +% Docker Community +% JUNE 2014 +# NAME +docker-unpause - Unpause all processes within a container + +# SYNOPSIS +**docker unpause** +CONTAINER + +# OPTIONS +There are no available options. + +# HISTORY +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-version.1.md b/docs/man/docker-version.1.md new file mode 100644 index 000000000..9c029b239 --- /dev/null +++ b/docs/man/docker-version.1.md @@ -0,0 +1,15 @@ +% DOCKER(1) Docker User Manuals +% Docker Community +% JUNE 2014 +# NAME +docker-version - Show the Docker version information. + +# SYNOPSIS +**docker version** + + +# OPTIONS +There are no available options. + +# HISTORY +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-wait.1.md b/docs/man/docker-wait.1.md index 6754151f0..286bea042 100644 --- a/docs/man/docker-wait.1.md +++ b/docs/man/docker-wait.1.md @@ -1,16 +1,21 @@ % DOCKER(1) Docker User Manuals -% William Henry -% APRIL 2014 +% Docker Community +% JUNE 2014 # NAME docker-wait - Block until a container stops, then print its exit code. # SYNOPSIS -**docker wait** CONTAINER [CONTAINER...] +**docker wait** +CONTAINER [CONTAINER...] # DESCRIPTION + Block until a container stops, then print its exit code. -#EXAMPLE +# OPTIONS +There are no available options. + +# EXAMPLES $ sudo docker run -d fedora sleep 99 079b83f558a2bc52ecad6b2a5de13622d584e6bb1aea058c11b36511e85e7622 @@ -20,4 +25,4 @@ Block until a container stops, then print its exit code. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.io source material and internal work. - +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index ae5efff87..fe3929dca 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -127,6 +127,9 @@ inside it) **docker-logs(1)** Fetch the logs of a container +**docker-pause(1)** + Pause all processes within a container + **docker-port(1)** Lookup the public-facing port which is NAT-ed to PRIVATE_PORT @@ -169,7 +172,10 @@ inside it) **docker-top(1)** Lookup the running processes of a container -**version** +**docker-unpause(1)** + Unpause all processes within a container + +**docker-version(1)** Show the Docker version information **docker-wait(1)** diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index d7f972423..301593f2f 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -54,9 +54,9 @@ expect an integer, and they can only be specified once. -b, --bridge="" Attach containers to a pre-existing network bridge use 'none' to disable container networking --bip="" Use this CIDR notation address for the network bridge's IP, not compatible with -b - -d, --daemon=false Enable daemon mode -D, --debug=false Enable debug mode - --dns=[] Force docker to use specific DNS servers + -d, --daemon=false Enable daemon mode + --dns=[] Force Docker to use specific DNS servers --dns-search=[] Force Docker to use specific DNS search domains -e, --exec-driver="native" Force the Docker runtime to use a specific exec driver -G, --group="docker" Group to assign the unix socket specified by -H when running in daemon mode @@ -73,8 +73,8 @@ expect an integer, and they can only be specified once. -p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file -r, --restart=true Restart previously running containers -s, --storage-driver="" Force the Docker runtime to use a specific storage driver - --storage-opt=[] Set storage driver options --selinux-enabled=false Enable selinux support + --storage-opt=[] Set storage driver options --tls=false Use TLS; implied by tls-verify flags --tlscacert="/home/sven/.docker/ca.pem" Trust only remotes providing a certificate signed by the CA given here --tlscert="/home/sven/.docker/cert.pem" Path to TLS certificate file @@ -134,8 +134,8 @@ like this: Attach to a running container - --no-stdin=false Do not attach stdin - --sig-proxy=true Proxify received signals to the process (even in non-tty mode). SIGCHLD is not proxied. + --no-stdin=false Do not attach STDIN + --sig-proxy=true Proxify all received signals to the process (even in non-TTY mode). SIGCHLD is not proxied. The `attach` command will allow you to view or interact with any running container, detached (`-d`) @@ -481,7 +481,7 @@ To see how the `docker:latest` image was built: List images -a, --all=false Show all images (by default filter out the intermediate image layers) - -f, --filter=[]: Provide filter values (i.e. 'dangling=true') + -f, --filter=[] Provide filter values (i.e. 'dangling=true') --no-trunc=false Don't truncate output -q, --quiet=false Only show numeric IDs @@ -600,6 +600,8 @@ tar, then the ownerships might not get preserved. Usage: docker info + Display system-wide information + For example: $ sudo docker -D info @@ -627,7 +629,7 @@ ensure we know how your setup is configured. Usage: docker inspect CONTAINER|IMAGE [CONTAINER|IMAGE...] - Return low-level information on a container/image + Return low-level information on a container or image -f, --format="" Format the output using the given go template. @@ -681,7 +683,7 @@ contains complex json object, so to grab it as JSON, you use Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...] - Kill a running container (send SIGKILL, or specified signal) + Kill a running container using SIGKILL or a specified signal -s, --signal="KILL" Signal to send to the container @@ -718,7 +720,7 @@ Restores both images and tags. Usage: docker login [OPTIONS] [SERVER] - Register or Login to a docker registry server, if no server is specified "https://index.docker.io/v1/" is the default. + Register or log in to a Docker registry server, if no server is specified "https://index.docker.io/v1/" is the default. -e, --email="" Email -p, --password="" Password @@ -752,7 +754,7 @@ value is set to `all` in that case. This behavior may change in the future. Usage: docker port CONTAINER PRIVATE_PORT - Lookup the public-facing port which is NAT-ed to PRIVATE_PORT + Lookup the public-facing port that is NAT-ed to PRIVATE_PORT ## ps @@ -781,7 +783,7 @@ Running `docker ps` showing 2 linked containers. ## pull - Usage: docker pull [REGISTRY_PATH/]NAME[:TAG] + Usage: docker pull NAME[:TAG] Pull an image or a repository from the registry @@ -824,7 +826,7 @@ registry or to a self-hosted one. Restart a running container - -t, --time=10 Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10 + -t, --time=10 Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds. ## rm @@ -834,7 +836,7 @@ registry or to a self-hosted one. -f, --force=false Force removal of running container -l, --link=false Remove the specified link and not the underlying container - -v, --volumes=false Remove the volumes associated to the container + -v, --volumes=false Remove the volumes associated with the container ### Known Issues (rm) @@ -870,7 +872,7 @@ delete them. Any running containers will not be deleted. Remove one or more images - -f, --force=false Force + -f, --force=false Force removal of the image --no-prune=false Do not delete untagged parents ### Removing tagged images @@ -910,6 +912,7 @@ removed before the image is removed. -a, --attach=[] Attach to stdin, stdout or stderr. -c, --cpu-shares=0 CPU shares (relative weight) --cidfile="" Write the container ID to the file + --cpuset="" CPUs in which to allow execution (0-3, 0,1) -d, --detach=false Detached mode: Run container in the background, print new container id --dns=[] Set custom dns servers --dns-search=[] Set custom dns search domains @@ -927,11 +930,11 @@ removed before the image is removed. 'bridge': creates a new network stack for the container on the docker bridge 'none': no networking for this container 'container:': reuses another container network stack - 'host': use the host network stack inside the container + 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. + -P, --publish-all=false Publish all exposed ports to the host interfaces -p, --publish=[] Publish a container's port to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort (use 'docker port' to see the actual mapping) - -P, --publish-all=false Publish all exposed ports to the host interfaces --privileged=false Give extended privileges to this container --rm=false Automatically remove the container when it exits (incompatible with -d) --sig-proxy=true Proxify received signals to the process (even in non-tty mode). SIGCHLD is not proxied. @@ -1150,7 +1153,7 @@ application change: Usage: docker save IMAGE - Save an image to a tar archive (streamed to stdout by default) + Save an image to a tar archive (streamed to STDOUT by default) -o, --output="" Write to an file, instead of STDOUT @@ -1175,11 +1178,11 @@ Search [Docker Hub](https://hub.docker.com) for images Usage: docker search TERM - Search the docker index for images + Search the Docker Hub for images - --no-trunc=false Don't truncate output - -s, --stars=0 Only displays with at least xxx stars - --automated=false Only show automated builds + --automated=false Only show automated builds + --no-trunc=false Don't truncate output + -s, --stars=0 Only displays with at least x stars See [*Find Public Images on Docker Hub*]( /userguide/dockerrepos/#find-public-images-on-docker-hub) for @@ -1191,8 +1194,8 @@ more details on finding shared images from the command line. Restart a stopped container - -a, --attach=false Attach container's stdout/stderr and forward all signals to the process - -i, --interactive=false Attach container's stdin + -a, --attach=false Attach container's STDOUT and STDERR and forward all signals to the process + -i, --interactive=false Attach container's STDIN When run on a container that has already been started, takes no action and succeeds unconditionally. @@ -1201,9 +1204,9 @@ takes no action and succeeds unconditionally. Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] - Stop a running container (Send SIGTERM, and then SIGKILL after grace period) + Stop a running container by sending SIGTERM and then SIGKILL after a grace period - -t, --time=10 Number of seconds to wait for the container to stop before killing it. + -t, --time=10 Number of seconds to wait for the container to stop before killing it. Default is 10 seconds. The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL @@ -1224,13 +1227,13 @@ them to [*Share Images via Repositories*]( Usage: docker top CONTAINER [ps OPTIONS] - Lookup the running processes of a container + Display the running processes of a container ## version Usage: docker version - Show the docker version information. + Show the Docker version information. Show the Docker version, API version, Git commit, and Go version of both Docker client and daemon. @@ -1240,3 +1243,4 @@ both Docker client and daemon. Usage: docker wait CONTAINER [CONTAINER...] Block until a container stops, then print its exit code. + diff --git a/runconfig/parse.go b/runconfig/parse.go index 2f2ca9b16..dfd9f4ddd 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -72,7 +72,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf ) cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to stdin, stdout or stderr.") - cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)") + cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g., from the host: -v /host:/container, from docker: -v /container)") cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)") cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables") cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a line delimited file of ENV variables") From fa29b1f062d25c1a8ca62f02b9cc7533df4c7449 Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Wed, 2 Jul 2014 10:30:25 +1000 Subject: [PATCH 164/167] I'm going to wish I didn't do this Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- CONTRIBUTING.md | 4 ++-- README.md | 2 +- contrib/completion/zsh/_docker | 2 +- contrib/init/systemd/docker.service | 2 +- .../init/systemd/socket-activation/docker.service | 2 +- contrib/init/sysvinit-redhat/docker | 6 +++--- daemon/daemon.go | 2 +- docs/README.md | 8 ++++---- docs/man/Dockerfile.5.md | 2 +- docs/man/README.md | 2 +- docs/man/docker-attach.1.md | 2 +- docs/man/docker-build.1.md | 2 +- docs/man/docker-commit.1.md | 2 +- docs/man/docker-cp.1.md | 2 +- docs/man/docker-diff.1.md | 2 +- docs/man/docker-events.1.md | 2 +- docs/man/docker-export.1.md | 2 +- docs/man/docker-history.1.md | 2 +- docs/man/docker-images.1.md | 2 +- docs/man/docker-import.1.md | 2 +- docs/man/docker-info.1.md | 2 +- docs/man/docker-inspect.1.md | 2 +- docs/man/docker-kill.1.md | 2 +- docs/man/docker-load.1.md | 2 +- docs/man/docker-login.1.md | 2 +- docs/man/docker-logs.1.md | 2 +- docs/man/docker-port.1.md | 1 - docs/man/docker-ps.1.md | 2 +- docs/man/docker-pull.1.md | 5 +++++ docs/man/docker-push.1.md | 8 ++++++-- docs/man/docker-restart.1.md | 5 +++++ docs/man/docker-rm.1.md | 4 ++++ docs/man/docker-rmi.1.md | 4 ++++ docs/man/docker-run.1.md | 4 ++++ docs/man/docker-save.1.md | 5 +++++ docs/man/docker-search.1.md | 4 ++++ docs/man/docker-start.1.md | 4 ++++ docs/man/docker-stop.1.md | 4 ++++ docs/man/docker-tag.1.md | 4 ++++ docs/man/docker-top.1.md | 5 +++++ docs/man/docker-wait.1.md | 5 +++++ docs/man/docker.1.md | 2 +- docs/mkdocs.yml | 2 +- docs/release.sh | 2 +- docs/sources/articles/security.md | 4 ++-- docs/sources/articles/using_supervisord.md | 2 +- docs/sources/contributing/devenvironment.md | 2 +- docs/sources/examples/postgresql_service.Dockerfile | 2 +- docs/sources/examples/postgresql_service.md | 2 +- docs/sources/faq.md | 4 ++-- docs/sources/introduction/understanding-docker.md | 12 ++++++------ docs/sources/reference/run.md | 2 +- docs/sources/userguide/index.md | 8 ++++---- docs/sources/userguide/usingdocker.md | 2 +- docs/theme/mkdocs/css/main.css | 4 ++-- hack/dind | 2 +- hack/infrastructure/README.md | 13 ++++++------- hack/make/ubuntu | 4 ++-- 58 files changed, 126 insertions(+), 71 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f3df8619f..d07b972eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ This information will help us review and fix your issue faster. For instructions on setting up your development environment, please see our dedicated [dev environment setup -docs](http://docs.docker.io/en/latest/contributing/devenvironment/). +docs](http://docs.docker.com/contributing/devenvironment/). ## Contribution guidelines @@ -190,7 +190,7 @@ There are several exceptions to the signing requirement. Currently these are: * Your patch fixes Markdown formatting or syntax errors in the documentation contained in the `docs` directory. -If you have any questions, please refer to the FAQ in the [docs](http://docs.docker.io) +If you have any questions, please refer to the FAQ in the [docs](http://docs.docker.com) ### How can I become a maintainer? diff --git a/README.md b/README.md index 608e638ea..3c378de6f 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Docker can be used to run short-lived commands, long-running daemons (app servers, databases etc.), interactive shell sessions, etc. You can find a [list of real-world -examples](http://docs.docker.io/en/latest/examples/) in the +examples](http://docs.docker.com/examples/) in the documentation. Under the hood diff --git a/contrib/completion/zsh/_docker b/contrib/completion/zsh/_docker index 4578d1eda..3f96f00ef 100644 --- a/contrib/completion/zsh/_docker +++ b/contrib/completion/zsh/_docker @@ -1,6 +1,6 @@ #compdef docker # -# zsh completion for docker (http://docker.io) +# zsh completion for docker (http://docker.com) # # version: 0.2.2 # author: Felix Riedel diff --git a/contrib/init/systemd/docker.service b/contrib/init/systemd/docker.service index 1bc4d1f56..6f3cc33c3 100644 --- a/contrib/init/systemd/docker.service +++ b/contrib/init/systemd/docker.service @@ -1,6 +1,6 @@ [Unit] Description=Docker Application Container Engine -Documentation=http://docs.docker.io +Documentation=http://docs.docker.com After=network.target [Service] diff --git a/contrib/init/systemd/socket-activation/docker.service b/contrib/init/systemd/socket-activation/docker.service index a3382ab41..4af71378c 100644 --- a/contrib/init/systemd/socket-activation/docker.service +++ b/contrib/init/systemd/socket-activation/docker.service @@ -1,6 +1,6 @@ [Unit] Description=Docker Application Container Engine -Documentation=http://docs.docker.io +Documentation=http://docs.docker.com After=network.target [Service] diff --git a/contrib/init/sysvinit-redhat/docker b/contrib/init/sysvinit-redhat/docker index 06699f6ab..aa94c0481 100755 --- a/contrib/init/sysvinit-redhat/docker +++ b/contrib/init/sysvinit-redhat/docker @@ -2,10 +2,10 @@ # # /etc/rc.d/init.d/docker # -# Daemon for docker.io +# Daemon for docker.com # # chkconfig: 2345 95 95 -# description: Daemon for docker.io +# description: Daemon for docker.com ### BEGIN INIT INFO # Provides: docker @@ -16,7 +16,7 @@ # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop docker -# Description: Daemon for docker.io +# Description: Daemon for docker.com ### END INIT INFO # Source function library. diff --git a/daemon/daemon.go b/daemon/daemon.go index 9500526f9..23402d951 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -836,7 +836,7 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION)) sysInitPath := utils.DockerInitPath(localCopy) if sysInitPath == "" { - return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.io/en/latest/contributing/devenvironment for official build instructions.") + return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.com/contributing/devenvironment for official build instructions.") } if sysInitPath != localCopy { diff --git a/docs/README.md b/docs/README.md index 99dc8712c..17299401e 100755 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ The source for Docker documentation is here under `sources/` and uses extended Markdown, as implemented by [MkDocs](http://mkdocs.org). -The HTML files are built and hosted on `https://docs.docker.io`, and update +The HTML files are built and hosted on `https://docs.docker.com`, and update automatically after each change to the master or release branch of [Docker on GitHub](https://github.com/dotcloud/docker) thanks to post-commit hooks. The `docs` branch maps to the "latest" documentation and the `master` (unreleased @@ -21,14 +21,14 @@ In the rare case where your change is not forward-compatible, you may need to base your changes on the `docs` branch. Also, now that we have a `docs` branch, we can keep the -[http://docs.docker.io](http://docs.docker.io) docs up to date with any bugs +[http://docs.docker.com](http://docs.docker.com) docs up to date with any bugs found between Docker code releases. **Warning**: When *reading* the docs, the -[http://beta-docs.docker.io](http://beta-docs.docker.io) documentation may +[http://docs-stage.docker.com](http://docs-stage.docker.com) documentation may include features not yet part of any official Docker release. The `beta-docs` site should be used only for understanding bleeding-edge development and -`docs.docker.io` (which points to the `docs` branch`) should be used for the +`docs.docker.com` (which points to the `docs` branch`) should be used for the latest official release. ## Contributing diff --git a/docs/man/Dockerfile.5.md b/docs/man/Dockerfile.5.md index 73c1312b8..b0a863f65 100644 --- a/docs/man/Dockerfile.5.md +++ b/docs/man/Dockerfile.5.md @@ -203,4 +203,4 @@ or run later, during the next build stage. # HISTORY -*May 2014, Compiled by Zac Dover (zdover at redhat dot com) based on docker.io Dockerfile documentation. +*May 2014, Compiled by Zac Dover (zdover at redhat dot com) based on docker.com Dockerfile documentation. diff --git a/docs/man/README.md b/docs/man/README.md index d04d82454..45f1a91c0 100644 --- a/docs/man/README.md +++ b/docs/man/README.md @@ -68,4 +68,4 @@ The Pandoc Docker container will process the Markdown files and generate the man pages inside the `docker/docs/man/man1` directory using Docker volumes. For more information on Docker volumes see the man page for `docker run` and also look at the article [Sharing Directories via Volumes] -(http://docs.docker.io/use/working_with_volumes/). +(http://docs.docker.com/use/working_with_volumes/). diff --git a/docs/man/docker-attach.1.md b/docs/man/docker-attach.1.md index 0ca979701..1b4e68b65 100644 --- a/docs/man/docker-attach.1.md +++ b/docs/man/docker-attach.1.md @@ -57,5 +57,5 @@ attach** command: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-build.1.md b/docs/man/docker-build.1.md index 2b426f1ce..c562660b6 100644 --- a/docs/man/docker-build.1.md +++ b/docs/man/docker-build.1.md @@ -117,5 +117,5 @@ Note: You can set an arbitrary Git repository via the `git://` schema. # HISTORY March 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index 5ec3808df..bbd1db21b 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -35,5 +35,5 @@ create a new image run docker ps to find the container's ID and then run: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and in +based on docker.com source material and in June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-cp.1.md b/docs/man/docker-cp.1.md index 750a6d1d5..dc8f295bb 100644 --- a/docs/man/docker-cp.1.md +++ b/docs/man/docker-cp.1.md @@ -24,5 +24,5 @@ the exited container to the current dir on the host: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-diff.1.md b/docs/man/docker-diff.1.md index d7aae25f8..acf0911b0 100644 --- a/docs/man/docker-diff.1.md +++ b/docs/man/docker-diff.1.md @@ -43,5 +43,5 @@ Inspect the changes to on a nginx container: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-events.1.md b/docs/man/docker-events.1.md index ca8f63db5..8fa85871a 100644 --- a/docs/man/docker-events.1.md +++ b/docs/man/docker-events.1.md @@ -49,5 +49,5 @@ Again the output container IDs have been shortened for the purposes of this docu # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-export.1.md b/docs/man/docker-export.1.md index efd884a79..8fd7834a1 100644 --- a/docs/man/docker-export.1.md +++ b/docs/man/docker-export.1.md @@ -26,5 +26,5 @@ called test.tar: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-history.1.md b/docs/man/docker-history.1.md index ee58e03fc..ddb164e50 100644 --- a/docs/man/docker-history.1.md +++ b/docs/man/docker-history.1.md @@ -30,5 +30,5 @@ Show the history of when and how an image was created. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-images.1.md b/docs/man/docker-images.1.md index a940192e9..c572ee674 100644 --- a/docs/man/docker-images.1.md +++ b/docs/man/docker-images.1.md @@ -86,5 +86,5 @@ tools. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-import.1.md b/docs/man/docker-import.1.md index f320eafa2..2d67b8bc7 100644 --- a/docs/man/docker-import.1.md +++ b/docs/man/docker-import.1.md @@ -39,5 +39,5 @@ Import to docker via pipe and stdin: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-info.1.md b/docs/man/docker-info.1.md index cae9a3290..2945d61df 100644 --- a/docs/man/docker-info.1.md +++ b/docs/man/docker-info.1.md @@ -44,5 +44,5 @@ Here is a sample output: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-inspect.1.md b/docs/man/docker-inspect.1.md index 29511fbe6..a52d57c97 100644 --- a/docs/man/docker-inspect.1.md +++ b/docs/man/docker-inspect.1.md @@ -225,5 +225,5 @@ Use an image's ID or name (e.g., repository/name[:tag]) to get information # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-kill.1.md b/docs/man/docker-kill.1.md index a454c432f..3c8d59e6d 100644 --- a/docs/man/docker-kill.1.md +++ b/docs/man/docker-kill.1.md @@ -20,5 +20,5 @@ The main process inside each container specified will be sent SIGKILL, # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) - based on docker.io source material and internal work. + based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-load.1.md b/docs/man/docker-load.1.md index 41ab5f64c..07dac4613 100644 --- a/docs/man/docker-load.1.md +++ b/docs/man/docker-load.1.md @@ -34,5 +34,5 @@ Restores both images and tags. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-login.1.md b/docs/man/docker-login.1.md index 658334265..c26935307 100644 --- a/docs/man/docker-login.1.md +++ b/docs/man/docker-login.1.md @@ -34,5 +34,5 @@ login to a private registry you can specify this by adding the server name. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-logs.1.md b/docs/man/docker-logs.1.md index 5881b0512..5c3df75b9 100644 --- a/docs/man/docker-logs.1.md +++ b/docs/man/docker-logs.1.md @@ -29,5 +29,5 @@ then continue streaming new output from the container’s stdout and stderr. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-port.1.md b/docs/man/docker-port.1.md index a92f75cd5..07b84b12d 100644 --- a/docs/man/docker-port.1.md +++ b/docs/man/docker-port.1.md @@ -13,5 +13,4 @@ There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-ps.1.md b/docs/man/docker-ps.1.md index 454be74ad..9264d53a6 100644 --- a/docs/man/docker-ps.1.md +++ b/docs/man/docker-ps.1.md @@ -66,5 +66,5 @@ the running containers. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -based on docker.io source material and internal work. +based on docker.com source material and internal work. June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-pull.1.md b/docs/man/docker-pull.1.md index c397b42ea..6fb0dc100 100644 --- a/docs/man/docker-pull.1.md +++ b/docs/man/docker-pull.1.md @@ -51,5 +51,10 @@ There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. + +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-push.1.md b/docs/man/docker-push.1.md index 4b05b62a7..56d814181 100644 --- a/docs/man/docker-push.1.md +++ b/docs/man/docker-push.1.md @@ -10,7 +10,7 @@ NAME[:TAG] # DESCRIPTION Push an image or a repository to a registry. The default registry is the Docker -Index located at [index.docker.io](https://index.docker.io/v1/). However the +Hub located at [hub.docker.com](https://hub.docker.com/). However the image can be pushed to another, perhaps private, registry as demonstrated in the example below. @@ -28,7 +28,7 @@ and then committing it to a new image name: Now push the image to the registry using the image ID. In this example the registry is on host named registry-host and listening on port 5000. -Default Docker commands will push to the default `index.docker.io` +Default Docker commands will push to the default `hub.docker.com` registry. Instead, push to the local registry, which is on a host called registry-host*. To do this, tag the image with the host name or IP address, and the port of the registry: @@ -45,5 +45,9 @@ listed. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-restart.1.md b/docs/man/docker-restart.1.md index 6374273cf..6f93858ba 100644 --- a/docs/man/docker-restart.1.md +++ b/docs/man/docker-restart.1.md @@ -18,5 +18,10 @@ Restart each container listed. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. + +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-rm.1.md b/docs/man/docker-rm.1.md index f41a6edb1..9195137ec 100644 --- a/docs/man/docker-rm.1.md +++ b/docs/man/docker-rm.1.md @@ -47,5 +47,9 @@ command. The use that name as follows: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-rmi.1.md b/docs/man/docker-rmi.1.md index e03ecc4bc..7a2973f87 100644 --- a/docs/man/docker-rmi.1.md +++ b/docs/man/docker-rmi.1.md @@ -34,5 +34,9 @@ Here is an example of removing and image: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index 1e1adbe55..fa73d8eee 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -369,5 +369,9 @@ changes will also be reflected on the host in /var/db. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-save.1.md b/docs/man/docker-save.1.md index a6546a044..403c3fb61 100644 --- a/docs/man/docker-save.1.md +++ b/docs/man/docker-save.1.md @@ -33,5 +33,10 @@ fedora image to a fedora-latest.tar: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. + +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-search.1.md b/docs/man/docker-search.1.md index e3103c65a..061042c7a 100644 --- a/docs/man/docker-search.1.md +++ b/docs/man/docker-search.1.md @@ -54,5 +54,9 @@ ranked 1 or higher: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-start.1.md b/docs/man/docker-start.1.md index a01e190b6..ed9f77b43 100644 --- a/docs/man/docker-start.1.md +++ b/docs/man/docker-start.1.md @@ -23,5 +23,9 @@ Start a stopped container. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-stop.1.md b/docs/man/docker-stop.1.md index 224a2a511..14bd7b30e 100644 --- a/docs/man/docker-stop.1.md +++ b/docs/man/docker-stop.1.md @@ -19,5 +19,9 @@ Stop a running container (Send SIGTERM, and then SIGKILL after # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-tag.1.md b/docs/man/docker-tag.1.md index fda6eb673..aae222085 100644 --- a/docs/man/docker-tag.1.md +++ b/docs/man/docker-tag.1.md @@ -54,5 +54,9 @@ registry you must tag it with the registry hostname and port (if needed). # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-top.1.md b/docs/man/docker-top.1.md index 0d55d77d5..5ba44d697 100644 --- a/docs/man/docker-top.1.md +++ b/docs/man/docker-top.1.md @@ -27,5 +27,10 @@ Run **docker top** with the ps option of -x: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. + +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker-wait.1.md b/docs/man/docker-wait.1.md index 286bea042..cfa19ef86 100644 --- a/docs/man/docker-wait.1.md +++ b/docs/man/docker-wait.1.md @@ -24,5 +24,10 @@ There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) +<<<<<<< HEAD based on docker.io source material and internal work. June 2014, updated by Sven Dowideit +======= +based on docker.com source material and internal work. + +>>>>>>> 834ef8a... I'm going to wish I didn't do this diff --git a/docs/man/docker.1.md b/docs/man/docker.1.md index fe3929dca..a7a826ed9 100644 --- a/docs/man/docker.1.md +++ b/docs/man/docker.1.md @@ -190,4 +190,4 @@ For example: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based - on docker.io source material and internal work. + on docker.com source material and internal work. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 97dc8fc36..f4ebcb68f 100755 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,5 +1,5 @@ site_name: Docker Documentation -#site_url: http://docs.docker.io/ +#site_url: http://docs.docker.com/ site_url: / site_description: Documentation for fast and lightweight Docker container based virtualization framework. site_favicon: img/favicon.png diff --git a/docs/release.sh b/docs/release.sh index d579a307b..f6dc2ec59 100755 --- a/docs/release.sh +++ b/docs/release.sh @@ -9,7 +9,7 @@ To publish the Docker documentation you need to set your access_key and secret_k (with the keys in a [profile $AWS_S3_BUCKET] section - so you can have more than one set of keys in your file) and set the AWS_S3_BUCKET env var to the name of your bucket. -make AWS_S3_BUCKET=beta-docs.docker.io docs-release +make AWS_S3_BUCKET=docs-stage.docker.com docs-release will then push the documentation site to your s3 bucket. EOF diff --git a/docs/sources/articles/security.md b/docs/sources/articles/security.md index 4c39c18a6..dcc61f386 100644 --- a/docs/sources/articles/security.md +++ b/docs/sources/articles/security.md @@ -5,7 +5,7 @@ page_keywords: Docker, Docker documentation, security # Docker Security > *Adapted from* [Containers & Docker: How Secure are -> They?](http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/) +> They?](http://blog.docker.com/2013/08/containers-docker-how-secure-are-they/) There are three major areas to consider when reviewing Docker security: @@ -251,4 +251,4 @@ with Docker, since everything is provided by the kernel anyway. For more context and especially for comparisons with VMs and other container systems, please also see the [original blog post]( -http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/). +http://blog.docker.com/2013/08/containers-docker-how-secure-are-they/). diff --git a/docs/sources/articles/using_supervisord.md b/docs/sources/articles/using_supervisord.md index fd7c07cab..91b8976d7 100644 --- a/docs/sources/articles/using_supervisord.md +++ b/docs/sources/articles/using_supervisord.md @@ -27,7 +27,7 @@ Let's start by creating a basic `Dockerfile` for our new image. FROM ubuntu:13.04 - MAINTAINER examples@docker.io + MAINTAINER examples@docker.com RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list RUN apt-get update RUN apt-get upgrade -y diff --git a/docs/sources/contributing/devenvironment.md b/docs/sources/contributing/devenvironment.md index 9188031e3..606f9302f 100644 --- a/docs/sources/contributing/devenvironment.md +++ b/docs/sources/contributing/devenvironment.md @@ -16,7 +16,7 @@ Docker's build environment itself is a Docker container, so the first step is to install Docker on your system. You can follow the [install instructions most relevant to your -system](https://docs.docker.io/installation/). Make sure you +system](https://docs.docker.com/installation/). Make sure you have a working, up-to-date docker installation, then continue to the next step. diff --git a/docs/sources/examples/postgresql_service.Dockerfile b/docs/sources/examples/postgresql_service.Dockerfile index 219a53788..364a18a81 100644 --- a/docs/sources/examples/postgresql_service.Dockerfile +++ b/docs/sources/examples/postgresql_service.Dockerfile @@ -1,5 +1,5 @@ # -# example Dockerfile for http://docs.docker.io/en/latest/examples/postgresql_service/ +# example Dockerfile for http://docs.docker.com/examples/postgresql_service/ # FROM ubuntu diff --git a/docs/sources/examples/postgresql_service.md b/docs/sources/examples/postgresql_service.md index b9fae49d9..5265935e3 100644 --- a/docs/sources/examples/postgresql_service.md +++ b/docs/sources/examples/postgresql_service.md @@ -21,7 +21,7 @@ Start by creating a new `Dockerfile`: > suitably secure. # - # example Dockerfile for http://docs.docker.io/examples/postgresql_service/ + # example Dockerfile for http://docs.docker.com/examples/postgresql_service/ # FROM ubuntu diff --git a/docs/sources/faq.md b/docs/sources/faq.md index 635caac89..667058c86 100644 --- a/docs/sources/faq.md +++ b/docs/sources/faq.md @@ -178,13 +178,13 @@ Cloud: ### How do I report a security issue with Docker? You can learn about the project's security policy -[here](https://www.docker.io/security/) and report security issues to +[here](https://www.docker.com/security/) and report security issues to this [mailbox](mailto:security@docker.com). ### Why do I need to sign my commits to Docker with the DCO? Please read [our blog post]( -http://blog.docker.io/2014/01/docker-code-contributions-require-developer-certificate-of-origin/) +http://blog.docker.com/2014/01/docker-code-contributions-require-developer-certificate-of-origin/) on the introduction of the DCO. ### When building an image, should I prefer system libraries or bundled ones? diff --git a/docs/sources/introduction/understanding-docker.md b/docs/sources/introduction/understanding-docker.md index 3a7615ebc..c79573a63 100644 --- a/docs/sources/introduction/understanding-docker.md +++ b/docs/sources/introduction/understanding-docker.md @@ -112,7 +112,7 @@ Docker images are the **build** component of Docker. #### Docker Registries Docker registries hold images. These are public or private stores from which you upload or download images. The public Docker registry is called -[Docker Hub](http://index.docker.io). It provides a huge collection of existing +[Docker Hub](http://hub.docker.com). It provides a huge collection of existing images for your use. These can be images you create yourself or you can use images that others have previously created. Docker registries are the **distribution** component of Docker. @@ -156,7 +156,7 @@ basis for a new image, for example if you have a base Apache image you could use this as the base of all your web application images. > **Note:** Docker usually gets these base images from -> [Docker Hub](https://index.docker.io). +> [Docker Hub](https://hub.docker.com). > Docker images are then built from these base images using a simple, descriptive set of steps we call *instructions*. Each instruction creates a new layer in our @@ -173,17 +173,17 @@ returns a final image. ### How does a Docker registry work? The Docker registry is the store for your Docker images. Once you build a Docker -image you can *push* it to a public registry [Docker Hub](https://index.docker.io) or to +image you can *push* it to a public registry [Docker Hub](https://hub.docker.com) or to your own registry running behind your firewall. Using the Docker client, you can search for already published images and then pull them down to your Docker host to build containers from them. -[Docker Hub](https://index.docker.io) provides both public and private storage +[Docker Hub](https://hub.docker.com) provides both public and private storage for images. Public storage is searchable and can be downloaded by anyone. Private storage is excluded from search results and only you and your users can pull images down and use them to build containers. You can [sign up for a storage plan -here](https://index.docker.io/plans). +here](https://hub.docker.com/plans). ### How does a container work? A container consists of an operating system, user-added files, and meta-data. As @@ -216,7 +216,7 @@ In order, Docker does the following: - **Pulls the `ubuntu` image:** Docker checks for the presence of the `ubuntu` image and, if it doesn't exist locally on the host, then Docker downloads it from -[Docker Hub](https://index.docker.io). If the image already exists, then Docker +[Docker Hub](https://hub.docker.com). If the image already exists, then Docker uses it for the new container. - **Creates a new container:** Once Docker has the image, it uses it to create a container. diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 37dba587b..a539ab0d1 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -240,7 +240,7 @@ to access to all devices on the host as well as set some configuration in AppArmor to allow the container nearly all the same access to the host as processes running outside containers on the host. Additional information about running with `--privileged` is available on the -[Docker Blog](http://blog.docker.io/2013/09/docker-can-now-run-within-docker/). +[Docker Blog](http://blog.docker.com/2013/09/docker-can-now-run-within-docker/). If the Docker daemon was started using the `lxc` exec-driver (`docker -d --exec-driver=lxc`) then the operator can also specify LXC options diff --git a/docs/sources/userguide/index.md b/docs/sources/userguide/index.md index e5c9ec272..eef59c000 100644 --- a/docs/sources/userguide/index.md +++ b/docs/sources/userguide/index.md @@ -82,11 +82,11 @@ Go to [Working with Docker Hub](/userguide/dockerrepos). ## Getting help -* [Docker homepage](http://www.docker.io/) +* [Docker homepage](http://www.docker.com/) * [Docker Hub](https://hub.docker.com) -* [Docker blog](http://blog.docker.io/) -* [Docker documentation](http://docs.docker.io/) -* [Docker Getting Started Guide](http://www.docker.io/gettingstarted/) +* [Docker blog](http://blog.docker.com/) +* [Docker documentation](http://docs.docker.com/) +* [Docker Getting Started Guide](http://www.docker.com/gettingstarted/) * [Docker code on GitHub](https://github.com/dotcloud/docker) * [Docker mailing list](https://groups.google.com/forum/#!forum/docker-user) diff --git a/docs/sources/userguide/usingdocker.md b/docs/sources/userguide/usingdocker.md index 7080e3ed4..857eac5e5 100644 --- a/docs/sources/userguide/usingdocker.md +++ b/docs/sources/userguide/usingdocker.md @@ -19,7 +19,7 @@ In the process we learned about several Docker commands: > **Tip:** > Another way to learn about `docker` commands is our -> [interactive tutorial](https://www.docker.io/gettingstarted). +> [interactive tutorial](https://www.docker.com/tryit/). The `docker` client is pretty simple. Each action you can take with Docker is a command and each command can take a series of diff --git a/docs/theme/mkdocs/css/main.css b/docs/theme/mkdocs/css/main.css index 42a7a18a5..18e65ebd3 100644 --- a/docs/theme/mkdocs/css/main.css +++ b/docs/theme/mkdocs/css/main.css @@ -4,7 +4,7 @@ Core Docker style file used on - www.docker.io + www.docker.com docker-index ****************************** */ /* this is about 10% darker, but slightly different */ @@ -2146,4 +2146,4 @@ a:hover { background: url("../img/homepage/docker-whale-home-logo+@2x.png"); background-size: 459px 261px; } -} \ No newline at end of file +} diff --git a/hack/dind b/hack/dind index a9de03e4f..77629ad0a 100755 --- a/hack/dind +++ b/hack/dind @@ -3,7 +3,7 @@ set -e # DinD: a wrapper script which allows docker to be run inside a docker container. # Original version by Jerome Petazzoni -# See the blog post: http://blog.docker.io/2013/09/docker-can-now-run-within-docker/ +# See the blog post: http://blog.docker.com/2013/09/docker-can-now-run-within-docker/ # # This script should be executed inside a docker container in privilieged mode # ('docker run --privileged', introduced in docker 0.6). diff --git a/hack/infrastructure/README.md b/hack/infrastructure/README.md index 9b2ffda95..d12fc4c63 100644 --- a/hack/infrastructure/README.md +++ b/hack/infrastructure/README.md @@ -20,7 +20,7 @@ AWS | packages (S3 bucket), dotCloud PAAS, dev-env, ci CloudFlare | cdn Digital Ocean | ci dotCloud PAAS | website, index, registry, ssl, blog -DynECT | dns (docker.io) +DynECT | dns (docker.com) GitHub | repository Linode | stackbrew Mailgun | outgoing e-mail @@ -36,20 +36,19 @@ and which service is handling them. URL | Service ---------------------------------------------|--------------------------------- - http://blog.docker.io/ | blog + http://blog.docker.com/ | blog *http://cdn-registry-1.docker.io/ | registry (pull) http://debug.docker.io/ | debug tool - http://docs.docker.io/ | docsproxy (proxy to readthedocs) + http://docs.docker.com/ | documentation served from an S3 bucket http://docker-ci.dotcloud.com/ | ci - http://docker.io/ | redirect to www.docker.io (dynect) - http://docker.readthedocs.org/ | docs + http://docker.com/ | redirect to www.docker.com (dynect) *http://get.docker.io/ | packages https://github.com/dotcloud/docker | repository -*https://index.docker.io/ | index +*https://hub.docker.com/ | Docker Hub http://registry-1.docker.io/ | registry (push) http://staging-docker-ci.dotcloud.com/ | ci *http://test.docker.io/ | packages -*http://www.docker.io/ | website +*http://www.docker.com/ | website http://? (internal URL, not for public use) | stackbrew *Ordered-by: lexicographic* diff --git a/hack/make/ubuntu b/hack/make/ubuntu index c55123fb7..0d19d7528 100644 --- a/hack/make/ubuntu +++ b/hack/make/ubuntu @@ -8,8 +8,8 @@ if [ -n "$(git status --porcelain)" ]; then fi PACKAGE_ARCHITECTURE="$(dpkg-architecture -qDEB_HOST_ARCH)" -PACKAGE_URL="http://www.docker.io/" -PACKAGE_MAINTAINER="docker@dotcloud.com" +PACKAGE_URL="http://www.docker.com/" +PACKAGE_MAINTAINER="support@docker.com" PACKAGE_DESCRIPTION="Linux container runtime Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and From c3f4972f6d036520df589676c7ebeef397d327c2 Mon Sep 17 00:00:00 2001 From: Fred Lifton Date: Wed, 2 Jul 2014 17:41:52 -0700 Subject: [PATCH 165/167] Corrected version number to 3 digits. Docker-DCO-1.1-Signed-off-by: Fred Lifton (github: fredlf) --- docs/sources/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 3ff9c8dde..75414b436 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -87,7 +87,7 @@ To learn about Docker in more detail and to answer questions about usage and imp ## Release Notes -Version 1.1 +Version 1.1.0 ### New Features From f8d9ecfb2ceda0cc2aed3d8fd3fbcbf625a8fcdd Mon Sep 17 00:00:00 2001 From: SvenDowideit Date: Thu, 3 Jul 2014 11:07:42 +1000 Subject: [PATCH 166/167] missed these merge conflicts when manually rebasing too many files Docker-DCO-1.1-Signed-off-by: SvenDowideit (github: SvenDowideit) --- docs/man/docker-pull.1.md | 7 +------ docs/man/docker-push.1.md | 6 +----- docs/man/docker-restart.1.md | 7 +------ docs/man/docker-rm.1.md | 6 +----- docs/man/docker-rmi.1.md | 6 +----- docs/man/docker-run.1.md | 6 +----- docs/man/docker-save.1.md | 7 +------ docs/man/docker-search.1.md | 6 +----- docs/man/docker-start.1.md | 6 +----- docs/man/docker-stop.1.md | 6 +----- docs/man/docker-tag.1.md | 6 +----- docs/man/docker-top.1.md | 7 +------ docs/man/docker-wait.1.md | 7 +------ 13 files changed, 13 insertions(+), 70 deletions(-) diff --git a/docs/man/docker-pull.1.md b/docs/man/docker-pull.1.md index 6fb0dc100..465c97aad 100644 --- a/docs/man/docker-pull.1.md +++ b/docs/man/docker-pull.1.md @@ -51,10 +51,5 @@ There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. - ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-push.1.md b/docs/man/docker-push.1.md index 56d814181..8523cb539 100644 --- a/docs/man/docker-push.1.md +++ b/docs/man/docker-push.1.md @@ -45,9 +45,5 @@ listed. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-restart.1.md b/docs/man/docker-restart.1.md index 6f93858ba..2a08caa5e 100644 --- a/docs/man/docker-restart.1.md +++ b/docs/man/docker-restart.1.md @@ -18,10 +18,5 @@ Restart each container listed. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. - ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-rm.1.md b/docs/man/docker-rm.1.md index 9195137ec..1b4537697 100644 --- a/docs/man/docker-rm.1.md +++ b/docs/man/docker-rm.1.md @@ -47,9 +47,5 @@ command. The use that name as follows: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-rmi.1.md b/docs/man/docker-rmi.1.md index 7a2973f87..08d740a3b 100644 --- a/docs/man/docker-rmi.1.md +++ b/docs/man/docker-rmi.1.md @@ -34,9 +34,5 @@ Here is an example of removing and image: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index fa73d8eee..e7571ac21 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -369,9 +369,5 @@ changes will also be reflected on the host in /var/db. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-save.1.md b/docs/man/docker-save.1.md index 403c3fb61..533b4c843 100644 --- a/docs/man/docker-save.1.md +++ b/docs/man/docker-save.1.md @@ -33,10 +33,5 @@ fedora image to a fedora-latest.tar: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. - ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-search.1.md b/docs/man/docker-search.1.md index 061042c7a..3937b870a 100644 --- a/docs/man/docker-search.1.md +++ b/docs/man/docker-search.1.md @@ -54,9 +54,5 @@ ranked 1 or higher: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-start.1.md b/docs/man/docker-start.1.md index ed9f77b43..e23fd70ab 100644 --- a/docs/man/docker-start.1.md +++ b/docs/man/docker-start.1.md @@ -23,9 +23,5 @@ Start a stopped container. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-stop.1.md b/docs/man/docker-stop.1.md index 14bd7b30e..0cc19918c 100644 --- a/docs/man/docker-stop.1.md +++ b/docs/man/docker-stop.1.md @@ -19,9 +19,5 @@ Stop a running container (Send SIGTERM, and then SIGKILL after # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-tag.1.md b/docs/man/docker-tag.1.md index aae222085..041c9e1cb 100644 --- a/docs/man/docker-tag.1.md +++ b/docs/man/docker-tag.1.md @@ -54,9 +54,5 @@ registry you must tag it with the registry hostname and port (if needed). # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-top.1.md b/docs/man/docker-top.1.md index 5ba44d697..9781739cd 100644 --- a/docs/man/docker-top.1.md +++ b/docs/man/docker-top.1.md @@ -27,10 +27,5 @@ Run **docker top** with the ps option of -x: # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. - ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit diff --git a/docs/man/docker-wait.1.md b/docs/man/docker-wait.1.md index cfa19ef86..798f6d652 100644 --- a/docs/man/docker-wait.1.md +++ b/docs/man/docker-wait.1.md @@ -24,10 +24,5 @@ There are no available options. # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) -<<<<<<< HEAD -based on docker.io source material and internal work. -June 2014, updated by Sven Dowideit -======= based on docker.com source material and internal work. - ->>>>>>> 834ef8a... I'm going to wish I didn't do this +June 2014, updated by Sven Dowideit From 79812e36468c6e9be19b7c028e37787d5ae6288b Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 3 Jul 2014 01:15:11 +0000 Subject: [PATCH 167/167] Bump version to v1.1.0 Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- CHANGELOG.md | 24 ++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a7d3c2e1..e55cb0c75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 1.1.0 (2014-07-03) + +#### Notable features since 1.0.1 ++ Add `.dockerignore` support ++ Pause containers during `docker commit` ++ Add `--tail` to `docker logs` + +#### Builder ++ Allow a tar file as context for `docker build` +* Fix issue with white-spaces and multi-lines in `Dockerfiles` + +#### Runtime +* Overall performance improvements +* Allow `/` as source of `docker run -v` +* Fix port allocation +* Fix bug in `docker save` +* Add links information to `docker inspect` + +#### Client +* Improve command line parsing for `docker commit` + +#### Remote API +* Improve status code for the `start` and `stop` endpoints + ## 1.0.1 (2014-06-19) #### Notable features since 1.0.0 diff --git a/VERSION b/VERSION index 3f60217db..9084fa2f7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1-dev +1.1.0