server.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. package docker
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker/auth"
  5. "github.com/dotcloud/docker/registry"
  6. "github.com/dotcloud/docker/utils"
  7. "io"
  8. "io/ioutil"
  9. "log"
  10. "net/http"
  11. "net/url"
  12. "os"
  13. "path"
  14. "runtime"
  15. "strings"
  16. )
  17. func (srv *Server) DockerVersion() APIVersion {
  18. return APIVersion{
  19. Version: VERSION,
  20. GitCommit: GITCOMMIT,
  21. GoVersion: runtime.Version(),
  22. }
  23. }
  24. func (srv *Server) ContainerKill(name string) error {
  25. if container := srv.runtime.Get(name); container != nil {
  26. if err := container.Kill(); err != nil {
  27. return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
  28. }
  29. } else {
  30. return fmt.Errorf("No such container: %s", name)
  31. }
  32. return nil
  33. }
  34. func (srv *Server) ContainerExport(name string, out io.Writer) error {
  35. if container := srv.runtime.Get(name); container != nil {
  36. data, err := container.Export()
  37. if err != nil {
  38. return err
  39. }
  40. // Stream the entire contents of the container (basically a volatile snapshot)
  41. if _, err := io.Copy(out, data); err != nil {
  42. return err
  43. }
  44. return nil
  45. }
  46. return fmt.Errorf("No such container: %s", name)
  47. }
  48. func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
  49. results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term)
  50. if err != nil {
  51. return nil, err
  52. }
  53. var outs []APISearch
  54. for _, repo := range results.Results {
  55. var out APISearch
  56. out.Description = repo["description"]
  57. if len(out.Description) > 45 {
  58. out.Description = utils.Trunc(out.Description, 42) + "..."
  59. }
  60. out.Name = repo["name"]
  61. outs = append(outs, out)
  62. }
  63. return outs, nil
  64. }
  65. func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.StreamFormatter) (string, error) {
  66. out = utils.NewWriteFlusher(out)
  67. img, err := srv.runtime.repositories.LookupImage(name)
  68. if err != nil {
  69. return "", err
  70. }
  71. file, err := utils.Download(url, out)
  72. if err != nil {
  73. return "", err
  74. }
  75. defer file.Body.Close()
  76. config, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
  77. if err != nil {
  78. return "", err
  79. }
  80. b := NewBuilder(srv.runtime)
  81. c, err := b.Create(config)
  82. if err != nil {
  83. return "", err
  84. }
  85. if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), path); err != nil {
  86. return "", err
  87. }
  88. // FIXME: Handle custom repo, tag comment, author
  89. img, err = b.Commit(c, "", "", img.Comment, img.Author, nil)
  90. if err != nil {
  91. return "", err
  92. }
  93. out.Write(sf.FormatStatus(img.ID))
  94. return img.ShortID(), nil
  95. }
  96. func (srv *Server) ImagesViz(out io.Writer) error {
  97. images, _ := srv.runtime.graph.All()
  98. if images == nil {
  99. return nil
  100. }
  101. out.Write([]byte("digraph docker {\n"))
  102. var (
  103. parentImage *Image
  104. err error
  105. )
  106. for _, image := range images {
  107. parentImage, err = image.GetParent()
  108. if err != nil {
  109. return fmt.Errorf("Error while getting parent image: %v", err)
  110. }
  111. if parentImage != nil {
  112. out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
  113. } else {
  114. out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
  115. }
  116. }
  117. reporefs := make(map[string][]string)
  118. for name, repository := range srv.runtime.repositories.Repositories {
  119. for tag, id := range repository {
  120. reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
  121. }
  122. }
  123. for id, repos := range reporefs {
  124. out.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
  125. }
  126. out.Write([]byte(" base [style=invisible]\n}\n"))
  127. return nil
  128. }
  129. func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
  130. var (
  131. allImages map[string]*Image
  132. err error
  133. )
  134. if all {
  135. allImages, err = srv.runtime.graph.Map()
  136. } else {
  137. allImages, err = srv.runtime.graph.Heads()
  138. }
  139. if err != nil {
  140. return nil, err
  141. }
  142. outs := []APIImages{} //produce [] when empty instead of 'null'
  143. for name, repository := range srv.runtime.repositories.Repositories {
  144. if filter != "" && name != filter {
  145. continue
  146. }
  147. for tag, id := range repository {
  148. var out APIImages
  149. image, err := srv.runtime.graph.Get(id)
  150. if err != nil {
  151. log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
  152. continue
  153. }
  154. delete(allImages, id)
  155. out.Repository = name
  156. out.Tag = tag
  157. out.ID = image.ID
  158. out.Created = image.Created.Unix()
  159. outs = append(outs, out)
  160. }
  161. }
  162. // Display images which aren't part of a
  163. if filter == "" {
  164. for _, image := range allImages {
  165. var out APIImages
  166. out.ID = image.ID
  167. out.Created = image.Created.Unix()
  168. outs = append(outs, out)
  169. }
  170. }
  171. return outs, nil
  172. }
  173. func (srv *Server) DockerInfo() *APIInfo {
  174. images, _ := srv.runtime.graph.All()
  175. var imgcount int
  176. if images == nil {
  177. imgcount = 0
  178. } else {
  179. imgcount = len(images)
  180. }
  181. return &APIInfo{
  182. Containers: len(srv.runtime.List()),
  183. Images: imgcount,
  184. MemoryLimit: srv.runtime.capabilities.MemoryLimit,
  185. SwapLimit: srv.runtime.capabilities.SwapLimit,
  186. Debug: os.Getenv("DEBUG") != "",
  187. NFd: utils.GetTotalUsedFds(),
  188. NGoroutines: runtime.NumGoroutine(),
  189. }
  190. }
  191. func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
  192. image, err := srv.runtime.repositories.LookupImage(name)
  193. if err != nil {
  194. return nil, err
  195. }
  196. outs := []APIHistory{} //produce [] when empty instead of 'null'
  197. err = image.WalkHistory(func(img *Image) error {
  198. var out APIHistory
  199. out.ID = srv.runtime.repositories.ImageName(img.ShortID())
  200. out.Created = img.Created.Unix()
  201. out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
  202. outs = append(outs, out)
  203. return nil
  204. })
  205. return outs, nil
  206. }
  207. func (srv *Server) ContainerChanges(name string) ([]Change, error) {
  208. if container := srv.runtime.Get(name); container != nil {
  209. return container.Changes()
  210. }
  211. return nil, fmt.Errorf("No such container: %s", name)
  212. }
  213. func (srv *Server) Containers(all bool, n int, since, before string) []APIContainers {
  214. var foundBefore bool
  215. var displayed int
  216. retContainers := []APIContainers{}
  217. for _, container := range srv.runtime.List() {
  218. if !container.State.Running && !all && n == -1 && since == "" && before == "" {
  219. continue
  220. }
  221. if before != "" {
  222. if container.ShortID() == before {
  223. foundBefore = true
  224. continue
  225. }
  226. if !foundBefore {
  227. continue
  228. }
  229. }
  230. if displayed == n {
  231. break
  232. }
  233. if container.ShortID() == since {
  234. break
  235. }
  236. displayed++
  237. c := APIContainers{
  238. ID: container.ID,
  239. }
  240. c.Image = srv.runtime.repositories.ImageName(container.Image)
  241. c.Command = fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  242. c.Created = container.Created.Unix()
  243. c.Status = container.State.String()
  244. c.Ports = container.NetworkSettings.PortMappingHuman()
  245. retContainers = append(retContainers, c)
  246. }
  247. return retContainers
  248. }
  249. func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, config *Config) (string, error) {
  250. container := srv.runtime.Get(name)
  251. if container == nil {
  252. return "", fmt.Errorf("No such container: %s", name)
  253. }
  254. img, err := NewBuilder(srv.runtime).Commit(container, repo, tag, comment, author, config)
  255. if err != nil {
  256. return "", err
  257. }
  258. return img.ShortID(), err
  259. }
  260. func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
  261. if err := srv.runtime.repositories.Set(repo, tag, name, force); err != nil {
  262. return err
  263. }
  264. return nil
  265. }
  266. func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoint string, token []string, sf *utils.StreamFormatter) error {
  267. history, err := r.GetRemoteHistory(imgId, endpoint, token)
  268. if err != nil {
  269. return err
  270. }
  271. // FIXME: Try to stream the images?
  272. // FIXME: Launch the getRemoteImage() in goroutines
  273. for _, id := range history {
  274. if !srv.runtime.graph.Exists(id) {
  275. out.Write(sf.FormatStatus("Pulling %s metadata", id))
  276. imgJSON, err := r.GetRemoteImageJSON(id, endpoint, token)
  277. if err != nil {
  278. // FIXME: Keep goging in case of error?
  279. return err
  280. }
  281. img, err := NewImgJSON(imgJSON)
  282. if err != nil {
  283. return fmt.Errorf("Failed to parse json: %s", err)
  284. }
  285. // Get the layer
  286. out.Write(sf.FormatStatus("Pulling %s fs layer", id))
  287. layer, contentLength, err := r.GetRemoteImageLayer(img.ID, endpoint, token)
  288. if err != nil {
  289. return err
  290. }
  291. defer layer.Close()
  292. if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil {
  293. return err
  294. }
  295. }
  296. }
  297. return nil
  298. }
  299. func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, remote, askedTag string, sf *utils.StreamFormatter) error {
  300. out.Write(sf.FormatStatus("Pulling repository %s from %s", local, auth.IndexServerAddress()))
  301. repoData, err := r.GetRepositoryData(remote)
  302. if err != nil {
  303. return err
  304. }
  305. utils.Debugf("Updating checksums")
  306. // Reload the json file to make sure not to overwrite faster sums
  307. if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
  308. return err
  309. }
  310. utils.Debugf("Retrieving the tag list")
  311. tagsList, err := r.GetRemoteTags(repoData.Endpoints, remote, repoData.Tokens)
  312. if err != nil {
  313. return err
  314. }
  315. utils.Debugf("Registering tags")
  316. // If not specific tag have been asked, take all
  317. if askedTag == "" {
  318. for tag, id := range tagsList {
  319. repoData.ImgList[id].Tag = tag
  320. }
  321. } else {
  322. // Otherwise, check that the tag exists and use only that one
  323. id, exists := tagsList[askedTag]
  324. if !exists {
  325. return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, local)
  326. }
  327. repoData.ImgList[id].Tag = askedTag
  328. }
  329. for _, img := range repoData.ImgList {
  330. if askedTag != "" && img.Tag != askedTag {
  331. utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
  332. continue
  333. }
  334. out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
  335. success := false
  336. for _, ep := range repoData.Endpoints {
  337. if err := srv.pullImage(r, out, img.ID, "https://"+ep+"/v1", repoData.Tokens, sf); err != nil {
  338. out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
  339. continue
  340. }
  341. success = true
  342. break
  343. }
  344. if !success {
  345. return fmt.Errorf("Could not find repository on any of the indexed registries.")
  346. }
  347. }
  348. for tag, id := range tagsList {
  349. if askedTag != "" && tag != askedTag {
  350. continue
  351. }
  352. if err := srv.runtime.repositories.Set(local, tag, id, true); err != nil {
  353. return err
  354. }
  355. }
  356. if err := srv.runtime.repositories.Save(); err != nil {
  357. return err
  358. }
  359. return nil
  360. }
  361. func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter) error {
  362. r := registry.NewRegistry(srv.runtime.root)
  363. out = utils.NewWriteFlusher(out)
  364. if endpoint != "" {
  365. if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil {
  366. return err
  367. }
  368. return nil
  369. }
  370. remote := name
  371. parts := strings.Split(name, "/")
  372. if len(parts) > 2 {
  373. remote = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
  374. }
  375. if err := srv.pullRepository(r, out, name, remote, tag, sf); err != nil {
  376. return err
  377. }
  378. return nil
  379. }
  380. // Retrieve the checksum of an image
  381. // Priority:
  382. // - Check on the stored checksums
  383. // - Check if the archive exists, if it does not, ask the registry
  384. // - If the archive does exists, process the checksum from it
  385. // - If the archive does not exists and not found on registry, process checksum from layer
  386. func (srv *Server) getChecksum(imageId string) (string, error) {
  387. // FIXME: Use in-memory map instead of reading the file each time
  388. if sums, err := srv.runtime.graph.getStoredChecksums(); err != nil {
  389. return "", err
  390. } else if checksum, exists := sums[imageId]; exists {
  391. return checksum, nil
  392. }
  393. img, err := srv.runtime.graph.Get(imageId)
  394. if err != nil {
  395. return "", err
  396. }
  397. if _, err := os.Stat(layerArchivePath(srv.runtime.graph.imageRoot(imageId))); err != nil {
  398. if os.IsNotExist(err) {
  399. // TODO: Ask the registry for the checksum
  400. // As the archive is not there, it is supposed to come from a pull.
  401. } else {
  402. return "", err
  403. }
  404. }
  405. checksum, err := img.Checksum()
  406. if err != nil {
  407. return "", err
  408. }
  409. return checksum, nil
  410. }
  411. // Retrieve the all the images to be uploaded in the correct order
  412. // Note: we can't use a map as it is not ordered
  413. func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgData, error) {
  414. var imgList []*registry.ImgData
  415. imageSet := make(map[string]struct{})
  416. for tag, id := range localRepo {
  417. img, err := srv.runtime.graph.Get(id)
  418. if err != nil {
  419. return nil, err
  420. }
  421. img.WalkHistory(func(img *Image) error {
  422. if _, exists := imageSet[img.ID]; exists {
  423. return nil
  424. }
  425. imageSet[img.ID] = struct{}{}
  426. checksum, err := srv.getChecksum(img.ID)
  427. if err != nil {
  428. return err
  429. }
  430. imgList = append([]*registry.ImgData{{
  431. ID: img.ID,
  432. Checksum: checksum,
  433. Tag: tag,
  434. }}, imgList...)
  435. return nil
  436. })
  437. }
  438. return imgList, nil
  439. }
  440. func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name string, localRepo map[string]string, sf *utils.StreamFormatter) error {
  441. out = utils.NewWriteFlusher(out)
  442. out.Write(sf.FormatStatus("Processing checksums"))
  443. imgList, err := srv.getImageList(localRepo)
  444. if err != nil {
  445. return err
  446. }
  447. out.Write(sf.FormatStatus("Sending image list"))
  448. srvName := name
  449. parts := strings.Split(name, "/")
  450. if len(parts) > 2 {
  451. srvName = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
  452. }
  453. repoData, err := r.PushImageJSONIndex(srvName, imgList, false)
  454. if err != nil {
  455. return err
  456. }
  457. for _, ep := range repoData.Endpoints {
  458. out.Write(sf.FormatStatus("Pushing repository %s to %s (%d tags)", name, ep, len(localRepo)))
  459. // For each image within the repo, push them
  460. for _, elem := range imgList {
  461. if _, exists := repoData.ImgList[elem.ID]; exists {
  462. out.Write(sf.FormatStatus("Image %s already on registry, skipping", name))
  463. continue
  464. }
  465. if err := srv.pushImage(r, out, name, elem.ID, ep, repoData.Tokens, sf); err != nil {
  466. // FIXME: Continue on error?
  467. return err
  468. }
  469. out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/users/"+srvName+"/"+elem.Tag))
  470. if err := r.PushRegistryTag(srvName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
  471. return err
  472. }
  473. }
  474. }
  475. if _, err := r.PushImageJSONIndex(srvName, imgList, true); err != nil {
  476. return err
  477. }
  478. return nil
  479. }
  480. func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, ep string, token []string, sf *utils.StreamFormatter) error {
  481. out = utils.NewWriteFlusher(out)
  482. jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgId, "json"))
  483. if err != nil {
  484. return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgId, err)
  485. }
  486. out.Write(sf.FormatStatus("Pushing %s", imgId))
  487. // Make sure we have the image's checksum
  488. checksum, err := srv.getChecksum(imgId)
  489. if err != nil {
  490. return err
  491. }
  492. imgData := &registry.ImgData{
  493. ID: imgId,
  494. Checksum: checksum,
  495. }
  496. // Send the json
  497. if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
  498. if err == registry.ErrAlreadyExists {
  499. out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.ID))
  500. return nil
  501. }
  502. return err
  503. }
  504. // Retrieve the tarball to be sent
  505. var layerData *TempArchive
  506. // If the archive exists, use it
  507. file, err := os.Open(layerArchivePath(srv.runtime.graph.imageRoot(imgId)))
  508. if err != nil {
  509. if os.IsNotExist(err) {
  510. // If the archive does not exist, create one from the layer
  511. layerData, err = srv.runtime.graph.TempLayerArchive(imgId, Xz, out)
  512. if err != nil {
  513. return fmt.Errorf("Failed to generate layer archive: %s", err)
  514. }
  515. } else {
  516. return err
  517. }
  518. } else {
  519. defer file.Close()
  520. st, err := file.Stat()
  521. if err != nil {
  522. return err
  523. }
  524. layerData = &TempArchive{
  525. File: file,
  526. Size: st.Size(),
  527. }
  528. }
  529. // Send the layer
  530. if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%v/%v (%v)"), sf), ep, token); err != nil {
  531. return err
  532. }
  533. return nil
  534. }
  535. func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter) error {
  536. out = utils.NewWriteFlusher(out)
  537. img, err := srv.runtime.graph.Get(name)
  538. r := registry.NewRegistry(srv.runtime.root)
  539. if err != nil {
  540. out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name])))
  541. // If it fails, try to get the repository
  542. if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
  543. if err := srv.pushRepository(r, out, name, localRepo, sf); err != nil {
  544. return err
  545. }
  546. return nil
  547. }
  548. return err
  549. }
  550. out.Write(sf.FormatStatus("The push refers to an image: [%s]", name))
  551. if err := srv.pushImage(r, out, name, img.ID, endpoint, nil, sf); err != nil {
  552. return err
  553. }
  554. return nil
  555. }
  556. func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Writer, sf *utils.StreamFormatter) error {
  557. var archive io.Reader
  558. var resp *http.Response
  559. if src == "-" {
  560. archive = in
  561. } else {
  562. u, err := url.Parse(src)
  563. if err != nil {
  564. return err
  565. }
  566. if u.Scheme == "" {
  567. u.Scheme = "http"
  568. u.Host = src
  569. u.Path = ""
  570. }
  571. out.Write(sf.FormatStatus("Downloading from %s", u))
  572. // Download with curl (pretty progress bar)
  573. // If curl is not available, fallback to http.Get()
  574. resp, err = utils.Download(u.String(), out)
  575. if err != nil {
  576. return err
  577. }
  578. archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%v/%v (%v)"), sf)
  579. }
  580. img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
  581. if err != nil {
  582. return err
  583. }
  584. // Optionally register the image at REPO/TAG
  585. if repo != "" {
  586. if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil {
  587. return err
  588. }
  589. }
  590. out.Write(sf.FormatStatus(img.ShortID()))
  591. return nil
  592. }
  593. func (srv *Server) ContainerCreate(config *Config) (string, error) {
  594. if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
  595. config.Memory = 0
  596. }
  597. if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
  598. config.MemorySwap = -1
  599. }
  600. b := NewBuilder(srv.runtime)
  601. container, err := b.Create(config)
  602. if err != nil {
  603. if srv.runtime.graph.IsNotExist(err) {
  604. return "", fmt.Errorf("No such image: %s", config.Image)
  605. }
  606. return "", err
  607. }
  608. return container.ShortID(), nil
  609. }
  610. func (srv *Server) ContainerRestart(name string, t int) error {
  611. if container := srv.runtime.Get(name); container != nil {
  612. if err := container.Restart(t); err != nil {
  613. return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
  614. }
  615. } else {
  616. return fmt.Errorf("No such container: %s", name)
  617. }
  618. return nil
  619. }
  620. func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
  621. if container := srv.runtime.Get(name); container != nil {
  622. volumes := make(map[string]struct{})
  623. // Store all the deleted containers volumes
  624. for _, volumeId := range container.Volumes {
  625. volumes[volumeId] = struct{}{}
  626. }
  627. if err := srv.runtime.Destroy(container); err != nil {
  628. return fmt.Errorf("Error destroying container %s: %s", name, err.Error())
  629. }
  630. if removeVolume {
  631. // Retrieve all volumes from all remaining containers
  632. usedVolumes := make(map[string]*Container)
  633. for _, container := range srv.runtime.List() {
  634. for _, containerVolumeId := range container.Volumes {
  635. usedVolumes[containerVolumeId] = container
  636. }
  637. }
  638. for volumeId := range volumes {
  639. // If the requested volu
  640. if c, exists := usedVolumes[volumeId]; exists {
  641. log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
  642. continue
  643. }
  644. if err := srv.runtime.volumes.Delete(volumeId); err != nil {
  645. return err
  646. }
  647. }
  648. }
  649. } else {
  650. return fmt.Errorf("No such container: %s", name)
  651. }
  652. return nil
  653. }
  654. func (srv *Server) ImageDelete(name string) error {
  655. img, err := srv.runtime.repositories.LookupImage(name)
  656. if err != nil {
  657. return fmt.Errorf("No such image: %s", name)
  658. }
  659. if err := srv.runtime.graph.Delete(img.ID); err != nil {
  660. return fmt.Errorf("Error deleting image %s: %s", name, err.Error())
  661. }
  662. return nil
  663. }
  664. func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error) {
  665. // Retrieve all images
  666. images, err := srv.runtime.graph.All()
  667. if err != nil {
  668. return nil, err
  669. }
  670. // Store the tree in a map of map (map[parentId][childId])
  671. imageMap := make(map[string]map[string]struct{})
  672. for _, img := range images {
  673. if _, exists := imageMap[img.Parent]; !exists {
  674. imageMap[img.Parent] = make(map[string]struct{})
  675. }
  676. imageMap[img.Parent][img.ID] = struct{}{}
  677. }
  678. // Loop on the children of the given image and check the config
  679. for elem := range imageMap[imgId] {
  680. img, err := srv.runtime.graph.Get(elem)
  681. if err != nil {
  682. return nil, err
  683. }
  684. if CompareConfig(&img.ContainerConfig, config) {
  685. return img, nil
  686. }
  687. }
  688. return nil, nil
  689. }
  690. func (srv *Server) ContainerStart(name string) error {
  691. if container := srv.runtime.Get(name); container != nil {
  692. if err := container.Start(); err != nil {
  693. return fmt.Errorf("Error starting container %s: %s", name, err.Error())
  694. }
  695. } else {
  696. return fmt.Errorf("No such container: %s", name)
  697. }
  698. return nil
  699. }
  700. func (srv *Server) ContainerStop(name string, t int) error {
  701. if container := srv.runtime.Get(name); container != nil {
  702. if err := container.Stop(t); err != nil {
  703. return fmt.Errorf("Error stopping container %s: %s", name, err.Error())
  704. }
  705. } else {
  706. return fmt.Errorf("No such container: %s", name)
  707. }
  708. return nil
  709. }
  710. func (srv *Server) ContainerWait(name string) (int, error) {
  711. if container := srv.runtime.Get(name); container != nil {
  712. return container.Wait(), nil
  713. }
  714. return 0, fmt.Errorf("No such container: %s", name)
  715. }
  716. func (srv *Server) ContainerResize(name string, h, w int) error {
  717. if container := srv.runtime.Get(name); container != nil {
  718. return container.Resize(h, w)
  719. }
  720. return fmt.Errorf("No such container: %s", name)
  721. }
  722. func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, in io.ReadCloser, out io.Writer) error {
  723. container := srv.runtime.Get(name)
  724. if container == nil {
  725. return fmt.Errorf("No such container: %s", name)
  726. }
  727. //logs
  728. if logs {
  729. if stdout {
  730. cLog, err := container.ReadLog("stdout")
  731. if err != nil {
  732. utils.Debugf(err.Error())
  733. } else if _, err := io.Copy(out, cLog); err != nil {
  734. utils.Debugf(err.Error())
  735. }
  736. }
  737. if stderr {
  738. cLog, err := container.ReadLog("stderr")
  739. if err != nil {
  740. utils.Debugf(err.Error())
  741. } else if _, err := io.Copy(out, cLog); err != nil {
  742. utils.Debugf(err.Error())
  743. }
  744. }
  745. }
  746. //stream
  747. if stream {
  748. if container.State.Ghost {
  749. return fmt.Errorf("Impossible to attach to a ghost container")
  750. }
  751. if !container.State.Running {
  752. return fmt.Errorf("Impossible to attach to a stopped container, start it first")
  753. }
  754. var (
  755. cStdin io.ReadCloser
  756. cStdout, cStderr io.Writer
  757. cStdinCloser io.Closer
  758. )
  759. if stdin {
  760. r, w := io.Pipe()
  761. go func() {
  762. defer w.Close()
  763. defer utils.Debugf("Closing buffered stdin pipe")
  764. io.Copy(w, in)
  765. }()
  766. cStdin = r
  767. cStdinCloser = in
  768. }
  769. if stdout {
  770. cStdout = out
  771. }
  772. if stderr {
  773. cStderr = out
  774. }
  775. <-container.Attach(cStdin, cStdinCloser, cStdout, cStderr)
  776. // If we are in stdinonce mode, wait for the process to end
  777. // otherwise, simply return
  778. if container.Config.StdinOnce && !container.Config.Tty {
  779. container.Wait()
  780. }
  781. }
  782. return nil
  783. }
  784. func (srv *Server) ContainerInspect(name string) (*Container, error) {
  785. if container := srv.runtime.Get(name); container != nil {
  786. return container, nil
  787. }
  788. return nil, fmt.Errorf("No such container: %s", name)
  789. }
  790. func (srv *Server) ImageInspect(name string) (*Image, error) {
  791. if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil {
  792. return image, nil
  793. }
  794. return nil, fmt.Errorf("No such image: %s", name)
  795. }
  796. func NewServer(autoRestart bool) (*Server, error) {
  797. if runtime.GOARCH != "amd64" {
  798. log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
  799. }
  800. runtime, err := NewRuntime(autoRestart)
  801. if err != nil {
  802. return nil, err
  803. }
  804. srv := &Server{
  805. runtime: runtime,
  806. }
  807. runtime.srv = srv
  808. return srv, nil
  809. }
  810. type Server struct {
  811. runtime *Runtime
  812. }