Browse code

Merge master within fs

creack authored on 2013/03/13 00:33:21
Showing 9 changed files
... ...
@@ -7,11 +7,11 @@ Vagrant::Config.run do |config|
7 7
   # please see the online documentation at vagrantup.com.
8 8
 
9 9
   # Every Vagrant virtual environment requires a box to build off of.
10
-  config.vm.box = "quantal64"
10
+  config.vm.box = "quantal64_3.5.0-25"
11 11
 
12 12
   # The url from where the 'config.vm.box' box will be fetched if it
13 13
   # doesn't already exist on the user's system.
14
-  config.vm.box_url = "http://unworkable.org/~niallo/quantal64.box"
14
+  config.vm.box_url = "http://get.docker.io/vbox/ubuntu/12.10/quantal64_3.5.0-25.box"
15 15
 
16 16
   # Boot with a GUI so you can see the screen. (Default is headless)
17 17
   # config.vm.boot_mode = :gui
... ...
@@ -111,6 +111,7 @@ func InteractiveMode(scripts ...string) error {
111 111
 	if err != nil {
112 112
 		return err
113 113
 	}
114
+	defer os.Remove(rcfile.Name())
114 115
 	io.WriteString(rcfile, "enable -n help\n")
115 116
 	os.Setenv("PATH", tmp+":"+os.Getenv("PATH"))
116 117
 	os.Setenv("PS1", "\\h docker> ")
... ...
@@ -53,12 +53,13 @@ type Container struct {
53 53
 }
54 54
 
55 55
 type Config struct {
56
-	Hostname  string
57
-	User      string
58
-	Ram       int64
59
-	Ports     []int
60
-	Tty       bool // Attach standard streams to a tty, including stdin if it is not closed.
61
-	OpenStdin bool // Open stdin
56
+	Hostname   string
57
+	User       string
58
+	Memory     int64 // Memory limit (in bytes)
59
+	MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
60
+	Ports      []int
61
+	Tty        bool // Attach standard streams to a tty, including stdin if it is not closed.
62
+	OpenStdin  bool // Open stdin
62 63
 }
63 64
 
64 65
 type NetworkSettings struct {
... ...
@@ -2,9 +2,12 @@ package docker
2 2
 
3 3
 import (
4 4
 	"./fs"
5
+	"bufio"
5 6
 	"fmt"
6 7
 	"io"
7 8
 	"io/ioutil"
9
+	"math/rand"
10
+	"os"
8 11
 	"sort"
9 12
 	"strings"
10 13
 	"testing"
... ...
@@ -23,7 +26,7 @@ func TestCommitRun(t *testing.T) {
23 23
 		[]string{"-c", "echo hello > /world"},
24 24
 		GetTestImage(docker),
25 25
 		&Config{
26
-			Ram: 33554432,
26
+			Memory: 33554432,
27 27
 		},
28 28
 	)
29 29
 	if err != nil {
... ...
@@ -65,7 +68,7 @@ func TestCommitRun(t *testing.T) {
65 65
 		[]string{"/world"},
66 66
 		img,
67 67
 		&Config{
68
-			Ram: 33554432,
68
+			Memory: 33554432,
69 69
 		},
70 70
 	)
71 71
 	if err != nil {
... ...
@@ -100,7 +103,7 @@ func TestRun(t *testing.T) {
100 100
 		[]string{"-al"},
101 101
 		GetTestImage(docker),
102 102
 		&Config{
103
-			Ram: 33554432,
103
+			Memory: 33554432,
104 104
 		},
105 105
 	)
106 106
 	if err != nil {
... ...
@@ -349,7 +352,7 @@ func TestUser(t *testing.T) {
349 349
 	// Set a username
350 350
 	container, err = docker.Create(
351 351
 		"user_root",
352
-		"/bin/id",
352
+		"id",
353 353
 		[]string{},
354 354
 		GetTestImage(docker),
355 355
 		&Config{
... ...
@@ -393,7 +396,7 @@ func TestUser(t *testing.T) {
393 393
 	// Set a different user by uid
394 394
 	container, err = docker.Create(
395 395
 		"user_uid1",
396
-		"/usr/bin/id",
396
+		"id",
397 397
 		[]string{},
398 398
 		GetTestImage(docker),
399 399
 		&Config{
... ...
@@ -417,7 +420,7 @@ func TestUser(t *testing.T) {
417 417
 	// Set a different user by username
418 418
 	container, err = docker.Create(
419 419
 		"user_daemon",
420
-		"/usr/bin/id",
420
+		"id",
421 421
 		[]string{},
422 422
 		GetTestImage(docker),
423 423
 		&Config{
... ...
@@ -616,6 +619,59 @@ func TestEnv(t *testing.T) {
616 616
 	}
617 617
 }
618 618
 
619
+func grepFile(t *testing.T, path string, pattern string) {
620
+	f, err := os.Open(path)
621
+	if err != nil {
622
+		t.Fatal(err)
623
+	}
624
+	defer f.Close()
625
+	r := bufio.NewReader(f)
626
+	var (
627
+		line string
628
+	)
629
+	err = nil
630
+	for err == nil {
631
+		line, err = r.ReadString('\n')
632
+		if strings.Contains(line, pattern) == true {
633
+			return
634
+		}
635
+	}
636
+	t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
637
+}
638
+
639
+func TestLXCConfig(t *testing.T) {
640
+	docker, err := newTestDocker()
641
+	if err != nil {
642
+		t.Fatal(err)
643
+	}
644
+	defer nuke(docker)
645
+	// Memory is allocated randomly for testing
646
+	rand.Seed(time.Now().UTC().UnixNano())
647
+	memMin := 33554432
648
+	memMax := 536870912
649
+	mem := memMin + rand.Intn(memMax-memMin)
650
+	container, err := docker.Create(
651
+		"config_test",
652
+		"/bin/true",
653
+		[]string{},
654
+		GetTestImage(docker),
655
+		&Config{
656
+			Hostname: "foobar",
657
+			Memory:   int64(mem),
658
+		},
659
+	)
660
+	if err != nil {
661
+		t.Fatal(err)
662
+	}
663
+	defer docker.Destroy(container)
664
+	container.generateLXCConfig()
665
+	grepFile(t, container.lxcConfigPath, "lxc.utsname = foobar")
666
+	grepFile(t, container.lxcConfigPath,
667
+		fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
668
+	grepFile(t, container.lxcConfigPath,
669
+		fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
670
+}
671
+
619 672
 func BenchmarkRunSequencial(b *testing.B) {
620 673
 	docker, err := newTestDocker()
621 674
 	if err != nil {
... ...
@@ -1,20 +1,46 @@
1
-# This script is meant for quick & easy install via 'curl URL-OF-SCRIPPT | bash'
2
-# Courtesy of Jeff Lindsay <progrium@gmail.com>
3
-
4
-cd /tmp
5
-
6
-echo "Ensuring dependencies are installed..."
7
-apt-get --yes install lxc wget bsdtar 2>&1 > /dev/null
8
-
9
-echo "Downloading docker binary..."
10
-wget -q https://dl.dropbox.com/u/20637798/docker.tar.gz 2>&1 > /dev/null
11
-tar -xf docker.tar.gz 2>&1 > /dev/null
1
+#!/bin/sh
2
+# This script is meant for quick & easy install via 'curl URL-OF-SCRIPT | sh'
3
+# Original version by Jeff Lindsay <progrium@gmail.com>
4
+# Revamped by Jerome Petazzoni <jerome@dotcloud.com>
5
+#
6
+# This script canonical location is http://get.docker.io/; to update it, run:
7
+# s3cmd put -m text/x-shellscript -P install.sh s3://get.docker.io/index
8
+
9
+echo "Ensuring basic dependencies are installed..."
10
+apt-get -qq update
11
+apt-get -qq install lxc wget bsdtar
12
+
13
+echo "Looking in /proc/filesystems to see if we have AUFS support..."
14
+if grep -q aufs /proc/filesystems
15
+then
16
+    echo "Found."
17
+else
18
+    echo "Ahem, it looks like the current kernel does not support AUFS."
19
+    echo "Let's see if we can load the AUFS module with modprobe..."
20
+    if modprobe aufs
21
+    then
22
+        echo "Module loaded."
23
+    else
24
+        echo "Ahem, things didn't turn out as expected."
25
+        KPKG=linux-image-extra-$(uname -r)
26
+        echo "Trying to install $KPKG..."
27
+        if apt-get -qq install $KPKG
28
+        then
29
+            echo "Installed."
30
+        else
31
+            echo "Oops, we couldn't install the -extra kernel."
32
+            echo "Are you sure you are running a supported version of Ubuntu?"
33
+            echo "Proceeding anyway, but Docker will probably NOT WORK!"
34
+        fi
35
+    fi
36
+fi
12 37
 
13
-echo "Installing into /usr/local/bin..."
14
-mv docker/docker /usr/local/bin
15
-mv dockerd/dockerd /usr/local/bin
38
+echo "Downloading docker binary and uncompressing into /usr/local/bin..."
39
+curl -s http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz |
40
+tar -C /usr/local/bin --strip-components=1 -zxf- \
41
+docker-master/docker docker-master/dockerd
16 42
 
17
-if [[ -f /etc/init/dockerd.conf ]]
43
+if [ -f /etc/init/dockerd.conf ]
18 44
 then
19 45
   echo "Upstart script already exists."
20 46
 else
... ...
@@ -22,13 +48,8 @@ else
22 22
   echo "exec /usr/local/bin/dockerd" > /etc/init/dockerd.conf
23 23
 fi
24 24
 
25
-echo "Restarting dockerd..."
26
-restart dockerd > /dev/null
27
-
28
-echo "Cleaning up..."
29
-rmdir docker
30
-rmdir dockerd
31
-rm docker.tar.gz
25
+echo "Starting dockerd..."
26
+start dockerd > /dev/null
32 27
 
33
-echo "Finished!"
28
+echo "Done."
34 29
 echo
... ...
@@ -85,16 +85,32 @@ lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
85 85
 lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod net_raw setfcap setpcap sys_admin sys_boot sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config
86 86
 
87 87
 # limits
88
-{{if .Config.Ram}}
89
-lxc.cgroup.memory.limit_in_bytes = {{.Config.Ram}}
88
+{{if .Config.Memory}}
89
+lxc.cgroup.memory.limit_in_bytes = {{.Config.Memory}}
90
+lxc.cgroup.memory.soft_limit_in_bytes = {{.Config.Memory}}
91
+{{with $memSwap := getMemorySwap .Config}}
92
+lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
93
+{{end}}
90 94
 {{end}}
91 95
 `
92 96
 
93 97
 var LxcTemplateCompiled *template.Template
94 98
 
99
+func getMemorySwap(config *Config) int64 {
100
+	// By default, MemorySwap is set to twice the size of RAM.
101
+	// If you want to omit MemorySwap, set it to `-1'.
102
+	if config.MemorySwap < 0 {
103
+		return 0
104
+	}
105
+	return config.Memory * 2
106
+}
107
+
95 108
 func init() {
96 109
 	var err error
97
-	LxcTemplateCompiled, err = template.New("lxc").Parse(LxcTemplate)
110
+	funcMap := template.FuncMap{
111
+		"getMemorySwap": getMemorySwap,
112
+	}
113
+	LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
98 114
 	if err != nil {
99 115
 		panic(err)
100 116
 	}
... ...
@@ -1,14 +1,19 @@
1 1
 class docker {
2 2
 
3 3
     # update this with latest docker binary distro
4
-    $docker_url = "https://dl.dropbox.com/u/20637798/docker.tar.gz"
4
+    $docker_url = "http://docker.io.s3.amazonaws.com/builds/$kernel/$hardwaremodel/docker-master.tgz"
5 5
     # update this with latest go binary distry
6 6
     $go_url = "http://go.googlecode.com/files/go1.0.3.linux-amd64.tar.gz"
7 7
 
8
-
9 8
     Package { ensure => "installed" }
10 9
 
11
-    package { ["lxc", "debootstrap", "wget", "bsdtar"]: }
10
+    package { ["lxc", "debootstrap", "wget", "bsdtar", "git",
11
+               "linux-image-3.5.0-25-generic",
12
+               "linux-image-extra-3.5.0-25-generic",
13
+               "virtualbox-guest-utils",
14
+               "linux-headers-3.5.0-25-generic"]: }
15
+
16
+    notify { "docker_url = $docker_url": withpath => true }
12 17
 
13 18
     exec { "debootstrap" :
14 19
         require => Package["debootstrap"],
... ...
@@ -26,7 +31,7 @@ class docker {
26 26
     exec { "fetch-docker" :
27 27
         require => Package["wget"],
28 28
         command => "/usr/bin/wget -O - $docker_url | /bin/tar xz -C /home/vagrant",
29
-        creates => "/home/vagrant/docker/dockerd"
29
+        creates => "/home/vagrant/docker-master"
30 30
     }
31 31
 
32 32
     file { "/etc/init/dockerd.conf":
... ...
@@ -39,10 +44,21 @@ class docker {
39 39
 
40 40
     exec { "copy-docker-bin" :
41 41
         require => Exec["fetch-docker"],
42
-        command => "/bin/cp /home/vagrant/docker/docker /usr/local/bin",
42
+        command => "/bin/cp /home/vagrant/docker-master/docker /usr/local/bin",
43 43
         creates => "/usr/local/bin/docker"
44 44
     }
45 45
 
46
+    exec { "copy-dockerd-bin" :
47
+        require => Exec["fetch-docker"],
48
+        command => "/bin/cp /home/vagrant/docker-master/dockerd /usr/local/bin",
49
+        creates => "/usr/local/bin/dockerd"
50
+    }
51
+
52
+    exec { "vbox-add" :
53
+        require => Package["linux-headers-3.5.0-25-generic"],
54
+        command => "/etc/init.d/vboxadd setup",
55
+    }
56
+
46 57
     service { "dockerd" :
47 58
         ensure => "running",
48 59
         start => "/sbin/initctl start dockerd",
... ...
@@ -7,5 +7,6 @@ start on runlevel [3]
7 7
 respawn
8 8
 
9 9
 script
10
-    /home/vagrant/dockerd/dockerd
10
+    test -f /etc/default/locale && . /etc/default/locale || true
11
+    LANG=$LANG LC_ALL=$LANG /usr/local/bin/dockerd
11 12
 end script
... ...
@@ -37,28 +37,43 @@ func (srv *Server) Name() string {
37 37
 	return "docker"
38 38
 }
39 39
 
40
+// FIXME: Stop violating DRY by repeating usage here and in Subcmd declarations
40 41
 func (srv *Server) Help() string {
41 42
 	help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
42 43
 	for _, cmd := range [][]interface{}{
43 44
 		{"run", "Run a command in a container"},
44 45
 		{"ps", "Display a list of containers"},
45 46
 		{"import", "Create a new filesystem image from the contents of a tarball"},
46
-		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
47
-		{"rm", "Remove containers"},
48
-		{"kill", "Kill a running container"},
49
-		{"wait", "Wait for the state of a container to change"},
50
-		{"stop", "Stop a running container"},
51
-		{"start", "Start a stopped container"},
52
-		{"restart", "Restart a running container"},
53
-		{"logs", "Fetch the logs of a container"},
47
+		{"attach", "Attach to a running container"},
48
+		{"cat", "Write the contents of a container's file to standard output"},
49
+		{"commit", "Create a new image from a container's changes"},
50
+		{"cp", "Create a copy of IMAGE and call it NAME"},
51
+		{"debug", "(debug only) (No documentation available)"},
54 52
 		{"diff", "Inspect changes on a container's filesystem"},
55
-		{"commit", "Save the state of a container"},
56
-		{"attach", "Attach to the standard inputs and outputs of a running container"},
57
-		{"wait", "Block until a container exits, then print its exit code"},
53
+		{"images", "List images"},
58 54
 		{"info", "Display system-wide information"},
55
+		{"inspect", "Return low-level information on a container"},
56
+		{"kill", "Kill a running container"},
57
+		{"layers", "(debug only) List filesystem layers"},
58
+		{"logs", "Fetch the logs of a container"},
59
+		{"ls", "List the contents of a container's directory"},
60
+		{"mirror", "(debug only) (No documentation available)"},
61
+		{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
62
+		{"ps", "List containers"},
63
+		{"pull", "Download a new image from a remote location"},
64
+		{"put", "Import a new image from a local archive"},
65
+		{"reset", "Reset changes to a container's filesystem"},
66
+		{"restart", "Restart a running container"},
67
+		{"rm", "Remove a container"},
68
+		{"rmimage", "Remove an image"},
69
+		{"run", "Run a command in a new container"},
70
+		{"start", "Start a stopped container"},
71
+		{"stop", "Stop a running container"},
59 72
 		{"tar", "Stream the contents of a container as a tar archive"},
60
-		{"web", "Generate a web UI"},
61
-		{"images", "List images"},
73
+		{"umount", "(debug only) Mount a container's filesystem"},
74
+		{"wait", "Block until a container stops, then print its exit code"},
75
+		{"web", "A web UI for docker"},
76
+		{"write", "Write the contents of standard input to a container's file"},
62 77
 	} {
63 78
 		help += fmt.Sprintf("    %-10.10s%s\n", cmd...)
64 79
 	}
... ...
@@ -69,7 +84,6 @@ func (srv *Server) Help() string {
69 69
 func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
70 70
 	cmd := rcli.Subcmd(stdout, "wait", "[OPTIONS] NAME", "Block until a container stops, then print its exit code.")
71 71
 	if err := cmd.Parse(args); err != nil {
72
-		cmd.Usage()
73 72
 		return nil
74 73
 	}
75 74
 	if cmd.NArg() < 1 {
... ...
@@ -88,25 +102,24 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string
88 88
 
89 89
 // 'docker info': display system-wide information.
90 90
 func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
91
-	images, _ := srv.images.Images()
92
-	var imgcount int
93
-	if images == nil {
94
-		imgcount = 0
95
-	} else {
96
-		imgcount = len(images)
91
+	cmd := rcli.Subcmd(stdout, "info", "", "Display system-wide information.")
92
+	if err := cmd.Parse(args); err != nil {
93
+		return nil
94
+	}
95
+	if cmd.NArg() > 1 {
96
+		cmd.Usage()
97
+		return nil
97 98
 	}
98
-
99 99
 	fmt.Fprintf(stdout, "containers: %d\nversion: %s\nimages: %d\n",
100 100
 		len(srv.containers.List()),
101 101
 		VERSION,
102
-		imgcount)
102
+		len(srv.images.ById))
103 103
 	return nil
104 104
 }
105 105
 
106 106
 func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
107 107
 	cmd := rcli.Subcmd(stdout, "stop", "[OPTIONS] NAME", "Stop a running container")
108 108
 	if err := cmd.Parse(args); err != nil {
109
-		cmd.Usage()
110 109
 		return nil
111 110
 	}
112 111
 	if cmd.NArg() < 1 {
... ...
@@ -129,7 +142,6 @@ func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string
129 129
 func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
130 130
 	cmd := rcli.Subcmd(stdout, "restart", "[OPTIONS] NAME", "Restart a running container")
131 131
 	if err := cmd.Parse(args); err != nil {
132
-		cmd.Usage()
133 132
 		return nil
134 133
 	}
135 134
 	if cmd.NArg() < 1 {
... ...
@@ -152,7 +164,6 @@ func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...str
152 152
 func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
153 153
 	cmd := rcli.Subcmd(stdout, "start", "[OPTIONS] NAME", "Start a stopped container")
154 154
 	if err := cmd.Parse(args); err != nil {
155
-		cmd.Usage()
156 155
 		return nil
157 156
 	}
158 157
 	if cmd.NArg() < 1 {
... ...
@@ -175,7 +186,6 @@ func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...strin
175 175
 func (srv *Server) CmdUmount(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
176 176
 	cmd := rcli.Subcmd(stdout, "umount", "[OPTIONS] NAME", "umount a container's filesystem (debug only)")
177 177
 	if err := cmd.Parse(args); err != nil {
178
-		cmd.Usage()
179 178
 		return nil
180 179
 	}
181 180
 	if cmd.NArg() < 1 {
... ...
@@ -198,7 +208,6 @@ func (srv *Server) CmdUmount(stdin io.ReadCloser, stdout io.Writer, args ...stri
198 198
 func (srv *Server) CmdMount(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
199 199
 	cmd := rcli.Subcmd(stdout, "umount", "[OPTIONS] NAME", "mount a container's filesystem (debug only)")
200 200
 	if err := cmd.Parse(args); err != nil {
201
-		cmd.Usage()
202 201
 		return nil
203 202
 	}
204 203
 	if cmd.NArg() < 1 {
... ...
@@ -221,7 +230,6 @@ func (srv *Server) CmdMount(stdin io.ReadCloser, stdout io.Writer, args ...strin
221 221
 func (srv *Server) CmdCat(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
222 222
 	cmd := rcli.Subcmd(stdout, "cat", "[OPTIONS] CONTAINER PATH", "write the contents of a container's file to standard output")
223 223
 	if err := cmd.Parse(args); err != nil {
224
-		cmd.Usage()
225 224
 		return nil
226 225
 	}
227 226
 	if cmd.NArg() < 2 {
... ...
@@ -243,7 +251,6 @@ func (srv *Server) CmdCat(stdin io.ReadCloser, stdout io.Writer, args ...string)
243 243
 func (srv *Server) CmdWrite(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
244 244
 	cmd := rcli.Subcmd(stdout, "write", "[OPTIONS] CONTAINER PATH", "write the contents of standard input to a container's file")
245 245
 	if err := cmd.Parse(args); err != nil {
246
-		cmd.Usage()
247 246
 		return nil
248 247
 	}
249 248
 	if cmd.NArg() < 2 {
... ...
@@ -265,7 +272,6 @@ func (srv *Server) CmdWrite(stdin io.ReadCloser, stdout io.Writer, args ...strin
265 265
 func (srv *Server) CmdLs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
266 266
 	cmd := rcli.Subcmd(stdout, "ls", "[OPTIONS] CONTAINER PATH", "List the contents of a container's directory")
267 267
 	if err := cmd.Parse(args); err != nil {
268
-		cmd.Usage()
269 268
 		return nil
270 269
 	}
271 270
 	if cmd.NArg() < 2 {
... ...
@@ -289,7 +295,6 @@ func (srv *Server) CmdLs(stdin io.ReadCloser, stdout io.Writer, args ...string)
289 289
 func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
290 290
 	cmd := rcli.Subcmd(stdout, "inspect", "[OPTIONS] CONTAINER", "Return low-level information on a container")
291 291
 	if err := cmd.Parse(args); err != nil {
292
-		cmd.Usage()
293 292
 		return nil
294 293
 	}
295 294
 	if cmd.NArg() < 1 {
... ...
@@ -322,7 +327,6 @@ func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...str
322 322
 func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
323 323
 	cmd := rcli.Subcmd(stdout, "port", "[OPTIONS] CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
324 324
 	if err := cmd.Parse(args); err != nil {
325
-		cmd.Usage()
326 325
 		return nil
327 326
 	}
328 327
 	if cmd.NArg() != 2 {
... ...
@@ -459,7 +463,9 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
459 459
 	cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images")
460 460
 	limit := cmd.Int("l", 0, "Only show the N most recent versions of each image")
461 461
 	quiet := cmd.Bool("q", false, "only show numeric IDs")
462
-	cmd.Parse(args)
462
+	if err := cmd.Parse(args); err != nil {
463
+		return nil
464
+	}
463 465
 	if cmd.NArg() > 1 {
464 466
 		cmd.Usage()
465 467
 		return nil
... ...
@@ -813,6 +819,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
813 813
 	fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
814 814
 	fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
815 815
 	fl_comment := cmd.String("c", "", "Comment")
816
+	fl_memory := cmd.Int64("m", 0, "Memory limit (in bytes)")
816 817
 	var fl_ports ports
817 818
 	cmd.Var(&fl_ports, "p", "Map a network port to the container")
818 819
 	if err := cmd.Parse(args); err != nil {
... ...
@@ -842,7 +849,8 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
842 842
 		return errors.New("No such image: " + name)
843 843
 	}
844 844
 	// Create new container
845
-	container, err := srv.CreateContainer(img, fl_ports, *fl_user, *fl_tty, *fl_stdin, *fl_comment, cmdline[0], cmdline[1:]...)
845
+	container, err := srv.CreateContainer(img, fl_ports, *fl_user, *fl_tty,
846
+		*fl_stdin, *fl_memory, *fl_comment, cmdline[0], cmdline[1:]...)
846 847
 	if err != nil {
847 848
 		return errors.New("Error creating container: " + err.Error())
848 849
 	}