diff --git a/api/handlers.go b/api/handlers.go index 45d55bd332..f9400c08c9 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -459,10 +459,20 @@ func postImagesCreate(c *context, w http.ResponseWriter, r *http.Request) { repo := r.Form.Get("repo") tag := r.Form.Get("tag") - callback := func(what, status string) { + errorFound := false + callback := func(what, status string, err error) { + if err != nil { + errorFound = true + sendJSONMessage(wf, what, err.Error()) + return + } sendJSONMessage(wf, what, status) } c.cluster.Import(source, repo, tag, r.Body, callback) + if errorFound { + sendErrorJSONMessage(wf, 1, "") + } + } } @@ -473,7 +483,14 @@ func postImagesLoad(c *context, w http.ResponseWriter, r *http.Request) { // call cluster to load image on every node wf := NewWriteFlusher(w) - callback := func(what, status string) { + errorFound := false + callback := func(what, status string, err error) { + if err != nil { + errorFound = true + sendJSONMessage(wf, what, fmt.Sprintf("Loading Image... : %s", err.Error())) + return + } + if status == "" { sendJSONMessage(wf, what, "Loading Image...") } else { @@ -481,6 +498,10 @@ func postImagesLoad(c *context, w http.ResponseWriter, r *http.Request) { } } c.cluster.Load(r.Body, callback) + if errorFound { + sendErrorJSONMessage(wf, 1, "") + } + } // GET /events diff --git a/cluster/cluster.go b/cluster/cluster.go index 696912c640..074614672e 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -47,13 +47,13 @@ type Cluster interface { // `callback` can be called multiple time // `where` is where it is being imported // `status` is the current status, like "", "in progress" or "imported" - Import(source string, repository string, tag string, imageReader io.Reader, callback func(where, status string)) + Import(source string, repository string, tag string, imageReader io.Reader, callback func(where, status string, err error)) // Load images // `callback` can be called multiple time // `what` is what is being loaded // `status` is the current status, like "", "in progress" or "loaded" - Load(imageReader io.Reader, callback func(what, status string)) + Load(imageReader io.Reader, callback func(what, status string, err error)) // Return some info about the cluster, like nb or containers / images // It is pretty open, so the implementation decides what to return. diff --git a/cluster/mesos/cluster.go b/cluster/mesos/cluster.go index c7bf14b56e..146208d1a7 100644 --- a/cluster/mesos/cluster.go +++ b/cluster/mesos/cluster.go @@ -275,12 +275,12 @@ func (c *Cluster) Pull(name string, authConfig *dockerclient.AuthConfig, callbac } // Load images -func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string)) { +func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string, err error)) { } // Import image -func (c *Cluster) Import(source string, repository string, tag string, imageReader io.Reader, callback func(what, status string)) { +func (c *Cluster) Import(source string, repository string, tag string, imageReader io.Reader, callback func(what, status string, err error)) { } diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index a8c60e29cd..481f117a18 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -325,7 +325,7 @@ func (c *Cluster) Pull(name string, authConfig *dockerclient.AuthConfig, callbac } // Load image -func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string)) { +func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string, err error)) { var wg sync.WaitGroup c.RLock() @@ -344,7 +344,7 @@ func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string err := engine.Load(reader) if callback != nil { if err != nil { - callback(engine.Name, err.Error()) + callback(engine.Name, "", err) } } }(pipeReader, e) @@ -373,7 +373,7 @@ func (c *Cluster) Load(imageReader io.Reader, callback func(where, status string } // Import image -func (c *Cluster) Import(source string, repository string, tag string, imageReader io.Reader, callback func(what, status string)) { +func (c *Cluster) Import(source string, repository string, tag string, imageReader io.Reader, callback func(what, status string, err error)) { var wg sync.WaitGroup c.RLock() pipeWriters := []*io.PipeWriter{} @@ -392,9 +392,9 @@ func (c *Cluster) Import(source string, repository string, tag string, imageRead err := engine.Import(source, repository, tag, reader) if callback != nil { if err != nil { - callback(engine.Name, err.Error()) + callback(engine.Name, "", err) } else { - callback(engine.Name, "Import success") + callback(engine.Name, "Import success", nil) } } diff --git a/cluster/swarm/cluster_test.go b/cluster/swarm/cluster_test.go index 0ba68830ee..0efa96fedb 100644 --- a/cluster/swarm/cluster_test.go +++ b/cluster/swarm/cluster_test.go @@ -142,9 +142,9 @@ func TestImportImage(t *testing.T) { readCloser := nopCloser{bytes.NewBufferString("ok")} client.On("ImportImage", mock.Anything, mock.Anything, mock.Anything, mock.AnythingOfType("*io.PipeReader")).Return(readCloser, nil).Once() - callback := func(what, status string) { + callback := func(what, status string, err error) { // import success - assert.Equal(t, status, "Import success") + assert.Nil(t, err) } c.Import("-", "testImageOK", "latest", bytes.NewReader(nil), callback) @@ -153,9 +153,9 @@ func TestImportImage(t *testing.T) { err := fmt.Errorf("Import error") client.On("ImportImage", mock.Anything, mock.Anything, mock.Anything, mock.AnythingOfType("*io.PipeReader")).Return(readCloser, err).Once() - callback = func(what, status string) { + callback = func(what, status string, err error) { // import error - assert.Equal(t, status, "Import error") + assert.NotNil(t, err) } c.Import("-", "testImageError", "latest", bytes.NewReader(nil), callback) } @@ -189,18 +189,18 @@ func TestLoadImage(t *testing.T) { // load success client.On("LoadImage", mock.AnythingOfType("*io.PipeReader")).Return(nil).Once() - callback := func(what, status string) { - //if load OK, will not come here - t.Fatalf("Load error") + callback := func(what, status string, err error) { + //if load OK, err will be nil + assert.Nil(t, err) } c.Load(bytes.NewReader(nil), callback) // load error err := fmt.Errorf("Load error") client.On("LoadImage", mock.AnythingOfType("*io.PipeReader")).Return(err).Once() - callback = func(what, status string) { - // load error - assert.Equal(t, status, "Load error") + callback = func(what, status string, err error) { + // load error, err is not nil + assert.NotNil(t, err) } c.Load(bytes.NewReader(nil), callback) } diff --git a/test/integration/api/import.bats b/test/integration/api/import.bats index 48e7508a07..6b21825e95 100644 --- a/test/integration/api/import.bats +++ b/test/integration/api/import.bats @@ -41,3 +41,15 @@ function teardown() { # after ok, delete exported tar file rm -f $temp_file_name } + +@test "docker import - check error code" { + start_docker 2 + swarm_manage + + temp_file=$(mktemp) + + run docker_swarm import - < $temp_file + [ "$status" -eq 1 ] + + rm -f $temp_file +} diff --git a/test/integration/api/load.bats b/test/integration/api/load.bats index 8e1bf502ab..c7f3ed8fae 100644 --- a/test/integration/api/load.bats +++ b/test/integration/api/load.bats @@ -40,3 +40,15 @@ function teardown() { rm -f $IMAGE_FILE } + +@test "docker load - check error code" { + start_docker 2 + swarm_manage + + temp_file=$(mktemp) + + run docker_swarm load -i $temp_file + [ "$status" -eq 1 ] + + rm -f $temp_file +}