Browse code

Merge branch 'master' of https://github.com/aanand/docker into aanand-master

Victor Vieux authored on 2013/11/12 05:28:20
Showing 5 changed files
... ...
@@ -171,7 +171,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
171 171
 	cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
172 172
 	flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
173 173
 	flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
174
-	flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
174
+	flMemoryString := cmd.String("m", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
175 175
 	flContainerIDFile := cmd.String("cidfile", "", "Write the container ID to the file")
176 176
 	flNetwork := cmd.Bool("n", true, "Enable networking for this container")
177 177
 	flPrivileged := cmd.Bool("privileged", false, "Give extended privileges to this container")
... ...
@@ -180,9 +180,9 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
180 180
 	cmd.String("name", "", "Assign a name to the container")
181 181
 	flPublishAll := cmd.Bool("P", false, "Publish all exposed ports to the host interfaces")
182 182
 
183
-	if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
183
+	if capabilities != nil && *flMemoryString != "" && !capabilities.MemoryLimit {
184 184
 		//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
185
-		*flMemory = 0
185
+		*flMemoryString = ""
186 186
 	}
187 187
 
188 188
 	flCpuShares := cmd.Int64("c", 0, "CPU shares (relative weight)")
... ...
@@ -249,6 +249,18 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
249 249
 		}
250 250
 	}
251 251
 
252
+	var flMemory int64
253
+
254
+	if *flMemoryString != "" {
255
+		parsedMemory, err := utils.RAMInBytes(*flMemoryString)
256
+
257
+		if err != nil {
258
+			return nil, nil, cmd, err
259
+		}
260
+
261
+		flMemory = parsedMemory
262
+	}
263
+
252 264
 	var binds []string
253 265
 
254 266
 	// add any bind targets to the list of container volumes
... ...
@@ -319,7 +331,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
319 319
 		Tty:             *flTty,
320 320
 		NetworkDisabled: !*flNetwork,
321 321
 		OpenStdin:       *flStdin,
322
-		Memory:          *flMemory,
322
+		Memory:          flMemory,
323 323
 		CpuShares:       *flCpuShares,
324 324
 		AttachStdin:     flAttach.Get("stdin"),
325 325
 		AttachStdout:    flAttach.Get("stdout"),
... ...
@@ -344,7 +356,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
344 344
 		PublishAllPorts: *flPublishAll,
345 345
 	}
346 346
 
347
-	if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
347
+	if capabilities != nil && flMemory > 0 && !capabilities.SwapLimit {
348 348
 		//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
349 349
 		config.MemorySwap = -1
350 350
 	}
... ...
@@ -652,7 +652,7 @@ network communication.
652 652
       -h="": Container host name
653 653
       -i=false: Keep stdin open even if not attached
654 654
       -privileged=false: Give extended privileges to this container
655
-      -m=0: Memory limit (in bytes)
655
+      -m="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
656 656
       -n=true: Enable networking for this container
657 657
       -p=[]: Map a network port to the container
658 658
       -rm=false: Automatically remove the container when it exits (incompatible with -d)
... ...
@@ -1023,7 +1023,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
1023 1023
 
1024 1024
 func (srv *Server) ContainerCreate(config *Config, name string) (string, []string, error) {
1025 1025
 	if config.Memory != 0 && config.Memory < 524288 {
1026
-		return "", nil, fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
1026
+		return "", nil, fmt.Errorf("Minimum memory limit allowed is 512k")
1027 1027
 	}
1028 1028
 
1029 1029
 	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
... ...
@@ -177,6 +177,40 @@ func HumanSize(size int64) string {
177 177
 	return fmt.Sprintf("%.4g %s", sizef, units[i])
178 178
 }
179 179
 
180
+// Parses a human-readable string representing an amount of RAM
181
+// in bytes, kibibytes, mebibytes or gibibytes, and returns the
182
+// number of bytes, or -1 if the string is unparseable.
183
+// Units are case-insensitive, and the 'b' suffix is optional.
184
+func RAMInBytes(size string) (bytes int64, err error) {
185
+	re, error := regexp.Compile("^(\\d+)([kKmMgG])?[bB]?$")
186
+	if error != nil {
187
+		return -1, error
188
+	}
189
+
190
+	matches := re.FindStringSubmatch(size)
191
+
192
+	if len(matches) != 3 {
193
+		return -1, fmt.Errorf("Invalid size: '%s'", size)
194
+	}
195
+
196
+	memLimit, error := strconv.ParseInt(matches[1], 10, 0)
197
+	if error != nil {
198
+		return -1, error
199
+	}
200
+
201
+	unit := strings.ToLower(matches[2])
202
+
203
+	if unit == "k" {
204
+		memLimit *= 1024
205
+	} else if unit == "m" {
206
+		memLimit *= 1024 * 1024
207
+	} else if unit == "g" {
208
+		memLimit *= 1024 * 1024 * 1024
209
+	}
210
+
211
+	return memLimit, nil
212
+}
213
+
180 214
 func Trunc(s string, maxlen int) string {
181 215
 	if len(s) <= maxlen {
182 216
 		return s
... ...
@@ -265,6 +265,39 @@ func TestHumanSize(t *testing.T) {
265 265
 	}
266 266
 }
267 267
 
268
+func TestRAMInBytes(t *testing.T) {
269
+	assertRAMInBytes(t, "32",   false, 32)
270
+	assertRAMInBytes(t, "32b",  false, 32)
271
+	assertRAMInBytes(t, "32B",  false, 32)
272
+	assertRAMInBytes(t, "32k",  false, 32*1024)
273
+	assertRAMInBytes(t, "32K",  false, 32*1024)
274
+	assertRAMInBytes(t, "32kb", false, 32*1024)
275
+	assertRAMInBytes(t, "32Kb", false, 32*1024)
276
+	assertRAMInBytes(t, "32Mb", false, 32*1024*1024)
277
+	assertRAMInBytes(t, "32Gb", false, 32*1024*1024*1024)
278
+
279
+	assertRAMInBytes(t, "",      true, -1)
280
+	assertRAMInBytes(t, "hello", true, -1)
281
+	assertRAMInBytes(t, "-32",   true, -1)
282
+	assertRAMInBytes(t, " 32 ",  true, -1)
283
+	assertRAMInBytes(t, "32 mb", true, -1)
284
+	assertRAMInBytes(t, "32m b", true, -1)
285
+	assertRAMInBytes(t, "32bm",  true, -1)
286
+}
287
+
288
+func assertRAMInBytes(t *testing.T, size string, expectError bool, expectedBytes int64) {
289
+	actualBytes, err := RAMInBytes(size)
290
+	if (err != nil) && !expectError {
291
+		t.Errorf("Unexpected error parsing '%s': %s", size, err)
292
+	}
293
+	if (err == nil) && expectError {
294
+		t.Errorf("Expected to get an error parsing '%s', but got none (bytes=%d)", size, actualBytes)
295
+	}
296
+	if actualBytes != expectedBytes {
297
+		t.Errorf("Expected '%s' to parse as %d bytes, got %d", size, expectedBytes, actualBytes)
298
+	}
299
+}
300
+
268 301
 func TestParseHost(t *testing.T) {
269 302
 	if addr, err := ParseHost("127.0.0.1", 4243, "0.0.0.0"); err != nil || addr != "tcp://0.0.0.0:4243" {
270 303
 		t.Errorf("0.0.0.0 -> expected tcp://0.0.0.0:4243, got %s", addr)