Fix image pull bug (wait until download finishes)

Signed-off-by: Nishant Totla <nishanttotla@gmail.com>
This commit is contained in:
Nishant Totla 2016-04-01 15:27:18 -07:00
parent 2363ea8077
commit ff0c79e08d
No known key found for this signature in database
GPG Key ID: 7EA5781C9B3D0C19
3 changed files with 36 additions and 19 deletions

View File

@ -2,6 +2,7 @@ package cluster
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
@ -952,40 +953,54 @@ func (e *Engine) CreateVolume(request *types.VolumeCreateRequest) (*Volume, erro
}
// FIXME: This will become unnecessary after docker/engine-api#162 is merged
func getTagFromNamedRef(dref reference.Named) string {
var tag string
switch x := dref.(type) {
case reference.Digested:
func buildImagePullOptions(image string) (types.ImagePullOptions, error) {
distributionRef, err := reference.ParseNamed(image)
if err != nil {
return types.ImagePullOptions{}, err
}
name := distributionRef.Name()
tag := "latest"
switch x := distributionRef.(type) {
case reference.Canonical:
tag = x.Digest().String()
case reference.NamedTagged:
tag = x.Tag()
}
return tag
return types.ImagePullOptions{
ImageID: name,
Tag: tag,
}, nil
}
// Pull an image on the engine
func (e *Engine) Pull(image string, authConfig *types.AuthConfig) error {
distributionRef, err := reference.ParseNamed(image)
pullOpts, err := buildImagePullOptions(image)
if err != nil {
return err
}
repository := distributionRef.Name()
tag := getTagFromNamedRef(distributionRef)
pullOpts := types.ImagePullOptions{
ImageID: repository,
Tag: tag,
}
_, err = e.apiClient.ImagePull(context.TODO(), pullOpts, nil)
pullResponse, err := e.apiClient.ImagePull(context.TODO(), pullOpts, nil)
e.CheckConnectionErr(err)
if err != nil {
return err
}
// wait until the image download is finished
dec := json.NewDecoder(pullResponse)
for {
m := map[string]interface{}{}
if err := dec.Decode(&m); err != nil {
if err == io.EOF {
break
}
return err
}
}
// force refresh images
e.RefreshImages()
return nil
}

View File

@ -293,7 +293,7 @@ func TestCreateContainer(t *testing.T) {
engine = NewEngine("test", 0, engOpts)
client = mockclient.NewMockClient()
apiClient = engineapimock.NewMockClient()
readCloser = nopCloser{bytes.NewBufferString("ok")}
readCloser = nopCloser{bytes.NewBufferString("")}
)
engine.setState(stateUnhealthy)
@ -346,7 +346,7 @@ func TestCreateContainer(t *testing.T) {
id = "id3"
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
mockConfig.CPUShares = int64(math.Ceil(float64(config.CPUShares*1024) / float64(mockInfo.NCPU)))
apiClient.On("ImagePull", mock.Anything, types.ImagePullOptions{ImageID: config.Image}, mock.Anything).Return(readCloser, nil).Once()
apiClient.On("ImagePull", mock.Anything, types.ImagePullOptions{ImageID: config.Image, Tag: "latest"}, mock.Anything).Return(readCloser, nil).Once()
// FIXMEENGINEAPI : below should return an engine-api error, or something custom
apiClient.On("ContainerCreate", mock.Anything, &mockConfig.Config, &mockConfig.HostConfig, &mockConfig.NetworkingConfig, name).Return(types.ContainerCreateResponse{}, dockerclient.ErrImageNotFound).Once()
// FIXMEENGINEAPI : below should return an engine-api error, or something custom

View File

@ -14,6 +14,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/discovery"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
containertypes "github.com/docker/engine-api/types/container"
networktypes "github.com/docker/engine-api/types/network"
@ -148,8 +149,9 @@ func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string,
if err != nil {
var retries int64
// fails with image not found, then try to reschedule with image affinity
// ENGINEAPIFIXME: The first error can be removed once dockerclient is removed
bImageNotFoundError, _ := regexp.MatchString(`image \S* not found`, err.Error())
if bImageNotFoundError && !config.HaveNodeConstraint() {
if (bImageNotFoundError || client.IsErrImageNotFound(err)) && !config.HaveNodeConstraint() {
// Check if the image exists in the cluster
// If exists, retry with a image affinity
if c.Image(config.Image) != nil {