commands.go 70 KB

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