diff --git a/api/client/create.go b/api/client/create.go index 0c19145463..0f06e8ccab 100644 --- a/api/client/create.go +++ b/api/client/create.go @@ -92,21 +92,22 @@ func (cli *DockerCli) createContainer(config *container.Config, hostConfig *cont defer containerIDFile.Close() } - ref, err := reference.ParseNamed(config.Image) + var trustedRef reference.Canonical + _, ref, err := reference.ParseIDOrReference(config.Image) if err != nil { return nil, err } - ref = reference.WithDefaultTag(ref) + if ref != nil { + ref = reference.WithDefaultTag(ref) - var trustedRef reference.Canonical - - if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() { - var err error - trustedRef, err = cli.trustedReference(ref) - if err != nil { - return nil, err + if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() { + var err error + trustedRef, err = cli.trustedReference(ref) + if err != nil { + return nil, err + } + config.Image = trustedRef.String() } - config.Image = trustedRef.String() } //create the container @@ -114,7 +115,7 @@ func (cli *DockerCli) createContainer(config *container.Config, hostConfig *cont //if image not found try to pull it if err != nil { - if client.IsErrImageNotFound(err) { + if client.IsErrImageNotFound(err) && ref != nil { fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.String()) // we don't want to write to stdout anything apart from container.ID diff --git a/daemon/daemon.go b/daemon/daemon.go index 892e83dac0..84969d0944 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -20,7 +20,6 @@ import ( "time" "github.com/Sirupsen/logrus" - "github.com/docker/distribution/digest" "github.com/docker/docker/api" "github.com/docker/docker/builder" "github.com/docker/docker/container" @@ -1267,25 +1266,25 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) { // GetImageID returns an image ID corresponding to the image referred to by // refOrID. func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) { - // Treat as an ID - if id, err := digest.ParseDigest(refOrID); err == nil { + id, ref, err := reference.ParseIDOrReference(refOrID) + if err != nil { + return "", err + } + if id != "" { if _, err := daemon.imageStore.Get(image.ID(id)); err != nil { return "", ErrImageDoesNotExist{refOrID} } return image.ID(id), nil } - // Treat it as a possible tag or digest reference - if ref, err := reference.ParseNamed(refOrID); err == nil { - if id, err := daemon.referenceStore.Get(ref); err == nil { - return id, nil - } - if tagged, ok := ref.(reference.NamedTagged); ok { - if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil { - for _, namedRef := range daemon.referenceStore.References(id) { - if namedRef.Name() == ref.Name() { - return id, nil - } + if id, err := daemon.referenceStore.Get(ref); err == nil { + return id, nil + } + if tagged, ok := ref.(reference.NamedTagged); ok { + if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil { + for _, namedRef := range daemon.referenceStore.References(id) { + if namedRef.Name() == ref.Name() { + return id, nil } } } diff --git a/image/tarexport/save.go b/image/tarexport/save.go index 45258e4f85..c92227fa49 100644 --- a/image/tarexport/save.go +++ b/image/tarexport/save.go @@ -70,10 +70,18 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor, } for _, name := range names { - ref, err := reference.ParseNamed(name) + id, ref, err := reference.ParseIDOrReference(name) if err != nil { return nil, err } + if id != "" { + _, err := l.is.Get(image.ID(id)) + if err != nil { + return nil, err + } + addAssoc(image.ID(id), nil) + continue + } if ref.Name() == string(digest.Canonical) { imgID, err := l.is.Search(name) if err != nil { diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go index c0f1854178..a22bb3ec50 100644 --- a/integration-cli/docker_cli_create_test.go +++ b/integration-cli/docker_cli_create_test.go @@ -450,3 +450,11 @@ func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *check.C) { out, _ = dockerCmd(c, "ps", "-a") c.Assert(out, checker.Not(checker.Contains), name) } + +// #20972 +func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) { + out := inspectField(c, "busybox", "Id") + imageID := strings.TrimPrefix(strings.TrimSpace(string(out)), "sha256:") + + dockerCmd(c, "create", imageID) +} diff --git a/reference/reference.go b/reference/reference.go index e355596eab..cdc8e63a96 100644 --- a/reference/reference.go +++ b/reference/reference.go @@ -155,6 +155,19 @@ func IsNameOnly(ref Named) bool { return true } +// ParseIDOrReference parses string for a image ID or a reference. ID can be +// without a default prefix. +func ParseIDOrReference(idOrRef string) (digest.Digest, Named, error) { + if err := v1.ValidateID(idOrRef); err == nil { + idOrRef = "sha256:" + idOrRef + } + if dgst, err := digest.ParseDigest(idOrRef); err == nil { + return dgst, nil, nil + } + ref, err := ParseNamed(idOrRef) + return "", ref, err +} + // splitHostname splits a repository name to hostname and remotename string. // If no valid hostname is found, the default hostname is used. Repository name // needs to be already validated before.