Skip to content

Commit

Permalink
Remove reference package dependency from the api.
Browse files Browse the repository at this point in the history
Signed-off-by: David Calavera <david.calavera@gmail.com>
  • Loading branch information
calavera committed Apr 7, 2016
1 parent e82830e commit 47afe6b
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 212 deletions.
9 changes: 4 additions & 5 deletions api/server/router/image/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"io"

"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/registry"
"golang.org/x/net/context"
Expand All @@ -28,17 +27,17 @@ type imageBackend interface {
ImageHistory(imageName string) ([]*types.ImageHistory, error)
Images(filterArgs string, filter string, all bool) ([]*types.Image, error)
LookupImage(name string) (*types.ImageInspect, error)
TagImage(newTag reference.Named, imageName string) error
TagImage(imageName, repository, tag string) error
}

type importExportBackend interface {
LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
ImportImage(src string, newRef reference.Named, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
ImportImage(src string, repository, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
ExportImage(names []string, outStream io.Writer) error
}

type registryBackend interface {
PullImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
}
106 changes: 21 additions & 85 deletions api/server/router/image/image_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@ package image
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"

"github.com/docker/distribution/digest"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
"golang.org/x/net/context"
Expand Down Expand Up @@ -89,78 +86,38 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite
w.Header().Set("Content-Type", "application/json")

if image != "" { //pull
// Special case: "pull -a" may send an image name with a
// trailing :. This is ugly, but let's not break API
// compatibility.
image = strings.TrimSuffix(image, ":")

var ref reference.Named
ref, err = reference.ParseNamed(image)
if err == nil {
if tag != "" {
// The "tag" could actually be a digest.
var dgst digest.Digest
dgst, err = digest.ParseDigest(tag)
if err == nil {
ref, err = reference.WithDigest(ref, dgst)
} else {
ref, err = reference.WithTag(ref, tag)
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
if err == nil {
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}

authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
authConfig = &types.AuthConfig{}
}
}

err = s.backend.PullImage(ctx, ref, metaHeaders, authConfig, output)
}

authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &types.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
authConfig = &types.AuthConfig{}
}
}

err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output)

// Check the error from pulling an image to make sure the request
// was authorized. Modify the status if the request was
// unauthorized to respond with 401 rather than 500.
if err != nil && isAuthorizedError(err) {
err = errcode.ErrorCodeUnauthorized.WithMessage(fmt.Sprintf("Authentication is required: %s", err))
}
} else { //import
var newRef reference.Named
if repo != "" {
var err error
newRef, err = reference.ParseNamed(repo)
if err != nil {
return err
}

if _, isCanonical := newRef.(reference.Canonical); isCanonical {
return errors.New("cannot import digest reference")
}

if tag != "" {
newRef, err = reference.WithTag(newRef, tag)
if err != nil {
return err
}
}
}

src := r.Form.Get("fromSrc")
// 'err' MUST NOT be defined within this block, we need any error
// generated from the download to be available to the output
// stream processing below
err = s.backend.ImportImage(src, newRef, message, r.Body, output, r.Form["changes"])
err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"])
}
if err != nil {
if !output.Flushed() {
Expand Down Expand Up @@ -200,25 +157,15 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
}
}

ref, err := reference.ParseNamed(vars["name"])
if err != nil {
return err
}
image := vars["name"]
tag := r.Form.Get("tag")
if tag != "" {
// Push by digest is not supported, so only tags are supported.
ref, err = reference.WithTag(ref, tag)
if err != nil {
return err
}
}

output := ioutils.NewWriteFlusher(w)
defer output.Close()

w.Header().Set("Content-Type", "application/json")

