diff --git a/pkg/kubelet/dockertools/docker.go b/pkg/kubelet/dockertools/docker.go index 8f84ae9f53a..d9785dcb899 100644 --- a/pkg/kubelet/dockertools/docker.go +++ b/pkg/kubelet/dockertools/docker.go @@ -150,6 +150,44 @@ func filterHTTPError(err error, image string) error { } } +// Check if the inspected image matches what we are looking for +func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool { + + // The image string follows the grammar specified here + // https://github.com/docker/distribution/blob/master/reference/reference.go#L4 + named, err := dockerref.ParseNamed(image) + if err != nil { + glog.V(4).Infof("couldn't parse image reference %q: %v", image, err) + return false + } + _, isTagged := named.(dockerref.Tagged) + digest, isDigested := named.(dockerref.Digested) + if !isTagged && !isDigested { + // No Tag or SHA specified, so just return what we have + return true + } + if isTagged { + // Check the RepoTags for an exact match + for _, tag := range inspected.RepoTags { + if tag == image { + // We found a specific tag that we were looking for + return true + } + } + } + if isDigested { + algo := digest.Digest().Algorithm().String() + sha := digest.Digest().Hex() + // Look specifically for short and long sha(s) + if strings.Contains(inspected.ID, algo+":"+sha) { + // We found the short or long SHA requested + return true + } + } + glog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image) + return false +} + // applyDefaultImageTag parses a docker image string, if it doesn't contain any tag or digest, // a default tag will be applied. func applyDefaultImageTag(image string) (string, error) { diff --git a/pkg/kubelet/dockertools/docker_test.go b/pkg/kubelet/dockertools/docker_test.go index a43b1cc8872..5fb9218583b 100644 --- a/pkg/kubelet/dockertools/docker_test.go +++ b/pkg/kubelet/dockertools/docker_test.go @@ -157,6 +157,49 @@ func TestContainerNaming(t *testing.T) { } } +func TestMatchImageTagOrSHA(t *testing.T) { + for _, testCase := range []struct { + Inspected dockertypes.ImageInspect + Image string + Output bool + }{ + { + Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:latest"}}, + Image: "ubuntu", + Output: true, + }, + { + Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:14.04"}}, + Image: "ubuntu:latest", + Output: false, + }, + { + Inspected: dockertypes.ImageInspect{ + ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d", + }, + Image: "myimage@sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d", + Output: true, + }, + { + Inspected: dockertypes.ImageInspect{ + ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d", + }, + Image: "myimage@sha256:2208f7a29005", + Output: false, + }, + { + Inspected: dockertypes.ImageInspect{ + ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d", + }, + Image: "myimage@sha256:2208", + Output: false, + }, + } { + match := matchImageTagOrSHA(testCase.Inspected, testCase.Image) + assert.Equal(t, testCase.Output, match, testCase.Image+" is not a match") + } +} + func TestApplyDefaultImageTag(t *testing.T) { for _, testCase := range []struct { Input string diff --git a/pkg/kubelet/dockertools/kube_docker_client.go b/pkg/kubelet/dockertools/kube_docker_client.go index a2de527c193..55613cf4f59 100644 --- a/pkg/kubelet/dockertools/kube_docker_client.go +++ b/pkg/kubelet/dockertools/kube_docker_client.go @@ -184,6 +184,9 @@ func (d *kubeDockerClient) InspectImage(image string) (*dockertypes.ImageInspect } return nil, err } + if !matchImageTagOrSHA(resp, image) { + return nil, imageNotFoundError{ID: image} + } return &resp, nil }