123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- package daemon
- import (
- "github.com/Sirupsen/logrus"
- "github.com/docker/distribution/reference"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/backend"
- "github.com/docker/docker/builder"
- "github.com/docker/docker/image"
- "github.com/docker/docker/layer"
- "github.com/docker/docker/pkg/stringid"
- "github.com/docker/docker/registry"
- "github.com/pkg/errors"
- "golang.org/x/net/context"
- "io"
- )
- type releaseableLayer struct {
- layerStore layer.Store
- roLayer layer.Layer
- rwLayer layer.RWLayer
- }
- func (rl *releaseableLayer) Mount() (string, error) {
- if rl.roLayer == nil {
- return "", errors.New("can not mount an image with no root FS")
- }
- var err error
- mountID := stringid.GenerateRandomID()
- rl.rwLayer, err = rl.layerStore.CreateRWLayer(mountID, rl.roLayer.ChainID(), nil)
- if err != nil {
- return "", errors.Wrap(err, "failed to create rwlayer")
- }
- return rl.rwLayer.Mount("")
- }
- func (rl *releaseableLayer) Release() error {
- rl.releaseRWLayer()
- return rl.releaseROLayer()
- }
- func (rl *releaseableLayer) releaseRWLayer() error {
- if rl.rwLayer == nil {
- return nil
- }
- metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer)
- layer.LogReleaseMetadata(metadata)
- if err != nil {
- logrus.Errorf("Failed to release RWLayer: %s", err)
- }
- return err
- }
- func (rl *releaseableLayer) releaseROLayer() error {
- if rl.roLayer == nil {
- return nil
- }
- metadata, err := rl.layerStore.Release(rl.roLayer)
- layer.LogReleaseMetadata(metadata)
- return err
- }
- func newReleasableLayerForImage(img *image.Image, layerStore layer.Store) (builder.ReleaseableLayer, error) {
- if img.RootFS.ChainID() == "" {
- return nil, nil
- }
- // Hold a reference to the image layer so that it can't be removed before
- // it is released
- roLayer, err := layerStore.Get(img.RootFS.ChainID())
- if err != nil {
- return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
- }
- return &releaseableLayer{layerStore: layerStore, roLayer: roLayer}, nil
- }
- // TODO: could this use the regular daemon PullImage ?
- func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (*image.Image, error) {
- ref, err := reference.ParseNormalizedNamed(name)
- if err != nil {
- return nil, err
- }
- ref = reference.TagNameOnly(ref)
- pullRegistryAuth := &types.AuthConfig{}
- if len(authConfigs) > 0 {
- // The request came with a full auth config, use it
- 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)
- }
- // GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
- // Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
- // leaking of layers.
- func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ReleaseableLayer, error) {
- if !opts.ForcePull {
- image, _ := daemon.GetImage(refOrID)
- // TODO: shouldn't we error out if error is different from "not found" ?
- if image != nil {
- layer, err := newReleasableLayerForImage(image, daemon.layerStore)
- return image, layer, err
- }
- }
- image, err := daemon.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output)
- if err != nil {
- return nil, nil, err
- }
- layer, err := newReleasableLayerForImage(image, daemon.layerStore)
- return image, layer, err
- }
|