driver/docker: pull image with digest
GH #4290 Add digest support to the docker driver image config. This commit factors out some common code to print the repo:tag (dockerImageRef) for events/logs as well as parsing the image to retreive the repo,tag (parseDockerImage) so that the results are consistent/sane for both repo:tag and repo@sha256:... references. When pulling an image with a digest, the tag is blank and the repo contains the digest. See: https://github.com/fsouza/go-dockerclient/blob/master/image_test.go#L471
This commit is contained in:
parent
cbd2b77c6c
commit
60f7f1aa08
|
@ -1500,10 +1500,7 @@ func (d *DockerDriver) Periodic() (bool, time.Duration) {
|
|||
// loading it from the file system
|
||||
func (d *DockerDriver) createImage(driverConfig *DockerDriverConfig, client *docker.Client, taskDir *allocdir.TaskDir) (string, error) {
|
||||
image := driverConfig.ImageName
|
||||
repo, tag := docker.ParseRepositoryTag(image)
|
||||
if tag == "" {
|
||||
tag = "latest"
|
||||
}
|
||||
repo, tag := parseDockerImage(image)
|
||||
|
||||
coordinator, callerID := d.getDockerCoordinator(client)
|
||||
|
||||
|
@ -1511,7 +1508,7 @@ func (d *DockerDriver) createImage(driverConfig *DockerDriverConfig, client *doc
|
|||
// is "latest", or ForcePull is set, we have to check for a new version every time so we don't
|
||||
// bother to check and cache the id here. We'll download first, then cache.
|
||||
if driverConfig.ForcePull {
|
||||
d.logger.Printf("[DEBUG] driver.docker: force pull image '%s:%s' instead of inspecting local", repo, tag)
|
||||
d.logger.Printf("[DEBUG] driver.docker: force pull image '%s' instead of inspecting local", dockerImageRef(repo, tag))
|
||||
} else if tag != "latest" {
|
||||
if dockerImage, _ := client.InspectImage(image); dockerImage != nil {
|
||||
// Image exists so just increment its reference count
|
||||
|
@ -1544,7 +1541,7 @@ func (d *DockerDriver) pullImage(driverConfig *DockerDriverConfig, client *docke
|
|||
d.logger.Printf("[DEBUG] driver.docker: did not find docker auth for repo %q", repo)
|
||||
}
|
||||
|
||||
d.emitEvent("Downloading image %s:%s", repo, tag)
|
||||
d.emitEvent("Downloading image %s", dockerImageRef(repo, tag))
|
||||
coordinator, callerID := d.getDockerCoordinator(client)
|
||||
|
||||
return coordinator.PullImage(driverConfig.ImageName, authOptions, callerID, d.emitEvent)
|
||||
|
@ -2183,3 +2180,24 @@ type createContainerClient interface {
|
|||
ListContainers(docker.ListContainersOptions) ([]docker.APIContainers, error)
|
||||
RemoveContainer(opts docker.RemoveContainerOptions) error
|
||||
}
|
||||
|
||||
func parseDockerImage(image string) (repo, tag string) {
|
||||
repo, tag = docker.ParseRepositoryTag(image)
|
||||
if tag == "" {
|
||||
if i := strings.IndexRune(image, '@'); i > -1 { // Has digest (@sha256:...)
|
||||
// when pulling images with a digest, the repository contains the sha hash, and the tag is empty
|
||||
// see: https://github.com/fsouza/go-dockerclient/blob/master/image_test.go#L471
|
||||
repo = image
|
||||
} else {
|
||||
tag = "latest"
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func dockerImageRef(repo string, tag string) string {
|
||||
if tag == "" {
|
||||
return repo
|
||||
}
|
||||
return fmt.Sprintf("%s:%s", repo, tag)
|
||||
}
|
||||
|
|
|
@ -178,10 +178,7 @@ func (d *dockerCoordinator) PullImage(image string, authOptions *docker.AuthConf
|
|||
func (d *dockerCoordinator) pullImageImpl(image string, authOptions *docker.AuthConfiguration, future *pullFuture) {
|
||||
defer d.clearPullLogger(image)
|
||||
// Parse the repo and tag
|
||||
repo, tag := docker.ParseRepositoryTag(image)
|
||||
if tag == "" {
|
||||
tag = "latest"
|
||||
}
|
||||
repo, tag := parseDockerImage(image)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
|
@ -206,18 +203,18 @@ func (d *dockerCoordinator) pullImageImpl(image string, authOptions *docker.Auth
|
|||
err := d.client.PullImage(pullOptions, auth)
|
||||
|
||||
if ctxErr := ctx.Err(); ctxErr == context.DeadlineExceeded {
|
||||
d.logger.Printf("[ERR] driver.docker: timeout pulling container %s:%s", repo, tag)
|
||||
d.logger.Printf("[ERR] driver.docker: timeout pulling container %s", dockerImageRef(repo, tag))
|
||||
future.set("", recoverablePullError(ctxErr, image))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
d.logger.Printf("[ERR] driver.docker: failed pulling container %s:%s: %s", repo, tag, err)
|
||||
d.logger.Printf("[ERR] driver.docker: failed pulling container %s: %s", dockerImageRef(repo, tag), err)
|
||||
future.set("", recoverablePullError(err, image))
|
||||
return
|
||||
}
|
||||
|
||||
d.logger.Printf("[DEBUG] driver.docker: docker pull %s:%s succeeded", repo, tag)
|
||||
d.logger.Printf("[DEBUG] driver.docker: docker pull %s succeeded", dockerImageRef(repo, tag))
|
||||
|
||||
dockerImage, err := d.client.InspectImage(image)
|
||||
if err != nil {
|
||||
|
|
|
@ -1092,6 +1092,30 @@ func TestDockerDriver_ForcePull(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDockerDriver_ForcePull_RepoDigest(t *testing.T) {
|
||||
if !tu.IsTravis() {
|
||||
t.Parallel()
|
||||
}
|
||||
if !testutil.DockerIsConnected(t) {
|
||||
t.Skip("Docker not connected")
|
||||
}
|
||||
|
||||
task, _, _ := dockerTask(t)
|
||||
task.Config["load"] = ""
|
||||
task.Config["image"] = "library/busybox@sha256:58ac43b2cc92c687a32c8be6278e50a063579655fe3090125dcb2af0ff9e1a64"
|
||||
task.Config["force_pull"] = "true"
|
||||
|
||||
client, handle, cleanup := dockerSetup(t, task)
|
||||
defer cleanup()
|
||||
|
||||
waitForExist(t, client, handle)
|
||||
|
||||
_, err := client.InspectContainer(handle.ContainerID())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDockerDriver_SecurityOpt(t *testing.T) {
|
||||
if !tu.IsTravis() {
|
||||
t.Parallel()
|
||||
|
@ -2458,3 +2482,27 @@ func TestDockerDriver_AdvertiseIPv6Address(t *testing.T) {
|
|||
t.Fatalf("Got GlobalIPv6address %s want GlobalIPv6address with prefix %s", expectedPrefix, container.NetworkSettings.GlobalIPv6Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDockerImage(t *testing.T) {
|
||||
tests := []struct {
|
||||
Image string
|
||||
Repo string
|
||||
Tag string
|
||||
}{
|
||||
{"library/hello-world:1.0", "library/hello-world", "1.0"},
|
||||
{"library/hello-world", "library/hello-world", "latest"},
|
||||
{"library/hello-world:latest", "library/hello-world", "latest"},
|
||||
{"library/hello-world@sha256:f5233545e43561214ca4891fd1157e1c3c563316ed8e237750d59bde73361e77", "library/hello-world@sha256:f5233545e43561214ca4891fd1157e1c3c563316ed8e237750d59bde73361e77", ""},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.Image, func(t *testing.T) {
|
||||
repo, tag := parseDockerImage(test.Image)
|
||||
if repo != test.Repo {
|
||||
t.Errorf("expected repo '%s' but got '%s'", test.Repo, repo)
|
||||
}
|
||||
if repo != test.Repo {
|
||||
t.Errorf("expected tag '%s' but got '%s'", test.Tag, tag)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue