server.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. package docker
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "net/http"
  7. "net/url"
  8. "os"
  9. "runtime"
  10. "strings"
  11. )
  12. func (srv *Server) DockerVersion() ApiVersion {
  13. return ApiVersion{VERSION, GIT_COMMIT, srv.runtime.capabilities.MemoryLimit, srv.runtime.capabilities.SwapLimit}
  14. }
  15. func (srv *Server) ContainerKill(name string) error {
  16. if container := srv.runtime.Get(name); container != nil {
  17. if err := container.Kill(); err != nil {
  18. return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
  19. }
  20. } else {
  21. return fmt.Errorf("No such container: %s", name)
  22. }
  23. return nil
  24. }
  25. func (srv *Server) ContainerExport(name string, file *os.File) error {
  26. if container := srv.runtime.Get(name); container != nil {
  27. data, err := container.Export()
  28. if err != nil {
  29. return err
  30. }
  31. // Stream the entire contents of the container (basically a volatile snapshot)
  32. if _, err := io.Copy(file, data); err != nil {
  33. return err
  34. }
  35. return nil
  36. }
  37. return fmt.Errorf("No such container: %s", name)
  38. }
  39. func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
  40. results, err := srv.runtime.graph.SearchRepositories(nil, term)
  41. if err != nil {
  42. return nil, err
  43. }
  44. var outs []ApiSearch
  45. for _, repo := range results.Results {
  46. var out ApiSearch
  47. out.Description = repo["description"]
  48. if len(out.Description) > 45 {
  49. out.Description = Trunc(out.Description, 42) + "..."
  50. }
  51. out.Name = repo["name"]
  52. outs = append(outs, out)
  53. }
  54. return outs, nil
  55. }
  56. func (srv *Server) ImageInsert(name, url, path string, stdout *os.File) error {
  57. img, err := srv.runtime.repositories.LookupImage(name)
  58. if err != nil {
  59. return err
  60. }
  61. file, err := Download(url, stdout)
  62. if err != nil {
  63. return err
  64. }
  65. defer file.Body.Close()
  66. config, _, err := ParseRun([]string{img.Id, "echo", "insert", url, path}, srv.runtime.capabilities)
  67. if err != nil {
  68. return err
  69. }
  70. b := NewBuilder(srv.runtime)
  71. c, err := b.Create(config)
  72. if err != nil {
  73. return err
  74. }
  75. if err := c.Inject(ProgressReader(file.Body, int(file.ContentLength), stdout, "Downloading %v/%v (%v)"), path); err != nil {
  76. return err
  77. }
  78. // FIXME: Handle custom repo, tag comment, author
  79. img, err = b.Commit(c, "", "", img.Comment, img.Author, nil)
  80. if err != nil {
  81. return err
  82. }
  83. fmt.Fprintf(stdout, "%s\n", img.Id)
  84. return nil
  85. }
  86. func (srv *Server) ImagesViz(file *os.File) error {
  87. images, _ := srv.runtime.graph.All()
  88. if images == nil {
  89. return nil
  90. }
  91. fmt.Fprintf(file, "digraph docker {\n")
  92. var parentImage *Image
  93. var err error
  94. for _, image := range images {
  95. parentImage, err = image.GetParent()
  96. if err != nil {
  97. return fmt.Errorf("Error while getting parent image: %v", err)
  98. }
  99. if parentImage != nil {
  100. fmt.Fprintf(file, " \"%s\" -> \"%s\"\n", parentImage.ShortId(), image.ShortId())
  101. } else {
  102. fmt.Fprintf(file, " base -> \"%s\" [style=invis]\n", image.ShortId())
  103. }
  104. }
  105. reporefs := make(map[string][]string)
  106. for name, repository := range srv.runtime.repositories.Repositories {
  107. for tag, id := range repository {
  108. reporefs[TruncateId(id)] = append(reporefs[TruncateId(id)], fmt.Sprintf("%s:%s", name, tag))
  109. }
  110. }
  111. for id, repos := range reporefs {
  112. fmt.Fprintf(file, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", id, id, strings.Join(repos, "\\n"))
  113. }
  114. fmt.Fprintf(file, " base [style=invisible]\n")
  115. fmt.Fprintf(file, "}\n")
  116. return nil
  117. }
  118. func (srv *Server) Images(all, quiet bool, filter string) ([]ApiImages, error) {
  119. var allImages map[string]*Image
  120. var err error
  121. if all {
  122. allImages, err = srv.runtime.graph.Map()
  123. } else {
  124. allImages, err = srv.runtime.graph.Heads()
  125. }
  126. if err != nil {
  127. return nil, err
  128. }
  129. var outs []ApiImages = []ApiImages{} //produce [] when empty instead of 'null'
  130. for name, repository := range srv.runtime.repositories.Repositories {
  131. if filter != "" && name != filter {
  132. continue
  133. }
  134. for tag, id := range repository {
  135. var out ApiImages
  136. image, err := srv.runtime.graph.Get(id)
  137. if err != nil {
  138. log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
  139. continue
  140. }
  141. delete(allImages, id)
  142. if !quiet {
  143. out.Repository = name
  144. out.Tag = tag
  145. out.Id = TruncateId(id)
  146. out.Created = image.Created.Unix()
  147. } else {
  148. out.Id = image.ShortId()
  149. }
  150. outs = append(outs, out)
  151. }
  152. }
  153. // Display images which aren't part of a
  154. if filter == "" {
  155. for id, image := range allImages {
  156. var out ApiImages
  157. if !quiet {
  158. out.Repository = "<none>"
  159. out.Tag = "<none>"
  160. out.Id = TruncateId(id)
  161. out.Created = image.Created.Unix()
  162. } else {
  163. out.Id = image.ShortId()
  164. }
  165. outs = append(outs, out)
  166. }
  167. }
  168. return outs, nil
  169. }
  170. func (srv *Server) DockerInfo() ApiInfo {
  171. images, _ := srv.runtime.graph.All()
  172. var imgcount int
  173. if images == nil {
  174. imgcount = 0
  175. } else {
  176. imgcount = len(images)
  177. }
  178. var out ApiInfo
  179. out.Containers = len(srv.runtime.List())
  180. out.Version = VERSION
  181. out.Images = imgcount
  182. if os.Getenv("DEBUG") != "" {
  183. out.Debug = true
  184. out.NFd = getTotalUsedFds()
  185. out.NGoroutines = runtime.NumGoroutine()
  186. }
  187. return out
  188. }
  189. func (srv *Server) ImageHistory(name string) ([]ApiHistory, error) {
  190. image, err := srv.runtime.repositories.LookupImage(name)
  191. if err != nil {
  192. return nil, err
  193. }
  194. var outs []ApiHistory = []ApiHistory{} //produce [] when empty instead of 'null'
  195. err = image.WalkHistory(func(img *Image) error {
  196. var out ApiHistory
  197. out.Id = srv.runtime.repositories.ImageName(img.ShortId())
  198. out.Created = img.Created.Unix()
  199. out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
  200. outs = append(outs, out)
  201. return nil
  202. })
  203. return outs, nil
  204. }
  205. func (srv *Server) ContainerChanges(name string) ([]string, error) {
  206. if container := srv.runtime.Get(name); container != nil {
  207. changes, err := container.Changes()
  208. if err != nil {
  209. return nil, err
  210. }
  211. var changesStr []string
  212. for _, name := range changes {
  213. changesStr = append(changesStr, name.String())
  214. }
  215. return changesStr, nil
  216. }
  217. return nil, fmt.Errorf("No such container: %s", name)
  218. }
  219. func (srv *Server) ContainerPort(name, privatePort string) (string, error) {
  220. if container := srv.runtime.Get(name); container != nil {
  221. if frontend, exists := container.NetworkSettings.PortMapping[privatePort]; exists {
  222. return frontend, nil
  223. }
  224. return "", fmt.Errorf("No private port '%s' allocated on %s", privatePort, name)
  225. }
  226. return "", fmt.Errorf("No such container: %s", name)
  227. }
  228. func (srv *Server) Containers(all, notrunc, quiet bool, n int) []ApiContainers {
  229. var outs []ApiContainers = []ApiContainers{} //produce [] when empty instead of 'null'
  230. for i, container := range srv.runtime.List() {
  231. if !container.State.Running && !all && n == -1 {
  232. continue
  233. }
  234. if i == n {
  235. break
  236. }
  237. var out ApiContainers
  238. out.Id = container.ShortId()
  239. if !quiet {
  240. command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  241. if !notrunc {
  242. command = Trunc(command, 20)
  243. }
  244. out.Image = srv.runtime.repositories.ImageName(container.Image)
  245. out.Command = command
  246. out.Created = container.Created.Unix()
  247. out.Status = container.State.String()
  248. out.Ports = container.NetworkSettings.PortMappingHuman()
  249. }
  250. outs = append(outs, out)
  251. }
  252. return outs
  253. }
  254. func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, config *Config) (string, error) {
  255. container := srv.runtime.Get(name)
  256. if container == nil {
  257. return "", fmt.Errorf("No such container: %s", name)
  258. }
  259. img, err := NewBuilder(srv.runtime).Commit(container, repo, tag, comment, author, config)
  260. if err != nil {
  261. return "", err
  262. }
  263. return img.ShortId(), err
  264. }
  265. func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
  266. if err := srv.runtime.repositories.Set(repo, tag, name, force); err != nil {
  267. return err
  268. }
  269. return nil
  270. }
  271. func (srv *Server) ImagePull(name, tag, registry string, file *os.File) error {
  272. if registry != "" {
  273. if err := srv.runtime.graph.PullImage(file, name, registry, nil); err != nil {
  274. return err
  275. }
  276. return nil
  277. }
  278. if err := srv.runtime.graph.PullRepository(file, name, tag, srv.runtime.repositories, srv.runtime.authConfig); err != nil {
  279. return err
  280. }
  281. return nil
  282. }
  283. func (srv *Server) ImagePush(name, registry string, file *os.File) error {
  284. img, err := srv.runtime.graph.Get(name)
  285. if err != nil {
  286. Debugf("The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))
  287. // If it fails, try to get the repository
  288. if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
  289. if err := srv.runtime.graph.PushRepository(file, name, localRepo, srv.runtime.authConfig); err != nil {
  290. return err
  291. }
  292. return nil
  293. }
  294. return err
  295. }
  296. err = srv.runtime.graph.PushImage(file, img, registry, nil)
  297. if err != nil {
  298. return err
  299. }
  300. return nil
  301. }
  302. func (srv *Server) ImageImport(src, repo, tag string, file *os.File) error {
  303. var archive io.Reader
  304. var resp *http.Response
  305. if src == "-" {
  306. archive = file
  307. } else {
  308. u, err := url.Parse(src)
  309. if err != nil {
  310. fmt.Fprintf(file, "Error: %s\n", err)
  311. }
  312. if u.Scheme == "" {
  313. u.Scheme = "http"
  314. u.Host = src
  315. u.Path = ""
  316. }
  317. fmt.Fprintln(file, "Downloading from", u)
  318. // Download with curl (pretty progress bar)
  319. // If curl is not available, fallback to http.Get()
  320. resp, err = Download(u.String(), file)
  321. if err != nil {
  322. return err
  323. }
  324. archive = ProgressReader(resp.Body, int(resp.ContentLength), file, "Importing %v/%v (%v)")
  325. }
  326. img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
  327. if err != nil {
  328. return err
  329. }
  330. // Optionally register the image at REPO/TAG
  331. if repo != "" {
  332. if err := srv.runtime.repositories.Set(repo, tag, img.Id, true); err != nil {
  333. return err
  334. }
  335. }
  336. fmt.Fprintln(file, img.ShortId())
  337. return nil
  338. }
  339. func (srv *Server) ContainerCreate(config Config) (string, bool, bool, error) {
  340. var memoryW, swapW bool
  341. if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
  342. memoryW = true
  343. log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
  344. config.Memory = 0
  345. }
  346. if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
  347. swapW = true
  348. log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
  349. config.MemorySwap = -1
  350. }
  351. b := NewBuilder(srv.runtime)
  352. container, err := b.Create(&config)
  353. if err != nil {
  354. if srv.runtime.graph.IsNotExist(err) {
  355. return "", false, false, fmt.Errorf("No such image: %s", config.Image)
  356. }
  357. return "", false, false, err
  358. }
  359. return container.ShortId(), memoryW, swapW, nil
  360. }
  361. func (srv *Server) ImageCreateFormFile(file *os.File) error {
  362. img, err := NewBuilder(srv.runtime).Build(file, file)
  363. if err != nil {
  364. return err
  365. }
  366. fmt.Fprintf(file, "%s\n", img.ShortId())
  367. return nil
  368. }
  369. func (srv *Server) ContainerRestart(name string, t int) error {
  370. if container := srv.runtime.Get(name); container != nil {
  371. if err := container.Restart(t); err != nil {
  372. return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
  373. }
  374. } else {
  375. return fmt.Errorf("No such container: %s", name)
  376. }
  377. return nil
  378. }
  379. func (srv *Server) ContainerDestroy(name string, v bool) error {
  380. if container := srv.runtime.Get(name); container != nil {
  381. volumes := make(map[string]struct{})
  382. // Store all the deleted containers volumes
  383. for _, volumeId := range container.Volumes {
  384. volumes[volumeId] = struct{}{}
  385. }
  386. if err := srv.runtime.Destroy(container); err != nil {
  387. return fmt.Errorf("Error destroying container %s: %s", name, err.Error())
  388. }
  389. if v {
  390. // Retrieve all volumes from all remaining containers
  391. usedVolumes := make(map[string]*Container)
  392. for _, container := range srv.runtime.List() {
  393. for _, containerVolumeId := range container.Volumes {
  394. usedVolumes[containerVolumeId] = container
  395. }
  396. }
  397. for volumeId := range volumes {
  398. // If the requested volu
  399. if c, exists := usedVolumes[volumeId]; exists {
  400. log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.Id)
  401. continue
  402. }
  403. if err := srv.runtime.volumes.Delete(volumeId); err != nil {
  404. return err
  405. }
  406. }
  407. }
  408. } else {
  409. return fmt.Errorf("No such container: %s", name)
  410. }
  411. return nil
  412. }
  413. func (srv *Server) ImageDelete(name string) error {
  414. img, err := srv.runtime.repositories.LookupImage(name)
  415. if err != nil {
  416. return fmt.Errorf("No such image: %s", name)
  417. } else {
  418. if err := srv.runtime.graph.Delete(img.Id); err != nil {
  419. return fmt.Errorf("Error deleteing image %s: %s", name, err.Error())
  420. }
  421. }
  422. return nil
  423. }
  424. func (srv *Server) ContainerStart(name string) error {
  425. if container := srv.runtime.Get(name); container != nil {
  426. if err := container.Start(); err != nil {
  427. return fmt.Errorf("Error starting container %s: %s", name, err.Error())
  428. }
  429. } else {
  430. return fmt.Errorf("No such container: %s", name)
  431. }
  432. return nil
  433. }
  434. func (srv *Server) ContainerStop(name string, t int) error {
  435. if container := srv.runtime.Get(name); container != nil {
  436. if err := container.Stop(t); err != nil {
  437. return fmt.Errorf("Error stopping container %s: %s", name, err.Error())
  438. }
  439. } else {
  440. return fmt.Errorf("No such container: %s", name)
  441. }
  442. return nil
  443. }
  444. func (srv *Server) ContainerWait(name string) (int, error) {
  445. if container := srv.runtime.Get(name); container != nil {
  446. return container.Wait(), nil
  447. }
  448. return 0, fmt.Errorf("No such container: %s", name)
  449. }
  450. func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, file *os.File) error {
  451. if container := srv.runtime.Get(name); container != nil {
  452. //logs
  453. if logs {
  454. if stdout {
  455. cLog, err := container.ReadLog("stdout")
  456. if err != nil {
  457. Debugf(err.Error())
  458. } else if _, err := io.Copy(file, cLog); err != nil {
  459. Debugf(err.Error())
  460. }
  461. }
  462. if stderr {
  463. cLog, err := container.ReadLog("stderr")
  464. if err != nil {
  465. Debugf(err.Error())
  466. } else if _, err := io.Copy(file, cLog); err != nil {
  467. Debugf(err.Error())
  468. }
  469. }
  470. }
  471. //stream
  472. if stream {
  473. if container.State.Ghost {
  474. return fmt.Errorf("Impossible to attach to a ghost container")
  475. }
  476. var (
  477. cStdin io.ReadCloser
  478. cStdout, cStderr io.Writer
  479. cStdinCloser io.Closer
  480. )
  481. if stdin {
  482. r, w := io.Pipe()
  483. go func() {
  484. defer w.Close()
  485. defer Debugf("Closing buffered stdin pipe")
  486. io.Copy(w, file)
  487. }()
  488. cStdin = r
  489. cStdinCloser = file
  490. }
  491. if stdout {
  492. cStdout = file
  493. }
  494. if stderr {
  495. cStderr = file
  496. }
  497. <-container.Attach(cStdin, cStdinCloser, cStdout, cStderr)
  498. // If we are in stdinonce mode, wait for the process to end
  499. // otherwise, simply return
  500. if container.Config.StdinOnce && !container.Config.Tty {
  501. container.Wait()
  502. }
  503. }
  504. } else {
  505. return fmt.Errorf("No such container: %s", name)
  506. }
  507. return nil
  508. }
  509. func (srv *Server) ContainerInspect(name string) (*Container, error) {
  510. if container := srv.runtime.Get(name); container != nil {
  511. return container, nil
  512. }
  513. return nil, fmt.Errorf("No such container: %s", name)
  514. }
  515. func (srv *Server) ImageInspect(name string) (*Image, error) {
  516. if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil {
  517. return image, nil
  518. }
  519. return nil, fmt.Errorf("No such image: %s", name)
  520. }
  521. func NewServer(autoRestart bool) (*Server, error) {
  522. if runtime.GOARCH != "amd64" {
  523. log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
  524. }
  525. runtime, err := NewRuntime(autoRestart)
  526. if err != nil {
  527. return nil, err
  528. }
  529. srv := &Server{
  530. runtime: runtime,
  531. }
  532. return srv, nil
  533. }
  534. type Server struct {
  535. runtime *Runtime
  536. }