mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
3c7676a057
Move configurations into a single file. Abstract download manager in pull config. Add supports for schema2 only and schema2 type checking. Add interface for providing push layers. Abstract image store to generically handle configurations. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
148 lines
4.3 KiB
Go
148 lines
4.3 KiB
Go
package daemon
|
|
|
|
import (
|
|
"io"
|
|
"strings"
|
|
|
|
dist "github.com/docker/distribution"
|
|
"github.com/docker/distribution/digest"
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/builder"
|
|
"github.com/docker/docker/distribution"
|
|
"github.com/docker/docker/pkg/progress"
|
|
"github.com/docker/docker/reference"
|
|
"github.com/docker/docker/registry"
|
|
"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.
|
|
func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
// 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, ":")
|
|
|
|
ref, err := reference.ParseNamed(image)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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(reference.TrimNamed(ref), dgst)
|
|
} else {
|
|
ref, err = reference.WithTag(ref, tag)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream)
|
|
}
|
|
|
|
// 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.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
|
|
return nil, err
|
|
}
|
|
return daemon.GetImage(name)
|
|
}
|
|
|
|
func (daemon *Daemon) pullImageWithReference(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{
|
|
Config: distribution.Config{
|
|
MetaHeaders: metaHeaders,
|
|
AuthConfig: authConfig,
|
|
ProgressOutput: progress.ChanOutput(progressChan),
|
|
RegistryService: daemon.RegistryService,
|
|
ImageEventLogger: daemon.LogImageEvent,
|
|
MetadataStore: daemon.distributionMetadataStore,
|
|
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
|
|
ReferenceStore: daemon.referenceStore,
|
|
},
|
|
DownloadManager: daemon.downloadManager,
|
|
Schema2Types: distribution.ImageTypes,
|
|
}
|
|
|
|
err := distribution.Pull(ctx, ref, imagePullConfig)
|
|
close(progressChan)
|
|
<-writesDone
|
|
return err
|
|
}
|
|
|
|
// GetRepository returns a repository from the registry.
|
|
func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagged, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
|
|
// get repository info
|
|
repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
// makes sure name is not empty or `scratch`
|
|
if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
// get endpoints
|
|
endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
// retrieve repository
|
|
var (
|
|
confirmedV2 bool
|
|
repository dist.Repository
|
|
lastError error
|
|
)
|
|
|
|
for _, endpoint := range endpoints {
|
|
if endpoint.Version == registry.APIVersion1 {
|
|
continue
|
|
}
|
|
|
|
repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
|
|
if lastError == nil && confirmedV2 {
|
|
break
|
|
}
|
|
}
|
|
return repository, confirmedV2, lastError
|
|
}
|