dispatchers.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  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. "regexp"
  11. "runtime"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "bytes"
  17. "github.com/Sirupsen/logrus"
  18. "github.com/docker/docker/api"
  19. "github.com/docker/docker/api/types"
  20. "github.com/docker/docker/api/types/container"
  21. "github.com/docker/docker/api/types/strslice"
  22. "github.com/docker/docker/builder"
  23. "github.com/docker/docker/pkg/signal"
  24. "github.com/docker/go-connections/nat"
  25. "github.com/pkg/errors"
  26. )
  27. // ENV foo bar
  28. //
  29. // Sets the environment variable foo to bar, also makes interpolation
  30. // in the dockerfile available from the next statement on via ${foo}.
  31. //
  32. func env(req dispatchRequest) error {
  33. if len(req.args) == 0 {
  34. return errAtLeastOneArgument("ENV")
  35. }
  36. if len(req.args)%2 != 0 {
  37. // should never get here, but just in case
  38. return errTooManyArguments("ENV")
  39. }
  40. if err := req.flags.Parse(); err != nil {
  41. return err
  42. }
  43. runConfig := req.state.runConfig
  44. commitMessage := bytes.NewBufferString("ENV")
  45. for j := 0; j < len(req.args); j += 2 {
  46. if len(req.args[j]) == 0 {
  47. return errBlankCommandNames("ENV")
  48. }
  49. name := req.args[j]
  50. value := req.args[j+1]
  51. newVar := name + "=" + value
  52. commitMessage.WriteString(" " + newVar)
  53. gotOne := false
  54. for i, envVar := range runConfig.Env {
  55. envParts := strings.SplitN(envVar, "=", 2)
  56. compareFrom := envParts[0]
  57. if equalEnvKeys(compareFrom, name) {
  58. runConfig.Env[i] = newVar
  59. gotOne = true
  60. break
  61. }
  62. }
  63. if !gotOne {
  64. runConfig.Env = append(runConfig.Env, newVar)
  65. }
  66. }
  67. return req.builder.commit(req.state, commitMessage.String())
  68. }
  69. // MAINTAINER some text <maybe@an.email.address>
  70. //
  71. // Sets the maintainer metadata.
  72. func maintainer(req dispatchRequest) error {
  73. if len(req.args) != 1 {
  74. return errExactlyOneArgument("MAINTAINER")
  75. }
  76. if err := req.flags.Parse(); err != nil {
  77. return err
  78. }
  79. maintainer := req.args[0]
  80. req.state.maintainer = maintainer
  81. return req.builder.commit(req.state, "MAINTAINER "+maintainer)
  82. }
  83. // LABEL some json data describing the image
  84. //
  85. // Sets the Label variable foo to bar,
  86. //
  87. func label(req dispatchRequest) error {
  88. if len(req.args) == 0 {
  89. return errAtLeastOneArgument("LABEL")
  90. }
  91. if len(req.args)%2 != 0 {
  92. // should never get here, but just in case
  93. return errTooManyArguments("LABEL")
  94. }
  95. if err := req.flags.Parse(); err != nil {
  96. return err
  97. }
  98. commitStr := "LABEL"
  99. runConfig := req.state.runConfig
  100. if runConfig.Labels == nil {
  101. runConfig.Labels = map[string]string{}
  102. }
  103. for j := 0; j < len(req.args); j++ {
  104. name := req.args[j]
  105. if name == "" {
  106. return errBlankCommandNames("LABEL")
  107. }
  108. value := req.args[j+1]
  109. commitStr += " " + name + "=" + value
  110. runConfig.Labels[name] = value
  111. j++
  112. }
  113. return req.builder.commit(req.state, commitStr)
  114. }
  115. // ADD foo /path
  116. //
  117. // Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
  118. // exist here. If you do not wish to have this automatic handling, use COPY.
  119. //
  120. func add(req dispatchRequest) error {
  121. if len(req.args) < 2 {
  122. return errAtLeastTwoArguments("ADD")
  123. }
  124. if err := req.flags.Parse(); err != nil {
  125. return err
  126. }
  127. return req.builder.runContextCommand(req, true, true, "ADD", nil)
  128. }
  129. // COPY foo /path
  130. //
  131. // Same as 'ADD' but without the tar and remote url handling.
  132. //
  133. func dispatchCopy(req dispatchRequest) error {
  134. if len(req.args) < 2 {
  135. return errAtLeastTwoArguments("COPY")
  136. }
  137. flFrom := req.flags.AddString("from", "")
  138. if err := req.flags.Parse(); err != nil {
  139. return err
  140. }
  141. var im *imageMount
  142. if flFrom.IsUsed() {
  143. var err error
  144. im, err = req.builder.imageContexts.get(flFrom.Value)
  145. if err != nil {
  146. return err
  147. }
  148. }
  149. return req.builder.runContextCommand(req, false, false, "COPY", im)
  150. }
  151. // FROM imagename[:tag | @digest] [AS build-stage-name]
  152. //
  153. func from(req dispatchRequest) error {
  154. stageName, err := parseBuildStageName(req.args)
  155. if err != nil {
  156. return err
  157. }
  158. if err := req.flags.Parse(); err != nil {
  159. return err
  160. }
  161. req.builder.resetImageCache()
  162. req.state.noBaseImage = false
  163. req.state.stageName = stageName
  164. if _, err := req.builder.imageContexts.add(stageName); err != nil {
  165. return err
  166. }
  167. image, err := req.builder.getFromImage(req.state, req.shlex, req.args[0])
  168. if err != nil {
  169. return err
  170. }
  171. switch image {
  172. case nil:
  173. req.state.imageID = ""
  174. req.state.noBaseImage = true
  175. default:
  176. req.builder.imageContexts.update(image.ImageID(), image.RunConfig())
  177. }
  178. req.state.baseImage = image
  179. req.builder.buildArgs.ResetAllowed()
  180. return req.builder.processImageFrom(req.state, image)
  181. }
  182. func parseBuildStageName(args []string) (string, error) {
  183. stageName := ""
  184. switch {
  185. case len(args) == 3 && strings.EqualFold(args[1], "as"):
  186. stageName = strings.ToLower(args[2])
  187. if ok, _ := regexp.MatchString("^[a-z][a-z0-9-_\\.]*$", stageName); !ok {
  188. return "", errors.Errorf("invalid name for build stage: %q, name can't start with a number or contain symbols", stageName)
  189. }
  190. case len(args) != 1:
  191. return "", errors.New("FROM requires either one or three arguments")
  192. }
  193. return stageName, nil
  194. }
  195. func (b *Builder) getFromImage(dispatchState *dispatchState, shlex *ShellLex, name string) (builder.Image, error) {
  196. substitutionArgs := []string{}
  197. for key, value := range b.buildArgs.GetAllMeta() {
  198. substitutionArgs = append(substitutionArgs, key+"="+value)
  199. }
  200. name, err := shlex.ProcessWord(name, substitutionArgs)
  201. if err != nil {
  202. return nil, err
  203. }
  204. if im, ok := b.imageContexts.byName[name]; ok {
  205. if len(im.ImageID()) > 0 {
  206. return im, nil
  207. }
  208. // FROM scratch does not have an ImageID
  209. return nil, nil
  210. }
  211. // Windows cannot support a container with no base image.
  212. if name == api.NoBaseImageSpecifier {
  213. if runtime.GOOS == "windows" {
  214. return nil, errors.New("Windows does not support FROM scratch")
  215. }
  216. return nil, nil
  217. }
  218. return pullOrGetImage(b, name)
  219. }
  220. // ONBUILD RUN echo yo
  221. //
  222. // ONBUILD triggers run when the image is used in a FROM statement.
  223. //
  224. // ONBUILD handling has a lot of special-case functionality, the heading in
  225. // evaluator.go and comments around dispatch() in the same file explain the
  226. // special cases. search for 'OnBuild' in internals.go for additional special
  227. // cases.
  228. //
  229. func onbuild(req dispatchRequest) error {
  230. if len(req.args) == 0 {
  231. return errAtLeastOneArgument("ONBUILD")
  232. }
  233. if err := req.flags.Parse(); err != nil {
  234. return err
  235. }
  236. triggerInstruction := strings.ToUpper(strings.TrimSpace(req.args[0]))
  237. switch triggerInstruction {
  238. case "ONBUILD":
  239. return errors.New("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
  240. case "MAINTAINER", "FROM":
  241. return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction)
  242. }
  243. runConfig := req.state.runConfig
  244. original := regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(req.original, "")
  245. runConfig.OnBuild = append(runConfig.OnBuild, original)
  246. return req.builder.commit(req.state, "ONBUILD "+original)
  247. }
  248. // WORKDIR /tmp
  249. //
  250. // Set the working directory for future RUN/CMD/etc statements.
  251. //
  252. func workdir(req dispatchRequest) error {
  253. if len(req.args) != 1 {
  254. return errExactlyOneArgument("WORKDIR")
  255. }
  256. err := req.flags.Parse()
  257. if err != nil {
  258. return err
  259. }
  260. runConfig := req.state.runConfig
  261. // This is from the Dockerfile and will not necessarily be in platform
  262. // specific semantics, hence ensure it is converted.
  263. runConfig.WorkingDir, err = normaliseWorkdir(runConfig.WorkingDir, req.args[0])
  264. if err != nil {
  265. return err
  266. }
  267. // For performance reasons, we explicitly do a create/mkdir now
  268. // This avoids having an unnecessary expensive mount/unmount calls
  269. // (on Windows in particular) during each container create.
  270. // Prior to 1.13, the mkdir was deferred and not executed at this step.
  271. if req.builder.disableCommit {
  272. // Don't call back into the daemon if we're going through docker commit --change "WORKDIR /foo".
  273. // We've already updated the runConfig and that's enough.
  274. return nil
  275. }
  276. comment := "WORKDIR " + runConfig.WorkingDir
  277. runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment))
  278. if hit, err := req.builder.probeCache(req.state, runConfigWithCommentCmd); err != nil || hit {
  279. return err
  280. }
  281. container, err := req.builder.docker.ContainerCreate(types.ContainerCreateConfig{
  282. Config: runConfigWithCommentCmd,
  283. // Set a log config to override any default value set on the daemon
  284. HostConfig: &container.HostConfig{LogConfig: defaultLogConfig},
  285. })
  286. if err != nil {
  287. return err
  288. }
  289. req.builder.tmpContainers[container.ID] = struct{}{}
  290. if err := req.builder.docker.ContainerCreateWorkdir(container.ID); err != nil {
  291. return err
  292. }
  293. return req.builder.commitContainer(req.state, container.ID, runConfigWithCommentCmd)
  294. }
  295. // RUN some command yo
  296. //
  297. // run a command and commit the image. Args are automatically prepended with
  298. // the current SHELL which defaults to 'sh -c' under linux or 'cmd /S /C' under
  299. // Windows, in the event there is only one argument The difference in processing:
  300. //
  301. // RUN echo hi # sh -c echo hi (Linux)
  302. // RUN echo hi # cmd /S /C echo hi (Windows)
  303. // RUN [ "echo", "hi" ] # echo hi
  304. //
  305. func run(req dispatchRequest) error {
  306. if !req.state.hasFromImage() {
  307. return errors.New("Please provide a source image with `from` prior to run")
  308. }
  309. if err := req.flags.Parse(); err != nil {
  310. return err
  311. }
  312. stateRunConfig := req.state.runConfig
  313. args := handleJSONArgs(req.args, req.attributes)
  314. if !req.attributes["json"] {
  315. args = append(getShell(stateRunConfig), args...)
  316. }
  317. cmdFromArgs := strslice.StrSlice(args)
  318. buildArgs := req.builder.buildArgs.FilterAllowed(stateRunConfig.Env)
  319. saveCmd := cmdFromArgs
  320. if len(buildArgs) > 0 {
  321. saveCmd = prependEnvOnCmd(req.builder.buildArgs, buildArgs, cmdFromArgs)
  322. }
  323. runConfigForCacheProbe := copyRunConfig(stateRunConfig,
  324. withCmd(saveCmd),
  325. withEntrypointOverride(saveCmd, nil))
  326. hit, err := req.builder.probeCache(req.state, runConfigForCacheProbe)
  327. if err != nil || hit {
  328. return err
  329. }
  330. runConfig := copyRunConfig(stateRunConfig,
  331. withCmd(cmdFromArgs),
  332. withEnv(append(stateRunConfig.Env, buildArgs...)),
  333. withEntrypointOverride(saveCmd, strslice.StrSlice{""}))
  334. // set config as already being escaped, this prevents double escaping on windows
  335. runConfig.ArgsEscaped = true
  336. logrus.Debugf("[BUILDER] Command to be executed: %v", runConfig.Cmd)
  337. cID, err := req.builder.create(runConfig)
  338. if err != nil {
  339. return err
  340. }
  341. if err := req.builder.run(cID, runConfig.Cmd); err != nil {
  342. return err
  343. }
  344. return req.builder.commitContainer(req.state, cID, runConfigForCacheProbe)
  345. }
  346. // Derive the command to use for probeCache() and to commit in this container.
  347. // Note that we only do this if there are any build-time env vars. Also, we
  348. // use the special argument "|#" at the start of the args array. This will
  349. // avoid conflicts with any RUN command since commands can not
  350. // start with | (vertical bar). The "#" (number of build envs) is there to
  351. // help ensure proper cache matches. We don't want a RUN command
  352. // that starts with "foo=abc" to be considered part of a build-time env var.
  353. //
  354. // remove any unreferenced built-in args from the environment variables.
  355. // These args are transparent so resulting image should be the same regardless
  356. // of the value.
  357. func prependEnvOnCmd(buildArgs *buildArgs, buildArgVars []string, cmd strslice.StrSlice) strslice.StrSlice {
  358. var tmpBuildEnv []string
  359. for _, env := range buildArgVars {
  360. key := strings.SplitN(env, "=", 2)[0]
  361. if buildArgs.IsReferencedOrNotBuiltin(key) {
  362. tmpBuildEnv = append(tmpBuildEnv, env)
  363. }
  364. }
  365. sort.Strings(tmpBuildEnv)
  366. tmpEnv := append([]string{fmt.Sprintf("|%d", len(tmpBuildEnv))}, tmpBuildEnv...)
  367. return strslice.StrSlice(append(tmpEnv, cmd...))
  368. }
  369. // CMD foo
  370. //
  371. // Set the default command to run in the container (which may be empty).
  372. // Argument handling is the same as RUN.
  373. //
  374. func cmd(req dispatchRequest) error {
  375. if err := req.flags.Parse(); err != nil {
  376. return err
  377. }
  378. runConfig := req.state.runConfig
  379. cmdSlice := handleJSONArgs(req.args, req.attributes)
  380. if !req.attributes["json"] {
  381. cmdSlice = append(getShell(runConfig), cmdSlice...)
  382. }
  383. runConfig.Cmd = strslice.StrSlice(cmdSlice)
  384. // set config as already being escaped, this prevents double escaping on windows
  385. runConfig.ArgsEscaped = true
  386. if err := req.builder.commit(req.state, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
  387. return err
  388. }
  389. if len(req.args) != 0 {
  390. req.state.cmdSet = true
  391. }
  392. return nil
  393. }
  394. // parseOptInterval(flag) is the duration of flag.Value, or 0 if
  395. // empty. An error is reported if the value is given and less than minimum duration.
  396. func parseOptInterval(f *Flag) (time.Duration, error) {
  397. s := f.Value
  398. if s == "" {
  399. return 0, nil
  400. }
  401. d, err := time.ParseDuration(s)
  402. if err != nil {
  403. return 0, err
  404. }
  405. if d < time.Duration(container.MinimumDuration) {
  406. return 0, fmt.Errorf("Interval %#v cannot be less than %s", f.name, container.MinimumDuration)
  407. }
  408. return d, nil
  409. }
  410. // HEALTHCHECK foo
  411. //
  412. // Set the default healthcheck command to run in the container (which may be empty).
  413. // Argument handling is the same as RUN.
  414. //
  415. func healthcheck(req dispatchRequest) error {
  416. if len(req.args) == 0 {
  417. return errAtLeastOneArgument("HEALTHCHECK")
  418. }
  419. runConfig := req.state.runConfig
  420. typ := strings.ToUpper(req.args[0])
  421. args := req.args[1:]
  422. if typ == "NONE" {
  423. if len(args) != 0 {
  424. return errors.New("HEALTHCHECK NONE takes no arguments")
  425. }
  426. test := strslice.StrSlice{typ}
  427. runConfig.Healthcheck = &container.HealthConfig{
  428. Test: test,
  429. }
  430. } else {
  431. if runConfig.Healthcheck != nil {
  432. oldCmd := runConfig.Healthcheck.Test
  433. if len(oldCmd) > 0 && oldCmd[0] != "NONE" {
  434. fmt.Fprintf(req.builder.Stdout, "Note: overriding previous HEALTHCHECK: %v\n", oldCmd)
  435. }
  436. }
  437. healthcheck := container.HealthConfig{}
  438. flInterval := req.flags.AddString("interval", "")
  439. flTimeout := req.flags.AddString("timeout", "")
  440. flStartPeriod := req.flags.AddString("start-period", "")
  441. flRetries := req.flags.AddString("retries", "")
  442. if err := req.flags.Parse(); err != nil {
  443. return err
  444. }
  445. switch typ {
  446. case "CMD":
  447. cmdSlice := handleJSONArgs(args, req.attributes)
  448. if len(cmdSlice) == 0 {
  449. return errors.New("Missing command after HEALTHCHECK CMD")
  450. }
  451. if !req.attributes["json"] {
  452. typ = "CMD-SHELL"
  453. }
  454. healthcheck.Test = strslice.StrSlice(append([]string{typ}, cmdSlice...))
  455. default:
  456. return fmt.Errorf("Unknown type %#v in HEALTHCHECK (try CMD)", typ)
  457. }
  458. interval, err := parseOptInterval(flInterval)
  459. if err != nil {
  460. return err
  461. }
  462. healthcheck.Interval = interval
  463. timeout, err := parseOptInterval(flTimeout)
  464. if err != nil {
  465. return err
  466. }
  467. healthcheck.Timeout = timeout
  468. startPeriod, err := parseOptInterval(flStartPeriod)
  469. if err != nil {
  470. return err
  471. }
  472. healthcheck.StartPeriod = startPeriod
  473. if flRetries.Value != "" {
  474. retries, err := strconv.ParseInt(flRetries.Value, 10, 32)
  475. if err != nil {
  476. return err
  477. }
  478. if retries < 1 {
  479. return fmt.Errorf("--retries must be at least 1 (not %d)", retries)
  480. }
  481. healthcheck.Retries = int(retries)
  482. } else {
  483. healthcheck.Retries = 0
  484. }
  485. runConfig.Healthcheck = &healthcheck
  486. }
  487. return req.builder.commit(req.state, fmt.Sprintf("HEALTHCHECK %q", runConfig.Healthcheck))
  488. }
  489. // ENTRYPOINT /usr/sbin/nginx
  490. //
  491. // Set the entrypoint to /usr/sbin/nginx. Will accept the CMD as the arguments
  492. // to /usr/sbin/nginx. Uses the default shell if not in JSON format.
  493. //
  494. // Handles command processing similar to CMD and RUN, only req.runConfig.Entrypoint
  495. // is initialized at newBuilder time instead of through argument parsing.
  496. //
  497. func entrypoint(req dispatchRequest) error {
  498. if err := req.flags.Parse(); err != nil {
  499. return err
  500. }
  501. runConfig := req.state.runConfig
  502. parsed := handleJSONArgs(req.args, req.attributes)
  503. switch {
  504. case req.attributes["json"]:
  505. // ENTRYPOINT ["echo", "hi"]
  506. runConfig.Entrypoint = strslice.StrSlice(parsed)
  507. case len(parsed) == 0:
  508. // ENTRYPOINT []
  509. runConfig.Entrypoint = nil
  510. default:
  511. // ENTRYPOINT echo hi
  512. runConfig.Entrypoint = strslice.StrSlice(append(getShell(runConfig), parsed[0]))
  513. }
  514. // when setting the entrypoint if a CMD was not explicitly set then
  515. // set the command to nil
  516. if !req.state.cmdSet {
  517. runConfig.Cmd = nil
  518. }
  519. return req.builder.commit(req.state, fmt.Sprintf("ENTRYPOINT %q", runConfig.Entrypoint))
  520. }
  521. // EXPOSE 6667/tcp 7000/tcp
  522. //
  523. // Expose ports for links and port mappings. This all ends up in
  524. // req.runConfig.ExposedPorts for runconfig.
  525. //
  526. func expose(req dispatchRequest) error {
  527. portsTab := req.args
  528. if len(req.args) == 0 {
  529. return errAtLeastOneArgument("EXPOSE")
  530. }
  531. if err := req.flags.Parse(); err != nil {
  532. return err
  533. }
  534. runConfig := req.state.runConfig
  535. if runConfig.ExposedPorts == nil {
  536. runConfig.ExposedPorts = make(nat.PortSet)
  537. }
  538. ports, _, err := nat.ParsePortSpecs(portsTab)
  539. if err != nil {
  540. return err
  541. }
  542. // instead of using ports directly, we build a list of ports and sort it so
  543. // the order is consistent. This prevents cache burst where map ordering
  544. // changes between builds
  545. portList := make([]string, len(ports))
  546. var i int
  547. for port := range ports {
  548. if _, exists := runConfig.ExposedPorts[port]; !exists {
  549. runConfig.ExposedPorts[port] = struct{}{}
  550. }
  551. portList[i] = string(port)
  552. i++
  553. }
  554. sort.Strings(portList)
  555. return req.builder.commit(req.state, "EXPOSE "+strings.Join(portList, " "))
  556. }
  557. // USER foo
  558. //
  559. // Set the user to 'foo' for future commands and when running the
  560. // ENTRYPOINT/CMD at container run time.
  561. //
  562. func user(req dispatchRequest) error {
  563. if len(req.args) != 1 {
  564. return errExactlyOneArgument("USER")
  565. }
  566. if err := req.flags.Parse(); err != nil {
  567. return err
  568. }
  569. req.state.runConfig.User = req.args[0]
  570. return req.builder.commit(req.state, fmt.Sprintf("USER %v", req.args))
  571. }
  572. // VOLUME /foo
  573. //
  574. // Expose the volume /foo for use. Will also accept the JSON array form.
  575. //
  576. func volume(req dispatchRequest) error {
  577. if len(req.args) == 0 {
  578. return errAtLeastOneArgument("VOLUME")
  579. }
  580. if err := req.flags.Parse(); err != nil {
  581. return err
  582. }
  583. runConfig := req.state.runConfig
  584. if runConfig.Volumes == nil {
  585. runConfig.Volumes = map[string]struct{}{}
  586. }
  587. for _, v := range req.args {
  588. v = strings.TrimSpace(v)
  589. if v == "" {
  590. return errors.New("VOLUME specified can not be an empty string")
  591. }
  592. runConfig.Volumes[v] = struct{}{}
  593. }
  594. return req.builder.commit(req.state, fmt.Sprintf("VOLUME %v", req.args))
  595. }
  596. // STOPSIGNAL signal
  597. //
  598. // Set the signal that will be used to kill the container.
  599. func stopSignal(req dispatchRequest) error {
  600. if len(req.args) != 1 {
  601. return errExactlyOneArgument("STOPSIGNAL")
  602. }
  603. sig := req.args[0]
  604. _, err := signal.ParseSignal(sig)
  605. if err != nil {
  606. return err
  607. }
  608. req.state.runConfig.StopSignal = sig
  609. return req.builder.commit(req.state, fmt.Sprintf("STOPSIGNAL %v", req.args))
  610. }
  611. // ARG name[=value]
  612. //
  613. // Adds the variable foo to the trusted list of variables that can be passed
  614. // to builder using the --build-arg flag for expansion/substitution or passing to 'run'.
  615. // Dockerfile author may optionally set a default value of this variable.
  616. func arg(req dispatchRequest) error {
  617. if len(req.args) != 1 {
  618. return errExactlyOneArgument("ARG")
  619. }
  620. var (
  621. name string
  622. newValue string
  623. hasDefault bool
  624. )
  625. arg := req.args[0]
  626. // 'arg' can just be a name or name-value pair. Note that this is different
  627. // from 'env' that handles the split of name and value at the parser level.
  628. // The reason for doing it differently for 'arg' is that we support just
  629. // defining an arg and not assign it a value (while 'env' always expects a
  630. // name-value pair). If possible, it will be good to harmonize the two.
  631. if strings.Contains(arg, "=") {
  632. parts := strings.SplitN(arg, "=", 2)
  633. if len(parts[0]) == 0 {
  634. return errBlankCommandNames("ARG")
  635. }
  636. name = parts[0]
  637. newValue = parts[1]
  638. hasDefault = true
  639. } else {
  640. name = arg
  641. hasDefault = false
  642. }
  643. var value *string
  644. if hasDefault {
  645. value = &newValue
  646. }
  647. req.builder.buildArgs.AddArg(name, value)
  648. // Arg before FROM doesn't add a layer
  649. if !req.state.hasFromImage() {
  650. req.builder.buildArgs.AddMetaArg(name, value)
  651. return nil
  652. }
  653. return req.builder.commit(req.state, "ARG "+arg)
  654. }
  655. // SHELL powershell -command
  656. //
  657. // Set the non-default shell to use.
  658. func shell(req dispatchRequest) error {
  659. if err := req.flags.Parse(); err != nil {
  660. return err
  661. }
  662. shellSlice := handleJSONArgs(req.args, req.attributes)
  663. switch {
  664. case len(shellSlice) == 0:
  665. // SHELL []
  666. return errAtLeastOneArgument("SHELL")
  667. case req.attributes["json"]:
  668. // SHELL ["powershell", "-command"]
  669. req.state.runConfig.Shell = strslice.StrSlice(shellSlice)
  670. default:
  671. // SHELL powershell -command - not JSON
  672. return errNotJSON("SHELL", req.original)
  673. }
  674. return req.builder.commit(req.state, fmt.Sprintf("SHELL %v", shellSlice))
  675. }
  676. func errAtLeastOneArgument(command string) error {
  677. return fmt.Errorf("%s requires at least one argument", command)
  678. }
  679. func errExactlyOneArgument(command string) error {
  680. return fmt.Errorf("%s requires exactly one argument", command)
  681. }
  682. func errAtLeastTwoArguments(command string) error {
  683. return fmt.Errorf("%s requires at least two arguments", command)
  684. }
  685. func errBlankCommandNames(command string) error {
  686. return fmt.Errorf("%s names can not be blank", command)
  687. }
  688. func errTooManyArguments(command string) error {
  689. return fmt.Errorf("Bad input to %s, too many arguments", command)
  690. }
  691. // mountByRef creates an imageMount from a reference. pulling the image if needed.
  692. func mountByRef(b *Builder, name string) (*imageMount, error) {
  693. image, err := pullOrGetImage(b, name)
  694. if err != nil {
  695. return nil, err
  696. }
  697. im := b.imageContexts.newImageMount(image.ImageID())
  698. return im, nil
  699. }
  700. func pullOrGetImage(b *Builder, name string) (builder.Image, error) {
  701. var image builder.Image
  702. if !b.options.PullParent {
  703. image, _ = b.docker.GetImageOnBuild(name)
  704. // TODO: shouldn't we error out if error is different from "not found" ?
  705. }
  706. if image == nil {
  707. var err error
  708. image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output)
  709. if err != nil {
  710. return nil, err
  711. }
  712. }
  713. return image, nil
  714. }