Skip to content

Commit b295239

Browse files
committed
added: info, history, logs, ps, start, stop, restart, rm, rmi
1 parent 79e9105 commit b295239

File tree

5 files changed

+713
-38
lines changed

5 files changed

+713
-38
lines changed

api.go

Lines changed: 315 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package docker
22

33
import (
44
"encoding/json"
5-
_ "fmt"
5+
"fmt"
66
"github.com/gorilla/mux"
7+
"io/ioutil"
78
"log"
89
"net/http"
10+
"os"
11+
"runtime"
12+
"strings"
913
"time"
1014
)
1115

12-
func ListenAndServe(addr string, runtime *Runtime) error {
16+
func ListenAndServe(addr string, rtime *Runtime) error {
1317
r := mux.NewRouter()
1418
log.Printf("Listening for HTTP on %s\n", addr)
1519

@@ -32,7 +36,7 @@ func ListenAndServe(addr string, runtime *Runtime) error {
3236

3337
var ret SimpleMessage
3438
for _, name := range ids {
35-
container := runtime.Get(name)
39+
container := rtime.Get(name)
3640
if container == nil {
3741
ret.Message = "No such container: " + name + "\n"
3842
break
@@ -63,22 +67,22 @@ func ListenAndServe(addr string, runtime *Runtime) error {
6367
var allImages map[string]*Image
6468
var err error
6569
if in.All {
66-
allImages, err = runtime.graph.Map()
70+
allImages, err = rtime.graph.Map()
6771
} else {
68-
allImages, err = runtime.graph.Heads()
72+
allImages, err = rtime.graph.Heads()
6973
}
7074
if err != nil {
7175
w.WriteHeader(500)
7276
return
7377
}
7478
var outs []ImagesOut
75-
for name, repository := range runtime.repositories.Repositories {
79+
for name, repository := range rtime.repositories.Repositories {
7680
if in.NameFilter != "" && name != in.NameFilter {
7781
continue
7882
}
7983
for tag, id := range repository {
8084
var out ImagesOut
81-
image, err := runtime.graph.Get(id)
85+
image, err := rtime.graph.Get(id)
8286
if err != nil {
8387
log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
8488
continue
@@ -113,7 +117,310 @@ func ListenAndServe(addr string, runtime *Runtime) error {
113117

114118
b, err := json.Marshal(outs)
115119
if err != nil {
116-
w.WriteHeader(500)
120+
http.Error(w, err.Error(), http.StatusInternalServerError)
121+
} else {
122+
w.Write(b)
123+
}
124+
125+
})
126+
127+
r.Path("/info").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
128+
images, _ := rtime.graph.All()
129+
var imgcount int
130+
if images == nil {
131+
imgcount = 0
132+
} else {
133+
imgcount = len(images)
134+
}
135+
var out InfoOut
136+
out.Containers = len(rtime.List())
137+
out.Version = VERSION
138+
out.Images = imgcount
139+
if os.Getenv("DEBUG") == "1" {
140+
out.Debug = true
141+
out.NFd = getTotalUsedFds()
142+
out.NGoroutines = runtime.NumGoroutine()
143+
}
144+
b, err := json.Marshal(out)
145+
if err != nil {
146+
http.Error(w, err.Error(), http.StatusInternalServerError)
147+
} else {
148+
w.Write(b)
149+
}
150+
})
151+
152+
r.Path("/history").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
153+
log.Println(r.RequestURI)
154+
155+
var in HistoryIn
156+
json.NewDecoder(r.Body).Decode(&in)
157+
158+
image, err := rtime.repositories.LookupImage(in.Name)
159+
if err != nil {
160+
http.Error(w, err.Error(), http.StatusInternalServerError)
161+
return
162+
}
163+
var outs []HistoryOut
164+
err = image.WalkHistory(func(img *Image) error {
165+
var out HistoryOut
166+
out.Id = rtime.repositories.ImageName(img.ShortId())
167+
out.Created = HumanDuration(time.Now().Sub(img.Created)) + " ago"
168+
out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
169+
return nil
170+
})
171+
172+
b, err := json.Marshal(outs)
173+
if err != nil {
174+
http.Error(w, err.Error(), http.StatusInternalServerError)
175+
} else {
176+
w.Write(b)
177+
}
178+
179+
})
180+
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)
185+
186+
if container := rtime.Get(in.Name); container != nil {
187+
var out LogsOut
188+
189+
logStdout, err := container.ReadLog("stdout")
190+
if err != nil {
191+
http.Error(w, err.Error(), http.StatusInternalServerError)
192+
return
193+
}
194+
logStderr, err := container.ReadLog("stderr")
195+
if err != nil {
196+
http.Error(w, err.Error(), http.StatusInternalServerError)
197+
return
198+
}
199+
200+
stdout, errStdout := ioutil.ReadAll(logStdout)
201+
if errStdout != nil {
202+
http.Error(w, errStdout.Error(), http.StatusInternalServerError)
203+
return
204+
} else {
205+
out.Stdout = fmt.Sprintf("%s", stdout)
206+
}
207+
stderr, errStderr := ioutil.ReadAll(logStderr)
208+
if errStderr != nil {
209+
http.Error(w, errStderr.Error(), http.StatusInternalServerError)
210+
return
211+
} else {
212+
out.Stderr = fmt.Sprintf("%s", stderr)
213+
}
214+
215+
b, err := json.Marshal(out)
216+
if err != nil {
217+
http.Error(w, err.Error(), http.StatusInternalServerError)
218+
} else {
219+
w.Write(b)
220+
}
221+
222+
} else {
223+
http.Error(w, "No such container: "+in.Name, http.StatusInternalServerError)
224+
}
225+
})
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+
231+
var outs []PsOut
232+
233+
for i, container := range rtime.List() {
234+
if !container.State.Running && !in.All && in.Last == -1 {
235+
continue
236+
}
237+
if i == in.Last {
238+
break
239+
}
240+
var out PsOut
241+
out.Id = container.ShortId()
242+
if !in.Quiet {
243+
command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
244+
if !in.Full {
245+
command = Trunc(command, 20)
246+
}
247+
out.Image = rtime.repositories.ImageName(container.Image)
248+
out.Command = command
249+
out.Created = HumanDuration(time.Now().Sub(container.Created)) + " ago"
250+
out.Status = container.State.String()
251+
}
252+
outs = append(outs, out)
253+
}
254+
255+
b, err := json.Marshal(outs)
256+
if err != nil {
257+
http.Error(w, err.Error(), http.StatusInternalServerError)
258+
} else {
259+
w.Write(b)
260+
}
261+
262+
})
263+
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)
277+
return
278+
}
279+
}
280+
b, err := json.Marshal(outs)
281+
if err != nil {
282+
http.Error(w, err.Error(), http.StatusInternalServerError)
283+
} 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)
309+
}
310+
311+
})
312+
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)
321+
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+
}
329+
}
330+
b, err := json.Marshal(outs)
331+
if err != nil {
332+
http.Error(w, err.Error(), http.StatusInternalServerError)
333+
} else {
334+
w.Write(b)
335+
}
336+
337+
})
338+
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()
350+
if err != nil {
351+
http.Error(w, err.Error(), http.StatusInternalServerError)
352+
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)
374+
return
375+
}
376+
}
377+
container = container
378+
})
379+
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)
393+
return
394+
}
395+
}
396+
b, err := json.Marshal(outs)
397+
if err != nil {
398+
http.Error(w, err.Error(), http.StatusInternalServerError)
399+
} else {
400+
w.Write(b)
401+
}
402+
403+
})
404+
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)
418+
return
419+
}
420+
}
421+
b, err := json.Marshal(outs)
422+
if err != nil {
423+
http.Error(w, err.Error(), http.StatusInternalServerError)
117424
} else {
118425
w.Write(b)
119426
}

0 commit comments

Comments
 (0)