if err := s.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil {
if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil {
if !output.Flushed() {
return err
}
Expand Down Expand Up @@ -322,18 +269,7 @@ func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
newTag, err := reference.WithName(repo)
if err != nil {
return err
}
if tag != "" {
if newTag, err = reference.WithTag(newTag, tag); err != nil {
return err
}
}
if err := s.backend.TagImage(newTag, vars["name"]); err != nil {
if err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil {
return err
}
w.WriteHeader(http.StatusCreated)
Expand Down
3 changes: 2 additions & 1 deletion builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/image"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
Expand Down Expand Up @@ -109,7 +110,7 @@ type Backend interface {
// GetImageOnBuild looks up a Docker image referenced by `name`.
GetImageOnBuild(name string) (Image, error)
// TagImage tags an image with newTag
TagImage(newTag reference.Named, imageName string) error
TagImageWithReference(image.ID, reference.Named) error
// PullOnBuild tells Docker to pull image referenced by `name`.
PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (Image, error)
// ContainerAttachRaw attaches to container.
Expand Down
4 changes: 3 additions & 1 deletion builder/dockerfile/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerfile/parser"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types"
Expand Down Expand Up @@ -256,8 +257,9 @@ func (b *Builder) build(config *types.ImageBuildOptions, context builder.Context
return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?")
}

imageID := image.ID(b.image)
for _, rt := range repoAndTags {
if err := b.docker.TagImage(rt, b.image); err != nil {
if err := b.docker.TagImageWithReference(imageID, rt); err != nil {
return "", err
}
}
Expand Down
2 changes: 1 addition & 1 deletion daemon/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
return "", err
}
}
if err := daemon.TagImage(newTag, id.String()); err != nil {
if err := daemon.TagImageWithReference(id, newTag); err != nil {
return "", err
}
}
Expand Down
114 changes: 0 additions & 114 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
_ "github.com/docker/docker/daemon/graphdriver/register"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/distribution"
dmetadata "github.com/docker/docker/distribution/metadata"
"github.com/docker/docker/distribution/xfer"
"github.com/docker/docker/dockerversion"
Expand Down Expand Up @@ -951,21 +950,6 @@ func (daemon *Daemon) changes(container *container.Container) ([]archive.Change,
return container.RWLayer.Changes()
}

// TagImage creates the tag specified by newTag, pointing to the image named
// imageName (alternatively, imageName can also be an image ID).
func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
imageID, err := daemon.GetImageID(imageName)
if err != nil {
return err
}
if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
return err
}

daemon.LogImageEvent(imageID.String(), newTag.String(), "tag")
return nil
}

func writeDistributionProgress(cancelFunc func(), outStream io.Writer, progressChan <-chan progress.Progress) {
progressOutput := streamformatter.NewJSONStreamFormatter().NewProgressOutput(outStream, false)
operationCancelled := false
Expand Down Expand Up @@ -996,69 +980,6 @@ func isBrokenPipe(e error) bool {
return e == syscall.EPIPE
}

// PullImage initiates a pull operation. image is the repository name to pull, and
// tag may be either empty, or indicate a specific tag to pull.
func (daemon *Daemon) PullImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
// Include a buffer so that slow client connections don't affect
// transfer performance.
progressChan := make(chan progress.Progress, 100)

writesDone := make(chan struct{})

ctx, cancelFunc := context.WithCancel(ctx)

go func() {
writeDistributionProgress(cancelFunc, outStream, progressChan)
close(writesDone)
}()

imagePullConfig := &distribution.ImagePullConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
ProgressOutput: progress.ChanOutput(progressChan),
RegistryService: daemon.RegistryService,
ImageEventLogger: daemon.LogImageEvent,
MetadataStore: daemon.distributionMetadataStore,
ImageStore: daemon.imageStore,
ReferenceStore: daemon.referenceStore,
DownloadManager: daemon.downloadManager,
}

err := distribution.Pull(ctx, ref, imagePullConfig)
close(progressChan)
<-writesDone
return err
}

// PullOnBuild tells Docker to pull image referenced by `name`.
func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
ref, err := reference.ParseNamed(name)
if err != nil {
return nil, err
}
ref = reference.WithDefaultTag(ref)

pullRegistryAuth := &types.AuthConfig{}
if len(authConfigs) > 0 {
// The request came with a full auth config file, we prefer to use that
repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
if err != nil {
return nil, err
}

resolvedConfig := registry.ResolveAuthConfig(
authConfigs,
repoInfo.Index,
)
pullRegistryAuth = &resolvedConfig
}

if err := daemon.PullImage(ctx, ref, nil, pullRegistryAuth, output); err != nil {
return nil, err
}
return daemon.GetImage(name)
}

// ExportImage exports a list of images to the given output stream. The
// exported images are archived into a tar when written to the output
// stream. All images with the given tag and all versions containing
Expand All @@ -1069,41 +990,6 @@ func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
return imageExporter.Save(names, outStream)
}

// PushImage initiates a push operation on the repository named localName.
func (daemon *Daemon) PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
// Include a buffer so that slow client connections don't affect
// transfer performance.
progressChan := make(chan progress.Progress, 100)

writesDone := make(chan struct{})

ctx, cancelFunc := context.WithCancel(ctx)

go func() {
writeDistributionProgress(cancelFunc, outStream, progressChan)
close(writesDone)
}()

imagePushConfig := &distribution.ImagePushConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
ProgressOutput: progress.ChanOutput(progressChan),
RegistryService: daemon.RegistryService,
ImageEventLogger: daemon.LogImageEvent,
MetadataStore: daemon.distributionMetadataStore,
LayerStore: daemon.layerStore,
ImageStore: daemon.imageStore,
ReferenceStore: daemon.referenceStore,
TrustKey: daemon.trustKey,
UploadManager: daemon.uploadManager,
}

err := distribution.Push(ctx, ref, imagePushConfig)
close(progressChan)
<-writesDone
return err
}

// LookupImage looks up an image by name and returns it as an ImageInspect
// structure.
func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
Expand Down
Loading

0 comments on commit 47afe6b

Please sign in to comment.