commands.go 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  1. package docker
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/dotcloud/docker/auth"
  9. "github.com/dotcloud/docker/fs"
  10. "github.com/dotcloud/docker/future"
  11. "github.com/dotcloud/docker/rcli"
  12. "io"
  13. "io/ioutil"
  14. "net/http"
  15. "net/url"
  16. "os"
  17. "path"
  18. "strconv"
  19. "strings"
  20. "sync"
  21. "text/tabwriter"
  22. "time"
  23. )
  24. const VERSION = "0.0.3"
  25. func (srv *Server) Name() string {
  26. return "docker"
  27. }
  28. // FIXME: Stop violating DRY by repeating usage here and in Subcmd declarations
  29. func (srv *Server) Help() string {
  30. help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
  31. for _, cmd := range [][]interface{}{
  32. {"run", "Run a command in a container"},
  33. {"ps", "Display a list of containers"},
  34. {"import", "Create a new filesystem image from the contents of a tarball"},
  35. {"attach", "Attach to a running container"},
  36. {"cat", "Write the contents of a container's file to standard output"},
  37. {"commit", "Create a new image from a container's changes"},
  38. {"cp", "Create a copy of IMAGE and call it NAME"},
  39. {"debug", "(debug only) (No documentation available)"},
  40. {"diff", "Inspect changes on a container's filesystem"},
  41. {"images", "List images"},
  42. {"info", "Display system-wide information"},
  43. {"inspect", "Return low-level information on a container"},
  44. {"kill", "Kill a running container"},
  45. {"layers", "(debug only) List filesystem layers"},
  46. {"login", "Register or Login to the docker registry server"},
  47. {"logs", "Fetch the logs of a container"},
  48. {"ls", "List the contents of a container's directory"},
  49. {"mirror", "(debug only) (No documentation available)"},
  50. {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
  51. {"ps", "List containers"},
  52. {"reset", "Reset changes to a container's filesystem"},
  53. {"restart", "Restart a running container"},
  54. {"rm", "Remove a container"},
  55. {"rmi", "Remove an image"},
  56. {"run", "Run a command in a new container"},
  57. {"start", "Start a stopped container"},
  58. {"stop", "Stop a running container"},
  59. {"tar", "Stream the contents of a container as a tar archive"},
  60. {"umount", "(debug only) Mount a container's filesystem"},
  61. {"version", "Show the docker version information"},
  62. {"wait", "Block until a container stops, then print its exit code"},
  63. {"web", "A web UI for docker"},
  64. {"write", "Write the contents of standard input to a container's file"},
  65. } {
  66. help += fmt.Sprintf(" %-10.10s%s\n", cmd...)
  67. }
  68. return help
  69. }
  70. // 'docker login': login / register a user to registry service.
  71. func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  72. cmd := rcli.Subcmd(stdout, "login", "", "Register or Login to the docker registry server")
  73. if err := cmd.Parse(args); err != nil {
  74. return nil
  75. }
  76. var username string
  77. var password string
  78. var email string
  79. authConfig, err := auth.LoadConfig()
  80. if err != nil {
  81. fmt.Fprintf(stdout, "Error : %s\n", err)
  82. }
  83. fmt.Fprint(stdout, "Username (", authConfig.Username, "): ")
  84. fmt.Fscanf(stdin, "%s", &username)
  85. if username == "" {
  86. username = authConfig.Username
  87. }
  88. if username != authConfig.Username {
  89. fmt.Fprint(stdout, "Password: ")
  90. fmt.Fscanf(stdin, "%s", &password)
  91. if password == "" {
  92. return errors.New("Error : Password Required\n")
  93. }
  94. fmt.Fprint(stdout, "Email (", authConfig.Email, "): ")
  95. fmt.Fscanf(stdin, "%s", &email)
  96. if email == "" {
  97. email = authConfig.Email
  98. }
  99. } else {
  100. password = authConfig.Password
  101. email = authConfig.Email
  102. }
  103. newAuthConfig := auth.AuthConfig{Username: username, Password: password, Email: email}
  104. status, err := auth.Login(newAuthConfig)
  105. if err != nil {
  106. fmt.Fprintf(stdout, "Error : %s\n", err)
  107. }
  108. if status != "" {
  109. fmt.Fprintf(stdout, status)
  110. }
  111. return nil
  112. }
  113. // 'docker wait': block until a container stops
  114. func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  115. cmd := rcli.Subcmd(stdout, "wait", "[OPTIONS] NAME", "Block until a container stops, then print its exit code.")
  116. if err := cmd.Parse(args); err != nil {
  117. return nil
  118. }
  119. if cmd.NArg() < 1 {
  120. cmd.Usage()
  121. return nil
  122. }
  123. for _, name := range cmd.Args() {
  124. if container := srv.containers.Get(name); container != nil {
  125. fmt.Fprintln(stdout, container.Wait())
  126. } else {
  127. return errors.New("No such container: " + name)
  128. }
  129. }
  130. return nil
  131. }
  132. // 'docker version': show version information
  133. func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  134. fmt.Fprintf(stdout, "Version:%s\n", VERSION)
  135. return nil
  136. }
  137. // 'docker info': display system-wide information.
  138. func (srv *Server) CmdInfo(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  139. images, _ := srv.images.Images()
  140. var imgcount int
  141. if images == nil {
  142. imgcount = 0
  143. } else {
  144. imgcount = len(images)
  145. }
  146. cmd := rcli.Subcmd(stdout, "info", "", "Display system-wide information.")
  147. if err := cmd.Parse(args); err != nil {
  148. return nil
  149. }
  150. if cmd.NArg() > 0 {
  151. cmd.Usage()
  152. return nil
  153. }
  154. fmt.Fprintf(stdout, "containers: %d\nversion: %s\nimages: %d\n",
  155. len(srv.containers.List()),
  156. VERSION,
  157. imgcount)
  158. return nil
  159. }
  160. func (srv *Server) CmdStop(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  161. cmd := rcli.Subcmd(stdout, "stop", "[OPTIONS] NAME", "Stop a running container")
  162. if err := cmd.Parse(args); err != nil {
  163. return nil
  164. }
  165. if cmd.NArg() < 1 {
  166. cmd.Usage()
  167. return nil
  168. }
  169. for _, name := range cmd.Args() {
  170. if container := srv.containers.Get(name); container != nil {
  171. if err := container.Stop(); err != nil {
  172. return err
  173. }
  174. fmt.Fprintln(stdout, container.Id)
  175. } else {
  176. return errors.New("No such container: " + name)
  177. }
  178. }
  179. return nil
  180. }
  181. func (srv *Server) CmdRestart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  182. cmd := rcli.Subcmd(stdout, "restart", "[OPTIONS] NAME", "Restart a running container")
  183. if err := cmd.Parse(args); err != nil {
  184. return nil
  185. }
  186. if cmd.NArg() < 1 {
  187. cmd.Usage()
  188. return nil
  189. }
  190. for _, name := range cmd.Args() {
  191. if container := srv.containers.Get(name); container != nil {
  192. if err := container.Restart(); err != nil {
  193. return err
  194. }
  195. fmt.Fprintln(stdout, container.Id)
  196. } else {
  197. return errors.New("No such container: " + name)
  198. }
  199. }
  200. return nil
  201. }
  202. func (srv *Server) CmdStart(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  203. cmd := rcli.Subcmd(stdout, "start", "[OPTIONS] NAME", "Start a stopped container")
  204. if err := cmd.Parse(args); err != nil {
  205. return nil
  206. }
  207. if cmd.NArg() < 1 {
  208. cmd.Usage()
  209. return nil
  210. }
  211. for _, name := range cmd.Args() {
  212. if container := srv.containers.Get(name); container != nil {
  213. if err := container.Start(); err != nil {
  214. return err
  215. }
  216. fmt.Fprintln(stdout, container.Id)
  217. } else {
  218. return errors.New("No such container: " + name)
  219. }
  220. }
  221. return nil
  222. }
  223. func (srv *Server) CmdUmount(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  224. cmd := rcli.Subcmd(stdout, "umount", "[OPTIONS] NAME", "umount a container's filesystem (debug only)")
  225. if err := cmd.Parse(args); err != nil {
  226. return nil
  227. }
  228. if cmd.NArg() < 1 {
  229. cmd.Usage()
  230. return nil
  231. }
  232. for _, name := range cmd.Args() {
  233. if container := srv.containers.Get(name); container != nil {
  234. if err := container.Mountpoint.Umount(); err != nil {
  235. return err
  236. }
  237. fmt.Fprintln(stdout, container.Id)
  238. } else {
  239. return errors.New("No such container: " + name)
  240. }
  241. }
  242. return nil
  243. }
  244. func (srv *Server) CmdMount(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  245. cmd := rcli.Subcmd(stdout, "umount", "[OPTIONS] NAME", "mount a container's filesystem (debug only)")
  246. if err := cmd.Parse(args); err != nil {
  247. return nil
  248. }
  249. if cmd.NArg() < 1 {
  250. cmd.Usage()
  251. return nil
  252. }
  253. for _, name := range cmd.Args() {
  254. if container := srv.containers.Get(name); container != nil {
  255. if err := container.Mountpoint.EnsureMounted(); err != nil {
  256. return err
  257. }
  258. fmt.Fprintln(stdout, container.Id)
  259. } else {
  260. return errors.New("No such container: " + name)
  261. }
  262. }
  263. return nil
  264. }
  265. func (srv *Server) CmdCat(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  266. cmd := rcli.Subcmd(stdout, "cat", "[OPTIONS] CONTAINER PATH", "write the contents of a container's file to standard output")
  267. if err := cmd.Parse(args); err != nil {
  268. return nil
  269. }
  270. if cmd.NArg() < 2 {
  271. cmd.Usage()
  272. return nil
  273. }
  274. name, path := cmd.Arg(0), cmd.Arg(1)
  275. if container := srv.containers.Get(name); container != nil {
  276. if f, err := container.Mountpoint.OpenFile(path, os.O_RDONLY, 0); err != nil {
  277. return err
  278. } else if _, err := io.Copy(stdout, f); err != nil {
  279. return err
  280. }
  281. return nil
  282. }
  283. return errors.New("No such container: " + name)
  284. }
  285. func (srv *Server) CmdWrite(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  286. cmd := rcli.Subcmd(stdout, "write", "[OPTIONS] CONTAINER PATH", "write the contents of standard input to a container's file")
  287. if err := cmd.Parse(args); err != nil {
  288. return nil
  289. }
  290. if cmd.NArg() < 2 {
  291. cmd.Usage()
  292. return nil
  293. }
  294. name, path := cmd.Arg(0), cmd.Arg(1)
  295. if container := srv.containers.Get(name); container != nil {
  296. if f, err := container.Mountpoint.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600); err != nil {
  297. return err
  298. } else if _, err := io.Copy(f, stdin); err != nil {
  299. return err
  300. }
  301. return nil
  302. }
  303. return errors.New("No such container: " + name)
  304. }
  305. func (srv *Server) CmdLs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  306. cmd := rcli.Subcmd(stdout, "ls", "[OPTIONS] CONTAINER PATH", "List the contents of a container's directory")
  307. if err := cmd.Parse(args); err != nil {
  308. return nil
  309. }
  310. if cmd.NArg() < 2 {
  311. cmd.Usage()
  312. return nil
  313. }
  314. name, path := cmd.Arg(0), cmd.Arg(1)
  315. if container := srv.containers.Get(name); container != nil {
  316. if files, err := container.Mountpoint.ReadDir(path); err != nil {
  317. return err
  318. } else {
  319. for _, f := range files {
  320. fmt.Fprintln(stdout, f.Name())
  321. }
  322. }
  323. return nil
  324. }
  325. return errors.New("No such container: " + name)
  326. }
  327. func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  328. cmd := rcli.Subcmd(stdout, "inspect", "[OPTIONS] CONTAINER", "Return low-level information on a container")
  329. if err := cmd.Parse(args); err != nil {
  330. return nil
  331. }
  332. if cmd.NArg() < 1 {
  333. cmd.Usage()
  334. return nil
  335. }
  336. name := cmd.Arg(0)
  337. var obj interface{}
  338. if container := srv.containers.Get(name); container != nil {
  339. obj = container
  340. } else if image, err := srv.images.Find(name); err != nil {
  341. return err
  342. } else if image != nil {
  343. obj = image
  344. } else {
  345. // No output means the object does not exist
  346. // (easier to script since stdout and stderr are not differentiated atm)
  347. return nil
  348. }
  349. data, err := json.Marshal(obj)
  350. if err != nil {
  351. return err
  352. }
  353. indented := new(bytes.Buffer)
  354. if err = json.Indent(indented, data, "", " "); err != nil {
  355. return err
  356. }
  357. if _, err := io.Copy(stdout, indented); err != nil {
  358. return err
  359. }
  360. stdout.Write([]byte{'\n'})
  361. return nil
  362. }
  363. func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  364. cmd := rcli.Subcmd(stdout, "port", "[OPTIONS] CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
  365. if err := cmd.Parse(args); err != nil {
  366. return nil
  367. }
  368. if cmd.NArg() != 2 {
  369. cmd.Usage()
  370. return nil
  371. }
  372. name := cmd.Arg(0)
  373. privatePort := cmd.Arg(1)
  374. if container := srv.containers.Get(name); container == nil {
  375. return errors.New("No such container: " + name)
  376. } else {
  377. if frontend, exists := container.NetworkSettings.PortMapping[privatePort]; !exists {
  378. return fmt.Errorf("No private port '%s' allocated on %s", privatePort, name)
  379. } else {
  380. fmt.Fprintln(stdout, frontend)
  381. }
  382. }
  383. return nil
  384. }
  385. // 'docker rmi NAME' removes all images with the name NAME
  386. func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) (err error) {
  387. cmd := rcli.Subcmd(stdout, "rmimage", "[OPTIONS] IMAGE", "Remove an image")
  388. fl_all := cmd.Bool("a", false, "Use IMAGE as a path and remove ALL images in this path")
  389. fl_regexp := cmd.Bool("r", false, "Use IMAGE as a regular expression instead of an exact name")
  390. if cmd.Parse(args) != nil || cmd.NArg() < 1 {
  391. cmd.Usage()
  392. return nil
  393. }
  394. for _, name := range cmd.Args() {
  395. if *fl_regexp {
  396. err = srv.images.RemoveRegexp(name)
  397. } else if *fl_all {
  398. err = srv.images.RemoveInPath(name)
  399. } else {
  400. if image, err1 := srv.images.Find(name); err1 != nil {
  401. err = err1
  402. } else if err1 == nil && image == nil {
  403. err = fmt.Errorf("No such image: %s", name)
  404. } else {
  405. err = srv.images.Remove(image)
  406. }
  407. }
  408. if err != nil {
  409. return err
  410. }
  411. }
  412. return nil
  413. }
  414. func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  415. cmd := rcli.Subcmd(stdout, "rm", "[OPTIONS] CONTAINER", "Remove a container")
  416. if err := cmd.Parse(args); err != nil {
  417. return nil
  418. }
  419. for _, name := range cmd.Args() {
  420. container := srv.containers.Get(name)
  421. if container == nil {
  422. return errors.New("No such container: " + name)
  423. }
  424. if err := srv.containers.Destroy(container); err != nil {
  425. fmt.Fprintln(stdout, "Error destroying container "+name+": "+err.Error())
  426. }
  427. }
  428. return nil
  429. }
  430. // 'docker kill NAME' kills a running container
  431. func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  432. cmd := rcli.Subcmd(stdout, "kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container")
  433. if err := cmd.Parse(args); err != nil {
  434. return nil
  435. }
  436. for _, name := range cmd.Args() {
  437. container := srv.containers.Get(name)
  438. if container == nil {
  439. return errors.New("No such container: " + name)
  440. }
  441. if err := container.Kill(); err != nil {
  442. fmt.Fprintln(stdout, "Error killing container "+name+": "+err.Error())
  443. }
  444. }
  445. return nil
  446. }
  447. func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  448. cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] NAME", "Create a new filesystem image from the contents of a tarball")
  449. fl_stdin := cmd.Bool("stdin", false, "Read tarball from stdin")
  450. var archive io.Reader
  451. var resp *http.Response
  452. if err := cmd.Parse(args); err != nil {
  453. return nil
  454. }
  455. name := cmd.Arg(0)
  456. if name == "" {
  457. return errors.New("Not enough arguments")
  458. }
  459. if *fl_stdin {
  460. archive = stdin
  461. } else {
  462. u, err := url.Parse(name)
  463. if err != nil {
  464. return err
  465. }
  466. if u.Scheme == "" {
  467. u.Scheme = "http"
  468. }
  469. if u.Host == "" {
  470. u.Host = "get.docker.io"
  471. u.Path = path.Join("/images", u.Path)
  472. }
  473. fmt.Fprintf(stdout, "Downloading from %s\n", u.String())
  474. // Download with curl (pretty progress bar)
  475. // If curl is not available, fallback to http.Get()
  476. resp, err = future.Download(u.String(), stdout)
  477. if err != nil {
  478. return err
  479. }
  480. archive = future.ProgressReader(resp.Body, int(resp.ContentLength), stdout)
  481. }
  482. fmt.Fprintf(stdout, "Unpacking to %s\n", name)
  483. img, err := srv.images.Create(archive, nil, name, "")
  484. if err != nil {
  485. return err
  486. }
  487. fmt.Fprintln(stdout, img.Id)
  488. return nil
  489. }
  490. func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  491. cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images")
  492. limit := cmd.Int("l", 0, "Only show the N most recent versions of each image")
  493. quiet := cmd.Bool("q", false, "only show numeric IDs")
  494. if err := cmd.Parse(args); err != nil {
  495. return nil
  496. }
  497. if cmd.NArg() > 1 {
  498. cmd.Usage()
  499. return nil
  500. }
  501. var nameFilter string
  502. if cmd.NArg() == 1 {
  503. nameFilter = cmd.Arg(0)
  504. }
  505. w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
  506. if !*quiet {
  507. fmt.Fprintf(w, "NAME\tID\tCREATED\tPARENT\n")
  508. }
  509. paths, err := srv.images.Paths()
  510. if err != nil {
  511. return err
  512. }
  513. for _, name := range paths {
  514. if nameFilter != "" && nameFilter != name {
  515. continue
  516. }
  517. ids, err := srv.images.List(name)
  518. if err != nil {
  519. return err
  520. }
  521. for idx, img := range ids {
  522. if *limit > 0 && idx >= *limit {
  523. break
  524. }
  525. if !*quiet {
  526. for idx, field := range []string{
  527. /* NAME */ name,
  528. /* ID */ img.Id,
  529. /* CREATED */ future.HumanDuration(time.Now().Sub(time.Unix(img.Created, 0))) + " ago",
  530. /* PARENT */ img.Parent,
  531. } {
  532. if idx == 0 {
  533. w.Write([]byte(field))
  534. } else {
  535. w.Write([]byte("\t" + field))
  536. }
  537. }
  538. w.Write([]byte{'\n'})
  539. } else {
  540. stdout.Write([]byte(img.Id + "\n"))
  541. }
  542. }
  543. }
  544. if !*quiet {
  545. w.Flush()
  546. }
  547. return nil
  548. }
  549. func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  550. cmd := rcli.Subcmd(stdout,
  551. "ps", "[OPTIONS]", "List containers")
  552. quiet := cmd.Bool("q", false, "Only display numeric IDs")
  553. fl_all := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.")
  554. fl_full := cmd.Bool("notrunc", false, "Don't truncate output")
  555. if err := cmd.Parse(args); err != nil {
  556. return nil
  557. }
  558. w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0)
  559. if !*quiet {
  560. fmt.Fprintf(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT\n")
  561. }
  562. for _, container := range srv.containers.List() {
  563. comment := container.GetUserData("comment")
  564. if !container.State.Running && !*fl_all {
  565. continue
  566. }
  567. if !*quiet {
  568. command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " "))
  569. if !*fl_full {
  570. command = Trunc(command, 20)
  571. }
  572. for idx, field := range []string{
  573. /* ID */ container.Id,
  574. /* IMAGE */ container.GetUserData("image"),
  575. /* COMMAND */ command,
  576. /* CREATED */ future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
  577. /* STATUS */ container.State.String(),
  578. /* COMMENT */ comment,
  579. } {
  580. if idx == 0 {
  581. w.Write([]byte(field))
  582. } else {
  583. w.Write([]byte("\t" + field))
  584. }
  585. }
  586. w.Write([]byte{'\n'})
  587. } else {
  588. stdout.Write([]byte(container.Id + "\n"))
  589. }
  590. }
  591. if !*quiet {
  592. w.Flush()
  593. }
  594. return nil
  595. }
  596. func (srv *Server) CmdLayers(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  597. cmd := rcli.Subcmd(stdout,
  598. "layers", "[OPTIONS]",
  599. "List filesystem layers (debug only)")
  600. if err := cmd.Parse(args); err != nil {
  601. return nil
  602. }
  603. for _, layer := range srv.images.Layers() {
  604. fmt.Fprintln(stdout, layer)
  605. }
  606. return nil
  607. }
  608. func (srv *Server) CmdCp(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  609. cmd := rcli.Subcmd(stdout,
  610. "cp", "[OPTIONS] IMAGE NAME",
  611. "Create a copy of IMAGE and call it NAME")
  612. if err := cmd.Parse(args); err != nil {
  613. return nil
  614. }
  615. if image, err := srv.images.Get(cmd.Arg(0)); err != nil {
  616. return err
  617. } else if image == nil {
  618. return errors.New("Image " + cmd.Arg(0) + " does not exist")
  619. } else {
  620. if img, err := image.Copy(cmd.Arg(1)); err != nil {
  621. return err
  622. } else {
  623. fmt.Fprintln(stdout, img.Id)
  624. }
  625. }
  626. return nil
  627. }
  628. func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  629. cmd := rcli.Subcmd(stdout,
  630. "commit", "[OPTIONS] CONTAINER [DEST]",
  631. "Create a new image from a container's changes")
  632. if err := cmd.Parse(args); err != nil {
  633. return nil
  634. }
  635. containerName, imgName := cmd.Arg(0), cmd.Arg(1)
  636. if containerName == "" || imgName == "" {
  637. cmd.Usage()
  638. return nil
  639. }
  640. if container := srv.containers.Get(containerName); container != nil {
  641. // FIXME: freeze the container before copying it to avoid data corruption?
  642. rwTar, err := fs.Tar(container.Mountpoint.Rw, fs.Uncompressed)
  643. if err != nil {
  644. return err
  645. }
  646. // Create a new image from the container's base layers + a new layer from container changes
  647. parentImg, err := srv.images.Get(container.Image)
  648. if err != nil {
  649. return err
  650. }
  651. img, err := srv.images.Create(rwTar, parentImg, imgName, "")
  652. if err != nil {
  653. return err
  654. }
  655. fmt.Fprintln(stdout, img.Id)
  656. return nil
  657. }
  658. return errors.New("No such container: " + containerName)
  659. }
  660. func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  661. cmd := rcli.Subcmd(stdout,
  662. "tar", "CONTAINER",
  663. "Stream the contents of a container as a tar archive")
  664. fl_sparse := cmd.Bool("s", false, "Generate a sparse tar stream (top layer + reference to bottom layers)")
  665. if err := cmd.Parse(args); err != nil {
  666. return nil
  667. }
  668. if *fl_sparse {
  669. return errors.New("Sparse mode not yet implemented") // FIXME
  670. }
  671. name := cmd.Arg(0)
  672. if container := srv.containers.Get(name); container != nil {
  673. if err := container.Mountpoint.EnsureMounted(); err != nil {
  674. return err
  675. }
  676. data, err := fs.Tar(container.Mountpoint.Root, fs.Uncompressed)
  677. if err != nil {
  678. return err
  679. }
  680. // Stream the entire contents of the container (basically a volatile snapshot)
  681. if _, err := io.Copy(stdout, data); err != nil {
  682. return err
  683. }
  684. return nil
  685. }
  686. return errors.New("No such container: " + name)
  687. }
  688. func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  689. cmd := rcli.Subcmd(stdout,
  690. "diff", "CONTAINER [OPTIONS]",
  691. "Inspect changes on a container's filesystem")
  692. if err := cmd.Parse(args); err != nil {
  693. return nil
  694. }
  695. if cmd.NArg() < 1 {
  696. return errors.New("Not enough arguments")
  697. }
  698. if container := srv.containers.Get(cmd.Arg(0)); container == nil {
  699. return errors.New("No such container")
  700. } else {
  701. changes, err := srv.images.Changes(container.Mountpoint)
  702. if err != nil {
  703. return err
  704. }
  705. for _, change := range changes {
  706. fmt.Fprintln(stdout, change.String())
  707. }
  708. }
  709. return nil
  710. }
  711. func (srv *Server) CmdReset(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  712. cmd := rcli.Subcmd(stdout,
  713. "reset", "CONTAINER [OPTIONS]",
  714. "Reset changes to a container's filesystem")
  715. if err := cmd.Parse(args); err != nil {
  716. return nil
  717. }
  718. if cmd.NArg() < 1 {
  719. return errors.New("Not enough arguments")
  720. }
  721. for _, name := range cmd.Args() {
  722. if container := srv.containers.Get(name); container != nil {
  723. if err := container.Mountpoint.Reset(); err != nil {
  724. return errors.New("Reset " + container.Id + ": " + err.Error())
  725. }
  726. }
  727. }
  728. return nil
  729. }
  730. func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  731. cmd := rcli.Subcmd(stdout, "logs", "[OPTIONS] CONTAINER", "Fetch the logs of a container")
  732. if err := cmd.Parse(args); err != nil {
  733. return nil
  734. }
  735. if cmd.NArg() != 1 {
  736. cmd.Usage()
  737. return nil
  738. }
  739. name := cmd.Arg(0)
  740. if container := srv.containers.Get(name); container != nil {
  741. if _, err := io.Copy(stdout, container.StdoutLog()); err != nil {
  742. return err
  743. }
  744. if _, err := io.Copy(stdout, container.StderrLog()); err != nil {
  745. return err
  746. }
  747. return nil
  748. }
  749. return errors.New("No such container: " + cmd.Arg(0))
  750. }
  751. func (srv *Server) CreateContainer(img *fs.Image, ports []int, user string, tty bool, openStdin bool, memory int64, comment string, cmd string, args ...string) (*Container, error) {
  752. id := future.RandomId()[:8]
  753. container, err := srv.containers.Create(id, cmd, args, img,
  754. &Config{
  755. Hostname: id,
  756. Ports: ports,
  757. User: user,
  758. Tty: tty,
  759. OpenStdin: openStdin,
  760. Memory: memory,
  761. })
  762. if err != nil {
  763. return nil, err
  764. }
  765. if err := container.SetUserData("image", img.Id); err != nil {
  766. srv.containers.Destroy(container)
  767. return nil, errors.New("Error setting container userdata: " + err.Error())
  768. }
  769. if err := container.SetUserData("comment", comment); err != nil {
  770. srv.containers.Destroy(container)
  771. return nil, errors.New("Error setting container userdata: " + err.Error())
  772. }
  773. return container, nil
  774. }
  775. func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  776. cmd := rcli.Subcmd(stdout, "attach", "[OPTIONS]", "Attach to a running container")
  777. fl_i := cmd.Bool("i", false, "Attach to stdin")
  778. fl_o := cmd.Bool("o", true, "Attach to stdout")
  779. fl_e := cmd.Bool("e", true, "Attach to stderr")
  780. if err := cmd.Parse(args); err != nil {
  781. return nil
  782. }
  783. if cmd.NArg() != 1 {
  784. cmd.Usage()
  785. return nil
  786. }
  787. name := cmd.Arg(0)
  788. container := srv.containers.Get(name)
  789. if container == nil {
  790. return errors.New("No such container: " + name)
  791. }
  792. var wg sync.WaitGroup
  793. if *fl_i {
  794. c_stdin, err := container.StdinPipe()
  795. if err != nil {
  796. return err
  797. }
  798. wg.Add(1)
  799. go func() { io.Copy(c_stdin, stdin); wg.Add(-1) }()
  800. }
  801. if *fl_o {
  802. c_stdout, err := container.StdoutPipe()
  803. if err != nil {
  804. return err
  805. }
  806. wg.Add(1)
  807. go func() { io.Copy(stdout, c_stdout); wg.Add(-1) }()
  808. }
  809. if *fl_e {
  810. c_stderr, err := container.StderrPipe()
  811. if err != nil {
  812. return err
  813. }
  814. wg.Add(1)
  815. go func() { io.Copy(stdout, c_stderr); wg.Add(-1) }()
  816. }
  817. wg.Wait()
  818. return nil
  819. }
  820. // Ports type - Used to parse multiple -p flags
  821. type ports []int
  822. func (p *ports) String() string {
  823. return fmt.Sprint(*p)
  824. }
  825. func (p *ports) Set(value string) error {
  826. port, err := strconv.Atoi(value)
  827. if err != nil {
  828. return fmt.Errorf("Invalid port: %v", value)
  829. }
  830. *p = append(*p, port)
  831. return nil
  832. }
  833. func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  834. cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container")
  835. fl_user := cmd.String("u", "", "Username or UID")
  836. fl_attach := cmd.Bool("a", false, "Attach stdin and stdout")
  837. fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
  838. fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
  839. fl_comment := cmd.String("c", "", "Comment")
  840. fl_memory := cmd.Int64("m", 0, "Memory limit (in bytes)")
  841. var fl_ports ports
  842. cmd.Var(&fl_ports, "p", "Map a network port to the container")
  843. if err := cmd.Parse(args); err != nil {
  844. return nil
  845. }
  846. name := cmd.Arg(0)
  847. var img_name string
  848. //var img_version string // Only here for reference
  849. var cmdline []string
  850. if len(cmd.Args()) >= 2 {
  851. cmdline = cmd.Args()[1:]
  852. }
  853. // Choose a default image if needed
  854. if name == "" {
  855. name = "base"
  856. }
  857. // Choose a default command if needed
  858. if len(cmdline) == 0 {
  859. *fl_stdin = true
  860. *fl_tty = true
  861. *fl_attach = true
  862. cmdline = []string{"/bin/bash", "-i"}
  863. }
  864. // Find the image
  865. img, err := srv.images.Find(name)
  866. if err != nil {
  867. return err
  868. } else if img == nil {
  869. // Separate the name:version tag
  870. if strings.Contains(name, ":") {
  871. parts := strings.SplitN(name, ":", 2)
  872. img_name = parts[0]
  873. //img_version = parts[1] // Only here for reference
  874. } else {
  875. img_name = name
  876. }
  877. stdin_noclose := ioutil.NopCloser(stdin)
  878. if err := srv.CmdImport(stdin_noclose, stdout, img_name); err != nil {
  879. return err
  880. }
  881. img, err = srv.images.Find(name)
  882. if err != nil || img == nil {
  883. return errors.New("Could not find image after downloading: " + name)
  884. }
  885. }
  886. // Create new container
  887. container, err := srv.CreateContainer(img, fl_ports, *fl_user, *fl_tty,
  888. *fl_stdin, *fl_memory, *fl_comment, cmdline[0], cmdline[1:]...)
  889. if err != nil {
  890. return errors.New("Error creating container: " + err.Error())
  891. }
  892. if *fl_stdin {
  893. cmd_stdin, err := container.StdinPipe()
  894. if err != nil {
  895. return err
  896. }
  897. if *fl_attach {
  898. future.Go(func() error {
  899. _, err := io.Copy(cmd_stdin, stdin)
  900. cmd_stdin.Close()
  901. return err
  902. })
  903. }
  904. }
  905. // Run the container
  906. if *fl_attach {
  907. cmd_stderr, err := container.StderrPipe()
  908. if err != nil {
  909. return err
  910. }
  911. cmd_stdout, err := container.StdoutPipe()
  912. if err != nil {
  913. return err
  914. }
  915. if err := container.Start(); err != nil {
  916. return err
  917. }
  918. sending_stdout := future.Go(func() error {
  919. _, err := io.Copy(stdout, cmd_stdout)
  920. return err
  921. })
  922. sending_stderr := future.Go(func() error {
  923. _, err := io.Copy(stdout, cmd_stderr)
  924. return err
  925. })
  926. err_sending_stdout := <-sending_stdout
  927. err_sending_stderr := <-sending_stderr
  928. if err_sending_stdout != nil {
  929. return err_sending_stdout
  930. }
  931. if err_sending_stderr != nil {
  932. return err_sending_stderr
  933. }
  934. container.Wait()
  935. } else {
  936. if err := container.Start(); err != nil {
  937. return err
  938. }
  939. fmt.Fprintln(stdout, container.Id)
  940. }
  941. return nil
  942. }
  943. func NewServer() (*Server, error) {
  944. future.Seed()
  945. // if err != nil {
  946. // return nil, err
  947. // }
  948. containers, err := New()
  949. if err != nil {
  950. return nil, err
  951. }
  952. srv := &Server{
  953. images: containers.Store,
  954. containers: containers,
  955. }
  956. return srv, nil
  957. }
  958. func (srv *Server) CmdMirror(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  959. _, err := io.Copy(stdout, stdin)
  960. return err
  961. }
  962. func (srv *Server) CmdDebug(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  963. for {
  964. if line, err := bufio.NewReader(stdin).ReadString('\n'); err == nil {
  965. fmt.Printf("--- %s", line)
  966. } else if err == io.EOF {
  967. if len(line) > 0 {
  968. fmt.Printf("--- %s\n", line)
  969. }
  970. break
  971. } else {
  972. return err
  973. }
  974. }
  975. return nil
  976. }
  977. func (srv *Server) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
  978. cmd := rcli.Subcmd(stdout, "web", "[OPTIONS]", "A web UI for docker")
  979. showurl := cmd.Bool("u", false, "Return the URL of the web UI")
  980. if err := cmd.Parse(args); err != nil {
  981. return nil
  982. }
  983. if *showurl {
  984. fmt.Fprintln(stdout, "http://localhost:4242/web")
  985. } else {
  986. if file, err := os.Open("dockerweb.html"); err != nil {
  987. return err
  988. } else if _, err := io.Copy(stdout, file); err != nil {
  989. return err
  990. }
  991. }
  992. return nil
  993. }
  994. type Server struct {
  995. containers *Docker
  996. images *fs.Store
  997. }