commands.go 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. package docker
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/dotcloud/docker/auth"
  7. "github.com/dotcloud/docker/rcli"
  8. "io"
  9. "log"
  10. "net/http"
  11. "net/url"
  12. "runtime"
  13. "strconv"
  14. "strings"
  15. "text/tabwriter"
  16. "time"
  17. "unicode"
  18. )
  19. const VERSION = "0.3.0"
  20. var (
  21. GIT_COMMIT string
  22. )
  23. func (srv *Server) Name() string {
  24. return "docker"
  25. }
  26. // FIXME: Stop violating DRY by repeating usage here and in Subcmd declarations
  27. func (srv *Server) Help() string {
  28. help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
  29. for _, cmd := range [][]string{
  30. {"attach", "Attach to a running container"},
  31. {"build", "Build a container from Dockerfile via stdin"},
  32. {"commit", "Create a new image from a container's changes"},
  33. {"diff", "Inspect changes on a container's filesystem"},
  34. {"export", "Stream the contents of a container as a tar archive"},
  35. {"history", "Show the history of an image"},
  36. {"images", "List images"},
  37. {"import", "Create a new filesystem image from the contents of a tarball"},
  38. {"info", "Display system-wide information"},
  39. {"insert", "Insert a file in an image"},
  40. {"inspect", "Return low-level information on a container"},
  41. {"kill", "Kill a running container"},
  42. {"login", "Register or Login to the docker registry server"},
  43. {"logs", "Fetch the logs of a container"},
  44. {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
  45. {"ps", "List containers"},
  46. {"pull", "Pull an image or a repository from the docker registry server"},
  47. {"push", "Push an image or a repository to the docker registry server"},
  48. {"restart", "Restart a running container"},
  49. {"rm", "Remove a container"},
  50. {"rmi", "Remove an image"},
  51. {"run", "Run a command in a new container"},
  52. {"start", "Start a stopped container"},
  53. {"stop", "Stop a running container"},
  54. {"tag", "Tag an image into a repository"},
  55. {"version", "Show the docker version information"},
  56. {"wait", "Block until a container stops, then print its exit code"},
  57. } {
  58. help += fmt.Sprintf(" %-10.10s%s\n", cmd[0], cmd[1])
  59. }
  60. return help
  61. }
  62. func (srv *Server) CmdInsert(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  63. stdout.Flush()
  64. cmd := rcli.Subcmd(stdout, "insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
  65. if err := cmd.Parse(args); err != nil {
  66. return nil
  67. }
  68. if cmd.NArg() != 3 {
  69. cmd.Usage()
  70. return nil
  71. }
  72. imageId := cmd.Arg(0)
  73. url := cmd.Arg(1)
  74. path := cmd.Arg(2)
  75. img, err := srv.runtime.repositories.LookupImage(imageId)
  76. if err != nil {
  77. return err
  78. }
  79. file, err := Download(url, stdout)
  80. if err != nil {
  81. return err
  82. }
  83. defer file.Body.Close()
  84. config, err := ParseRun([]string{img.Id, "echo", "insert", url, path}, nil, srv.runtime.capabilities)
  85. if err != nil {
  86. return err
  87. }
  88. b := NewBuilder(srv.runtime)
  89. c, err := b.Create(config)
  90. if err != nil {
  91. return err
  92. }
  93. if err := c.Inject(ProgressReader(file.Body, int(file.ContentLength), stdout, "Downloading %v/%v (%v)"), path); err != nil {
  94. return err
  95. }
  96. // FIXME: Handle custom repo, tag comment, author
  97. img, err = b.Commit(c, "", "", img.Comment, img.Author, nil)
  98. if err != nil {
  99. return err
  100. }
  101. fmt.Fprintf(stdout, "%s\n", img.Id)
  102. return nil
  103. }
  104. func (srv *Server) CmdBuild(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  105. stdout.Flush()
  106. cmd := rcli.Subcmd(stdout, "build", "-", "Build a container from Dockerfile via stdin")
  107. if err := cmd.Parse(args); err != nil {
  108. return nil
  109. }
  110. img, err := NewBuilder(srv.runtime).Build(stdin, stdout)
  111. if err != nil {
  112. return err
  113. }
  114. fmt.Fprintf(stdout, "%s\n", img.ShortId())
  115. return nil
  116. }
  117. // 'docker login': login / register a user to registry service.
  118. func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  119. // Read a line on raw terminal with support for simple backspace
  120. // sequences and echo.
  121. //
  122. // This function is necessary because the login command must be done in a
  123. // raw terminal for two reasons:
  124. // - we have to read a password (without echoing it);
  125. // - the rcli "protocol" only supports cannonical and raw modes and you
  126. // can't tune it once the command as been started.
  127. var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string {
  128. char := make([]byte, 1)
  129. buffer := make([]byte, 64)
  130. var i = 0
  131. for i < len(buffer) {
  132. n, err := stdin.Read(char)
  133. if n > 0 {
  134. if char[0] == '\r' || char[0] == '\n' {
  135. stdout.Write([]byte{'\r', '\n'})
  136. break
  137. } else if char[0] == 127 || char[0] == '\b' {
  138. if i > 0 {
  139. if echo {
  140. stdout.Write([]byte{'\b', ' ', '\b'})
  141. }
  142. i--
  143. }
  144. } else if !unicode.IsSpace(rune(char[0])) &&
  145. !unicode.IsControl(rune(char[0])) {
  146. if echo {
  147. stdout.Write(char)
  148. }
  149. buffer[i] = char[0]
  150. i++
  151. }
  152. }
  153. if err != nil {
  154. if err != io.EOF {
  155. fmt.Fprintf(stdout, "Read error: %v\r\n", err)
  156. }
  157. break
  158. }
  159. }
  160. return string(buffer[:i])
  161. }
  162. var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string {
  163. return readStringOnRawTerminal(stdin, stdout, true)
  164. }
  165. var readString = func(stdin io.Reader, stdout io.Writer) string {
  166. return readStringOnRawTerminal(stdin, stdout, false)
  167. }
  168. stdout.SetOptionRawTerminal()
  169. cmd := rcli.Subcmd(stdout, "login", "", "Register or Login to the docker registry server")
  170. if err := cmd.Parse(args); err != nil {
  171. return nil
  172. }
  173. var username string
  174. var password string
  175. var email string
  176. fmt.Fprint(stdout, "Username (", srv.runtime.authConfig.Username, "): ")
  177. username = readAndEchoString(stdin, stdout)
  178. if username == "" {
  179. username = srv.runtime.authConfig.Username
  180. }
  181. if username != srv.runtime.authConfig.Username {
  182. fmt.Fprint(stdout, "Password: ")
  183. password = readString(stdin, stdout)
  184. if password == "" {
  185. return fmt.Errorf("Error : Password Required")
  186. }
  187. fmt.Fprint(stdout, "Email (", srv.runtime.authConfig.Email, "): ")
  188. email = readAndEchoString(stdin, stdout)
  189. if email == "" {
  190. email = srv.runtime.authConfig.Email
  191. }
  192. } else {
  193. password = srv.runtime.authConfig.Password
  194. email = srv.runtime.authConfig.Email
  195. }
  196. newAuthConfig := auth.NewAuthConfig(username, password, email, srv.runtime.root)
  197. status, err := auth.Login(newAuthConfig)
  198. if err != nil {
  199. fmt.Fprintf(stdout, "Error: %s\r\n", err)
  200. } else {
  201. srv.runtime.authConfig = newAuthConfig
  202. }
  203. if status != "" {
  204. fmt.Fprint(stdout, status)
  205. }
  206. return nil
  207. }
  208. // 'docker wait': block until a container stops
  209. func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  210. cmd := rcli.Subcmd(stdout, "wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
  211. if err := cmd.Parse(args); err != nil {
  212. return nil
  213. }
  214. if cmd.NArg() < 1 {
  215. cmd.Usage()
  216. return nil
  217. }
  218. for _, name := range cmd.Args() {
  219. if container := srv.runtime.Get(name); container != nil {
  220. fmt.Fprintln(stdout, container.Wait())
  221. } else {
  222. return fmt.Errorf("No such container: %s", name)
  223. }
  224. }
  225. return nil
  226. }
  227. // 'docker version': show version information
  228. func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  229. fmt.Fprintf(stdout, "Version: %s\n", VERSION)
  230. fmt.Fprintf(stdout, "Git Commit: %s\n", GIT_COMMIT)
  231. fmt.Fprintf(stdout, "Kernel: %s\n", srv.runtime.kernelVersion)
  232. if !srv.runtime.capabilities.MemoryLimit {
  233. fmt.Fprintf(stdout, "WARNING: No memory limit support\n")
  234. }
  235. if !srv.runtime.capabilities.SwapLimit {
  236. fmt.Fprintf(stdout, "WARNING: No swap limit support\n")
  237. }
  238. return nil
  239. }
  240. // 'docker info': display system-wide information.
  241. func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  242. images, _ := srv.runtime.graph.All()
  243. var imgcount int
  244. if images == nil {
  245. imgcount = 0
  246. } else {
  247. imgcount = len(images)
  248. }
  249. cmd := rcli.Subcmd(stdout, "info", "", "Display system-wide information.")
  250. if err := cmd.Parse(args); err != nil {
  251. return nil
  252. }
  253. if cmd.NArg() > 0 {
  254. cmd.Usage()
  255. return nil
  256. }
  257. fmt.Fprintf(stdout, "containers: %d\nversion: %s\nimages: %d\n",
  258. len(srv.runtime.List()),
  259. VERSION,
  260. imgcount)
  261. if !rcli.DEBUG_FLAG {
  262. return nil
  263. }
  264. fmt.Fprintln(stdout, "debug mode enabled")
  265. fmt.Fprintf(stdout, "fds: %d\ngoroutines: %d\n", getTotalUsedFds(), runtime.NumGoroutine())
  266. return nil
  267. }
  268. func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  269. cmd := rcli.Subcmd(stdout, "stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container")
  270. nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
  271. if err := cmd.Parse(args); err != nil {
  272. return nil
  273. }
  274. if cmd.NArg() < 1 {
  275. cmd.Usage()
  276. return nil
  277. }
  278. for _, name := range cmd.Args() {
  279. if container := srv.runtime.Get(name); container != nil {
  280. if err := container.Stop(*nSeconds); err != nil {
  281. return err
  282. }
  283. fmt.Fprintln(stdout, container.ShortId())
  284. } else {
  285. return fmt.Errorf("No such container: %s", name)
  286. }
  287. }
  288. return nil
  289. }
  290. func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  291. cmd := rcli.Subcmd(stdout, "restart", "CONTAINER [CONTAINER...]", "Restart a running container")
  292. nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
  293. if err := cmd.Parse(args); err != nil {
  294. return nil
  295. }
  296. if cmd.NArg() < 1 {
  297. cmd.Usage()
  298. return nil
  299. }
  300. for _, name := range cmd.Args() {
  301. if container := srv.runtime.Get(name); container != nil {
  302. if err := container.Restart(*nSeconds); err != nil {
  303. return err
  304. }
  305. fmt.Fprintln(stdout, container.ShortId())
  306. } else {
  307. return fmt.Errorf("No such container: %s", name)
  308. }
  309. }
  310. return nil
  311. }
  312. func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  313. cmd := rcli.Subcmd(stdout, "start", "CONTAINER [CONTAINER...]", "Start a stopped container")
  314. if err := cmd.Parse(args); err != nil {
  315. return nil
  316. }
  317. if cmd.NArg() < 1 {
  318. cmd.Usage()
  319. return nil
  320. }
  321. for _, name := range cmd.Args() {
  322. if container := srv.runtime.Get(name); container != nil {
  323. if err := container.Start(); err != nil {
  324. return err
  325. }
  326. fmt.Fprintln(stdout, container.ShortId())
  327. } else {
  328. return fmt.Errorf("No such container: %s", name)
  329. }
  330. }
  331. return nil
  332. }
  333. func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  334. cmd := rcli.Subcmd(stdout, "inspect", "CONTAINER", "Return low-level information on a container")
  335. if err := cmd.Parse(args); err != nil {
  336. return nil
  337. }
  338. if cmd.NArg() < 1 {
  339. cmd.Usage()
  340. return nil
  341. }
  342. name := cmd.Arg(0)
  343. var obj interface{}
  344. if container := srv.runtime.Get(name); container != nil {
  345. obj = container
  346. } else if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil {
  347. obj = image
  348. } else {
  349. // No output means the object does not exist
  350. // (easier to script since stdout and stderr are not differentiated atm)
  351. return nil
  352. }
  353. data, err := json.Marshal(obj)
  354. if err != nil {
  355. return err
  356. }
  357. indented := new(bytes.Buffer)
  358. if err = json.Indent(indented, data, "", " "); err != nil {
  359. return err
  360. }
  361. if _, err := io.Copy(stdout, indented); err != nil {
  362. return err
  363. }
  364. stdout.Write([]byte{'\n'})
  365. return nil
  366. }
  367. func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  368. cmd := rcli.Subcmd(stdout, "port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
  369. if err := cmd.Parse(args); err != nil {
  370. return nil
  371. }
  372. if cmd.NArg() != 2 {
  373. cmd.Usage()
  374. return nil
  375. }
  376. name := cmd.Arg(0)
  377. privatePort := cmd.Arg(1)
  378. if container := srv.runtime.Get(name); container == nil {
  379. return fmt.Errorf("No such container: %s", name)
  380. } else {
  381. if frontend, exists := container.NetworkSettings.PortMapping[privatePort]; !exists {
  382. return fmt.Errorf("No private port '%s' allocated on %s", privatePort, name)
  383. } else {
  384. fmt.Fprintln(stdout, frontend)
  385. }
  386. }
  387. return nil
  388. }
  389. // 'docker rmi IMAGE' removes all images with the name IMAGE
  390. func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) (err error) {
  391. cmd := rcli.Subcmd(stdout, "rmimage", "IMAGE [IMAGE...]", "Remove an image")
  392. if err := cmd.Parse(args); err != nil {
  393. return nil
  394. }
  395. if cmd.NArg() < 1 {
  396. cmd.Usage()
  397. return nil
  398. }
  399. for _, name := range cmd.Args() {
  400. img, err := srv.runtime.repositories.LookupImage(name)
  401. if err != nil {
  402. return err
  403. }
  404. if err := srv.runtime.graph.Delete(img.Id); err != nil {
  405. return err
  406. }
  407. }
  408. return nil
  409. }
  410. func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  411. cmd := rcli.Subcmd(stdout, "history", "IMAGE", "Show the history of an image")
  412. if err := cmd.Parse(args); err != nil {
  413. return nil
  414. }
  415. if cmd.NArg() != 1 {
  416. cmd.Usage()
  417. return nil
  418. }
  419. image, err := srv.runtime.repositories.LookupImage(cmd.Arg(0))
  420. if err != nil {
  421. return err
  422. }
  423. w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
  424. defer w.Flush()
  425. fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
  426. return image.WalkHistory(func(img *Image) error {
  427. fmt.Fprintf(w, "%s\t%s\t%s\n",
  428. srv.runtime.repositories.ImageName(img.ShortId()),
  429. HumanDuration(time.Now().Sub(img.Created))+" ago",
  430. strings.Join(img.ContainerConfig.Cmd, " "),
  431. )
  432. return nil
  433. })
  434. }
  435. func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  436. cmd := rcli.Subcmd(stdout, "rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove a container")
  437. v := cmd.Bool("v", false, "Remove the volumes associated to the container")
  438. if err := cmd.Parse(args); err != nil {
  439. return nil
  440. }
  441. if cmd.NArg() < 1 {
  442. cmd.Usage()
  443. return nil
  444. }
  445. volumes := make(map[string]struct{})
  446. for _, name := range cmd.Args() {
  447. container := srv.runtime.Get(name)
  448. if container == nil {
  449. return fmt.Errorf("No such container: %s", name)
  450. }
  451. // Store all the deleted containers volumes
  452. for _, volumeId := range container.Volumes {
  453. volumes[volumeId] = struct{}{}
  454. }
  455. if err := srv.runtime.Destroy(container); err != nil {
  456. fmt.Fprintln(stdout, "Error destroying container "+name+": "+err.Error())
  457. }
  458. }
  459. if *v {
  460. // Retrieve all volumes from all remaining containers
  461. usedVolumes := make(map[string]*Container)
  462. for _, container := range srv.runtime.List() {
  463. for _, containerVolumeId := range container.Volumes {
  464. usedVolumes[containerVolumeId] = container
  465. }
  466. }
  467. for volumeId := range volumes {
  468. // If the requested volu
  469. if c, exists := usedVolumes[volumeId]; exists {
  470. fmt.Fprintf(stdout, "The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.Id)
  471. continue
  472. }
  473. if err := srv.runtime.volumes.Delete(volumeId); err != nil {
  474. return err
  475. }
  476. }
  477. }
  478. return nil
  479. }
  480. // 'docker kill NAME' kills a running container
  481. func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  482. cmd := rcli.Subcmd(stdout, "kill", "CONTAINER [CONTAINER...]", "Kill a running container")
  483. if err := cmd.Parse(args); err != nil {
  484. return nil
  485. }
  486. if cmd.NArg() < 1 {
  487. cmd.Usage()
  488. return nil
  489. }
  490. for _, name := range cmd.Args() {
  491. container := srv.runtime.Get(name)
  492. if container == nil {
  493. return fmt.Errorf("No such container: %s", name)
  494. }
  495. if err := container.Kill(); err != nil {
  496. fmt.Fprintln(stdout, "Error killing container "+name+": "+err.Error())
  497. }
  498. }
  499. return nil
  500. }
  501. func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  502. stdout.Flush()
  503. cmd := rcli.Subcmd(stdout, "import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
  504. var archive io.Reader
  505. var resp *http.Response
  506. if err := cmd.Parse(args); err != nil {
  507. return nil
  508. }
  509. if cmd.NArg() < 1 {
  510. cmd.Usage()
  511. return nil
  512. }
  513. src := cmd.Arg(0)
  514. if src == "-" {
  515. archive = stdin
  516. } else {
  517. u, err := url.Parse(src)
  518. if err != nil {
  519. return err
  520. }
  521. if u.Scheme == "" {
  522. u.Scheme = "http"
  523. u.Host = src
  524. u.Path = ""
  525. }
  526. fmt.Fprintln(stdout, "Downloading from", u)
  527. // Download with curl (pretty progress bar)
  528. // If curl is not available, fallback to http.Get()
  529. resp, err = Download(u.String(), stdout)
  530. if err != nil {
  531. return err
  532. }
  533. archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout, "Importing %v/%v (%v)")
  534. }
  535. img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
  536. if err != nil {
  537. return err
  538. }
  539. // Optionally register the image at REPO/TAG
  540. if repository := cmd.Arg(1); repository != "" {
  541. tag := cmd.Arg(2) // Repository will handle an empty tag properly
  542. if err := srv.runtime.repositories.Set(repository, tag, img.Id, true); err != nil {
  543. return err
  544. }
  545. }
  546. fmt.Fprintln(stdout, img.ShortId())
  547. return nil
  548. }
  549. func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  550. cmd := rcli.Subcmd(stdout, "push", "NAME", "Push an image or a repository to the registry")
  551. registry := cmd.String("registry", "", "Registry host to push the image to")
  552. if err := cmd.Parse(args); err != nil {
  553. return nil
  554. }
  555. local := cmd.Arg(0)
  556. if local == "" {
  557. cmd.Usage()
  558. return nil
  559. }
  560. // If the login failed AND we're using the index, abort
  561. if *registry == "" && (srv.runtime.authConfig == nil || srv.runtime.authConfig.Username == "") {
  562. if err := srv.CmdLogin(stdin, stdout, args...); err != nil {
  563. return err
  564. }
  565. if srv.runtime.authConfig == nil || srv.runtime.authConfig.Username == "" {
  566. return fmt.Errorf("Please login prior to push. ('docker login')")
  567. }
  568. }
  569. var remote string
  570. tmp := strings.SplitN(local, "/", 2)
  571. if len(tmp) == 1 {
  572. return fmt.Errorf(
  573. "Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)",
  574. srv.runtime.authConfig.Username, local)
  575. } else {
  576. remote = local
  577. }
  578. Debugf("Pushing [%s] to [%s]\n", local, remote)
  579. // Try to get the image
  580. img, err := srv.runtime.graph.Get(local)
  581. if err != nil {
  582. Debugf("The push refers to a repository [%s] (len: %d)\n", local, len(srv.runtime.repositories.Repositories[local]))
  583. // If it fails, try to get the repository
  584. if localRepo, exists := srv.runtime.repositories.Repositories[local]; exists {
  585. if err := srv.runtime.graph.PushRepository(stdout, remote, localRepo, srv.runtime.authConfig); err != nil {
  586. return err
  587. }
  588. return nil
  589. }
  590. return err
  591. }
  592. err = srv.runtime.graph.PushImage(stdout, img, *registry, nil)
  593. if err != nil {
  594. return err
  595. }
  596. return nil
  597. }
  598. func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  599. cmd := rcli.Subcmd(stdout, "pull", "NAME", "Pull an image or a repository from the registry")
  600. tag := cmd.String("t", "", "Download tagged image in repository")
  601. registry := cmd.String("registry", "", "Registry to download from. Necessary if image is pulled by ID")
  602. if err := cmd.Parse(args); err != nil {
  603. return nil
  604. }
  605. remote := cmd.Arg(0)
  606. if remote == "" {
  607. cmd.Usage()
  608. return nil
  609. }
  610. if strings.Contains(remote, ":") {
  611. remoteParts := strings.Split(remote, ":")
  612. tag = &remoteParts[1]
  613. remote = remoteParts[0]
  614. }
  615. // FIXME: CmdPull should be a wrapper around Runtime.Pull()
  616. if *registry != "" {
  617. if err := srv.runtime.graph.PullImage(stdout, remote, *registry, nil); err != nil {
  618. return err
  619. }
  620. return nil
  621. }
  622. if err := srv.runtime.graph.PullRepository(stdout, remote, *tag, srv.runtime.repositories, srv.runtime.authConfig); err != nil {
  623. return err
  624. }
  625. return nil
  626. }
  627. func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  628. cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images")
  629. //limit := cmd.Int("l", 0, "Only show the N most recent versions of each image")
  630. quiet := cmd.Bool("q", false, "only show numeric IDs")
  631. flAll := cmd.Bool("a", false, "show all images")
  632. if err := cmd.Parse(args); err != nil {
  633. return nil
  634. }
  635. if cmd.NArg() > 1 {
  636. cmd.Usage()
  637. return nil
  638. }
  639. var nameFilter string
  640. if cmd.NArg() == 1 {
  641. nameFilter = cmd.Arg(0)
  642. }
  643. w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
  644. if !*quiet {
  645. fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
  646. }
  647. var allImages map[string]*Image
  648. var err error
  649. if *flAll {
  650. allImages, err = srv.runtime.graph.Map()
  651. } else {
  652. allImages, err = srv.runtime.graph.Heads()
  653. }
  654. if err != nil {
  655. return err
  656. }
  657. for name, repository := range srv.runtime.repositories.Repositories {
  658. if nameFilter != "" && name != nameFilter {
  659. continue
  660. }
  661. for tag, id := range repository {
  662. image, err := srv.runtime.graph.Get(id)
  663. if err != nil {
  664. log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
  665. continue
  666. }
  667. delete(allImages, id)
  668. if !*quiet {
  669. for idx, field := range []string{
  670. /* REPOSITORY */ name,
  671. /* TAG */ tag,
  672. /* ID */ TruncateId(id),
  673. /* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
  674. } {
  675. if idx == 0 {
  676. w.Write([]byte(field))
  677. } else {
  678. w.Write([]byte("\t" + field))
  679. }
  680. }
  681. w.Write([]byte{'\n'})
  682. } else {
  683. stdout.Write([]byte(image.ShortId() + "\n"))
  684. }
  685. }
  686. }
  687. // Display images which aren't part of a
  688. if nameFilter == "" {
  689. for id, image := range allImages {
  690. if !*quiet {
  691. for idx, field := range []string{
  692. /* REPOSITORY */ "<none>",
  693. /* TAG */ "<none>",
  694. /* ID */ TruncateId(id),
  695. /* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
  696. } {
  697. if idx == 0 {
  698. w.Write([]byte(field))
  699. } else {
  700. w.Write([]byte("\t" + field))
  701. }
  702. }
  703. w.Write([]byte{'\n'})
  704. } else {
  705. stdout.Write([]byte(image.ShortId() + "\n"))
  706. }
  707. }
  708. }
  709. if !*quiet {
  710. w.Flush()
  711. }
  712. return nil
  713. }
  714. func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  715. cmd := rcli.Subcmd(stdout,
  716. "ps", "[OPTIONS]", "List containers")
  717. quiet := cmd.Bool("q", false, "Only display numeric IDs")
  718. flAll := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.")
  719. flFull := cmd.Bool("notrunc", false, "Don't truncate output")
  720. latest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.")
  721. nLast := cmd.Int("n", -1, "Show n last created containers, include non-running ones.")
  722. if err := cmd.Parse(args); err != nil {
  723. return nil
  724. }
  725. if *nLast == -1 && *latest {
  726. *nLast = 1
  727. }
  728. w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0)
  729. if !*quiet {
  730. fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT\tPORTS")
  731. }
  732. for i, container := range srv.runtime.List() {
  733. if !container.State.Running && !*flAll && *nLast == -1 {
  734. continue
  735. }
  736. if i == *nLast {
  737. break
  738. }
  739. if !*quiet {
  740. command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  741. if !*flFull {
  742. command = Trunc(command, 20)
  743. }
  744. for idx, field := range []string{
  745. /* ID */ container.ShortId(),
  746. /* IMAGE */ srv.runtime.repositories.ImageName(container.Image),
  747. /* COMMAND */ command,
  748. /* CREATED */ HumanDuration(time.Now().Sub(container.Created)) + " ago",
  749. /* STATUS */ container.State.String(),
  750. /* COMMENT */ "",
  751. /* PORTS */ container.NetworkSettings.PortMappingHuman(),
  752. } {
  753. if idx == 0 {
  754. w.Write([]byte(field))
  755. } else {
  756. w.Write([]byte("\t" + field))
  757. }
  758. }
  759. w.Write([]byte{'\n'})
  760. } else {
  761. stdout.Write([]byte(container.ShortId() + "\n"))
  762. }
  763. }
  764. if !*quiet {
  765. w.Flush()
  766. }
  767. return nil
  768. }
  769. func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  770. cmd := rcli.Subcmd(stdout,
  771. "commit", "[OPTIONS] CONTAINER [REPOSITORY [TAG]]",
  772. "Create a new image from a container's changes")
  773. flComment := cmd.String("m", "", "Commit message")
  774. flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
  775. flConfig := cmd.String("run", "", "Config automatically applied when the image is run. "+`(ex: {"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
  776. if err := cmd.Parse(args); err != nil {
  777. return nil
  778. }
  779. containerName, repository, tag := cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
  780. if containerName == "" {
  781. cmd.Usage()
  782. return nil
  783. }
  784. var config *Config
  785. if *flConfig != "" {
  786. config = &Config{}
  787. if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
  788. return err
  789. }
  790. }
  791. container := srv.runtime.Get(containerName)
  792. if container == nil {
  793. return fmt.Errorf("No such container: %s", containerName)
  794. }
  795. img, err := NewBuilder(srv.runtime).Commit(container, repository, tag, *flComment, *flAuthor, config)
  796. if err != nil {
  797. return err
  798. }
  799. fmt.Fprintln(stdout, img.ShortId())
  800. return nil
  801. }
  802. func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  803. cmd := rcli.Subcmd(stdout,
  804. "export", "CONTAINER",
  805. "Export the contents of a filesystem as a tar archive")
  806. if err := cmd.Parse(args); err != nil {
  807. return nil
  808. }
  809. name := cmd.Arg(0)
  810. if container := srv.runtime.Get(name); container != nil {
  811. data, err := container.Export()
  812. if err != nil {
  813. return err
  814. }
  815. // Stream the entire contents of the container (basically a volatile snapshot)
  816. if _, err := io.Copy(stdout, data); err != nil {
  817. return err
  818. }
  819. return nil
  820. }
  821. return fmt.Errorf("No such container: %s", name)
  822. }
  823. func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  824. cmd := rcli.Subcmd(stdout,
  825. "diff", "CONTAINER",
  826. "Inspect changes on a container's filesystem")
  827. if err := cmd.Parse(args); err != nil {
  828. return nil
  829. }
  830. if cmd.NArg() < 1 {
  831. cmd.Usage()
  832. return nil
  833. }
  834. if container := srv.runtime.Get(cmd.Arg(0)); container == nil {
  835. return fmt.Errorf("No such container")
  836. } else {
  837. changes, err := container.Changes()
  838. if err != nil {
  839. return err
  840. }
  841. for _, change := range changes {
  842. fmt.Fprintln(stdout, change.String())
  843. }
  844. }
  845. return nil
  846. }
  847. func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  848. cmd := rcli.Subcmd(stdout, "logs", "CONTAINER", "Fetch the logs of a container")
  849. if err := cmd.Parse(args); err != nil {
  850. return nil
  851. }
  852. if cmd.NArg() != 1 {
  853. cmd.Usage()
  854. return nil
  855. }
  856. name := cmd.Arg(0)
  857. if container := srv.runtime.Get(name); container != nil {
  858. logStdout, err := container.ReadLog("stdout")
  859. if err != nil {
  860. return err
  861. }
  862. logStderr, err := container.ReadLog("stderr")
  863. if err != nil {
  864. return err
  865. }
  866. // FIXME: Interpolate stdout and stderr instead of concatenating them
  867. // FIXME: Differentiate stdout and stderr in the remote protocol
  868. if _, err := io.Copy(stdout, logStdout); err != nil {
  869. return err
  870. }
  871. if _, err := io.Copy(stdout, logStderr); err != nil {
  872. return err
  873. }
  874. return nil
  875. }
  876. return fmt.Errorf("No such container: %s", cmd.Arg(0))
  877. }
  878. func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  879. cmd := rcli.Subcmd(stdout, "attach", "CONTAINER", "Attach to a running container")
  880. if err := cmd.Parse(args); err != nil {
  881. return nil
  882. }
  883. if cmd.NArg() != 1 {
  884. cmd.Usage()
  885. return nil
  886. }
  887. name := cmd.Arg(0)
  888. container := srv.runtime.Get(name)
  889. if container == nil {
  890. return fmt.Errorf("No such container: %s", name)
  891. }
  892. if container.State.Ghost {
  893. return fmt.Errorf("Impossible to attach to a ghost container")
  894. }
  895. if container.Config.Tty {
  896. stdout.SetOptionRawTerminal()
  897. }
  898. // Flush the options to make sure the client sets the raw mode
  899. stdout.Flush()
  900. return <-container.Attach(stdin, nil, stdout, stdout)
  901. }
  902. // Ports type - Used to parse multiple -p flags
  903. type ports []int
  904. func (p *ports) String() string {
  905. return fmt.Sprint(*p)
  906. }
  907. func (p *ports) Set(value string) error {
  908. port, err := strconv.Atoi(value)
  909. if err != nil {
  910. return fmt.Errorf("Invalid port: %v", value)
  911. }
  912. *p = append(*p, port)
  913. return nil
  914. }
  915. // ListOpts type
  916. type ListOpts []string
  917. func (opts *ListOpts) String() string {
  918. return fmt.Sprint(*opts)
  919. }
  920. func (opts *ListOpts) Set(value string) error {
  921. *opts = append(*opts, value)
  922. return nil
  923. }
  924. // AttachOpts stores arguments to 'docker run -a', eg. which streams to attach to
  925. type AttachOpts map[string]bool
  926. func NewAttachOpts() AttachOpts {
  927. return make(AttachOpts)
  928. }
  929. func (opts AttachOpts) String() string {
  930. // Cast to underlying map type to avoid infinite recursion
  931. return fmt.Sprintf("%v", map[string]bool(opts))
  932. }
  933. func (opts AttachOpts) Set(val string) error {
  934. if val != "stdin" && val != "stdout" && val != "stderr" {
  935. return fmt.Errorf("Unsupported stream name: %s", val)
  936. }
  937. opts[val] = true
  938. return nil
  939. }
  940. func (opts AttachOpts) Get(val string) bool {
  941. if res, exists := opts[val]; exists {
  942. return res
  943. }
  944. return false
  945. }
  946. // PathOpts stores a unique set of absolute paths
  947. type PathOpts map[string]struct{}
  948. func NewPathOpts() PathOpts {
  949. return make(PathOpts)
  950. }
  951. func (opts PathOpts) String() string {
  952. return fmt.Sprintf("%v", map[string]struct{}(opts))
  953. }
  954. func (opts PathOpts) Set(val string) error {
  955. if !filepath.IsAbs(val) {
  956. return fmt.Errorf("%s is not an absolute path", val)
  957. }
  958. opts[filepath.Clean(val)] = struct{}{}
  959. return nil
  960. }
  961. func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  962. cmd := rcli.Subcmd(stdout, "tag", "[OPTIONS] IMAGE REPOSITORY [TAG]", "Tag an image into a repository")
  963. force := cmd.Bool("f", false, "Force")
  964. if err := cmd.Parse(args); err != nil {
  965. return nil
  966. }
  967. if cmd.NArg() < 2 {
  968. cmd.Usage()
  969. return nil
  970. }
  971. return srv.runtime.repositories.Set(cmd.Arg(1), cmd.Arg(2), cmd.Arg(0), *force)
  972. }
  973. func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
  974. config, err := ParseRun(args, stdout, srv.runtime.capabilities)
  975. if err != nil {
  976. return err
  977. }
  978. if config.Image == "" {
  979. fmt.Fprintln(stdout, "Error: Image not specified")
  980. return fmt.Errorf("Image not specified")
  981. }
  982. if config.Tty {
  983. stdout.SetOptionRawTerminal()
  984. }
  985. // Flush the options to make sure the client sets the raw mode
  986. // or tell the client there is no options
  987. stdout.Flush()
  988. b := NewBuilder(srv.runtime)
  989. // Create new container
  990. container, err := b.Create(config)
  991. if err != nil {
  992. // If container not found, try to pull it
  993. if srv.runtime.graph.IsNotExist(err) {
  994. fmt.Fprintf(stdout, "Image %s not found, trying to pull it from registry.\r\n", config.Image)
  995. if err = srv.CmdPull(stdin, stdout, config.Image); err != nil {
  996. return err
  997. }
  998. if container, err = b.Create(config); err != nil {
  999. return err
  1000. }
  1001. } else {
  1002. return err
  1003. }
  1004. }
  1005. var (
  1006. cStdin io.ReadCloser
  1007. cStdout, cStderr io.Writer
  1008. )
  1009. if config.AttachStdin {
  1010. r, w := io.Pipe()
  1011. go func() {
  1012. defer w.Close()
  1013. defer Debugf("Closing buffered stdin pipe")
  1014. io.Copy(w, stdin)
  1015. }()
  1016. cStdin = r
  1017. }
  1018. if config.AttachStdout {
  1019. cStdout = stdout
  1020. }
  1021. if config.AttachStderr {
  1022. cStderr = stdout // FIXME: rcli can't differentiate stdout from stderr
  1023. }
  1024. attachErr := container.Attach(cStdin, stdin, cStdout, cStderr)
  1025. Debugf("Starting\n")
  1026. if err := container.Start(); err != nil {
  1027. return err
  1028. }
  1029. if cStdout == nil && cStderr == nil {
  1030. fmt.Fprintln(stdout, container.ShortId())
  1031. }
  1032. Debugf("Waiting for attach to return\n")
  1033. <-attachErr
  1034. // Expecting I/O pipe error, discarding
  1035. // If we are in stdinonce mode, wait for the process to end
  1036. // otherwise, simply return
  1037. if config.StdinOnce && !config.Tty {
  1038. container.Wait()
  1039. }
  1040. return nil
  1041. }
  1042. func NewServer(autoRestart bool) (*Server, error) {
  1043. if runtime.GOARCH != "amd64" {
  1044. log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
  1045. }
  1046. runtime, err := NewRuntime(autoRestart)
  1047. if err != nil {
  1048. return nil, err
  1049. }
  1050. srv := &Server{
  1051. runtime: runtime,
  1052. }
  1053. return srv, nil
  1054. }
  1055. type Server struct {
  1056. runtime *Runtime
  1057. }