dispatchers.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. package dockerfile
  2. // This file contains the dispatchers for each command. Note that
  3. // `nullDispatch` is not actually a command, but support for commands we parse
  4. // but do nothing with.
  5. //
  6. // See evaluator.go for a higher level discussion of the whole evaluator
  7. // package.
  8. import (
  9. "fmt"
  10. "io/ioutil"
  11. "os"
  12. "path/filepath"
  13. "regexp"
  14. "runtime"
  15. "sort"
  16. "strings"
  17. "github.com/Sirupsen/logrus"
  18. "github.com/docker/docker/api/types/strslice"
  19. "github.com/docker/docker/builder"
  20. derr "github.com/docker/docker/errors"
  21. flag "github.com/docker/docker/pkg/mflag"
  22. "github.com/docker/docker/pkg/signal"
  23. "github.com/docker/docker/pkg/system"
  24. "github.com/docker/docker/runconfig"
  25. "github.com/docker/go-connections/nat"
  26. )
  27. const (
  28. // NoBaseImageSpecifier is the symbol used by the FROM
  29. // command to specify that no base image is to be used.
  30. NoBaseImageSpecifier string = "scratch"
  31. )
  32. // dispatch with no layer / parsing. This is effectively not a command.
  33. func nullDispatch(b *Builder, args []string, attributes map[string]bool, original string) error {
  34. return nil
  35. }
  36. // ENV foo bar
  37. //
  38. // Sets the environment variable foo to bar, also makes interpolation
  39. // in the dockerfile available from the next statement on via ${foo}.
  40. //
  41. func env(b *Builder, args []string, attributes map[string]bool, original string) error {
  42. if len(args) == 0 {
  43. return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV")
  44. }
  45. if len(args)%2 != 0 {
  46. // should never get here, but just in case
  47. return derr.ErrorCodeTooManyArgs.WithArgs("ENV")
  48. }
  49. if err := b.flags.Parse(); err != nil {
  50. return err
  51. }
  52. // TODO/FIXME/NOT USED
  53. // Just here to show how to use the builder flags stuff within the
  54. // context of a builder command. Will remove once we actually add
  55. // a builder command to something!
  56. /*
  57. flBool1 := b.flags.AddBool("bool1", false)
  58. flStr1 := b.flags.AddString("str1", "HI")
  59. if err := b.flags.Parse(); err != nil {
  60. return err
  61. }
  62. fmt.Printf("Bool1:%v\n", flBool1)
  63. fmt.Printf("Str1:%v\n", flStr1)
  64. */
  65. commitStr := "ENV"
  66. for j := 0; j < len(args); j++ {
  67. // name ==> args[j]
  68. // value ==> args[j+1]
  69. newVar := args[j] + "=" + args[j+1] + ""
  70. commitStr += " " + newVar
  71. gotOne := false
  72. for i, envVar := range b.runConfig.Env {
  73. envParts := strings.SplitN(envVar, "=", 2)
  74. if envParts[0] == args[j] {
  75. b.runConfig.Env[i] = newVar
  76. gotOne = true
  77. break
  78. }
  79. }
  80. if !gotOne {
  81. b.runConfig.Env = append(b.runConfig.Env, newVar)
  82. }
  83. j++
  84. }
  85. return b.commit("", b.runConfig.Cmd, commitStr)
  86. }
  87. // MAINTAINER some text <maybe@an.email.address>
  88. //
  89. // Sets the maintainer metadata.
  90. func maintainer(b *Builder, args []string, attributes map[string]bool, original string) error {
  91. if len(args) != 1 {
  92. return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER")
  93. }
  94. if err := b.flags.Parse(); err != nil {
  95. return err
  96. }
  97. b.maintainer = args[0]
  98. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer))
  99. }
  100. // LABEL some json data describing the image
  101. //
  102. // Sets the Label variable foo to bar,
  103. //
  104. func label(b *Builder, args []string, attributes map[string]bool, original string) error {
  105. if len(args) == 0 {
  106. return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL")
  107. }
  108. if len(args)%2 != 0 {
  109. // should never get here, but just in case
  110. return derr.ErrorCodeTooManyArgs.WithArgs("LABEL")
  111. }
  112. if err := b.flags.Parse(); err != nil {
  113. return err
  114. }
  115. commitStr := "LABEL"
  116. if b.runConfig.Labels == nil {
  117. b.runConfig.Labels = map[string]string{}
  118. }
  119. for j := 0; j < len(args); j++ {
  120. // name ==> args[j]
  121. // value ==> args[j+1]
  122. newVar := args[j] + "=" + args[j+1] + ""
  123. commitStr += " " + newVar
  124. b.runConfig.Labels[args[j]] = args[j+1]
  125. j++
  126. }
  127. return b.commit("", b.runConfig.Cmd, commitStr)
  128. }
  129. // ADD foo /path
  130. //
  131. // Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
  132. // exist here. If you do not wish to have this automatic handling, use COPY.
  133. //
  134. func add(b *Builder, args []string, attributes map[string]bool, original string) error {
  135. if len(args) < 2 {
  136. return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD")
  137. }
  138. if err := b.flags.Parse(); err != nil {
  139. return err
  140. }
  141. return b.runContextCommand(args, true, true, "ADD")
  142. }
  143. // COPY foo /path
  144. //
  145. // Same as 'ADD' but without the tar and remote url handling.
  146. //
  147. func dispatchCopy(b *Builder, args []string, attributes map[string]bool, original string) error {
  148. if len(args) < 2 {
  149. return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY")
  150. }
  151. if err := b.flags.Parse(); err != nil {
  152. return err
  153. }
  154. return b.runContextCommand(args, false, false, "COPY")
  155. }
  156. // FROM imagename
  157. //
  158. // This sets the image the dockerfile will build on top of.
  159. //
  160. func from(b *Builder, args []string, attributes map[string]bool, original string) error {
  161. if len(args) != 1 {
  162. return derr.ErrorCodeExactlyOneArg.WithArgs("FROM")
  163. }
  164. if err := b.flags.Parse(); err != nil {
  165. return err
  166. }
  167. name := args[0]
  168. // Windows cannot support a container with no base image.
  169. if name == NoBaseImageSpecifier {
  170. if runtime.GOOS == "windows" {
  171. return fmt.Errorf("Windows does not support FROM scratch")
  172. }
  173. b.image = ""
  174. b.noBaseImage = true
  175. return nil
  176. }
  177. var (
  178. image builder.Image
  179. err error
  180. )
  181. // TODO: don't use `name`, instead resolve it to a digest
  182. if !b.Pull {
  183. image, err = b.docker.GetImage(name)
  184. // TODO: shouldn't we error out if error is different from "not found" ?
  185. }
  186. if image == nil {
  187. image, err = b.docker.Pull(name)
  188. if err != nil {
  189. return err
  190. }
  191. }
  192. return b.processImageFrom(image)
  193. }
  194. // ONBUILD RUN echo yo
  195. //
  196. // ONBUILD triggers run when the image is used in a FROM statement.
  197. //
  198. // ONBUILD handling has a lot of special-case functionality, the heading in
  199. // evaluator.go and comments around dispatch() in the same file explain the
  200. // special cases. search for 'OnBuild' in internals.go for additional special
  201. // cases.
  202. //
  203. func onbuild(b *Builder, args []string, attributes map[string]bool, original string) error {
  204. if len(args) == 0 {
  205. return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD")
  206. }
  207. if err := b.flags.Parse(); err != nil {
  208. return err
  209. }
  210. triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
  211. switch triggerInstruction {
  212. case "ONBUILD":
  213. return derr.ErrorCodeChainOnBuild
  214. case "MAINTAINER", "FROM":
  215. return derr.ErrorCodeBadOnBuildCmd.WithArgs(triggerInstruction)
  216. }
  217. original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
  218. b.runConfig.OnBuild = append(b.runConfig.OnBuild, original)
  219. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ONBUILD %s", original))
  220. }
  221. // WORKDIR /tmp
  222. //
  223. // Set the working directory for future RUN/CMD/etc statements.
  224. //
  225. func workdir(b *Builder, args []string, attributes map[string]bool, original string) error {
  226. if len(args) != 1 {
  227. return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR")
  228. }
  229. if err := b.flags.Parse(); err != nil {
  230. return err
  231. }
  232. // This is from the Dockerfile and will not necessarily be in platform
  233. // specific semantics, hence ensure it is converted.
  234. workdir := filepath.FromSlash(args[0])
  235. if !system.IsAbs(workdir) {
  236. current := filepath.FromSlash(b.runConfig.WorkingDir)
  237. workdir = filepath.Join(string(os.PathSeparator), current, workdir)
  238. }
  239. b.runConfig.WorkingDir = workdir
  240. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
  241. }
  242. // RUN some command yo
  243. //
  244. // run a command and commit the image. Args are automatically prepended with
  245. // 'sh -c' under linux or 'cmd /S /C' under Windows, in the event there is
  246. // only one argument. The difference in processing:
  247. //
  248. // RUN echo hi # sh -c echo hi (Linux)
  249. // RUN echo hi # cmd /S /C echo hi (Windows)
  250. // RUN [ "echo", "hi" ] # echo hi
  251. //
  252. func run(b *Builder, args []string, attributes map[string]bool, original string) error {
  253. if b.image == "" && !b.noBaseImage {
  254. return derr.ErrorCodeMissingFrom
  255. }
  256. if err := b.flags.Parse(); err != nil {
  257. return err
  258. }
  259. args = handleJSONArgs(args, attributes)
  260. if !attributes["json"] {
  261. if runtime.GOOS != "windows" {
  262. args = append([]string{"/bin/sh", "-c"}, args...)
  263. } else {
  264. args = append([]string{"cmd", "/S", "/C"}, args...)
  265. }
  266. }
  267. runCmd := flag.NewFlagSet("run", flag.ContinueOnError)
  268. runCmd.SetOutput(ioutil.Discard)
  269. runCmd.Usage = nil
  270. config, _, _, err := runconfig.Parse(runCmd, append([]string{b.image}, args...))
  271. if err != nil {
  272. return err
  273. }
  274. // stash the cmd
  275. cmd := b.runConfig.Cmd
  276. runconfig.Merge(b.runConfig, config)
  277. // stash the config environment
  278. env := b.runConfig.Env
  279. defer func(cmd *strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
  280. defer func(env []string) { b.runConfig.Env = env }(env)
  281. // derive the net build-time environment for this run. We let config
  282. // environment override the build time environment.
  283. // This means that we take the b.buildArgs list of env vars and remove
  284. // any of those variables that are defined as part of the container. In other
  285. // words, anything in b.Config.Env. What's left is the list of build-time env
  286. // vars that we need to add to each RUN command - note the list could be empty.
  287. //
  288. // We don't persist the build time environment with container's config
  289. // environment, but just sort and prepend it to the command string at time
  290. // of commit.
  291. // This helps with tracing back the image's actual environment at the time
  292. // of RUN, without leaking it to the final image. It also aids cache
  293. // lookup for same image built with same build time environment.
  294. cmdBuildEnv := []string{}
  295. configEnv := runconfig.ConvertKVStringsToMap(b.runConfig.Env)
  296. for key, val := range b.BuildArgs {
  297. if !b.isBuildArgAllowed(key) {
  298. // skip build-args that are not in allowed list, meaning they have
  299. // not been defined by an "ARG" Dockerfile command yet.
  300. // This is an error condition but only if there is no "ARG" in the entire
  301. // Dockerfile, so we'll generate any necessary errors after we parsed
  302. // the entire file (see 'leftoverArgs' processing in evaluator.go )
  303. continue
  304. }
  305. if _, ok := configEnv[key]; !ok {
  306. cmdBuildEnv = append(cmdBuildEnv, fmt.Sprintf("%s=%s", key, val))
  307. }
  308. }
  309. // derive the command to use for probeCache() and to commit in this container.
  310. // Note that we only do this if there are any build-time env vars. Also, we
  311. // use the special argument "|#" at the start of the args array. This will
  312. // avoid conflicts with any RUN command since commands can not
  313. // start with | (vertical bar). The "#" (number of build envs) is there to
  314. // help ensure proper cache matches. We don't want a RUN command
  315. // that starts with "foo=abc" to be considered part of a build-time env var.
  316. saveCmd := config.Cmd
  317. if len(cmdBuildEnv) > 0 {
  318. sort.Strings(cmdBuildEnv)
  319. tmpEnv := append([]string{fmt.Sprintf("|%d", len(cmdBuildEnv))}, cmdBuildEnv...)
  320. saveCmd = strslice.New(append(tmpEnv, saveCmd.Slice()...)...)
  321. }
  322. b.runConfig.Cmd = saveCmd
  323. hit, err := b.probeCache()
  324. if err != nil {
  325. return err
  326. }
  327. if hit {
  328. return nil
  329. }
  330. // set Cmd manually, this is special case only for Dockerfiles
  331. b.runConfig.Cmd = config.Cmd
  332. // set build-time environment for 'run'.
  333. b.runConfig.Env = append(b.runConfig.Env, cmdBuildEnv...)
  334. // set config as already being escaped, this prevents double escaping on windows
  335. b.runConfig.ArgsEscaped = true
  336. logrus.Debugf("[BUILDER] Command to be executed: %v", b.runConfig.Cmd)
  337. cID, err := b.create()
  338. if err != nil {
  339. return err
  340. }
  341. if err := b.run(cID); err != nil {
  342. return err
  343. }
  344. // revert to original config environment and set the command string to
  345. // have the build-time env vars in it (if any) so that future cache look-ups
  346. // properly match it.
  347. b.runConfig.Env = env
  348. b.runConfig.Cmd = saveCmd
  349. return b.commit(cID, cmd, "run")
  350. }
  351. // CMD foo
  352. //
  353. // Set the default command to run in the container (which may be empty).
  354. // Argument handling is the same as RUN.
  355. //
  356. func cmd(b *Builder, args []string, attributes map[string]bool, original string) error {
  357. if err := b.flags.Parse(); err != nil {
  358. return err
  359. }
  360. cmdSlice := handleJSONArgs(args, attributes)
  361. if !attributes["json"] {
  362. if runtime.GOOS != "windows" {
  363. cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...)
  364. } else {
  365. cmdSlice = append([]string{"cmd", "/S", "/C"}, cmdSlice...)
  366. }
  367. }
  368. b.runConfig.Cmd = strslice.New(cmdSlice...)
  369. if err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
  370. return err
  371. }
  372. if len(args) != 0 {
  373. b.cmdSet = true
  374. }
  375. return nil
  376. }
  377. // ENTRYPOINT /usr/sbin/nginx
  378. //
  379. // Set the entrypoint (which defaults to sh -c on linux, or cmd /S /C on Windows) to
  380. // /usr/sbin/nginx. Will accept the CMD as the arguments to /usr/sbin/nginx.
  381. //
  382. // Handles command processing similar to CMD and RUN, only b.runConfig.Entrypoint
  383. // is initialized at NewBuilder time instead of through argument parsing.
  384. //
  385. func entrypoint(b *Builder, args []string, attributes map[string]bool, original string) error {
  386. if err := b.flags.Parse(); err != nil {
  387. return err
  388. }
  389. parsed := handleJSONArgs(args, attributes)
  390. switch {
  391. case attributes["json"]:
  392. // ENTRYPOINT ["echo", "hi"]
  393. b.runConfig.Entrypoint = strslice.New(parsed...)
  394. case len(parsed) == 0:
  395. // ENTRYPOINT []
  396. b.runConfig.Entrypoint = nil
  397. default:
  398. // ENTRYPOINT echo hi
  399. if runtime.GOOS != "windows" {
  400. b.runConfig.Entrypoint = strslice.New("/bin/sh", "-c", parsed[0])
  401. } else {
  402. b.runConfig.Entrypoint = strslice.New("cmd", "/S", "/C", parsed[0])
  403. }
  404. }
  405. // when setting the entrypoint if a CMD was not explicitly set then
  406. // set the command to nil
  407. if !b.cmdSet {
  408. b.runConfig.Cmd = nil
  409. }
  410. if err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.runConfig.Entrypoint)); err != nil {
  411. return err
  412. }
  413. return nil
  414. }
  415. // EXPOSE 6667/tcp 7000/tcp
  416. //
  417. // Expose ports for links and port mappings. This all ends up in
  418. // b.runConfig.ExposedPorts for runconfig.
  419. //
  420. func expose(b *Builder, args []string, attributes map[string]bool, original string) error {
  421. portsTab := args
  422. if len(args) == 0 {
  423. return derr.ErrorCodeAtLeastOneArg.WithArgs("EXPOSE")
  424. }
  425. if err := b.flags.Parse(); err != nil {
  426. return err
  427. }
  428. if b.runConfig.ExposedPorts == nil {
  429. b.runConfig.ExposedPorts = make(nat.PortSet)
  430. }
  431. ports, _, err := nat.ParsePortSpecs(portsTab)
  432. if err != nil {
  433. return err
  434. }
  435. // instead of using ports directly, we build a list of ports and sort it so
  436. // the order is consistent. This prevents cache burst where map ordering
  437. // changes between builds
  438. portList := make([]string, len(ports))
  439. var i int
  440. for port := range ports {
  441. if _, exists := b.runConfig.ExposedPorts[port]; !exists {
  442. b.runConfig.ExposedPorts[port] = struct{}{}
  443. }
  444. portList[i] = string(port)
  445. i++
  446. }
  447. sort.Strings(portList)
  448. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
  449. }
  450. // USER foo
  451. //
  452. // Set the user to 'foo' for future commands and when running the
  453. // ENTRYPOINT/CMD at container run time.
  454. //
  455. func user(b *Builder, args []string, attributes map[string]bool, original string) error {
  456. if len(args) != 1 {
  457. return derr.ErrorCodeExactlyOneArg.WithArgs("USER")
  458. }
  459. if err := b.flags.Parse(); err != nil {
  460. return err
  461. }
  462. b.runConfig.User = args[0]
  463. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("USER %v", args))
  464. }
  465. // VOLUME /foo
  466. //
  467. // Expose the volume /foo for use. Will also accept the JSON array form.
  468. //
  469. func volume(b *Builder, args []string, attributes map[string]bool, original string) error {
  470. if len(args) == 0 {
  471. return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME")
  472. }
  473. if err := b.flags.Parse(); err != nil {
  474. return err
  475. }
  476. if b.runConfig.Volumes == nil {
  477. b.runConfig.Volumes = map[string]struct{}{}
  478. }
  479. for _, v := range args {
  480. v = strings.TrimSpace(v)
  481. if v == "" {
  482. return derr.ErrorCodeVolumeEmpty
  483. }
  484. b.runConfig.Volumes[v] = struct{}{}
  485. }
  486. if err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
  487. return err
  488. }
  489. return nil
  490. }
  491. // STOPSIGNAL signal
  492. //
  493. // Set the signal that will be used to kill the container.
  494. func stopSignal(b *Builder, args []string, attributes map[string]bool, original string) error {
  495. if len(args) != 1 {
  496. return fmt.Errorf("STOPSIGNAL requires exactly one argument")
  497. }
  498. sig := args[0]
  499. _, err := signal.ParseSignal(sig)
  500. if err != nil {
  501. return err
  502. }
  503. b.runConfig.StopSignal = sig
  504. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
  505. }
  506. // ARG name[=value]
  507. //
  508. // Adds the variable foo to the trusted list of variables that can be passed
  509. // to builder using the --build-arg flag for expansion/subsitution or passing to 'run'.
  510. // Dockerfile author may optionally set a default value of this variable.
  511. func arg(b *Builder, args []string, attributes map[string]bool, original string) error {
  512. if len(args) != 1 {
  513. return fmt.Errorf("ARG requires exactly one argument definition")
  514. }
  515. var (
  516. name string
  517. value string
  518. hasDefault bool
  519. )
  520. arg := args[0]
  521. // 'arg' can just be a name or name-value pair. Note that this is different
  522. // from 'env' that handles the split of name and value at the parser level.
  523. // The reason for doing it differently for 'arg' is that we support just
  524. // defining an arg and not assign it a value (while 'env' always expects a
  525. // name-value pair). If possible, it will be good to harmonize the two.
  526. if strings.Contains(arg, "=") {
  527. parts := strings.SplitN(arg, "=", 2)
  528. name = parts[0]
  529. value = parts[1]
  530. hasDefault = true
  531. } else {
  532. name = arg
  533. hasDefault = false
  534. }
  535. // add the arg to allowed list of build-time args from this step on.
  536. b.allowedBuildArgs[name] = true
  537. // If there is a default value associated with this arg then add it to the
  538. // b.buildArgs if one is not already passed to the builder. The args passed
  539. // to builder override the default value of 'arg'.
  540. if _, ok := b.BuildArgs[name]; !ok && hasDefault {
  541. b.BuildArgs[name] = value
  542. }
  543. return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
  544. }