Skip to content

Commit

Permalink
Merge pull request #23327 from dmcgowan/refactor-foreign-layer
Browse files Browse the repository at this point in the history
Refactor foreign sources to describable interfaces
  • Loading branch information
runcom committed Jun 7, 2016
2 parents 13d101d + 2c60430 commit f6ff9ac
Show file tree
Hide file tree
Showing 16 changed files with 105 additions and 103 deletions.
11 changes: 2 additions & 9 deletions distribution/pull_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ type v2LayerDescriptor struct {
V2MetadataService *metadata.V2MetadataService
tmpFile *os.File
verifier digest.Verifier
foreignSrc *distribution.Descriptor
src distribution.Descriptor
}

func (ld *v2LayerDescriptor) Key() string {
Expand Down Expand Up @@ -511,14 +511,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
repo: p.repo,
repoInfo: p.repoInfo,
V2MetadataService: p.V2MetadataService,
}

if d.MediaType == schema2.MediaTypeForeignLayer && len(d.URLs) > 0 {
if !layer.ForeignSourceSupported() {
return "", "", errors.New("foreign layers are not supported on this OS")
}

layerDescriptor.foreignSrc = &d
src: d,
}

descriptors = append(descriptors, layerDescriptor)
Expand Down
15 changes: 9 additions & 6 deletions distribution/pull_v2_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/registry/client/transport"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
)

func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
Expand All @@ -35,14 +35,17 @@ func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS)
return fmt.Errorf("Invalid base layer %q", v1img.Parent)
}

var _ layer.ForeignSourcer = &v2LayerDescriptor{}
var _ distribution.Describable = &v2LayerDescriptor{}

