diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0b3818..da768655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Unreleased * config: Support for sysctl configuration [[GH-82](https://github.com/hashicorp/nomad-driver-podman/issues/82)] +* config: Fixed a bug where we always pulled an image if image name has a transport prefix [[GH-88](https://github.com/hashicorp/nomad-driver-podman/pull/88)] ## 0.2.0 diff --git a/driver.go b/driver.go index 405f0b16..a49534a6 100644 --- a/driver.go +++ b/driver.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/nomad/plugins/shared/hclspec" pstructs "github.com/hashicorp/nomad/plugins/shared/structs" + dockerref "github.com/docker/distribution/reference" shelpers "github.com/hashicorp/nomad/helper/stats" spec "github.com/opencontainers/runtime-spec/specs-go" ) @@ -472,15 +473,24 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive // FIXME: there are more variations of image sources, we should handle it // e.g. oci-archive:/... etc // see also https://github.com/hashicorp/nomad-driver-podman/issues/69 + + imageName, tag, err := parseImage(createOpts.Image) + if err != nil { + return nil, nil, fmt.Errorf("failed to start task, unable to parse image reference %s: %v", createOpts.Image, err) + } + // do we already have this image in local storage? - haveImage, err := d.podman.ImageExists(d.ctx, createOpts.Image) + haveImage, err := d.podman.ImageExists(d.ctx, fmt.Sprintf("%s:%s", imageName, tag)) if err != nil { - return nil, nil, fmt.Errorf("failed to start task, unable to check for local image: %v", err) + d.logger.Warn("Unable to check for local image", "image", imageName, "err", err) + // do NOT fail this operation, instead try to pull the image + haveImage = false } if !haveImage { + d.logger.Debug("Pull image", "image", imageName) // image is not in local storage, so we need to pull it - if err = d.podman.ImagePull(d.ctx, createOpts.Image); err != nil { - return nil, nil, fmt.Errorf("failed to start task, unable to pull image %s: %v", createOpts.Image, err) + if err = d.podman.ImagePull(d.ctx, imageName); err != nil { + return nil, nil, fmt.Errorf("failed to start task, unable to pull image %s: %v", imageName, err) } } @@ -583,6 +593,36 @@ func memoryInBytes(strmem string) (int64, error) { } } +func parseImage(image string) (string, string, error) { + // strip http/https and docker transport prefix + for _, prefix := range []string{"http://", "https://", "docker://"} { + if strings.HasPrefix(image, prefix) { + image = strings.Replace(image, prefix, "", 1) + } + } + + named, err := dockerref.ParseNormalizedNamed(image) + if err != nil { + return "", "", nil + } + + var tag, digest string + + tagged, ok := named.(dockerref.Tagged) + if ok { + tag = tagged.Tag() + } + + digested, ok := named.(dockerref.Digested) + if ok { + digest = digested.Digest().String() + } + if len(tag) == 0 && len(digest) == 0 { + tag = "latest" + } + return named.Name(), tag, nil +} + // WaitTask function is expected to return a channel that will send an *ExitResult when the task // exits or close the channel when the context is canceled. It is also expected that calling // WaitTask on an exited task will immediately send an *ExitResult on the returned channel. diff --git a/driver_test.go b/driver_test.go index a35e8ed2..47c53ccd 100644 --- a/driver_test.go +++ b/driver_test.go @@ -1341,6 +1341,38 @@ func TestPodmanDriver_Sysctl(t *testing.T) { } +func Test_parseImage(t *testing.T) { + if !tu.IsCI() { + t.Parallel() + } + + testCases := []struct { + Input string + Repo string + Tag string + }{ + {Input: "quay.io/prometheus/busybox:glibc", Repo: "quay.io/prometheus/busybox", Tag: "glibc"}, + {Input: "root", Repo: "docker.io/library/root", Tag: "latest"}, + {Input: "root:tag", Repo: "docker.io/library/root", Tag: "tag"}, + {Input: "docker://root", Repo: "docker.io/library/root", Tag: "latest"}, + {Input: "user/repo", Repo: "docker.io/user/repo", Tag: "latest"}, + {Input: "https://busybox", Repo: "docker.io/library/busybox", Tag: "latest"}, + {Input: "user/repo:tag", Repo: "docker.io/user/repo", Tag: "tag"}, + {Input: "url:5000/repo", Repo: "url:5000/repo", Tag: "latest"}, + {Input: "http://busybox", Repo: "docker.io/library/busybox", Tag: "latest"}, + {Input: "url:5000/repo:tag", Repo: "url:5000/repo", Tag: "tag"}, + {Input: "https://quay.io/busybox", Repo: "quay.io/busybox", Tag: "latest"}, + } + for _, testCase := range testCases { + repo, tag, err := parseImage(testCase.Input) + if err != nil { + t.Errorf("parseImage(%s) failed: %v", testCase.Input, err) + } else if repo != testCase.Repo || tag != testCase.Tag { + t.Errorf("Expected repo: %q, tag: %q, but got %q and %q", testCase.Repo, testCase.Tag, repo, tag) + } + } +} + // read a tasks logfile into a string, fail on error func readLogfile(t *testing.T, task *drivers.TaskConfig) string { logfile := filepath.Join(filepath.Dir(task.StdoutPath), fmt.Sprintf("%s.stdout.0", task.Name)) diff --git a/go.mod b/go.mod index aa7a0c74..f7ac34a1 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,8 @@ require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/container-storage-interface/spec v1.2.0 // indirect github.com/containernetworking/plugins v0.8.5 // indirect + github.com/distribution/distribution v2.7.1+incompatible // indirect + github.com/docker/distribution v2.7.1+incompatible github.com/docker/go-metrics v0.0.1 // indirect github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/go-cmp v0.5.0 // indirect diff --git a/go.sum b/go.sum index c76bd55c..dd6707e5 100644 --- a/go.sum +++ b/go.sum @@ -222,6 +222,8 @@ github.com/digitalocean/godo v1.10.0 h1:uW1/FcvZE/hoixnJcnlmIUvTVNdZCLjRLzmDtRi1 github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/distribution/distribution v2.7.1+incompatible h1:aGFx4EvJWKEh//lHPLwFhFgwFHKH06TzNVPamrMn04M= +github.com/distribution/distribution v2.7.1+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20200303215952-eb310fca4956 h1:5/ZRsUbguX7xFNLlbxVQY/yhD3Psy+vylKZrNme5BJs= github.com/docker/cli v0.0.0-20200303215952-eb310fca4956/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= diff --git a/tools/go.mod b/tools/go.mod index 7230d334..0680bcc2 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -5,6 +5,6 @@ go 1.14 require ( github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.24.0 - github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20201116205511-59fbd7b93270 - gotest.tools/gotestsum v0.6.0 + github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20210108181059-a2184e57a2d4 + gotest.tools/gotestsum v1.6.1 ) diff --git a/tools/go.sum b/tools/go.sum index c2381544..7a8eaf80 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -132,6 +132,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20201116205511-59fbd7b93270 h1:sf11XTIhELLKzn/M8CLKYp1RhH4cSBzRPOMg4Tv4CUA= github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20201116205511-59fbd7b93270/go.mod h1:f0uAs1kAopX4JXFgR4kMixWftM8qLha6edaFVawdNtg= +github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20210108181059-a2184e57a2d4 h1:enjElMLR8g18mbWLgwkgoz5+V4hAsX8uniIJoLKnbd0= +github.com/hashicorp/go-hclog/hclogvet v0.1.4-0.20210108181059-a2184e57a2d4/go.mod h1:f0uAs1kAopX4JXFgR4kMixWftM8qLha6edaFVawdNtg= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -395,6 +397,8 @@ gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools/gotestsum v0.6.0 h1:0zIxynXq9gkAcRpboAi3qOQIkZkCt/stfQzd7ab7Czs= gotest.tools/gotestsum v0.6.0/go.mod h1:LEX+ioCVdeWhZc8GYfiBRag360eBhwixWJ62R9eDQtI= +gotest.tools/gotestsum v1.6.1 h1:stfd/+B+OaI9CEKHP6uiSNYhmMwT6RnzMp8LyDjnYYQ= +gotest.tools/gotestsum v1.6.1/go.mod h1:LEX+ioCVdeWhZc8GYfiBRag360eBhwixWJ62R9eDQtI= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=