... | ... |
@@ -9,6 +9,7 @@ import ( |
9 | 9 |
"net/http" |
10 | 10 |
"os" |
11 | 11 |
"runtime" |
12 |
+ "strconv" |
|
12 | 13 |
"strings" |
13 | 14 |
"time" |
14 | 15 |
) |
... | ... |
@@ -17,56 +18,42 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
17 | 17 |
r := mux.NewRouter() |
18 | 18 |
log.Printf("Listening for HTTP on %s\n", addr) |
19 | 19 |
|
20 |
- r.Path("/version").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
20 |
+ r.Path("/version").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
21 |
+ log.Println(r.RequestURI) |
|
21 | 22 |
m := VersionOut{VERSION, GIT_COMMIT, NO_MEMORY_LIMIT} |
22 | 23 |
b, err := json.Marshal(m) |
23 | 24 |
if err != nil { |
24 |
- w.WriteHeader(500) |
|
25 |
+ http.Error(w, err.Error(), http.StatusInternalServerError) |
|
25 | 26 |
} else { |
26 | 27 |
w.Write(b) |
27 | 28 |
} |
28 | 29 |
}) |
29 | 30 |
|
30 |
- r.Path("/kill").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
31 |
- var ids []string |
|
32 |
- if err := json.NewDecoder(r.Body).Decode(&ids); err != nil { |
|
33 |
- w.WriteHeader(500) |
|
34 |
- return |
|
35 |
- } |
|
36 |
- |
|
37 |
- var ret SimpleMessage |
|
38 |
- for _, name := range ids { |
|
39 |
- container := rtime.Get(name) |
|
40 |
- if container == nil { |
|
41 |
- ret.Message = "No such container: " + name + "\n" |
|
42 |
- break |
|
43 |
- } |
|
44 |
- if err := container.Kill(); err != nil { |
|
45 |
- ret.Message = ret.Message + "Error killing container " + name + ": " + err.Error() + "\n" |
|
46 |
- } |
|
47 |
- } |
|
48 |
- if ret.Message == "" { |
|
49 |
- w.WriteHeader(200) |
|
50 |
- } else { |
|
51 |
- w.WriteHeader(500) |
|
52 |
- } |
|
53 |
- |
|
54 |
- b, err := json.Marshal(ret) |
|
55 |
- if err != nil { |
|
56 |
- w.WriteHeader(500) |
|
57 |
- } else { |
|
58 |
- w.Write(b) |
|
59 |
- } |
|
60 |
- |
|
31 |
+ r.Path("/containers/{name:.*}/kill").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
32 |
+ log.Println(r.RequestURI) |
|
33 |
+ vars := mux.Vars(r) |
|
34 |
+ name := vars["name"] |
|
35 |
+ if container := rtime.Get(name); container != nil { |
|
36 |
+ if err := container.Kill(); err != nil { |
|
37 |
+ http.Error(w, "Error restarting container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
38 |
+ return |
|
39 |
+ } |
|
40 |
+ } else { |
|
41 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
42 |
+ return |
|
43 |
+ } |
|
44 |
+ w.WriteHeader(200) |
|
61 | 45 |
}) |
62 | 46 |
|
63 |
- r.Path("/images").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
64 |
- var in ImagesIn |
|
65 |
- json.NewDecoder(r.Body).Decode(&in) |
|
47 |
+ r.Path("/images").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
48 |
+ log.Println(r.RequestURI) |
|
49 |
+ All := r.Form.Get("all") |
|
50 |
+ NameFilter := r.Form.Get("filter") |
|
51 |
+ Quiet := r.Form.Get("quiet") |
|
66 | 52 |
|
67 | 53 |
var allImages map[string]*Image |
68 | 54 |
var err error |
69 |
- if in.All { |
|
55 |
+ if All == "true" { |
|
70 | 56 |
allImages, err = rtime.graph.Map() |
71 | 57 |
} else { |
72 | 58 |
allImages, err = rtime.graph.Heads() |
... | ... |
@@ -77,7 +64,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
77 | 77 |
} |
78 | 78 |
var outs []ImagesOut |
79 | 79 |
for name, repository := range rtime.repositories.Repositories { |
80 |
- if in.NameFilter != "" && name != in.NameFilter { |
|
80 |
+ if NameFilter != "" && name != NameFilter { |
|
81 | 81 |
continue |
82 | 82 |
} |
83 | 83 |
for tag, id := range repository { |
... | ... |
@@ -88,7 +75,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
88 | 88 |
continue |
89 | 89 |
} |
90 | 90 |
delete(allImages, id) |
91 |
- if !in.Quiet { |
|
91 |
+ if Quiet != "true" { |
|
92 | 92 |
out.Repository = name |
93 | 93 |
out.Tag = tag |
94 | 94 |
out.Id = TruncateId(id) |
... | ... |
@@ -100,10 +87,10 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
100 | 100 |
} |
101 | 101 |
} |
102 | 102 |
// Display images which aren't part of a |
103 |
- if in.NameFilter == "" { |
|
103 |
+ if NameFilter == "" { |
|
104 | 104 |
for id, image := range allImages { |
105 | 105 |
var out ImagesOut |
106 |
- if !in.Quiet { |
|
106 |
+ if Quiet != "true" { |
|
107 | 107 |
out.Repository = "<none>" |
108 | 108 |
out.Tag = "<none>" |
109 | 109 |
out.Id = TruncateId(id) |
... | ... |
@@ -121,10 +108,10 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
121 | 121 |
} else { |
122 | 122 |
w.Write(b) |
123 | 123 |
} |
124 |
- |
|
125 | 124 |
}) |
126 | 125 |
|
127 |
- r.Path("/info").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
126 |
+ r.Path("/info").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
127 |
+ log.Println(r.RequestURI) |
|
128 | 128 |
images, _ := rtime.graph.All() |
129 | 129 |
var imgcount int |
130 | 130 |
if images == nil { |
... | ... |
@@ -149,13 +136,12 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
149 | 149 |
} |
150 | 150 |
}) |
151 | 151 |
|
152 |
- r.Path("/history").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
152 |
+ r.Path("/images/{name:.*}/history").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
153 | 153 |
log.Println(r.RequestURI) |
154 |
+ vars := mux.Vars(r) |
|
155 |
+ name := vars["name"] |
|
154 | 156 |
|
155 |
- var in HistoryIn |
|
156 |
- json.NewDecoder(r.Body).Decode(&in) |
|
157 |
- |
|
158 |
- image, err := rtime.repositories.LookupImage(in.Name) |
|
157 |
+ image, err := rtime.repositories.LookupImage(name) |
|
159 | 158 |
if err != nil { |
160 | 159 |
http.Error(w, err.Error(), http.StatusInternalServerError) |
161 | 160 |
return |
... | ... |
@@ -175,15 +161,14 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
175 | 175 |
} else { |
176 | 176 |
w.Write(b) |
177 | 177 |
} |
178 |
- |
|
179 | 178 |
}) |
180 | 179 |
|
181 |
- r.Path("/logs").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
182 |
- |
|
183 |
- var in LogsIn |
|
184 |
- json.NewDecoder(r.Body).Decode(&in) |
|
180 |
+ r.Path("/containers/{name:.*}/logs").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
181 |
+ log.Println(r.RequestURI) |
|
182 |
+ vars := mux.Vars(r) |
|
183 |
+ name := vars["name"] |
|
185 | 184 |
|
186 |
- if container := rtime.Get(in.Name); container != nil { |
|
185 |
+ if container := rtime.Get(name); container != nil { |
|
187 | 186 |
var out LogsOut |
188 | 187 |
|
189 | 188 |
logStdout, err := container.ReadLog("stdout") |
... | ... |
@@ -220,28 +205,34 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
220 | 220 |
} |
221 | 221 |
|
222 | 222 |
} else { |
223 |
- http.Error(w, "No such container: "+in.Name, http.StatusInternalServerError) |
|
223 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
224 | 224 |
} |
225 | 225 |
}) |
226 | 226 |
|
227 |
- r.Path("/ps").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
228 |
- var in PsIn |
|
229 |
- json.NewDecoder(r.Body).Decode(&in) |
|
230 |
- |
|
227 |
+ r.Path("/containers").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
228 |
+ log.Println(r.RequestURI) |
|
229 |
+ All := r.Form.Get("all") |
|
230 |
+ NoTrunc := r.Form.Get("notrunc") |
|
231 |
+ Quiet := r.Form.Get("quiet") |
|
232 |
+ Last := r.Form.Get("n") |
|
233 |
+ n, err := strconv.Atoi(Last) |
|
234 |
+ if err != nil { |
|
235 |
+ n = -1 |
|
236 |
+ } |
|
231 | 237 |
var outs []PsOut |
232 | 238 |
|
233 | 239 |
for i, container := range rtime.List() { |
234 |
- if !container.State.Running && !in.All && in.Last == -1 { |
|
240 |
+ if !container.State.Running && All != "true" && n == -1 { |
|
235 | 241 |
continue |
236 | 242 |
} |
237 |
- if i == in.Last { |
|
243 |
+ if i == n { |
|
238 | 244 |
break |
239 | 245 |
} |
240 | 246 |
var out PsOut |
241 | 247 |
out.Id = container.ShortId() |
242 |
- if !in.Quiet { |
|
248 |
+ if Quiet != "true" { |
|
243 | 249 |
command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")) |
244 |
- if !in.Full { |
|
250 |
+ if NoTrunc != "true" { |
|
245 | 251 |
command = Trunc(command, 20) |
246 | 252 |
} |
247 | 253 |
out.Image = rtime.repositories.ImageName(container.Image) |
... | ... |
@@ -258,173 +249,88 @@ func ListenAndServe(addr string, rtime *Runtime) error { |
258 | 258 |
} else { |
259 | 259 |
w.Write(b) |
260 | 260 |
} |
261 |
- |
|
262 | 261 |
}) |
263 | 262 |
|
264 |
- r.Path("/restart").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
265 |
- var ins, outs []string |
|
266 |
- json.NewDecoder(r.Body).Decode(&ins) |
|
267 |
- |
|
268 |
- for _, name := range ins { |
|
269 |
- if container := rtime.Get(name); container != nil { |
|
270 |
- if err := container.Restart(); err != nil { |
|
271 |
- http.Error(w, "Error restaring container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
272 |
- return |
|
273 |
- } |
|
274 |
- outs = append(outs, container.ShortId()) |
|
275 |
- } else { |
|
276 |
- http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
263 |
+ r.Path("/containers/{name:.*}/restart").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
264 |
+ log.Println(r.RequestURI) |
|
265 |
+ vars := mux.Vars(r) |
|
266 |
+ name := vars["name"] |
|
267 |
+ if container := rtime.Get(name); container != nil { |
|
268 |
+ if err := container.Restart(); err != nil { |
|
269 |
+ http.Error(w, "Error restarting container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
277 | 270 |
return |
278 | 271 |
} |
279 |
- } |
|
280 |
- b, err := json.Marshal(outs) |
|
281 |
- if err != nil { |
|
282 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
283 | 272 |
} else { |
284 |
- w.Write(b) |
|
285 |
- } |
|
286 |
- }) |
|
287 |
- |
|
288 |
- r.Path("/rm").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
289 |
- var ins, outs []string |
|
290 |
- json.NewDecoder(r.Body).Decode(&ins) |
|
291 |
- |
|
292 |
- for _, name := range ins { |
|
293 |
- if container := rtime.Get(name); container != nil { |
|
294 |
- if err := rtime.Destroy(container); err != nil { |
|
295 |
- http.Error(w, "Error destroying container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
296 |
- return |
|
297 |
- } |
|
298 |
- outs = append(outs, container.ShortId()) |
|
299 |
- } else { |
|
300 |
- http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
301 |
- return |
|
302 |
- } |
|
303 |
- } |
|
304 |
- b, err := json.Marshal(outs) |
|
305 |
- if err != nil { |
|
306 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
307 |
- } else { |
|
308 |
- w.Write(b) |
|
273 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
274 |
+ return |
|
309 | 275 |
} |
310 |
- |
|
276 |
+ w.WriteHeader(200) |
|
311 | 277 |
}) |
312 | 278 |
|
313 |
- r.Path("/rmi").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
314 |
- var ins, outs []string |
|
315 |
- json.NewDecoder(r.Body).Decode(&ins) |
|
316 |
- |
|
317 |
- for _, name := range ins { |
|
318 |
- img, err := rtime.repositories.LookupImage(name) |
|
319 |
- if err != nil { |
|
320 |
- http.Error(w, "No such image: "+name, http.StatusInternalServerError) |
|
279 |
+ r.Path("/containers/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
280 |
+ log.Println(r.RequestURI) |
|
281 |
+ vars := mux.Vars(r) |
|
282 |
+ name := vars["name"] |
|
283 |
+ if container := rtime.Get(name); container != nil { |
|
284 |
+ if err := rtime.Destroy(container); err != nil { |
|
285 |
+ http.Error(w, "Error destroying container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
321 | 286 |
return |
322 |
- } else { |
|
323 |
- if err := rtime.graph.Delete(img.Id); err != nil { |
|
324 |
- http.Error(w, "Error deleting image "+name+": "+err.Error(), http.StatusInternalServerError) |
|
325 |
- return |
|
326 |
- } |
|
327 |
- outs = append(outs, img.ShortId()) |
|
328 | 287 |
} |
329 |
- } |
|
330 |
- b, err := json.Marshal(outs) |
|
331 |
- if err != nil { |
|
332 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
333 | 288 |
} else { |
334 |
- w.Write(b) |
|
289 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
290 |
+ return |
|
335 | 291 |
} |
336 |
- |
|
292 |
+ w.WriteHeader(200) |
|
337 | 293 |
}) |
338 | 294 |
|
339 |
- r.Path("/run").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
340 |
- |
|
341 |
- var config Config |
|
342 |
- json.NewDecoder(r.Body).Decode(&config) |
|
343 |
- |
|
344 |
- hj, ok := w.(http.Hijacker) |
|
345 |
- if !ok { |
|
346 |
- http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) |
|
347 |
- return |
|
348 |
- } |
|
349 |
- conn, bufrw, err := hj.Hijack() |
|
295 |
+ r.Path("/images/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
296 |
+ log.Println(r.RequestURI) |
|
297 |
+ vars := mux.Vars(r) |
|
298 |
+ name := vars["name"] |
|
299 |
+ |
|
300 |
+ img, err := rtime.repositories.LookupImage(name) |
|
350 | 301 |
if err != nil { |
351 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
302 |
+ http.Error(w, "No such image: "+name, http.StatusInternalServerError) |
|
352 | 303 |
return |
353 |
- } |
|
354 |
- defer conn.Close() |
|
355 |
- |
|
356 |
- //TODO config.Tty |
|
357 |
- |
|
358 |
- // Create new container |
|
359 |
- container, err := rtime.Create(&config) |
|
360 |
- if err != nil { |
|
361 |
- // If container not found, try to pull it |
|
362 |
- if rtime.graph.IsNotExist(err) { |
|
363 |
- bufrw.WriteString("Image " + config.Image + " not found, trying to pull it from registry.\r\n") |
|
364 |
- bufrw.Flush() |
|
365 |
- //TODO if err = srv.CmdPull(stdin, stdout, config.Image); err != nil { |
|
366 |
- //return err |
|
367 |
- //} |
|
368 |
- if container, err = rtime.Create(&config); err != nil { |
|
369 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
370 |
- return |
|
371 |
- } |
|
372 |
- } else { |
|
373 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
304 |
+ } else { |
|
305 |
+ if err := rtime.graph.Delete(img.Id); err != nil { |
|
306 |
+ http.Error(w, "Error deleting image "+name+": "+err.Error(), http.StatusInternalServerError) |
|
374 | 307 |
return |
375 | 308 |
} |
376 | 309 |
} |
377 |
- container = container |
|
310 |
+ w.WriteHeader(200) |
|
378 | 311 |
}) |
379 | 312 |
|
380 |
- r.Path("/start").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
381 |
- var ins, outs []string |
|
382 |
- json.NewDecoder(r.Body).Decode(&ins) |
|
383 |
- |
|
384 |
- for _, name := range ins { |
|
385 |
- if container := rtime.Get(name); container != nil { |
|
386 |
- if err := container.Start(); err != nil { |
|
387 |
- http.Error(w, "Error starting container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
388 |
- return |
|
389 |
- } |
|
390 |
- outs = append(outs, container.ShortId()) |
|
391 |
- } else { |
|
392 |
- http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
313 |
+ r.Path("/containers/{name:.*}/start").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
314 |
+ log.Println(r.RequestURI) |
|
315 |
+ vars := mux.Vars(r) |
|
316 |
+ name := vars["name"] |
|
317 |
+ if container := rtime.Get(name); container != nil { |
|
318 |
+ if err := container.Start(); err != nil { |
|
319 |
+ http.Error(w, "Error starting container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
393 | 320 |
return |
394 | 321 |
} |
395 |
- } |
|
396 |
- b, err := json.Marshal(outs) |
|
397 |
- if err != nil { |
|
398 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
399 | 322 |
} else { |
400 |
- w.Write(b) |
|
323 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
324 |
+ return |
|
401 | 325 |
} |
402 |
- |
|
326 |
+ w.WriteHeader(200) |
|
403 | 327 |
}) |
404 | 328 |
|
405 |
- r.Path("/stop").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
406 |
- var ins, outs []string |
|
407 |
- json.NewDecoder(r.Body).Decode(&ins) |
|
408 |
- |
|
409 |
- for _, name := range ins { |
|
410 |
- if container := rtime.Get(name); container != nil { |
|
411 |
- if err := container.Stop(); err != nil { |
|
412 |
- http.Error(w, "Error stopping container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
413 |
- return |
|
414 |
- } |
|
415 |
- outs = append(outs, container.ShortId()) |
|
416 |
- } else { |
|
417 |
- http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
329 |
+ r.Path("/containers/{name:.*}/stop").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
330 |
+ log.Println(r.RequestURI) |
|
331 |
+ vars := mux.Vars(r) |
|
332 |
+ name := vars["name"] |
|
333 |
+ if container := rtime.Get(name); container != nil { |
|
334 |
+ if err := container.Stop(); err != nil { |
|
335 |
+ http.Error(w, "Error stopping container "+name+": "+err.Error(), http.StatusInternalServerError) |
|
418 | 336 |
return |
419 | 337 |
} |
420 |
- } |
|
421 |
- b, err := json.Marshal(outs) |
|
422 |
- if err != nil { |
|
423 |
- http.Error(w, err.Error(), http.StatusInternalServerError) |
|
424 | 338 |
} else { |
425 |
- w.Write(b) |
|
339 |
+ http.Error(w, "No such container: "+name, http.StatusInternalServerError) |
|
340 |
+ return |
|
426 | 341 |
} |
427 |
- |
|
342 |
+ w.WriteHeader(200) |
|
428 | 343 |
}) |
429 | 344 |
|
430 | 345 |
return http.ListenAndServe(addr, r) |
... | ... |
@@ -1,21 +1,17 @@ |
1 | 1 |
package docker |
2 | 2 |
|
3 | 3 |
import ( |
4 |
- "bytes" |
|
4 |
+ _"bytes" |
|
5 | 5 |
"encoding/json" |
6 |
+ "flag" |
|
6 | 7 |
"fmt" |
7 |
- "github.com/dotcloud/docker/auth" |
|
8 |
- "github.com/dotcloud/docker/rcli" |
|
9 |
- "io" |
|
10 |
- "log" |
|
8 |
+ _"io" |
|
9 |
+ "io/ioutil" |
|
11 | 10 |
"net/http" |
12 | 11 |
"net/url" |
13 |
- "runtime" |
|
12 |
+ "os" |
|
14 | 13 |
"strconv" |
15 |
- "strings" |
|
16 | 14 |
"text/tabwriter" |
17 |
- "time" |
|
18 |
- "unicode" |
|
19 | 15 |
) |
20 | 16 |
|
21 | 17 |
const VERSION = "0.1.4" |
... | ... |
@@ -25,45 +21,70 @@ var ( |
25 | 25 |
NO_MEMORY_LIMIT bool |
26 | 26 |
) |
27 | 27 |
|
28 |
-func (srv *Server) Name() string { |
|
29 |
- return "docker" |
|
28 |
+func ParseCommands(args []string) error { |
|
29 |
+ |
|
30 |
+ cmds := map[string]func(args []string) error{ |
|
31 |
+ "images": CmdImages, |
|
32 |
+ "info": CmdInfo, |
|
33 |
+ "history": CmdHistory, |
|
34 |
+ "kill": CmdKill, |
|
35 |
+ "logs": CmdLogs, |
|
36 |
+ "ps": CmdPs, |
|
37 |
+ "restart": CmdRestart, |
|
38 |
+ "rm": CmdRm, |
|
39 |
+ "rmi": CmdRmi, |
|
40 |
+ "start": CmdStart, |
|
41 |
+ "stop": CmdStop, |
|
42 |
+ "version": CmdVersion, |
|
43 |
+ } |
|
44 |
+ |
|
45 |
+ if len(args) > 0 { |
|
46 |
+ cmd, exists := cmds[args[0]] |
|
47 |
+ if !exists { |
|
48 |
+ //TODO display commend not found |
|
49 |
+ return cmdHelp(args) |
|
50 |
+ } |
|
51 |
+ return cmd(args[1:]) |
|
52 |
+ } |
|
53 |
+ return cmdHelp(args) |
|
30 | 54 |
} |
31 | 55 |
|
32 |
-// FIXME: Stop violating DRY by repeating usage here and in Subcmd declarations |
|
33 |
-func (srv *Server) Help() string { |
|
56 |
+func cmdHelp(args []string) error { |
|
34 | 57 |
help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n" |
35 | 58 |
for _, cmd := range [][]string{ |
36 |
- {"attach", "Attach to a running container"}, |
|
37 |
- {"commit", "Create a new image from a container's changes"}, |
|
38 |
- {"diff", "Inspect changes on a container's filesystem"}, |
|
39 |
- {"export", "Stream the contents of a container as a tar archive"}, |
|
59 |
+ // {"attach", "Attach to a running container"}, |
|
60 |
+ // {"commit", "Create a new image from a container's changes"}, |
|
61 |
+ // {"diff", "Inspect changes on a container's filesystem"}, |
|
62 |
+ // {"export", "Stream the contents of a container as a tar archive"}, |
|
40 | 63 |
{"history", "Show the history of an image"}, |
41 | 64 |
{"images", "List images"}, |
42 |
- {"import", "Create a new filesystem image from the contents of a tarball"}, |
|
65 |
+ // {"import", "Create a new filesystem image from the contents of a tarball"}, |
|
43 | 66 |
{"info", "Display system-wide information"}, |
44 |
- {"inspect", "Return low-level information on a container"}, |
|
67 |
+ // {"inspect", "Return low-level information on a container"}, |
|
45 | 68 |
{"kill", "Kill a running container"}, |
46 |
- {"login", "Register or Login to the docker registry server"}, |
|
69 |
+ // {"login", "Register or Login to the docker registry server"}, |
|
47 | 70 |
{"logs", "Fetch the logs of a container"}, |
48 |
- {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, |
|
71 |
+ // {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, |
|
49 | 72 |
{"ps", "List containers"}, |
50 |
- {"pull", "Pull an image or a repository from the docker registry server"}, |
|
51 |
- {"push", "Push an image or a repository to the docker registry server"}, |
|
73 |
+ // {"pull", "Pull an image or a repository from the docker registry server"}, |
|
74 |
+ // {"push", "Push an image or a repository to the docker registry server"}, |
|
52 | 75 |
{"restart", "Restart a running container"}, |
53 | 76 |
{"rm", "Remove a container"}, |
54 | 77 |
{"rmi", "Remove an image"}, |
55 |
- {"run", "Run a command in a new container"}, |
|
78 |
+ // {"run", "Run a command in a new container"}, |
|
56 | 79 |
{"start", "Start a stopped container"}, |
57 | 80 |
{"stop", "Stop a running container"}, |
58 |
- {"tag", "Tag an image into a repository"}, |
|
81 |
+ // {"tag", "Tag an image into a repository"}, |
|
59 | 82 |
{"version", "Show the docker version information"}, |
60 |
- {"wait", "Block until a container stops, then print its exit code"}, |
|
83 |
+ // {"wait", "Block until a container stops, then print its exit code"}, |
|
61 | 84 |
} { |
62 | 85 |
help += fmt.Sprintf(" %-10.10s%s\n", cmd[0], cmd[1]) |
63 | 86 |
} |
64 |
- return help |
|
87 |
+ fmt.Println(help) |
|
88 |
+ return nil |
|
65 | 89 |
} |
66 | 90 |
|
91 |
+/* |
|
67 | 92 |
// 'docker login': login / register a user to registry service. |
68 | 93 |
func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
69 | 94 |
// Read a line on raw terminal with support for simple backspace |
... | ... |
@@ -161,7 +182,9 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args .. |
161 | 161 |
} |
162 | 162 |
return nil |
163 | 163 |
} |
164 |
+*/ |
|
164 | 165 |
|
166 |
+/* |
|
165 | 167 |
// 'docker wait': block until a container stops |
166 | 168 |
func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
167 | 169 |
cmd := rcli.Subcmd(stdout, "wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.") |
... | ... |
@@ -181,27 +204,42 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string |
181 | 181 |
} |
182 | 182 |
return nil |
183 | 183 |
} |
184 |
+*/ |
|
185 |
+ |
|
184 | 186 |
|
185 | 187 |
// 'docker version': show version information |
186 |
-func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
187 |
- fmt.Fprintf(stdout, "Version:%s\n", VERSION) |
|
188 |
- fmt.Fprintf(stdout, "Git Commit:%s\n", GIT_COMMIT) |
|
189 |
- if NO_MEMORY_LIMIT { |
|
190 |
- fmt.Fprintf(stdout, "Memory limit disabled\n") |
|
188 |
+func CmdVersion(args []string) error { |
|
189 |
+ cmd := Subcmd("version", "", "Show the docker version information.") |
|
190 |
+ if err := cmd.Parse(args); err != nil { |
|
191 |
+ return nil |
|
192 |
+ } |
|
193 |
+ if cmd.NArg() > 0 { |
|
194 |
+ cmd.Usage() |
|
195 |
+ return nil |
|
196 |
+ } |
|
197 |
+ |
|
198 |
+ body, err := call("GET", "version") |
|
199 |
+ if err != nil { |
|
200 |
+ return err |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ var out VersionOut |
|
204 |
+ err = json.Unmarshal(body, &out) |
|
205 |
+ if err != nil { |
|
206 |
+ return err |
|
207 |
+ } |
|
208 |
+ fmt.Println("Version:", out.Version) |
|
209 |
+ fmt.Println("Git Commit:", out.GitCommit) |
|
210 |
+ if out.MemoryLimitDisabled { |
|
211 |
+ fmt.Println("Memory limit disabled") |
|
191 | 212 |
} |
213 |
+ |
|
192 | 214 |
return nil |
193 | 215 |
} |
194 | 216 |
|
195 | 217 |
// 'docker info': display system-wide information. |
196 |
-func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
197 |
- images, _ := srv.runtime.graph.All() |
|
198 |
- var imgcount int |
|
199 |
- if images == nil { |
|
200 |
- imgcount = 0 |
|
201 |
- } else { |
|
202 |
- imgcount = len(images) |
|
203 |
- } |
|
204 |
- cmd := rcli.Subcmd(stdout, "info", "", "Display system-wide information.") |
|
218 |
+func CmdInfo(args []string) error { |
|
219 |
+ cmd := Subcmd("info", "", "Display system-wide information") |
|
205 | 220 |
if err := cmd.Parse(args); err != nil { |
206 | 221 |
return nil |
207 | 222 |
} |
... | ... |
@@ -209,21 +247,27 @@ func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string |
209 | 209 |
cmd.Usage() |
210 | 210 |
return nil |
211 | 211 |
} |
212 |
- fmt.Fprintf(stdout, "containers: %d\nversion: %s\nimages: %d\n", |
|
213 |
- len(srv.runtime.List()), |
|
214 |
- VERSION, |
|
215 |
- imgcount) |
|
216 | 212 |
|
217 |
- if !rcli.DEBUG_FLAG { |
|
218 |
- return nil |
|
213 |
+ body, err := call("GET", "info") |
|
214 |
+ if err != nil { |
|
215 |
+ return err |
|
216 |
+ } |
|
217 |
+ |
|
218 |
+ var out InfoOut |
|
219 |
+ err = json.Unmarshal(body, &out) |
|
220 |
+ if err != nil { |
|
221 |
+ return err |
|
222 |
+ } |
|
223 |
+ fmt.Printf("containers: %d\nversion: %s\nimages: %d\n", out.Containers, out.Version, out.Images) |
|
224 |
+ if out.Debug { |
|
225 |
+ fmt.Println("debug mode enabled") |
|
226 |
+ fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines) |
|
219 | 227 |
} |
220 |
- fmt.Fprintln(stdout, "debug mode enabled") |
|
221 |
- fmt.Fprintf(stdout, "fds: %d\ngoroutines: %d\n", getTotalUsedFds(), runtime.NumGoroutine()) |
|
222 | 228 |
return nil |
223 | 229 |
} |
224 | 230 |
|
225 |
-func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
226 |
- cmd := rcli.Subcmd(stdout, "stop", "CONTAINER [CONTAINER...]", "Stop a running container") |
|
231 |
+func CmdStop(args []string) error { |
|
232 |
+ cmd := Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container") |
|
227 | 233 |
if err := cmd.Parse(args); err != nil { |
228 | 234 |
return nil |
229 | 235 |
} |
... | ... |
@@ -231,21 +275,20 @@ func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string |
231 | 231 |
cmd.Usage() |
232 | 232 |
return nil |
233 | 233 |
} |
234 |
- for _, name := range cmd.Args() { |
|
235 |
- if container := srv.runtime.Get(name); container != nil { |
|
236 |
- if err := container.Stop(); err != nil { |
|
237 |
- return err |
|
238 |
- } |
|
239 |
- fmt.Fprintln(stdout, container.ShortId()) |
|
234 |
+ |
|
235 |
+ for _, name := range args { |
|
236 |
+ _, err := call("GET", "/containers/"+name+"/stop") |
|
237 |
+ if err != nil { |
|
238 |
+ fmt.Printf("%s", err) |
|
240 | 239 |
} else { |
241 |
- return fmt.Errorf("No such container: %s", name) |
|
240 |
+ fmt.Println(name) |
|
242 | 241 |
} |
243 | 242 |
} |
244 | 243 |
return nil |
245 | 244 |
} |
246 | 245 |
|
247 |
-func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
248 |
- cmd := rcli.Subcmd(stdout, "restart", "CONTAINER [CONTAINER...]", "Restart a running container") |
|
246 |
+func CmdRestart(args []string) error { |
|
247 |
+ cmd := Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container") |
|
249 | 248 |
if err := cmd.Parse(args); err != nil { |
250 | 249 |
return nil |
251 | 250 |
} |
... | ... |
@@ -253,21 +296,20 @@ func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...str |
253 | 253 |
cmd.Usage() |
254 | 254 |
return nil |
255 | 255 |
} |
256 |
- for _, name := range cmd.Args() { |
|
257 |
- if container := srv.runtime.Get(name); container != nil { |
|
258 |
- if err := container.Restart(); err != nil { |
|
259 |
- return err |
|
260 |
- } |
|
261 |
- fmt.Fprintln(stdout, container.ShortId()) |
|
256 |
+ |
|
257 |
+ for _, name := range args { |
|
258 |
+ _, err := call("GET", "/containers/"+name+"/restart") |
|
259 |
+ if err != nil { |
|
260 |
+ fmt.Printf("%s", err) |
|
262 | 261 |
} else { |
263 |
- return fmt.Errorf("No such container: %s", name) |
|
262 |
+ fmt.Println(name) |
|
264 | 263 |
} |
265 | 264 |
} |
266 | 265 |
return nil |
267 | 266 |
} |
268 | 267 |
|
269 |
-func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
270 |
- cmd := rcli.Subcmd(stdout, "start", "CONTAINER [CONTAINER...]", "Start a stopped container") |
|
268 |
+func CmdStart(args []string) error { |
|
269 |
+ cmd := Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container") |
|
271 | 270 |
if err := cmd.Parse(args); err != nil { |
272 | 271 |
return nil |
273 | 272 |
} |
... | ... |
@@ -275,19 +317,19 @@ func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...strin |
275 | 275 |
cmd.Usage() |
276 | 276 |
return nil |
277 | 277 |
} |
278 |
- for _, name := range cmd.Args() { |
|
279 |
- if container := srv.runtime.Get(name); container != nil { |
|
280 |
- if err := container.Start(); err != nil { |
|
281 |
- return err |
|
282 |
- } |
|
283 |
- fmt.Fprintln(stdout, container.ShortId()) |
|
278 |
+ |
|
279 |
+ for _, name := range args { |
|
280 |
+ _, err := call("GET", "/containers/"+name+"/start") |
|
281 |
+ if err != nil { |
|
282 |
+ fmt.Printf("%s", err) |
|
284 | 283 |
} else { |
285 |
- return fmt.Errorf("No such container: %s", name) |
|
284 |
+ fmt.Println(name) |
|
286 | 285 |
} |
287 | 286 |
} |
288 | 287 |
return nil |
289 | 288 |
} |
290 | 289 |
|
290 |
+/* |
|
291 | 291 |
func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
292 | 292 |
cmd := rcli.Subcmd(stdout, "inspect", "CONTAINER", "Return low-level information on a container") |
293 | 293 |
if err := cmd.Parse(args); err != nil { |
... | ... |
@@ -322,7 +364,9 @@ func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...str |
322 | 322 |
stdout.Write([]byte{'\n'}) |
323 | 323 |
return nil |
324 | 324 |
} |
325 |
+*/ |
|
325 | 326 |
|
327 |
+/* |
|
326 | 328 |
func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
327 | 329 |
cmd := rcli.Subcmd(stdout, "port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT") |
328 | 330 |
if err := cmd.Parse(args); err != nil { |
... | ... |
@@ -345,10 +389,11 @@ func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string |
345 | 345 |
} |
346 | 346 |
return nil |
347 | 347 |
} |
348 |
+*/ |
|
348 | 349 |
|
349 | 350 |
// 'docker rmi IMAGE' removes all images with the name IMAGE |
350 |
-func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) (err error) { |
|
351 |
- cmd := rcli.Subcmd(stdout, "rmimage", "IMAGE [IMAGE...]", "Remove an image") |
|
351 |
+func CmdRmi(args []string) error { |
|
352 |
+ cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image") |
|
352 | 353 |
if err := cmd.Parse(args); err != nil { |
353 | 354 |
return nil |
354 | 355 |
} |
... | ... |
@@ -356,20 +401,20 @@ func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) |
356 | 356 |
cmd.Usage() |
357 | 357 |
return nil |
358 | 358 |
} |
359 |
- for _, name := range cmd.Args() { |
|
360 |
- img, err := srv.runtime.repositories.LookupImage(name) |
|
359 |
+ |
|
360 |
+ for _, name := range args { |
|
361 |
+ _, err := call("DELETE", "/images/"+name) |
|
361 | 362 |
if err != nil { |
362 |
- return err |
|
363 |
- } |
|
364 |
- if err := srv.runtime.graph.Delete(img.Id); err != nil { |
|
365 |
- return err |
|
363 |
+ fmt.Printf("%s", err) |
|
364 |
+ } else { |
|
365 |
+ fmt.Println(name) |
|
366 | 366 |
} |
367 | 367 |
} |
368 | 368 |
return nil |
369 | 369 |
} |
370 | 370 |
|
371 |
-func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
372 |
- cmd := rcli.Subcmd(stdout, "history", "IMAGE", "Show the history of an image") |
|
371 |
+func CmdHistory(args []string) error { |
|
372 |
+ cmd := Subcmd("history", "IMAGE", "Show the history of an image") |
|
373 | 373 |
if err := cmd.Parse(args); err != nil { |
374 | 374 |
return nil |
375 | 375 |
} |
... | ... |
@@ -377,25 +422,29 @@ func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...str |
377 | 377 |
cmd.Usage() |
378 | 378 |
return nil |
379 | 379 |
} |
380 |
- image, err := srv.runtime.repositories.LookupImage(cmd.Arg(0)) |
|
380 |
+ |
|
381 |
+ body, err := call("GET", "images/"+cmd.Arg(0)+"/history") |
|
382 |
+ if err != nil { |
|
383 |
+ return err |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ var outs []HistoryOut |
|
387 |
+ err = json.Unmarshal(body, &outs) |
|
381 | 388 |
if err != nil { |
382 | 389 |
return err |
383 | 390 |
} |
384 |
- w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0) |
|
385 |
- defer w.Flush() |
|
391 |
+ w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
386 | 392 |
fmt.Fprintln(w, "ID\tCREATED\tCREATED BY") |
387 |
- return image.WalkHistory(func(img *Image) error { |
|
388 |
- fmt.Fprintf(w, "%s\t%s\t%s\n", |
|
389 |
- srv.runtime.repositories.ImageName(img.ShortId()), |
|
390 |
- HumanDuration(time.Now().Sub(img.Created))+" ago", |
|
391 |
- strings.Join(img.ContainerConfig.Cmd, " "), |
|
392 |
- ) |
|
393 |
- return nil |
|
394 |
- }) |
|
393 |
+ |
|
394 |
+ for _, out := range outs { |
|
395 |
+ fmt.Fprintf(w, "%s\t%s\t%s\n", out.Id, out.Created, out.CreatedBy) |
|
396 |
+ } |
|
397 |
+ w.Flush() |
|
398 |
+ return nil |
|
395 | 399 |
} |
396 | 400 |
|
397 |
-func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
398 |
- cmd := rcli.Subcmd(stdout, "rm", "CONTAINER [CONTAINER...]", "Remove a container") |
|
401 |
+func CmdRm(args []string) error { |
|
402 |
+ cmd := Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove a container") |
|
399 | 403 |
if err := cmd.Parse(args); err != nil { |
400 | 404 |
return nil |
401 | 405 |
} |
... | ... |
@@ -403,21 +452,21 @@ func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) |
403 | 403 |
cmd.Usage() |
404 | 404 |
return nil |
405 | 405 |
} |
406 |
- for _, name := range cmd.Args() { |
|
407 |
- container := srv.runtime.Get(name) |
|
408 |
- if container == nil { |
|
409 |
- return fmt.Errorf("No such container: %s", name) |
|
410 |
- } |
|
411 |
- if err := srv.runtime.Destroy(container); err != nil { |
|
412 |
- fmt.Fprintln(stdout, "Error destroying container "+name+": "+err.Error()) |
|
406 |
+ |
|
407 |
+ for _, name := range args { |
|
408 |
+ _, err := call("DELETE", "/containers/"+name) |
|
409 |
+ if err != nil { |
|
410 |
+ fmt.Printf("%s", err) |
|
411 |
+ } else { |
|
412 |
+ fmt.Println(name) |
|
413 | 413 |
} |
414 | 414 |
} |
415 | 415 |
return nil |
416 | 416 |
} |
417 | 417 |
|
418 | 418 |
// 'docker kill NAME' kills a running container |
419 |
-func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
420 |
- cmd := rcli.Subcmd(stdout, "kill", "CONTAINER [CONTAINER...]", "Kill a running container") |
|
419 |
+func CmdKill(args []string) error { |
|
420 |
+ cmd := Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container") |
|
421 | 421 |
if err := cmd.Parse(args); err != nil { |
422 | 422 |
return nil |
423 | 423 |
} |
... | ... |
@@ -425,18 +474,19 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string |
425 | 425 |
cmd.Usage() |
426 | 426 |
return nil |
427 | 427 |
} |
428 |
- for _, name := range cmd.Args() { |
|
429 |
- container := srv.runtime.Get(name) |
|
430 |
- if container == nil { |
|
431 |
- return fmt.Errorf("No such container: %s", name) |
|
432 |
- } |
|
433 |
- if err := container.Kill(); err != nil { |
|
434 |
- fmt.Fprintln(stdout, "Error killing container "+name+": "+err.Error()) |
|
428 |
+ |
|
429 |
+ for _, name := range args { |
|
430 |
+ _, err := call("POST", "/containers/"+name+"/kill") |
|
431 |
+ if err != nil { |
|
432 |
+ fmt.Printf("%s", err) |
|
433 |
+ } else { |
|
434 |
+ fmt.Println(name) |
|
435 | 435 |
} |
436 | 436 |
} |
437 | 437 |
return nil |
438 | 438 |
} |
439 | 439 |
|
440 |
+/* |
|
440 | 441 |
func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
441 | 442 |
stdout.Flush() |
442 | 443 |
cmd := rcli.Subcmd(stdout, "import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball") |
... | ... |
@@ -486,7 +536,9 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args . |
486 | 486 |
fmt.Fprintln(stdout, img.ShortId()) |
487 | 487 |
return nil |
488 | 488 |
} |
489 |
+*/ |
|
489 | 490 |
|
491 |
+/* |
|
490 | 492 |
func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
491 | 493 |
cmd := rcli.Subcmd(stdout, "push", "NAME", "Push an image or a repository to the registry") |
492 | 494 |
if err := cmd.Parse(args); err != nil { |
... | ... |
@@ -545,7 +597,9 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ... |
545 | 545 |
} |
546 | 546 |
return nil |
547 | 547 |
} |
548 |
+*/ |
|
548 | 549 |
|
550 |
+/* |
|
549 | 551 |
func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
550 | 552 |
cmd := rcli.Subcmd(stdout, "pull", "NAME", "Pull an image or a repository from the registry") |
551 | 553 |
if err := cmd.Parse(args); err != nil { |
... | ... |
@@ -570,12 +624,13 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string |
570 | 570 |
} |
571 | 571 |
return nil |
572 | 572 |
} |
573 |
+*/ |
|
573 | 574 |
|
574 |
-func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
575 |
- cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images") |
|
576 |
- //limit := cmd.Int("l", 0, "Only show the N most recent versions of each image") |
|
575 |
+func CmdImages(args []string) error { |
|
576 |
+ cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images") |
|
577 | 577 |
quiet := cmd.Bool("q", false, "only show numeric IDs") |
578 |
- flAll := cmd.Bool("a", false, "show all images") |
|
578 |
+ all := cmd.Bool("a", false, "show all images") |
|
579 |
+ |
|
579 | 580 |
if err := cmd.Parse(args); err != nil { |
580 | 581 |
return nil |
581 | 582 |
} |
... | ... |
@@ -583,137 +638,104 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri |
583 | 583 |
cmd.Usage() |
584 | 584 |
return nil |
585 | 585 |
} |
586 |
- var nameFilter string |
|
586 |
+ v := url.Values{} |
|
587 | 587 |
if cmd.NArg() == 1 { |
588 |
- nameFilter = cmd.Arg(0) |
|
588 |
+ v.Set("filter", cmd.Arg(0)) |
|
589 | 589 |
} |
590 |
- w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0) |
|
591 |
- if !*quiet { |
|
592 |
- fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") |
|
590 |
+ if *quiet { |
|
591 |
+ v.Set("quiet", "true") |
|
593 | 592 |
} |
594 |
- var allImages map[string]*Image |
|
595 |
- var err error |
|
596 |
- if *flAll { |
|
597 |
- allImages, err = srv.runtime.graph.Map() |
|
598 |
- } else { |
|
599 |
- allImages, err = srv.runtime.graph.Heads() |
|
593 |
+ if *all { |
|
594 |
+ v.Set("all", "true") |
|
600 | 595 |
} |
596 |
+ |
|
597 |
+ body, err := call("GET", "images?"+v.Encode()) |
|
601 | 598 |
if err != nil { |
602 | 599 |
return err |
603 | 600 |
} |
604 |
- for name, repository := range srv.runtime.repositories.Repositories { |
|
605 |
- if nameFilter != "" && name != nameFilter { |
|
606 |
- continue |
|
607 |
- } |
|
608 |
- for tag, id := range repository { |
|
609 |
- image, err := srv.runtime.graph.Get(id) |
|
610 |
- if err != nil { |
|
611 |
- log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err) |
|
612 |
- continue |
|
613 |
- } |
|
614 |
- delete(allImages, id) |
|
615 |
- if !*quiet { |
|
616 |
- for idx, field := range []string{ |
|
617 |
- /* REPOSITORY */ name, |
|
618 |
- /* TAG */ tag, |
|
619 |
- /* ID */ TruncateId(id), |
|
620 |
- /* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago", |
|
621 |
- } { |
|
622 |
- if idx == 0 { |
|
623 |
- w.Write([]byte(field)) |
|
624 |
- } else { |
|
625 |
- w.Write([]byte("\t" + field)) |
|
626 |
- } |
|
627 |
- } |
|
628 |
- w.Write([]byte{'\n'}) |
|
629 |
- } else { |
|
630 |
- stdout.Write([]byte(image.ShortId() + "\n")) |
|
631 |
- } |
|
632 |
- } |
|
601 |
+ |
|
602 |
+ var outs []ImagesOut |
|
603 |
+ err = json.Unmarshal(body, &outs) |
|
604 |
+ if err != nil { |
|
605 |
+ return err |
|
633 | 606 |
} |
634 |
- // Display images which aren't part of a |
|
635 |
- if nameFilter == "" { |
|
636 |
- for id, image := range allImages { |
|
637 |
- if !*quiet { |
|
638 |
- for idx, field := range []string{ |
|
639 |
- /* REPOSITORY */ "<none>", |
|
640 |
- /* TAG */ "<none>", |
|
641 |
- /* ID */ TruncateId(id), |
|
642 |
- /* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago", |
|
643 |
- } { |
|
644 |
- if idx == 0 { |
|
645 |
- w.Write([]byte(field)) |
|
646 |
- } else { |
|
647 |
- w.Write([]byte("\t" + field)) |
|
648 |
- } |
|
649 |
- } |
|
650 |
- w.Write([]byte{'\n'}) |
|
651 |
- } else { |
|
652 |
- stdout.Write([]byte(image.ShortId() + "\n")) |
|
653 |
- } |
|
607 |
+ w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
608 |
+ if !*quiet { |
|
609 |
+ fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") |
|
610 |
+ } |
|
611 |
+ |
|
612 |
+ for _, out := range outs { |
|
613 |
+ if !*quiet { |
|
614 |
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Repository, out.Tag, out.Id, out.Created) |
|
615 |
+ } else { |
|
616 |
+ fmt.Fprintln(w, out.Id) |
|
654 | 617 |
} |
655 | 618 |
} |
619 |
+ |
|
656 | 620 |
if !*quiet { |
657 | 621 |
w.Flush() |
658 | 622 |
} |
659 | 623 |
return nil |
660 | 624 |
} |
661 | 625 |
|
662 |
-func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
663 |
- cmd := rcli.Subcmd(stdout, |
|
664 |
- "ps", "[OPTIONS]", "List containers") |
|
626 |
+func CmdPs(args []string) error { |
|
627 |
+ cmd := Subcmd("ps", "[OPTIONS]", "List containers") |
|
665 | 628 |
quiet := cmd.Bool("q", false, "Only display numeric IDs") |
666 |
- flAll := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.") |
|
667 |
- flFull := cmd.Bool("notrunc", false, "Don't truncate output") |
|
668 |
- latest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.") |
|
669 |
- nLast := cmd.Int("n", -1, "Show n last created containers, include non-running ones.") |
|
629 |
+ all := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.") |
|
630 |
+ noTrunc := cmd.Bool("notrunc", false, "Don't truncate output") |
|
631 |
+ nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.") |
|
632 |
+ last := cmd.Int("n", -1, "Show n last created containers, include non-running ones.") |
|
633 |
+ |
|
670 | 634 |
if err := cmd.Parse(args); err != nil { |
671 | 635 |
return nil |
672 | 636 |
} |
673 |
- if *nLast == -1 && *latest { |
|
674 |
- *nLast = 1 |
|
637 |
+ v := url.Values{} |
|
638 |
+ if *last == -1 && *nLatest { |
|
639 |
+ *last = 1 |
|
640 |
+ } |
|
641 |
+ if *quiet { |
|
642 |
+ v.Set("quiet", "true") |
|
675 | 643 |
} |
676 |
- w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0) |
|
644 |
+ if *all { |
|
645 |
+ v.Set("all", "true") |
|
646 |
+ } |
|
647 |
+ if *noTrunc { |
|
648 |
+ v.Set("notrunc", "true") |
|
649 |
+ } |
|
650 |
+ if *last != -1 { |
|
651 |
+ v.Set("n", strconv.Itoa(*last)) |
|
652 |
+ } |
|
653 |
+ |
|
654 |
+ body, err := call("GET", "containers?"+v.Encode()) |
|
655 |
+ if err != nil { |
|
656 |
+ return err |
|
657 |
+ } |
|
658 |
+ |
|
659 |
+ var outs []PsOut |
|
660 |
+ err = json.Unmarshal(body, &outs) |
|
661 |
+ if err != nil { |
|
662 |
+ return err |
|
663 |
+ } |
|
664 |
+ w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
677 | 665 |
if !*quiet { |
678 |
- fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT") |
|
666 |
+ fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS") |
|
679 | 667 |
} |
680 |
- for i, container := range srv.runtime.List() { |
|
681 |
- if !container.State.Running && !*flAll && *nLast == -1 { |
|
682 |
- continue |
|
683 |
- } |
|
684 |
- if i == *nLast { |
|
685 |
- break |
|
686 |
- } |
|
668 |
+ |
|
669 |
+ for _, out := range outs { |
|
687 | 670 |
if !*quiet { |
688 |
- command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")) |
|
689 |
- if !*flFull { |
|
690 |
- command = Trunc(command, 20) |
|
691 |
- } |
|
692 |
- for idx, field := range []string{ |
|
693 |
- /* ID */ container.ShortId(), |
|
694 |
- /* IMAGE */ srv.runtime.repositories.ImageName(container.Image), |
|
695 |
- /* COMMAND */ command, |
|
696 |
- /* CREATED */ HumanDuration(time.Now().Sub(container.Created)) + " ago", |
|
697 |
- /* STATUS */ container.State.String(), |
|
698 |
- /* COMMENT */ "", |
|
699 |
- } { |
|
700 |
- if idx == 0 { |
|
701 |
- w.Write([]byte(field)) |
|
702 |
- } else { |
|
703 |
- w.Write([]byte("\t" + field)) |
|
704 |
- } |
|
705 |
- } |
|
706 |
- w.Write([]byte{'\n'}) |
|
671 |
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Id, out.Image, out.Command, out.Status, out.Created) |
|
707 | 672 |
} else { |
708 |
- stdout.Write([]byte(container.ShortId() + "\n")) |
|
673 |
+ fmt.Fprintln(w, out.Id) |
|
709 | 674 |
} |
710 | 675 |
} |
676 |
+ |
|
711 | 677 |
if !*quiet { |
712 | 678 |
w.Flush() |
713 | 679 |
} |
714 | 680 |
return nil |
715 | 681 |
} |
716 | 682 |
|
683 |
+/* |
|
717 | 684 |
func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
718 | 685 |
cmd := rcli.Subcmd(stdout, |
719 | 686 |
"commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]", |
... | ... |
@@ -734,7 +756,9 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri |
734 | 734 |
fmt.Fprintln(stdout, img.ShortId()) |
735 | 735 |
return nil |
736 | 736 |
} |
737 |
+*/ |
|
737 | 738 |
|
739 |
+/* |
|
738 | 740 |
func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
739 | 741 |
cmd := rcli.Subcmd(stdout, |
740 | 742 |
"export", "CONTAINER", |
... | ... |
@@ -756,7 +780,9 @@ func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...stri |
756 | 756 |
} |
757 | 757 |
return fmt.Errorf("No such container: %s", name) |
758 | 758 |
} |
759 |
+*/ |
|
759 | 760 |
|
761 |
+/* |
|
760 | 762 |
func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
761 | 763 |
cmd := rcli.Subcmd(stdout, |
762 | 764 |
"diff", "CONTAINER", |
... | ... |
@@ -781,9 +807,10 @@ func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string |
781 | 781 |
} |
782 | 782 |
return nil |
783 | 783 |
} |
784 |
+*/ |
|
784 | 785 |
|
785 |
-func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
|
786 |
- cmd := rcli.Subcmd(stdout, "logs", "CONTAINER", "Fetch the logs of a container") |
|
786 |
+func CmdLogs(args []string) error { |
|
787 |
+ cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container") |
|
787 | 788 |
if err := cmd.Parse(args); err != nil { |
788 | 789 |
return nil |
789 | 790 |
} |
... | ... |
@@ -791,29 +818,23 @@ func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string |
791 | 791 |
cmd.Usage() |
792 | 792 |
return nil |
793 | 793 |
} |
794 |
- name := cmd.Arg(0) |
|
795 |
- if container := srv.runtime.Get(name); container != nil { |
|
796 |
- logStdout, err := container.ReadLog("stdout") |
|
797 |
- if err != nil { |
|
798 |
- return err |
|
799 |
- } |
|
800 |
- logStderr, err := container.ReadLog("stderr") |
|
801 |
- if err != nil { |
|
802 |
- return err |
|
803 |
- } |
|
804 |
- // FIXME: Interpolate stdout and stderr instead of concatenating them |
|
805 |
- // FIXME: Differentiate stdout and stderr in the remote protocol |
|
806 |
- if _, err := io.Copy(stdout, logStdout); err != nil { |
|
807 |
- return err |
|
808 |
- } |
|
809 |
- if _, err := io.Copy(stdout, logStderr); err != nil { |
|
810 |
- return err |
|
811 |
- } |
|
812 |
- return nil |
|
794 |
+ body, err := call("GET", "containers/"+cmd.Arg(0)+"/logs") |
|
795 |
+ if err != nil { |
|
796 |
+ return err |
|
813 | 797 |
} |
814 |
- return fmt.Errorf("No such container: %s", cmd.Arg(0)) |
|
798 |
+ |
|
799 |
+ var out LogsOut |
|
800 |
+ err = json.Unmarshal(body, &out) |
|
801 |
+ if err != nil { |
|
802 |
+ return err |
|
803 |
+ } |
|
804 |
+ fmt.Fprintln(os.Stdout, out.Stdout) |
|
805 |
+ fmt.Fprintln(os.Stderr, out.Stderr) |
|
806 |
+ |
|
807 |
+ return nil |
|
815 | 808 |
} |
816 | 809 |
|
810 |
+/* |
|
817 | 811 |
func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
818 | 812 |
cmd := rcli.Subcmd(stdout, "attach", "CONTAINER", "Attach to a running container") |
819 | 813 |
if err := cmd.Parse(args); err != nil { |
... | ... |
@@ -836,7 +857,8 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args . |
836 | 836 |
stdout.Flush() |
837 | 837 |
return <-container.Attach(stdin, nil, stdout, stdout) |
838 | 838 |
} |
839 |
- |
|
839 |
+*/ |
|
840 |
+/* |
|
840 | 841 |
// Ports type - Used to parse multiple -p flags |
841 | 842 |
type ports []int |
842 | 843 |
|
... | ... |
@@ -852,6 +874,7 @@ func (p *ports) Set(value string) error { |
852 | 852 |
*p = append(*p, port) |
853 | 853 |
return nil |
854 | 854 |
} |
855 |
+*/ |
|
855 | 856 |
|
856 | 857 |
// ListOpts type |
857 | 858 |
type ListOpts []string |
... | ... |
@@ -892,6 +915,8 @@ func (opts AttachOpts) Get(val string) bool { |
892 | 892 |
return false |
893 | 893 |
} |
894 | 894 |
|
895 |
+ |
|
896 |
+/* |
|
895 | 897 |
func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) error { |
896 | 898 |
cmd := rcli.Subcmd(stdout, "tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository") |
897 | 899 |
force := cmd.Bool("f", false, "Force") |
... | ... |
@@ -904,7 +929,9 @@ func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) |
904 | 904 |
} |
905 | 905 |
return srv.runtime.repositories.Set(cmd.Arg(1), cmd.Arg(2), cmd.Arg(0), *force) |
906 | 906 |
} |
907 |
+*/ |
|
907 | 908 |
|
909 |
+/* |
|
908 | 910 |
func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
909 | 911 |
config, err := ParseRun(args) |
910 | 912 |
if err != nil { |
... | ... |
@@ -974,8 +1001,72 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...s |
974 | 974 |
<-attachErr |
975 | 975 |
// Expecting I/O pipe error, discarding |
976 | 976 |
return nil |
977 |
+ } |
|
978 |
+ */ |
|
979 |
+ |
|
980 |
+ |
|
981 |
+func call(method, path string) ([]byte, error) { |
|
982 |
+ req, err := http.NewRequest(method, "http://0.0.0.0:4243/" + path, nil) |
|
983 |
+ if err != nil { |
|
984 |
+ return nil, err |
|
985 |
+ } |
|
986 |
+ resp, err := http.DefaultClient.Do(req) |
|
987 |
+ if err != nil { |
|
988 |
+ return nil, err |
|
989 |
+ } |
|
990 |
+ defer resp.Body.Close() |
|
991 |
+ body, err := ioutil.ReadAll(resp.Body) |
|
992 |
+ if err != nil { |
|
993 |
+ return nil, err |
|
994 |
+ } |
|
995 |
+ if resp.StatusCode != 200 { |
|
996 |
+ return nil, fmt.Errorf("error: %s", body) |
|
997 |
+ } |
|
998 |
+ return body, nil |
|
999 |
+ |
|
977 | 1000 |
} |
1001 |
+/* |
|
1002 |
+func apiPost(path string, data interface{}) ([]byte, error) { |
|
1003 |
+ buf, err := json.Marshal(data) |
|
1004 |
+ if err != nil { |
|
1005 |
+ return nil, err |
|
1006 |
+ } |
|
1007 |
+ dataBuf := bytes.NewBuffer(buf) |
|
1008 |
+ resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf) |
|
1009 |
+ if err != nil { |
|
1010 |
+ return nil, err |
|
1011 |
+ } |
|
1012 |
+ defer resp.Body.Close() |
|
1013 |
+ body, err := ioutil.ReadAll(resp.Body) |
|
1014 |
+ if err != nil { |
|
1015 |
+ return nil, err |
|
1016 |
+ } |
|
1017 |
+ if resp.StatusCode != 200 { |
|
1018 |
+ return nil, fmt.Errorf("[error] %s", body) |
|
1019 |
+ } |
|
1020 |
+ return body, nil |
|
1021 |
+} |
|
1022 |
+ |
|
1023 |
+func apiPostHijack(path string, data interface{}) (io.ReadCloser, error) { |
|
1024 |
+ buf, err := json.Marshal(data) |
|
1025 |
+ if err != nil { |
|
1026 |
+ return nil, err |
|
1027 |
+ } |
|
1028 |
+ dataBuf := bytes.NewBuffer(buf) |
|
1029 |
+ resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf) |
|
1030 |
+ if err != nil { |
|
1031 |
+ return nil, err |
|
1032 |
+ } |
|
1033 |
+ //TODO check status code |
|
978 | 1034 |
|
979 |
-type Server struct { |
|
980 |
- runtime *Runtime |
|
1035 |
+ return resp.Body, nil |
|
1036 |
+} |
|
1037 |
+*/ |
|
1038 |
+func Subcmd(name, signature, description string) *flag.FlagSet { |
|
1039 |
+ flags := flag.NewFlagSet(name, flag.ContinueOnError) |
|
1040 |
+ flags.Usage = func() { |
|
1041 |
+ fmt.Printf("\nUsage: docker %s %s\n\n%s\n\n", name, signature, description) |
|
1042 |
+ flags.PrintDefaults() |
|
1043 |
+ } |
|
1044 |
+ return flags |
|
981 | 1045 |
} |
982 | 1046 |
deleted file mode 100644 |
... | ... |
@@ -1,528 +0,0 @@ |
1 |
-package docker |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "bytes" |
|
5 |
- "encoding/json" |
|
6 |
- "flag" |
|
7 |
- "fmt" |
|
8 |
- "io" |
|
9 |
- "io/ioutil" |
|
10 |
- "net/http" |
|
11 |
- "os" |
|
12 |
- "text/tabwriter" |
|
13 |
-) |
|
14 |
- |
|
15 |
-func ParseCommands(args []string) error { |
|
16 |
- |
|
17 |
- cmds := map[string]func(args []string) error{ |
|
18 |
- "images": cmdImages, |
|
19 |
- "info": cmdInfo, |
|
20 |
- "history": cmdHistory, |
|
21 |
- "kill": cmdKill, |
|
22 |
- "logs": cmdLogs, |
|
23 |
- "ps": cmdPs, |
|
24 |
- "restart": cmdRestart, |
|
25 |
- "rm": cmdRm, |
|
26 |
- "rmi": cmdRmi, |
|
27 |
- "run": cmdRun, |
|
28 |
- "start": cmdStart, |
|
29 |
- "stop": cmdStop, |
|
30 |
- "version": cmdVersion, |
|
31 |
- } |
|
32 |
- |
|
33 |
- if len(args) > 0 { |
|
34 |
- cmd, exists := cmds[args[0]] |
|
35 |
- if !exists { |
|
36 |
- //TODO display commend not found |
|
37 |
- return cmdHelp(args) |
|
38 |
- } |
|
39 |
- return cmd(args[1:]) |
|
40 |
- } |
|
41 |
- return cmdHelp(args) |
|
42 |
-} |
|
43 |
- |
|
44 |
-func cmdHelp(args []string) error { |
|
45 |
- help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n" |
|
46 |
- for _, cmd := range [][]string{ |
|
47 |
- // {"attach", "Attach to a running container"}, |
|
48 |
- // {"commit", "Create a new image from a container's changes"}, |
|
49 |
- // {"diff", "Inspect changes on a container's filesystem"}, |
|
50 |
- // {"export", "Stream the contents of a container as a tar archive"}, |
|
51 |
- {"history", "Show the history of an image"}, |
|
52 |
- {"images", "List images"}, |
|
53 |
- // {"import", "Create a new filesystem image from the contents of a tarball"}, |
|
54 |
- {"info", "Display system-wide information"}, |
|
55 |
- // {"inspect", "Return low-level information on a container"}, |
|
56 |
- {"kill", "Kill a running container"}, |
|
57 |
- // {"login", "Register or Login to the docker registry server"}, |
|
58 |
- {"logs", "Fetch the logs of a container"}, |
|
59 |
- // {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, |
|
60 |
- {"ps", "List containers"}, |
|
61 |
- // {"pull", "Pull an image or a repository from the docker registry server"}, |
|
62 |
- // {"push", "Push an image or a repository to the docker registry server"}, |
|
63 |
- {"restart", "Restart a running container"}, |
|
64 |
- {"rm", "Remove a container"}, |
|
65 |
- {"rmi", "Remove an image"}, |
|
66 |
- {"run", "Run a command in a new container"}, |
|
67 |
- {"start", "Start a stopped container"}, |
|
68 |
- {"stop", "Stop a running container"}, |
|
69 |
- // {"tag", "Tag an image into a repository"}, |
|
70 |
- {"version", "Show the docker version information"}, |
|
71 |
- // {"wait", "Block until a container stops, then print its exit code"}, |
|
72 |
- } { |
|
73 |
- help += fmt.Sprintf(" %-10.10s%s\n", cmd[0], cmd[1]) |
|
74 |
- } |
|
75 |
- fmt.Println(help) |
|
76 |
- return nil |
|
77 |
-} |
|
78 |
- |
|
79 |
-func cmdImages(args []string) error { |
|
80 |
- cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images") |
|
81 |
- var in ImagesIn |
|
82 |
- cmd.BoolVar(&in.Quiet, "q", false, "only show numeric IDs") |
|
83 |
- cmd.BoolVar(&in.All, "a", false, "show all images") |
|
84 |
- if err := cmd.Parse(args); err != nil { |
|
85 |
- return nil |
|
86 |
- } |
|
87 |
- if cmd.NArg() > 1 { |
|
88 |
- cmd.Usage() |
|
89 |
- return nil |
|
90 |
- } |
|
91 |
- if cmd.NArg() == 1 { |
|
92 |
- in.NameFilter = cmd.Arg(0) |
|
93 |
- } |
|
94 |
- |
|
95 |
- body, err := apiPost("images", in) |
|
96 |
- if err != nil { |
|
97 |
- return err |
|
98 |
- } |
|
99 |
- |
|
100 |
- var outs []ImagesOut |
|
101 |
- err = json.Unmarshal(body, &outs) |
|
102 |
- if err != nil { |
|
103 |
- return err |
|
104 |
- } |
|
105 |
- w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
106 |
- if !in.Quiet { |
|
107 |
- fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") |
|
108 |
- } |
|
109 |
- |
|
110 |
- for _, out := range outs { |
|
111 |
- if !in.Quiet { |
|
112 |
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Repository, out.Tag, out.Id, out.Created) |
|
113 |
- } else { |
|
114 |
- fmt.Fprintln(w, out.Id) |
|
115 |
- } |
|
116 |
- } |
|
117 |
- |
|
118 |
- if !in.Quiet { |
|
119 |
- w.Flush() |
|
120 |
- } |
|
121 |
- return nil |
|
122 |
- |
|
123 |
-} |
|
124 |
- |
|
125 |
-func cmdInfo(args []string) error { |
|
126 |
- cmd := Subcmd("info", "", "Display system-wide information") |
|
127 |
- if err := cmd.Parse(args); err != nil { |
|
128 |
- return nil |
|
129 |
- } |
|
130 |
- if cmd.NArg() > 0 { |
|
131 |
- cmd.Usage() |
|
132 |
- return nil |
|
133 |
- } |
|
134 |
- |
|
135 |
- body, err := apiGet("info") |
|
136 |
- if err != nil { |
|
137 |
- return err |
|
138 |
- } |
|
139 |
- |
|
140 |
- var out InfoOut |
|
141 |
- err = json.Unmarshal(body, &out) |
|
142 |
- if err != nil { |
|
143 |
- return err |
|
144 |
- } |
|
145 |
- fmt.Printf("containers: %d\nversion: %s\nimages: %d\n", out.Containers, out.Version, out.Images) |
|
146 |
- if out.Debug { |
|
147 |
- fmt.Println("debug mode enabled") |
|
148 |
- fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines) |
|
149 |
- } |
|
150 |
- return nil |
|
151 |
- |
|
152 |
-} |
|
153 |
- |
|
154 |
-func cmdHistory(args []string) error { |
|
155 |
- cmd := Subcmd("history", "IMAGE", "Show the history of an image") |
|
156 |
- if err := cmd.Parse(args); err != nil { |
|
157 |
- return nil |
|
158 |
- } |
|
159 |
- if cmd.NArg() != 1 { |
|
160 |
- cmd.Usage() |
|
161 |
- return nil |
|
162 |
- } |
|
163 |
- |
|
164 |
- body, err := apiPost("history", HistoryIn{cmd.Arg(0)}) |
|
165 |
- if err != nil { |
|
166 |
- return err |
|
167 |
- } |
|
168 |
- |
|
169 |
- var outs []HistoryOut |
|
170 |
- err = json.Unmarshal(body, &outs) |
|
171 |
- if err != nil { |
|
172 |
- return err |
|
173 |
- } |
|
174 |
- w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
175 |
- fmt.Fprintln(w, "ID\tCREATED\tCREATED BY") |
|
176 |
- |
|
177 |
- for _, out := range outs { |
|
178 |
- fmt.Fprintf(w, "%s\t%s\t%s\n", out.Id, out.Created, out.CreatedBy) |
|
179 |
- } |
|
180 |
- w.Flush() |
|
181 |
- return nil |
|
182 |
-} |
|
183 |
- |
|
184 |
-func cmdKill(args []string) error { |
|
185 |
- cmd := Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container") |
|
186 |
- if err := cmd.Parse(args); err != nil { |
|
187 |
- return nil |
|
188 |
- } |
|
189 |
- if cmd.NArg() < 1 { |
|
190 |
- cmd.Usage() |
|
191 |
- return nil |
|
192 |
- } |
|
193 |
- |
|
194 |
- body, err := apiPost("kill", args) |
|
195 |
- if err != nil { |
|
196 |
- return err |
|
197 |
- } |
|
198 |
- |
|
199 |
- var out SimpleMessage |
|
200 |
- err = json.Unmarshal(body, &out) |
|
201 |
- if err != nil { |
|
202 |
- return err |
|
203 |
- } |
|
204 |
- fmt.Print(out.Message) |
|
205 |
- return nil |
|
206 |
-} |
|
207 |
- |
|
208 |
-func cmdLogs(args []string) error { |
|
209 |
- cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container") |
|
210 |
- if err := cmd.Parse(args); err != nil { |
|
211 |
- return nil |
|
212 |
- } |
|
213 |
- if cmd.NArg() != 1 { |
|
214 |
- cmd.Usage() |
|
215 |
- return nil |
|
216 |
- } |
|
217 |
- body, err := apiPost("logs", LogsIn{cmd.Arg(0)}) |
|
218 |
- if err != nil { |
|
219 |
- return err |
|
220 |
- } |
|
221 |
- |
|
222 |
- var out LogsOut |
|
223 |
- err = json.Unmarshal(body, &out) |
|
224 |
- if err != nil { |
|
225 |
- return err |
|
226 |
- } |
|
227 |
- fmt.Fprintln(os.Stdout, out.Stdout) |
|
228 |
- fmt.Fprintln(os.Stderr, out.Stderr) |
|
229 |
- |
|
230 |
- return nil |
|
231 |
-} |
|
232 |
- |
|
233 |
-func cmdPs(args []string) error { |
|
234 |
- cmd := Subcmd("ps", "[OPTIONS]", "List containers") |
|
235 |
- var in PsIn |
|
236 |
- cmd.BoolVar(&in.Quiet, "q", false, "Only display numeric IDs") |
|
237 |
- cmd.BoolVar(&in.All, "a", false, "Show all containers. Only running containers are shown by default.") |
|
238 |
- cmd.BoolVar(&in.Full, "notrunc", false, "Don't truncate output") |
|
239 |
- nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.") |
|
240 |
- cmd.IntVar(&in.Last, "n", -1, "Show n last created containers, include non-running ones.") |
|
241 |
- if err := cmd.Parse(args); err != nil { |
|
242 |
- return nil |
|
243 |
- } |
|
244 |
- if in.Last == -1 && *nLatest { |
|
245 |
- in.Last = 1 |
|
246 |
- } |
|
247 |
- |
|
248 |
- body, err := apiPost("ps", in) |
|
249 |
- if err != nil { |
|
250 |
- return err |
|
251 |
- } |
|
252 |
- |
|
253 |
- var outs []PsOut |
|
254 |
- err = json.Unmarshal(body, &outs) |
|
255 |
- if err != nil { |
|
256 |
- return err |
|
257 |
- } |
|
258 |
- w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) |
|
259 |
- if !in.Quiet { |
|
260 |
- fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS") |
|
261 |
- } |
|
262 |
- |
|
263 |
- for _, out := range outs { |
|
264 |
- if !in.Quiet { |
|
265 |
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Id, out.Image, out.Command, out.Status, out.Created) |
|
266 |
- } else { |
|
267 |
- fmt.Fprintln(w, out.Id) |
|
268 |
- } |
|
269 |
- } |
|
270 |
- |
|
271 |
- if !in.Quiet { |
|
272 |
- w.Flush() |
|
273 |
- } |
|
274 |
- return nil |
|
275 |
-} |
|
276 |
- |
|
277 |
-func cmdRestart(args []string) error { |
|
278 |
- cmd := Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container") |
|
279 |
- if err := cmd.Parse(args); err != nil { |
|
280 |
- return nil |
|
281 |
- } |
|
282 |
- if cmd.NArg() < 1 { |
|
283 |
- cmd.Usage() |
|
284 |
- return nil |
|
285 |
- } |
|
286 |
- |
|
287 |
- body, err := apiPost("restart", cmd.Args()) |
|
288 |
- if err != nil { |
|
289 |
- return err |
|
290 |
- } |
|
291 |
- |
|
292 |
- var out []string |
|
293 |
- err = json.Unmarshal(body, &out) |
|
294 |
- if err != nil { |
|
295 |
- return err |
|
296 |
- } |
|
297 |
- for _, name := range out { |
|
298 |
- fmt.Println(name) |
|
299 |
- } |
|
300 |
- return nil |
|
301 |
-} |
|
302 |
- |
|
303 |
-func cmdRm(args []string) error { |
|
304 |
- cmd := Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove a container") |
|
305 |
- if err := cmd.Parse(args); err != nil { |
|
306 |
- return nil |
|
307 |
- } |
|
308 |
- if cmd.NArg() < 1 { |
|
309 |
- cmd.Usage() |
|
310 |
- return nil |
|
311 |
- } |
|
312 |
- |
|
313 |
- body, err := apiPost("rm", cmd.Args()) |
|
314 |
- if err != nil { |
|
315 |
- return err |
|
316 |
- } |
|
317 |
- |
|
318 |
- var out []string |
|
319 |
- err = json.Unmarshal(body, &out) |
|
320 |
- if err != nil { |
|
321 |
- return err |
|
322 |
- } |
|
323 |
- for _, name := range out { |
|
324 |
- fmt.Println(name) |
|
325 |
- } |
|
326 |
- return nil |
|
327 |
-} |
|
328 |
- |
|
329 |
-func cmdRmi(args []string) error { |
|
330 |
- cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image") |
|
331 |
- if err := cmd.Parse(args); err != nil { |
|
332 |
- return nil |
|
333 |
- } |
|
334 |
- if cmd.NArg() < 1 { |
|
335 |
- cmd.Usage() |
|
336 |
- return nil |
|
337 |
- } |
|
338 |
- |
|
339 |
- body, err := apiPost("rmi", cmd.Args()) |
|
340 |
- if err != nil { |
|
341 |
- return err |
|
342 |
- } |
|
343 |
- |
|
344 |
- var out []string |
|
345 |
- err = json.Unmarshal(body, &out) |
|
346 |
- if err != nil { |
|
347 |
- return err |
|
348 |
- } |
|
349 |
- for _, name := range out { |
|
350 |
- fmt.Println(name) |
|
351 |
- } |
|
352 |
- return nil |
|
353 |
-} |
|
354 |
- |
|
355 |
-func cmdRun(args []string) error { |
|
356 |
- config, err := ParseRun(args) |
|
357 |
- if err != nil { |
|
358 |
- return err |
|
359 |
- } |
|
360 |
- if config.Image == "" { |
|
361 |
- fmt.Println("Error: Image not specified") |
|
362 |
- return fmt.Errorf("Image not specified") |
|
363 |
- } |
|
364 |
- if len(config.Cmd) == 0 { |
|
365 |
- fmt.Println("Error: Command not specified") |
|
366 |
- return fmt.Errorf("Command not specified") |
|
367 |
- } |
|
368 |
- |
|
369 |
- body, err := apiPostHijack("run", config) |
|
370 |
- if err != nil { |
|
371 |
- return err |
|
372 |
- } |
|
373 |
- defer body.Close() |
|
374 |
- |
|
375 |
- /*str, err2 := ioutil.ReadAll(body) |
|
376 |
- if err2 != nil { |
|
377 |
- return err2 |
|
378 |
- } |
|
379 |
- fmt.Println(str)*/ |
|
380 |
- return nil |
|
381 |
- |
|
382 |
-} |
|
383 |
- |
|
384 |
-func cmdStart(args []string) error { |
|
385 |
- cmd := Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container") |
|
386 |
- if err := cmd.Parse(args); err != nil { |
|
387 |
- return nil |
|
388 |
- } |
|
389 |
- if cmd.NArg() < 1 { |
|
390 |
- cmd.Usage() |
|
391 |
- return nil |
|
392 |
- } |
|
393 |
- |
|
394 |
- body, err := apiPost("start", cmd.Args()) |
|
395 |
- if err != nil { |
|
396 |
- return err |
|
397 |
- } |
|
398 |
- |
|
399 |
- var out []string |
|
400 |
- err = json.Unmarshal(body, &out) |
|
401 |
- if err != nil { |
|
402 |
- return err |
|
403 |
- } |
|
404 |
- for _, name := range out { |
|
405 |
- fmt.Println(name) |
|
406 |
- } |
|
407 |
- |
|
408 |
- return nil |
|
409 |
- |
|
410 |
-} |
|
411 |
- |
|
412 |
-func cmdStop(args []string) error { |
|
413 |
- cmd := Subcmd("stop", "CONTAINER [CONTAINER...]", "Restart a running container") |
|
414 |
- if err := cmd.Parse(args); err != nil { |
|
415 |
- return nil |
|
416 |
- } |
|
417 |
- if cmd.NArg() < 1 { |
|
418 |
- cmd.Usage() |
|
419 |
- return nil |
|
420 |
- } |
|
421 |
- |
|
422 |
- body, err := apiPost("stop", cmd.Args()) |
|
423 |
- if err != nil { |
|
424 |
- return err |
|
425 |
- } |
|
426 |
- |
|
427 |
- var out []string |
|
428 |
- err = json.Unmarshal(body, &out) |
|
429 |
- if err != nil { |
|
430 |
- return err |
|
431 |
- } |
|
432 |
- for _, name := range out { |
|
433 |
- fmt.Println(name) |
|
434 |
- } |
|
435 |
- return nil |
|
436 |
- |
|
437 |
-} |
|
438 |
- |
|
439 |
-func cmdVersion(args []string) error { |
|
440 |
- cmd := Subcmd("version", "", "Show the docker version information.") |
|
441 |
- if err := cmd.Parse(args); err != nil { |
|
442 |
- return nil |
|
443 |
- } |
|
444 |
- if cmd.NArg() > 0 { |
|
445 |
- cmd.Usage() |
|
446 |
- return nil |
|
447 |
- } |
|
448 |
- |
|
449 |
- body, err := apiGet("version") |
|
450 |
- if err != nil { |
|
451 |
- return err |
|
452 |
- } |
|
453 |
- |
|
454 |
- var out VersionOut |
|
455 |
- err = json.Unmarshal(body, &out) |
|
456 |
- if err != nil { |
|
457 |
- return err |
|
458 |
- } |
|
459 |
- fmt.Println("Version:", out.Version) |
|
460 |
- fmt.Println("Git Commit:", out.GitCommit) |
|
461 |
- if out.MemoryLimitDisabled { |
|
462 |
- fmt.Println("Memory limit disabled") |
|
463 |
- } |
|
464 |
- |
|
465 |
- return nil |
|
466 |
-} |
|
467 |
- |
|
468 |
-func apiGet(path string) ([]byte, error) { |
|
469 |
- resp, err := http.Get("http://0.0.0.0:4243/" + path) |
|
470 |
- if err != nil { |
|
471 |
- return nil, err |
|
472 |
- } |
|
473 |
- defer resp.Body.Close() |
|
474 |
- body, err := ioutil.ReadAll(resp.Body) |
|
475 |
- if err != nil { |
|
476 |
- return nil, err |
|
477 |
- } |
|
478 |
- if resp.StatusCode != 200 { |
|
479 |
- return nil, fmt.Errorf("error: %s", body) |
|
480 |
- } |
|
481 |
- return body, nil |
|
482 |
- |
|
483 |
-} |
|
484 |
- |
|
485 |
-func apiPost(path string, data interface{}) ([]byte, error) { |
|
486 |
- buf, err := json.Marshal(data) |
|
487 |
- if err != nil { |
|
488 |
- return nil, err |
|
489 |
- } |
|
490 |
- dataBuf := bytes.NewBuffer(buf) |
|
491 |
- resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf) |
|
492 |
- if err != nil { |
|
493 |
- return nil, err |
|
494 |
- } |
|
495 |
- defer resp.Body.Close() |
|
496 |
- body, err := ioutil.ReadAll(resp.Body) |
|
497 |
- if err != nil { |
|
498 |
- return nil, err |
|
499 |
- } |
|
500 |
- if resp.StatusCode != 200 { |
|
501 |
- return nil, fmt.Errorf("[error] %s", body) |
|
502 |
- } |
|
503 |
- return body, nil |
|
504 |
-} |
|
505 |
- |
|
506 |
-func apiPostHijack(path string, data interface{}) (io.ReadCloser, error) { |
|
507 |
- buf, err := json.Marshal(data) |
|
508 |
- if err != nil { |
|
509 |
- return nil, err |
|
510 |
- } |
|
511 |
- dataBuf := bytes.NewBuffer(buf) |
|
512 |
- resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf) |
|
513 |
- if err != nil { |
|
514 |
- return nil, err |
|
515 |
- } |
|
516 |
- //TODO check status code |
|
517 |
- |
|
518 |
- return resp.Body, nil |
|
519 |
-} |
|
520 |
- |
|
521 |
-func Subcmd(name, signature, description string) *flag.FlagSet { |
|
522 |
- flags := flag.NewFlagSet(name, flag.ContinueOnError) |
|
523 |
- flags.Usage = func() { |
|
524 |
- fmt.Printf("\nUsage: docker %s %s\n\n%s\n\n", name, signature, description) |
|
525 |
- flags.PrintDefaults() |
|
526 |
- } |
|
527 |
- return flags |
|
528 |
-} |