api.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. package docker
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/gorilla/mux"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "os"
  10. "runtime"
  11. "strconv"
  12. "strings"
  13. "time"
  14. )
  15. func ListenAndServe(addr string, rtime *Runtime) error {
  16. r := mux.NewRouter()
  17. log.Printf("Listening for HTTP on %s\n", addr)
  18. r.Path("/version").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  19. log.Println(r.RequestURI)
  20. m := VersionOut{VERSION, GIT_COMMIT, NO_MEMORY_LIMIT}
  21. b, err := json.Marshal(m)
  22. if err != nil {
  23. http.Error(w, err.Error(), http.StatusInternalServerError)
  24. } else {
  25. w.Write(b)
  26. }
  27. })
  28. r.Path("/containers/{name:.*}/kill").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  29. log.Println(r.RequestURI)
  30. vars := mux.Vars(r)
  31. name := vars["name"]
  32. if container := rtime.Get(name); container != nil {
  33. if err := container.Kill(); err != nil {
  34. http.Error(w, "Error restarting container "+name+": "+err.Error(), http.StatusInternalServerError)
  35. return
  36. }
  37. } else {
  38. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  39. return
  40. }
  41. w.WriteHeader(200)
  42. })
  43. r.Path("/images").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  44. log.Println(r.RequestURI)
  45. All := r.Form.Get("all")
  46. NameFilter := r.Form.Get("filter")
  47. Quiet := r.Form.Get("quiet")
  48. var allImages map[string]*Image
  49. var err error
  50. if All == "true" {
  51. allImages, err = rtime.graph.Map()
  52. } else {
  53. allImages, err = rtime.graph.Heads()
  54. }
  55. if err != nil {
  56. w.WriteHeader(500)
  57. return
  58. }
  59. var outs []ImagesOut
  60. for name, repository := range rtime.repositories.Repositories {
  61. if NameFilter != "" && name != NameFilter {
  62. continue
  63. }
  64. for tag, id := range repository {
  65. var out ImagesOut
  66. image, err := rtime.graph.Get(id)
  67. if err != nil {
  68. log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
  69. continue
  70. }
  71. delete(allImages, id)
  72. if Quiet != "true" {
  73. out.Repository = name
  74. out.Tag = tag
  75. out.Id = TruncateId(id)
  76. out.Created = HumanDuration(time.Now().Sub(image.Created)) + " ago"
  77. } else {
  78. out.Id = image.ShortId()
  79. }
  80. outs = append(outs, out)
  81. }
  82. }
  83. // Display images which aren't part of a
  84. if NameFilter == "" {
  85. for id, image := range allImages {
  86. var out ImagesOut
  87. if Quiet != "true" {
  88. out.Repository = "<none>"
  89. out.Tag = "<none>"
  90. out.Id = TruncateId(id)
  91. out.Created = HumanDuration(time.Now().Sub(image.Created)) + " ago"
  92. } else {
  93. out.Id = image.ShortId()
  94. }
  95. outs = append(outs, out)
  96. }
  97. }
  98. b, err := json.Marshal(outs)
  99. if err != nil {
  100. http.Error(w, err.Error(), http.StatusInternalServerError)
  101. } else {
  102. w.Write(b)
  103. }
  104. })
  105. r.Path("/info").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  106. log.Println(r.RequestURI)
  107. images, _ := rtime.graph.All()
  108. var imgcount int
  109. if images == nil {
  110. imgcount = 0
  111. } else {
  112. imgcount = len(images)
  113. }
  114. var out InfoOut
  115. out.Containers = len(rtime.List())
  116. out.Version = VERSION
  117. out.Images = imgcount
  118. if os.Getenv("DEBUG") == "1" {
  119. out.Debug = true
  120. out.NFd = getTotalUsedFds()
  121. out.NGoroutines = runtime.NumGoroutine()
  122. }
  123. b, err := json.Marshal(out)
  124. if err != nil {
  125. http.Error(w, err.Error(), http.StatusInternalServerError)
  126. } else {
  127. w.Write(b)
  128. }
  129. })
  130. r.Path("/images/{name:.*}/history").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  131. log.Println(r.RequestURI)
  132. vars := mux.Vars(r)
  133. name := vars["name"]
  134. image, err := rtime.repositories.LookupImage(name)
  135. if err != nil {
  136. http.Error(w, err.Error(), http.StatusInternalServerError)
  137. return
  138. }
  139. var outs []HistoryOut
  140. err = image.WalkHistory(func(img *Image) error {
  141. var out HistoryOut
  142. out.Id = rtime.repositories.ImageName(img.ShortId())
  143. out.Created = HumanDuration(time.Now().Sub(img.Created)) + " ago"
  144. out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
  145. return nil
  146. })
  147. b, err := json.Marshal(outs)
  148. if err != nil {
  149. http.Error(w, err.Error(), http.StatusInternalServerError)
  150. } else {
  151. w.Write(b)
  152. }
  153. })
  154. r.Path("/containers/{name:.*}/logs").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  155. log.Println(r.RequestURI)
  156. vars := mux.Vars(r)
  157. name := vars["name"]
  158. if container := rtime.Get(name); container != nil {
  159. var out LogsOut
  160. logStdout, err := container.ReadLog("stdout")
  161. if err != nil {
  162. http.Error(w, err.Error(), http.StatusInternalServerError)
  163. return
  164. }
  165. logStderr, err := container.ReadLog("stderr")
  166. if err != nil {
  167. http.Error(w, err.Error(), http.StatusInternalServerError)
  168. return
  169. }
  170. stdout, errStdout := ioutil.ReadAll(logStdout)
  171. if errStdout != nil {
  172. http.Error(w, errStdout.Error(), http.StatusInternalServerError)
  173. return
  174. } else {
  175. out.Stdout = fmt.Sprintf("%s", stdout)
  176. }
  177. stderr, errStderr := ioutil.ReadAll(logStderr)
  178. if errStderr != nil {
  179. http.Error(w, errStderr.Error(), http.StatusInternalServerError)
  180. return
  181. } else {
  182. out.Stderr = fmt.Sprintf("%s", stderr)
  183. }
  184. b, err := json.Marshal(out)
  185. if err != nil {
  186. http.Error(w, err.Error(), http.StatusInternalServerError)
  187. } else {
  188. w.Write(b)
  189. }
  190. } else {
  191. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  192. }
  193. })
  194. r.Path("/containers").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  195. log.Println(r.RequestURI)
  196. All := r.Form.Get("all")
  197. NoTrunc := r.Form.Get("notrunc")
  198. Quiet := r.Form.Get("quiet")
  199. Last := r.Form.Get("n")
  200. n, err := strconv.Atoi(Last)
  201. if err != nil {
  202. n = -1
  203. }
  204. var outs []PsOut
  205. for i, container := range rtime.List() {
  206. if !container.State.Running && All != "true" && n == -1 {
  207. continue
  208. }
  209. if i == n {
  210. break
  211. }
  212. var out PsOut
  213. out.Id = container.ShortId()
  214. if Quiet != "true" {
  215. command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  216. if NoTrunc != "true" {
  217. command = Trunc(command, 20)
  218. }
  219. out.Image = rtime.repositories.ImageName(container.Image)
  220. out.Command = command
  221. out.Created = HumanDuration(time.Now().Sub(container.Created)) + " ago"
  222. out.Status = container.State.String()
  223. }
  224. outs = append(outs, out)
  225. }
  226. b, err := json.Marshal(outs)
  227. if err != nil {
  228. http.Error(w, err.Error(), http.StatusInternalServerError)
  229. } else {
  230. w.Write(b)
  231. }
  232. })
  233. r.Path("/containers/{name:.*}/restart").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  234. log.Println(r.RequestURI)
  235. vars := mux.Vars(r)
  236. name := vars["name"]
  237. if container := rtime.Get(name); container != nil {
  238. if err := container.Restart(); err != nil {
  239. http.Error(w, "Error restarting container "+name+": "+err.Error(), http.StatusInternalServerError)
  240. return
  241. }
  242. } else {
  243. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  244. return
  245. }
  246. w.WriteHeader(200)
  247. })
  248. r.Path("/containers/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  249. log.Println(r.RequestURI)
  250. vars := mux.Vars(r)
  251. name := vars["name"]
  252. if container := rtime.Get(name); container != nil {
  253. if err := rtime.Destroy(container); err != nil {
  254. http.Error(w, "Error destroying container "+name+": "+err.Error(), http.StatusInternalServerError)
  255. return
  256. }
  257. } else {
  258. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  259. return
  260. }
  261. w.WriteHeader(200)
  262. })
  263. r.Path("/images/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  264. log.Println(r.RequestURI)
  265. vars := mux.Vars(r)
  266. name := vars["name"]
  267. img, err := rtime.repositories.LookupImage(name)
  268. if err != nil {
  269. http.Error(w, "No such image: "+name, http.StatusInternalServerError)
  270. return
  271. } else {
  272. if err := rtime.graph.Delete(img.Id); err != nil {
  273. http.Error(w, "Error deleting image "+name+": "+err.Error(), http.StatusInternalServerError)
  274. return
  275. }
  276. }
  277. w.WriteHeader(200)
  278. })
  279. r.Path("/containers/{name:.*}/start").Methods("POST").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 := container.Start(); err != nil {
  285. http.Error(w, "Error starting container "+name+": "+err.Error(), http.StatusInternalServerError)
  286. return
  287. }
  288. } else {
  289. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  290. return
  291. }
  292. w.WriteHeader(200)
  293. })
  294. r.Path("/containers/{name:.*}/stop").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  295. log.Println(r.RequestURI)
  296. vars := mux.Vars(r)
  297. name := vars["name"]
  298. if container := rtime.Get(name); container != nil {
  299. if err := container.Stop(); err != nil {
  300. http.Error(w, "Error stopping container "+name+": "+err.Error(), http.StatusInternalServerError)
  301. return
  302. }
  303. } else {
  304. http.Error(w, "No such container: "+name, http.StatusInternalServerError)
  305. return
  306. }
  307. w.WriteHeader(200)
  308. })
  309. return http.ListenAndServe(addr, r)
  310. }