| package distribution // import "github.com/docker/docker/distribution" | |
| import ( | |
| "context" | |
| "encoding/json" | |
| "io" | |
| "runtime" | |
| "github.com/docker/distribution" | |
| "github.com/docker/distribution/manifest/schema2" | |
| "github.com/docker/distribution/reference" | |
| "github.com/docker/docker/api/types/registry" | |
| "github.com/docker/docker/distribution/metadata" | |
| "github.com/docker/docker/distribution/xfer" | |
| "github.com/docker/docker/image" | |
| "github.com/docker/docker/layer" | |
| "github.com/docker/docker/pkg/progress" | |
| "github.com/docker/docker/pkg/system" | |
| refstore "github.com/docker/docker/reference" | |
| registrypkg "github.com/docker/docker/registry" | |
| "github.com/opencontainers/go-digest" | |
| ocispec "github.com/opencontainers/image-spec/specs-go/v1" | |
| "github.com/pkg/errors" | |
| ) | |
| // Config stores configuration for communicating | |
| // with a registry. | |
| type Config struct { | |
| // MetaHeaders stores HTTP headers with metadata about the image | |
| MetaHeaders map[string][]string | |
| // AuthConfig holds authentication credentials for authenticating with | |
| // the registry. | |
| AuthConfig *registry.AuthConfig | |
| // ProgressOutput is the interface for showing the status of the pull | |
| // operation. | |
| ProgressOutput progress.Output | |
| // RegistryService is the registry service to use for TLS configuration | |
| // and endpoint lookup. | |
| RegistryService RegistryResolver | |
| // ImageEventLogger notifies events for a given image | |
| ImageEventLogger func(id, name, action string) | |
| // MetadataStore is the storage backend for distribution-specific | |
| // metadata. | |
| MetadataStore metadata.Store | |
| // ImageStore manages images. | |
| ImageStore ImageConfigStore | |
| // ReferenceStore manages tags. This value is optional, when excluded | |
| // content will not be tagged. | |
| ReferenceStore refstore.Store | |
| } | |
| // ImagePullConfig stores pull configuration. | |
| type ImagePullConfig struct { | |
| Config | |
| // DownloadManager manages concurrent pulls. | |
| DownloadManager *xfer.LayerDownloadManager | |
| // Schema2Types is an optional list of valid schema2 configuration types | |
| // allowed by the pull operation. If omitted, the default list of accepted | |
| // types is used. | |
| Schema2Types []string | |
| // Platform is the requested platform of the image being pulled | |
| Platform *ocispec.Platform | |
| } | |
| // ImagePushConfig stores push configuration. | |
| type ImagePushConfig struct { | |
| Config | |
| // ConfigMediaType is the configuration media type for | |
| // schema2 manifests. | |
| ConfigMediaType string | |
| // LayerStores manages layers. | |
| LayerStores PushLayerProvider | |
| // UploadManager dispatches uploads. | |
| UploadManager *xfer.LayerUploadManager | |
| } | |
| // RegistryResolver is used for TLS configuration and endpoint lookup. | |
| type RegistryResolver interface { | |
| LookupPushEndpoints(hostname string) (endpoints []registrypkg.APIEndpoint, err error) | |
| LookupPullEndpoints(hostname string) (endpoints []registrypkg.APIEndpoint, err error) | |
| ResolveRepository(name reference.Named) (*registrypkg.RepositoryInfo, error) | |
| } | |
| // ImageConfigStore handles storing and getting image configurations | |
| // by digest. Allows getting an image configurations rootfs from the | |
| // configuration. | |
| type ImageConfigStore interface { | |
| Put(context.Context, []byte) (digest.Digest, error) | |
| Get(context.Context, digest.Digest) ([]byte, error) | |
| } | |
| // PushLayerProvider provides layers to be pushed by ChainID. | |
| type PushLayerProvider interface { | |
| Get(layer.ChainID) (PushLayer, error) | |
| } | |
| // PushLayer is a pushable layer with metadata about the layer | |
| // and access to the content of the layer. | |
| type PushLayer interface { | |
| ChainID() layer.ChainID | |
| DiffID() layer.DiffID | |
| Parent() PushLayer | |
| Open() (io.ReadCloser, error) | |
| Size() int64 | |
| MediaType() string | |
| Release() | |
| } | |
| type imageConfigStore struct { | |
| image.Store | |
| } | |
| // NewImageConfigStoreFromStore returns an ImageConfigStore backed | |
| // by an image.Store for container images. | |
| func NewImageConfigStoreFromStore(is image.Store) ImageConfigStore { | |
| return &imageConfigStore{ | |
| Store: is, | |
| } | |
| } | |
| func (s *imageConfigStore) Put(_ context.Context, c []byte) (digest.Digest, error) { | |
| id, err := s.Store.Create(c) | |
| return digest.Digest(id), err | |
| } | |
| func (s *imageConfigStore) Get(_ context.Context, d digest.Digest) ([]byte, error) { | |
| img, err := s.Store.Get(image.ID(d)) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return img.RawJSON(), nil | |
| } | |
| func rootFSFromConfig(c []byte) (*image.RootFS, error) { | |
| var unmarshalledConfig image.Image | |
| if err := json.Unmarshal(c, &unmarshalledConfig); err != nil { | |
| return nil, err | |
| } | |
| return unmarshalledConfig.RootFS, nil | |
| } | |
| func platformFromConfig(c []byte) (*ocispec.Platform, error) { | |
| var unmarshalledConfig image.Image | |
| if err := json.Unmarshal(c, &unmarshalledConfig); err != nil { | |
| return nil, err | |
| } | |
| os := unmarshalledConfig.OS | |
| if os == "" { | |
| os = runtime.GOOS | |
| } | |
| if !system.IsOSSupported(os) { | |
| return nil, errors.Wrapf(system.ErrNotSupportedOperatingSystem, "image operating system %q cannot be used on this platform", os) | |
| } | |
| return &ocispec.Platform{ | |
| OS: os, | |
| Architecture: unmarshalledConfig.Architecture, | |
| Variant: unmarshalledConfig.Variant, | |
| OSVersion: unmarshalledConfig.OSVersion, | |
| }, nil | |
| } | |
| type storeLayerProvider struct { | |
| ls layer.Store | |
| } | |
| // NewLayerProvidersFromStore returns layer providers backed by | |
| // an instance of LayerStore. Only getting layers as gzipped | |
| // tars is supported. | |
| func NewLayerProvidersFromStore(ls layer.Store) PushLayerProvider { | |
| return &storeLayerProvider{ls: ls} | |
| } | |
| func (p *storeLayerProvider) Get(lid layer.ChainID) (PushLayer, error) { | |
| if lid == "" { | |
| return &storeLayer{ | |
| Layer: layer.EmptyLayer, | |
| }, nil | |
| } | |
| l, err := p.ls.Get(lid) | |
| if err != nil { | |
| return nil, err | |
| } | |
| sl := storeLayer{ | |
| Layer: l, | |
| ls: p.ls, | |
| } | |
| if d, ok := l.(distribution.Describable); ok { | |
| return &describableStoreLayer{ | |
| storeLayer: sl, | |
| describable: d, | |
| }, nil | |
| } | |
| return &sl, nil | |
| } | |
| type storeLayer struct { | |
| layer.Layer | |
| ls layer.Store | |
| } | |
| func (l *storeLayer) Parent() PushLayer { | |
| p := l.Layer.Parent() | |
| if p == nil { | |
| return nil | |
| } | |
| sl := storeLayer{ | |
| Layer: p, | |
| ls: l.ls, | |
| } | |
| if d, ok := p.(distribution.Describable); ok { | |
| return &describableStoreLayer{ | |
| storeLayer: sl, | |
| describable: d, | |
| } | |
| } | |
| return &sl | |
| } | |
| func (l *storeLayer) Open() (io.ReadCloser, error) { | |
| return l.Layer.TarStream() | |
| } | |
| func (l *storeLayer) Size() int64 { | |
| return l.Layer.DiffSize() | |
| } | |
| func (l *storeLayer) MediaType() string { | |
| // layer store always returns uncompressed tars | |
| return schema2.MediaTypeUncompressedLayer | |
| } | |
| func (l *storeLayer) Release() { | |
| if l.ls != nil { | |
| layer.ReleaseAndLog(l.ls, l.Layer) | |
| } | |
| } | |
| type describableStoreLayer struct { | |
| storeLayer | |
| describable distribution.Describable | |
| } | |
| func (l *describableStoreLayer) Descriptor() distribution.Descriptor { | |
| return l.describable.Descriptor() | |
| } |