47afe6bd |
package daemon
import (
"io" |
3aa4a007 |
"runtime" |
47afe6bd |
"strings"
|
764a9ed3 |
dist "github.com/docker/distribution" |
3a127939 |
"github.com/docker/distribution/reference" |
91e197d6 |
"github.com/docker/docker/api/types" |
47afe6bd |
"github.com/docker/docker/distribution" |
3d86b0c7 |
progressutils "github.com/docker/docker/distribution/utils" |
d453fe35 |
"github.com/docker/docker/errdefs" |
47afe6bd |
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/registry" |
7a855799 |
"github.com/opencontainers/go-digest" |
47afe6bd |
"golang.org/x/net/context"
)
// 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. |
ce8e529e |
func (daemon *Daemon) PullImage(ctx context.Context, image, tag, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { |
47afe6bd |
// 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, ":")
|
3a127939 |
ref, err := reference.ParseNormalizedNamed(image) |
47afe6bd |
if err != nil { |
87a12421 |
return errdefs.InvalidParameter(err) |
47afe6bd |
}
if tag != "" {
// The "tag" could actually be a digest.
var dgst digest.Digest |
7a855799 |
dgst, err = digest.Parse(tag) |
47afe6bd |
if err == nil { |
c85eb008 |
ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst) |
47afe6bd |
} else {
ref, err = reference.WithTag(ref, tag)
}
if err != nil { |
87a12421 |
return errdefs.InvalidParameter(err) |
47afe6bd |
}
}
|
ce8e529e |
return daemon.pullImageWithReference(ctx, ref, os, metaHeaders, authConfig, outStream) |
47afe6bd |
}
|
ce8e529e |
func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { |
47afe6bd |
// 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() { |
3d86b0c7 |
progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan) |
47afe6bd |
close(writesDone)
}()
|
a1fe1dc7 |
// Default to the host OS platform in case it hasn't been populated with an explicit value. |
ce8e529e |
if os == "" {
os = runtime.GOOS |
a1fe1dc7 |
} |
3aa4a007 |
|
47afe6bd |
imagePullConfig := &distribution.ImagePullConfig{ |
3c7676a0 |
Config: distribution.Config{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
ProgressOutput: progress.ChanOutput(progressChan),
RegistryService: daemon.RegistryService,
ImageEventLogger: daemon.LogImageEvent, |
ce8e529e |
MetadataStore: daemon.distributionMetadataStore,
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore), |
7b9a8f46 |
ReferenceStore: daemon.referenceStore, |
3c7676a0 |
},
DownloadManager: daemon.downloadManager,
Schema2Types: distribution.ImageTypes, |
ce8e529e |
OS: os, |
47afe6bd |
}
err := distribution.Pull(ctx, ref, imagePullConfig)
close(progressChan)
<-writesDone
return err
} |
87075353 |
|
9c559e6d |
// GetRepository returns a repository from the registry. |
e842c653 |
func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) { |
87075353 |
// get repository info
repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
if err != nil { |
764a9ed3 |
return nil, false, err |
87075353 |
}
// makes sure name is not empty or `scratch` |
3a127939 |
if err := distribution.ValidateRepoName(repoInfo.Name); err != nil { |
87a12421 |
return nil, false, errdefs.InvalidParameter(err) |
87075353 |
}
// get endpoints |
3a127939 |
endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name)) |
87075353 |
if err != nil { |
764a9ed3 |
return nil, false, err |
87075353 |
}
// retrieve repository |
764a9ed3 |
var (
confirmedV2 bool
repository dist.Repository
lastError error
)
for _, endpoint := range endpoints {
if endpoint.Version == registry.APIVersion1 {
continue
} |
87075353 |
|
764a9ed3 |
repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
if lastError == nil && confirmedV2 {
break |
87075353 |
}
} |
764a9ed3 |
return repository, confirmedV2, lastError |
87075353 |
} |