dotcloud/docker

View on GitHub
distribution/config.go

Summary

Maintainability
A
0 mins
Test Coverage
package distribution // import "github.com/docker/docker/distribution"

import (
    "context"
    "encoding/json"
    "io"
    "runtime"

    "github.com/distribution/reference"
    "github.com/docker/distribution"
    "github.com/docker/distribution/manifest/schema2"
    "github.com/docker/docker/api/types/events"
    "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"
    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 string, action events.Action)
    // 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 err := image.CheckOS(os); err != nil {
        return nil, errors.Wrapf(err, "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()
}