Sfoglia il codice sorgente

Better error context when failing to create a new image. Added basic tag support + unit tests

shin- 12 anni fa
parent
commit
8002af43fb
3 ha cambiato i file con 95 aggiunte e 15 eliminazioni
  1. 17 10
      fs/layers.go
  2. 47 5
      fs/store.go
  3. 31 0
      fs/store_test.go

+ 17 - 10
fs/layers.go

@@ -8,6 +8,7 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
+	"fmt"
 	"github.com/dotcloud/docker/future"
 	"github.com/dotcloud/docker/future"
 )
 )
 
 
@@ -15,6 +16,14 @@ type LayerStore struct {
 	Root	string
 	Root	string
 }
 }
 
 
+type Compression uint32
+
+const (
+	Uncompressed	Compression = iota
+	Bzip2
+	Gzip
+)
+
 func NewLayerStore(root string) (*LayerStore, error) {
 func NewLayerStore(root string) (*LayerStore, error) {
 	abspath, err := filepath.Abs(root)
 	abspath, err := filepath.Abs(root)
 	if err != nil {
 	if err != nil {
@@ -93,7 +102,7 @@ func (store *LayerStore) AddLayer(id string, archive Archive, stderr io.Writer,
 	tmp, err := store.Mktemp()
 	tmp, err := store.Mktemp()
 	defer os.RemoveAll(tmp)
 	defer os.RemoveAll(tmp)
 	if err != nil {
 	if err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Mktemp failed: %s", err))
 	}
 	}
 	extractFlags := "-x"
 	extractFlags := "-x"
 	if compression == Bzip2 {
 	if compression == Bzip2 {
@@ -104,16 +113,16 @@ func (store *LayerStore) AddLayer(id string, archive Archive, stderr io.Writer,
 	untarCmd := exec.Command("tar", "-C", tmp, extractFlags)
 	untarCmd := exec.Command("tar", "-C", tmp, extractFlags)
 	untarW, err := untarCmd.StdinPipe()
 	untarW, err := untarCmd.StdinPipe()
 	if err != nil {
 	if err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Could not obtain stdin pipe: %s", err))
 	}
 	}
 	untarStderr, err := untarCmd.StderrPipe()
 	untarStderr, err := untarCmd.StderrPipe()
 	if err != nil {
 	if err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Could not obtain stderr pipe: %s", err))
 	}
 	}
 	go io.Copy(stderr, untarStderr)
 	go io.Copy(stderr, untarStderr)
 	untarStdout, err := untarCmd.StdoutPipe()
 	untarStdout, err := untarCmd.StdoutPipe()
 	if err != nil {
 	if err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Could not obtain stdout pipe: %s", err))
 	}
 	}
 	go io.Copy(stderr, untarStdout)
 	go io.Copy(stderr, untarStdout)
 	untarCmd.Start()
 	untarCmd.Start()
@@ -122,19 +131,17 @@ func (store *LayerStore) AddLayer(id string, archive Archive, stderr io.Writer,
 		untarW.Close()
 		untarW.Close()
 		return err
 		return err
 	})
 	})
-	if err != nil {
-		return "", err
-	}
+
 	if err := untarCmd.Wait(); err != nil {
 	if err := untarCmd.Wait(); err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Error while waiting for untar command to complete: %s", err))
 	}
 	}
 	if err := <-job_copy; err != nil {
 	if err := <-job_copy; err != nil {
-		return "", err
+		return "", errors.New(fmt.Sprintf("Error while copying: %s", err))
 	}
 	}
 	layer := store.layerPath(id)
 	layer := store.layerPath(id)
 	if !store.Exists(id) {
 	if !store.Exists(id) {
 		if err := os.Rename(tmp, layer); err != nil {
 		if err := os.Rename(tmp, layer); err != nil {
-			return "", err
+			return "", errors.New(fmt.Sprintf("Could not rename temp dir to layer %s: %s", layer, err))
 		}
 		}
 	}
 	}
 	return layer, nil
 	return layer, nil

+ 47 - 5
fs/store.go

