Merge pull request #22866 from jstarks/foreign_layers
Support layers from external URLs
This commit is contained in:
commit
7d08f3a5ad
|
@ -133,6 +133,7 @@ type v2LayerDescriptor struct {
|
||||||
V2MetadataService *metadata.V2MetadataService
|
V2MetadataService *metadata.V2MetadataService
|
||||||
tmpFile *os.File
|
tmpFile *os.File
|
||||||
verifier digest.Verifier
|
verifier digest.Verifier
|
||||||
|
foreignSrc *distribution.Descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ld *v2LayerDescriptor) Key() string {
|
func (ld *v2LayerDescriptor) Key() string {
|
||||||
|
@ -180,9 +181,8 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpFile := ld.tmpFile
|
tmpFile := ld.tmpFile
|
||||||
blobs := ld.repo.Blobs(ctx)
|
|
||||||
|
|
||||||
layerDownload, err := blobs.Open(ctx, ld.digest)
|
layerDownload, err := ld.open(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Error initiating layer download: %v", err)
|
logrus.Errorf("Error initiating layer download: %v", err)
|
||||||
if err == distribution.ErrBlobUnknown {
|
if err == distribution.ErrBlobUnknown {
|
||||||
|
@ -501,6 +501,29 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||||
return imageID, manifestDigest, nil
|
return imageID, manifestDigest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var descriptors []xfer.DownloadDescriptor
|
||||||
|
|
||||||
|
// Note that the order of this loop is in the direction of bottom-most
|
||||||
|
// to top-most, so that the downloads slice gets ordered correctly.
|
||||||
|
for _, d := range mfst.Layers {
|
||||||
|
layerDescriptor := &v2LayerDescriptor{
|
||||||
|
digest: d.Digest,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptors = append(descriptors, layerDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
configChan := make(chan []byte, 1)
|
configChan := make(chan []byte, 1)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
var cancel func()
|
var cancel func()
|
||||||
|
@ -517,21 +540,6 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||||
configChan <- configJSON
|
configChan <- configJSON
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var descriptors []xfer.DownloadDescriptor
|
|
||||||
|
|
||||||
// Note that the order of this loop is in the direction of bottom-most
|
|
||||||
// to top-most, so that the downloads slice gets ordered correctly.
|
|
||||||
for _, d := range mfst.References() {
|
|
||||||
layerDescriptor := &v2LayerDescriptor{
|
|
||||||
digest: d.Digest,
|
|
||||||
repo: p.repo,
|
|
||||||
repoInfo: p.repoInfo,
|
|
||||||
V2MetadataService: p.V2MetadataService,
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptors = append(descriptors, layerDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
configJSON []byte // raw serialized image config
|
configJSON []byte // raw serialized image config
|
||||||
unmarshalledConfig image.Image // deserialized image config
|
unmarshalledConfig image.Image // deserialized image config
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
package distribution
|
package distribution
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
)
|
)
|
||||||
|
@ -10,3 +12,8 @@ import (
|
||||||
func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
|
func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
|
||||||
|
blobs := ld.repo.Blobs(ctx)
|
||||||
|
return blobs.Open(ctx, ld.digest)
|
||||||
|
}
|
||||||
|
|
|
@ -5,9 +5,15 @@ package distribution
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/docker/distribution/context"
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/layer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
|
func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
|
||||||
|
@ -28,3 +34,33 @@ func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Invalid base layer %q", v1img.Parent)
|
return fmt.Errorf("Invalid base layer %q", v1img.Parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ layer.ForeignSourcer = &v2LayerDescriptor{}
|
||||||
|
|
||||||
|
func (ld *v2LayerDescriptor) ForeignSource() *distribution.Descriptor {
|
||||||
|
return ld.foreignSrc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekCloser, error) {
|
||||||
|
if ld.foreignSrc == nil {
|
||||||
|
blobs := ld.repo.Blobs(ctx)
|
||||||
|
return blobs.Open(ctx, ld.digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
rsc distribution.ReadSeekCloser
|
||||||
|
)
|
||||||
|
|
||||||
|
// Find the first URL that results in a 200 result code.
|
||||||
|
for _, url := range ld.foreignSrc.URLs {
|
||||||
|
rsc = transport.NewHTTPReadSeeker(http.DefaultClient, url, nil)
|
||||||
|
_, err = rsc.Seek(0, os.SEEK_SET)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rsc.Close()
|
||||||
|
rsc = nil
|
||||||
|
}
|
||||||
|
return rsc, err
|
||||||
|
}
|
||||||
|
|
|
@ -240,6 +240,13 @@ func (pd *v2PushDescriptor) DiffID() layer.DiffID {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error) {
|
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 {
|
||||||
|
progress.Update(progressOutput, pd.ID(), "Skipped foreign layer")
|
||||||
|
return *d, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diffID := pd.DiffID()
|
diffID := pd.DiffID()
|
||||||
|
|
||||||
pd.pushState.Lock()
|
pd.pushState.Lock()
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
@ -318,7 +319,11 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
d.layer, err = d.layerStore.Register(inflatedLayerData, parentLayer)
|
var src *distribution.Descriptor
|
||||||
|
if fs, ok := descriptor.(layer.ForeignSourcer); ok {
|
||||||
|
src = fs.ForeignSource()
|
||||||
|
}
|
||||||
|
d.layer, err = d.layerStore.RegisterForeign(inflatedLayerData, parentLayer, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
case <-d.Transfer.Context().Done():
|
case <-d.Transfer.Context().Done():
|
||||||
|
@ -409,7 +414,11 @@ func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor Downloa
|
||||||
}
|
}
|
||||||
defer layerReader.Close()
|
defer layerReader.Close()
|
||||||
|
|
||||||
d.layer, err = d.layerStore.Register(layerReader, parentLayer)
|
var src *distribution.Descriptor
|
||||||
|
if fs, ok := l.(layer.ForeignSourcer); ok {
|
||||||
|
src = fs.ForeignSource()
|
||||||
|
}
|
||||||
|
d.layer, err = d.layerStore.RegisterForeign(layerReader, parentLayer, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.err = fmt.Errorf("failed to register layer: %v", err)
|
d.err = fmt.Errorf("failed to register layer: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
|
@ -71,6 +72,10 @@ func createChainIDFromParent(parent layer.ChainID, dgsts ...layer.DiffID) layer.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (layer.Layer, error) {
|
func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (layer.Layer, error) {
|
||||||
|
return ls.RegisterForeign(reader, parentID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *mockLayerStore) RegisterForeign(reader io.Reader, parentID layer.ChainID, _ *distribution.Descriptor) (layer.Layer, error) {
|
||||||
var (
|
var (
|
||||||
parent layer.Layer
|
parent layer.Layer
|
||||||
err error
|
err error
|
||||||
|
|
|
@ -87,7 +87,7 @@ clone git github.com/boltdb/bolt v1.2.1
|
||||||
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
||||||
|
|
||||||
# get graph and distribution packages
|
# get graph and distribution packages
|
||||||
clone git github.com/docker/distribution 9ec0d742d69f77caa4dd5f49ceb70c3067d39f30
|
clone git github.com/docker/distribution 5bbf65499960b184fe8e0f045397375e1a6722b8
|
||||||
clone git github.com/vbatts/tar-split v0.9.11
|
clone git github.com/vbatts/tar-split v0.9.11
|
||||||
|
|
||||||
# get go-zfs packages
|
# get go-zfs packages
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/image/v1"
|
"github.com/docker/docker/image/v1"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
|
@ -63,6 +64,10 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
||||||
var parentLinks []parentLink
|
var parentLinks []parentLink
|
||||||
|
|
||||||
for _, m := range manifest {
|
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)
|
configPath, err := safePath(tmpDir, m.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -92,7 +97,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
||||||
r.Append(diffID)
|
r.Append(diffID)
|
||||||
newLayer, err := l.ls.Get(r.ChainID())
|
newLayer, err := l.ls.Get(r.ChainID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), progressOutput)
|
newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), m.LayerSources[diffID], progressOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -151,7 +156,7 @@ func (l *tarexporter) setParentID(id, parentID image.ID) error {
|
||||||
return l.is.SetParent(id, parentID)
|
return l.is.SetParent(id, parentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, 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)
|
rawTar, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error reading embedded tar: %v", err)
|
logrus.Debugf("Error reading embedded tar: %v", err)
|
||||||
|
@ -174,9 +179,9 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string,
|
||||||
|
|
||||||
progressReader := progress.NewProgressReader(inflatedLayerData, progressOutput, fileInfo.Size(), stringid.TruncateID(id), "Loading layer")
|
progressReader := progress.NewProgressReader(inflatedLayerData, progressOutput, fileInfo.Size(), stringid.TruncateID(id), "Loading layer")
|
||||||
|
|
||||||
return l.ls.Register(progressReader, rootFS.ChainID())
|
return l.ls.RegisterForeign(progressReader, rootFS.ChainID(), foreignSrc)
|
||||||
}
|
}
|
||||||
return l.ls.Register(inflatedLayerData, rootFS.ChainID())
|
return l.ls.RegisterForeign(inflatedLayerData, rootFS.ChainID(), foreignSrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, outStream io.Writer) error {
|
func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, outStream io.Writer) error {
|
||||||
|
@ -298,7 +303,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, progressOutput)
|
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, nil, progressOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/image/v1"
|
"github.com/docker/docker/image/v1"
|
||||||
|
@ -131,7 +132,8 @@ func (s *saveSession) save(outStream io.Writer) error {
|
||||||
var parentLinks []parentLink
|
var parentLinks []parentLink
|
||||||
|
|
||||||
for id, imageDescr := range s.images {
|
for id, imageDescr := range s.images {
|
||||||
if err = s.saveImage(id); err != nil {
|
foreignSrcs, err := s.saveImage(id)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,9 +153,10 @@ func (s *saveSession) save(outStream io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest = append(manifest, manifestItem{
|
manifest = append(manifest, manifestItem{
|
||||||
Config: digest.Digest(id).Hex() + ".json",
|
Config: digest.Digest(id).Hex() + ".json",
|
||||||
RepoTags: repoTags,
|
RepoTags: repoTags,
|
||||||
Layers: layers,
|
Layers: layers,
|
||||||
|
LayerSources: foreignSrcs,
|
||||||
})
|
})
|
||||||
|
|
||||||
parentID, _ := s.is.GetParent(id)
|
parentID, _ := s.is.GetParent(id)
|
||||||
|
@ -213,18 +216,19 @@ func (s *saveSession) save(outStream io.Writer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *saveSession) saveImage(id image.ID) error {
|
func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]*distribution.Descriptor, error) {
|
||||||
img, err := s.is.Get(id)
|
img, err := s.is.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(img.RootFS.DiffIDs) == 0 {
|
if len(img.RootFS.DiffIDs) == 0 {
|
||||||
return fmt.Errorf("empty export - not implemented")
|
return nil, fmt.Errorf("empty export - not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent digest.Digest
|
var parent digest.Digest
|
||||||
var layers []string
|
var layers []string
|
||||||
|
var foreignSrcs map[layer.DiffID]*distribution.Descriptor
|
||||||
for i := range img.RootFS.DiffIDs {
|
for i := range img.RootFS.DiffIDs {
|
||||||
v1Img := image.V1Image{}
|
v1Img := image.V1Image{}
|
||||||
if i == len(img.RootFS.DiffIDs)-1 {
|
if i == len(img.RootFS.DiffIDs)-1 {
|
||||||
|
@ -234,7 +238,7 @@ func (s *saveSession) saveImage(id image.ID) error {
|
||||||
rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
|
rootFS.DiffIDs = rootFS.DiffIDs[:i+1]
|
||||||
v1ID, err := v1.CreateID(v1Img, rootFS.ChainID(), parent)
|
v1ID, err := v1.CreateID(v1Img, rootFS.ChainID(), parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
v1Img.ID = v1ID.Hex()
|
v1Img.ID = v1ID.Hex()
|
||||||
|
@ -242,79 +246,91 @@ func (s *saveSession) saveImage(id image.ID) error {
|
||||||
v1Img.Parent = parent.Hex()
|
v1Img.Parent = parent.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.saveLayer(rootFS.ChainID(), v1Img, img.Created); err != nil {
|
src, err := s.saveLayer(rootFS.ChainID(), v1Img, img.Created)
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
layers = append(layers, v1Img.ID)
|
layers = append(layers, v1Img.ID)
|
||||||
parent = v1ID
|
parent = v1ID
|
||||||
|
if src != nil {
|
||||||
|
if foreignSrcs == nil {
|
||||||
|
foreignSrcs = make(map[layer.DiffID]*distribution.Descriptor)
|
||||||
|
}
|
||||||
|
foreignSrcs[img.RootFS.DiffIDs[i]] = src
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configFile := filepath.Join(s.outDir, digest.Digest(id).Hex()+".json")
|
configFile := filepath.Join(s.outDir, digest.Digest(id).Hex()+".json")
|
||||||
if err := ioutil.WriteFile(configFile, img.RawJSON(), 0644); err != nil {
|
if err := ioutil.WriteFile(configFile, img.RawJSON(), 0644); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := system.Chtimes(configFile, img.Created, img.Created); err != nil {
|
if err := system.Chtimes(configFile, img.Created, img.Created); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.images[id].layers = layers
|
s.images[id].layers = layers
|
||||||
return nil
|
return foreignSrcs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) error {
|
func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, createdTime time.Time) (*distribution.Descriptor, error) {
|
||||||
if _, exists := s.savedLayers[legacyImg.ID]; exists {
|
if _, exists := s.savedLayers[legacyImg.ID]; exists {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
outDir := filepath.Join(s.outDir, legacyImg.ID)
|
outDir := filepath.Join(s.outDir, legacyImg.ID)
|
||||||
if err := os.Mkdir(outDir, 0755); err != nil {
|
if err := os.Mkdir(outDir, 0755); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: why is this version file here?
|
// todo: why is this version file here?
|
||||||
if err := ioutil.WriteFile(filepath.Join(outDir, legacyVersionFileName), []byte("1.0"), 0644); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(outDir, legacyVersionFileName), []byte("1.0"), 0644); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
imageConfig, err := json.Marshal(legacyImg)
|
imageConfig, err := json.Marshal(legacyImg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(outDir, legacyConfigFileName), imageConfig, 0644); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(outDir, legacyConfigFileName), imageConfig, 0644); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize filesystem
|
// serialize filesystem
|
||||||
tarFile, err := os.Create(filepath.Join(outDir, legacyLayerFileName))
|
tarFile, err := os.Create(filepath.Join(outDir, legacyLayerFileName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer tarFile.Close()
|
defer tarFile.Close()
|
||||||
|
|
||||||
l, err := s.ls.Get(id)
|
l, err := s.ls.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer layer.ReleaseAndLog(s.ls, l)
|
defer layer.ReleaseAndLog(s.ls, l)
|
||||||
|
|
||||||
arch, err := l.TarStream()
|
arch, err := l.TarStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer arch.Close()
|
defer arch.Close()
|
||||||
|
|
||||||
if _, err := io.Copy(tarFile, arch); err != nil {
|
if _, err := io.Copy(tarFile, arch); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
|
for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
|
||||||
// todo: maybe save layer created timestamp?
|
// todo: maybe save layer created timestamp?
|
||||||
if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
|
if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.savedLayers[legacyImg.ID] = struct{}{}
|
s.savedLayers[legacyImg.ID] = struct{}{}
|
||||||
return nil
|
|
||||||
|
var src *distribution.Descriptor
|
||||||
|
if fs, ok := l.(layer.ForeignSourcer); ok {
|
||||||
|
src = fs.ForeignSource()
|
||||||
|
}
|
||||||
|
return src, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package tarexport
|
package tarexport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/reference"
|
"github.com/docker/docker/reference"
|
||||||
|
@ -15,10 +16,11 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type manifestItem struct {
|
type manifestItem struct {
|
||||||
Config string
|
Config string
|
||||||
RepoTags []string
|
RepoTags []string
|
||||||
Layers []string
|
Layers []string
|
||||||
Parent image.ID `json:",omitempty"`
|
Parent image.ID `json:",omitempty"`
|
||||||
|
LayerSources map[layer.DiffID]*distribution.Descriptor `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type tarexporter struct {
|
type tarexporter struct {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package layer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
)
|
)
|
||||||
|
@ -24,6 +26,9 @@ var (
|
||||||
// digest.SHA384, // Currently not used
|
// digest.SHA384, // Currently not used
|
||||||
// digest.SHA512, // 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 {
|
type fileMetadataStore struct {
|
||||||
|
@ -98,6 +103,14 @@ func (fm *fileMetadataTransaction) SetCacheID(cacheID string) error {
|
||||||
return ioutil.WriteFile(filepath.Join(fm.root, "cache-id"), []byte(cacheID), 0644)
|
return ioutil.WriteFile(filepath.Join(fm.root, "cache-id"), []byte(cacheID), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fm *fileMetadataTransaction) SetForeignSource(ref distribution.Descriptor) error {
|
||||||
|
jsonRef, err := json.Marshal(ref)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(filepath.Join(fm.root, "descriptor.json"), jsonRef, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
func (fm *fileMetadataTransaction) TarSplitWriter(compressInput bool) (io.WriteCloser, error) {
|
func (fm *fileMetadataTransaction) TarSplitWriter(compressInput bool) (io.WriteCloser, error) {
|
||||||
f, err := os.OpenFile(filepath.Join(fm.root, "tar-split.json.gz"), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
|
f, err := os.OpenFile(filepath.Join(fm.root, "tar-split.json.gz"), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -191,6 +204,23 @@ func (fms *fileMetadataStore) GetCacheID(layer ChainID) (string, error) {
|
||||||
return content, nil
|
return content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fms *fileMetadataStore) GetForeignSource(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
|
||||||
|
}
|
||||||
|
return distribution.Descriptor{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ref distribution.Descriptor
|
||||||
|
err = json.Unmarshal(content, &ref)
|
||||||
|
if err != nil {
|
||||||
|
return distribution.Descriptor{}, err
|
||||||
|
}
|
||||||
|
return ref, err
|
||||||
|
}
|
||||||
|
|
||||||
func (fms *fileMetadataStore) TarSplitReader(layer ChainID) (io.ReadCloser, error) {
|
func (fms *fileMetadataStore) TarSplitReader(layer ChainID) (io.ReadCloser, error) {
|
||||||
fz, err := os.Open(fms.getLayerFilename(layer, "tar-split.json.gz"))
|
fz, err := os.Open(fms.getLayerFilename(layer, "tar-split.json.gz"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
)
|
)
|
||||||
|
@ -107,6 +108,14 @@ type Layer interface {
|
||||||
Metadata() (map[string]string, error)
|
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
|
// RWLayer represents a layer which is
|
||||||
// read and writable
|
// read and writable
|
||||||
type RWLayer interface {
|
type RWLayer interface {
|
||||||
|
@ -168,6 +177,7 @@ type MountInit func(root string) error
|
||||||
// read-only and read-write layers.
|
// read-only and read-write layers.
|
||||||
type Store interface {
|
type Store interface {
|
||||||
Register(io.Reader, ChainID) (Layer, error)
|
Register(io.Reader, ChainID) (Layer, error)
|
||||||
|
RegisterForeign(io.Reader, ChainID, *distribution.Descriptor) (Layer, error)
|
||||||
Get(ChainID) (Layer, error)
|
Get(ChainID) (Layer, error)
|
||||||
Release(Layer) ([]Metadata, error)
|
Release(Layer) ([]Metadata, error)
|
||||||
|
|
||||||
|
@ -188,6 +198,7 @@ type MetadataTransaction interface {
|
||||||
SetParent(parent ChainID) error
|
SetParent(parent ChainID) error
|
||||||
SetDiffID(DiffID) error
|
SetDiffID(DiffID) error
|
||||||
SetCacheID(string) error
|
SetCacheID(string) error
|
||||||
|
SetForeignSource(distribution.Descriptor) error
|
||||||
TarSplitWriter(compressInput bool) (io.WriteCloser, error)
|
TarSplitWriter(compressInput bool) (io.WriteCloser, error)
|
||||||
|
|
||||||
Commit(ChainID) error
|
Commit(ChainID) error
|
||||||
|
@ -207,6 +218,7 @@ type MetadataStore interface {
|
||||||
GetParent(ChainID) (ChainID, error)
|
GetParent(ChainID) (ChainID, error)
|
||||||
GetDiffID(ChainID) (DiffID, error)
|
GetDiffID(ChainID) (DiffID, error)
|
||||||
GetCacheID(ChainID) (string, error)
|
GetCacheID(ChainID) (string, error)
|
||||||
|
GetForeignSource(ChainID) (distribution.Descriptor, error)
|
||||||
TarSplitReader(ChainID) (io.ReadCloser, error)
|
TarSplitReader(ChainID) (io.ReadCloser, error)
|
||||||
|
|
||||||
SetMountID(string, string) error
|
SetMountID(string, string) error
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
@ -137,6 +138,13 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
|
||||||
references: map[Layer]struct{}{},
|
references: map[Layer]struct{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreignSrc, err := ls.store.GetForeignSource(layer)
|
||||||
|
if err == nil {
|
||||||
|
cl.foreignSrc = &foreignSrc
|
||||||
|
} else if err != ErrNoForeignSource {
|
||||||
|
return nil, fmt.Errorf("failed to get foreign reference for %s: %s", layer, err)
|
||||||
|
}
|
||||||
|
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
p, err := ls.loadLayer(parent)
|
p, err := ls.loadLayer(parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -228,6 +236,10 @@ func (ls *layerStore) applyTar(tx MetadataTransaction, ts io.Reader, parent stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
|
func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
|
||||||
|
return ls.RegisterForeign(ts, parent, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *layerStore) RegisterForeign(ts io.Reader, parent ChainID, foreignSrc *distribution.Descriptor) (Layer, error) {
|
||||||
// err is used to hold the error which will always trigger
|
// err is used to hold the error which will always trigger
|
||||||
// cleanup of creates sources but may not be an error returned
|
// cleanup of creates sources but may not be an error returned
|
||||||
// to the caller (already exists).
|
// to the caller (already exists).
|
||||||
|
@ -258,6 +270,7 @@ func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
|
||||||
layer := &roLayer{
|
layer := &roLayer{
|
||||||
parent: p,
|
parent: p,
|
||||||
cacheID: stringid.GenerateRandomID(),
|
cacheID: stringid.GenerateRandomID(),
|
||||||
|
foreignSrc: foreignSrc,
|
||||||
referenceCount: 1,
|
referenceCount: 1,
|
||||||
layerStore: ls,
|
layerStore: ls,
|
||||||
references: map[Layer]struct{}{},
|
references: map[Layer]struct{}{},
|
||||||
|
|
|
@ -7,3 +7,9 @@ import "github.com/docker/docker/pkg/stringid"
|
||||||
func (ls *layerStore) mountID(name string) string {
|
func (ls *layerStore) mountID(name string) string {
|
||||||
return stringid.GenerateRandomID()
|
return stringid.GenerateRandomID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForeignSourceSupported returns whether layers downloaded from foreign sources are
|
||||||
|
// supported in this daemon.
|
||||||
|
func ForeignSourceSupported() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -96,3 +96,9 @@ func (ls *layerStore) mountID(name string) string {
|
||||||
func (ls *layerStore) GraphDriver() graphdriver.Driver {
|
func (ls *layerStore) GraphDriver() graphdriver.Driver {
|
||||||
return ls.driver
|
return ls.driver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForeignSourceSupported returns whether layers downloaded from foreign sources are
|
||||||
|
// supported in this daemon.
|
||||||
|
func ForeignSourceSupported() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ type roLayer struct {
|
||||||
cacheID string
|
cacheID string
|
||||||
size int64
|
size int64
|
||||||
layerStore *layerStore
|
layerStore *layerStore
|
||||||
|
foreignSrc *distribution.Descriptor
|
||||||
|
|
||||||
referenceCount int
|
referenceCount int
|
||||||
references map[Layer]struct{}
|
references map[Layer]struct{}
|
||||||
|
@ -123,6 +125,11 @@ func storeLayer(tx MetadataTransaction, layer *roLayer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if layer.foreignSrc != nil {
|
||||||
|
if err := tx.SetForeignSource(*layer.foreignSrc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package layer
|
||||||
|
|
||||||
|
import "github.com/docker/distribution"
|
||||||
|
|
||||||
|
var _ ForeignSourcer = &roLayer{}
|
||||||
|
|
||||||
|
func (rl *roLayer) ForeignSource() *distribution.Descriptor {
|
||||||
|
return rl.foreignSrc
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
Aaron Lehmann <aaron.lehmann@docker.com>
|
Aaron Lehmann <aaron.lehmann@docker.com>
|
||||||
|
Aaron Schlesinger <aschlesinger@deis.com>
|
||||||
Aaron Vinson <avinson.public@gmail.com>
|
Aaron Vinson <avinson.public@gmail.com>
|
||||||
Adam Enger <adamenger@gmail.com>
|
Adam Enger <adamenger@gmail.com>
|
||||||
Adrian Mouat <adrian.mouat@gmail.com>
|
Adrian Mouat <adrian.mouat@gmail.com>
|
||||||
|
@ -7,13 +8,16 @@ Alex Chan <alex.chan@metaswitch.com>
|
||||||
Alex Elman <aelman@indeed.com>
|
Alex Elman <aelman@indeed.com>
|
||||||
amitshukla <ashukla73@hotmail.com>
|
amitshukla <ashukla73@hotmail.com>
|
||||||
Amy Lindburg <amy.lindburg@docker.com>
|
Amy Lindburg <amy.lindburg@docker.com>
|
||||||
|
Andrew Hsu <andrewhsu@acm.org>
|
||||||
Andrew Meredith <andymeredith@gmail.com>
|
Andrew Meredith <andymeredith@gmail.com>
|
||||||
Andrew T Nguyen <andrew.nguyen@docker.com>
|
Andrew T Nguyen <andrew.nguyen@docker.com>
|
||||||
Andrey Kostov <kostov.andrey@gmail.com>
|
Andrey Kostov <kostov.andrey@gmail.com>
|
||||||
Andy Goldstein <agoldste@redhat.com>
|
Andy Goldstein <agoldste@redhat.com>
|
||||||
|
Anis Elleuch <vadmeste@gmail.com>
|
||||||
Anton Tiurin <noxiouz@yandex.ru>
|
Anton Tiurin <noxiouz@yandex.ru>
|
||||||
Antonio Mercado <amercado@thinknode.com>
|
Antonio Mercado <amercado@thinknode.com>
|
||||||
Antonio Murdaca <runcom@redhat.com>
|
Antonio Murdaca <runcom@redhat.com>
|
||||||
|
Arien Holthuizen <aholthuizen@schubergphilis.com>
|
||||||
Arnaud Porterie <arnaud.porterie@docker.com>
|
Arnaud Porterie <arnaud.porterie@docker.com>
|
||||||
Arthur Baars <arthur@semmle.com>
|
Arthur Baars <arthur@semmle.com>
|
||||||
Asuka Suzuki <hello@tanksuzuki.com>
|
Asuka Suzuki <hello@tanksuzuki.com>
|
||||||
|
@ -27,6 +31,7 @@ burnettk <burnettk@gmail.com>
|
||||||
Carson A <ca@carsonoid.net>
|
Carson A <ca@carsonoid.net>
|
||||||
Chris Dillon <squarism@gmail.com>
|
Chris Dillon <squarism@gmail.com>
|
||||||
Daisuke Fujita <dtanshi45@gmail.com>
|
Daisuke Fujita <dtanshi45@gmail.com>
|
||||||
|
Daniel Huhn <daniel@danielhuhn.de>
|
||||||
Darren Shepherd <darren@rancher.com>
|
Darren Shepherd <darren@rancher.com>
|
||||||
Dave Trombley <dave.trombley@gmail.com>
|
Dave Trombley <dave.trombley@gmail.com>
|
||||||
Dave Tucker <dt@docker.com>
|
Dave Tucker <dt@docker.com>
|
||||||
|
@ -41,6 +46,7 @@ DJ Enriquez <dj.enriquez@infospace.com>
|
||||||
Donald Huang <don.hcd@gmail.com>
|
Donald Huang <don.hcd@gmail.com>
|
||||||
Doug Davis <dug@us.ibm.com>
|
Doug Davis <dug@us.ibm.com>
|
||||||
Eric Yang <windfarer@gmail.com>
|
Eric Yang <windfarer@gmail.com>
|
||||||
|
Fabio Huser <fabio@fh1.ch>
|
||||||
farmerworking <farmerworking@gmail.com>
|
farmerworking <farmerworking@gmail.com>
|
||||||
Felix Yan <felixonmars@archlinux.org>
|
Felix Yan <felixonmars@archlinux.org>
|
||||||
Florentin Raud <florentin.raud@gmail.com>
|
Florentin Raud <florentin.raud@gmail.com>
|
||||||
|
@ -57,8 +63,10 @@ Jack Griffin <jackpg14@gmail.com>
|
||||||
Jason Freidman <jason.freidman@gmail.com>
|
Jason Freidman <jason.freidman@gmail.com>
|
||||||
Jeff Nickoloff <jeff@allingeek.com>
|
Jeff Nickoloff <jeff@allingeek.com>
|
||||||
Jessie Frazelle <jessie@docker.com>
|
Jessie Frazelle <jessie@docker.com>
|
||||||
|
jhaohai <jhaohai@foxmail.com>
|
||||||
Jianqing Wang <tsing@jianqing.org>
|
Jianqing Wang <tsing@jianqing.org>
|
||||||
John Starks <jostarks@microsoft.com>
|
John Starks <jostarks@microsoft.com>
|
||||||
|
Jon Johnson <jonjohnson@google.com>
|
||||||
Jon Poler <jonathan.poler@apcera.com>
|
Jon Poler <jonathan.poler@apcera.com>
|
||||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
Jordan Liggitt <jliggitt@redhat.com>
|
Jordan Liggitt <jliggitt@redhat.com>
|
||||||
|
@ -92,17 +100,20 @@ Olivier Gambier <olivier@docker.com>
|
||||||
Olivier Jacques <olivier.jacques@hp.com>
|
Olivier Jacques <olivier.jacques@hp.com>
|
||||||
Omer Cohen <git@omer.io>
|
Omer Cohen <git@omer.io>
|
||||||
Patrick Devine <patrick.devine@docker.com>
|
Patrick Devine <patrick.devine@docker.com>
|
||||||
|
Phil Estes <estesp@linux.vnet.ibm.com>
|
||||||
Philip Misiowiec <philip@atlashealth.com>
|
Philip Misiowiec <philip@atlashealth.com>
|
||||||
Richard Scothern <richard.scothern@docker.com>
|
Richard Scothern <richard.scothern@docker.com>
|
||||||
Rodolfo Carvalho <rhcarvalho@gmail.com>
|
Rodolfo Carvalho <rhcarvalho@gmail.com>
|
||||||
Rusty Conover <rusty@luckydinosaur.com>
|
Rusty Conover <rusty@luckydinosaur.com>
|
||||||
Sean Boran <Boran@users.noreply.github.com>
|
Sean Boran <Boran@users.noreply.github.com>
|
||||||
Sebastiaan van Stijn <github@gone.nl>
|
Sebastiaan van Stijn <github@gone.nl>
|
||||||
|
Serge Dubrouski <sergeyfd@gmail.com>
|
||||||
Sharif Nassar <sharif@mrwacky.com>
|
Sharif Nassar <sharif@mrwacky.com>
|
||||||
Shawn Falkner-Horine <dreadpirateshawn@gmail.com>
|
Shawn Falkner-Horine <dreadpirateshawn@gmail.com>
|
||||||
Shreyas Karnik <karnik.shreyas@gmail.com>
|
Shreyas Karnik <karnik.shreyas@gmail.com>
|
||||||
Simon Thulbourn <simon+github@thulbourn.com>
|
Simon Thulbourn <simon+github@thulbourn.com>
|
||||||
Spencer Rinehart <anubis@overthemonkey.com>
|
Spencer Rinehart <anubis@overthemonkey.com>
|
||||||
|
Stefan Majewsky <stefan.majewsky@sap.com>
|
||||||
Stefan Weil <sw@weilnetz.de>
|
Stefan Weil <sw@weilnetz.de>
|
||||||
Stephen J Day <stephen.day@docker.com>
|
Stephen J Day <stephen.day@docker.com>
|
||||||
Sungho Moon <sungho.moon@navercorp.com>
|
Sungho Moon <sungho.moon@navercorp.com>
|
||||||
|
@ -114,6 +125,7 @@ Thomas Sjögren <konstruktoid@users.noreply.github.com>
|
||||||
Tianon Gravi <admwiggin@gmail.com>
|
Tianon Gravi <admwiggin@gmail.com>
|
||||||
Tibor Vass <teabee89@gmail.com>
|
Tibor Vass <teabee89@gmail.com>
|
||||||
Tonis Tiigi <tonistiigi@gmail.com>
|
Tonis Tiigi <tonistiigi@gmail.com>
|
||||||
|
Tony Holdstock-Brown <tony@docker.com>
|
||||||
Trevor Pounds <trevor.pounds@gmail.com>
|
Trevor Pounds <trevor.pounds@gmail.com>
|
||||||
Troels Thomsen <troels@thomsen.io>
|
Troels Thomsen <troels@thomsen.io>
|
||||||
Vincent Batts <vbatts@redhat.com>
|
Vincent Batts <vbatts@redhat.com>
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
FROM golang:1.6
|
FROM golang:1.6-alpine
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y apache2-utils && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
|
||||||
ENV DOCKER_BUILDTAGS include_oss include_gcs
|
ENV DOCKER_BUILDTAGS include_oss include_gcs
|
||||||
|
@ -10,6 +6,10 @@ ENV DOCKER_BUILDTAGS include_oss include_gcs
|
||||||
WORKDIR $DISTRIBUTION_DIR
|
WORKDIR $DISTRIBUTION_DIR
|
||||||
COPY . $DISTRIBUTION_DIR
|
COPY . $DISTRIBUTION_DIR
|
||||||
COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml
|
COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml
|
||||||
|
|
||||||
|
RUN set -ex \
|
||||||
|
&& apk add --no-cache make git
|
||||||
|
|
||||||
RUN make PREFIX=/go clean binaries
|
RUN make PREFIX=/go clean binaries
|
||||||
|
|
||||||
VOLUME ["/var/lib/registry"]
|
VOLUME ["/var/lib/registry"]
|
||||||
|
|
|
@ -69,6 +69,9 @@ type Descriptor struct {
|
||||||
// against against this digest.
|
// against against this digest.
|
||||||
Digest digest.Digest `json:"digest,omitempty"`
|
Digest digest.Digest `json:"digest,omitempty"`
|
||||||
|
|
||||||
|
// URLs contains the source URLs of this content.
|
||||||
|
URLs []string `json:"urls,omitempty"`
|
||||||
|
|
||||||
// NOTE: Before adding a field here, please ensure that all
|
// NOTE: Before adding a field here, please ensure that all
|
||||||
// other options have been exhausted. Much of the type relationships
|
// other options have been exhausted. Much of the type relationships
|
||||||
// depend on the simplicity of this type.
|
// depend on the simplicity of this type.
|
||||||
|
|
|
@ -20,6 +20,10 @@ const (
|
||||||
// MediaTypeLayer is the mediaType used for layers referenced by the
|
// MediaTypeLayer is the mediaType used for layers referenced by the
|
||||||
// manifest.
|
// manifest.
|
||||||
MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
|
MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
|
||||||
|
|
||||||
|
// MediaTypeForeignLayer is the mediaType used for layers that must be
|
||||||
|
// downloaded from foreign URLs.
|
||||||
|
MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -63,7 +67,6 @@ type Manifest struct {
|
||||||
// References returnes the descriptors of this manifests references.
|
// References returnes the descriptors of this manifests references.
|
||||||
func (m Manifest) References() []distribution.Descriptor {
|
func (m Manifest) References() []distribution.Descriptor {
|
||||||
return m.Layers
|
return m.Layers
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target returns the target of this signed manifest.
|
// Target returns the target of this signed manifest.
|
||||||
|
|
Loading…
Reference in New Issue