mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Make docker build return exit code of build step
If a command during build fails, `docker build` now returns with the exit code of that command. This makes it necessary to change the build api endpoint to return a json object stream.
This commit is contained in:
parent
c4548506c5
commit
b04c6466cd
9 changed files with 168 additions and 82 deletions
10
api.go
10
api.go
|
@ -960,9 +960,17 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm)
|
if version > 1.6 {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
sf := utils.NewStreamFormatter(version > 1.6)
|
||||||
|
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm, sf)
|
||||||
id, err := b.Build(context)
|
id, err := b.Build(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if sf.Used() {
|
||||||
|
w.Write(sf.FormatError(err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return fmt.Errorf("Error build: %s", err)
|
return fmt.Errorf("Error build: %s", err)
|
||||||
}
|
}
|
||||||
if repoName != "" {
|
if repoName != "" {
|
||||||
|
|
45
buildfile.go
45
buildfile.go
|
@ -37,6 +37,7 @@ type buildFile struct {
|
||||||
tmpImages map[string]struct{}
|
tmpImages map[string]struct{}
|
||||||
|
|
||||||
out io.Writer
|
out io.Writer
|
||||||
|
sf *utils.StreamFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) clearTmp(containers map[string]struct{}) {
|
func (b *buildFile) clearTmp(containers map[string]struct{}) {
|
||||||
|
@ -52,7 +53,7 @@ func (b *buildFile) CmdFrom(name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if b.runtime.graph.IsNotExist(err) {
|
if b.runtime.graph.IsNotExist(err) {
|
||||||
remote, tag := utils.ParseRepositoryTag(name)
|
remote, tag := utils.ParseRepositoryTag(name)
|
||||||
if err := b.srv.ImagePull(remote, tag, b.out, utils.NewStreamFormatter(false), nil, nil, true); err != nil {
|
if err := b.srv.ImagePull(remote, tag, b.out, b.sf, nil, nil, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
image, err = b.runtime.repositories.LookupImage(name)
|
image, err = b.runtime.repositories.LookupImage(name)
|
||||||
|
@ -100,7 +101,11 @@ func (b *buildFile) CmdRun(args string) error {
|
||||||
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
|
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if cache != nil {
|
} else if cache != nil {
|
||||||
fmt.Fprintf(b.out, " ---> Using cache\n")
|
if b.sf.Used() {
|
||||||
|
b.out.Write(b.sf.FormatStatus("", " ---> Using cache"))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b.out, " ---> Using cache\n")
|
||||||
|
}
|
||||||
utils.Debugf("[BUILDER] Use cached version")
|
utils.Debugf("[BUILDER] Use cached version")
|
||||||
b.image = cache.ID
|
b.image = cache.ID
|
||||||
return nil
|
return nil
|
||||||
|
@ -376,8 +381,11 @@ func (b *buildFile) run() (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
b.tmpContainers[c.ID] = struct{}{}
|
b.tmpContainers[c.ID] = struct{}{}
|
||||||
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
|
if b.sf.Used() {
|
||||||
|
b.out.Write(b.sf.FormatStatus("", " ---> Running in %s", utils.TruncateID(c.ID)))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
|
||||||
|
}
|
||||||
// override the entry point that may have been picked up from the base image
|
// override the entry point that may have been picked up from the base image
|
||||||
c.Path = b.config.Cmd[0]
|
c.Path = b.config.Cmd[0]
|
||||||
c.Args = b.config.Cmd[1:]
|
c.Args = b.config.Cmd[1:]
|
||||||
|
@ -403,7 +411,11 @@ func (b *buildFile) run() (string, error) {
|
||||||
|
|
||||||
// Wait for it to finish
|
// Wait for it to finish
|
||||||
if ret := c.Wait(); ret != 0 {
|
if ret := c.Wait(); ret != 0 {
|
||||||
return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
|
err := &utils.JSONError{
|
||||||
|
Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.config.Cmd, ret),
|
||||||
|
Code: ret,
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ID, nil
|
return c.ID, nil
|
||||||
|
@ -424,7 +436,11 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
||||||
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
|
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if cache != nil {
|
} else if cache != nil {
|
||||||
fmt.Fprintf(b.out, " ---> Using cache\n")
|
if b.sf.Used() {
|
||||||
|
b.out.Write(b.sf.FormatStatus("", " ---> Using cache"))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b.out, " ---> Using cache\n")
|
||||||
|
}
|
||||||
utils.Debugf("[BUILDER] Use cached version")
|
utils.Debugf("[BUILDER] Use cached version")
|
||||||
b.image = cache.ID
|
b.image = cache.ID
|
||||||
return nil
|
return nil
|
||||||
|
@ -441,7 +457,11 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
||||||
fmt.Fprintf(b.out, " ---> [Warning] %s\n", warning)
|
fmt.Fprintf(b.out, " ---> [Warning] %s\n", warning)
|
||||||
}
|
}
|
||||||
b.tmpContainers[container.ID] = struct{}{}
|
b.tmpContainers[container.ID] = struct{}{}
|
||||||
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
|
if b.sf.Used() {
|
||||||
|
b.out.Write(b.sf.FormatStatus("", " ---> Running in %s", utils.TruncateID(container.ID)))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
|
||||||
|
}
|
||||||
id = container.ID
|
id = container.ID
|
||||||
if err := container.EnsureMounted(); err != nil {
|
if err := container.EnsureMounted(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -507,22 +527,22 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
|
||||||
|
|
||||||
method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
|
method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
|
||||||
if !exists {
|
if !exists {
|
||||||
fmt.Fprintf(b.out, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction))
|
b.out.Write(b.sf.FormatStatus("", "# Skipping unknown instruction %s", strings.ToUpper(instruction)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
stepN += 1
|
stepN += 1
|
||||||
fmt.Fprintf(b.out, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments)
|
b.out.Write(b.sf.FormatStatus("", "Step %d : %s %s", stepN, strings.ToUpper(instruction), arguments))
|
||||||
|
|
||||||
ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
|
ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
|
||||||
if ret != nil {
|
if ret != nil {
|
||||||
return "", ret.(error)
|
return "", ret.(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image))
|
b.out.Write(b.sf.FormatStatus("", " ---> %s", utils.TruncateID(b.image)))
|
||||||
}
|
}
|
||||||
if b.image != "" {
|
if b.image != "" {
|
||||||
fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image))
|
b.out.Write(b.sf.FormatStatus("", "Successfully built %s", utils.TruncateID(b.image)))
|
||||||
if b.rm {
|
if b.rm {
|
||||||
b.clearTmp(b.tmpContainers)
|
b.clearTmp(b.tmpContainers)
|
||||||
}
|
}
|
||||||
|
@ -531,7 +551,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
|
||||||
return "", fmt.Errorf("An error occurred during the build\n")
|
return "", fmt.Errorf("An error occurred during the build\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache, rm bool) BuildFile {
|
func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache, rm bool, sf *utils.StreamFormatter) BuildFile {
|
||||||
return &buildFile{
|
return &buildFile{
|
||||||
runtime: srv.runtime,
|
runtime: srv.runtime,
|
||||||
srv: srv,
|
srv: srv,
|
||||||
|
@ -542,5 +562,6 @@ func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache, rm bool) Bu
|
||||||
verbose: verbose,
|
verbose: verbose,
|
||||||
utilizeCache: utilizeCache,
|
utilizeCache: utilizeCache,
|
||||||
rm: rm,
|
rm: rm,
|
||||||
|
sf: sf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
commands.go
46
commands.go
|
@ -220,42 +220,16 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
if *rm {
|
if *rm {
|
||||||
v.Set("rm", "1")
|
v.Set("rm", "1")
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest("POST", fmt.Sprintf("/v%g/build?%s", APIVERSION, v.Encode()), body)
|
|
||||||
if err != nil {
|
headers := http.Header(make(map[string][]string))
|
||||||
return err
|
|
||||||
}
|
|
||||||
if context != nil {
|
if context != nil {
|
||||||
req.Header.Set("Content-Type", "application/tar")
|
headers.Set("Content-Type", "application/tar")
|
||||||
}
|
}
|
||||||
dial, err := net.Dial(cli.proto, cli.addr)
|
err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
|
||||||
if err != nil {
|
if jerr, ok := err.(*utils.JSONError); ok {
|
||||||
return err
|
return &utils.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
||||||
}
|
}
|
||||||
clientconn := httputil.NewClientConn(dial, nil)
|
return err
|
||||||
resp, err := clientconn.Do(req)
|
|
||||||
defer clientconn.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
// Check for errors
|
|
||||||
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(body) == 0 {
|
|
||||||
return fmt.Errorf("Error: %s", http.StatusText(resp.StatusCode))
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Error: %s", body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the result
|
|
||||||
if _, err := io.Copy(cli.out, resp.Body); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'docker login': login / register a user to registry service.
|
// 'docker login': login / register a user to registry service.
|
||||||
|
@ -699,7 +673,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "]")
|
fmt.Fprintf(cli.out, "]")
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
return &utils.StatusError{Status: status}
|
return &utils.StatusError{StatusCode: status}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1584,7 +1558,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
return &utils.StatusError{Status: status}
|
return &utils.StatusError{StatusCode: status}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -2167,7 +2141,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
return &utils.StatusError{Status: status}
|
return &utils.StatusError{StatusCode: status}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,10 @@ func main() {
|
||||||
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
|
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
|
||||||
if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil {
|
if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil {
|
||||||
if sterr, ok := err.(*utils.StatusError); ok {
|
if sterr, ok := err.(*utils.StatusError); ok {
|
||||||
os.Exit(sterr.Status)
|
if sterr.Status != "" {
|
||||||
|
log.Println(sterr.Status)
|
||||||
|
}
|
||||||
|
os.Exit(sterr.StatusCode)
|
||||||
}
|
}
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,11 @@ What's new
|
||||||
This URI no longer exists. The ``images -viz`` output is now generated in
|
This URI no longer exists. The ``images -viz`` output is now generated in
|
||||||
the client, using the ``/images/json`` data.
|
the client, using the ``/images/json`` data.
|
||||||
|
|
||||||
|
.. http:post:: /build
|
||||||
|
|
||||||
|
**New!** This endpoint now returns build status as json stream. In case
|
||||||
|
of a build error, it returns the exit status of the failed command.
|
||||||
|
|
||||||
v1.6
|
v1.6
|
||||||
****
|
****
|
||||||
|
|
||||||
|
|
|
@ -990,9 +990,11 @@ Build an image from Dockerfile via stdin
|
||||||
.. sourcecode:: http
|
.. sourcecode:: http
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
{{ STREAM }}
|
{"status":"Step 1..."}
|
||||||
|
{"status":"..."}
|
||||||
|
{"error":"Error...", "errorDetail":{"code": 123, "message": "Error..."}}
|
||||||
|
|
||||||
The stream must be a tar archive compressed with one of the
|
The stream must be a tar archive compressed with one of the
|
||||||
following algorithms: identity (no compression), gzip, bzip2,
|
following algorithms: identity (no compression), gzip, bzip2,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/dotcloud/docker"
|
"github.com/dotcloud/docker"
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/dotcloud/docker/archive"
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/dotcloud/docker/engine"
|
||||||
|
"github.com/dotcloud/docker/utils"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -226,11 +227,14 @@ func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
for _, ctx := range testContexts {
|
for _, ctx := range testContexts {
|
||||||
buildImage(ctx, t, nil, true)
|
_, err := buildImage(ctx, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, useCache bool) *docker.Image {
|
func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, useCache bool) (*docker.Image, error) {
|
||||||
if eng == nil {
|
if eng == nil {
|
||||||
eng = NewTestEngine(t)
|
eng = NewTestEngine(t)
|
||||||
runtime := mkRuntimeFromEngine(eng, t)
|
runtime := mkRuntimeFromEngine(eng, t)
|
||||||
|
@ -262,25 +266,24 @@ func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, u
|
||||||
}
|
}
|
||||||
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
||||||
|
|
||||||
buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, useCache, false)
|
buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, useCache, false, utils.NewStreamFormatter(false))
|
||||||
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
img, err := srv.ImageInspect(id)
|
return srv.ImageInspect(id)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return img
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVolume(t *testing.T) {
|
func TestVolume(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
volume /test
|
volume /test
|
||||||
cmd Hello world
|
cmd Hello world
|
||||||
`, nil, nil}, t, nil, true)
|
`, nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(img.Config.Volumes) == 0 {
|
if len(img.Config.Volumes) == 0 {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -293,10 +296,13 @@ func TestVolume(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildMaintainer(t *testing.T) {
|
func TestBuildMaintainer(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
maintainer dockerio
|
maintainer dockerio
|
||||||
`, nil, nil}, t, nil, true)
|
`, nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if img.Author != "dockerio" {
|
if img.Author != "dockerio" {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -304,10 +310,13 @@ func TestBuildMaintainer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildUser(t *testing.T) {
|
func TestBuildUser(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
user dockerio
|
user dockerio
|
||||||
`, nil, nil}, t, nil, true)
|
`, nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if img.Config.User != "dockerio" {
|
if img.Config.User != "dockerio" {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -315,11 +324,15 @@ func TestBuildUser(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildEnv(t *testing.T) {
|
func TestBuildEnv(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
env port 4243
|
env port 4243
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, nil, true)
|
nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
hasEnv := false
|
hasEnv := false
|
||||||
for _, envVar := range img.Config.Env {
|
for _, envVar := range img.Config.Env {
|
||||||
if envVar == "port=4243" {
|
if envVar == "port=4243" {
|
||||||
|
@ -333,11 +346,14 @@ func TestBuildEnv(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildCmd(t *testing.T) {
|
func TestBuildCmd(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
cmd ["/bin/echo", "Hello World"]
|
cmd ["/bin/echo", "Hello World"]
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, nil, true)
|
nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if img.Config.Cmd[0] != "/bin/echo" {
|
if img.Config.Cmd[0] != "/bin/echo" {
|
||||||
t.Log(img.Config.Cmd[0])
|
t.Log(img.Config.Cmd[0])
|
||||||
|
@ -350,11 +366,14 @@ func TestBuildCmd(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildExpose(t *testing.T) {
|
func TestBuildExpose(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
expose 4243
|
expose 4243
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, nil, true)
|
nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if img.Config.PortSpecs[0] != "4243" {
|
if img.Config.PortSpecs[0] != "4243" {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -362,11 +381,14 @@ func TestBuildExpose(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildEntrypoint(t *testing.T) {
|
func TestBuildEntrypoint(t *testing.T) {
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
entrypoint ["/bin/echo"]
|
entrypoint ["/bin/echo"]
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, nil, true)
|
nil, nil}, t, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if img.Config.Entrypoint[0] != "/bin/echo" {
|
if img.Config.Entrypoint[0] != "/bin/echo" {
|
||||||
}
|
}
|
||||||
|
@ -378,19 +400,25 @@ func TestBuildEntrypointRunCleanup(t *testing.T) {
|
||||||
eng := NewTestEngine(t)
|
eng := NewTestEngine(t)
|
||||||
defer nuke(mkRuntimeFromEngine(eng, t))
|
defer nuke(mkRuntimeFromEngine(eng, t))
|
||||||
|
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
run echo "hello"
|
run echo "hello"
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, eng, true)
|
nil, nil}, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
img = buildImage(testContextTemplate{`
|
img, err = buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
run echo "hello"
|
run echo "hello"
|
||||||
add foo /foo
|
add foo /foo
|
||||||
entrypoint ["/bin/echo"]
|
entrypoint ["/bin/echo"]
|
||||||
`,
|
`,
|
||||||
[][2]string{{"foo", "HEYO"}}, nil}, t, eng, true)
|
[][2]string{{"foo", "HEYO"}}, nil}, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(img.Config.Cmd) != 0 {
|
if len(img.Config.Cmd) != 0 {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -407,11 +435,18 @@ func TestBuildImageWithCache(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
nil, nil}
|
nil, nil}
|
||||||
|
|
||||||
img := buildImage(template, t, eng, true)
|
img, err := buildImage(template, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
imageId := img.ID
|
imageId := img.ID
|
||||||
|
|
||||||
img = nil
|
img = nil
|
||||||
img = buildImage(template, t, eng, true)
|
img, err = buildImage(template, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if imageId != img.ID {
|
if imageId != img.ID {
|
||||||
t.Logf("Image ids should match: %s != %s", imageId, img.ID)
|
t.Logf("Image ids should match: %s != %s", imageId, img.ID)
|
||||||
|
@ -429,11 +464,17 @@ func TestBuildImageWithoutCache(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
nil, nil}
|
nil, nil}
|
||||||
|
|
||||||
img := buildImage(template, t, eng, true)
|
img, err := buildImage(template, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
imageId := img.ID
|
imageId := img.ID
|
||||||
|
|
||||||
img = nil
|
img = nil
|
||||||
img = buildImage(template, t, eng, false)
|
img, err = buildImage(template, t, eng, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if imageId == img.ID {
|
if imageId == img.ID {
|
||||||
t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
|
t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
|
||||||
|
@ -475,7 +516,7 @@ func TestForbiddenContextPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
||||||
|
|
||||||
buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, true, false)
|
buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, true, false, utils.NewStreamFormatter(false))
|
||||||
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -521,7 +562,7 @@ func TestBuildADDFileNotFound(t *testing.T) {
|
||||||
}
|
}
|
||||||
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
||||||
|
|
||||||
buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, false, true, false)
|
buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, false, true, false, utils.NewStreamFormatter(false))
|
||||||
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -539,18 +580,26 @@ func TestBuildInheritance(t *testing.T) {
|
||||||
eng := NewTestEngine(t)
|
eng := NewTestEngine(t)
|
||||||
defer nuke(mkRuntimeFromEngine(eng, t))
|
defer nuke(mkRuntimeFromEngine(eng, t))
|
||||||
|
|
||||||
img := buildImage(testContextTemplate{`
|
img, err := buildImage(testContextTemplate{`
|
||||||
from {IMAGE}
|
from {IMAGE}
|
||||||
expose 4243
|
expose 4243
|
||||||
`,
|
`,
|
||||||
nil, nil}, t, eng, true)
|
nil, nil}, t, eng, true)
|
||||||
|
|
||||||
img2 := buildImage(testContextTemplate{fmt.Sprintf(`
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
img2, _ := buildImage(testContextTemplate{fmt.Sprintf(`
|
||||||
from %s
|
from %s
|
||||||
entrypoint ["/bin/echo"]
|
entrypoint ["/bin/echo"]
|
||||||
`, img.ID),
|
`, img.ID),
|
||||||
nil, nil}, t, eng, true)
|
nil, nil}, t, eng, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// from child
|
// from child
|
||||||
if img2.Config.Entrypoint[0] != "/bin/echo" {
|
if img2.Config.Entrypoint[0] != "/bin/echo" {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -561,3 +610,23 @@ func TestBuildInheritance(t *testing.T) {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildFails(t *testing.T) {
|
||||||
|
_, err := buildImage(testContextTemplate{`
|
||||||
|
from {IMAGE}
|
||||||
|
run sh -c "exit 23"
|
||||||
|
`,
|
||||||
|
nil, nil}, t, nil, true)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Error should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
sterr, ok := err.(*utils.JSONError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Error should be utils.JSONError")
|
||||||
|
}
|
||||||
|
if sterr.Code != 23 {
|
||||||
|
t.Fatalf("StatusCode %d unexpected, should be 23", sterr.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -905,9 +905,12 @@ run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
}
|
}
|
||||||
image := buildImage(testBuilder, t, eng, true)
|
image, err := buildImage(testBuilder, t, eng, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
err := mkServerFromEngine(eng, t).ContainerTag(image.ID, "test", "latest", false)
|
err = mkServerFromEngine(eng, t).ContainerTag(image.ID, "test", "latest", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1184,11 +1184,12 @@ func (graph *DependencyGraph) GenerateTraversalMap() ([][]string, error) {
|
||||||
|
|
||||||
// An StatusError reports an unsuccessful exit by a command.
|
// An StatusError reports an unsuccessful exit by a command.
|
||||||
type StatusError struct {
|
type StatusError struct {
|
||||||
Status int
|
Status string
|
||||||
|
StatusCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *StatusError) Error() string {
|
func (e *StatusError) Error() string {
|
||||||
return fmt.Sprintf("Status: %d", e.Status)
|
return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func quote(word string, buf *bytes.Buffer) {
|
func quote(word string, buf *bytes.Buffer) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue