diff --git a/distribution/xfer/download_test.go b/distribution/xfer/download_test.go index 69323bb869..e3434ae312 100644 --- a/distribution/xfer/download_test.go +++ b/distribution/xfer/download_test.go @@ -26,6 +26,7 @@ type mockLayer struct { diffID layer.DiffID chainID layer.ChainID parent layer.Layer + platform layer.Platform } func (ml *mockLayer) TarStream() (io.ReadCloser, error) { @@ -56,6 +57,10 @@ func (ml *mockLayer) DiffSize() (size int64, err error) { return 0, nil } +func (ml *mockLayer) Platform() layer.Platform { + return ml.platform +} + func (ml *mockLayer) Metadata() (map[string]string, error) { return make(map[string]string), nil } diff --git a/layer/empty.go b/layer/empty.go index 80f2c12439..cf04aa12fe 100644 --- a/layer/empty.go +++ b/layer/empty.go @@ -55,6 +55,10 @@ func (el *emptyLayer) Metadata() (map[string]string, error) { return make(map[string]string), nil } +func (el *emptyLayer) Platform() Platform { + return "" +} + // IsEmpty returns true if the layer is an EmptyLayer func IsEmpty(diffID DiffID) bool { return diffID == DigestSHA256EmptyTar diff --git a/layer/filestore_unix.go b/layer/filestore_unix.go new file mode 100644 index 0000000000..fe8a4f8b2a --- /dev/null +++ b/layer/filestore_unix.go @@ -0,0 +1,13 @@ +// +build !windows + +package layer + +// SetPlatform writes the "platform" file to the layer filestore +func (fm *fileMetadataTransaction) SetPlatform(platform Platform) error { + return nil +} + +// GetPlatform reads the "platform" file from the layer filestore +func (fms *fileMetadataStore) GetPlatform(layer ChainID) (Platform, error) { + return "", nil +} diff --git a/layer/filestore_windows.go b/layer/filestore_windows.go new file mode 100644 index 0000000000..066456d8d2 --- /dev/null +++ b/layer/filestore_windows.go @@ -0,0 +1,35 @@ +package layer + +import ( + "fmt" + "io/ioutil" + "os" + "strings" +) + +// SetPlatform writes the "platform" file to the layer filestore +func (fm *fileMetadataTransaction) SetPlatform(platform Platform) error { + if platform == "" { + return nil + } + return fm.ws.WriteFile("platform", []byte(platform), 0644) +} + +// GetPlatform reads the "platform" file from the layer filestore +func (fms *fileMetadataStore) GetPlatform(layer ChainID) (Platform, error) { + contentBytes, err := ioutil.ReadFile(fms.getLayerFilename(layer, "platform")) + if err != nil { + // For backwards compatibility, the platform file may not exist. Default to "windows" if missing. + if os.IsNotExist(err) { + return "windows", nil + } + return "", err + } + content := strings.TrimSpace(string(contentBytes)) + + if content != "windows" && content != "linux" { + return "", fmt.Errorf("invalid platform value: %s", content) + } + + return Platform(content), nil +} diff --git a/layer/layer.go b/layer/layer.go index 7b993ee4ad..2e5dcf9c85 100644 --- a/layer/layer.go +++ b/layer/layer.go @@ -64,6 +64,14 @@ func (id ChainID) String() string { return string(id) } +// Platform is the platform of a layer +type Platform string + +// String returns a string rendition of layers target platform +func (id Platform) String() string { + return string(id) +} + // DiffID is the hash of an individual layer tar. type DiffID digest.Digest @@ -99,6 +107,9 @@ type Layer interface { // Parent returns the next layer in the layer chain. Parent() Layer + // Platform returns the platform of the layer + Platform() Platform + // Size returns the size of the entire layer chain. The size // is calculated from the total size of all files in the layers. Size() (int64, error) @@ -208,6 +219,7 @@ type MetadataTransaction interface { SetDiffID(DiffID) error SetCacheID(string) error SetDescriptor(distribution.Descriptor) error + SetPlatform(Platform) error TarSplitWriter(compressInput bool) (io.WriteCloser, error) Commit(ChainID) error @@ -228,6 +240,7 @@ type MetadataStore interface { GetDiffID(ChainID) (DiffID, error) GetCacheID(ChainID) (string, error) GetDescriptor(ChainID) (distribution.Descriptor, error) + GetPlatform(ChainID) (Platform, error) TarSplitReader(ChainID) (io.ReadCloser, error) SetMountID(string, string) error diff --git a/layer/layer_store.go b/layer/layer_store.go index 25861c6669..4e3594ed60 100644 --- a/layer/layer_store.go +++ b/layer/layer_store.go @@ -144,6 +144,11 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) { return nil, fmt.Errorf("failed to get descriptor for %s: %s", layer, err) } + platform, err := ls.store.GetPlatform(layer) + if err != nil { + return nil, fmt.Errorf("failed to get platform for %s: %s", layer, err) + } + cl = &roLayer{ chainID: layer, diffID: diff, @@ -152,6 +157,7 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) { layerStore: ls, references: map[Layer]struct{}{}, descriptor: descriptor, + platform: platform, } if parent != "" { diff --git a/layer/ro_layer.go b/layer/ro_layer.go index 8b4cf8f0de..e03d78b4db 100644 --- a/layer/ro_layer.go +++ b/layer/ro_layer.go @@ -16,6 +16,7 @@ type roLayer struct { size int64 layerStore *layerStore descriptor distribution.Descriptor + platform Platform referenceCount int references map[Layer]struct{} @@ -142,6 +143,9 @@ func storeLayer(tx MetadataTransaction, layer *roLayer) error { return err } } + if err := tx.SetPlatform(layer.platform); err != nil { + return err + } return nil } diff --git a/layer/ro_layer_unix.go b/layer/ro_layer_unix.go new file mode 100644 index 0000000000..1b36856f9e --- /dev/null +++ b/layer/ro_layer_unix.go @@ -0,0 +1,7 @@ +// +build !windows + +package layer + +func (rl *roLayer) Platform() Platform { + return "" +} diff --git a/layer/ro_layer_windows.go b/layer/ro_layer_windows.go index 32bd7182a3..6679bdfe8f 100644 --- a/layer/ro_layer_windows.go +++ b/layer/ro_layer_windows.go @@ -7,3 +7,10 @@ var _ distribution.Describable = &roLayer{} func (rl *roLayer) Descriptor() distribution.Descriptor { return rl.descriptor } + +func (rl *roLayer) Platform() Platform { + if rl.platform == "" { + return "windows" + } + return rl.platform +} diff --git a/migrate/v1/migratev1_test.go b/migrate/v1/migratev1_test.go index 55898f12b4..852f5891fb 100644 --- a/migrate/v1/migratev1_test.go +++ b/migrate/v1/migratev1_test.go @@ -433,6 +433,10 @@ func (l *mockLayer) DiffSize() (int64, error) { return 0, nil } +func (l *mockLayer) Platform() layer.Platform { + return "" +} + func (l *mockLayer) Metadata() (map[string]string, error) { return nil, nil }