@@ -8,6 +8,8 @@ import (
 	"io"
 	"io"
 	"path"
 	"path"
 	"github.com/dotcloud/docker/future"
 	"github.com/dotcloud/docker/future"
+	"fmt"
+	"errors"
 )
 )
 
 
 type Store struct {
 type Store struct {
@@ -31,6 +33,7 @@ func New(root string) (*Store, error) {
 	orm.AddTableWithName(Image{}, "images").SetKeys(false, "Id")
 	orm.AddTableWithName(Image{}, "images").SetKeys(false, "Id")
 	orm.AddTableWithName(Path{}, "paths").SetKeys(false, "Path", "Image")
 	orm.AddTableWithName(Path{}, "paths").SetKeys(false, "Path", "Image")
 	orm.AddTableWithName(Mountpoint{}, "mountpoints").SetKeys(false, "Root")
 	orm.AddTableWithName(Mountpoint{}, "mountpoints").SetKeys(false, "Root")
+	orm.AddTableWithName(Tag{}, "tags").SetKeys(false, "TagName")
 	if err := orm.CreateTables(); err != nil {
 	if err := orm.CreateTables(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -105,7 +108,7 @@ func (store *Store) Create(layerData Archive, parent *Image, pth, comment string
 	// FIXME: Archive should contain compression info. For now we only support uncompressed.
 	// FIXME: Archive should contain compression info. For now we only support uncompressed.
 	_, err := store.layers.AddLayer(img.Id, layerData, os.Stderr, Uncompressed)
 	_, err := store.layers.AddLayer(img.Id, layerData, os.Stderr, Uncompressed)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, errors.New(fmt.Sprintf("Could not add layer: %s", err))
 	}
 	}
 	path := &Path{
 	path := &Path{
 		Path:		path.Clean(pth),
 		Path:		path.Clean(pth),
@@ -113,16 +116,16 @@ func (store *Store) Create(layerData Archive, parent *Image, pth, comment string
 	}
 	}
 	trans, err := store.orm.Begin()
 	trans, err := store.orm.Begin()
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, errors.New(fmt.Sprintf("Could not begin transaction:", err))
 	}
 	}
 	if err := trans.Insert(img); err != nil {
 	if err := trans.Insert(img); err != nil {
-		return nil, err
+		return nil, errors.New(fmt.Sprintf("Could not insert image info: %s", err))
 	}
 	}
 	if err := trans.Insert(path); err != nil {
 	if err := trans.Insert(path); err != nil {
-		return nil, err
+		return nil, errors.New(fmt.Sprintf("Could not insert path info: %s", err))
 	}
 	}
 	if err := trans.Commit(); err != nil {
 	if err := trans.Commit(); err != nil {
-		return nil, err
+		return nil, errors.New(fmt.Sprintf("Could not commit transaction: %s", err))
 	}
 	}
 	return img, nil
 	return img, nil
 }
 }
@@ -183,8 +186,47 @@ func (image *Image) Mountpoints() ([]*Mountpoint, error) {
 	return mountpoints, nil
 	return mountpoints, nil
 }
 }
 
 
+func (store *Store) AddTag(imageId, tagName string) error {
+	if image, err := store.Get(imageId); err != nil {
+		return err
+	} else if image == nil {
+		return errors.New("No image with ID " + imageId)
+	}
+
+	err2 := store.orm.Insert(&Tag{
+		TagName:	tagName,
+		Image:		imageId,
+	})
+
+	return err2
+}
+
+func (store *Store) GetByTag(tagName string) (*Image, error) {
+	res, err := store.orm.Get(Tag{}, tagName)
+	if err != nil {
+		return nil, err
+	} else if res == nil {
+		return nil, errors.New("No image associated to tag \"" + tagName + "\"")
+	}
+
+	tag := res.(*Tag)
+
+	img, err2 := store.Get(tag.Image)
+	if err2 != nil {
+		return nil, err2
+	} else if img == nil {
+		return nil, errors.New("Tag was found but image seems to be inexistent.")
+	}
+
+	return img, nil
+}
 
 
 type Path struct {
 type Path struct {
 	Path	string
 	Path	string
 	Image	string
 	Image	string
 }
 }
+
+type Tag struct {
+	TagName	string
+	Image	string
+}

+ 31 - 0
fs/store_test.go

@@ -52,6 +52,37 @@ func TestCreate(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestTag(t *testing.T) {
+	store, err := TempStore("testtag")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(store)
+	archive, err := fake.FakeTar()
+	if err != nil {
+		t.Fatal(err)
+	}
+	image, err := store.Create(archive, nil, "foo", "Testing")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if images, err := store.Images(); err != nil {
+		t.Fatal(err)
+	} else if l := len(images); l != 1 {
+		t.Fatalf("Wrong number of images. Should be %d, not %d", 1, l)
+	}
+
+	if err := store.AddTag(image.Id, "baz"); err != nil {
+		t.Fatalf("Error while adding a tag to created image: %s", err)
+	}
+
+	if taggedImage, err := store.GetByTag("baz"); err != nil {
+		t.Fatalf("Error while trying to retrieve image for tag 'baz': %s", err)
+	} else if taggedImage.Id != image.Id {
+		t.Fatalf("Expected to retrieve image %s but found %s instead", image.Id, taggedImage.Id)
+	}
+}
+
 // Copy an image to a new path
 // Copy an image to a new path
 func TestCopyNewPath(t *testing.T) {
 func TestCopyNewPath(t *testing.T) {
 	store, err := TempStore("testcopynewpath")
 	store, err := TempStore("testcopynewpath")