diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 992691e6ad..6ed3474e7d 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -118,7 +118,7 @@ }, { "ImportPath": "github.com/samalba/dockerclient", - "Rev": "a3241e22d7230854778614ebca9c7f869776c5f0" + "Rev": "c17bc9a62a1e2f966c05987313e187568e2ca894" }, { "ImportPath": "github.com/samuel/go-zookeeper/zk", diff --git a/Godeps/_workspace/src/github.com/samalba/dockerclient/dockerclient.go b/Godeps/_workspace/src/github.com/samalba/dockerclient/dockerclient.go index 399129d69a..96ea37fe38 100644 --- a/Godeps/_workspace/src/github.com/samalba/dockerclient/dockerclient.go +++ b/Godeps/_workspace/src/github.com/samalba/dockerclient/dockerclient.go @@ -21,7 +21,8 @@ const ( ) var ( - ErrNotFound = errors.New("Not found") + ErrImageNotFound = errors.New("Image not found") + ErrNotFound = errors.New("Not found") defaultTimeout = 30 * time.Second ) @@ -103,6 +104,17 @@ func (client *DockerClient) doStreamRequest(method string, path string, in io.Re } if resp.StatusCode == 404 { defer resp.Body.Close() + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, ErrNotFound + } + if len(data) > 0 { + // check if is image not found error + if strings.Index(string(data), "No such image") != -1 { + return nil, ErrImageNotFound + } + return nil, errors.New(string(data)) + } return nil, ErrNotFound } if resp.StatusCode >= 400 { diff --git a/Godeps/_workspace/src/github.com/samalba/dockerclient/types.go b/Godeps/_workspace/src/github.com/samalba/dockerclient/types.go index 8707bfec42..61badef7c1 100644 --- a/Godeps/_workspace/src/github.com/samalba/dockerclient/types.go +++ b/Godeps/_workspace/src/github.com/samalba/dockerclient/types.go @@ -23,7 +23,6 @@ type ContainerConfig struct { Cmd []string Image string Volumes map[string]struct{} - VolumeDriver string WorkingDir string Entrypoint []string NetworkDisabled bool @@ -32,6 +31,9 @@ type ContainerConfig struct { Labels map[string]string StopSignal string + // FIXME: VolumeDriver have been removed since docker 1.9 + VolumeDriver string + // FIXME: The following fields have been removed since API v1.18 Memory int64 MemorySwap int64 @@ -83,6 +85,7 @@ type HostConfig struct { LogConfig LogConfig CgroupParent string ConsoleSize [2]int + VolumeDriver string } type DeviceMapping struct { diff --git a/cluster/engine.go b/cluster/engine.go index 2bd137efd6..aba9f061aa 100644 --- a/cluster/engine.go +++ b/cluster/engine.go @@ -505,7 +505,7 @@ func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool) (* if id, err = client.CreateContainer(&dockerConfig, name); err != nil { // If the error is other than not found, abort immediately. - if err != dockerclient.ErrNotFound || !pullImage { + if err != dockerclient.ErrImageNotFound || !pullImage { return nil, err } // Otherwise, try to pull the image... diff --git a/cluster/engine_test.go b/cluster/engine_test.go index ffbe677f33..eb2bf99350 100644 --- a/cluster/engine_test.go +++ b/cluster/engine_test.go @@ -200,9 +200,9 @@ func TestCreateContainer(t *testing.T) { // Image not found, pullImage == false name = "test2" mockConfig.CpuShares = int64(math.Ceil(float64(config.CpuShares*1024) / float64(mockInfo.NCPU))) - client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrNotFound).Once() + client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrImageNotFound).Once() container, err = engine.Create(config, name, false) - assert.Equal(t, err, dockerclient.ErrNotFound) + assert.Equal(t, err, dockerclient.ErrImageNotFound) assert.Nil(t, container) // Image not found, pullImage == true, and the image can be pulled successfully @@ -210,7 +210,7 @@ func TestCreateContainer(t *testing.T) { id = "id3" mockConfig.CpuShares = int64(math.Ceil(float64(config.CpuShares*1024) / float64(mockInfo.NCPU))) client.On("PullImage", config.Image+":latest", mock.Anything).Return(nil).Once() - client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrNotFound).Once() + client.On("CreateContainer", &mockConfig, name).Return("", dockerclient.ErrImageNotFound).Once() client.On("CreateContainer", &mockConfig, name).Return(id, nil).Once() client.On("ListContainers", true, false, fmt.Sprintf(`{"id":[%q]}`, id)).Return([]dockerclient.Container{{Id: id}}, nil).Once() client.On("ListImages", mock.Anything).Return([]*dockerclient.Image{}, nil).Once() diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index 7e0141aff5..a821e17934 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "regexp" "sort" "strings" "sync" @@ -114,11 +115,14 @@ func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string) container, err := c.createContainer(config, name, false) // fails with image not found, then try to reschedule with soft-image-affinity - if err != nil && strings.HasSuffix(err.Error(), "not found") && !config.HaveNodeConstraint() { - // Check if the image exists in the cluster - // If exists, retry with a soft-image-affinity - if image := c.Image(config.Image); image != nil { - container, err = c.createContainer(config, name, true) + if err != nil { + bImageNotFoundError, _ := regexp.MatchString(`image \S* not found`, err.Error()) + if bImageNotFoundError && !config.HaveNodeConstraint() { + // Check if the image exists in the cluster + // If exists, retry with a soft-image-affinity + if image := c.Image(config.Image); image != nil { + container, err = c.createContainer(config, name, true) + } } } return container, err diff --git a/test/integration/api/run.bats b/test/integration/api/run.bats index 31f86fd2f8..b6f5823764 100644 --- a/test/integration/api/run.bats +++ b/test/integration/api/run.bats @@ -128,3 +128,19 @@ function teardown() { [[ "${output}" != *"unable to find a node that satisfies"* ]] [[ "${output}" == *"busyboxabcde:latest not found"* ]] } + +@test "docker run - with not exist volume driver" { + start_docker_with_busybox 2 + swarm_manage + + # make sure no container exist + run docker_swarm ps -qa + [ "${#lines[@]}" -eq 0 ] + + # run + run docker_swarm run -d --volume-driver=not_exist_volume_driver -v testvolume:/testvolume --name test_container busybox sleep 100 + + # check error message + [ "$status" -ne 0 ] + [[ "${output}" == *"Plugin not found"* ]] +}