evaluator.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Package builder is the evaluation step in the Dockerfile parse/evaluate pipeline.
  2. //
  3. // It incorporates a dispatch table based on the parser.Node values (see the
  4. // parser package for more information) that are yielded from the parser itself.
  5. // Calling NewBuilder with the BuildOpts struct can be used to customize the
  6. // experience for execution purposes only. Parsing is controlled in the parser
  7. // package, and this division of resposibility should be respected.
  8. //
  9. // Please see the jump table targets for the actual invocations, most of which
  10. // will call out to the functions in internals.go to deal with their tasks.
  11. //
  12. // ONBUILD is a special case, which is covered in the onbuild() func in
  13. // dispatchers.go.
  14. //
  15. // The evaluator uses the concept of "steps", which are usually each processable
  16. // line in the Dockerfile. Each step is numbered and certain actions are taken
  17. // before and after each step, such as creating an image ID and removing temporary
  18. // containers and images. Note that ONBUILD creates a kinda-sorta "sub run" which
  19. // includes its own set of steps (usually only one of them).
  20. package builder
  21. import (
  22. "fmt"
  23. "io"
  24. "os"
  25. "path/filepath"
  26. "runtime"
  27. "strings"
  28. "github.com/Sirupsen/logrus"
  29. "github.com/docker/docker/api"
  30. "github.com/docker/docker/builder/command"
  31. "github.com/docker/docker/builder/parser"
  32. "github.com/docker/docker/cliconfig"
  33. "github.com/docker/docker/context"
  34. "github.com/docker/docker/daemon"
  35. "github.com/docker/docker/pkg/fileutils"
  36. "github.com/docker/docker/pkg/streamformatter"
  37. "github.com/docker/docker/pkg/stringid"
  38. "github.com/docker/docker/pkg/symlink"
  39. "github.com/docker/docker/pkg/tarsum"
  40. "github.com/docker/docker/pkg/ulimit"
  41. "github.com/docker/docker/runconfig"
  42. "github.com/docker/docker/utils"
  43. )
  44. // Environment variable interpolation will happen on these statements only.
  45. var replaceEnvAllowed = map[string]struct{}{
  46. command.Env: {},
  47. command.Label: {},
  48. command.Add: {},
  49. command.Copy: {},
  50. command.Workdir: {},
  51. command.Expose: {},
  52. command.Volume: {},
  53. command.User: {},
  54. command.StopSignal: {},
  55. command.Arg: {},
  56. }
  57. var evaluateTable map[string]func(context.Context, *builder, []string, map[string]bool, string) error
  58. func init() {
  59. evaluateTable = map[string]func(context.Context, *builder, []string, map[string]bool, string) error{
  60. command.Env: env,
  61. command.Label: label,
  62. command.Maintainer: maintainer,
  63. command.Add: add,
  64. command.Copy: dispatchCopy, // copy() is a go builtin
  65. command.From: from,
  66. command.Onbuild: onbuild,
  67. command.Workdir: workdir,
  68. command.Run: run,
  69. command.Cmd: cmd,
  70. command.Entrypoint: entrypoint,
  71. command.Expose: expose,
  72. command.Volume: volume,
  73. command.User: user,
  74. command.StopSignal: stopSignal,
  75. command.Arg: arg,
  76. }
  77. }
  78. // builder is an internal struct, used to maintain configuration of the Dockerfile's
  79. // processing as it evaluates the parsing result.
  80. type builder struct {
  81. Daemon *daemon.Daemon
  82. // effectively stdio for the run. Because it is not stdio, I said
  83. // "Effectively". Do not use stdio anywhere in this package for any reason.
  84. OutStream io.Writer
  85. ErrStream io.Writer
  86. Verbose bool
  87. UtilizeCache bool
  88. cacheBusted bool
  89. // controls how images and containers are handled between steps.
  90. Remove bool
  91. ForceRemove bool
  92. Pull bool
  93. // set this to true if we want the builder to not commit between steps.
  94. // This is useful when we only want to use the evaluator table to generate
  95. // the final configs of the Dockerfile but dont want the layers
  96. disableCommit bool
  97. // Registry server auth configs used to pull images when handling `FROM`.
  98. AuthConfigs map[string]cliconfig.AuthConfig
  99. // Deprecated, original writer used for ImagePull. To be removed.
  100. OutOld io.Writer
  101. StreamFormatter *streamformatter.StreamFormatter
  102. Config *runconfig.Config // runconfig for cmd, run, entrypoint etc.
  103. buildArgs map[string]string // build-time args received in build context for expansion/substitution and commands in 'run'.
  104. allowedBuildArgs map[string]bool // list of build-time args that are allowed for expansion/substitution and passing to commands in 'run'.
  105. // both of these are controlled by the Remove and ForceRemove options in BuildOpts
  106. TmpContainers map[string]struct{} // a map of containers used for removes
  107. dockerfileName string // name of Dockerfile
  108. dockerfile *parser.Node // the syntax tree of the dockerfile
  109. image string // image name for commit processing
  110. maintainer string // maintainer name. could probably be removed.
  111. cmdSet bool // indicates is CMD was set in current Dockerfile
  112. BuilderFlags *BFlags // current cmd's BuilderFlags - temporary
  113. context tarsum.TarSum // the context is a tarball that is uploaded by the client
  114. contextPath string // the path of the temporary directory the local context is unpacked to (server side)
  115. noBaseImage bool // indicates that this build does not start from any base image, but is being built from an empty file system.
  116. // Set resource restrictions for build containers
  117. cpuSetCpus string
  118. cpuSetMems string
  119. cpuShares int64
  120. cpuPeriod int64
  121. cpuQuota int64
  122. cgroupParent string
  123. memory int64
  124. memorySwap int64
  125. ulimits []*ulimit.Ulimit
  126. cancelled <-chan struct{} // When closed, job was cancelled.
  127. activeImages []string
  128. id string // Used to hold reference images
  129. }
  130. // Run the builder with the context. This is the lynchpin of this package. This
  131. // will (barring errors):
  132. //
  133. // * call readContext() which will set up the temporary directory and unpack
  134. // the context into it.
  135. // * read the dockerfile
  136. // * parse the dockerfile
  137. // * walk the parse tree and execute it by dispatching to handlers. If Remove
  138. // or ForceRemove is set, additional cleanup around containers happens after
  139. // processing.
  140. // * Print a happy message and return the image ID.
  141. //
  142. func (b *builder) Run(ctx context.Context, context io.Reader) (string, error) {
  143. if err := b.readContext(context); err != nil {
  144. return "", err
  145. }
  146. defer func() {
  147. if err := os.RemoveAll(b.contextPath); err != nil {
  148. logrus.Debugf("[BUILDER] failed to remove temporary context: %s", err)
  149. }
  150. }()
  151. if err := b.readDockerfile(); err != nil {
  152. return "", err
  153. }
  154. // some initializations that would not have been supplied by the caller.
  155. b.Config = &runconfig.Config{}
  156. b.TmpContainers = map[string]struct{}{}
  157. for i, n := range b.dockerfile.Children {
  158. select {
  159. case <-b.cancelled:
  160. logrus.Debug("Builder: build cancelled!")
  161. fmt.Fprintf(b.OutStream, "Build cancelled")
  162. return "", fmt.Errorf("Build cancelled")
  163. default:
  164. // Not cancelled yet, keep going...
  165. }
  166. if err := b.dispatch(ctx, i, n); err != nil {
  167. if b.ForceRemove {
  168. b.clearTmp(ctx)
  169. }
  170. return "", err
  171. }
  172. fmt.Fprintf(b.OutStream, " ---> %s\n", stringid.TruncateID(b.image))
  173. if b.Remove {
  174. b.clearTmp(ctx)
  175. }
  176. }
  177. // check if there are any leftover build-args that were passed but not
  178. // consumed during build. Return an error, if there are any.
  179. leftoverArgs := []string{}
  180. for arg := range b.buildArgs {
  181. if !b.isBuildArgAllowed(arg) {
  182. leftoverArgs = append(leftoverArgs, arg)
  183. }
  184. }
  185. if len(leftoverArgs) > 0 {
  186. return "", fmt.Errorf("One or more build-args %v were not consumed, failing build.", leftoverArgs)
  187. }
  188. if b.image == "" {
  189. return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?")
  190. }
  191. fmt.Fprintf(b.OutStream, "Successfully built %s\n", stringid.TruncateID(b.image))
  192. return b.image, nil
  193. }
  194. // Reads a Dockerfile from the current context. It assumes that the
  195. // 'filename' is a relative path from the root of the context
  196. func (b *builder) readDockerfile() error {
  197. // If no -f was specified then look for 'Dockerfile'. If we can't find
  198. // that then look for 'dockerfile'. If neither are found then default
  199. // back to 'Dockerfile' and use that in the error message.
  200. if b.dockerfileName == "" {
  201. b.dockerfileName = api.DefaultDockerfileName
  202. tmpFN := filepath.Join(b.contextPath, api.DefaultDockerfileName)
  203. if _, err := os.Lstat(tmpFN); err != nil {
  204. tmpFN = filepath.Join(b.contextPath, strings.ToLower(api.DefaultDockerfileName))
  205. if _, err := os.Lstat(tmpFN); err == nil {
  206. b.dockerfileName = strings.ToLower(api.DefaultDockerfileName)
  207. }
  208. }
  209. }
  210. origFile := b.dockerfileName
  211. filename, err := symlink.FollowSymlinkInScope(filepath.Join(b.contextPath, origFile), b.contextPath)
  212. if err != nil {
  213. return fmt.Errorf("The Dockerfile (%s) must be within the build context", origFile)
  214. }
  215. fi, err := os.Lstat(filename)
  216. if os.IsNotExist(err) {
  217. return fmt.Errorf("Cannot locate specified Dockerfile: %s", origFile)
  218. }
  219. if fi.Size() == 0 {
  220. return fmt.Errorf("The Dockerfile (%s) cannot be empty", origFile)
  221. }
  222. f, err := os.Open(filename)
  223. if err != nil {
  224. return err
  225. }
  226. b.dockerfile, err = parser.Parse(f)
  227. f.Close()
  228. if err != nil {
  229. return err
  230. }
  231. // After the Dockerfile has been parsed, we need to check the .dockerignore
  232. // file for either "Dockerfile" or ".dockerignore", and if either are
  233. // present then erase them from the build context. These files should never
  234. // have been sent from the client but we did send them to make sure that
  235. // we had the Dockerfile to actually parse, and then we also need the
  236. // .dockerignore file to know whether either file should be removed.
  237. // Note that this assumes the Dockerfile has been read into memory and
  238. // is now safe to be removed.
  239. excludes, _ := utils.ReadDockerIgnore(filepath.Join(b.contextPath, ".dockerignore"))
  240. if rm, _ := fileutils.Matches(".dockerignore", excludes); rm == true {
  241. os.Remove(filepath.Join(b.contextPath, ".dockerignore"))
  242. b.context.(tarsum.BuilderContext).Remove(".dockerignore")
  243. }
  244. if rm, _ := fileutils.Matches(b.dockerfileName, excludes); rm == true {
  245. os.Remove(filepath.Join(b.contextPath, b.dockerfileName))
  246. b.context.(tarsum.BuilderContext).Remove(b.dockerfileName)
  247. }
  248. return nil
  249. }
  250. // determine if build arg is part of built-in args or user
  251. // defined args in Dockerfile at any point in time.
  252. func (b *builder) isBuildArgAllowed(arg string) bool {
  253. if _, ok := BuiltinAllowedBuildArgs[arg]; ok {
  254. return true
  255. }
  256. if _, ok := b.allowedBuildArgs[arg]; ok {
  257. return true
  258. }
  259. return false
  260. }
  261. // This method is the entrypoint to all statement handling routines.
  262. //
  263. // Almost all nodes will have this structure:
  264. // Child[Node, Node, Node] where Child is from parser.Node.Children and each
  265. // node comes from parser.Node.Next. This forms a "line" with a statement and
  266. // arguments and we process them in this normalized form by hitting
  267. // evaluateTable with the leaf nodes of the command and the Builder object.
  268. //
  269. // ONBUILD is a special case; in this case the parser will emit:
  270. // Child[Node, Child[Node, Node...]] where the first node is the literal
  271. // "onbuild" and the child entrypoint is the command of the ONBUILD statmeent,
  272. // such as `RUN` in ONBUILD RUN foo. There is special case logic in here to
  273. // deal with that, at least until it becomes more of a general concern with new
  274. // features.
  275. func (b *builder) dispatch(ctx context.Context, stepN int, ast *parser.Node) error {
  276. cmd := ast.Value
  277. // To ensure the user is give a decent error message if the platform
  278. // on which the daemon is running does not support a builder command.
  279. if err := platformSupports(strings.ToLower(cmd)); err != nil {
  280. return err
  281. }
  282. attrs := ast.Attributes
  283. original := ast.Original
  284. flags := ast.Flags
  285. strs := []string{}
  286. msg := fmt.Sprintf("Step %d : %s", stepN+1, strings.ToUpper(cmd))
  287. if len(ast.Flags) > 0 {
  288. msg += " " + strings.Join(ast.Flags, " ")
  289. }
  290. if cmd == "onbuild" {
  291. if ast.Next == nil {
  292. return fmt.Errorf("ONBUILD requires at least one argument")
  293. }
  294. ast = ast.Next.Children[0]
  295. strs = append(strs, ast.Value)
  296. msg += " " + ast.Value
  297. if len(ast.Flags) > 0 {
  298. msg += " " + strings.Join(ast.Flags, " ")
  299. }
  300. }
  301. // count the number of nodes that we are going to traverse first
  302. // so we can pre-create the argument and message array. This speeds up the
  303. // allocation of those list a lot when they have a lot of arguments
  304. cursor := ast
  305. var n int
  306. for cursor.Next != nil {
  307. cursor = cursor.Next
  308. n++
  309. }
  310. l := len(strs)
  311. strList := make([]string, n+l)
  312. copy(strList, strs)
  313. msgList := make([]string, n)
  314. var i int
  315. // Append the build-time args to config-environment.
  316. // This allows builder config to override the variables, making the behavior similar to
  317. // a shell script i.e. `ENV foo bar` overrides value of `foo` passed in build
  318. // context. But `ENV foo $foo` will use the value from build context if one
  319. // isn't already been defined by a previous ENV primitive.
  320. // Note, we get this behavior because we know that ProcessWord() will
  321. // stop on the first occurrence of a variable name and not notice
  322. // a subsequent one. So, putting the buildArgs list after the Config.Env
  323. // list, in 'envs', is safe.
  324. envs := b.Config.Env
  325. for key, val := range b.buildArgs {
  326. if !b.isBuildArgAllowed(key) {
  327. // skip build-args that are not in allowed list, meaning they have
  328. // not been defined by an "ARG" Dockerfile command yet.
  329. // This is an error condition but only if there is no "ARG" in the entire
  330. // Dockerfile, so we'll generate any necessary errors after we parsed
  331. // the entire file (see 'leftoverArgs' processing in evaluator.go )
  332. continue
  333. }
  334. envs = append(envs, fmt.Sprintf("%s=%s", key, val))
  335. }
  336. for ast.Next != nil {
  337. ast = ast.Next
  338. var str string
  339. str = ast.Value
  340. if _, ok := replaceEnvAllowed[cmd]; ok {
  341. var err error
  342. str, err = ProcessWord(ast.Value, envs)
  343. if err != nil {
  344. return err
  345. }
  346. }
  347. strList[i+l] = str
  348. msgList[i] = ast.Value
  349. i++
  350. }
  351. msg += " " + strings.Join(msgList, " ")
  352. fmt.Fprintln(b.OutStream, msg)
  353. // XXX yes, we skip any cmds that are not valid; the parser should have
  354. // picked these out already.
  355. if f, ok := evaluateTable[cmd]; ok {
  356. b.BuilderFlags = NewBFlags()
  357. b.BuilderFlags.Args = flags
  358. return f(ctx, b, strList, attrs, original)
  359. }
  360. return fmt.Errorf("Unknown instruction: %s", strings.ToUpper(cmd))
  361. }
  362. // platformSupports is a short-term function to give users a quality error
  363. // message if a Dockerfile uses a command not supported on the platform.
  364. func platformSupports(command string) error {
  365. if runtime.GOOS != "windows" {
  366. return nil
  367. }
  368. switch command {
  369. case "expose", "volume", "user", "stopsignal", "arg":
  370. return fmt.Errorf("The daemon on this platform does not support the command '%s'", command)
  371. }
  372. return nil
  373. }