Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -4,7 +4,6 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/docker/api/types/backend" |
| 7 |
- "github.com/docker/docker/reference" |
|
| 8 | 7 |
"github.com/docker/engine-api/types" |
| 9 | 8 |
"github.com/docker/engine-api/types/registry" |
| 10 | 9 |
"golang.org/x/net/context" |
| ... | ... |
@@ -28,17 +27,17 @@ type imageBackend interface {
|
| 28 | 28 |
ImageHistory(imageName string) ([]*types.ImageHistory, error) |
| 29 | 29 |
Images(filterArgs string, filter string, all bool) ([]*types.Image, error) |
| 30 | 30 |
LookupImage(name string) (*types.ImageInspect, error) |
| 31 |
- TagImage(newTag reference.Named, imageName string) error |
|
| 31 |
+ TagImage(imageName, repository, tag string) error |
|
| 32 | 32 |
} |
| 33 | 33 |
|
| 34 | 34 |
type importExportBackend interface {
|
| 35 | 35 |
LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error |
| 36 |
- ImportImage(src string, newRef reference.Named, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error |
|
| 36 |
+ ImportImage(src string, repository, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error |
|
| 37 | 37 |
ExportImage(names []string, outStream io.Writer) error |
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
type registryBackend interface {
|
| 41 |
- PullImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 42 |
- PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 41 |
+ PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 42 |
+ PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 43 | 43 |
SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) |
| 44 | 44 |
} |
| ... | ... |
@@ -3,20 +3,17 @@ package image |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/base64" |
| 5 | 5 |
"encoding/json" |
| 6 |
- "errors" |
|
| 7 | 6 |
"fmt" |
| 8 | 7 |
"io" |
| 9 | 8 |
"net/http" |
| 10 | 9 |
"net/url" |
| 11 | 10 |
"strings" |
| 12 | 11 |
|
| 13 |
- "github.com/docker/distribution/digest" |
|
| 14 | 12 |
"github.com/docker/distribution/registry/api/errcode" |
| 15 | 13 |
"github.com/docker/docker/api/server/httputils" |
| 16 | 14 |
"github.com/docker/docker/api/types/backend" |
| 17 | 15 |
"github.com/docker/docker/pkg/ioutils" |
| 18 | 16 |
"github.com/docker/docker/pkg/streamformatter" |
| 19 |
- "github.com/docker/docker/reference" |
|
| 20 | 17 |
"github.com/docker/engine-api/types" |
| 21 | 18 |
"github.com/docker/engine-api/types/container" |
| 22 | 19 |
"golang.org/x/net/context" |
| ... | ... |
@@ -89,46 +86,26 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite |
| 89 | 89 |
w.Header().Set("Content-Type", "application/json")
|
| 90 | 90 |
|
| 91 | 91 |
if image != "" { //pull
|
| 92 |
- // Special case: "pull -a" may send an image name with a |
|
| 93 |
- // trailing :. This is ugly, but let's not break API |
|
| 94 |
- // compatibility. |
|
| 95 |
- image = strings.TrimSuffix(image, ":") |
|
| 96 |
- |
|
| 97 |
- var ref reference.Named |
|
| 98 |
- ref, err = reference.ParseNamed(image) |
|
| 99 |
- if err == nil {
|
|
| 100 |
- if tag != "" {
|
|
| 101 |
- // The "tag" could actually be a digest. |
|
| 102 |
- var dgst digest.Digest |
|
| 103 |
- dgst, err = digest.ParseDigest(tag) |
|
| 104 |
- if err == nil {
|
|
| 105 |
- ref, err = reference.WithDigest(ref, dgst) |
|
| 106 |
- } else {
|
|
| 107 |
- ref, err = reference.WithTag(ref, tag) |
|
| 108 |
- } |
|
| 92 |
+ metaHeaders := map[string][]string{}
|
|
| 93 |
+ for k, v := range r.Header {
|
|
| 94 |
+ if strings.HasPrefix(k, "X-Meta-") {
|
|
| 95 |
+ metaHeaders[k] = v |
|
| 109 | 96 |
} |
| 110 |
- if err == nil {
|
|
| 111 |
- metaHeaders := map[string][]string{}
|
|
| 112 |
- for k, v := range r.Header {
|
|
| 113 |
- if strings.HasPrefix(k, "X-Meta-") {
|
|
| 114 |
- metaHeaders[k] = v |
|
| 115 |
- } |
|
| 116 |
- } |
|
| 117 |
- |
|
| 118 |
- authEncoded := r.Header.Get("X-Registry-Auth")
|
|
| 119 |
- authConfig := &types.AuthConfig{}
|
|
| 120 |
- if authEncoded != "" {
|
|
| 121 |
- authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) |
|
| 122 |
- if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
|
|
| 123 |
- // for a pull it is not an error if no auth was given |
|
| 124 |
- // to increase compatibility with the existing api it is defaulting to be empty |
|
| 125 |
- authConfig = &types.AuthConfig{}
|
|
| 126 |
- } |
|
| 127 |
- } |
|
| 128 |
- |
|
| 129 |
- err = s.backend.PullImage(ctx, ref, metaHeaders, authConfig, output) |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ authEncoded := r.Header.Get("X-Registry-Auth")
|
|
| 100 |
+ authConfig := &types.AuthConfig{}
|
|
| 101 |
+ if authEncoded != "" {
|
|
| 102 |
+ authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) |
|
| 103 |
+ if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
|
|
| 104 |
+ // for a pull it is not an error if no auth was given |
|
| 105 |
+ // to increase compatibility with the existing api it is defaulting to be empty |
|
| 106 |
+ authConfig = &types.AuthConfig{}
|
|
| 130 | 107 |
} |
| 131 | 108 |
} |
| 109 |
+ |
|
| 110 |
+ err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output) |
|
| 111 |
+ |
|
| 132 | 112 |
// Check the error from pulling an image to make sure the request |
| 133 | 113 |
// was authorized. Modify the status if the request was |
| 134 | 114 |
// unauthorized to respond with 401 rather than 500. |
| ... | ... |
@@ -136,31 +113,11 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite |
| 136 | 136 |
err = errcode.ErrorCodeUnauthorized.WithMessage(fmt.Sprintf("Authentication is required: %s", err))
|
| 137 | 137 |
} |
| 138 | 138 |
} else { //import
|
| 139 |
- var newRef reference.Named |
|
| 140 |
- if repo != "" {
|
|
| 141 |
- var err error |
|
| 142 |
- newRef, err = reference.ParseNamed(repo) |
|
| 143 |
- if err != nil {
|
|
| 144 |
- return err |
|
| 145 |
- } |
|
| 146 |
- |
|
| 147 |
- if _, isCanonical := newRef.(reference.Canonical); isCanonical {
|
|
| 148 |
- return errors.New("cannot import digest reference")
|
|
| 149 |
- } |
|
| 150 |
- |
|
| 151 |
- if tag != "" {
|
|
| 152 |
- newRef, err = reference.WithTag(newRef, tag) |
|
| 153 |
- if err != nil {
|
|
| 154 |
- return err |
|
| 155 |
- } |
|
| 156 |
- } |
|
| 157 |
- } |
|
| 158 |
- |
|
| 159 | 139 |
src := r.Form.Get("fromSrc")
|
| 160 | 140 |
// 'err' MUST NOT be defined within this block, we need any error |
| 161 | 141 |
// generated from the download to be available to the output |
| 162 | 142 |
// stream processing below |
| 163 |
- err = s.backend.ImportImage(src, newRef, message, r.Body, output, r.Form["changes"]) |
|
| 143 |
+ err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"]) |
|
| 164 | 144 |
} |
| 165 | 145 |
if err != nil {
|
| 166 | 146 |
if !output.Flushed() {
|
| ... | ... |
@@ -200,25 +157,15 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, |
| 200 | 200 |
} |
| 201 | 201 |
} |
| 202 | 202 |
|
| 203 |
- ref, err := reference.ParseNamed(vars["name"]) |
|
| 204 |
- if err != nil {
|
|
| 205 |
- return err |
|
| 206 |
- } |
|
| 203 |
+ image := vars["name"] |
|
| 207 | 204 |
tag := r.Form.Get("tag")
|
| 208 |
- if tag != "" {
|
|
| 209 |
- // Push by digest is not supported, so only tags are supported. |
|
| 210 |
- ref, err = reference.WithTag(ref, tag) |
|
| 211 |
- if err != nil {
|
|
| 212 |
- return err |
|
| 213 |
- } |
|
| 214 |
- } |
|
| 215 | 205 |
|
| 216 | 206 |
output := ioutils.NewWriteFlusher(w) |
| 217 | 207 |
defer output.Close() |
| 218 | 208 |
|
| 219 | 209 |
w.Header().Set("Content-Type", "application/json")
|
| 220 | 210 |
|
| 221 |
- if err := s.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil {
|
|
| 211 |
+ if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil {
|
|
| 222 | 212 |
if !output.Flushed() {
|
| 223 | 213 |
return err |
| 224 | 214 |
} |
| ... | ... |
@@ -322,18 +269,7 @@ func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter, |
| 322 | 322 |
if err := httputils.ParseForm(r); err != nil {
|
| 323 | 323 |
return err |
| 324 | 324 |
} |
| 325 |
- repo := r.Form.Get("repo")
|
|
| 326 |
- tag := r.Form.Get("tag")
|
|
| 327 |
- newTag, err := reference.WithName(repo) |
|
| 328 |
- if err != nil {
|
|
| 329 |
- return err |
|
| 330 |
- } |
|
| 331 |
- if tag != "" {
|
|
| 332 |
- if newTag, err = reference.WithTag(newTag, tag); err != nil {
|
|
| 333 |
- return err |
|
| 334 |
- } |
|
| 335 |
- } |
|
| 336 |
- if err := s.backend.TagImage(newTag, vars["name"]); err != nil {
|
|
| 325 |
+ if err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil {
|
|
| 337 | 326 |
return err |
| 338 | 327 |
} |
| 339 | 328 |
w.WriteHeader(http.StatusCreated) |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"time" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/api/types/backend" |
| 13 |
+ "github.com/docker/docker/image" |
|
| 13 | 14 |
"github.com/docker/docker/reference" |
| 14 | 15 |
"github.com/docker/engine-api/types" |
| 15 | 16 |
"github.com/docker/engine-api/types/container" |
| ... | ... |
@@ -109,7 +110,7 @@ type Backend interface {
|
| 109 | 109 |
// GetImageOnBuild looks up a Docker image referenced by `name`. |
| 110 | 110 |
GetImageOnBuild(name string) (Image, error) |
| 111 | 111 |
// TagImage tags an image with newTag |
| 112 |
- TagImage(newTag reference.Named, imageName string) error |
|
| 112 |
+ TagImageWithReference(image.ID, reference.Named) error |
|
| 113 | 113 |
// PullOnBuild tells Docker to pull image referenced by `name`. |
| 114 | 114 |
PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (Image, error) |
| 115 | 115 |
// ContainerAttachRaw attaches to container. |
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"github.com/Sirupsen/logrus" |
| 13 | 13 |
"github.com/docker/docker/builder" |
| 14 | 14 |
"github.com/docker/docker/builder/dockerfile/parser" |
| 15 |
+ "github.com/docker/docker/image" |
|
| 15 | 16 |
"github.com/docker/docker/pkg/stringid" |
| 16 | 17 |
"github.com/docker/docker/reference" |
| 17 | 18 |
"github.com/docker/engine-api/types" |
| ... | ... |
@@ -256,8 +257,9 @@ func (b *Builder) build(config *types.ImageBuildOptions, context builder.Context |
| 256 | 256 |
return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?")
|
| 257 | 257 |
} |
| 258 | 258 |
|
| 259 |
+ imageID := image.ID(b.image) |
|
| 259 | 260 |
for _, rt := range repoAndTags {
|
| 260 |
- if err := b.docker.TagImage(rt, b.image); err != nil {
|
|
| 261 |
+ if err := b.docker.TagImageWithReference(imageID, rt); err != nil {
|
|
| 261 | 262 |
return "", err |
| 262 | 263 |
} |
| 263 | 264 |
} |
| ... | ... |
@@ -215,7 +215,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str |
| 215 | 215 |
return "", err |
| 216 | 216 |
} |
| 217 | 217 |
} |
| 218 |
- if err := daemon.TagImage(newTag, id.String()); err != nil {
|
|
| 218 |
+ if err := daemon.TagImageWithReference(id, newTag); err != nil {
|
|
| 219 | 219 |
return "", err |
| 220 | 220 |
} |
| 221 | 221 |
} |
| ... | ... |
@@ -38,7 +38,6 @@ import ( |
| 38 | 38 |
_ "github.com/docker/docker/daemon/graphdriver/register" |
| 39 | 39 |
"github.com/docker/docker/daemon/logger" |
| 40 | 40 |
"github.com/docker/docker/daemon/network" |
| 41 |
- "github.com/docker/docker/distribution" |
|
| 42 | 41 |
dmetadata "github.com/docker/docker/distribution/metadata" |
| 43 | 42 |
"github.com/docker/docker/distribution/xfer" |
| 44 | 43 |
"github.com/docker/docker/dockerversion" |
| ... | ... |
@@ -951,21 +950,6 @@ func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, |
| 951 | 951 |
return container.RWLayer.Changes() |
| 952 | 952 |
} |
| 953 | 953 |
|
| 954 |
-// TagImage creates the tag specified by newTag, pointing to the image named |
|
| 955 |
-// imageName (alternatively, imageName can also be an image ID). |
|
| 956 |
-func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
|
|
| 957 |
- imageID, err := daemon.GetImageID(imageName) |
|
| 958 |
- if err != nil {
|
|
| 959 |
- return err |
|
| 960 |
- } |
|
| 961 |
- if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
|
|
| 962 |
- return err |
|
| 963 |
- } |
|
| 964 |
- |
|
| 965 |
- daemon.LogImageEvent(imageID.String(), newTag.String(), "tag") |
|
| 966 |
- return nil |
|
| 967 |
-} |
|
| 968 |
- |
|
| 969 | 954 |
func writeDistributionProgress(cancelFunc func(), outStream io.Writer, progressChan <-chan progress.Progress) {
|
| 970 | 955 |
progressOutput := streamformatter.NewJSONStreamFormatter().NewProgressOutput(outStream, false) |
| 971 | 956 |
operationCancelled := false |
| ... | ... |
@@ -996,69 +980,6 @@ func isBrokenPipe(e error) bool {
|
| 996 | 996 |
return e == syscall.EPIPE |
| 997 | 997 |
} |
| 998 | 998 |
|
| 999 |
-// PullImage initiates a pull operation. image is the repository name to pull, and |
|
| 1000 |
-// tag may be either empty, or indicate a specific tag to pull. |
|
| 1001 |
-func (daemon *Daemon) PullImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 1002 |
- // Include a buffer so that slow client connections don't affect |
|
| 1003 |
- // transfer performance. |
|
| 1004 |
- progressChan := make(chan progress.Progress, 100) |
|
| 1005 |
- |
|
| 1006 |
- writesDone := make(chan struct{})
|
|
| 1007 |
- |
|
| 1008 |
- ctx, cancelFunc := context.WithCancel(ctx) |
|
| 1009 |
- |
|
| 1010 |
- go func() {
|
|
| 1011 |
- writeDistributionProgress(cancelFunc, outStream, progressChan) |
|
| 1012 |
- close(writesDone) |
|
| 1013 |
- }() |
|
| 1014 |
- |
|
| 1015 |
- imagePullConfig := &distribution.ImagePullConfig{
|
|
| 1016 |
- MetaHeaders: metaHeaders, |
|
| 1017 |
- AuthConfig: authConfig, |
|
| 1018 |
- ProgressOutput: progress.ChanOutput(progressChan), |
|
| 1019 |
- RegistryService: daemon.RegistryService, |
|
| 1020 |
- ImageEventLogger: daemon.LogImageEvent, |
|
| 1021 |
- MetadataStore: daemon.distributionMetadataStore, |
|
| 1022 |
- ImageStore: daemon.imageStore, |
|
| 1023 |
- ReferenceStore: daemon.referenceStore, |
|
| 1024 |
- DownloadManager: daemon.downloadManager, |
|
| 1025 |
- } |
|
| 1026 |
- |
|
| 1027 |
- err := distribution.Pull(ctx, ref, imagePullConfig) |
|
| 1028 |
- close(progressChan) |
|
| 1029 |
- <-writesDone |
|
| 1030 |
- return err |
|
| 1031 |
-} |
|
| 1032 |
- |
|
| 1033 |
-// PullOnBuild tells Docker to pull image referenced by `name`. |
|
| 1034 |
-func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
|
|
| 1035 |
- ref, err := reference.ParseNamed(name) |
|
| 1036 |
- if err != nil {
|
|
| 1037 |
- return nil, err |
|
| 1038 |
- } |
|
| 1039 |
- ref = reference.WithDefaultTag(ref) |
|
| 1040 |
- |
|
| 1041 |
- pullRegistryAuth := &types.AuthConfig{}
|
|
| 1042 |
- if len(authConfigs) > 0 {
|
|
| 1043 |
- // The request came with a full auth config file, we prefer to use that |
|
| 1044 |
- repoInfo, err := daemon.RegistryService.ResolveRepository(ref) |
|
| 1045 |
- if err != nil {
|
|
| 1046 |
- return nil, err |
|
| 1047 |
- } |
|
| 1048 |
- |
|
| 1049 |
- resolvedConfig := registry.ResolveAuthConfig( |
|
| 1050 |
- authConfigs, |
|
| 1051 |
- repoInfo.Index, |
|
| 1052 |
- ) |
|
| 1053 |
- pullRegistryAuth = &resolvedConfig |
|
| 1054 |
- } |
|
| 1055 |
- |
|
| 1056 |
- if err := daemon.PullImage(ctx, ref, nil, pullRegistryAuth, output); err != nil {
|
|
| 1057 |
- return nil, err |
|
| 1058 |
- } |
|
| 1059 |
- return daemon.GetImage(name) |
|
| 1060 |
-} |
|
| 1061 |
- |
|
| 1062 | 999 |
// ExportImage exports a list of images to the given output stream. The |
| 1063 | 1000 |
// exported images are archived into a tar when written to the output |
| 1064 | 1001 |
// stream. All images with the given tag and all versions containing |
| ... | ... |
@@ -1069,41 +990,6 @@ func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
| 1069 | 1069 |
return imageExporter.Save(names, outStream) |
| 1070 | 1070 |
} |
| 1071 | 1071 |
|
| 1072 |
-// PushImage initiates a push operation on the repository named localName. |
|
| 1073 |
-func (daemon *Daemon) PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 1074 |
- // Include a buffer so that slow client connections don't affect |
|
| 1075 |
- // transfer performance. |
|
| 1076 |
- progressChan := make(chan progress.Progress, 100) |
|
| 1077 |
- |
|
| 1078 |
- writesDone := make(chan struct{})
|
|
| 1079 |
- |
|
| 1080 |
- ctx, cancelFunc := context.WithCancel(ctx) |
|
| 1081 |
- |
|
| 1082 |
- go func() {
|
|
| 1083 |
- writeDistributionProgress(cancelFunc, outStream, progressChan) |
|
| 1084 |
- close(writesDone) |
|
| 1085 |
- }() |
|
| 1086 |
- |
|
| 1087 |
- imagePushConfig := &distribution.ImagePushConfig{
|
|
| 1088 |
- MetaHeaders: metaHeaders, |
|
| 1089 |
- AuthConfig: authConfig, |
|
| 1090 |
- ProgressOutput: progress.ChanOutput(progressChan), |
|
| 1091 |
- RegistryService: daemon.RegistryService, |
|
| 1092 |
- ImageEventLogger: daemon.LogImageEvent, |
|
| 1093 |
- MetadataStore: daemon.distributionMetadataStore, |
|
| 1094 |
- LayerStore: daemon.layerStore, |
|
| 1095 |
- ImageStore: daemon.imageStore, |
|
| 1096 |
- ReferenceStore: daemon.referenceStore, |
|
| 1097 |
- TrustKey: daemon.trustKey, |
|
| 1098 |
- UploadManager: daemon.uploadManager, |
|
| 1099 |
- } |
|
| 1100 |
- |
|
| 1101 |
- err := distribution.Push(ctx, ref, imagePushConfig) |
|
| 1102 |
- close(progressChan) |
|
| 1103 |
- <-writesDone |
|
| 1104 |
- return err |
|
| 1105 |
-} |
|
| 1106 |
- |
|
| 1107 | 1072 |
// LookupImage looks up an image by name and returns it as an ImageInspect |
| 1108 | 1073 |
// structure. |
| 1109 | 1074 |
func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
| 1110 | 1075 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,106 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/distribution/digest" |
|
| 7 |
+ "github.com/docker/docker/builder" |
|
| 8 |
+ "github.com/docker/docker/distribution" |
|
| 9 |
+ "github.com/docker/docker/pkg/progress" |
|
| 10 |
+ "github.com/docker/docker/reference" |
|
| 11 |
+ "github.com/docker/docker/registry" |
|
| 12 |
+ "github.com/docker/engine-api/types" |
|
| 13 |
+ "golang.org/x/net/context" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+// PullImage initiates a pull operation. image is the repository name to pull, and |
|
| 17 |
+// tag may be either empty, or indicate a specific tag to pull. |
|
| 18 |
+func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 19 |
+ // Special case: "pull -a" may send an image name with a |
|
| 20 |
+ // trailing :. This is ugly, but let's not break API |
|
| 21 |
+ // compatibility. |
|
| 22 |
+ image = strings.TrimSuffix(image, ":") |
|
| 23 |
+ |
|
| 24 |
+ ref, err := reference.ParseNamed(image) |
|
| 25 |
+ if err != nil {
|
|
| 26 |
+ return err |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ if tag != "" {
|
|
| 30 |
+ // The "tag" could actually be a digest. |
|
| 31 |
+ var dgst digest.Digest |
|
| 32 |
+ dgst, err = digest.ParseDigest(tag) |
|
| 33 |
+ if err == nil {
|
|
| 34 |
+ ref, err = reference.WithDigest(ref, dgst) |
|
| 35 |
+ } else {
|
|
| 36 |
+ ref, err = reference.WithTag(ref, tag) |
|
| 37 |
+ } |
|
| 38 |
+ if err != nil {
|
|
| 39 |
+ return err |
|
| 40 |
+ } |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream) |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+// PullOnBuild tells Docker to pull image referenced by `name`. |
|
| 47 |
+func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
|
|
| 48 |
+ ref, err := reference.ParseNamed(name) |
|
| 49 |
+ if err != nil {
|
|
| 50 |
+ return nil, err |
|
| 51 |
+ } |
|
| 52 |
+ ref = reference.WithDefaultTag(ref) |
|
| 53 |
+ |
|
| 54 |
+ pullRegistryAuth := &types.AuthConfig{}
|
|
| 55 |
+ if len(authConfigs) > 0 {
|
|
| 56 |
+ // The request came with a full auth config file, we prefer to use that |
|
| 57 |
+ repoInfo, err := daemon.RegistryService.ResolveRepository(ref) |
|
| 58 |
+ if err != nil {
|
|
| 59 |
+ return nil, err |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ resolvedConfig := registry.ResolveAuthConfig( |
|
| 63 |
+ authConfigs, |
|
| 64 |
+ repoInfo.Index, |
|
| 65 |
+ ) |
|
| 66 |
+ pullRegistryAuth = &resolvedConfig |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
|
|
| 70 |
+ return nil, err |
|
| 71 |
+ } |
|
| 72 |
+ return daemon.GetImage(name) |
|
| 73 |
+} |
|
| 74 |
+ |
|
| 75 |
+func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 76 |
+ // Include a buffer so that slow client connections don't affect |
|
| 77 |
+ // transfer performance. |
|
| 78 |
+ progressChan := make(chan progress.Progress, 100) |
|
| 79 |
+ |
|
| 80 |
+ writesDone := make(chan struct{})
|
|
| 81 |
+ |
|
| 82 |
+ ctx, cancelFunc := context.WithCancel(ctx) |
|
| 83 |
+ |
|
| 84 |
+ go func() {
|
|
| 85 |
+ writeDistributionProgress(cancelFunc, outStream, progressChan) |
|
| 86 |
+ close(writesDone) |
|
| 87 |
+ }() |
|
| 88 |
+ |
|
| 89 |
+ imagePullConfig := &distribution.ImagePullConfig{
|
|
| 90 |
+ MetaHeaders: metaHeaders, |
|
| 91 |
+ AuthConfig: authConfig, |
|
| 92 |
+ ProgressOutput: progress.ChanOutput(progressChan), |
|
| 93 |
+ RegistryService: daemon.RegistryService, |
|
| 94 |
+ ImageEventLogger: daemon.LogImageEvent, |
|
| 95 |
+ MetadataStore: daemon.distributionMetadataStore, |
|
| 96 |
+ ImageStore: daemon.imageStore, |
|
| 97 |
+ ReferenceStore: daemon.referenceStore, |
|
| 98 |
+ DownloadManager: daemon.downloadManager, |
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ err := distribution.Pull(ctx, ref, imagePullConfig) |
|
| 102 |
+ close(progressChan) |
|
| 103 |
+ <-writesDone |
|
| 104 |
+ return err |
|
| 105 |
+} |
| 0 | 106 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,58 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/docker/distribution" |
|
| 6 |
+ "github.com/docker/docker/pkg/progress" |
|
| 7 |
+ "github.com/docker/docker/reference" |
|
| 8 |
+ "github.com/docker/engine-api/types" |
|
| 9 |
+ "golang.org/x/net/context" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+// PushImage initiates a push operation on the repository named localName. |
|
| 13 |
+func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 14 |
+ ref, err := reference.ParseNamed(image) |
|
| 15 |
+ if err != nil {
|
|
| 16 |
+ return err |
|
| 17 |
+ } |
|
| 18 |
+ if tag != "" {
|
|
| 19 |
+ // Push by digest is not supported, so only tags are supported. |
|
| 20 |
+ ref, err = reference.WithTag(ref, tag) |
|
| 21 |
+ if err != nil {
|
|
| 22 |
+ return err |
|
| 23 |
+ } |
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 26 |
+ // Include a buffer so that slow client connections don't affect |
|
| 27 |
+ // transfer performance. |
|
| 28 |
+ progressChan := make(chan progress.Progress, 100) |
|
| 29 |
+ |
|
| 30 |
+ writesDone := make(chan struct{})
|
|
| 31 |
+ |
|
| 32 |
+ ctx, cancelFunc := context.WithCancel(ctx) |
|
| 33 |
+ |
|
| 34 |
+ go func() {
|
|
| 35 |
+ writeDistributionProgress(cancelFunc, outStream, progressChan) |
|
| 36 |
+ close(writesDone) |
|
| 37 |
+ }() |
|
| 38 |
+ |
|
| 39 |
+ imagePushConfig := &distribution.ImagePushConfig{
|
|
| 40 |
+ MetaHeaders: metaHeaders, |
|
| 41 |
+ AuthConfig: authConfig, |
|
| 42 |
+ ProgressOutput: progress.ChanOutput(progressChan), |
|
| 43 |
+ RegistryService: daemon.RegistryService, |
|
| 44 |
+ ImageEventLogger: daemon.LogImageEvent, |
|
| 45 |
+ MetadataStore: daemon.distributionMetadataStore, |
|
| 46 |
+ LayerStore: daemon.layerStore, |
|
| 47 |
+ ImageStore: daemon.imageStore, |
|
| 48 |
+ ReferenceStore: daemon.referenceStore, |
|
| 49 |
+ TrustKey: daemon.trustKey, |
|
| 50 |
+ UploadManager: daemon.uploadManager, |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ err = distribution.Push(ctx, ref, imagePushConfig) |
|
| 54 |
+ close(progressChan) |
|
| 55 |
+ <-writesDone |
|
| 56 |
+ return err |
|
| 57 |
+} |
| 0 | 58 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,37 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/docker/image" |
|
| 4 |
+ "github.com/docker/docker/reference" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// TagImage creates the tag specified by newTag, pointing to the image named |
|
| 8 |
+// imageName (alternatively, imageName can also be an image ID). |
|
| 9 |
+func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
|
| 10 |
+ imageID, err := daemon.GetImageID(imageName) |
|
| 11 |
+ if err != nil {
|
|
| 12 |
+ return err |
|
| 13 |
+ } |
|
| 14 |
+ |
|
| 15 |
+ newTag, err := reference.WithName(repository) |
|
| 16 |
+ if err != nil {
|
|
| 17 |
+ return err |
|
| 18 |
+ } |
|
| 19 |
+ if tag != "" {
|
|
| 20 |
+ if newTag, err = reference.WithTag(newTag, tag); err != nil {
|
|
| 21 |
+ return err |
|
| 22 |
+ } |
|
| 23 |
+ } |
|
| 24 |
+ |
|
| 25 |
+ return daemon.TagImageWithReference(imageID, newTag) |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+// TagImageWithReference adds the given reference to the image ID provided. |
|
| 29 |
+func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
|
|
| 30 |
+ if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
|
|
| 31 |
+ return err |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ daemon.LogImageEvent(imageID.String(), newTag.String(), "tag") |
|
| 35 |
+ return nil |
|
| 36 |
+} |
| ... | ... |
@@ -2,6 +2,7 @@ package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "errors" |
|
| 5 | 6 |
"io" |
| 6 | 7 |
"net/http" |
| 7 | 8 |
"net/url" |
| ... | ... |
@@ -24,13 +25,33 @@ import ( |
| 24 | 24 |
// inConfig (if src is "-"), or from a URI specified in src. Progress output is |
| 25 | 25 |
// written to outStream. Repository and tag names can optionally be given in |
| 26 | 26 |
// the repo and tag arguments, respectively. |
| 27 |
-func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
|
|
| 27 |
+func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
|
|
| 28 | 28 |
var ( |
| 29 |
- sf = streamformatter.NewJSONStreamFormatter() |
|
| 30 |
- rc io.ReadCloser |
|
| 31 |
- resp *http.Response |
|
| 29 |
+ sf = streamformatter.NewJSONStreamFormatter() |
|
| 30 |
+ rc io.ReadCloser |
|
| 31 |
+ resp *http.Response |
|
| 32 |
+ newRef reference.Named |
|
| 32 | 33 |
) |
| 33 | 34 |
|
| 35 |
+ if repository != "" {
|
|
| 36 |
+ var err error |
|
| 37 |
+ newRef, err = reference.ParseNamed(repository) |
|
| 38 |
+ if err != nil {
|
|
| 39 |
+ return err |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ if _, isCanonical := newRef.(reference.Canonical); isCanonical {
|
|
| 43 |
+ return errors.New("cannot import digest reference")
|
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ if tag != "" {
|
|
| 47 |
+ newRef, err = reference.WithTag(newRef, tag) |
|
| 48 |
+ if err != nil {
|
|
| 49 |
+ return err |
|
| 50 |
+ } |
|
| 51 |
+ } |
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 34 | 54 |
config, err := dockerfile.BuildFromConfig(&container.Config{}, changes)
|
| 35 | 55 |
if err != nil {
|
| 36 | 56 |
return err |
| ... | ... |
@@ -103,7 +124,7 @@ func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string |
| 103 | 103 |
|
| 104 | 104 |
// FIXME: connect with commit code and call refstore directly |
| 105 | 105 |
if newRef != nil {
|
| 106 |
- if err := daemon.TagImage(newRef, id.String()); err != nil {
|
|
| 106 |
+ if err := daemon.TagImageWithReference(id, newRef); err != nil {
|
|
| 107 | 107 |
return err |
| 108 | 108 |
} |
| 109 | 109 |
} |