Browse code

Adding timestamp end to events endpoint. Modifying api docs.

Docker-DCO-1.1-Signed-off-by: Isabel Jimenez <contact@isabeljimenez.com> (github: jimenez)

Isabel Jimenez authored on 2014/03/24 08:14:40
Showing 7 changed files
... ...
@@ -1484,7 +1484,8 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
1484 1484
 
1485 1485
 func (cli *DockerCli) CmdEvents(args ...string) error {
1486 1486
 	cmd := cli.Subcmd("events", "[OPTIONS]", "Get real time events from the server")
1487
-	since := cmd.String([]string{"#since", "-since"}, "", "Show previously created events and then stream.")
1487
+	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
1488
+	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
1488 1489
 	if err := cmd.Parse(args); err != nil {
1489 1490
 		return nil
1490 1491
 	}
... ...
@@ -1493,22 +1494,27 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
1493 1493
 		cmd.Usage()
1494 1494
 		return nil
1495 1495
 	}
1496
-
1497
-	v := url.Values{}
1498
-	if *since != "" {
1499
-		loc := time.FixedZone(time.Now().Zone())
1496
+	var (
1497
+		v   = url.Values{}
1498
+		loc = time.FixedZone(time.Now().Zone())
1499
+	)
1500
+	var setTime = func(key, value string) {
1500 1501
 		format := "2006-01-02 15:04:05 -0700 MST"
1501
-		if len(*since) < len(format) {
1502
-			format = format[:len(*since)]
1502
+		if len(value) < len(format) {
1503
+			format = format[:len(value)]
1503 1504
 		}
1504
-
1505
-		if t, err := time.ParseInLocation(format, *since, loc); err == nil {
1506
-			v.Set("since", strconv.FormatInt(t.Unix(), 10))
1505
+		if t, err := time.ParseInLocation(format, value, loc); err == nil {
1506
+			v.Set(key, strconv.FormatInt(t.Unix(), 10))
1507 1507
 		} else {
1508
-			v.Set("since", *since)
1508
+			v.Set(key, value)
1509 1509
 		}
1510 1510
 	}
1511
-
1511
+	if *since != "" {
1512
+		setTime("since", *since)
1513
+	}
1514
+	if *until != "" {
1515
+		setTime("until", *until)
1516
+	}
1512 1517
 	if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
1513 1518
 		return err
1514 1519
 	}
... ...
@@ -10,7 +10,7 @@ import (
10 10
 )
11 11
 
12 12
 const (
13
-	APIVERSION        version.Version = "1.10"
13
+	APIVERSION        version.Version = "1.11"
14 14
 	DEFAULTHTTPHOST                   = "127.0.0.1"
15 15
 	DEFAULTUNIXSOCKET                 = "/var/run/docker.sock"
16 16
 )
... ...
@@ -246,6 +246,7 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite
246 246
 	var job = eng.Job("events", r.RemoteAddr)
247 247
 	streamJSON(job, w, true)
248 248
 	job.Setenv("since", r.Form.Get("since"))
249
+	job.Setenv("until", r.Form.Get("until"))
249 250
 	return job.Run()
250 251
 }
251 252
 
... ...
@@ -28,15 +28,30 @@ Docker Remote API
28 28
 2. Versions
29 29
 ===========
30 30
 
31
-The current version of the API is 1.10
31
+The current version of the API is 1.11
32 32
 
33 33
 Calling /images/<name>/insert is the same as calling
34
-/v1.10/images/<name>/insert
34
+/v1.11/images/<name>/insert
35 35
 
36 36
 You can still call an old version of the api using
37
-/v1.0/images/<name>/insert
37
+/v1.11/images/<name>/insert
38 38
 
39 39
 
40
+v1.11
41
+*****
42
+
43
+Full Documentation
44
+------------------
45
+
46
+:doc:`docker_remote_api_v1.11`
47
+
48
+What's new
49
+----------
50
+
51
+.. http:get:: /events
52
+
53
+   **New!** You can now use the ``-until`` parameter to close connection after timestamp.
54
+
40 55
 v1.10
41 56
 *****
42 57
 
43 58
new file mode 100644
... ...
@@ -0,0 +1,1286 @@
0
+:title: Remote API v1.11
1
+:description: API Documentation for Docker
2
+:keywords: API, Docker, rcli, REST, documentation
3
+
4
+:orphan:
5
+
6
+=======================
7
+Docker Remote API v1.11
8
+=======================
9
+
10
+.. contents:: Table of Contents
11
+
12
+1. Brief introduction
13
+=====================
14
+
15
+- The Remote API has replaced rcli
16
+- The daemon listens on ``unix:///var/run/docker.sock``, but you can
17
+  :ref:`bind_docker`.
18
+- The API tends to be REST, but for some complex commands, like
19
+  ``attach`` or ``pull``, the HTTP connection is hijacked to transport
20
+  ``stdout, stdin`` and ``stderr``
21
+
22
+2. Endpoints
23
+============
24
+
25
+2.1 Containers
26
+--------------
27
+
28
+List containers
29
+***************
30
+
31
+.. http:get:: /containers/json
32
+
33
+        List containers
34
+
35
+        **Example request**:
36
+
37
+        .. sourcecode:: http
38
+
39
+           GET /containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1
40
+
41
+        **Example response**:
42
+
43
+        .. sourcecode:: http
44
+
45
+           HTTP/1.1 200 OK
46
+           Content-Type: application/json
47
+
48
+           [
49
+                {
50
+                        "Id": "8dfafdbc3a40",
51
+                        "Image": "base:latest",
52
+                        "Command": "echo 1",
53
+                        "Created": 1367854155,
54
+                        "Status": "Exit 0",
55
+                        "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
56
+                        "SizeRw":12288,
57
+                        "SizeRootFs":0
58
+                },
59
+                {
60
+                        "Id": "9cd87474be90",
61
+                        "Image": "base:latest",
62
+                        "Command": "echo 222222",
63
+                        "Created": 1367854155,
64
+                        "Status": "Exit 0",
65
+                        "Ports":[],
66
+                        "SizeRw":12288,
67
+                        "SizeRootFs":0
68
+                },
69
+                {
70
+                        "Id": "3176a2479c92",
71
+                        "Image": "base:latest",
72
+                        "Command": "echo 3333333333333333",
73
+                        "Created": 1367854154,
74
+                        "Status": "Exit 0",
75
+                        "Ports":[],
76
+                        "SizeRw":12288,
77
+                        "SizeRootFs":0
78
+                },
79
+                {
80
+                        "Id": "4cb07b47f9fb",
81
+                        "Image": "base:latest",
82
+                        "Command": "echo 444444444444444444444444444444444",
83
+                        "Created": 1367854152,
84
+                        "Status": "Exit 0",
85
+                        "Ports":[],
86
+                        "SizeRw":12288,
87
+                        "SizeRootFs":0
88
+                }
89
+           ]
90
+
91
+        :query all: 1/True/true or 0/False/false, Show all containers. Only running containers are shown by default
92
+        :query limit: Show ``limit`` last created containers, include non-running ones.
93
+        :query since: Show only containers created since Id, include non-running ones.
94
+        :query before: Show only containers created before Id, include non-running ones.
95
+        :query size: 1/True/true or 0/False/false, Show the containers sizes
96
+        :statuscode 200: no error
97
+        :statuscode 400: bad parameter
98
+        :statuscode 500: server error
99
+
100
+
101
+Create a container
102
+******************
103
+
104
+.. http:post:: /containers/create
105
+
106
+        Create a container
107
+
108
+        **Example request**:
109
+
110
+        .. sourcecode:: http
111
+
112
+           POST /containers/create HTTP/1.1
113
+           Content-Type: application/json
114
+
115
+           {
116
+                "Hostname":"",
117
+                "User":"",
118
+                "Memory":0,
119
+                "MemorySwap":0,
120
+                "AttachStdin":false,
121
+                "AttachStdout":true,
122
+                "AttachStderr":true,
123
+                "PortSpecs":null,
124
+                "Tty":false,
125
+                "OpenStdin":false,
126
+                "StdinOnce":false,
127
+                "Env":null,
128
+                "Cmd":[
129
+                        "date"
130
+                ],
131
+                "Dns":null,
132
+                "Image":"base",
133
+                "Volumes":{
134
+                        "/tmp": {}
135
+                },
136
+                "VolumesFrom":"",
137
+                "WorkingDir":"",
138
+                "DisableNetwork": false,
139
+                "ExposedPorts":{
140
+                        "22/tcp": {}
141
+                }
142
+           }
143
+
144
+        **Example response**:
145
+
146
+        .. sourcecode:: http
147
+
148
+           HTTP/1.1 201 OK
149
+           Content-Type: application/json
150
+
151
+           {
152
+                "Id":"e90e34656806"
153
+                "Warnings":[]
154
+           }
155
+
156
+        :jsonparam config: the container's configuration
157
+        :query name: Assign the specified name to the container. Must match ``/?[a-zA-Z0-9_-]+``.
158
+        :statuscode 201: no error
159
+        :statuscode 404: no such container
160
+        :statuscode 406: impossible to attach (container not running)
161
+        :statuscode 500: server error
162
+
163
+
164
+Inspect a container
165
+*******************
166
+
167
+.. http:get:: /containers/(id)/json
168
+
169
+        Return low-level information on the container ``id``
170
+
171
+        **Example request**:
172
+
173
+        .. sourcecode:: http
174
+
175
+           GET /containers/4fa6e0f0c678/json HTTP/1.1
176
+
177
+        **Example response**:
178
+
179
+        .. sourcecode:: http
180
+
181
+           HTTP/1.1 200 OK
182
+           Content-Type: application/json
183
+
184
+           {
185
+                        "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
186
+                        "Created": "2013-05-07T14:51:42.041847+02:00",
187
+                        "Path": "date",
188
+                        "Args": [],
189
+                        "Config": {
190
+                                "Hostname": "4fa6e0f0c678",
191
+                                "User": "",
192
+                                "Memory": 0,
193
+                                "MemorySwap": 0,
194
+                                "AttachStdin": false,
195
+                                "AttachStdout": true,
196
+                                "AttachStderr": true,
197
+                                "PortSpecs": null,
198
+                                "Tty": false,
199
+                                "OpenStdin": false,
200
+                                "StdinOnce": false,
201
+                                "Env": null,
202
+                                "Cmd": [
203
+                                        "date"
204
+                                ],
205
+                                "Dns": null,
206
+                                "Image": "base",
207
+                                "Volumes": {},
208
+                                "VolumesFrom": "",
209
+                                "WorkingDir":""
210
+
211
+                        },
212
+                        "State": {
213
+                                "Running": false,
214
+                                "Pid": 0,
215
+                                "ExitCode": 0,
216
+                                "StartedAt": "2013-05-07T14:51:42.087658+02:01360",
217
+                                "Ghost": false
218
+                        },
219
+                        "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
220
+                        "NetworkSettings": {
221
+                                "IpAddress": "",
222
+                                "IpPrefixLen": 0,
223
+                                "Gateway": "",
224
+                                "Bridge": "",
225
+                                "PortMapping": null
226
+                        },
227
+                        "SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker",
228
+                        "ResolvConfPath": "/etc/resolv.conf",
229
+                        "Volumes": {},
230
+                        "HostConfig": {
231
+                            "Binds": null,
232
+                            "ContainerIDFile": "",
233
+                            "LxcConf": [],
234
+                            "Privileged": false,
235
+                            "PortBindings": {
236
+                               "80/tcp": [
237
+                                   {
238
+                                       "HostIp": "0.0.0.0",
239
+                                       "HostPort": "49153"
240
+                                   }
241
+                               ]
242
+                            },
243
+                            "Links": null,
244
+                            "PublishAllPorts": false
245
+                        }
246
+           }
247
+
248
+        :statuscode 200: no error
249
+        :statuscode 404: no such container
250
+        :statuscode 500: server error
251
+
252
+
253
+List processes running inside a container
254
+*****************************************
255
+
256
+.. http:get:: /containers/(id)/top
257
+
258
+        List processes running inside the container ``id``
259
+
260
+        **Example request**:
261
+
262
+        .. sourcecode:: http
263
+
264
+           GET /containers/4fa6e0f0c678/top HTTP/1.1
265
+
266
+        **Example response**:
267
+
268
+        .. sourcecode:: http
269
+
270
+           HTTP/1.1 200 OK
271
+           Content-Type: application/json
272
+
273
+           {
274
+                "Titles":[
275
+                        "USER",
276
+                        "PID",
277
+                        "%CPU",
278
+                        "%MEM",
279
+                        "VSZ",
280
+                        "RSS",
281
+                        "TTY",
282
+                        "STAT",
283
+                        "START",
284
+                        "TIME",
285
+                        "COMMAND"
286
+                        ],
287
+                "Processes":[
288
+                        ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"],
289
+                        ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"]
290
+                ]
291
+           }
292
+
293
+        :query ps_args: ps arguments to use (eg. aux)
294
+        :statuscode 200: no error
295
+        :statuscode 404: no such container
296
+        :statuscode 500: server error
297
+
298
+
299
+Inspect changes on a container's filesystem
300
+*******************************************
301
+
302
+.. http:get:: /containers/(id)/changes
303
+
304
+        Inspect changes on container ``id`` 's filesystem
305
+
306
+        **Example request**:
307
+
308
+        .. sourcecode:: http
309
+
310
+           GET /containers/4fa6e0f0c678/changes HTTP/1.1
311
+
312
+
313
+        **Example response**:
314
+
315
+        .. sourcecode:: http
316
+
317
+           HTTP/1.1 200 OK
318
+           Content-Type: application/json
319
+
320
+           [
321
+                {
322
+                        "Path":"/dev",
323
+                        "Kind":0
324
+                },
325
+                {
326
+                        "Path":"/dev/kmsg",
327
+                        "Kind":1
328
+                },
329
+                {
330
+                        "Path":"/test",
331
+                        "Kind":1
332
+                }
333
+           ]
334
+
335
+        :statuscode 200: no error
336
+        :statuscode 404: no such container
337
+        :statuscode 500: server error
338
+
339
+
340
+Export a container
341
+******************
342
+
343
+.. http:get:: /containers/(id)/export
344
+
345
+        Export the contents of container ``id``
346
+
347
+        **Example request**:
348
+
349
+        .. sourcecode:: http
350
+
351
+           GET /containers/4fa6e0f0c678/export HTTP/1.1
352
+
353
+
354
+        **Example response**:
355
+
356
+        .. sourcecode:: http
357
+
358
+           HTTP/1.1 200 OK
359
+           Content-Type: application/octet-stream
360
+
361
+           {{ STREAM }}
362
+
363
+        :statuscode 200: no error
364
+        :statuscode 404: no such container
365
+        :statuscode 500: server error
366
+
367
+
368
+Start a container
369
+*****************
370
+
371
+.. http:post:: /containers/(id)/start
372
+
373
+        Start the container ``id``
374
+
375
+        **Example request**:
376
+
377
+        .. sourcecode:: http
378
+
379
+           POST /containers/(id)/start HTTP/1.1
380
+           Content-Type: application/json
381
+
382
+           {
383
+                "Binds":["/tmp:/tmp"],
384
+                "LxcConf":{"lxc.utsname":"docker"},
385
+                "PortBindings":{ "22/tcp": [{ "HostPort": "11022" }] },
386
+                "PublishAllPorts":false,
387
+                "Privileged":false
388
+           }
389
+
390
+        **Example response**:
391
+
392
+        .. sourcecode:: http
393
+
394
+           HTTP/1.1 204 No Content
395
+           Content-Type: text/plain
396
+
397
+        :jsonparam hostConfig: the container's host configuration (optional)
398
+        :statuscode 204: no error
399
+        :statuscode 404: no such container
400
+        :statuscode 500: server error
401
+
402
+
403
+Stop a container
404
+****************
405
+
406
+.. http:post:: /containers/(id)/stop
407
+
408
+        Stop the container ``id``
409
+
410
+        **Example request**:
411
+
412
+        .. sourcecode:: http
413
+
414
+           POST /containers/e90e34656806/stop?t=5 HTTP/1.1
415
+
416
+        **Example response**:
417
+
418
+        .. sourcecode:: http
419
+
420
+           HTTP/1.1 204 OK
421
+
422
+        :query t: number of seconds to wait before killing the container
423
+        :statuscode 204: no error
424
+        :statuscode 404: no such container
425
+        :statuscode 500: server error
426
+
427
+
428
+Restart a container
429
+*******************
430
+
431
+.. http:post:: /containers/(id)/restart
432
+
433
+        Restart the container ``id``
434
+
435
+        **Example request**:
436
+
437
+        .. sourcecode:: http
438
+
439
+           POST /containers/e90e34656806/restart?t=5 HTTP/1.1
440
+
441
+        **Example response**:
442
+
443
+        .. sourcecode:: http
444
+
445
+           HTTP/1.1 204 OK
446
+
447
+        :query t: number of seconds to wait before killing the container
448
+        :statuscode 204: no error
449
+        :statuscode 404: no such container
450
+        :statuscode 500: server error
451
+
452
+
453
+Kill a container
454
+****************
455
+
456
+.. http:post:: /containers/(id)/kill
457
+
458
+        Kill the container ``id``
459
+
460
+        **Example request**:
461
+
462
+        .. sourcecode:: http
463
+
464
+           POST /containers/e90e34656806/kill HTTP/1.1
465
+
466
+        **Example response**:
467
+
468
+        .. sourcecode:: http
469
+
470
+           HTTP/1.1 204 OK
471
+
472
+        :statuscode 204: no error
473
+        :statuscode 404: no such container
474
+        :statuscode 500: server error
475
+
476
+
477
+Attach to a container
478
+*********************
479
+
480
+.. http:post:: /containers/(id)/attach
481
+
482
+        Attach to the container ``id``
483
+
484
+        **Example request**:
485
+
486
+        .. sourcecode:: http
487
+
488
+           POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1
489
+
490
+        **Example response**:
491
+
492
+        .. sourcecode:: http
493
+
494
+           HTTP/1.1 200 OK
495
+           Content-Type: application/vnd.docker.raw-stream
496
+
497
+           {{ STREAM }}
498
+
499
+        :query logs: 1/True/true or 0/False/false, return logs. Default false
500
+        :query stream: 1/True/true or 0/False/false, return stream. Default false
501
+        :query stdin: 1/True/true or 0/False/false, if stream=true, attach to stdin. Default false
502
+        :query stdout: 1/True/true or 0/False/false, if logs=true, return stdout log, if stream=true, attach to stdout. Default false
503
+        :query stderr: 1/True/true or 0/False/false, if logs=true, return stderr log, if stream=true, attach to stderr. Default false
504
+        :statuscode 200: no error
505
+        :statuscode 400: bad parameter
506
+        :statuscode 404: no such container
507
+        :statuscode 500: server error
508
+
509
+        **Stream details**:
510
+
511
+        When using the TTY setting is enabled in
512
+        :http:post:`/containers/create`, the stream is the raw data
513
+        from the process PTY and client's stdin.  When the TTY is
514
+        disabled, then the stream is multiplexed to separate stdout
515
+        and stderr.
516
+
517
+        The format is a **Header** and a **Payload** (frame).
518
+
519
+        **HEADER**
520
+
521
+        The header will contain the information on which stream write
522
+        the stream (stdout or stderr). It also contain the size of
523
+        the associated frame encoded on the last 4 bytes (uint32).
524
+
525
+        It is encoded on the first 8 bytes like this::
526
+
527
+            header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
528
+
529
+        ``STREAM_TYPE`` can be:
530
+
531
+        - 0: stdin (will be writen on stdout)
532
+        - 1: stdout
533
+        - 2: stderr
534
+
535
+        ``SIZE1, SIZE2, SIZE3, SIZE4`` are the 4 bytes of the uint32 size encoded as big endian.
536
+
537
+        **PAYLOAD**
538
+
539
+        The payload is the raw stream.
540
+
541
+        **IMPLEMENTATION**
542
+
543
+        The simplest way to implement the Attach protocol is the following:
544
+
545
+        1) Read 8 bytes
546
+        2) chose stdout or stderr depending on the first byte
547
+        3) Extract the frame size from the last 4 byets
548
+        4) Read the extracted size and output it on the correct output
549
+        5) Goto 1)
550
+
551
+
552
+
553
+Wait a container
554
+****************
555
+
556
+.. http:post:: /containers/(id)/wait
557
+
558
+        Block until container ``id`` stops, then returns the exit code
559
+
560
+        **Example request**:
561
+
562
+        .. sourcecode:: http
563
+
564
+           POST /containers/16253994b7c4/wait HTTP/1.1
565
+
566
+        **Example response**:
567
+
568
+        .. sourcecode:: http
569
+
570
+           HTTP/1.1 200 OK
571
+           Content-Type: application/json
572
+
573
+           {"StatusCode":0}
574
+
575
+        :statuscode 200: no error
576
+        :statuscode 404: no such container
577
+        :statuscode 500: server error
578
+
579
+
580
+Remove a container
581
+*******************
582
+
583
+.. http:delete:: /containers/(id)
584
+
585
+        Remove the container ``id`` from the filesystem
586
+
587
+        **Example request**:
588
+
589
+        .. sourcecode:: http
590
+
591
+           DELETE /containers/16253994b7c4?v=1 HTTP/1.1
592
+
593
+        **Example response**:
594
+
595
+        .. sourcecode:: http
596
+
597
+           HTTP/1.1 204 OK
598
+
599
+        :query v: 1/True/true or 0/False/false, Remove the volumes associated to the container. Default false
600
+        :query force: 1/True/true or 0/False/false, Removes the container even if it was running. Default false
601
+        :statuscode 204: no error
602
+        :statuscode 400: bad parameter
603
+        :statuscode 404: no such container
604
+        :statuscode 500: server error
605
+
606
+
607
+Copy files or folders from a container
608
+**************************************
609
+
610
+.. http:post:: /containers/(id)/copy
611
+
612
+        Copy files or folders of container ``id``
613
+
614
+        **Example request**:
615
+
616
+        .. sourcecode:: http
617
+
618
+           POST /containers/4fa6e0f0c678/copy HTTP/1.1
619
+           Content-Type: application/json
620
+
621
+           {
622
+                "Resource":"test.txt"
623
+           }
624
+
625
+        **Example response**:
626
+
627
+        .. sourcecode:: http
628
+
629
+           HTTP/1.1 200 OK
630
+           Content-Type: application/octet-stream
631
+
632
+           {{ STREAM }}
633
+
634
+        :statuscode 200: no error
635
+        :statuscode 404: no such container
636
+        :statuscode 500: server error
637
+
638
+
639
+2.2 Images
640
+----------
641
+
642
+List Images
643
+***********
644
+
645
+.. http:get:: /images/json
646
+
647
+        **Example request**:
648
+
649
+        .. sourcecode:: http
650
+
651
+           GET /images/json?all=0 HTTP/1.1
652
+
653
+        **Example response**:
654
+
655
+        .. sourcecode:: http
656
+
657
+           HTTP/1.1 200 OK
658
+           Content-Type: application/json
659
+
660
+           [
661
+             {
662
+                "RepoTags": [
663
+                  "ubuntu:12.04",
664
+                  "ubuntu:precise",
665
+                  "ubuntu:latest"
666
+                ],
667
+                "Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
668
+                "Created": 1365714795,
669
+                "Size": 131506275,
670
+                "VirtualSize": 131506275
671
+             },
672
+             {
673
+                "RepoTags": [
674
+                  "ubuntu:12.10",
675
+                  "ubuntu:quantal"
676
+                ],
677
+                "ParentId": "27cf784147099545",
678
+                "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
679
+                "Created": 1364102658,
680
+                "Size": 24653,
681
+                "VirtualSize": 180116135
682
+             }
683
+           ]
684
+
685
+
686
+Create an image
687
+***************
688
+
689
+.. http:post:: /images/create
690
+
691
+        Create an image, either by pull it from the registry or by importing it
692
+
693
+        **Example request**:
694
+
695
+        .. sourcecode:: http
696
+
697
+           POST /images/create?fromImage=base HTTP/1.1
698
+
699
+        **Example response**:
700
+
701
+        .. sourcecode:: http
702
+
703
+           HTTP/1.1 200 OK
704
+           Content-Type: application/json
705
+
706
+           {"status":"Pulling..."}
707
+           {"status":"Pulling", "progress":"1 B/ 100 B", "progressDetail":{"current":1, "total":100}}
708
+           {"error":"Invalid..."}
709
+           ...
710
+
711
+        When using this endpoint to pull an image from the registry,
712
+        the ``X-Registry-Auth`` header can be used to include a
713
+        base64-encoded AuthConfig object.
714
+
715
+        :query fromImage: name of the image to pull
716
+        :query fromSrc: source to import, - means stdin
717
+        :query repo: repository
718
+        :query tag: tag
719
+        :query registry: the registry to pull from
720
+        :reqheader X-Registry-Auth: base64-encoded AuthConfig object
721
+        :statuscode 200: no error
722
+        :statuscode 500: server error
723
+
724
+
725
+
726
+Insert a file in an image
727
+*************************
728
+
729
+.. http:post:: /images/(name)/insert
730
+
731
+        Insert a file from ``url`` in the image ``name`` at ``path``
732
+
733
+        **Example request**:
734
+
735
+        .. sourcecode:: http
736
+
737
+           POST /images/test/insert?path=/usr&url=myurl HTTP/1.1
738
+
739
+        **Example response**:
740
+
741
+        .. sourcecode:: http
742
+
743
+           HTTP/1.1 200 OK
744
+           Content-Type: application/json
745
+
746
+           {"status":"Inserting..."}
747
+           {"status":"Inserting", "progress":"1/? (n/a)", "progressDetail":{"current":1}}
748
+           {"error":"Invalid..."}
749
+           ...
750
+
751
+        :statuscode 200: no error
752
+        :statuscode 500: server error
753
+
754
+
755
+Inspect an image
756
+****************
757
+
758
+.. http:get:: /images/(name)/json
759
+
760
+        Return low-level information on the image ``name``
761
+
762
+        **Example request**:
763
+
764
+        .. sourcecode:: http
765
+
766
+           GET /images/base/json HTTP/1.1
767
+
768
+        **Example response**:
769
+
770
+        .. sourcecode:: http
771
+
772
+           HTTP/1.1 200 OK
773
+           Content-Type: application/json
774
+
775
+           {
776
+                "id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
777
+                "parent":"27cf784147099545",
778
+                "created":"2013-03-23T22:24:18.818426-07:00",
779
+                "container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0",
780
+                "container_config":
781
+                        {
782
+                                "Hostname":"",
783
+                                "User":"",
784
+                                "Memory":0,
785
+                                "MemorySwap":0,
786
+                                "AttachStdin":false,
787
+                                "AttachStdout":false,
788
+                                "AttachStderr":false,
789
+                                "PortSpecs":null,
790
+                                "Tty":true,
791
+                                "OpenStdin":true,
792
+                                "StdinOnce":false,
793
+                                "Env":null,
794
+                                "Cmd": ["/bin/bash"]
795
+                                ,"Dns":null,
796
+                                "Image":"base",
797
+                                "Volumes":null,
798
+                                "VolumesFrom":"",
799
+                                "WorkingDir":""
800
+                        },
801
+                "Size": 6824592
802
+           }
803
+
804
+        :statuscode 200: no error
805
+        :statuscode 404: no such image
806
+        :statuscode 500: server error
807
+
808
+
809
+Get the history of an image
810
+***************************
811
+
812
+.. http:get:: /images/(name)/history
813
+
814
+        Return the history of the image ``name``
815
+
816
+        **Example request**:
817
+
818
+        .. sourcecode:: http
819
+
820
+           GET /images/base/history HTTP/1.1
821
+
822
+        **Example response**:
823
+
824
+        .. sourcecode:: http
825
+
826
+           HTTP/1.1 200 OK
827
+           Content-Type: application/json
828
+
829
+           [
830
+                {
831
+                        "Id":"b750fe79269d",
832
+                        "Created":1364102658,
833
+                        "CreatedBy":"/bin/bash"
834
+                },
835
+                {
836
+                        "Id":"27cf78414709",
837
+                        "Created":1364068391,
838
+                        "CreatedBy":""
839
+                }
840
+           ]
841
+
842
+        :statuscode 200: no error
843
+        :statuscode 404: no such image
844
+        :statuscode 500: server error
845
+
846
+
847
+Push an image on the registry
848
+*****************************
849
+
850
+.. http:post:: /images/(name)/push
851
+
852
+   Push the image ``name`` on the registry
853
+
854
+   **Example request**:
855
+
856
+   .. sourcecode:: http
857
+
858
+      POST /images/test/push HTTP/1.1
859
+
860
+   **Example response**:
861
+
862
+   .. sourcecode:: http
863
+
864
+    HTTP/1.1 200 OK
865
+    Content-Type: application/json
866
+
867
+    {"status":"Pushing..."}
868
+    {"status":"Pushing", "progress":"1/? (n/a)", "progressDetail":{"current":1}}}
869
+    {"error":"Invalid..."}
870
+    ...
871
+
872
+   :query registry: the registry you wan to push, optional
873
+   :reqheader X-Registry-Auth: include a base64-encoded AuthConfig object.
874
+   :statuscode 200: no error
875
+   :statuscode 404: no such image
876
+   :statuscode 500: server error
877
+
878
+
879
+Tag an image into a repository
880
+******************************
881
+
882
+.. http:post:: /images/(name)/tag
883
+
884
+        Tag the image ``name`` into a repository
885
+
886
+        **Example request**:
887
+
888
+        .. sourcecode:: http
889
+
890
+           POST /images/test/tag?repo=myrepo&force=0 HTTP/1.1
891
+
892
+        **Example response**:
893
+
894
+        .. sourcecode:: http
895
+
896
+           HTTP/1.1 201 OK
897
+
898
+        :query repo: The repository to tag in
899
+        :query force: 1/True/true or 0/False/false, default false
900
+        :statuscode 201: no error
901
+        :statuscode 400: bad parameter
902
+        :statuscode 404: no such image
903
+        :statuscode 409: conflict
904
+        :statuscode 500: server error
905
+
906
+
907
+Remove an image
908
+***************
909
+
910
+.. http:delete:: /images/(name)
911
+
912
+        Remove the image ``name`` from the filesystem
913
+
914
+        **Example request**:
915
+
916
+        .. sourcecode:: http
917
+
918
+           DELETE /images/test HTTP/1.1
919
+
920
+        **Example response**:
921
+
922
+        .. sourcecode:: http
923
+
924
+           HTTP/1.1 200 OK
925
+           Content-type: application/json
926
+
927
+           [
928
+            {"Untagged":"3e2f21a89f"},
929
+            {"Deleted":"3e2f21a89f"},
930
+            {"Deleted":"53b4f83ac9"}
931
+           ]
932
+
933
+        :query force: 1/True/true or 0/False/false, default false
934
+        :query noprune: 1/True/true or 0/False/false, default false
935
+        :statuscode 200: no error
936
+        :statuscode 404: no such image
937
+        :statuscode 409: conflict
938
+        :statuscode 500: server error
939
+
940
+
941
+Search images
942
+*************
943
+
944
+.. http:get:: /images/search
945
+
946
+        Search for an image in the docker index.
947
+
948
+        .. note::
949
+
950
+           The response keys have changed from API v1.6 to reflect the JSON
951
+           sent by the registry server to the docker daemon's request.
952
+
953
+        **Example request**:
954
+
955
+        .. sourcecode:: http
956
+
957
+           GET /images/search?term=sshd HTTP/1.1
958
+
959
+        **Example response**:
960
+
961
+        .. sourcecode:: http
962
+
963
+           HTTP/1.1 200 OK
964
+           Content-Type: application/json
965
+
966
+           [
967
+                   {
968
+                       "description": "",
969
+                       "is_official": false,
970
+                       "is_trusted": false,
971
+                       "name": "wma55/u1210sshd",
972
+                       "star_count": 0
973
+                   },
974
+                   {
975
+                       "description": "",
976
+                       "is_official": false,
977
+                       "is_trusted": false,
978
+                       "name": "jdswinbank/sshd",
979
+                       "star_count": 0
980
+                   },
981
+                   {
982
+                       "description": "",
983
+                       "is_official": false,
984
+                       "is_trusted": false,
985
+                       "name": "vgauthier/sshd",
986
+                       "star_count": 0
987
+                   }
988
+           ...
989
+           ]
990
+
991
+        :query term: term to search
992
+        :statuscode 200: no error
993
+        :statuscode 500: server error
994
+
995
+
996
+2.3 Misc
997
+--------
998
+
999
+Build an image from Dockerfile via stdin
1000
+****************************************
1001
+
1002
+.. http:post:: /build
1003
+
1004
+   Build an image from Dockerfile via stdin
1005
+
1006
+   **Example request**:
1007
+
1008
+   .. sourcecode:: http
1009
+
1010
+      POST /build HTTP/1.1
1011
+
1012
+      {{ STREAM }}
1013
+
1014
+   **Example response**:
1015
+
1016
+   .. sourcecode:: http
1017
+
1018
+      HTTP/1.1 200 OK
1019
+      Content-Type: application/json
1020
+
1021
+      {"stream":"Step 1..."}
1022
+      {"stream":"..."}
1023
+      {"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}}
1024
+
1025
+
1026
+   The stream must be a tar archive compressed with one of the
1027
+   following algorithms: identity (no compression), gzip, bzip2,
1028
+   xz.
1029
+
1030
+   The archive must include a file called ``Dockerfile`` at its
1031
+   root. It may include any number of other files, which will be
1032
+   accessible in the build context (See the :ref:`ADD build command
1033
+   <dockerbuilder>`).
1034
+
1035
+   :query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
1036
+   :query q: suppress verbose build output
1037
+   :query nocache: do not use the cache when building the image
1038
+   :reqheader Content-type: should be set to ``"application/tar"``.
1039
+   :reqheader X-Registry-Config: base64-encoded ConfigFile object
1040
+   :statuscode 200: no error
1041
+   :statuscode 500: server error
1042
+
1043
+
1044
+
1045
+Check auth configuration
1046
+************************
1047
+
1048
+.. http:post:: /auth
1049
+
1050
+        Get the default username and email
1051
+
1052
+        **Example request**:
1053
+
1054
+        .. sourcecode:: http
1055
+
1056
+           POST /auth HTTP/1.1
1057
+           Content-Type: application/json
1058
+
1059
+           {
1060
+                "username":"hannibal",
1061
+                "password:"xxxx",
1062
+                "email":"hannibal@a-team.com",
1063
+                "serveraddress":"https://index.docker.io/v1/"
1064
+           }
1065
+
1066
+        **Example response**:
1067
+
1068
+        .. sourcecode:: http
1069
+
1070
+           HTTP/1.1 200 OK
1071
+
1072
+        :statuscode 200: no error
1073
+        :statuscode 204: no error
1074
+        :statuscode 500: server error
1075
+
1076
+
1077
+Display system-wide information
1078
+*******************************
1079
+
1080
+.. http:get:: /info
1081
+
1082
+        Display system-wide information
1083
+
1084
+        **Example request**:
1085
+
1086
+        .. sourcecode:: http
1087
+
1088
+           GET /info HTTP/1.1
1089
+
1090
+        **Example response**:
1091
+
1092
+        .. sourcecode:: http
1093
+
1094
+           HTTP/1.1 200 OK
1095
+           Content-Type: application/json
1096
+
1097
+           {
1098
+                "Containers":11,
1099
+                "Images":16,
1100
+                "Debug":false,
1101
+                "NFd": 11,
1102
+                "NGoroutines":21,
1103
+                "MemoryLimit":true,
1104
+                "SwapLimit":false,
1105
+                "IPv4Forwarding":true
1106
+           }
1107
+
1108
+        :statuscode 200: no error
1109
+        :statuscode 500: server error
1110
+
1111
+
1112
+Show the docker version information
1113
+***********************************
1114
+
1115
+.. http:get:: /version
1116
+
1117
+        Show the docker version information
1118
+
1119
+        **Example request**:
1120
+
1121
+        .. sourcecode:: http
1122
+
1123
+           GET /version HTTP/1.1
1124
+
1125
+        **Example response**:
1126
+
1127
+        .. sourcecode:: http
1128
+
1129
+           HTTP/1.1 200 OK
1130
+           Content-Type: application/json
1131
+
1132
+           {
1133
+                "Version":"0.2.2",
1134
+                "GitCommit":"5a2a5cc+CHANGES",
1135
+                "GoVersion":"go1.0.3"
1136
+           }
1137
+
1138
+        :statuscode 200: no error
1139
+        :statuscode 500: server error
1140
+
1141
+
1142
+Create a new image from a container's changes
1143
+*********************************************
1144
+
1145
+.. http:post:: /commit
1146
+
1147
+    Create a new image from a container's changes
1148
+
1149
+    **Example request**:
1150
+
1151
+    .. sourcecode:: http
1152
+
1153
+        POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
1154
+
1155
+    **Example response**:
1156
+
1157
+    .. sourcecode:: http
1158
+
1159
+        HTTP/1.1 201 OK
1160
+            Content-Type: application/vnd.docker.raw-stream
1161
+
1162
+        {"Id":"596069db4bf5"}
1163
+
1164
+    :query container: source container
1165
+    :query repo: repository
1166
+    :query tag: tag
1167
+    :query m: commit message
1168
+    :query author: author (eg. "John Hannibal Smith <hannibal@a-team.com>")
1169
+    :query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]})
1170
+    :statuscode 201: no error
1171
+    :statuscode 404: no such container
1172
+    :statuscode 500: server error
1173
+
1174
+
1175
+Monitor Docker's events
1176
+***********************
1177
+
1178
+.. http:get:: /events
1179
+
1180
+        Get events from docker, either in real time via streaming, or via polling (using `since`)
1181
+
1182
+        **Example request**:
1183
+
1184
+        .. sourcecode:: http
1185
+
1186
+           GET /events?since=1374067924
1187
+
1188
+        **Example response**:
1189
+
1190
+        .. sourcecode:: http
1191
+
1192
+           HTTP/1.1 200 OK
1193
+           Content-Type: application/json
1194
+
1195
+           {"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
1196
+           {"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
1197
+           {"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966}
1198
+           {"status":"destroy","id":"dfdf82bd3881","from":"base:latest","time":1374067970}
1199
+
1200
+        :query since: timestamp used for polling
1201
+        :query until: timestamp used for polling
1202
+        :statuscode 200: no error
1203
+        :statuscode 500: server error
1204
+
1205
+Get a tarball containing all images and tags in a repository
1206
+************************************************************
1207
+
1208
+.. http:get:: /images/(name)/get
1209
+
1210
+        Get a tarball containing all images and metadata for the repository specified by ``name``.
1211
+
1212
+        **Example request**
1213
+
1214
+        .. sourcecode:: http
1215
+
1216
+           GET /images/ubuntu/get
1217
+
1218
+        **Example response**:
1219
+
1220
+        .. sourcecode:: http
1221
+
1222
+           HTTP/1.1 200 OK
1223
+           Content-Type: application/x-tar
1224
+
1225
+           Binary data stream
1226
+
1227
+        :statuscode 200: no error
1228
+        :statuscode 500: server error
1229
+
1230
+Load a tarball with a set of images and tags into docker
1231
+********************************************************
1232
+
1233
+.. http:post:: /images/load
1234
+
1235
+   Load a set of images and tags into the docker repository.
1236
+
1237
+   **Example request**
1238
+
1239
+   .. sourcecode:: http
1240
+
1241
+      POST /images/load
1242
+
1243
+      Tarball in body
1244
+
1245
+   **Example response**:
1246
+
1247
+   .. sourcecode:: http
1248
+
1249
+      HTTP/1.1 200 OK
1250
+
1251
+   :statuscode 200: no error
1252
+   :statuscode 500: server error
1253
+
1254
+3. Going further
1255
+================
1256
+
1257
+3.1 Inside 'docker run'
1258
+-----------------------
1259
+
1260
+Here are the steps of 'docker run' :
1261
+
1262
+* Create the container
1263
+* If the status code is 404, it means the image doesn't exists:
1264
+        * Try to pull it
1265
+        * Then retry to create the container
1266
+* Start the container
1267
+* If you are not in detached mode:
1268
+        * Attach to the container, using logs=1 (to have stdout and stderr from the container's start) and stream=1
1269
+* If in detached mode or only stdin is attached:
1270
+        * Display the container's id
1271
+
1272
+
1273
+3.2 Hijacking
1274
+-------------
1275
+
1276
+In this version of the API, /attach, uses hijacking to transport stdin, stdout and stderr on the same socket. This might change in the future.
1277
+
1278
+3.3 CORS Requests
1279
+-----------------
1280
+
1281
+To enable cross origin requests to the remote api add the flag "--api-enable-cors" when running docker in daemon mode.
1282
+
1283
+.. code-block:: bash
1284
+
1285
+   docker -d -H="192.168.1.9:4243" --api-enable-cors
... ...
@@ -490,7 +490,9 @@ For example:
490 490
 
491 491
     Get real time events from the server
492 492
 
493
-    --since="": Show previously created events and then stream.
493
+    --since="": Show all events created since timestamp
494
+               (either seconds since epoch, or date string as below)
495
+    --until="": Show events created before timestamp
494 496
                (either seconds since epoch, or date string as below)
495 497
 
496 498
 .. _cli_events_example:
... ...
@@ -220,8 +220,10 @@ func (srv *Server) Events(job *engine.Job) engine.Status {
220 220
 	}
221 221
 
222 222
 	var (
223
-		from  = job.Args[0]
224
-		since = job.GetenvInt64("since")
223
+		from    = job.Args[0]
224
+		since   = job.GetenvInt64("since")
225
+		until   = job.GetenvInt64("until")
226
+		timeout = time.NewTimer(time.Unix(until, 0).Sub(time.Now()))
225 227
 	)
226 228
 	sendEvent := func(event *utils.JSONMessage) error {
227 229
 		b, err := json.Marshal(event)
... ...
@@ -250,9 +252,9 @@ func (srv *Server) Events(job *engine.Job) engine.Status {
250 250
 	srv.Unlock()
251 251
 	job.Stdout.Write(nil) // flush
252 252
 	if since != 0 {
253
-		// If since, send previous events that happened after the timestamp
253
+		// If since, send previous events that happened after the timestamp and until timestamp
254 254
 		for _, event := range srv.GetEvents() {
255
-			if event.Time >= since {
255
+			if event.Time >= since && (event.Time <= until || until == 0) {
256 256
 				err := sendEvent(&event)
257 257
 				if err != nil && err.Error() == "JSON error" {
258 258
 					continue
... ...
@@ -264,13 +266,23 @@ func (srv *Server) Events(job *engine.Job) engine.Status {
264 264
 			}
265 265
 		}
266 266
 	}
267
-	for event := range listener {
268
-		err := sendEvent(&event)
269
-		if err != nil && err.Error() == "JSON error" {
270
-			continue
271
-		}
272
-		if err != nil {
273
-			return job.Error(err)
267
+
268
+	// If no until, disable timeout
269
+	if until == 0 {
270
+		timeout.Stop()
271
+	}
272
+	for {
273
+		select {
274
+		case event := <-listener:
275
+			err := sendEvent(&event)
276
+			if err != nil && err.Error() == "JSON error" {
277
+				continue
278
+			}
279
+			if err != nil {
280
+				return job.Error(err)
281
+			}
282
+		case <-timeout.C:
283
+			return engine.StatusOK
274 284
 		}
275 285
 	}
276 286
 	return engine.StatusOK