api: Extract parsing reference from repo and tag

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-01-31 10:27:09 +01:00
parent afc6e3fa46
commit 62be425bcc
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A
5 changed files with 52 additions and 63 deletions

View file

@ -1,9 +1,12 @@
package httputils // import "github.com/docker/docker/api/server/httputils"
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/docker/distribution/reference"
)
// BoolValue transforms a form value in different formats into a boolean type.
@ -41,6 +44,38 @@ func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error
return def, nil
}
// RepoTagReference parses form values "repo" and "tag" and returns a valid
// reference with repository and tag.
// If repo is empty, then a nil reference is returned.
// If no tag is given, then the default "latest" tag is set.
func RepoTagReference(repo, tag string) (reference.NamedTagged, error) {
if repo == "" {
return nil, nil
}
ref, err := reference.ParseNormalizedNamed(repo)
if err != nil {
return nil, err
}
if _, isDigested := ref.(reference.Digested); isDigested {
return nil, fmt.Errorf("cannot import digest reference")
}
if tag != "" {
return reference.WithTag(ref, tag)
}
withDefaultTag := reference.TagNameOnly(ref)
namedTagged, ok := withDefaultTag.(reference.NamedTagged)
if !ok {
return nil, fmt.Errorf("unexpected reference: %q", ref.String())
}
return namedTagged, nil
}
// ArchiveOptions stores archive information for different operations.
type ArchiveOptions struct {
Name string

View file

@ -48,10 +48,14 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
return err
}
ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
if err != nil {
return errdefs.InvalidParameter(err)
}
commitCfg := &backend.CreateImageConfig{
Pause: pause,
Repo: r.Form.Get("repo"),
Tag: r.Form.Get("tag"),
Tag: ref,
Author: r.Form.Get("author"),
Comment: r.Form.Get("comment"),
Config: config,

View file

@ -72,25 +72,9 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
} else { // import
src := r.Form.Get("fromSrc")
var ref reference.Named
if repo != "" {
var err error
ref, err = reference.ParseNormalizedNamed(repo)
if err != nil {
return errdefs.InvalidParameter(err)
}
if _, isDigested := ref.(reference.Digested); isDigested {
return errdefs.InvalidParameter(errors.New("cannot import digest reference"))
}
if tag != "" {
ref, err = reference.WithTag(ref, tag)
if err != nil {
return errdefs.InvalidParameter(err)
}
} else {
ref = reference.TagNameOnly(ref)
}
tagRef, err := httputils.RepoTagReference(repo, tag)
if err != nil {
return errdefs.InvalidParameter(err)
}
if len(comment) == 0 {
@ -121,7 +105,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
}
var id image.ID
id, progressErr = ir.backend.ImportImage(ctx, ref, platform, comment, layerReader, r.Form["changes"])
id, progressErr = ir.backend.ImportImage(ctx, tagRef, platform, comment, layerReader, r.Form["changes"])
if progressErr == nil {
output.Write(streamformatter.FormatStatus("", id.String()))
@ -370,26 +354,11 @@ func (ir *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
return err
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
ref, err := reference.ParseNormalizedNamed(repo)
if err != nil {
ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
if ref == nil || err != nil {
return errdefs.InvalidParameter(err)
}
if _, isDigested := ref.(reference.Digested); isDigested {
return errdefs.InvalidParameter(errors.New("tag reference can't have a digest"))
}
if tag != "" {
if ref, err = reference.WithTag(reference.TrimNamed(ref), tag); err != nil {
return errdefs.InvalidParameter(err)
}
} else {
ref = reference.TagNameOnly(ref)
}
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
if err != nil {
return errdefs.NotFound(err)

View file

@ -5,6 +5,7 @@ import (
"io"
"time"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types/container"
)
@ -102,8 +103,7 @@ type ExecProcessConfig struct {
// CreateImageConfig is the configuration for creating an image from a
// container.
type CreateImageConfig struct {
Repo string
Tag string
Tag reference.NamedTagged
Pause bool
Author string
Comment string

View file

@ -121,25 +121,6 @@ func merge(userConf, imageConf *containertypes.Config) error {
func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string, c *backend.CreateImageConfig) (string, error) {
start := time.Now()
var newRef reference.Named
if c.Repo != "" {
ref, err := reference.ParseNormalizedNamed(c.Repo)
if err != nil {
return "", errdefs.InvalidParameter(err)
}
if c.Tag != "" {
ref, err = reference.WithTag(ref, c.Tag)
if err != nil {
return "", errdefs.InvalidParameter(err)
}
} else {
ref = reference.TagNameOnly(ref)
}
newRef = ref
}
container, err := daemon.GetContainer(name)
if err != nil {
return "", err
@ -191,12 +172,12 @@ func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string,
}
imageRef := ""
if newRef != nil {
err = daemon.imageService.TagImage(ctx, id, newRef)
if c.Tag != nil {
err = daemon.imageService.TagImage(ctx, id, c.Tag)
if err != nil {
return "", err
}
imageRef = reference.FamiliarString(newRef)
imageRef = reference.FamiliarString(c.Tag)
}
daemon.LogContainerEventWithAttributes(container, "commit", map[string]string{
"comment": c.Comment,