func (ld *v2LayerDescriptor) ForeignSource() *distribution.Descriptor {
return ld.foreignSrc
func (ld *v2LayerDescriptor) Descriptor() distribution.Descriptor {
if ld.src.MediaType == schema2.MediaTypeForeignLayer && len(ld.src.URLs) > 0 {
return ld.src
}
return distribution.Descriptor{}
}

func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
if ld.foreignSrc == nil {
if len(ld.src.URLs) == 0 {
blobs := ld.repo.Blobs(ctx)
return blobs.Open(ctx, ld.digest)
}
Expand All @@ -53,7 +56,7 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
)

// Find the first URL that results in a 200 result code.
for _, url := range ld.foreignSrc.URLs {
for _, url := range ld.src.URLs {
rsc = transport.NewHTTPReadSeeker(http.DefaultClient, url, nil)
_, err = rsc.Seek(0, os.SEEK_SET)
if err == nil {
Expand Down
6 changes: 3 additions & 3 deletions distribution/push_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ func (pd *v2PushDescriptor) DiffID() layer.DiffID {
}

func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error) {
if fs, ok := pd.layer.(layer.ForeignSourcer); ok {
if d := fs.ForeignSource(); d != nil {
if fs, ok := pd.layer.(distribution.Describable); ok {
if d := fs.Descriptor(); len(d.URLs) > 0 {
progress.Update(progressOutput, pd.ID(), "Skipped foreign layer")
return *d, nil
return d, nil
}
}

Expand Down
24 changes: 16 additions & 8 deletions distribution/xfer/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,15 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
return
}

var src *distribution.Descriptor
if fs, ok := descriptor.(layer.ForeignSourcer); ok {
src = fs.ForeignSource()
var src distribution.Descriptor
if fs, ok := descriptor.(distribution.Describable); ok {
src = fs.Descriptor()
}
if ds, ok := d.layerStore.(layer.DescribableStore); ok {
d.layer, err = ds.RegisterWithDescriptor(inflatedLayerData, parentLayer, src)
} else {
d.layer, err = d.layerStore.Register(inflatedLayerData, parentLayer)
}
d.layer, err = d.layerStore.RegisterForeign(inflatedLayerData, parentLayer, src)
if err != nil {
select {
case <-d.Transfer.Context().Done():
Expand Down Expand Up @@ -414,11 +418,15 @@ func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor Downloa
}
defer layerReader.Close()

var src *distribution.Descriptor
if fs, ok := l.(layer.ForeignSourcer); ok {
src = fs.ForeignSource()
var src distribution.Descriptor
if fs, ok := l.(distribution.Describable); ok {
src = fs.Descriptor()
}
if ds, ok := d.layerStore.(layer.DescribableStore); ok {
d.layer, err = ds.RegisterWithDescriptor(layerReader, parentLayer, src)
} else {
d.layer, err = d.layerStore.Register(layerReader, parentLayer)
}
d.layer, err = d.layerStore.RegisterForeign(layerReader, parentLayer, src)
if err != nil {
d.err = fmt.Errorf("failed to register layer: %v", err)
return
Expand Down
4 changes: 2 additions & 2 deletions distribution/xfer/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ func createChainIDFromParent(parent layer.ChainID, dgsts ...layer.DiffID) layer.
}

func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (layer.Layer, error) {
return ls.RegisterForeign(reader, parentID, nil)
return ls.RegisterWithDescriptor(reader, parentID, distribution.Descriptor{})
}

func (ls *mockLayerStore) RegisterForeign(reader io.Reader, parentID layer.ChainID, _ *distribution.Descriptor) (layer.Layer, error) {
func (ls *mockLayerStore) RegisterWithDescriptor(reader io.Reader, parentID layer.ChainID, _ distribution.Descriptor) (layer.Layer, error) {
var (
parent layer.Layer
err error
Expand Down
20 changes: 12 additions & 8 deletions image/tarexport/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
var parentLinks []parentLink

for _, m := range manifest {
if m.LayerSources != nil && !layer.ForeignSourceSupported() {
return fmt.Errorf("invalid manifest, foreign layers not supported on this operating system")
}

configPath, err := safePath(tmpDir, m.Config)
if err != nil {
return err
Expand Down Expand Up @@ -156,7 +152,7 @@ func (l *tarexporter) setParentID(id, parentID image.ID) error {
return l.is.SetParent(id, parentID)
}

func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, foreignSrc *distribution.Descriptor, progressOutput progress.Output) (layer.Layer, error) {
func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, foreignSrc distribution.Descriptor, progressOutput progress.Output) (layer.Layer, error) {
rawTar, err := os.Open(filename)
if err != nil {
logrus.Debugf("Error reading embedded tar: %v", err)
Expand All @@ -179,9 +175,17 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string,

progressReader := progress.NewProgressReader(inflatedLayerData, progressOutput, fileInfo.Size(), stringid.TruncateID(id), "Loading layer")

return l.ls.RegisterForeign(progressReader, rootFS.ChainID(), foreignSrc)
if ds, ok := l.ls.(layer.DescribableStore); ok {
return ds.RegisterWithDescriptor(progressReader, rootFS.ChainID(), foreignSrc)
}
return l.ls.Register(progressReader, rootFS.ChainID())

}

if ds, ok := l.ls.(layer.DescribableStore); ok {
return ds.RegisterWithDescriptor(inflatedLayerData, rootFS.ChainID(), foreignSrc)
}
return l.ls.RegisterForeign(inflatedLayerData, rootFS.ChainID(), foreignSrc)
return l.ls.Register(inflatedLayerData, rootFS.ChainID())
}

func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, outStream io.Writer) error {
Expand Down Expand Up @@ -303,7 +307,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
if err != nil {
return err
}
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, nil, progressOutput)
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, distribution.Descriptor{}, progressOutput)
if err != nil {
return err
}
Expand Down
36 changes: 18 additions & 18 deletions image/tarexport/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (s *saveSession) save(outStream io.Writer) error {
return nil
}

func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]*distribution.Descriptor, error) {
func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Descriptor, error) {
img, err := s.is.Get(id)
if err != nil {
return nil, err
Expand All @@ -228,7 +228,7 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]*distribution.Des

var parent digest.Digest
var layers []string
var foreignSrcs map[layer.DiffID]*distribution.Descriptor
var foreignSrcs map[layer.DiffID]distribution.Descriptor
for i := range img.RootFS.DiffIDs {
v1Img := image.V1Image{}
if i == len(img.RootFS.DiffIDs)-1 {
Expand All @@ -252,9 +252,9 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]*distribution.Des
}
layers = append(layers, v1Img.ID)
parent = v1ID
if src != nil {
if src.Digest != "" {
if foreignSrcs == nil {
foreignSrcs = make(map[layer.DiffID]*distribution.Descriptor)
foreignSrcs = make(map[layer.DiffID]distribution.Descriptor)
}
foreignSrcs[img.RootFS.DiffIDs[i]] = src
}
Expand All @@ -272,65 +272,65 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]*distribution.Des
return foreignSrcs, nil
}

func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (*distribution.Descriptor, error) {
func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (distribution.Descriptor, error) {
if _, exists := s.savedLayers[legacyImg.ID]; exists {
return nil, nil
return distribution.Descriptor{}, nil
}

outDir := filepath.Join(s.outDir, legacyImg.ID)
if err := os.Mkdir(outDir, 0755); err != nil {
return nil, err
return distribution.Descriptor{}, err
}

// todo: why is this version file here?
if err := ioutil.WriteFile(filepath.Join(outDir, legacyVersionFileName), []byte("1.0"), 0644); err != nil {
return nil, err
return distribution.Descriptor{}, err
}

imageConfig, err := json.Marshal(legacyImg)
if err != nil {
return nil, err
return distribution.Descriptor{}, err
}

if err := ioutil.WriteFile(filepath.Join(outDir, legacyConfigFileName), imageConfig, 0644); err != nil {
return nil, err
return distribution.Descriptor{}, err
}

// serialize filesystem
tarFile, err := os.Create(filepath.Join(outDir, legacyLayerFileName))
if err != nil {
return nil, err
return distribution.Descriptor{}, err
}
defer tarFile.Close()

l, err := s.ls.Get(id)
if err != nil {
return nil, err
return distribution.Descriptor{}, err
}
defer layer.ReleaseAndLog(s.ls, l)

arch, err := l.TarStream()
if err != nil {
return nil, err
return distribution.Descriptor{}, err
}
defer arch.Close()

if _, err := io.Copy(tarFile, arch); err != nil {
return nil, err
return distribution.Descriptor{}, err
}

for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
// todo: maybe save layer created timestamp?
if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
return nil, err
return distribution.Descriptor{}, err
}
}

s.savedLayers[legacyImg.ID] = struct{}{}

var src *distribution.Descriptor
if fs, ok := l.(layer.ForeignSourcer); ok {
src = fs.ForeignSource()
var src distribution.Descriptor
if fs, ok := l.(distribution.Describable); ok {
src = fs.Descriptor()
}
return src, nil
}
4 changes: 2 additions & 2 deletions image/tarexport/tarexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type manifestItem struct {
Config string
RepoTags []string
Layers []string
Parent image.ID `json:",omitempty"`
LayerSources map[layer.DiffID]*distribution.Descriptor `json:",omitempty"`
Parent image.ID `json:",omitempty"`
LayerSources map[layer.DiffID]distribution.Descriptor `json:",omitempty"`
}

type tarexporter struct {
Expand Down
10 changes: 4 additions & 6 deletions layer/filestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ var (
// digest.SHA384, // Currently not used
// digest.SHA512, // Currently not used
}

// ErrNoForeignSource is returned when no foreign source is set for a layer.
ErrNoForeignSource = errors.New("layer does not have a foreign source")
)

type fileMetadataStore struct {
Expand Down Expand Up @@ -103,7 +100,7 @@ func (fm *fileMetadataTransaction) SetCacheID(cacheID string) error {
return ioutil.WriteFile(filepath.Join(fm.root, "cache-id"), []byte(cacheID), 0644)
}

func (fm *fileMetadataTransaction) SetForeignSource(ref distribution.Descriptor) error {
func (fm *fileMetadataTransaction) SetDescriptor(ref distribution.Descriptor) error {
jsonRef, err := json.Marshal(ref)
if err != nil {
return err
Expand Down Expand Up @@ -204,11 +201,12 @@ func (fms *fileMetadataStore) GetCacheID(layer ChainID) (string, error) {
return content, nil
}

func (fms *fileMetadataStore) GetForeignSource(layer ChainID) (distribution.Descriptor, error) {
func (fms *fileMetadataStore) GetDescriptor(layer ChainID) (distribution.Descriptor, error) {
content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "descriptor.json"))
if err != nil {
if os.IsNotExist(err) {
return distribution.Descriptor{}, ErrNoForeignSource
// only return empty descriptor to represent what is stored
return distribution.Descriptor{}, nil
}
return distribution.Descriptor{}, err
}
Expand Down
19 changes: 8 additions & 11 deletions layer/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,6 @@ type Layer interface {
Metadata() (map[string]string, error)
}

// ForeignSourcer is an interface used to describe the source of layers
// and objects representing layers, when the source is a foreign URL.
type ForeignSourcer interface {
// ForeignSource returns the descriptor for this layer if it is
// a foreign layer, or nil for ordinary layers.
ForeignSource() *distribution.Descriptor
}

// RWLayer represents a layer which is
// read and writable
type RWLayer interface {
Expand Down Expand Up @@ -177,7 +169,6 @@ type MountInit func(root string) error
// read-only and read-write layers.
type Store interface {
Register(io.Reader, ChainID) (Layer, error)
RegisterForeign(io.Reader, ChainID, *distribution.Descriptor) (Layer, error)
Get(ChainID) (Layer, error)
Release(Layer) ([]Metadata, error)

Expand All @@ -191,14 +182,20 @@ type Store interface {
DriverName() string
}

// DescribableStore represents a layer store capable of storing
// descriptors for layers.
type DescribableStore interface {
RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
}

// MetadataTransaction represents functions for setting layer metadata
// with a single transaction.
type MetadataTransaction interface {
SetSize(int64) error
SetParent(parent ChainID) error
SetDiffID(DiffID) error
SetCacheID(string) error
SetForeignSource(distribution.Descriptor) error
SetDescriptor(distribution.Descriptor) error
TarSplitWriter(compressInput bool) (io.WriteCloser, error)

Commit(ChainID) error
Expand All @@ -218,7 +215,7 @@ type MetadataStore interface {
GetParent(ChainID) (ChainID, error)
GetDiffID(ChainID) (DiffID, error)
GetCacheID(ChainID) (string, error)
GetForeignSource(ChainID) (distribution.Descriptor, error)
GetDescriptor(ChainID) (distribution.Descriptor, error)
TarSplitReader(ChainID) (io.ReadCloser, error)

SetMountID(string, string) error
Expand Down
Loading

0 comments on commit f6ff9ac

Please sign in to comment.