server.go 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356
  1. package docker
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/dotcloud/docker/auth"
  8. "github.com/dotcloud/docker/registry"
  9. "github.com/dotcloud/docker/utils"
  10. "io"
  11. "io/ioutil"
  12. "log"
  13. "net/http"
  14. "net/url"
  15. "os"
  16. "os/exec"
  17. "path"
  18. "runtime"
  19. "strings"
  20. "sync"
  21. "time"
  22. )
  23. func (srv *Server) DockerVersion() APIVersion {
  24. return APIVersion{
  25. Version: VERSION,
  26. GitCommit: GITCOMMIT,
  27. GoVersion: runtime.Version(),
  28. }
  29. }
  30. // simpleVersionInfo is a simple implementation of
  31. // the interface VersionInfo, which is used
  32. // to provide version information for some product,
  33. // component, etc. It stores the product name and the version
  34. // in string and returns them on calls to Name() and Version().
  35. type simpleVersionInfo struct {
  36. name string
  37. version string
  38. }
  39. func (v *simpleVersionInfo) Name() string {
  40. return v.name
  41. }
  42. func (v *simpleVersionInfo) Version() string {
  43. return v.version
  44. }
  45. // versionCheckers() returns version informations of:
  46. // docker, go, git-commit (of the docker) and the host's kernel.
  47. //
  48. // Such information will be used on call to NewRegistry().
  49. func (srv *Server) versionInfos() []utils.VersionInfo {
  50. v := srv.DockerVersion()
  51. ret := make([]utils.VersionInfo, 0, 4)
  52. ret = append(ret, &simpleVersionInfo{"docker", v.Version})
  53. if len(v.GoVersion) > 0 {
  54. ret = append(ret, &simpleVersionInfo{"go", v.GoVersion})
  55. }
  56. if len(v.GitCommit) > 0 {
  57. ret = append(ret, &simpleVersionInfo{"git-commit", v.GitCommit})
  58. }
  59. kernelVersion, err := utils.GetKernelVersion()
  60. if err == nil {
  61. ret = append(ret, &simpleVersionInfo{"kernel", kernelVersion.String()})
  62. }
  63. return ret
  64. }
  65. func (srv *Server) ContainerKill(name string) error {
  66. if container := srv.runtime.Get(name); container != nil {
  67. if err := container.Kill(); err != nil {
  68. return fmt.Errorf("Error killing container %s: %s", name, err)
  69. }
  70. srv.LogEvent("kill", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  71. } else {
  72. return fmt.Errorf("No such container: %s", name)
  73. }
  74. return nil
  75. }
  76. func (srv *Server) ContainerExport(name string, out io.Writer) error {
  77. if container := srv.runtime.Get(name); container != nil {
  78. data, err := container.Export()
  79. if err != nil {
  80. return err
  81. }
  82. // Stream the entire contents of the container (basically a volatile snapshot)
  83. if _, err := io.Copy(out, data); err != nil {
  84. return err
  85. }
  86. srv.LogEvent("export", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  87. return nil
  88. }
  89. return fmt.Errorf("No such container: %s", name)
  90. }
  91. func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
  92. r, err := registry.NewRegistry(srv.runtime.root, nil, srv.HTTPRequestFactory(nil))
  93. if err != nil {
  94. return nil, err
  95. }
  96. results, err := r.SearchRepositories(term)
  97. if err != nil {
  98. return nil, err
  99. }
  100. var outs []APISearch
  101. for _, repo := range results.Results {
  102. var out APISearch
  103. out.Description = repo["description"]
  104. out.Name = repo["name"]
  105. outs = append(outs, out)
  106. }
  107. return outs, nil
  108. }
  109. func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.StreamFormatter) (string, error) {
  110. out = utils.NewWriteFlusher(out)
  111. img, err := srv.runtime.repositories.LookupImage(name)
  112. if err != nil {
  113. return "", err
  114. }
  115. file, err := utils.Download(url, out)
  116. if err != nil {
  117. return "", err
  118. }
  119. defer file.Body.Close()
  120. config, _, _, err := ParseRun([]string{img.ID, "echo", "insert", url, path}, srv.runtime.capabilities)
  121. if err != nil {
  122. return "", err
  123. }
  124. c, err := srv.runtime.Create(config)
  125. if err != nil {
  126. return "", err
  127. }
  128. if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("", "Downloading", "%8v/%v (%v)"), sf, true), path); err != nil {
  129. return "", err
  130. }
  131. // FIXME: Handle custom repo, tag comment, author
  132. img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil)
  133. if err != nil {
  134. return "", err
  135. }
  136. out.Write(sf.FormatStatus("", img.ID))
  137. return img.ShortID(), nil
  138. }
  139. func (srv *Server) ImagesViz(out io.Writer) error {
  140. images, _ := srv.runtime.graph.Map()
  141. if images == nil {
  142. return nil
  143. }
  144. out.Write([]byte("digraph docker {\n"))
  145. var (
  146. parentImage *Image
  147. err error
  148. )
  149. for _, image := range images {
  150. parentImage, err = image.GetParent()
  151. if err != nil {
  152. return fmt.Errorf("Error while getting parent image: %v", err)
  153. }
  154. if parentImage != nil {
  155. out.Write([]byte(" \"" + parentImage.ShortID() + "\" -> \"" + image.ShortID() + "\"\n"))
  156. } else {
  157. out.Write([]byte(" base -> \"" + image.ShortID() + "\" [style=invis]\n"))
  158. }
  159. }
  160. reporefs := make(map[string][]string)
  161. for name, repository := range srv.runtime.repositories.Repositories {
  162. for tag, id := range repository {
  163. reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
  164. }
  165. }
  166. for id, repos := range reporefs {
  167. out.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
  168. }
  169. out.Write([]byte(" base [style=invisible]\n}\n"))
  170. return nil
  171. }
  172. func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
  173. var (
  174. allImages map[string]*Image
  175. err error
  176. )
  177. if all {
  178. allImages, err = srv.runtime.graph.Map()
  179. } else {
  180. allImages, err = srv.runtime.graph.Heads()
  181. }
  182. if err != nil {
  183. return nil, err
  184. }
  185. outs := []APIImages{} //produce [] when empty instead of 'null'
  186. for name, repository := range srv.runtime.repositories.Repositories {
  187. if filter != "" {
  188. if match, _ := path.Match(filter, name); !match {
  189. continue
  190. }
  191. }
  192. for tag, id := range repository {
  193. var out APIImages
  194. image, err := srv.runtime.graph.Get(id)
  195. if err != nil {
  196. log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
  197. continue
  198. }
  199. delete(allImages, id)
  200. out.Repository = name
  201. out.Tag = tag
  202. out.ID = image.ID
  203. out.Created = image.Created.Unix()
  204. out.Size = image.Size
  205. out.VirtualSize = image.getParentsSize(0) + image.Size
  206. outs = append(outs, out)
  207. }
  208. }
  209. // Display images which aren't part of a
  210. if filter == "" {
  211. for _, image := range allImages {
  212. var out APIImages
  213. out.ID = image.ID
  214. out.Created = image.Created.Unix()
  215. out.Size = image.Size
  216. out.VirtualSize = image.getParentsSize(0) + image.Size
  217. outs = append(outs, out)
  218. }
  219. }
  220. sortImagesByCreationAndTag(outs)
  221. return outs, nil
  222. }
  223. func (srv *Server) DockerInfo() *APIInfo {
  224. images, _ := srv.runtime.graph.Map()
  225. var imgcount int
  226. if images == nil {
  227. imgcount = 0
  228. } else {
  229. imgcount = len(images)
  230. }
  231. lxcVersion := ""
  232. if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil {
  233. outputStr := string(output)
  234. if len(strings.SplitN(outputStr, ":", 2)) == 2 {
  235. lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1])
  236. }
  237. }
  238. kernelVersion := "<unknown>"
  239. if kv, err := utils.GetKernelVersion(); err == nil {
  240. kernelVersion = kv.String()
  241. }
  242. return &APIInfo{
  243. Containers: len(srv.runtime.List()),
  244. Images: imgcount,
  245. MemoryLimit: srv.runtime.capabilities.MemoryLimit,
  246. SwapLimit: srv.runtime.capabilities.SwapLimit,
  247. IPv4Forwarding: !srv.runtime.capabilities.IPv4ForwardingDisabled,
  248. Debug: os.Getenv("DEBUG") != "",
  249. NFd: utils.GetTotalUsedFds(),
  250. NGoroutines: runtime.NumGoroutine(),
  251. LXCVersion: lxcVersion,
  252. NEventsListener: len(srv.events),
  253. KernelVersion: kernelVersion,
  254. IndexServerAddress: auth.IndexServerAddress(),
  255. }
  256. }
  257. func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
  258. image, err := srv.runtime.repositories.LookupImage(name)
  259. if err != nil {
  260. return nil, err
  261. }
  262. lookupMap := make(map[string][]string)
  263. for name, repository := range srv.runtime.repositories.Repositories {
  264. for tag, id := range repository {
  265. // If the ID already has a reverse lookup, do not update it unless for "latest"
  266. if _, exists := lookupMap[id]; !exists {
  267. lookupMap[id] = []string{}
  268. }
  269. lookupMap[id] = append(lookupMap[id], name+":"+tag)
  270. }
  271. }
  272. outs := []APIHistory{} //produce [] when empty instead of 'null'
  273. err = image.WalkHistory(func(img *Image) error {
  274. var out APIHistory
  275. out.ID = srv.runtime.repositories.ImageName(img.ShortID())
  276. out.Created = img.Created.Unix()
  277. out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ")
  278. out.Tags = lookupMap[img.ID]
  279. outs = append(outs, out)
  280. return nil
  281. })
  282. return outs, nil
  283. }
  284. func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
  285. if container := srv.runtime.Get(name); container != nil {
  286. output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
  287. if err != nil {
  288. return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output)
  289. }
  290. procs := APITop{}
  291. for i, line := range strings.Split(string(output), "\n") {
  292. if len(line) == 0 {
  293. continue
  294. }
  295. words := []string{}
  296. scanner := bufio.NewScanner(strings.NewReader(line))
  297. scanner.Split(bufio.ScanWords)
  298. if !scanner.Scan() {
  299. return nil, fmt.Errorf("Error trying to use lxc-ps")
  300. }
  301. // no scanner.Text because we skip container id
  302. for scanner.Scan() {
  303. words = append(words, scanner.Text())
  304. }
  305. if i == 0 {
  306. procs.Titles = words
  307. } else {
  308. procs.Processes = append(procs.Processes, words)
  309. }
  310. }
  311. return &procs, nil
  312. }
  313. return nil, fmt.Errorf("No such container: %s", name)
  314. }
  315. func (srv *Server) ContainerChanges(name string) ([]Change, error) {
  316. if container := srv.runtime.Get(name); container != nil {
  317. return container.Changes()
  318. }
  319. return nil, fmt.Errorf("No such container: %s", name)
  320. }
  321. func (srv *Server) Containers(all, size bool, n int, since, before string) []APIContainers {
  322. var foundBefore bool
  323. var displayed int
  324. retContainers := []APIContainers{}
  325. for _, container := range srv.runtime.List() {
  326. if !container.State.Running && !all && n == -1 && since == "" && before == "" {
  327. continue
  328. }
  329. if before != "" {
  330. if container.ShortID() == before {
  331. foundBefore = true
  332. continue
  333. }
  334. if !foundBefore {
  335. continue
  336. }
  337. }
  338. if displayed == n {
  339. break
  340. }
  341. if container.ShortID() == since {
  342. break
  343. }
  344. displayed++
  345. c := APIContainers{
  346. ID: container.ID,
  347. }
  348. c.Image = srv.runtime.repositories.ImageName(container.Image)
  349. c.Command = fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  350. c.Created = container.Created.Unix()
  351. c.Status = container.State.String()
  352. c.Ports = container.NetworkSettings.PortMappingAPI()
  353. if size {
  354. c.SizeRw, c.SizeRootFs = container.GetSize()
  355. }
  356. retContainers = append(retContainers, c)
  357. }
  358. return retContainers
  359. }
  360. func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, config *Config) (string, error) {
  361. container := srv.runtime.Get(name)
  362. if container == nil {
  363. return "", fmt.Errorf("No such container: %s", name)
  364. }
  365. img, err := srv.runtime.Commit(container, repo, tag, comment, author, config)
  366. if err != nil {
  367. return "", err
  368. }
  369. return img.ShortID(), err
  370. }
  371. func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
  372. if err := srv.runtime.repositories.Set(repo, tag, name, force); err != nil {
  373. return err
  374. }
  375. return nil
  376. }
  377. func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error {
  378. history, err := r.GetRemoteHistory(imgID, endpoint, token)
  379. if err != nil {
  380. return err
  381. }
  382. out.Write(sf.FormatProgress(utils.TruncateID(imgID), "Pulling", "dependend layers"))
  383. // FIXME: Try to stream the images?
  384. // FIXME: Launch the getRemoteImage() in goroutines
  385. for _, id := range history {
  386. // ensure no two downloads of the same layer happen at the same time
  387. if err := srv.poolAdd("pull", "layer:"+id); err != nil {
  388. utils.Debugf("Image (id: %s) pull is already running, skipping: %v", id, err)
  389. return nil
  390. }
  391. defer srv.poolRemove("pull", "layer:"+id)
  392. if !srv.runtime.graph.Exists(id) {
  393. out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "metadata"))
  394. imgJSON, imgSize, err := r.GetRemoteImageJSON(id, endpoint, token)
  395. if err != nil {
  396. out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers"))
  397. // FIXME: Keep going in case of error?
  398. return err
  399. }
  400. img, err := NewImgJSON(imgJSON)
  401. if err != nil {
  402. out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers"))
  403. return fmt.Errorf("Failed to parse json: %s", err)
  404. }
  405. // Get the layer
  406. out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling", "fs layer"))
  407. layer, err := r.GetRemoteImageLayer(img.ID, endpoint, token)
  408. if err != nil {
  409. out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "pulling dependend layers"))
  410. return err
  411. }
  412. defer layer.Close()
  413. if err := srv.runtime.graph.Register(imgJSON, utils.ProgressReader(layer, imgSize, out, sf.FormatProgress(utils.TruncateID(id), "Downloading", "%8v/%v (%v)"), sf, false), img); err != nil {
  414. out.Write(sf.FormatProgress(utils.TruncateID(id), "Error", "downloading dependend layers"))
  415. return err
  416. }
  417. }
  418. out.Write(sf.FormatProgress(utils.TruncateID(id), "Download", "complete"))
  419. }
  420. return nil
  421. }
  422. func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName, remoteName, askedTag, indexEp string, sf *utils.StreamFormatter, parallel bool) error {
  423. out.Write(sf.FormatStatus("", "Pulling repository %s", localName))
  424. repoData, err := r.GetRepositoryData(indexEp, remoteName)
  425. if err != nil {
  426. return err
  427. }
  428. utils.Debugf("Retrieving the tag list")
  429. tagsList, err := r.GetRemoteTags(repoData.Endpoints, remoteName, repoData.Tokens)
  430. if err != nil {
  431. utils.Debugf("%v", err)
  432. return err
  433. }
  434. for tag, id := range tagsList {
  435. repoData.ImgList[id] = &registry.ImgData{
  436. ID: id,
  437. Tag: tag,
  438. Checksum: "",
  439. }
  440. }
  441. utils.Debugf("Registering tags")
  442. // If no tag has been specified, pull them all
  443. if askedTag == "" {
  444. for tag, id := range tagsList {
  445. repoData.ImgList[id].Tag = tag
  446. }
  447. } else {
  448. // Otherwise, check that the tag exists and use only that one
  449. id, exists := tagsList[askedTag]
  450. if !exists {
  451. return fmt.Errorf("Tag %s not found in repository %s", askedTag, localName)
  452. }
  453. repoData.ImgList[id].Tag = askedTag
  454. }
  455. errors := make(chan error)
  456. for _, image := range repoData.ImgList {
  457. downloadImage := func(img *registry.ImgData) {
  458. if askedTag != "" && img.Tag != askedTag {
  459. utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
  460. if parallel {
  461. errors <- nil
  462. }
  463. return
  464. }
  465. if img.Tag == "" {
  466. utils.Debugf("Image (id: %s) present in this repository but untagged, skipping", img.ID)
  467. if parallel {
  468. errors <- nil
  469. }
  470. return
  471. }
  472. // ensure no two downloads of the same image happen at the same time
  473. if err := srv.poolAdd("pull", "img:"+img.ID); err != nil {
  474. utils.Debugf("Image (id: %s) pull is already running, skipping: %v", img.ID, err)
  475. if parallel {
  476. errors <- nil
  477. }
  478. return
  479. }
  480. defer srv.poolRemove("pull", "img:"+img.ID)
  481. out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Pulling", fmt.Sprintf("image (%s) from %s", img.Tag, localName)))
  482. success := false
  483. var lastErr error
  484. for _, ep := range repoData.Endpoints {
  485. out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Pulling", fmt.Sprintf("image (%s) from %s, endpoint: %s", img.Tag, localName, ep)))
  486. if err := srv.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
  487. // Its not ideal that only the last error is returned, it would be better to concatenate the errors.
  488. // As the error is also given to the output stream the user will see the error.
  489. lastErr = err
  490. out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Error pulling", fmt.Sprintf("image (%s) from %s, endpoint: %s, %s", img.Tag, localName, ep, err)))
  491. continue
  492. }
  493. success = true
  494. break
  495. }
  496. if !success {
  497. out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Error pulling", fmt.Sprintf("image (%s) from %s, %s", img.Tag, localName, lastErr)))
  498. if parallel {
  499. errors <- fmt.Errorf("Could not find repository on any of the indexed registries.")
  500. return
  501. }
  502. }
  503. out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Download", "complete"))
  504. if parallel {
  505. errors <- nil
  506. }
  507. }
  508. if parallel {
  509. go downloadImage(image)
  510. } else {
  511. downloadImage(image)
  512. }
  513. }
  514. if parallel {
  515. var lastError error
  516. for i := 0; i < len(repoData.ImgList); i++ {
  517. if err := <-errors; err != nil {
  518. lastError = err
  519. }
  520. }
  521. if lastError != nil {
  522. return lastError
  523. }
  524. }
  525. for tag, id := range tagsList {
  526. if askedTag != "" && tag != askedTag {
  527. continue
  528. }
  529. if err := srv.runtime.repositories.Set(localName, tag, id, true); err != nil {
  530. return err
  531. }
  532. }
  533. if err := srv.runtime.repositories.Save(); err != nil {
  534. return err
  535. }
  536. return nil
  537. }
  538. func (srv *Server) poolAdd(kind, key string) error {
  539. srv.Lock()
  540. defer srv.Unlock()
  541. if _, exists := srv.pullingPool[key]; exists {
  542. return fmt.Errorf("pull %s is already in progress", key)
  543. }
  544. if _, exists := srv.pushingPool[key]; exists {
  545. return fmt.Errorf("push %s is already in progress", key)
  546. }
  547. switch kind {
  548. case "pull":
  549. srv.pullingPool[key] = struct{}{}
  550. break
  551. case "push":
  552. srv.pushingPool[key] = struct{}{}
  553. break
  554. default:
  555. return fmt.Errorf("Unknown pool type")
  556. }
  557. return nil
  558. }
  559. func (srv *Server) poolRemove(kind, key string) error {
  560. switch kind {
  561. case "pull":
  562. delete(srv.pullingPool, key)
  563. break
  564. case "push":
  565. delete(srv.pushingPool, key)
  566. break
  567. default:
  568. return fmt.Errorf("Unknown pool type")
  569. }
  570. return nil
  571. }
  572. func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig, metaHeaders map[string][]string, parallel bool) error {
  573. r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory(metaHeaders))
  574. if err != nil {
  575. return err
  576. }
  577. if err := srv.poolAdd("pull", localName+":"+tag); err != nil {
  578. return err
  579. }
  580. defer srv.poolRemove("pull", localName+":"+tag)
  581. // Resolve the Repository name from fqn to endpoint + name
  582. endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
  583. if err != nil {
  584. return err
  585. }
  586. if endpoint == auth.IndexServerAddress() {
  587. // If pull "index.docker.io/foo/bar", it's stored locally under "foo/bar"
  588. localName = remoteName
  589. }
  590. out = utils.NewWriteFlusher(out)
  591. err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf, parallel)
  592. if err == registry.ErrLoginRequired {
  593. return err
  594. }
  595. if err != nil {
  596. if err := srv.pullImage(r, out, remoteName, endpoint, nil, sf); err != nil {
  597. return err
  598. }
  599. return nil
  600. }
  601. return nil
  602. }
  603. // Retrieve the all the images to be uploaded in the correct order
  604. // Note: we can't use a map as it is not ordered
  605. func (srv *Server) getImageList(localRepo map[string]string) ([][]*registry.ImgData, error) {
  606. imgList := map[string]*registry.ImgData{}
  607. depGraph := utils.NewDependencyGraph()
  608. for tag, id := range localRepo {
  609. img, err := srv.runtime.graph.Get(id)
  610. if err != nil {
  611. return nil, err
  612. }
  613. depGraph.NewNode(img.ID)
  614. img.WalkHistory(func(current *Image) error {
  615. imgList[current.ID] = &registry.ImgData{
  616. ID: current.ID,
  617. Tag: tag,
  618. }
  619. parent, err := current.GetParent()
  620. if err != nil {
  621. return err
  622. }
  623. if parent == nil {
  624. return nil
  625. }
  626. depGraph.NewNode(parent.ID)
  627. depGraph.AddDependency(current.ID, parent.ID)
  628. return nil
  629. })
  630. }
  631. traversalMap, err := depGraph.GenerateTraversalMap()
  632. if err != nil {
  633. return nil, err
  634. }
  635. utils.Debugf("Traversal map: %v", traversalMap)
  636. result := [][]*registry.ImgData{}
  637. for _, round := range traversalMap {
  638. dataRound := []*registry.ImgData{}
  639. for _, imgID := range round {
  640. dataRound = append(dataRound, imgList[imgID])
  641. }
  642. result = append(result, dataRound)
  643. }
  644. return result, nil
  645. }
  646. func flatten(slc [][]*registry.ImgData) []*registry.ImgData {
  647. result := []*registry.ImgData{}
  648. for _, x := range slc {
  649. result = append(result, x...)
  650. }
  651. return result
  652. }
  653. func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, indexEp string, sf *utils.StreamFormatter) error {
  654. out = utils.NewWriteFlusher(out)
  655. imgList, err := srv.getImageList(localRepo)
  656. if err != nil {
  657. return err
  658. }
  659. flattenedImgList := flatten(imgList)
  660. out.Write(sf.FormatStatus("", "Sending image list"))
  661. var repoData *registry.RepositoryData
  662. repoData, err = r.PushImageJSONIndex(indexEp, remoteName, flattenedImgList, false, nil)
  663. if err != nil {
  664. return err
  665. }
  666. for _, ep := range repoData.Endpoints {
  667. out.Write(sf.FormatStatus("", "Pushing repository %s (%d tags)", localName, len(localRepo)))
  668. // This section can not be parallelized (each round depends on the previous one)
  669. for _, round := range imgList {
  670. // FIXME: This section can be parallelized
  671. for _, elem := range round {
  672. var pushTags func() error
  673. pushTags = func() error {
  674. out.Write(sf.FormatStatus("", "Pushing tags for rev [%s] on {%s}", elem.ID, ep+"repositories/"+remoteName+"/tags/"+elem.Tag))
  675. if err := r.PushRegistryTag(remoteName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
  676. return err
  677. }
  678. return nil
  679. }
  680. if _, exists := repoData.ImgList[elem.ID]; exists {
  681. if err := pushTags(); err != nil {
  682. return err
  683. }
  684. out.Write(sf.FormatStatus("", "Image %s already pushed, skipping", elem.ID))
  685. continue
  686. } else if r.LookupRemoteImage(elem.ID, ep, repoData.Tokens) {
  687. if err := pushTags(); err != nil {
  688. return err
  689. }
  690. out.Write(sf.FormatStatus("", "Image %s already pushed, skipping", elem.ID))
  691. continue
  692. }
  693. if checksum, err := srv.pushImage(r, out, remoteName, elem.ID, ep, repoData.Tokens, sf); err != nil {
  694. // FIXME: Continue on error?
  695. return err
  696. } else {
  697. elem.Checksum = checksum
  698. }
  699. if err := pushTags(); err != nil {
  700. return err
  701. }
  702. }
  703. }
  704. }
  705. if _, err := r.PushImageJSONIndex(indexEp, remoteName, flattenedImgList, true, repoData.Endpoints); err != nil {
  706. return err
  707. }
  708. return nil
  709. }
  710. func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID, ep string, token []string, sf *utils.StreamFormatter) (checksum string, err error) {
  711. out = utils.NewWriteFlusher(out)
  712. jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgID, "json"))
  713. if err != nil {
  714. return "", fmt.Errorf("Error while retrieving the path for {%s}: %s", imgID, err)
  715. }
  716. out.Write(sf.FormatStatus("", "Pushing %s", imgID))
  717. imgData := &registry.ImgData{
  718. ID: imgID,
  719. }
  720. // Send the json
  721. if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
  722. if err == registry.ErrAlreadyExists {
  723. out.Write(sf.FormatStatus("", "Image %s already pushed, skipping", imgData.ID))
  724. return "", nil
  725. }
  726. return "", err
  727. }
  728. layerData, err := srv.runtime.graph.TempLayerArchive(imgID, Uncompressed, sf, out)
  729. if err != nil {
  730. return "", fmt.Errorf("Failed to generate layer archive: %s", err)
  731. }
  732. // Send the layer
  733. if checksum, err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("", "Pushing", "%8v/%v (%v)"), sf, false), ep, token, jsonRaw); err != nil {
  734. return "", err
  735. } else {
  736. imgData.Checksum = checksum
  737. }
  738. out.Write(sf.FormatStatus("", ""))
  739. // Send the checksum
  740. if err := r.PushImageChecksumRegistry(imgData, ep, token); err != nil {
  741. return "", err
  742. }
  743. return imgData.Checksum, nil
  744. }
  745. // FIXME: Allow to interrupt current push when new push of same image is done.
  746. func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig, metaHeaders map[string][]string) error {
  747. if err := srv.poolAdd("push", localName); err != nil {
  748. return err
  749. }
  750. defer srv.poolRemove("push", localName)
  751. // Resolve the Repository name from fqn to endpoint + name
  752. endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
  753. if err != nil {
  754. return err
  755. }
  756. out = utils.NewWriteFlusher(out)
  757. img, err := srv.runtime.graph.Get(localName)
  758. r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory(metaHeaders))
  759. if err2 != nil {
  760. return err2
  761. }
  762. if err != nil {
  763. reposLen := len(srv.runtime.repositories.Repositories[localName])
  764. out.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen))
  765. // If it fails, try to get the repository
  766. if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists {
  767. if err := srv.pushRepository(r, out, localName, remoteName, localRepo, endpoint, sf); err != nil {
  768. return err
  769. }
  770. return nil
  771. }
  772. return err
  773. }
  774. var token []string
  775. out.Write(sf.FormatStatus("", "The push refers to an image: [%s]", localName))
  776. if _, err := srv.pushImage(r, out, remoteName, img.ID, endpoint, token, sf); err != nil {
  777. return err
  778. }
  779. return nil
  780. }
  781. func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Writer, sf *utils.StreamFormatter) error {
  782. var archive io.Reader
  783. var resp *http.Response
  784. if src == "-" {
  785. archive = in
  786. } else {
  787. u, err := url.Parse(src)
  788. if err != nil {
  789. return err
  790. }
  791. if u.Scheme == "" {
  792. u.Scheme = "http"
  793. u.Host = src
  794. u.Path = ""
  795. }
  796. out.Write(sf.FormatStatus("", "Downloading from %s", u))
  797. // Download with curl (pretty progress bar)
  798. // If curl is not available, fallback to http.Get()
  799. resp, err = utils.Download(u.String(), out)
  800. if err != nil {
  801. return err
  802. }
  803. archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("", "Importing", "%8v/%v (%v)"), sf, true)
  804. }
  805. img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
  806. if err != nil {
  807. return err
  808. }
  809. // Optionally register the image at REPO/TAG
  810. if repo != "" {
  811. if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil {
  812. return err
  813. }
  814. }
  815. out.Write(sf.FormatStatus("", img.ShortID()))
  816. return nil
  817. }
  818. func (srv *Server) ContainerCreate(config *Config) (string, error) {
  819. if config.Memory != 0 && config.Memory < 524288 {
  820. return "", fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
  821. }
  822. if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
  823. config.Memory = 0
  824. }
  825. if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
  826. config.MemorySwap = -1
  827. }
  828. container, err := srv.runtime.Create(config)
  829. if err != nil {
  830. if srv.runtime.graph.IsNotExist(err) {
  831. _, tag := utils.ParseRepositoryTag(config.Image)
  832. if tag == "" {
  833. tag = DEFAULTTAG
  834. }
  835. return "", fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
  836. }
  837. return "", err
  838. }
  839. srv.LogEvent("create", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  840. return container.ShortID(), nil
  841. }
  842. func (srv *Server) ContainerRestart(name string, t int) error {
  843. if container := srv.runtime.Get(name); container != nil {
  844. if err := container.Restart(t); err != nil {
  845. return fmt.Errorf("Error restarting container %s: %s", name, err)
  846. }
  847. srv.LogEvent("restart", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  848. } else {
  849. return fmt.Errorf("No such container: %s", name)
  850. }
  851. return nil
  852. }
  853. func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
  854. if container := srv.runtime.Get(name); container != nil {
  855. if container.State.Running {
  856. return fmt.Errorf("Impossible to remove a running container, please stop it first")
  857. }
  858. volumes := make(map[string]struct{})
  859. // Store all the deleted containers volumes
  860. for _, volumeId := range container.Volumes {
  861. volumes[volumeId] = struct{}{}
  862. }
  863. if err := srv.runtime.Destroy(container); err != nil {
  864. return fmt.Errorf("Error destroying container %s: %s", name, err)
  865. }
  866. srv.LogEvent("destroy", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  867. if removeVolume {
  868. // Retrieve all volumes from all remaining containers
  869. usedVolumes := make(map[string]*Container)
  870. for _, container := range srv.runtime.List() {
  871. for _, containerVolumeId := range container.Volumes {
  872. usedVolumes[containerVolumeId] = container
  873. }
  874. }
  875. for volumeId := range volumes {
  876. // If the requested volu
  877. if c, exists := usedVolumes[volumeId]; exists {
  878. log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
  879. continue
  880. }
  881. if err := srv.runtime.volumes.Delete(volumeId); err != nil {
  882. return err
  883. }
  884. }
  885. }
  886. } else {
  887. return fmt.Errorf("No such container: %s", name)
  888. }
  889. return nil
  890. }
  891. var ErrImageReferenced = errors.New("Image referenced by a repository")
  892. func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
  893. // If the image is referenced by a repo, do not delete
  894. if len(srv.runtime.repositories.ByID()[id]) != 0 {
  895. return ErrImageReferenced
  896. }
  897. // If the image is not referenced but has children, go recursive
  898. referenced := false
  899. byParents, err := srv.runtime.graph.ByParent()
  900. if err != nil {
  901. return err
  902. }
  903. for _, img := range byParents[id] {
  904. if err := srv.deleteImageAndChildren(img.ID, imgs); err != nil {
  905. if err != ErrImageReferenced {
  906. return err
  907. }
  908. referenced = true
  909. }
  910. }
  911. if referenced {
  912. return ErrImageReferenced
  913. }
  914. // If the image is not referenced and has no children, remove it
  915. byParents, err = srv.runtime.graph.ByParent()
  916. if err != nil {
  917. return err
  918. }
  919. if len(byParents[id]) == 0 {
  920. if err := srv.runtime.repositories.DeleteAll(id); err != nil {
  921. return err
  922. }
  923. err := srv.runtime.graph.Delete(id)
  924. if err != nil {
  925. return err
  926. }
  927. *imgs = append(*imgs, APIRmi{Deleted: utils.TruncateID(id)})
  928. srv.LogEvent("delete", utils.TruncateID(id), "")
  929. return nil
  930. }
  931. return nil
  932. }
  933. func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
  934. if img.Parent != "" {
  935. parent, err := srv.runtime.graph.Get(img.Parent)
  936. if err != nil {
  937. return err
  938. }
  939. // Remove all children images
  940. if err := srv.deleteImageAndChildren(img.Parent, imgs); err != nil {
  941. return err
  942. }
  943. return srv.deleteImageParents(parent, imgs)
  944. }
  945. return nil
  946. }
  947. func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
  948. imgs := []APIRmi{}
  949. //If delete by id, see if the id belong only to one repository
  950. if strings.Contains(img.ID, repoName) && tag == "" {
  951. for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
  952. parsedRepo, parsedTag := utils.ParseRepositoryTag(repoAndTag)
  953. if strings.Contains(img.ID, repoName) {
  954. repoName = parsedRepo
  955. if len(srv.runtime.repositories.ByID()[img.ID]) == 1 && len(parsedTag) > 1 {
  956. tag = parsedTag
  957. }
  958. } else if repoName != parsedRepo {
  959. // the id belongs to multiple repos, like base:latest and user:test,
  960. // in that case return conflict
  961. return imgs, nil
  962. }
  963. }
  964. }
  965. //Untag the current image
  966. tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
  967. if err != nil {
  968. return nil, err
  969. }
  970. if tagDeleted {
  971. imgs = append(imgs, APIRmi{Untagged: img.ShortID()})
  972. srv.LogEvent("untag", img.ShortID(), "")
  973. }
  974. if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
  975. if err := srv.deleteImageAndChildren(img.ID, &imgs); err != nil {
  976. if err != ErrImageReferenced {
  977. return imgs, err
  978. }
  979. } else if err := srv.deleteImageParents(img, &imgs); err != nil {
  980. if err != ErrImageReferenced {
  981. return imgs, err
  982. }
  983. }
  984. }
  985. return imgs, nil
  986. }
  987. func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
  988. img, err := srv.runtime.repositories.LookupImage(name)
  989. if err != nil {
  990. return nil, fmt.Errorf("No such image: %s", name)
  991. }
  992. if !autoPrune {
  993. if err := srv.runtime.graph.Delete(img.ID); err != nil {
  994. return nil, fmt.Errorf("Error deleting image %s: %s", name, err)
  995. }
  996. return nil, nil
  997. }
  998. name, tag := utils.ParseRepositoryTag(name)
  999. return srv.deleteImage(img, name, tag)
  1000. }
  1001. func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
  1002. // Retrieve all images
  1003. images, err := srv.runtime.graph.Map()
  1004. if err != nil {
  1005. return nil, err
  1006. }
  1007. // Store the tree in a map of map (map[parentId][childId])
  1008. imageMap := make(map[string]map[string]struct{})
  1009. for _, img := range images {
  1010. if _, exists := imageMap[img.Parent]; !exists {
  1011. imageMap[img.Parent] = make(map[string]struct{})
  1012. }
  1013. imageMap[img.Parent][img.ID] = struct{}{}
  1014. }
  1015. // Loop on the children of the given image and check the config
  1016. for elem := range imageMap[imgID] {
  1017. img, err := srv.runtime.graph.Get(elem)
  1018. if err != nil {
  1019. return nil, err
  1020. }
  1021. if CompareConfig(&img.ContainerConfig, config) {
  1022. return img, nil
  1023. }
  1024. }
  1025. return nil, nil
  1026. }
  1027. func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
  1028. if container := srv.runtime.Get(name); container != nil {
  1029. if err := container.Start(hostConfig); err != nil {
  1030. return fmt.Errorf("Error starting container %s: %s", name, err)
  1031. }
  1032. srv.LogEvent("start", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  1033. } else {
  1034. return fmt.Errorf("No such container: %s", name)
  1035. }
  1036. return nil
  1037. }
  1038. func (srv *Server) ContainerStop(name string, t int) error {
  1039. if container := srv.runtime.Get(name); container != nil {
  1040. if err := container.Stop(t); err != nil {
  1041. return fmt.Errorf("Error stopping container %s: %s", name, err)
  1042. }
  1043. srv.LogEvent("stop", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
  1044. } else {
  1045. return fmt.Errorf("No such container: %s", name)
  1046. }
  1047. return nil
  1048. }
  1049. func (srv *Server) ContainerWait(name string) (int, error) {
  1050. if container := srv.runtime.Get(name); container != nil {
  1051. return container.Wait(), nil
  1052. }
  1053. return 0, fmt.Errorf("No such container: %s", name)
  1054. }
  1055. func (srv *Server) ContainerResize(name string, h, w int) error {
  1056. if container := srv.runtime.Get(name); container != nil {
  1057. return container.Resize(h, w)
  1058. }
  1059. return fmt.Errorf("No such container: %s", name)
  1060. }
  1061. func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, inStream io.ReadCloser, outStream, errStream io.Writer) error {
  1062. container := srv.runtime.Get(name)
  1063. if container == nil {
  1064. return fmt.Errorf("No such container: %s", name)
  1065. }
  1066. //logs
  1067. if logs {
  1068. cLog, err := container.ReadLog("json")
  1069. if err != nil && os.IsNotExist(err) {
  1070. // Legacy logs
  1071. utils.Debugf("Old logs format")
  1072. if stdout {
  1073. cLog, err := container.ReadLog("stdout")
  1074. if err != nil {
  1075. utils.Debugf("Error reading logs (stdout): %s", err)
  1076. } else if _, err := io.Copy(outStream, cLog); err != nil {
  1077. utils.Debugf("Error streaming logs (stdout): %s", err)
  1078. }
  1079. }
  1080. if stderr {
  1081. cLog, err := container.ReadLog("stderr")
  1082. if err != nil {
  1083. utils.Debugf("Error reading logs (stderr): %s", err)
  1084. } else if _, err := io.Copy(errStream, cLog); err != nil {
  1085. utils.Debugf("Error streaming logs (stderr): %s", err)
  1086. }
  1087. }
  1088. } else if err != nil {
  1089. utils.Debugf("Error reading logs (json): %s", err)
  1090. } else {
  1091. dec := json.NewDecoder(cLog)
  1092. for {
  1093. l := &utils.JSONLog{}
  1094. if err := dec.Decode(l); err == io.EOF {
  1095. break
  1096. } else if err != nil {
  1097. utils.Debugf("Error streaming logs: %s", err)
  1098. break
  1099. }
  1100. if l.Stream == "stdout" && stdout {
  1101. fmt.Fprintf(outStream, "%s", l.Log)
  1102. }
  1103. if l.Stream == "stderr" && stderr {
  1104. fmt.Fprintf(errStream, "%s", l.Log)
  1105. }
  1106. }
  1107. }
  1108. }
  1109. //stream
  1110. if stream {
  1111. if container.State.Ghost {
  1112. return fmt.Errorf("Impossible to attach to a ghost container")
  1113. }
  1114. var (
  1115. cStdin io.ReadCloser
  1116. cStdout, cStderr io.Writer
  1117. cStdinCloser io.Closer
  1118. )
  1119. if stdin {
  1120. r, w := io.Pipe()
  1121. go func() {
  1122. defer w.Close()
  1123. defer utils.Debugf("Closing buffered stdin pipe")
  1124. io.Copy(w, inStream)
  1125. }()
  1126. cStdin = r
  1127. cStdinCloser = inStream
  1128. }
  1129. if stdout {
  1130. cStdout = outStream
  1131. }
  1132. if stderr {
  1133. cStderr = errStream
  1134. }
  1135. <-container.Attach(cStdin, cStdinCloser, cStdout, cStderr)
  1136. // If we are in stdinonce mode, wait for the process to end
  1137. // otherwise, simply return
  1138. if container.Config.StdinOnce && !container.Config.Tty {
  1139. container.Wait()
  1140. }
  1141. }
  1142. return nil
  1143. }
  1144. func (srv *Server) ContainerInspect(name string) (*Container, error) {
  1145. if container := srv.runtime.Get(name); container != nil {
  1146. return container, nil
  1147. }
  1148. return nil, fmt.Errorf("No such container: %s", name)
  1149. }
  1150. func (srv *Server) ImageInspect(name string) (*Image, error) {
  1151. if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil {
  1152. return image, nil
  1153. }
  1154. return nil, fmt.Errorf("No such image: %s", name)
  1155. }
  1156. func (srv *Server) ContainerCopy(name string, resource string, out io.Writer) error {
  1157. if container := srv.runtime.Get(name); container != nil {
  1158. data, err := container.Copy(resource)
  1159. if err != nil {
  1160. return err
  1161. }
  1162. if _, err := io.Copy(out, data); err != nil {
  1163. return err
  1164. }
  1165. return nil
  1166. }
  1167. return fmt.Errorf("No such container: %s", name)
  1168. }
  1169. func NewServer(flGraphPath string, deviceSet DeviceSet, autoRestart, enableCors bool, dns ListOpts) (*Server, error) {
  1170. if runtime.GOARCH != "amd64" {
  1171. log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
  1172. }
  1173. runtime, err := NewRuntime(flGraphPath, autoRestart, dns)
  1174. if err != nil {
  1175. return nil, err
  1176. }
  1177. srv := &Server{
  1178. runtime: runtime,
  1179. enableCors: enableCors,
  1180. pullingPool: make(map[string]struct{}),
  1181. pushingPool: make(map[string]struct{}),
  1182. events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events
  1183. listeners: make(map[string]chan utils.JSONMessage),
  1184. reqFactory: nil,
  1185. }
  1186. runtime.srv = srv
  1187. return srv, nil
  1188. }
  1189. func (srv *Server) HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory {
  1190. if srv.reqFactory == nil {
  1191. ud := utils.NewHTTPUserAgentDecorator(srv.versionInfos()...)
  1192. md := &utils.HTTPMetaHeadersDecorator{
  1193. Headers: metaHeaders,
  1194. }
  1195. factory := utils.NewHTTPRequestFactory(ud, md)
  1196. srv.reqFactory = factory
  1197. }
  1198. return srv.reqFactory
  1199. }
  1200. func (srv *Server) LogEvent(action, id, from string) {
  1201. now := time.Now().Unix()
  1202. jm := utils.JSONMessage{Status: action, ID: id, From: from, Time: now}
  1203. srv.events = append(srv.events, jm)
  1204. for _, c := range srv.listeners {
  1205. select { // non blocking channel
  1206. case c <- jm:
  1207. default:
  1208. }
  1209. }
  1210. }
  1211. type Server struct {
  1212. sync.Mutex
  1213. runtime *Runtime
  1214. enableCors bool
  1215. pullingPool map[string]struct{}
  1216. pushingPool map[string]struct{}
  1217. events []utils.JSONMessage
  1218. listeners map[string]chan utils.JSONMessage
  1219. reqFactory *utils.HTTPRequestFactory
  1220. }