Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,3 @@ require (
gopkg.in/ini.v1 v1.63.2
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

replace github.com/containerd/containerd => github.com/containerd/containerd v1.3.1-0.20200227195959-4d242818bf55

replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20200227233006-38f52c9fec82
15 changes: 12 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
github.com/containerd/containerd v1.3.1-0.20200227195959-4d242818bf55/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.1-0.20201117152358-0edc412565dc/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
Expand Down Expand Up @@ -259,8 +263,13 @@ github.com/docker/cli v20.10.0-beta1.0.20201029214301-1d20b15adc38+incompatible/
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20200227233006-38f52c9fec82 h1:kZwwJwYnVWtU/byBNjD9rEGWVMvwnfiKu9lFJXjrk04=
github.com/docker/docker v1.4.2-0.20200227233006-38f52c9fec82/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.0.0-20200511152416-a93e9eb0e95c/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200730172259-9f28837c1d93+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible h1:J2OhsbfqoBRRT048iD/tqXBvEQWQATQ8vew6LqQmDSU=
github.com/docker/docker v20.10.0-beta1.0.20201110211921-af34b94a78a1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/cli/svc_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func (o *initSvcOpts) Execute() error {
if o.dockerfilePath != "" {
hc, err = parseHealthCheck(o.dockerfile(o.dockerfilePath))
if err != nil {
return fmt.Errorf("parse dockerfile %s: %w", o.dockerfilePath, err)
log.Warningf("Cannot parse the HEALTHCHECK instruction from the Dockerfile: %v\n", err)
}
}

Expand Down
60 changes: 27 additions & 33 deletions internal/pkg/docker/dockerfile/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
"strings"
"time"

"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/spf13/afero"
)

Expand All @@ -41,7 +39,6 @@ const (
hcRetriesFlag = "retries"
retriesDefault = 2

hcInstrStartIndex = len("HEALTHCHECK ")
cmdInstructionPrefix = "CMD "
cmdShell = "CMD-SHELL"
)
Expand Down Expand Up @@ -142,7 +139,7 @@ func (df *Dockerfile) parse() error {
return fmt.Errorf("read Dockerfile %s error: %w", f, err)
}

parsedDockerfile, err := parse(string(f))
parsedDockerfile, err := parse(file.Name(), string(f))
if err != nil {
return err
}
Expand All @@ -154,39 +151,29 @@ func (df *Dockerfile) parse() error {
}

// parse parses the contents of a Dockerfile into a Dockerfile struct.
func parse(content string) (*Dockerfile, error) {
func parse(name, content string) (*Dockerfile, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

Suggested change
func parse(name, content string) (*Dockerfile, error) {
func parse(lexer *lexer) (*Dockerfile, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it as is because i removed name from the lexer following Wanxian's comment, so now I'm writing the name information in this function!

var df Dockerfile
df.exposedPorts = []Port{}

ast, err := parser.Parse(strings.NewReader(content))
if err != nil {
return nil, fmt.Errorf("parse reader: %w", err)
}

for _, child := range ast.AST.Children {
// ParseInstruction converts an AST to a typed instruction.
// Does prevalidation checks before parsing
// Example of an instruction is HEALTHCHECK CMD curl -f http://localhost/ || exit 1.
instruction, err := instructions.ParseInstruction(child)
if err != nil {
return nil, fmt.Errorf("parse instructions: %w", err)
}
inst := fmt.Sprint(instruction)

// Getting the value at a children will return the Dockerfile directive
switch d := child.Value; d {
case "expose":
currentPorts := parseExpose(inst)
lexer := lex(strings.NewReader(content))
for {
instr := lexer.next()
switch instr.name {
case instrErr:
return nil, fmt.Errorf("scan Dockerfile %s: %s", name, instr.args)
case instrEOF:
return &df, nil
case instrExpose:
currentPorts := parseExpose(instr.args)
df.exposedPorts = append(df.exposedPorts, currentPorts...)
case "healthcheck":
healthcheckOptions, err := parseHealthCheck(inst)
case instrHealthCheck:
hc, err := parseHealthCheck(instr.args)
if err != nil {
return nil, err
}
df.healthCheck = healthcheckOptions
df.healthCheck = hc
}
}
return &df, nil
}

func parseExpose(line string) []Port {
Expand Down Expand Up @@ -245,24 +232,31 @@ func parseExpose(line string) []Port {

// parseHealthCheck takes a HEALTHCHECK directives and turns into a healthCheck struct.
func parseHealthCheck(content string) (*HealthCheck, error) {
if strings.TrimSpace(content[hcInstrStartIndex:]) == "NONE" {
if strings.ToUpper(strings.TrimSpace(content)) == "NONE" {
return nil, nil
}
if !strings.Contains(content, "CMD") {
return nil, errors.New("HEALTHCHECK instruction must contain either CMD or NONE")
return nil, errors.New("parse HEALTHCHECK: instruction must contain either CMD or NONE")
}

var retries int
var interval, timeout, startPeriod time.Duration
fs := flag.NewFlagSet("flags", flag.ContinueOnError)

fs.DurationVar(&interval, intervalFlag, intervalDefault, "")
fs.DurationVar(&timeout, timeoutFlag, timeoutDefault, "")
fs.DurationVar(&startPeriod, startPeriodFlag, startPeriodDefault, "")
fs.IntVar(&retries, hcRetriesFlag, retriesDefault, "")

if err := fs.Parse(strings.Split(content[hcInstrStartIndex:], " ")); err != nil {
return nil, err
var instrArgs []string
for _, arg := range strings.Split(content, " ") {
if arg == "" {
continue
}
instrArgs = append(instrArgs, strings.TrimSpace(arg))
}

if err := fs.Parse(instrArgs); err != nil {
return nil, fmt.Errorf("parse HEALTHCHECK: %w", err)
}

// if HEALTHCHECK instruction is not "NONE", there must be a "CMD" instruction otherwise will error out.
Expand Down
28 changes: 20 additions & 8 deletions internal/pkg/docker/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package dockerfile

import (
"bytes"
"errors"
"fmt"
"testing"
"time"
Expand Down Expand Up @@ -86,7 +87,7 @@ FROM nginx
EXPOSE $arg
`),
wantedPorts: nil,
wantedErr: ErrInvalidPort{Match: "EXPOSE $arg"},
wantedErr: ErrInvalidPort{Match: "$arg"},
},
"bad expose token multiple ports": {
dockerfilePath: wantedPath,
Expand All @@ -96,7 +97,7 @@ EXPOSE 80
EXPOSE $arg
EXPOSE 8080/tcp 5000`),
wantedPorts: nil,
wantedErr: ErrInvalidPort{Match: "EXPOSE $arg"},
wantedErr: ErrInvalidPort{Match: "$arg"},
},
}

Expand Down Expand Up @@ -158,6 +159,21 @@ HEALTHCHECK CMD curl -f http://localhost/ || exit 1
Cmd: []string{cmdShell, "curl -f http://localhost/ || exit 1"},
},
},
"correctly parses multiline healthcheck": {
dockerfile: []byte(`
FROM nginx
HEALTHCHECK --interval=5m\
--timeout=3s --start-period=2s --retries=3 \
CMD curl -f http://localhost/ || exit 1 `),
wantedErr: nil,
wantedConfig: &HealthCheck{
Interval: 300 * time.Second,
Timeout: 3 * time.Second,
StartPeriod: 2 * time.Second,
Retries: 3,
Cmd: []string{cmdShell, "curl -f http://localhost/ || exit 1"},
},
},
"correctly parses healthcheck with user's values": {
dockerfile: []byte(`
FROM nginx
Expand Down Expand Up @@ -214,15 +230,11 @@ HEALTHCHECK CMD ["a", "b"]
},
"healthcheck contains an invalid flag": {
dockerfile: []byte(`HEALTHCHECK --interval=5m --randomFlag=4s CMD curl -f http://localhost/ || exit 1`),
wantedErr: fmt.Errorf("parse instructions: Unknown flag: randomFlag"),
wantedErr: fmt.Errorf("parse HEALTHCHECK: flag provided but not defined: -randomFlag"),
},
"healthcheck does not contain CMD": {
dockerfile: []byte(`HEALTHCHECK --interval=5m curl -f http://localhost/ || exit 1`),
wantedErr: fmt.Errorf("parse instructions: Unknown type \"CURL\" in HEALTHCHECK (try CMD)"),
},
"healthcheck does not contain command": {
dockerfile: []byte(`HEALTHCHECK --interval=5m CMD`),
wantedErr: fmt.Errorf("parse instructions: Missing command after HEALTHCHECK CMD"),
wantedErr: errors.New("parse HEALTHCHECK: instruction must contain either CMD or NONE"),
},
}

Expand Down
4 changes: 2 additions & 2 deletions internal/pkg/docker/dockerfile/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ErrInvalidPort struct {
}

func (e ErrInvalidPort) Error() string {
return fmt.Sprintf("port represented at %s is invalid or unparseable", e.Match)
return fmt.Sprintf("parse EXPOSE: port represented at %s is invalid or unparseable", e.Match)
}

// ErrNoExpose means there were no documented EXPOSE statements in the given dockerfile.
Expand All @@ -20,5 +20,5 @@ type ErrNoExpose struct {
}

func (e ErrNoExpose) Error() string {
return fmt.Sprintf("no EXPOSE statements in Dockerfile %s", e.Dockerfile)
return fmt.Sprintf("parse EXPOSE: no EXPOSE statements in Dockerfile %s", e.Dockerfile)
}
Loading