commands.go 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599
  1. package client
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/base64"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "os/exec"
  15. "path"
  16. "path/filepath"
  17. "runtime"
  18. "strconv"
  19. "strings"
  20. "text/tabwriter"
  21. "text/template"
  22. "time"
  23. log "github.com/Sirupsen/logrus"
  24. "github.com/docker/docker/api"
  25. "github.com/docker/docker/dockerversion"
  26. "github.com/docker/docker/engine"
  27. "github.com/docker/docker/graph"
  28. "github.com/docker/docker/nat"
  29. "github.com/docker/docker/opts"
  30. "github.com/docker/docker/pkg/archive"
  31. "github.com/docker/docker/pkg/fileutils"
  32. flag "github.com/docker/docker/pkg/mflag"
  33. "github.com/docker/docker/pkg/parsers"
  34. "github.com/docker/docker/pkg/parsers/filters"
  35. "github.com/docker/docker/pkg/promise"
  36. "github.com/docker/docker/pkg/signal"
  37. "github.com/docker/docker/pkg/term"
  38. "github.com/docker/docker/pkg/timeutils"
  39. "github.com/docker/docker/pkg/units"
  40. "github.com/docker/docker/pkg/urlutil"
  41. "github.com/docker/docker/registry"
  42. "github.com/docker/docker/runconfig"
  43. "github.com/docker/docker/utils"
  44. )
  45. const (
  46. tarHeaderSize = 512
  47. )
  48. func (cli *DockerCli) CmdHelp(args ...string) error {
  49. if len(args) > 1 {
  50. method, exists := cli.getMethod(args[:2]...)
  51. if exists {
  52. method("--help")
  53. return nil
  54. }
  55. }
  56. if len(args) > 0 {
  57. method, exists := cli.getMethod(args[0])
  58. if !exists {
  59. fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
  60. os.Exit(1)
  61. } else {
  62. method("--help")
  63. return nil
  64. }
  65. }
  66. flag.Usage()
  67. return nil
  68. }
  69. func (cli *DockerCli) CmdBuild(args ...string) error {
  70. cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
  71. tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
  72. suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
  73. noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
  74. rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
  75. forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
  76. pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
  77. dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile(Default is 'Dockerfile' at context root)")
  78. cmd.Require(flag.Exact, 1)
  79. utils.ParseFlags(cmd, args, true)
  80. var (
  81. context archive.Archive
  82. isRemote bool
  83. err error
  84. )
  85. _, err = exec.LookPath("git")
  86. hasGit := err == nil
  87. if cmd.Arg(0) == "-" {
  88. // As a special case, 'docker build -' will build from either an empty context with the
  89. // contents of stdin as a Dockerfile, or a tar-ed context from stdin.
  90. buf := bufio.NewReader(cli.in)
  91. magic, err := buf.Peek(tarHeaderSize)
  92. if err != nil && err != io.EOF {
  93. return fmt.Errorf("failed to peek context header from STDIN: %v", err)
  94. }
  95. if !archive.IsArchive(magic) {
  96. dockerfile, err := ioutil.ReadAll(buf)
  97. if err != nil {
  98. return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err)
  99. }
  100. if *dockerfileName == "" {
  101. *dockerfileName = api.DefaultDockerfileName
  102. }
  103. context, err = archive.Generate(*dockerfileName, string(dockerfile))
  104. } else {
  105. context = ioutil.NopCloser(buf)
  106. }
  107. } else if urlutil.IsURL(cmd.Arg(0)) && (!urlutil.IsGitURL(cmd.Arg(0)) || !hasGit) {
  108. isRemote = true
  109. } else {
  110. root := cmd.Arg(0)
  111. if urlutil.IsGitURL(root) {
  112. remoteURL := cmd.Arg(0)
  113. if !urlutil.IsGitTransport(remoteURL) {
  114. remoteURL = "https://" + remoteURL
  115. }
  116. root, err = ioutil.TempDir("", "docker-build-git")
  117. if err != nil {
  118. return err
  119. }
  120. defer os.RemoveAll(root)
  121. if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
  122. return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
  123. }
  124. }
  125. if _, err := os.Stat(root); err != nil {
  126. return err
  127. }
  128. absRoot, err := filepath.Abs(root)
  129. if err != nil {
  130. return err
  131. }
  132. var filename string // path to Dockerfile
  133. var origDockerfile string // used for error msg
  134. if *dockerfileName == "" {
  135. // No -f/--file was specified so use the default
  136. origDockerfile = api.DefaultDockerfileName
  137. *dockerfileName = origDockerfile
  138. filename = path.Join(absRoot, *dockerfileName)
  139. } else {
  140. origDockerfile = *dockerfileName
  141. if filename, err = filepath.Abs(*dockerfileName); err != nil {
  142. return err
  143. }
  144. // Verify that 'filename' is within the build context
  145. if !strings.HasSuffix(absRoot, string(os.PathSeparator)) {
  146. absRoot += string(os.PathSeparator)
  147. }
  148. if !strings.HasPrefix(filename, absRoot) {
  149. return fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", *dockerfileName, root)
  150. }
  151. // Now reset the dockerfileName to be relative to the build context
  152. *dockerfileName = filename[len(absRoot):]
  153. }
  154. if _, err = os.Stat(filename); os.IsNotExist(err) {
  155. return fmt.Errorf("Can not locate Dockerfile: %s", origDockerfile)
  156. }
  157. var includes []string = []string{"."}
  158. excludes, err := utils.ReadDockerIgnore(path.Join(root, ".dockerignore"))
  159. if err != nil {
  160. return err
  161. }
  162. // If .dockerignore mentions .dockerignore or the Dockerfile
  163. // then make sure we send both files over to the daemon
  164. // because Dockerfile is, obviously, needed no matter what, and
  165. // .dockerignore is needed to know if either one needs to be
  166. // removed. The deamon will remove them for us, if needed, after it
  167. // parses the Dockerfile.
  168. keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
  169. keepThem2, _ := fileutils.Matches(*dockerfileName, excludes)
  170. if keepThem1 || keepThem2 {
  171. includes = append(includes, ".dockerignore", *dockerfileName)
  172. }
  173. if err = utils.ValidateContextDirectory(root, excludes); err != nil {
  174. return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
  175. }
  176. options := &archive.TarOptions{
  177. Compression: archive.Uncompressed,
  178. ExcludePatterns: excludes,
  179. IncludeFiles: includes,
  180. }
  181. context, err = archive.TarWithOptions(root, options)
  182. if err != nil {
  183. return err
  184. }
  185. }
  186. var body io.Reader
  187. // Setup an upload progress bar
  188. // FIXME: ProgressReader shouldn't be this annoying to use
  189. if context != nil {
  190. sf := utils.NewStreamFormatter(false)
  191. body = utils.ProgressReader(context, 0, cli.out, sf, true, "", "Sending build context to Docker daemon")
  192. }
  193. // Send the build context
  194. v := &url.Values{}
  195. //Check if the given image name can be resolved
  196. if *tag != "" {
  197. repository, tag := parsers.ParseRepositoryTag(*tag)
  198. if err := registry.ValidateRepositoryName(repository); err != nil {
  199. return err
  200. }
  201. if len(tag) > 0 {
  202. if err := graph.ValidateTagName(tag); err != nil {
  203. return err
  204. }
  205. }
  206. }
  207. v.Set("t", *tag)
  208. if *suppressOutput {
  209. v.Set("q", "1")
  210. }
  211. if isRemote {
  212. v.Set("remote", cmd.Arg(0))
  213. }
  214. if *noCache {
  215. v.Set("nocache", "1")
  216. }
  217. if *rm {
  218. v.Set("rm", "1")
  219. } else {
  220. v.Set("rm", "0")
  221. }
  222. if *forceRm {
  223. v.Set("forcerm", "1")
  224. }
  225. if *pull {
  226. v.Set("pull", "1")
  227. }
  228. v.Set("dockerfile", *dockerfileName)
  229. cli.LoadConfigFile()
  230. headers := http.Header(make(map[string][]string))
  231. buf, err := json.Marshal(cli.configFile)
  232. if err != nil {
  233. return err
  234. }
  235. headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
  236. if context != nil {
  237. headers.Set("Content-Type", "application/tar")
  238. }
  239. err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
  240. if jerr, ok := err.(*utils.JSONError); ok {
  241. // If no error code is set, default to 1
  242. if jerr.Code == 0 {
  243. jerr.Code = 1
  244. }
  245. return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
  246. }
  247. return err
  248. }
  249. // 'docker login': login / register a user to registry service.
  250. func (cli *DockerCli) CmdLogin(args ...string) error {
  251. cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
  252. cmd.Require(flag.Max, 1)
  253. var username, password, email string
  254. cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
  255. cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
  256. cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
  257. utils.ParseFlags(cmd, args, true)
  258. serverAddress := registry.IndexServerAddress()
  259. if len(cmd.Args()) > 0 {
  260. serverAddress = cmd.Arg(0)
  261. }
  262. promptDefault := func(prompt string, configDefault string) {
  263. if configDefault == "" {
  264. fmt.Fprintf(cli.out, "%s: ", prompt)
  265. } else {
  266. fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
  267. }
  268. }
  269. readInput := func(in io.Reader, out io.Writer) string {
  270. reader := bufio.NewReader(in)
  271. line, _, err := reader.ReadLine()
  272. if err != nil {
  273. fmt.Fprintln(out, err.Error())
  274. os.Exit(1)
  275. }
  276. return string(line)
  277. }
  278. cli.LoadConfigFile()
  279. authconfig, ok := cli.configFile.Configs[serverAddress]
  280. if !ok {
  281. authconfig = registry.AuthConfig{}
  282. }
  283. if username == "" {
  284. promptDefault("Username", authconfig.Username)
  285. username = readInput(cli.in, cli.out)
  286. if username == "" {
  287. username = authconfig.Username
  288. }
  289. }
  290. // Assume that a different username means they may not want to use
  291. // the password or email from the config file, so prompt them
  292. if username != authconfig.Username {
  293. if password == "" {
  294. oldState, err := term.SaveState(cli.inFd)
  295. if err != nil {
  296. return err
  297. }
  298. fmt.Fprintf(cli.out, "Password: ")
  299. term.DisableEcho(cli.inFd, oldState)
  300. password = readInput(cli.in, cli.out)
  301. fmt.Fprint(cli.out, "\n")
  302. term.RestoreTerminal(cli.inFd, oldState)
  303. if password == "" {
  304. return fmt.Errorf("Error : Password Required")
  305. }
  306. }
  307. if email == "" {
  308. promptDefault("Email", authconfig.Email)
  309. email = readInput(cli.in, cli.out)
  310. if email == "" {
  311. email = authconfig.Email
  312. }
  313. }
  314. } else {
  315. // However, if they don't override the username use the
  316. // password or email from the cmd line if specified. IOW, allow
  317. // then to change/overide them. And if not specified, just
  318. // use what's in the config file
  319. if password == "" {
  320. password = authconfig.Password
  321. }
  322. if email == "" {
  323. email = authconfig.Email
  324. }
  325. }
  326. authconfig.Username = username
  327. authconfig.Password = password
  328. authconfig.Email = email
  329. authconfig.ServerAddress = serverAddress
  330. cli.configFile.Configs[serverAddress] = authconfig
  331. stream, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress], false)
  332. if statusCode == 401 {
  333. delete(cli.configFile.Configs, serverAddress)
  334. registry.SaveConfig(cli.configFile)
  335. return err
  336. }
  337. if err != nil {
  338. return err
  339. }
  340. var out2 engine.Env
  341. err = out2.Decode(stream)
  342. if err != nil {
  343. cli.configFile, _ = registry.LoadConfig(os.Getenv("HOME"))
  344. return err
  345. }
  346. registry.SaveConfig(cli.configFile)
  347. if out2.Get("Status") != "" {
  348. fmt.Fprintf(cli.out, "%s\n", out2.Get("Status"))
  349. }
  350. return nil
  351. }
  352. // log out from a Docker registry
  353. func (cli *DockerCli) CmdLogout(args ...string) error {
  354. cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
  355. cmd.Require(flag.Max, 1)
  356. utils.ParseFlags(cmd, args, false)
  357. serverAddress := registry.IndexServerAddress()
  358. if len(cmd.Args()) > 0 {
  359. serverAddress = cmd.Arg(0)
  360. }
  361. cli.LoadConfigFile()
  362. if _, ok := cli.configFile.Configs[serverAddress]; !ok {
  363. fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
  364. } else {
  365. fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
  366. delete(cli.configFile.Configs, serverAddress)
  367. if err := registry.SaveConfig(cli.configFile); err != nil {
  368. return fmt.Errorf("Failed to save docker config: %v", err)
  369. }
  370. }
  371. return nil
  372. }
  373. // 'docker wait': block until a container stops
  374. func (cli *DockerCli) CmdWait(args ...string) error {
  375. cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
  376. cmd.Require(flag.Min, 1)
  377. utils.ParseFlags(cmd, args, true)
  378. var encounteredError error
  379. for _, name := range cmd.Args() {
  380. status, err := waitForExit(cli, name)
  381. if err != nil {
  382. fmt.Fprintf(cli.err, "%s\n", err)
  383. encounteredError = fmt.Errorf("Error: failed to wait one or more containers")
  384. } else {
  385. fmt.Fprintf(cli.out, "%d\n", status)
  386. }
  387. }
  388. return encounteredError
  389. }
  390. // 'docker version': show version information
  391. func (cli *DockerCli) CmdVersion(args ...string) error {
  392. cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
  393. cmd.Require(flag.Exact, 0)
  394. utils.ParseFlags(cmd, args, false)
  395. if dockerversion.VERSION != "" {
  396. fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
  397. }
  398. fmt.Fprintf(cli.out, "Client API version: %s\n", api.APIVERSION)
  399. fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
  400. if dockerversion.GITCOMMIT != "" {
  401. fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
  402. }
  403. fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
  404. body, _, err := readBody(cli.call("GET", "/version", nil, false))
  405. if err != nil {
  406. return err
  407. }
  408. out := engine.NewOutput()
  409. remoteVersion, err := out.AddEnv()
  410. if err != nil {
  411. log.Errorf("Error reading remote version: %s", err)
  412. return err
  413. }
  414. if _, err := out.Write(body); err != nil {
  415. log.Errorf("Error reading remote version: %s", err)
  416. return err
  417. }
  418. out.Close()
  419. fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
  420. if apiVersion := remoteVersion.Get("ApiVersion"); apiVersion != "" {
  421. fmt.Fprintf(cli.out, "Server API version: %s\n", apiVersion)
  422. }
  423. fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
  424. fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
  425. return nil
  426. }
  427. // 'docker info': display system-wide information.
  428. func (cli *DockerCli) CmdInfo(args ...string) error {
  429. cmd := cli.Subcmd("info", "", "Display system-wide information", true)
  430. cmd.Require(flag.Exact, 0)
  431. utils.ParseFlags(cmd, args, false)
  432. body, _, err := readBody(cli.call("GET", "/info", nil, false))
  433. if err != nil {
  434. return err
  435. }
  436. out := engine.NewOutput()
  437. remoteInfo, err := out.AddEnv()
  438. if err != nil {
  439. return err
  440. }
  441. if _, err := out.Write(body); err != nil {
  442. log.Errorf("Error reading remote info: %s", err)
  443. return err
  444. }
  445. out.Close()
  446. if remoteInfo.Exists("Containers") {
  447. fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
  448. }
  449. if remoteInfo.Exists("Images") {
  450. fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
  451. }
  452. if remoteInfo.Exists("Driver") {
  453. fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
  454. }
  455. if remoteInfo.Exists("DriverStatus") {
  456. var driverStatus [][2]string
  457. if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
  458. return err
  459. }
  460. for _, pair := range driverStatus {
  461. fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
  462. }
  463. }
  464. if remoteInfo.Exists("ExecutionDriver") {
  465. fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
  466. }
  467. if remoteInfo.Exists("KernelVersion") {
  468. fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
  469. }
  470. if remoteInfo.Exists("OperatingSystem") {
  471. fmt.Fprintf(cli.out, "Operating System: %s\n", remoteInfo.Get("OperatingSystem"))
  472. }
  473. if remoteInfo.Exists("NCPU") {
  474. fmt.Fprintf(cli.out, "CPUs: %d\n", remoteInfo.GetInt("NCPU"))
  475. }
  476. if remoteInfo.Exists("MemTotal") {
  477. fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(remoteInfo.GetInt64("MemTotal"))))
  478. }
  479. if remoteInfo.Exists("Name") {
  480. fmt.Fprintf(cli.out, "Name: %s\n", remoteInfo.Get("Name"))
  481. }
  482. if remoteInfo.Exists("ID") {
  483. fmt.Fprintf(cli.out, "ID: %s\n", remoteInfo.Get("ID"))
  484. }
  485. if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
  486. if remoteInfo.Exists("Debug") {
  487. fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
  488. }
  489. fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
  490. if remoteInfo.Exists("NFd") {
  491. fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
  492. }
  493. if remoteInfo.Exists("NGoroutines") {
  494. fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
  495. }
  496. if remoteInfo.Exists("NEventsListener") {
  497. fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
  498. }
  499. if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
  500. fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
  501. }
  502. if initPath := remoteInfo.Get("InitPath"); initPath != "" {
  503. fmt.Fprintf(cli.out, "Init Path: %s\n", initPath)
  504. }
  505. if root := remoteInfo.Get("DockerRootDir"); root != "" {
  506. fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", root)
  507. }
  508. }
  509. if len(remoteInfo.GetList("IndexServerAddress")) != 0 {
  510. cli.LoadConfigFile()
  511. u := cli.configFile.Configs[remoteInfo.Get("IndexServerAddress")].Username
  512. if len(u) > 0 {
  513. fmt.Fprintf(cli.out, "Username: %v\n", u)
  514. fmt.Fprintf(cli.out, "Registry: %v\n", remoteInfo.GetList("IndexServerAddress"))
  515. }
  516. }
  517. if remoteInfo.Exists("MemoryLimit") && !remoteInfo.GetBool("MemoryLimit") {
  518. fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
  519. }
  520. if remoteInfo.Exists("SwapLimit") && !remoteInfo.GetBool("SwapLimit") {
  521. fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
  522. }
  523. if remoteInfo.Exists("IPv4Forwarding") && !remoteInfo.GetBool("IPv4Forwarding") {
  524. fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
  525. }
  526. if remoteInfo.Exists("Labels") {
  527. fmt.Fprintln(cli.out, "Labels:")
  528. for _, attribute := range remoteInfo.GetList("Labels") {
  529. fmt.Fprintf(cli.out, " %s\n", attribute)
  530. }
  531. }
  532. return nil
  533. }
  534. func (cli *DockerCli) CmdStop(args ...string) error {
  535. cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true)
  536. nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
  537. cmd.Require(flag.Min, 1)
  538. utils.ParseFlags(cmd, args, true)
  539. v := url.Values{}
  540. v.Set("t", strconv.Itoa(*nSeconds))
  541. var encounteredError error
  542. for _, name := range cmd.Args() {
  543. _, _, err := readBody(cli.call("POST", "/containers/"+name+"/stop?"+v.Encode(), nil, false))
  544. if err != nil {
  545. fmt.Fprintf(cli.err, "%s\n", err)
  546. encounteredError = fmt.Errorf("Error: failed to stop one or more containers")
  547. } else {
  548. fmt.Fprintf(cli.out, "%s\n", name)
  549. }
  550. }
  551. return encounteredError
  552. }
  553. func (cli *DockerCli) CmdRestart(args ...string) error {
  554. cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
  555. nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
  556. cmd.Require(flag.Min, 1)
  557. utils.ParseFlags(cmd, args, true)
  558. v := url.Values{}
  559. v.Set("t", strconv.Itoa(*nSeconds))
  560. var encounteredError error
  561. for _, name := range cmd.Args() {
  562. _, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false))
  563. if err != nil {
  564. fmt.Fprintf(cli.err, "%s\n", err)
  565. encounteredError = fmt.Errorf("Error: failed to restart one or more containers")
  566. } else {
  567. fmt.Fprintf(cli.out, "%s\n", name)
  568. }
  569. }
  570. return encounteredError
  571. }
  572. func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
  573. sigc := make(chan os.Signal, 128)
  574. signal.CatchAll(sigc)
  575. go func() {
  576. for s := range sigc {
  577. if s == signal.SIGCHLD {
  578. continue
  579. }
  580. var sig string
  581. for sigStr, sigN := range signal.SignalMap {
  582. if sigN == s {
  583. sig = sigStr
  584. break
  585. }
  586. }
  587. if sig == "" {
  588. log.Errorf("Unsupported signal: %v. Discarding.", s)
  589. }
  590. if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
  591. log.Debugf("Error sending signal: %s", err)
  592. }
  593. }
  594. }()
  595. return sigc
  596. }
  597. func (cli *DockerCli) CmdStart(args ...string) error {
  598. var (
  599. cErr chan error
  600. tty bool
  601. cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true)
  602. attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
  603. openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
  604. )
  605. cmd.Require(flag.Min, 1)
  606. utils.ParseFlags(cmd, args, true)
  607. hijacked := make(chan io.Closer)
  608. if *attach || *openStdin {
  609. if cmd.NArg() > 1 {
  610. return fmt.Errorf("You cannot start and attach multiple containers at once.")
  611. }
  612. stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
  613. if err != nil {
  614. return err
  615. }
  616. env := engine.Env{}
  617. if err := env.Decode(stream); err != nil {
  618. return err
  619. }
  620. config := env.GetSubEnv("Config")
  621. tty = config.GetBool("Tty")
  622. if !tty {
  623. sigc := cli.forwardAllSignals(cmd.Arg(0))
  624. defer signal.StopCatch(sigc)
  625. }
  626. var in io.ReadCloser
  627. v := url.Values{}
  628. v.Set("stream", "1")
  629. if *openStdin && config.GetBool("OpenStdin") {
  630. v.Set("stdin", "1")
  631. in = cli.in
  632. }
  633. v.Set("stdout", "1")
  634. v.Set("stderr", "1")
  635. cErr = promise.Go(func() error {
  636. return cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, hijacked, nil)
  637. })
  638. } else {
  639. close(hijacked)
  640. }
  641. // Acknowledge the hijack before starting
  642. select {
  643. case closer := <-hijacked:
  644. // Make sure that the hijack gets closed when returning (results
  645. // in closing the hijack chan and freeing server's goroutines)
  646. if closer != nil {
  647. defer closer.Close()
  648. }
  649. case err := <-cErr:
  650. if err != nil {
  651. return err
  652. }
  653. }
  654. var encounteredError error
  655. for _, name := range cmd.Args() {
  656. _, _, err := readBody(cli.call("POST", "/containers/"+name+"/start", nil, false))
  657. if err != nil {
  658. if !*attach && !*openStdin {
  659. fmt.Fprintf(cli.err, "%s\n", err)
  660. }
  661. encounteredError = fmt.Errorf("Error: failed to start one or more containers")
  662. } else {
  663. if !*attach && !*openStdin {
  664. fmt.Fprintf(cli.out, "%s\n", name)
  665. }
  666. }
  667. }
  668. if encounteredError != nil {
  669. if *openStdin || *attach {
  670. cli.in.Close()
  671. }
  672. return encounteredError
  673. }
  674. if *openStdin || *attach {
  675. if tty && cli.isTerminalOut {
  676. if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
  677. log.Errorf("Error monitoring TTY size: %s", err)
  678. }
  679. }
  680. if attchErr := <-cErr; attchErr != nil {
  681. return attchErr
  682. }
  683. _, status, err := getExitCode(cli, cmd.Arg(0))
  684. if err != nil {
  685. return err
  686. }
  687. if status != 0 {
  688. return &utils.StatusError{StatusCode: status}
  689. }
  690. }
  691. return nil
  692. }
  693. func (cli *DockerCli) CmdUnpause(args ...string) error {
  694. cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true)
  695. cmd.Require(flag.Exact, 1)
  696. utils.ParseFlags(cmd, args, false)
  697. var encounteredError error
  698. for _, name := range cmd.Args() {
  699. if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/unpause", name), nil, false)); err != nil {
  700. fmt.Fprintf(cli.err, "%s\n", err)
  701. encounteredError = fmt.Errorf("Error: failed to unpause container named %s", name)
  702. } else {
  703. fmt.Fprintf(cli.out, "%s\n", name)
  704. }
  705. }
  706. return encounteredError
  707. }
  708. func (cli *DockerCli) CmdPause(args ...string) error {
  709. cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true)
  710. cmd.Require(flag.Exact, 1)
  711. utils.ParseFlags(cmd, args, false)
  712. var encounteredError error
  713. for _, name := range cmd.Args() {
  714. if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/pause", name), nil, false)); err != nil {
  715. fmt.Fprintf(cli.err, "%s\n", err)
  716. encounteredError = fmt.Errorf("Error: failed to pause container named %s", name)
  717. } else {
  718. fmt.Fprintf(cli.out, "%s\n", name)
  719. }
  720. }
  721. return encounteredError
  722. }
  723. func (cli *DockerCli) CmdRename(args ...string) error {
  724. cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
  725. if err := cmd.Parse(args); err != nil {
  726. return nil
  727. }
  728. if cmd.NArg() != 2 {
  729. cmd.Usage()
  730. return nil
  731. }
  732. old_name := cmd.Arg(0)
  733. new_name := cmd.Arg(1)
  734. if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/rename?name=%s", old_name, new_name), nil, false)); err != nil {
  735. fmt.Fprintf(cli.err, "%s\n", err)
  736. return fmt.Errorf("Error: failed to rename container named %s", old_name)
  737. }
  738. return nil
  739. }
  740. func (cli *DockerCli) CmdInspect(args ...string) error {
  741. cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
  742. tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
  743. cmd.Require(flag.Min, 1)
  744. utils.ParseFlags(cmd, args, true)
  745. var tmpl *template.Template
  746. if *tmplStr != "" {
  747. var err error
  748. if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil {
  749. fmt.Fprintf(cli.err, "Template parsing error: %v\n", err)
  750. return &utils.StatusError{StatusCode: 64,
  751. Status: "Template parsing error: " + err.Error()}
  752. }
  753. }
  754. indented := new(bytes.Buffer)
  755. indented.WriteByte('[')
  756. status := 0
  757. for _, name := range cmd.Args() {
  758. obj, _, err := readBody(cli.call("GET", "/containers/"+name+"/json", nil, false))
  759. if err != nil {
  760. obj, _, err = readBody(cli.call("GET", "/images/"+name+"/json", nil, false))
  761. if err != nil {
  762. if strings.Contains(err.Error(), "No such") {
  763. fmt.Fprintf(cli.err, "Error: No such image or container: %s\n", name)
  764. } else {
  765. fmt.Fprintf(cli.err, "%s", err)
  766. }
  767. status = 1
  768. continue
  769. }
  770. }
  771. if tmpl == nil {
  772. if err = json.Indent(indented, obj, "", " "); err != nil {
  773. fmt.Fprintf(cli.err, "%s\n", err)
  774. status = 1
  775. continue
  776. }
  777. } else {
  778. // Has template, will render
  779. var value interface{}
  780. if err := json.Unmarshal(obj, &value); err != nil {
  781. fmt.Fprintf(cli.err, "%s\n", err)
  782. status = 1
  783. continue
  784. }
  785. if err := tmpl.Execute(cli.out, value); err != nil {
  786. return err
  787. }
  788. cli.out.Write([]byte{'\n'})
  789. }
  790. indented.WriteString(",")
  791. }
  792. if indented.Len() > 1 {
  793. // Remove trailing ','
  794. indented.Truncate(indented.Len() - 1)
  795. }
  796. indented.WriteString("]\n")
  797. if tmpl == nil {
  798. if _, err := io.Copy(cli.out, indented); err != nil {
  799. return err
  800. }
  801. }
  802. if status != 0 {
  803. return &utils.StatusError{StatusCode: status}
  804. }
  805. return nil
  806. }
  807. func (cli *DockerCli) CmdTop(args ...string) error {
  808. cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
  809. cmd.Require(flag.Min, 1)
  810. utils.ParseFlags(cmd, args, true)
  811. val := url.Values{}
  812. if cmd.NArg() > 1 {
  813. val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
  814. }
  815. stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, false)
  816. if err != nil {
  817. return err
  818. }
  819. var procs engine.Env
  820. if err := procs.Decode(stream); err != nil {
  821. return err
  822. }
  823. w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  824. fmt.Fprintln(w, strings.Join(procs.GetList("Titles"), "\t"))
  825. processes := [][]string{}
  826. if err := procs.GetJson("Processes", &processes); err != nil {
  827. return err
  828. }
  829. for _, proc := range processes {
  830. fmt.Fprintln(w, strings.Join(proc, "\t"))
  831. }
  832. w.Flush()
  833. return nil
  834. }
  835. func (cli *DockerCli) CmdPort(args ...string) error {
  836. cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT", true)
  837. cmd.Require(flag.Min, 1)
  838. utils.ParseFlags(cmd, args, true)
  839. stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
  840. if err != nil {
  841. return err
  842. }
  843. env := engine.Env{}
  844. if err := env.Decode(stream); err != nil {
  845. return err
  846. }
  847. ports := nat.PortMap{}
  848. if err := env.GetSubEnv("NetworkSettings").GetJson("Ports", &ports); err != nil {
  849. return err
  850. }
  851. if cmd.NArg() == 2 {
  852. var (
  853. port = cmd.Arg(1)
  854. proto = "tcp"
  855. parts = strings.SplitN(port, "/", 2)
  856. )
  857. if len(parts) == 2 && len(parts[1]) != 0 {
  858. port = parts[0]
  859. proto = parts[1]
  860. }
  861. natPort := port + "/" + proto
  862. if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
  863. for _, frontend := range frontends {
  864. fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
  865. }
  866. return nil
  867. }
  868. return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
  869. }
  870. for from, frontends := range ports {
  871. for _, frontend := range frontends {
  872. fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
  873. }
  874. }
  875. return nil
  876. }
  877. // 'docker rmi IMAGE' removes all images with the name IMAGE
  878. func (cli *DockerCli) CmdRmi(args ...string) error {
  879. var (
  880. cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
  881. force = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
  882. noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
  883. )
  884. cmd.Require(flag.Min, 1)
  885. utils.ParseFlags(cmd, args, true)
  886. v := url.Values{}
  887. if *force {
  888. v.Set("force", "1")
  889. }
  890. if *noprune {
  891. v.Set("noprune", "1")
  892. }
  893. var encounteredError error
  894. for _, name := range cmd.Args() {
  895. body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, false))
  896. if err != nil {
  897. fmt.Fprintf(cli.err, "%s\n", err)
  898. encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  899. } else {
  900. outs := engine.NewTable("Created", 0)
  901. if _, err := outs.ReadListFrom(body); err != nil {
  902. fmt.Fprintf(cli.err, "%s\n", err)
  903. encounteredError = fmt.Errorf("Error: failed to remove one or more images")
  904. continue
  905. }
  906. for _, out := range outs.Data {
  907. if out.Get("Deleted") != "" {
  908. fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted"))
  909. } else {
  910. fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged"))
  911. }
  912. }
  913. }
  914. }
  915. return encounteredError
  916. }
  917. func (cli *DockerCli) CmdHistory(args ...string) error {
  918. cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
  919. quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  920. noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  921. cmd.Require(flag.Exact, 1)
  922. utils.ParseFlags(cmd, args, true)
  923. body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
  924. if err != nil {
  925. return err
  926. }
  927. outs := engine.NewTable("Created", 0)
  928. if _, err := outs.ReadListFrom(body); err != nil {
  929. return err
  930. }
  931. w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  932. if !*quiet {
  933. fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE")
  934. }
  935. for _, out := range outs.Data {
  936. outID := out.Get("Id")
  937. if !*quiet {
  938. if *noTrunc {
  939. fmt.Fprintf(w, "%s\t", outID)
  940. } else {
  941. fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
  942. }
  943. fmt.Fprintf(w, "%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
  944. if *noTrunc {
  945. fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
  946. } else {
  947. fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
  948. }
  949. fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("Size"))))
  950. } else {
  951. if *noTrunc {
  952. fmt.Fprintln(w, outID)
  953. } else {
  954. fmt.Fprintln(w, utils.TruncateID(outID))
  955. }
  956. }
  957. }
  958. w.Flush()
  959. return nil
  960. }
  961. func (cli *DockerCli) CmdRm(args ...string) error {
  962. cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
  963. v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
  964. link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
  965. force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
  966. cmd.Require(flag.Min, 1)
  967. utils.ParseFlags(cmd, args, true)
  968. val := url.Values{}
  969. if *v {
  970. val.Set("v", "1")
  971. }
  972. if *link {
  973. val.Set("link", "1")
  974. }
  975. if *force {
  976. val.Set("force", "1")
  977. }
  978. var encounteredError error
  979. for _, name := range cmd.Args() {
  980. _, _, err := readBody(cli.call("DELETE", "/containers/"+name+"?"+val.Encode(), nil, false))
  981. if err != nil {
  982. fmt.Fprintf(cli.err, "%s\n", err)
  983. encounteredError = fmt.Errorf("Error: failed to remove one or more containers")
  984. } else {
  985. fmt.Fprintf(cli.out, "%s\n", name)
  986. }
  987. }
  988. return encounteredError
  989. }
  990. // 'docker kill NAME' kills a running container
  991. func (cli *DockerCli) CmdKill(args ...string) error {
  992. cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
  993. signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
  994. cmd.Require(flag.Min, 1)
  995. utils.ParseFlags(cmd, args, true)
  996. var encounteredError error
  997. for _, name := range cmd.Args() {
  998. if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", name, *signal), nil, false)); err != nil {
  999. fmt.Fprintf(cli.err, "%s\n", err)
  1000. encounteredError = fmt.Errorf("Error: failed to kill one or more containers")
  1001. } else {
  1002. fmt.Fprintf(cli.out, "%s\n", name)
  1003. }
  1004. }
  1005. return encounteredError
  1006. }
  1007. func (cli *DockerCli) CmdImport(args ...string) error {
  1008. cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.", true)
  1009. cmd.Require(flag.Min, 1)
  1010. utils.ParseFlags(cmd, args, true)
  1011. var (
  1012. v = url.Values{}
  1013. src = cmd.Arg(0)
  1014. repository = cmd.Arg(1)
  1015. )
  1016. v.Set("fromSrc", src)
  1017. v.Set("repo", repository)
  1018. if cmd.NArg() == 3 {
  1019. fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
  1020. v.Set("tag", cmd.Arg(2))
  1021. }
  1022. if repository != "" {
  1023. //Check if the given image name can be resolved
  1024. repo, _ := parsers.ParseRepositoryTag(repository)
  1025. if err := registry.ValidateRepositoryName(repo); err != nil {
  1026. return err
  1027. }
  1028. }
  1029. var in io.Reader
  1030. if src == "-" {
  1031. in = cli.in
  1032. }
  1033. return cli.stream("POST", "/images/create?"+v.Encode(), in, cli.out, nil)
  1034. }
  1035. func (cli *DockerCli) CmdPush(args ...string) error {
  1036. cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
  1037. cmd.Require(flag.Exact, 1)
  1038. utils.ParseFlags(cmd, args, true)
  1039. name := cmd.Arg(0)
  1040. cli.LoadConfigFile()
  1041. remote, tag := parsers.ParseRepositoryTag(name)
  1042. // Resolve the Repository name from fqn to RepositoryInfo
  1043. repoInfo, err := registry.ParseRepositoryInfo(remote)
  1044. if err != nil {
  1045. return err
  1046. }
  1047. // Resolve the Auth config relevant for this server
  1048. authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1049. // If we're not using a custom registry, we know the restrictions
  1050. // applied to repository names and can warn the user in advance.
  1051. // Custom repositories can have different rules, and we must also
  1052. // allow pushing by image ID.
  1053. if repoInfo.Official {
  1054. username := authConfig.Username
  1055. if username == "" {
  1056. username = "<user>"
  1057. }
  1058. return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
  1059. }
  1060. v := url.Values{}
  1061. v.Set("tag", tag)
  1062. push := func(authConfig registry.AuthConfig) error {
  1063. buf, err := json.Marshal(authConfig)
  1064. if err != nil {
  1065. return err
  1066. }
  1067. registryAuthHeader := []string{
  1068. base64.URLEncoding.EncodeToString(buf),
  1069. }
  1070. return cli.stream("POST", "/images/"+remote+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
  1071. "X-Registry-Auth": registryAuthHeader,
  1072. })
  1073. }
  1074. if err := push(authConfig); err != nil {
  1075. if strings.Contains(err.Error(), "Status 401") {
  1076. fmt.Fprintln(cli.out, "\nPlease login prior to push:")
  1077. if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1078. return err
  1079. }
  1080. authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1081. return push(authConfig)
  1082. }
  1083. return err
  1084. }
  1085. return nil
  1086. }
  1087. func (cli *DockerCli) CmdPull(args ...string) error {
  1088. cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true)
  1089. allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
  1090. cmd.Require(flag.Exact, 1)
  1091. utils.ParseFlags(cmd, args, true)
  1092. var (
  1093. v = url.Values{}
  1094. remote = cmd.Arg(0)
  1095. newRemote = remote
  1096. )
  1097. taglessRemote, tag := parsers.ParseRepositoryTag(remote)
  1098. if tag == "" && !*allTags {
  1099. newRemote = taglessRemote + ":" + graph.DEFAULTTAG
  1100. }
  1101. if tag != "" && *allTags {
  1102. return fmt.Errorf("tag can't be used with --all-tags/-a")
  1103. }
  1104. v.Set("fromImage", newRemote)
  1105. // Resolve the Repository name from fqn to RepositoryInfo
  1106. repoInfo, err := registry.ParseRepositoryInfo(taglessRemote)
  1107. if err != nil {
  1108. return err
  1109. }
  1110. cli.LoadConfigFile()
  1111. // Resolve the Auth config relevant for this server
  1112. authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1113. pull := func(authConfig registry.AuthConfig) error {
  1114. buf, err := json.Marshal(authConfig)
  1115. if err != nil {
  1116. return err
  1117. }
  1118. registryAuthHeader := []string{
  1119. base64.URLEncoding.EncodeToString(buf),
  1120. }
  1121. return cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out, map[string][]string{
  1122. "X-Registry-Auth": registryAuthHeader,
  1123. })
  1124. }
  1125. if err := pull(authConfig); err != nil {
  1126. if strings.Contains(err.Error(), "Status 401") {
  1127. fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
  1128. if err := cli.CmdLogin(repoInfo.Index.GetAuthConfigKey()); err != nil {
  1129. return err
  1130. }
  1131. authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1132. return pull(authConfig)
  1133. }
  1134. return err
  1135. }
  1136. return nil
  1137. }
  1138. func (cli *DockerCli) CmdImages(args ...string) error {
  1139. cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
  1140. quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
  1141. all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)")
  1142. noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1143. // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1144. flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
  1145. flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
  1146. flFilter := opts.NewListOpts(nil)
  1147. cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
  1148. cmd.Require(flag.Max, 1)
  1149. utils.ParseFlags(cmd, args, true)
  1150. // Consolidate all filter flags, and sanity check them early.
  1151. // They'll get process in the daemon/server.
  1152. imageFilterArgs := filters.Args{}
  1153. for _, f := range flFilter.GetAll() {
  1154. var err error
  1155. imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
  1156. if err != nil {
  1157. return err
  1158. }
  1159. }
  1160. matchName := cmd.Arg(0)
  1161. // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1162. if *flViz || *flTree {
  1163. v := url.Values{
  1164. "all": []string{"1"},
  1165. }
  1166. if len(imageFilterArgs) > 0 {
  1167. filterJson, err := filters.ToParam(imageFilterArgs)
  1168. if err != nil {
  1169. return err
  1170. }
  1171. v.Set("filters", filterJson)
  1172. }
  1173. body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1174. if err != nil {
  1175. return err
  1176. }
  1177. outs := engine.NewTable("Created", 0)
  1178. if _, err := outs.ReadListFrom(body); err != nil {
  1179. return err
  1180. }
  1181. var (
  1182. printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)
  1183. startImage *engine.Env
  1184. roots = engine.NewTable("Created", outs.Len())
  1185. byParent = make(map[string]*engine.Table)
  1186. )
  1187. for _, image := range outs.Data {
  1188. if image.Get("ParentId") == "" {
  1189. roots.Add(image)
  1190. } else {
  1191. if children, exists := byParent[image.Get("ParentId")]; exists {
  1192. children.Add(image)
  1193. } else {
  1194. byParent[image.Get("ParentId")] = engine.NewTable("Created", 1)
  1195. byParent[image.Get("ParentId")].Add(image)
  1196. }
  1197. }
  1198. if matchName != "" {
  1199. if matchName == image.Get("Id") || matchName == utils.TruncateID(image.Get("Id")) {
  1200. startImage = image
  1201. }
  1202. for _, repotag := range image.GetList("RepoTags") {
  1203. if repotag == matchName {
  1204. startImage = image
  1205. }
  1206. }
  1207. }
  1208. }
  1209. if *flViz {
  1210. fmt.Fprintf(cli.out, "digraph docker {\n")
  1211. printNode = (*DockerCli).printVizNode
  1212. } else {
  1213. printNode = (*DockerCli).printTreeNode
  1214. }
  1215. if startImage != nil {
  1216. root := engine.NewTable("Created", 1)
  1217. root.Add(startImage)
  1218. cli.WalkTree(*noTrunc, root, byParent, "", printNode)
  1219. } else if matchName == "" {
  1220. cli.WalkTree(*noTrunc, roots, byParent, "", printNode)
  1221. }
  1222. if *flViz {
  1223. fmt.Fprintf(cli.out, " base [style=invisible]\n}\n")
  1224. }
  1225. } else {
  1226. v := url.Values{}
  1227. if len(imageFilterArgs) > 0 {
  1228. filterJson, err := filters.ToParam(imageFilterArgs)
  1229. if err != nil {
  1230. return err
  1231. }
  1232. v.Set("filters", filterJson)
  1233. }
  1234. if cmd.NArg() == 1 {
  1235. // FIXME rename this parameter, to not be confused with the filters flag
  1236. v.Set("filter", matchName)
  1237. }
  1238. if *all {
  1239. v.Set("all", "1")
  1240. }
  1241. body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
  1242. if err != nil {
  1243. return err
  1244. }
  1245. outs := engine.NewTable("Created", 0)
  1246. if _, err := outs.ReadListFrom(body); err != nil {
  1247. return err
  1248. }
  1249. w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1250. if !*quiet {
  1251. fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE")
  1252. }
  1253. for _, out := range outs.Data {
  1254. for _, repotag := range out.GetList("RepoTags") {
  1255. repo, tag := parsers.ParseRepositoryTag(repotag)
  1256. outID := out.Get("Id")
  1257. if !*noTrunc {
  1258. outID = utils.TruncateID(outID)
  1259. }
  1260. if !*quiet {
  1261. fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(float64(out.GetInt64("VirtualSize"))))
  1262. } else {
  1263. fmt.Fprintln(w, outID)
  1264. }
  1265. }
  1266. }
  1267. if !*quiet {
  1268. w.Flush()
  1269. }
  1270. }
  1271. return nil
  1272. }
  1273. // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1274. func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) {
  1275. length := images.Len()
  1276. if length > 1 {
  1277. for index, image := range images.Data {
  1278. if index+1 == length {
  1279. printNode(cli, noTrunc, image, prefix+"└─")
  1280. if subimages, exists := byParent[image.Get("Id")]; exists {
  1281. cli.WalkTree(noTrunc, subimages, byParent, prefix+" ", printNode)
  1282. }
  1283. } else {
  1284. printNode(cli, noTrunc, image, prefix+"\u251C─")
  1285. if subimages, exists := byParent[image.Get("Id")]; exists {
  1286. cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode)
  1287. }
  1288. }
  1289. }
  1290. } else {
  1291. for _, image := range images.Data {
  1292. printNode(cli, noTrunc, image, prefix+"└─")
  1293. if subimages, exists := byParent[image.Get("Id")]; exists {
  1294. cli.WalkTree(noTrunc, subimages, byParent, prefix+" ", printNode)
  1295. }
  1296. }
  1297. }
  1298. }
  1299. // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1300. func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) {
  1301. var (
  1302. imageID string
  1303. parentID string
  1304. )
  1305. if noTrunc {
  1306. imageID = image.Get("Id")
  1307. parentID = image.Get("ParentId")
  1308. } else {
  1309. imageID = utils.TruncateID(image.Get("Id"))
  1310. parentID = utils.TruncateID(image.Get("ParentId"))
  1311. }
  1312. if parentID == "" {
  1313. fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID)
  1314. } else {
  1315. fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID)
  1316. }
  1317. if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1318. fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n",
  1319. imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n"))
  1320. }
  1321. }
  1322. // FIXME: --viz and --tree are deprecated. Remove them in a future version.
  1323. func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) {
  1324. var imageID string
  1325. if noTrunc {
  1326. imageID = image.Get("Id")
  1327. } else {
  1328. imageID = utils.TruncateID(image.Get("Id"))
  1329. }
  1330. fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(float64(image.GetInt64("VirtualSize"))))
  1331. if image.GetList("RepoTags")[0] != "<none>:<none>" {
  1332. fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
  1333. } else {
  1334. fmt.Fprint(cli.out, "\n")
  1335. }
  1336. }
  1337. func (cli *DockerCli) CmdPs(args ...string) error {
  1338. var (
  1339. err error
  1340. psFilterArgs = filters.Args{}
  1341. v = url.Values{}
  1342. cmd = cli.Subcmd("ps", "", "List containers", true)
  1343. quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
  1344. size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
  1345. all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
  1346. noTrunc = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1347. nLatest = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
  1348. since = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
  1349. before = cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
  1350. last = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
  1351. flFilter = opts.NewListOpts(nil)
  1352. )
  1353. cmd.Require(flag.Exact, 0)
  1354. cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
  1355. utils.ParseFlags(cmd, args, true)
  1356. if *last == -1 && *nLatest {
  1357. *last = 1
  1358. }
  1359. if *all {
  1360. v.Set("all", "1")
  1361. }
  1362. if *last != -1 {
  1363. v.Set("limit", strconv.Itoa(*last))
  1364. }
  1365. if *since != "" {
  1366. v.Set("since", *since)
  1367. }
  1368. if *before != "" {
  1369. v.Set("before", *before)
  1370. }
  1371. if *size {
  1372. v.Set("size", "1")
  1373. }
  1374. // Consolidate all filter flags, and sanity check them.
  1375. // They'll get processed in the daemon/server.
  1376. for _, f := range flFilter.GetAll() {
  1377. if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil {
  1378. return err
  1379. }
  1380. }
  1381. if len(psFilterArgs) > 0 {
  1382. filterJson, err := filters.ToParam(psFilterArgs)
  1383. if err != nil {
  1384. return err
  1385. }
  1386. v.Set("filters", filterJson)
  1387. }
  1388. body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
  1389. if err != nil {
  1390. return err
  1391. }
  1392. outs := engine.NewTable("Created", 0)
  1393. if _, err := outs.ReadListFrom(body); err != nil {
  1394. return err
  1395. }
  1396. w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
  1397. if !*quiet {
  1398. fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
  1399. if *size {
  1400. fmt.Fprintln(w, "\tSIZE")
  1401. } else {
  1402. fmt.Fprint(w, "\n")
  1403. }
  1404. }
  1405. stripNamePrefix := func(ss []string) []string {
  1406. for i, s := range ss {
  1407. ss[i] = s[1:]
  1408. }
  1409. return ss
  1410. }
  1411. for _, out := range outs.Data {
  1412. outID := out.Get("Id")
  1413. if !*noTrunc {
  1414. outID = utils.TruncateID(outID)
  1415. }
  1416. if *quiet {
  1417. fmt.Fprintln(w, outID)
  1418. continue
  1419. }
  1420. var (
  1421. outNames = stripNamePrefix(out.GetList("Names"))
  1422. outCommand = strconv.Quote(out.Get("Command"))
  1423. ports = engine.NewTable("", 0)
  1424. )
  1425. if !*noTrunc {
  1426. outCommand = utils.Trunc(outCommand, 20)
  1427. // only display the default name for the container with notrunc is passed
  1428. for _, name := range outNames {
  1429. if len(strings.Split(name, "/")) == 1 {
  1430. outNames = []string{name}
  1431. break
  1432. }
  1433. }
  1434. }
  1435. ports.ReadListFrom([]byte(out.Get("Ports")))
  1436. image := out.Get("Image")
  1437. if image == "" {
  1438. image = "<no image>"
  1439. }
  1440. fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, image, outCommand,
  1441. units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))),
  1442. out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
  1443. if *size {
  1444. if out.GetInt("SizeRootFs") > 0 {
  1445. fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(out.GetInt64("SizeRw"))), units.HumanSize(float64(out.GetInt64("SizeRootFs"))))
  1446. } else {
  1447. fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("SizeRw"))))
  1448. }
  1449. continue
  1450. }
  1451. fmt.Fprint(w, "\n")
  1452. }
  1453. if !*quiet {
  1454. w.Flush()
  1455. }
  1456. return nil
  1457. }
  1458. func (cli *DockerCli) CmdCommit(args ...string) error {
  1459. cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
  1460. flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
  1461. flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
  1462. flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
  1463. // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
  1464. flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
  1465. cmd.Require(flag.Max, 2)
  1466. cmd.Require(flag.Min, 1)
  1467. utils.ParseFlags(cmd, args, true)
  1468. var (
  1469. name = cmd.Arg(0)
  1470. repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  1471. )
  1472. //Check if the given image name can be resolved
  1473. if repository != "" {
  1474. if err := registry.ValidateRepositoryName(repository); err != nil {
  1475. return err
  1476. }
  1477. }
  1478. v := url.Values{}
  1479. v.Set("container", name)
  1480. v.Set("repo", repository)
  1481. v.Set("tag", tag)
  1482. v.Set("comment", *flComment)
  1483. v.Set("author", *flAuthor)
  1484. if *flPause != true {
  1485. v.Set("pause", "0")
  1486. }
  1487. var (
  1488. config *runconfig.Config
  1489. env engine.Env
  1490. )
  1491. if *flConfig != "" {
  1492. config = &runconfig.Config{}
  1493. if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
  1494. return err
  1495. }
  1496. }
  1497. stream, _, err := cli.call("POST", "/commit?"+v.Encode(), config, false)
  1498. if err != nil {
  1499. return err
  1500. }
  1501. if err := env.Decode(stream); err != nil {
  1502. return err
  1503. }
  1504. fmt.Fprintf(cli.out, "%s\n", env.Get("Id"))
  1505. return nil
  1506. }
  1507. func (cli *DockerCli) CmdEvents(args ...string) error {
  1508. cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
  1509. since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
  1510. until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
  1511. flFilter := opts.NewListOpts(nil)
  1512. cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
  1513. cmd.Require(flag.Exact, 0)
  1514. utils.ParseFlags(cmd, args, true)
  1515. var (
  1516. v = url.Values{}
  1517. loc = time.FixedZone(time.Now().Zone())
  1518. eventFilterArgs = filters.Args{}
  1519. )
  1520. // Consolidate all filter flags, and sanity check them early.
  1521. // They'll get process in the daemon/server.
  1522. for _, f := range flFilter.GetAll() {
  1523. var err error
  1524. eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
  1525. if err != nil {
  1526. return err
  1527. }
  1528. }
  1529. var setTime = func(key, value string) {
  1530. format := timeutils.RFC3339NanoFixed
  1531. if len(value) < len(format) {
  1532. format = format[:len(value)]
  1533. }
  1534. if t, err := time.ParseInLocation(format, value, loc); err == nil {
  1535. v.Set(key, strconv.FormatInt(t.Unix(), 10))
  1536. } else {
  1537. v.Set(key, value)
  1538. }
  1539. }
  1540. if *since != "" {
  1541. setTime("since", *since)
  1542. }
  1543. if *until != "" {
  1544. setTime("until", *until)
  1545. }
  1546. if len(eventFilterArgs) > 0 {
  1547. filterJson, err := filters.ToParam(eventFilterArgs)
  1548. if err != nil {
  1549. return err
  1550. }
  1551. v.Set("filters", filterJson)
  1552. }
  1553. if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out, nil); err != nil {
  1554. return err
  1555. }
  1556. return nil
  1557. }
  1558. func (cli *DockerCli) CmdExport(args ...string) error {
  1559. cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
  1560. cmd.Require(flag.Exact, 1)
  1561. utils.ParseFlags(cmd, args, true)
  1562. if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
  1563. return err
  1564. }
  1565. return nil
  1566. }
  1567. func (cli *DockerCli) CmdDiff(args ...string) error {
  1568. cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
  1569. cmd.Require(flag.Exact, 1)
  1570. utils.ParseFlags(cmd, args, true)
  1571. body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
  1572. if err != nil {
  1573. return err
  1574. }
  1575. outs := engine.NewTable("", 0)
  1576. if _, err := outs.ReadListFrom(body); err != nil {
  1577. return err
  1578. }
  1579. for _, change := range outs.Data {
  1580. var kind string
  1581. switch change.GetInt("Kind") {
  1582. case archive.ChangeModify:
  1583. kind = "C"
  1584. case archive.ChangeAdd:
  1585. kind = "A"
  1586. case archive.ChangeDelete:
  1587. kind = "D"
  1588. }
  1589. fmt.Fprintf(cli.out, "%s %s\n", kind, change.Get("Path"))
  1590. }
  1591. return nil
  1592. }
  1593. func (cli *DockerCli) CmdLogs(args ...string) error {
  1594. var (
  1595. cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
  1596. follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
  1597. times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
  1598. tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
  1599. )
  1600. cmd.Require(flag.Exact, 1)
  1601. utils.ParseFlags(cmd, args, true)
  1602. name := cmd.Arg(0)
  1603. stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1604. if err != nil {
  1605. return err
  1606. }
  1607. env := engine.Env{}
  1608. if err := env.Decode(stream); err != nil {
  1609. return err
  1610. }
  1611. v := url.Values{}
  1612. v.Set("stdout", "1")
  1613. v.Set("stderr", "1")
  1614. if *times {
  1615. v.Set("timestamps", "1")
  1616. }
  1617. if *follow {
  1618. v.Set("follow", "1")
  1619. }
  1620. v.Set("tail", *tail)
  1621. return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
  1622. }
  1623. func (cli *DockerCli) CmdAttach(args ...string) error {
  1624. var (
  1625. cmd = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
  1626. noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
  1627. proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
  1628. )
  1629. cmd.Require(flag.Exact, 1)
  1630. utils.ParseFlags(cmd, args, true)
  1631. name := cmd.Arg(0)
  1632. stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
  1633. if err != nil {
  1634. return err
  1635. }
  1636. env := engine.Env{}
  1637. if err := env.Decode(stream); err != nil {
  1638. return err
  1639. }
  1640. if !env.GetSubEnv("State").GetBool("Running") {
  1641. return fmt.Errorf("You cannot attach to a stopped container, start it first")
  1642. }
  1643. var (
  1644. config = env.GetSubEnv("Config")
  1645. tty = config.GetBool("Tty")
  1646. )
  1647. if err := cli.CheckTtyInput(!*noStdin, tty); err != nil {
  1648. return err
  1649. }
  1650. if tty && cli.isTerminalOut {
  1651. if err := cli.monitorTtySize(cmd.Arg(0), false); err != nil {
  1652. log.Debugf("Error monitoring TTY size: %s", err)
  1653. }
  1654. }
  1655. var in io.ReadCloser
  1656. v := url.Values{}
  1657. v.Set("stream", "1")
  1658. if !*noStdin && config.GetBool("OpenStdin") {
  1659. v.Set("stdin", "1")
  1660. in = cli.in
  1661. }
  1662. v.Set("stdout", "1")
  1663. v.Set("stderr", "1")
  1664. if *proxy && !tty {
  1665. sigc := cli.forwardAllSignals(cmd.Arg(0))
  1666. defer signal.StopCatch(sigc)
  1667. }
  1668. if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), tty, in, cli.out, cli.err, nil, nil); err != nil {
  1669. return err
  1670. }
  1671. _, status, err := getExitCode(cli, cmd.Arg(0))
  1672. if err != nil {
  1673. return err
  1674. }
  1675. if status != 0 {
  1676. return &utils.StatusError{StatusCode: status}
  1677. }
  1678. return nil
  1679. }
  1680. func (cli *DockerCli) CmdSearch(args ...string) error {
  1681. cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
  1682. noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
  1683. trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
  1684. automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
  1685. stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
  1686. cmd.Require(flag.Exact, 1)
  1687. utils.ParseFlags(cmd, args, true)
  1688. v := url.Values{}
  1689. v.Set("term", cmd.Arg(0))
  1690. body, _, err := readBody(cli.call("GET", "/images/search?"+v.Encode(), nil, true))
  1691. if err != nil {
  1692. return err
  1693. }
  1694. outs := engine.NewTable("star_count", 0)
  1695. if _, err := outs.ReadListFrom(body); err != nil {
  1696. return err
  1697. }
  1698. w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
  1699. fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
  1700. for _, out := range outs.Data {
  1701. if ((*automated || *trusted) && (!out.GetBool("is_trusted") && !out.GetBool("is_automated"))) || (*stars > out.GetInt("star_count")) {
  1702. continue
  1703. }
  1704. desc := strings.Replace(out.Get("description"), "\n", " ", -1)
  1705. desc = strings.Replace(desc, "\r", " ", -1)
  1706. if !*noTrunc && len(desc) > 45 {
  1707. desc = utils.Trunc(desc, 42) + "..."
  1708. }
  1709. fmt.Fprintf(w, "%s\t%s\t%d\t", out.Get("name"), desc, out.GetInt("star_count"))
  1710. if out.GetBool("is_official") {
  1711. fmt.Fprint(w, "[OK]")
  1712. }
  1713. fmt.Fprint(w, "\t")
  1714. if out.GetBool("is_automated") || out.GetBool("is_trusted") {
  1715. fmt.Fprint(w, "[OK]")
  1716. }
  1717. fmt.Fprint(w, "\n")
  1718. }
  1719. w.Flush()
  1720. return nil
  1721. }
  1722. // Ports type - Used to parse multiple -p flags
  1723. type ports []int
  1724. func (cli *DockerCli) CmdTag(args ...string) error {
  1725. cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
  1726. force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
  1727. cmd.Require(flag.Exact, 2)
  1728. utils.ParseFlags(cmd, args, true)
  1729. var (
  1730. repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
  1731. v = url.Values{}
  1732. )
  1733. //Check if the given image name can be resolved
  1734. if err := registry.ValidateRepositoryName(repository); err != nil {
  1735. return err
  1736. }
  1737. v.Set("repo", repository)
  1738. v.Set("tag", tag)
  1739. if *force {
  1740. v.Set("force", "1")
  1741. }
  1742. if _, _, err := readBody(cli.call("POST", "/images/"+cmd.Arg(0)+"/tag?"+v.Encode(), nil, false)); err != nil {
  1743. return err
  1744. }
  1745. return nil
  1746. }
  1747. func (cli *DockerCli) pullImage(image string) error {
  1748. return cli.pullImageCustomOut(image, cli.out)
  1749. }
  1750. func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
  1751. v := url.Values{}
  1752. repos, tag := parsers.ParseRepositoryTag(image)
  1753. // pull only the image tagged 'latest' if no tag was specified
  1754. if tag == "" {
  1755. tag = graph.DEFAULTTAG
  1756. }
  1757. v.Set("fromImage", repos)
  1758. v.Set("tag", tag)
  1759. // Resolve the Repository name from fqn to RepositoryInfo
  1760. repoInfo, err := registry.ParseRepositoryInfo(repos)
  1761. if err != nil {
  1762. return err
  1763. }
  1764. // Load the auth config file, to be able to pull the image
  1765. cli.LoadConfigFile()
  1766. // Resolve the Auth config relevant for this server
  1767. authConfig := cli.configFile.ResolveAuthConfig(repoInfo.Index)
  1768. buf, err := json.Marshal(authConfig)
  1769. if err != nil {
  1770. return err
  1771. }
  1772. registryAuthHeader := []string{
  1773. base64.URLEncoding.EncodeToString(buf),
  1774. }
  1775. if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, out, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
  1776. return err
  1777. }
  1778. return nil
  1779. }
  1780. type cidFile struct {
  1781. path string
  1782. file *os.File
  1783. written bool
  1784. }
  1785. func newCIDFile(path string) (*cidFile, error) {
  1786. if _, err := os.Stat(path); err == nil {
  1787. return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
  1788. }
  1789. f, err := os.Create(path)
  1790. if err != nil {
  1791. return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
  1792. }
  1793. return &cidFile{path: path, file: f}, nil
  1794. }
  1795. func (cid *cidFile) Close() error {
  1796. cid.file.Close()
  1797. if !cid.written {
  1798. if err := os.Remove(cid.path); err != nil {
  1799. return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
  1800. }
  1801. }
  1802. return nil
  1803. }
  1804. func (cid *cidFile) Write(id string) error {
  1805. if _, err := cid.file.Write([]byte(id)); err != nil {
  1806. return fmt.Errorf("Failed to write the container ID to the file: %s", err)
  1807. }
  1808. cid.written = true
  1809. return nil
  1810. }
  1811. func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (engine.Env, error) {
  1812. containerValues := url.Values{}
  1813. if name != "" {
  1814. containerValues.Set("name", name)
  1815. }
  1816. mergedConfig := runconfig.MergeConfigs(config, hostConfig)
  1817. var containerIDFile *cidFile
  1818. if cidfile != "" {
  1819. var err error
  1820. if containerIDFile, err = newCIDFile(cidfile); err != nil {
  1821. return nil, err
  1822. }
  1823. defer containerIDFile.Close()
  1824. }
  1825. //create the container
  1826. stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
  1827. //if image not found try to pull it
  1828. if statusCode == 404 {
  1829. repo, tag := parsers.ParseRepositoryTag(config.Image)
  1830. if tag == "" {
  1831. tag = graph.DEFAULTTAG
  1832. }
  1833. fmt.Fprintf(cli.err, "Unable to find image '%s:%s' locally\n", repo, tag)
  1834. // we don't want to write to stdout anything apart from container.ID
  1835. if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
  1836. return nil, err
  1837. }
  1838. // Retry
  1839. if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
  1840. return nil, err
  1841. }
  1842. } else if err != nil {
  1843. return nil, err
  1844. }
  1845. var result engine.Env
  1846. if err := result.Decode(stream); err != nil {
  1847. return nil, err
  1848. }
  1849. for _, warning := range result.GetList("Warnings") {
  1850. fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
  1851. }
  1852. if containerIDFile != nil {
  1853. if err = containerIDFile.Write(result.Get("Id")); err != nil {
  1854. return nil, err
  1855. }
  1856. }
  1857. return result, nil
  1858. }
  1859. func (cli *DockerCli) CmdCreate(args ...string) error {
  1860. cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
  1861. // These are flags not stored in Config/HostConfig
  1862. var (
  1863. flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
  1864. )
  1865. config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  1866. if err != nil {
  1867. utils.ReportError(cmd, err.Error(), true)
  1868. }
  1869. if config.Image == "" {
  1870. cmd.Usage()
  1871. return nil
  1872. }
  1873. createResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  1874. if err != nil {
  1875. return err
  1876. }
  1877. fmt.Fprintf(cli.out, "%s\n", createResult.Get("Id"))
  1878. return nil
  1879. }
  1880. func (cli *DockerCli) CmdRun(args ...string) error {
  1881. // FIXME: just use runconfig.Parse already
  1882. cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
  1883. // These are flags not stored in Config/HostConfig
  1884. var (
  1885. flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
  1886. flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run the container in the background and print the new container ID")
  1887. flSigProxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.")
  1888. flName = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
  1889. flAttach *opts.ListOpts
  1890. ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
  1891. ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
  1892. ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d")
  1893. )
  1894. config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
  1895. // just in case the Parse does not exit
  1896. if err != nil {
  1897. utils.ReportError(cmd, err.Error(), true)
  1898. }
  1899. if config.Image == "" {
  1900. cmd.Usage()
  1901. return nil
  1902. }
  1903. if !*flDetach {
  1904. if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
  1905. return err
  1906. }
  1907. } else {
  1908. if fl := cmd.Lookup("attach"); fl != nil {
  1909. flAttach = fl.Value.(*opts.ListOpts)
  1910. if flAttach.Len() != 0 {
  1911. return ErrConflictAttachDetach
  1912. }
  1913. }
  1914. if *flAutoRemove {
  1915. return ErrConflictDetachAutoRemove
  1916. }
  1917. config.AttachStdin = false
  1918. config.AttachStdout = false
  1919. config.AttachStderr = false
  1920. config.StdinOnce = false
  1921. }
  1922. // Disable flSigProxy when in TTY mode
  1923. sigProxy := *flSigProxy
  1924. if config.Tty {
  1925. sigProxy = false
  1926. }
  1927. runResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
  1928. if err != nil {
  1929. return err
  1930. }
  1931. if sigProxy {
  1932. sigc := cli.forwardAllSignals(runResult.Get("Id"))
  1933. defer signal.StopCatch(sigc)
  1934. }
  1935. var (
  1936. waitDisplayId chan struct{}
  1937. errCh chan error
  1938. )
  1939. if !config.AttachStdout && !config.AttachStderr {
  1940. // Make this asynchronous to allow the client to write to stdin before having to read the ID
  1941. waitDisplayId = make(chan struct{})
  1942. go func() {
  1943. defer close(waitDisplayId)
  1944. fmt.Fprintf(cli.out, "%s\n", runResult.Get("Id"))
  1945. }()
  1946. }
  1947. if *flAutoRemove && (hostConfig.RestartPolicy.Name == "always" || hostConfig.RestartPolicy.Name == "on-failure") {
  1948. return ErrConflictRestartPolicyAndAutoRemove
  1949. }
  1950. // We need to instantiate the chan because the select needs it. It can
  1951. // be closed but can't be uninitialized.
  1952. hijacked := make(chan io.Closer)
  1953. // Block the return until the chan gets closed
  1954. defer func() {
  1955. log.Debugf("End of CmdRun(), Waiting for hijack to finish.")
  1956. if _, ok := <-hijacked; ok {
  1957. log.Errorf("Hijack did not finish (chan still open)")
  1958. }
  1959. }()
  1960. if config.AttachStdin || config.AttachStdout || config.AttachStderr {
  1961. var (
  1962. out, stderr io.Writer
  1963. in io.ReadCloser
  1964. v = url.Values{}
  1965. )
  1966. v.Set("stream", "1")
  1967. if config.AttachStdin {
  1968. v.Set("stdin", "1")
  1969. in = cli.in
  1970. }
  1971. if config.AttachStdout {
  1972. v.Set("stdout", "1")
  1973. out = cli.out
  1974. }
  1975. if config.AttachStderr {
  1976. v.Set("stderr", "1")
  1977. if config.Tty {
  1978. stderr = cli.out
  1979. } else {
  1980. stderr = cli.err
  1981. }
  1982. }
  1983. errCh = promise.Go(func() error {
  1984. return cli.hijack("POST", "/containers/"+runResult.Get("Id")+"/attach?"+v.Encode(), config.Tty, in, out, stderr, hijacked, nil)
  1985. })
  1986. } else {
  1987. close(hijacked)
  1988. }
  1989. // Acknowledge the hijack before starting
  1990. select {
  1991. case closer := <-hijacked:
  1992. // Make sure that the hijack gets closed when returning (results
  1993. // in closing the hijack chan and freeing server's goroutines)
  1994. if closer != nil {
  1995. defer closer.Close()
  1996. }
  1997. case err := <-errCh:
  1998. if err != nil {
  1999. log.Debugf("Error hijack: %s", err)
  2000. return err
  2001. }
  2002. }
  2003. //start the container
  2004. if _, _, err = readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/start", nil, false)); err != nil {
  2005. return err
  2006. }
  2007. if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
  2008. if err := cli.monitorTtySize(runResult.Get("Id"), false); err != nil {
  2009. log.Errorf("Error monitoring TTY size: %s", err)
  2010. }
  2011. }
  2012. if errCh != nil {
  2013. if err := <-errCh; err != nil {
  2014. log.Debugf("Error hijack: %s", err)
  2015. return err
  2016. }
  2017. }
  2018. // Detached mode: wait for the id to be displayed and return.
  2019. if !config.AttachStdout && !config.AttachStderr {
  2020. // Detached mode
  2021. <-waitDisplayId
  2022. return nil
  2023. }
  2024. var status int
  2025. // Attached mode
  2026. if *flAutoRemove {
  2027. // Autoremove: wait for the container to finish, retrieve
  2028. // the exit code and remove the container
  2029. if _, _, err := readBody(cli.call("POST", "/containers/"+runResult.Get("Id")+"/wait", nil, false)); err != nil {
  2030. return err
  2031. }
  2032. if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2033. return err
  2034. }
  2035. if _, _, err := readBody(cli.call("DELETE", "/containers/"+runResult.Get("Id")+"?v=1", nil, false)); err != nil {
  2036. return err
  2037. }
  2038. } else {
  2039. // No Autoremove: Simply retrieve the exit code
  2040. if !config.Tty {
  2041. // In non-TTY mode, we can't detach, so we must wait for container exit
  2042. if status, err = waitForExit(cli, runResult.Get("Id")); err != nil {
  2043. return err
  2044. }
  2045. } else {
  2046. // In TTY mode, there is a race: if the process dies too slowly, the state could
  2047. // be updated after the getExitCode call and result in the wrong exit code being reported
  2048. if _, status, err = getExitCode(cli, runResult.Get("Id")); err != nil {
  2049. return err
  2050. }
  2051. }
  2052. }
  2053. if status != 0 {
  2054. return &utils.StatusError{StatusCode: status}
  2055. }
  2056. return nil
  2057. }
  2058. func (cli *DockerCli) CmdCp(args ...string) error {
  2059. cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true)
  2060. cmd.Require(flag.Exact, 2)
  2061. utils.ParseFlags(cmd, args, true)
  2062. var copyData engine.Env
  2063. info := strings.Split(cmd.Arg(0), ":")
  2064. if len(info) != 2 {
  2065. return fmt.Errorf("Error: Path not specified")
  2066. }
  2067. copyData.Set("Resource", info[1])
  2068. copyData.Set("HostPath", cmd.Arg(1))
  2069. stream, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", copyData, false)
  2070. if stream != nil {
  2071. defer stream.Close()
  2072. }
  2073. if statusCode == 404 {
  2074. return fmt.Errorf("No such container: %v", info[0])
  2075. }
  2076. if err != nil {
  2077. return err
  2078. }
  2079. if statusCode == 200 {
  2080. if err := archive.Untar(stream, copyData.Get("HostPath"), &archive.TarOptions{NoLchown: true}); err != nil {
  2081. return err
  2082. }
  2083. }
  2084. return nil
  2085. }
  2086. func (cli *DockerCli) CmdSave(args ...string) error {
  2087. cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
  2088. outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
  2089. cmd.Require(flag.Min, 1)
  2090. utils.ParseFlags(cmd, args, true)
  2091. var (
  2092. output io.Writer = cli.out
  2093. err error
  2094. )
  2095. if *outfile != "" {
  2096. output, err = os.Create(*outfile)
  2097. if err != nil {
  2098. return err
  2099. }
  2100. } else if cli.isTerminalOut {
  2101. return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
  2102. }
  2103. if len(cmd.Args()) == 1 {
  2104. image := cmd.Arg(0)
  2105. if err := cli.stream("GET", "/images/"+image+"/get", nil, output, nil); err != nil {
  2106. return err
  2107. }
  2108. } else {
  2109. v := url.Values{}
  2110. for _, arg := range cmd.Args() {
  2111. v.Add("names", arg)
  2112. }
  2113. if err := cli.stream("GET", "/images/get?"+v.Encode(), nil, output, nil); err != nil {
  2114. return err
  2115. }
  2116. }
  2117. return nil
  2118. }
  2119. func (cli *DockerCli) CmdLoad(args ...string) error {
  2120. cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
  2121. infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
  2122. cmd.Require(flag.Exact, 0)
  2123. utils.ParseFlags(cmd, args, true)
  2124. var (
  2125. input io.Reader = cli.in
  2126. err error
  2127. )
  2128. if *infile != "" {
  2129. input, err = os.Open(*infile)
  2130. if err != nil {
  2131. return err
  2132. }
  2133. }
  2134. if err := cli.stream("POST", "/images/load", input, cli.out, nil); err != nil {
  2135. return err
  2136. }
  2137. return nil
  2138. }
  2139. func (cli *DockerCli) CmdExec(args ...string) error {
  2140. cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
  2141. execConfig, err := runconfig.ParseExec(cmd, args)
  2142. // just in case the ParseExec does not exit
  2143. if execConfig.Container == "" || err != nil {
  2144. return &utils.StatusError{StatusCode: 1}
  2145. }
  2146. stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
  2147. if err != nil {
  2148. return err
  2149. }
  2150. var execResult engine.Env
  2151. if err := execResult.Decode(stream); err != nil {
  2152. return err
  2153. }
  2154. execID := execResult.Get("Id")
  2155. if execID == "" {
  2156. fmt.Fprintf(cli.out, "exec ID empty")
  2157. return nil
  2158. }
  2159. if !execConfig.Detach {
  2160. if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
  2161. return err
  2162. }
  2163. } else {
  2164. if _, _, err := readBody(cli.call("POST", "/exec/"+execID+"/start", execConfig, false)); err != nil {
  2165. return err
  2166. }
  2167. // For now don't print this - wait for when we support exec wait()
  2168. // fmt.Fprintf(cli.out, "%s\n", execID)
  2169. return nil
  2170. }
  2171. // Interactive exec requested.
  2172. var (
  2173. out, stderr io.Writer
  2174. in io.ReadCloser
  2175. hijacked = make(chan io.Closer)
  2176. errCh chan error
  2177. )
  2178. // Block the return until the chan gets closed
  2179. defer func() {
  2180. log.Debugf("End of CmdExec(), Waiting for hijack to finish.")
  2181. if _, ok := <-hijacked; ok {
  2182. log.Errorf("Hijack did not finish (chan still open)")
  2183. }
  2184. }()
  2185. if execConfig.AttachStdin {
  2186. in = cli.in
  2187. }
  2188. if execConfig.AttachStdout {
  2189. out = cli.out
  2190. }
  2191. if execConfig.AttachStderr {
  2192. if execConfig.Tty {
  2193. stderr = cli.out
  2194. } else {
  2195. stderr = cli.err
  2196. }
  2197. }
  2198. errCh = promise.Go(func() error {
  2199. return cli.hijack("POST", "/exec/"+execID+"/start", execConfig.Tty, in, out, stderr, hijacked, execConfig)
  2200. })
  2201. // Acknowledge the hijack before starting
  2202. select {
  2203. case closer := <-hijacked:
  2204. // Make sure that hijack gets closed when returning. (result
  2205. // in closing hijack chan and freeing server's goroutines.
  2206. if closer != nil {
  2207. defer closer.Close()
  2208. }
  2209. case err := <-errCh:
  2210. if err != nil {
  2211. log.Debugf("Error hijack: %s", err)
  2212. return err
  2213. }
  2214. }
  2215. if execConfig.Tty && cli.isTerminalIn {
  2216. if err := cli.monitorTtySize(execID, true); err != nil {
  2217. log.Errorf("Error monitoring TTY size: %s", err)
  2218. }
  2219. }
  2220. if err := <-errCh; err != nil {
  2221. log.Debugf("Error hijack: %s", err)
  2222. return err
  2223. }
  2224. var status int
  2225. if _, status, err = getExecExitCode(cli, execID); err != nil {
  2226. return err
  2227. }
  2228. if status != 0 {
  2229. return &utils.StatusError{StatusCode: status}
  2230. }
  2231. return nil
  2232. }