1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

docker/fs: initial support for filesystem layers (adapted from image/layers.go)

This commit is contained in:
Solomon Hykes 2013-02-18 15:25:43 -08:00
parent 1531848ca6
commit 6372a1a0d0
3 changed files with 103 additions and 7 deletions

View file

@ -1,4 +1,4 @@
package image
package fs
import (
"errors"
@ -20,6 +20,10 @@ func NewLayerStore(root string) (*LayerStore, error) {
if err != nil {
return nil, err
}
// Create the root directory if it doesn't exists
if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
return nil, err
}
return &LayerStore{
Root: abspath,
}, nil
@ -82,7 +86,10 @@ func (store *LayerStore) layerPath(id string) string {
}
func (store *LayerStore) AddLayer(archive io.Reader, stderr io.Writer, compression Compression) (string, error) {
func (store *LayerStore) AddLayer(id string, archive Archive, stderr io.Writer, compression Compression) (string, error) {
if _, err := os.Stat(store.layerPath(id)); err == nil {
return "", errors.New("Layer already exists: " + id)
}
tmp, err := store.Mktemp()
defer os.RemoveAll(tmp)
if err != nil {
@ -110,14 +117,11 @@ func (store *LayerStore) AddLayer(archive io.Reader, stderr io.Writer, compressi
}
go io.Copy(stderr, untarStdout)
untarCmd.Start()
hashR, hashW := io.Pipe()
job_copy := future.Go(func() error {
_, err := io.Copy(io.MultiWriter(hashW, untarW), archive)
hashW.Close()
_, err := io.Copy(untarW, archive)
untarW.Close()
return err
})
id, err := future.ComputeId(hashR)
if err != nil {
return "", err
}

80
fs/layers_test.go Normal file
View file

@ -0,0 +1,80 @@
package fs
import (
"io/ioutil"
"testing"
"os"
"github.com/dotcloud/docker/fake"
)
func TestLayersInit(t *testing.T) {
store := tempStore(t)
defer os.RemoveAll(store.Root)
// Root should exist
if _, err := os.Stat(store.Root); err != nil {
t.Fatal(err)
}
// List() should be empty
if l := store.List(); len(l) != 0 {
t.Fatalf("List() should return %d, not %d", 0, len(l))
}
}
func TestAddLayer(t *testing.T) {
store := tempStore(t)
defer os.RemoveAll(store.Root)
layer, err := store.AddLayer("foo", testArchive(t), os.Stderr, Uncompressed)
if err != nil {
t.Fatal(err)
}
// Layer path should exist
if _, err := os.Stat(layer); err != nil {
t.Fatal(err)
}
// List() should return 1 layer
if l := store.List(); len(l) != 1 {
t.Fatalf("List() should return %d elements, not %d", 1, len(l))
}
// Get("foo") should return the correct layer
if foo := store.Get("foo"); foo != layer {
t.Fatalf("get(\"foo\") should return '%d', not '%d'", layer, foo)
}
}
func TestAddLayerDuplicate(t *testing.T) {
store := tempStore(t)
defer os.RemoveAll(store.Root)
if _, err := store.AddLayer("foobar123", testArchive(t), os.Stderr, Uncompressed); err != nil {
t.Fatal(err)
}
if _, err := store.AddLayer("foobar123", testArchive(t), os.Stderr, Uncompressed); err == nil {
t.Fatalf("Creating duplicate layer should fail")
}
}
/*
* HELPER FUNCTIONS
*/
func tempStore(t *testing.T) *LayerStore {
tmp, err := ioutil.TempDir("", "docker-fs-layerstore-")
if err != nil {
t.Fatal(err)
}
store, err := NewLayerStore(tmp)
if err != nil {
t.Fatal(err)
}
return store
}
func testArchive(t *testing.T) Archive {
archive, err := fake.FakeTar()
if err != nil {
t.Fatal(err)
}
return archive
}

View file

@ -14,6 +14,7 @@ type Store struct {
Root string
db *sql.DB
orm *gorp.DbMap
layers *LayerStore
}
type Archive io.Reader
@ -33,10 +34,15 @@ func New(root string) (*Store, error) {
if err := orm.CreateTables(); err != nil {
return nil, err
}
layers, err := NewLayerStore(path.Join(root, "layers"))
if err != nil {
return nil, err
}
return &Store{
Root: root,
db: db,
orm: orm,
layers: layers,
}, nil
}
@ -88,13 +94,19 @@ func (store *Store) Get(id string) (*Image, error) {
return img.(*Image), err
}
func (store *Store) Create(layer Archive, parent *Image, pth, comment string) (*Image, error) {
func (store *Store) Create(layerData Archive, parent *Image, pth, comment string) (*Image, error) {
// FIXME: actually do something with the layer...
img := &Image{
Id : future.RandomId(),
Comment: comment,
store: store,
}
// FIXME: we shouldn't have to pass os.Stderr to AddLayer()...
// FIXME: Archive should contain compression info. For now we only support uncompressed.
_, err := store.layers.AddLayer(img.Id, layerData, os.Stderr, Uncompressed)
if err != nil {
return nil, err
}
path := &Path{
Path: path.Clean(pth),
Image: img.Id,