api.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. package docker
  2. import (
  3. _ "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/gorilla/mux"
  7. "log"
  8. "net"
  9. "net/http"
  10. "os"
  11. "strconv"
  12. "strings"
  13. )
  14. func hijackServer(w http.ResponseWriter) (*os.File, net.Conn, error) {
  15. rwc, _, err := w.(http.Hijacker).Hijack()
  16. if err != nil {
  17. return nil, nil, err
  18. }
  19. file, err := rwc.(*net.TCPConn).File()
  20. if err != nil {
  21. return nil, rwc, err
  22. }
  23. // Flush the options to make sure the client sets the raw mode
  24. rwc.Write([]byte{})
  25. return file, rwc, nil
  26. }
  27. func httpError(w http.ResponseWriter, err error) {
  28. if strings.HasPrefix(err.Error(), "No such") {
  29. http.Error(w, err.Error(), http.StatusNotFound)
  30. } else {
  31. http.Error(w, err.Error(), http.StatusInternalServerError)
  32. }
  33. }
  34. func ListenAndServe(addr string, srv *Server) error {
  35. r := mux.NewRouter()
  36. log.Printf("Listening for HTTP on %s\n", addr)
  37. r.Path("/version").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  38. log.Println(r.Method, r.RequestURI)
  39. m := srv.DockerVersion()
  40. b, err := json.Marshal(m)
  41. if err != nil {
  42. http.Error(w, err.Error(), http.StatusInternalServerError)
  43. } else {
  44. w.Write(b)
  45. }
  46. })
  47. r.Path("/containers/{name:.*}/kill").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  48. log.Println(r.Method, r.RequestURI)
  49. vars := mux.Vars(r)
  50. name := vars["name"]
  51. if err := srv.ContainerKill(name); err != nil {
  52. httpError(w, err)
  53. } else {
  54. w.WriteHeader(http.StatusOK)
  55. }
  56. })
  57. r.Path("/containers/{name:.*}/export").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  58. log.Println(r.Method, r.RequestURI)
  59. vars := mux.Vars(r)
  60. name := vars["name"]
  61. file, rwc, err := hijackServer(w)
  62. if file != nil {
  63. defer file.Close()
  64. }
  65. if rwc != nil {
  66. defer rwc.Close()
  67. }
  68. if err != nil {
  69. httpError(w, err)
  70. return
  71. }
  72. fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
  73. if err := srv.ContainerExport(name, file); err != nil {
  74. fmt.Fprintln(file, "Error: "+err.Error())
  75. }
  76. })
  77. r.Path("/images").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  78. log.Println(r.Method, r.RequestURI)
  79. if err := r.ParseForm(); err != nil {
  80. http.Error(w, err.Error(), http.StatusInternalServerError)
  81. }
  82. all := r.Form.Get("all")
  83. filter := r.Form.Get("filter")
  84. quiet := r.Form.Get("quiet")
  85. outs, err := srv.Images(all, filter, quiet)
  86. if err != nil {
  87. httpError(w, err)
  88. }
  89. b, err := json.Marshal(outs)
  90. if err != nil {
  91. http.Error(w, err.Error(), http.StatusInternalServerError)
  92. } else {
  93. w.Write(b)
  94. }
  95. })
  96. r.Path("/info").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  97. log.Println(r.Method, r.RequestURI)
  98. out := srv.DockerInfo()
  99. b, err := json.Marshal(out)
  100. if err != nil {
  101. http.Error(w, err.Error(), http.StatusInternalServerError)
  102. } else {
  103. w.Write(b)
  104. }
  105. })
  106. r.Path("/images/{name:.*}/history").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  107. log.Println(r.Method, r.RequestURI)
  108. vars := mux.Vars(r)
  109. name := vars["name"]
  110. outs, err := srv.ImageHistory(name)
  111. if err != nil {
  112. httpError(w, err)
  113. }
  114. b, err := json.Marshal(outs)
  115. if err != nil {
  116. http.Error(w, err.Error(), http.StatusInternalServerError)
  117. } else {
  118. w.Write(b)
  119. }
  120. })
  121. r.Path("/containers/{name:.*}/changes").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  122. log.Println(r.Method, r.RequestURI)
  123. vars := mux.Vars(r)
  124. name := vars["name"]
  125. changesStr, err := srv.ContainerChanges(name)
  126. if err != nil {
  127. httpError(w, err)
  128. }
  129. b, err := json.Marshal(changesStr)
  130. if err != nil {
  131. http.Error(w, err.Error(), http.StatusInternalServerError)
  132. } else {
  133. w.Write(b)
  134. }
  135. })
  136. r.Path("/containers/{name:.*}/port").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  137. log.Println(r.Method, r.RequestURI)
  138. if err := r.ParseForm(); err != nil {
  139. http.Error(w, err.Error(), http.StatusInternalServerError)
  140. }
  141. vars := mux.Vars(r)
  142. name := vars["name"]
  143. out, err := srv.ContainerPort(name, r.Form.Get("port"))
  144. if err != nil {
  145. httpError(w, err)
  146. }
  147. b, err := json.Marshal(ApiPort{out})
  148. if err != nil {
  149. http.Error(w, err.Error(), http.StatusInternalServerError)
  150. } else {
  151. w.Write(b)
  152. }
  153. })
  154. r.Path("/containers").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  155. log.Println(r.Method, r.RequestURI)
  156. if err := r.ParseForm(); err != nil {
  157. http.Error(w, err.Error(), http.StatusInternalServerError)
  158. }
  159. all := r.Form.Get("all")
  160. notrunc := r.Form.Get("notrunc")
  161. quiet := r.Form.Get("quiet")
  162. n, err := strconv.Atoi(r.Form.Get("n"))
  163. if err != nil {
  164. n = -1
  165. }
  166. outs := srv.Containers(all, notrunc, quiet, n)
  167. b, err := json.Marshal(outs)
  168. if err != nil {
  169. http.Error(w, err.Error(), http.StatusInternalServerError)
  170. } else {
  171. w.Write(b)
  172. }
  173. })
  174. r.Path("/images/{name:.*}/tag").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  175. log.Println(r.Method, r.RequestURI)
  176. if err := r.ParseForm(); err != nil {
  177. http.Error(w, err.Error(), http.StatusInternalServerError)
  178. }
  179. repo := r.Form.Get("repo")
  180. tag := r.Form.Get("tag")
  181. vars := mux.Vars(r)
  182. name := vars["name"]
  183. var force bool
  184. if r.Form.Get("force") == "1" {
  185. force = true
  186. }
  187. if err := srv.ContainerTag(name, repo, tag, force); err != nil {
  188. http.Error(w, err.Error(), http.StatusInternalServerError)
  189. return
  190. }
  191. w.WriteHeader(http.StatusCreated)
  192. })
  193. r.Path("/images").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  194. log.Println(r.Method, r.RequestURI)
  195. if err := r.ParseForm(); err != nil {
  196. http.Error(w, err.Error(), http.StatusInternalServerError)
  197. }
  198. src := r.Form.Get("fromSrc")
  199. image := r.Form.Get("fromImage")
  200. container := r.Form.Get("fromContainer")
  201. repo := r.Form.Get("repo")
  202. tag := r.Form.Get("tag")
  203. if container != "" { //commit
  204. var config Config
  205. if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
  206. http.Error(w, err.Error(), http.StatusInternalServerError)
  207. return
  208. }
  209. author := r.Form.Get("author")
  210. comment := r.Form.Get("comment")
  211. id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config)
  212. if err != nil {
  213. httpError(w, err)
  214. }
  215. b, err := json.Marshal(ApiId{id})
  216. if err != nil {
  217. http.Error(w, err.Error(), http.StatusInternalServerError)
  218. } else {
  219. w.Write(b)
  220. }
  221. } else if image != "" || src != "" {
  222. file, rwc, err := hijackServer(w)
  223. if file != nil {
  224. defer file.Close()
  225. }
  226. if rwc != nil {
  227. defer rwc.Close()
  228. }
  229. if err != nil {
  230. httpError(w, err)
  231. return
  232. }
  233. fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
  234. if image != "" { //pull
  235. if err := srv.ImagePull(image, file); err != nil {
  236. fmt.Fprintln(file, "Error: "+err.Error())
  237. }
  238. } else { //import
  239. if err := srv.ImageImport(src, repo, tag, file); err != nil {
  240. fmt.Fprintln(file, "Error: "+err.Error())
  241. }
  242. }
  243. } else {
  244. w.WriteHeader(http.StatusNotFound)
  245. }
  246. })
  247. r.Path("/containers").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  248. log.Println(r.Method, r.RequestURI)
  249. var config Config
  250. if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
  251. http.Error(w, err.Error(), http.StatusInternalServerError)
  252. return
  253. }
  254. id, memoryW, swapW, err := srv.ContainerCreate(config)
  255. if err != nil {
  256. httpError(w, err)
  257. return
  258. }
  259. var out ApiRun
  260. out.Id = id
  261. if memoryW {
  262. out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
  263. }
  264. if swapW {
  265. out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
  266. }
  267. b, err := json.Marshal(out)
  268. if err != nil {
  269. http.Error(w, err.Error(), http.StatusInternalServerError)
  270. } else {
  271. w.Write(b)
  272. }
  273. })
  274. r.Path("/containers/{name:.*}/restart").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  275. log.Println(r.Method, r.RequestURI)
  276. if err := r.ParseForm(); err != nil {
  277. http.Error(w, err.Error(), http.StatusInternalServerError)
  278. }
  279. t, err := strconv.Atoi(r.Form.Get("t"))
  280. if err != nil || t < 0 {
  281. t = 10
  282. }
  283. vars := mux.Vars(r)
  284. name := vars["name"]
  285. if err := srv.ContainerRestart(name, t); err != nil {
  286. httpError(w, err)
  287. } else {
  288. w.WriteHeader(http.StatusOK)
  289. }
  290. })
  291. r.Path("/containers/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  292. log.Println(r.Method, r.RequestURI)
  293. vars := mux.Vars(r)
  294. name := vars["name"]
  295. if err := srv.ContainerDestroy(name); err != nil {
  296. httpError(w, err)
  297. } else {
  298. w.WriteHeader(http.StatusOK)
  299. }
  300. })
  301. r.Path("/images/{name:.*}").Methods("DELETE").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  302. log.Println(r.Method, r.RequestURI)
  303. vars := mux.Vars(r)
  304. name := vars["name"]
  305. if err := srv.ImageDelete(name); err != nil {
  306. httpError(w, err)
  307. } else {
  308. w.WriteHeader(http.StatusOK)
  309. }
  310. })
  311. r.Path("/containers/{name:.*}/start").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  312. log.Println(r.Method, r.RequestURI)
  313. vars := mux.Vars(r)
  314. name := vars["name"]
  315. if err := srv.ContainerStart(name); err != nil {
  316. httpError(w, err)
  317. } else {
  318. w.WriteHeader(http.StatusOK)
  319. }
  320. })
  321. r.Path("/containers/{name:.*}/stop").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  322. log.Println(r.Method, r.RequestURI)
  323. if err := r.ParseForm(); err != nil {
  324. http.Error(w, err.Error(), http.StatusInternalServerError)
  325. }
  326. t, err := strconv.Atoi(r.Form.Get("t"))
  327. if err != nil || t < 0 {
  328. t = 10
  329. }
  330. vars := mux.Vars(r)
  331. name := vars["name"]
  332. if err := srv.ContainerStop(name, t); err != nil {
  333. httpError(w, err)
  334. } else {
  335. w.WriteHeader(http.StatusOK)
  336. }
  337. })
  338. r.Path("/containers/{name:.*}/wait").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  339. log.Println(r.Method, r.RequestURI)
  340. vars := mux.Vars(r)
  341. name := vars["name"]
  342. status, err := srv.ContainerWait(name)
  343. if err != nil {
  344. httpError(w, err)
  345. }
  346. b, err := json.Marshal(ApiWait{status})
  347. if err != nil {
  348. http.Error(w, err.Error(), http.StatusInternalServerError)
  349. } else {
  350. w.Write(b)
  351. }
  352. })
  353. r.Path("/containers/{name:.*}/attach").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  354. log.Println(r.Method, r.RequestURI)
  355. if err := r.ParseForm(); err != nil {
  356. http.Error(w, err.Error(), http.StatusInternalServerError)
  357. }
  358. logs := r.Form.Get("logs")
  359. stream := r.Form.Get("stream")
  360. stdin := r.Form.Get("stdin")
  361. stdout := r.Form.Get("stdout")
  362. stderr := r.Form.Get("stderr")
  363. vars := mux.Vars(r)
  364. name := vars["name"]
  365. file, rwc, err := hijackServer(w)
  366. if file != nil {
  367. defer file.Close()
  368. }
  369. if rwc != nil {
  370. defer rwc.Close()
  371. }
  372. if err != nil {
  373. httpError(w, err)
  374. return
  375. }
  376. fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n")
  377. if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, file); err != nil {
  378. fmt.Fprintln(file, "Error: "+err.Error())
  379. }
  380. })
  381. r.Path("/containers/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  382. log.Println(r.Method, r.RequestURI)
  383. vars := mux.Vars(r)
  384. name := vars["name"]
  385. container, err := srv.ContainerInspect(name)
  386. if err != nil {
  387. httpError(w, err)
  388. }
  389. b, err := json.Marshal(container)
  390. if err != nil {
  391. http.Error(w, err.Error(), http.StatusInternalServerError)
  392. } else {
  393. w.Write(b)
  394. }
  395. })
  396. r.Path("/images/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  397. log.Println(r.Method, r.RequestURI)
  398. vars := mux.Vars(r)
  399. name := vars["name"]
  400. image, err := srv.ImageInspect(name)
  401. if err != nil {
  402. httpError(w, err)
  403. }
  404. b, err := json.Marshal(image)
  405. if err != nil {
  406. http.Error(w, err.Error(), http.StatusInternalServerError)
  407. } else {
  408. w.Write(b)
  409. }
  410. })
  411. return http.ListenAndServe(addr, r)
  412. }