Bläddra i källkod

Merge branch 'graph' of github.com:dotcloud/docker into graph

creack 12 år sedan
förälder
incheckning
864a8d9aca
14 ändrade filer med 147 tillägg och 138 borttagningar
  1. 1 1
      archive.go
  2. 1 1
      archive_test.go
  3. 1 1
      changes.go
  4. 76 70
      commands.go
  5. 8 14
      container.go
  6. 17 4
      graph.go
  7. 3 3
      graph_test.go
  8. 1 1
      image.go
  9. 1 1
      mount.go
  10. 1 1
      mount_darwin.go
  11. 1 1
      mount_linux.go
  12. 12 7
      runtime.go
  13. 7 8
      runtime_test.go
  14. 17 25
      tags.go

+ 1 - 1
graph/archive.go → archive.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"errors"

+ 1 - 1
graph/archive_test.go → archive_test.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"io/ioutil"

+ 1 - 1
graph/changes.go → changes.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"fmt"

+ 76 - 70
commands.go

@@ -14,7 +14,6 @@ import (
 	"math/rand"
 	"net/http"
 	"net/url"
-	"path"
 	"runtime"
 	"strconv"
 	"strings"
@@ -358,32 +357,26 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string
 }
 
 func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
-	cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] NAME", "Create a new filesystem image from the contents of a tarball")
-	fl_stdin := cmd.Bool("stdin", false, "Read tarball from stdin")
+	cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
 	var archive io.Reader
 	var resp *http.Response
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
-	name := cmd.Arg(0)
-	if name == "" {
+	src := cmd.Arg(0)
+	if src == "" {
 		return errors.New("Not enough arguments")
-	}
-	if *fl_stdin {
+	} else if src == "-" {
 		archive = stdin
 	} else {
-		u, err := url.Parse(name)
+		u, err := url.Parse(src)
 		if err != nil {
 			return err
 		}
 		if u.Scheme == "" {
 			u.Scheme = "http"
 		}
-		if u.Host == "" {
-			u.Host = "get.docker.io"
-			u.Path = path.Join("/images", u.Path)
-		}
 		fmt.Fprintf(stdout, "Downloading from %s\n", u.String())
 		// Download with curl (pretty progress bar)
 		// If curl is not available, fallback to http.Get()
@@ -393,11 +386,17 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		}
 		archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout)
 	}
-	fmt.Fprintf(stdout, "Unpacking to %s\n", name)
-	img, err := srv.runtime.graph.Create(archive, "", "")
+	img, err := srv.runtime.graph.Create(archive, "", "Imported from "+src)
 	if err != nil {
 		return err
 	}
+	// Optionally register the image at REPO/TAG
+	if repository := cmd.Arg(1); repository != "" {
+		tag := cmd.Arg(2) // Repository will handle an empty tag properly
+		if err := srv.runtime.repositories.Set(repository, tag, img.Id); err != nil {
+			return err
+		}
+	}
 	fmt.Fprintln(stdout, img.Id)
 	return nil
 }
@@ -580,68 +579,75 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		cmd.Usage()
 		return nil
 	}
-	/*
-		var nameFilter string
-		if cmd.NArg() == 1 {
-			nameFilter = cmd.Arg(0)
-		}
-	*/
+	var nameFilter string
+	if cmd.NArg() == 1 {
+		nameFilter = cmd.Arg(0)
+	}
 	w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
 	if !*quiet {
-		fmt.Fprintf(w, "NAME\tID\tCREATED\tPARENT\n")
+		fmt.Fprintf(w, "REPOSITORY\tTAG\tID\tCREATED\tPARENT\n")
 	}
-	if *quiet {
-		images, err := srv.runtime.graph.All()
-		if err != nil {
-			return err
+	allImages, err := srv.runtime.graph.Map()
+	if err != nil {
+		return err
+	}
+	for name, repository := range srv.runtime.repositories.Repositories {
+		if nameFilter != "" && name != nameFilter {
+			continue
 		}
-		for _, image := range images {
-			fmt.Fprintln(stdout, image.Id)
+		for tag, id := range repository {
+			image, err := srv.runtime.graph.Get(id)
+			if err != nil {
+				log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
+				continue
+			}
+			delete(allImages, id)
+			if !*quiet {
+				for idx, field := range []string{
+					/* REPOSITORY */ name,
+					/* TAG */ tag,
+					/* ID */ id,
+					/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
+					/* PARENT */ image.Parent,
+				} {
+					if idx == 0 {
+						w.Write([]byte(field))
+					} else {
+						w.Write([]byte("\t" + field))
+					}
+				}
+				w.Write([]byte{'\n'})
+			} else {
+				stdout.Write([]byte(image.Id + "\n"))
+			}
+		}
+	}
+	// Display images which aren't part of a 
+	if nameFilter != "" {
+		for id, image := range allImages {
+			if !*quiet {
+				for idx, field := range []string{
+					/* REPOSITORY */ "",
+					/* TAG */ "",
+					/* ID */ id,
+					/* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
+					/* PARENT */ image.Parent,
+				} {
+					if idx == 0 {
+						w.Write([]byte(field))
+					} else {
+						w.Write([]byte("\t" + field))
+					}
+				}
+			} else {
+				stdout.Write([]byte(image.Id + "\n"))
+			}
 		}
-	} else {
-		// FIXME:
-		//		paths, err := srv.images.Paths()
-		//		if err != nil {
-		//			return err
-		//		}
-		//		for _, name := range paths {
-		//			if nameFilter != "" && nameFilter != name {
-		//				continue
-		//			}
-		//			ids, err := srv.images.List(name)
-		//			if err != nil {
-		//				return err
-		//			}
-		//			for idx, img := range ids {
-		//				if *limit > 0 && idx >= *limit {
-		//					break
-		//				}
-		//				if !*quiet {
-		//					for idx, field := range []string{
-		//						/* NAME */ name,
-		//						/* ID */ img.Id,
-		//						/* CREATED */ HumanDuration(time.Now().Sub(time.Unix(img.Created, 0))) + " ago",
-		//						/* PARENT */ img.Parent,
-		//					} {
-		//						if idx == 0 {
-		//							w.Write([]byte(field))
-		//						} else {
-		//							w.Write([]byte("\t" + field))
-		//						}
-		//					}
-		//					w.Write([]byte{'\n'})
-		//				} else {
-		//					stdout.Write([]byte(img.Id + "\n"))
-		//				}
-		//			}
-		//		}
-		//		if !*quiet {
-		//			w.Flush()
-		//		}
-		//
+	}
+	if !*quiet {
+		w.Flush()
 	}
 	return nil
-
 }
 
 func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
@@ -966,7 +972,7 @@ func NewServer() (*Server, error) {
 	// if err != nil {
 	// 	return nil, err
 	// }
-	runtime, err := New()
+	runtime, err := NewRuntime()
 	if err != nil {
 		return nil, err
 	}

+ 8 - 14
container.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/dotcloud/docker/graph"
 	"github.com/kr/pty"
 	"io"
 	"io/ioutil"
@@ -63,11 +62,6 @@ type NetworkSettings struct {
 	PortMapping map[string]string
 }
 
-func GenerateId() string {
-	return graph.GenerateId() // Re-use the same code to generate container and image IDs
-	// (this might change when image Ids become content-based)
-}
-
 func (container *Container) Cmd() *exec.Cmd {
 	return container.cmd
 }
@@ -376,15 +370,15 @@ func (container *Container) Wait() int {
 	return container.State.ExitCode
 }
 
-func (container *Container) ExportRw() (graph.Archive, error) {
-	return graph.Tar(container.rwPath(), graph.Uncompressed)
+func (container *Container) ExportRw() (Archive, error) {
+	return Tar(container.rwPath(), Uncompressed)
 }
 
-func (container *Container) Export() (graph.Archive, error) {
+func (container *Container) Export() (Archive, error) {
 	if err := container.EnsureMounted(); err != nil {
 		return nil, err
 	}
-	return graph.Tar(container.RootfsPath(), graph.Uncompressed)
+	return Tar(container.RootfsPath(), Uncompressed)
 }
 
 func (container *Container) WaitTimeout(timeout time.Duration) error {
@@ -420,7 +414,7 @@ func (container *Container) Mount() error {
 	return image.Mount(container.RootfsPath(), container.rwPath())
 }
 
-func (container *Container) Changes() ([]graph.Change, error) {
+func (container *Container) Changes() ([]Change, error) {
 	image, err := container.GetImage()
 	if err != nil {
 		return nil, err
@@ -428,7 +422,7 @@ func (container *Container) Changes() ([]graph.Change, error) {
 	return image.Changes(container.rwPath())
 }
 
-func (container *Container) GetImage() (*graph.Image, error) {
+func (container *Container) GetImage() (*Image, error) {
 	if container.runtime == nil {
 		return nil, fmt.Errorf("Can't get image of unregistered container")
 	}
@@ -436,11 +430,11 @@ func (container *Container) GetImage() (*graph.Image, error) {
 }
 
 func (container *Container) Mounted() (bool, error) {
-	return graph.Mounted(container.RootfsPath())
+	return Mounted(container.RootfsPath())
 }
 
 func (container *Container) Unmount() error {
-	return graph.Unmount(container.RootfsPath())
+	return Unmount(container.RootfsPath())
 }
 
 func (container *Container) logPath(name string) string {

+ 17 - 4
graph/graph.go → graph.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"fmt"
@@ -13,7 +13,7 @@ type Graph struct {
 	Root string
 }
 
-func New(root string) (*Graph, error) {
+func NewGraph(root string) (*Graph, error) {
 	abspath, err := filepath.Abs(root)
 	if err != nil {
 		return nil, err
@@ -84,7 +84,7 @@ func (graph *Graph) Register(layerData Archive, img *Image) error {
 }
 
 func (graph *Graph) Mktemp(id string) (string, error) {
-	tmp, err := New(path.Join(graph.Root, ":tmp:"))
+	tmp, err := NewGraph(path.Join(graph.Root, ":tmp:"))
 	if err != nil {
 		return "", fmt.Errorf("Couldn't create temp: %s", err)
 	}
@@ -95,7 +95,7 @@ func (graph *Graph) Mktemp(id string) (string, error) {
 }
 
 func (graph *Graph) Garbage() (*Graph, error) {
-	return New(path.Join(graph.Root, ":garbage:"))
+	return NewGraph(path.Join(graph.Root, ":garbage:"))
 }
 
 func (graph *Graph) Delete(id string) error {
@@ -122,6 +122,19 @@ func (graph *Graph) GarbageCollect() error {
 	return os.RemoveAll(garbage.Root)
 }
 
+func (graph *Graph) Map() (map[string]*Image, error) {
+	// FIXME: this should replace All()
+	all, err := graph.All()
+	if err != nil {
+		return nil, err
+	}
+	images := make(map[string]*Image, len(all))
+	for _, image := range all {
+		images[image.Id] = image
+	}
+	return images, nil
+}
+
 func (graph *Graph) All() ([]*Image, error) {
 	files, err := ioutil.ReadDir(graph.Root)
 	if err != nil {

+ 3 - 3
graph/graph_test.go → graph_test.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"archive/tar"
@@ -28,7 +28,7 @@ func TestInit(t *testing.T) {
 
 // FIXME: Do more extensive tests (ex: create multiple, delete, recreate;
 //       create multiple, check the amount of images and paths, etc..)
-func TestCreate(t *testing.T) {
+func TestGraphCreate(t *testing.T) {
 	graph := tempGraph(t)
 	defer os.RemoveAll(graph.Root)
 	archive, err := fakeTar()
@@ -177,7 +177,7 @@ func tempGraph(t *testing.T) *Graph {
 	if err != nil {
 		t.Fatal(err)
 	}
-	graph, err := New(tmp)
+	graph, err := NewGraph(tmp)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 1 - 1
graph/image.go → image.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"bytes"

+ 1 - 1
graph/mount.go → mount.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"fmt"

+ 1 - 1
graph/mount_darwin.go → mount_darwin.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import "errors"
 

+ 1 - 1
graph/mount_linux.go → mount_linux.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import "syscall"
 

+ 12 - 7
runtime.go

@@ -3,7 +3,6 @@ package docker
 import (
 	"container/list"
 	"fmt"
-	"github.com/dotcloud/docker/graph"
 	"io"
 	"io/ioutil"
 	"log"
@@ -19,7 +18,8 @@ type Runtime struct {
 	repository     string
 	containers     *list.List
 	networkManager *NetworkManager
-	graph          *graph.Graph
+	graph          *Graph
+	repositories   *TagStore
 }
 
 var sysInitPath string
@@ -190,21 +190,25 @@ func (runtime *Runtime) restore() error {
 	return nil
 }
 
-func New() (*Runtime, error) {
-	return NewFromDirectory("/var/lib/docker")
+func NewRuntime() (*Runtime, error) {
+	return NewRuntimeFromDirectory("/var/lib/docker")
 }
 
-func NewFromDirectory(root string) (*Runtime, error) {
+func NewRuntimeFromDirectory(root string) (*Runtime, error) {
 	runtime_repo := path.Join(root, "containers")
 
 	if err := os.MkdirAll(runtime_repo, 0700); err != nil && !os.IsExist(err) {
 		return nil, err
 	}
 
-	graph, err := graph.New(path.Join(root, "graph"))
+	g, err := NewGraph(path.Join(root, "graph"))
 	if err != nil {
 		return nil, err
 	}
+	repositories, err := NewTagStore(path.Join(root, "repositories"), g)
+	if err != nil {
+		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
+	}
 	netManager, err := newNetworkManager(networkBridgeIface)
 	if err != nil {
 		return nil, err
@@ -215,7 +219,8 @@ func NewFromDirectory(root string) (*Runtime, error) {
 		repository:     runtime_repo,
 		containers:     list.New(),
 		networkManager: netManager,
-		graph:          graph,
+		graph:          g,
+		repositories:   repositories,
 	}
 
 	if err := runtime.restore(); err != nil {

+ 7 - 8
runtime_test.go

@@ -1,7 +1,6 @@
 package docker
 
 import (
-	"github.com/dotcloud/docker/graph"
 	"io"
 	"io/ioutil"
 	"os"
@@ -11,7 +10,7 @@ import (
 )
 
 const testLayerPath string = "/var/lib/docker/docker-ut.tar"
-const unitTestImageName string = "busybox"
+const unitTestImageName string = "http://get.docker.io/images/busybox"
 
 var unitTestStoreBase string
 var srv *Server
@@ -57,7 +56,7 @@ func init() {
 	unitTestStoreBase = root
 
 	// Make it our Store root
-	runtime, err := NewFromDirectory(root)
+	runtime, err := NewRuntimeFromDirectory(root)
 	if err != nil {
 		panic(err)
 	}
@@ -84,7 +83,7 @@ func newTestRuntime() (*Runtime, error) {
 		return nil, err
 	}
 
-	runtime, err := NewFromDirectory(root)
+	runtime, err := NewRuntimeFromDirectory(root)
 	if err != nil {
 		return nil, err
 	}
@@ -92,7 +91,7 @@ func newTestRuntime() (*Runtime, error) {
 	return runtime, nil
 }
 
-func GetTestImage(runtime *Runtime) *graph.Image {
+func GetTestImage(runtime *Runtime) *Image {
 	imgs, err := runtime.graph.All()
 	if err != nil {
 		panic(err)
@@ -102,7 +101,7 @@ func GetTestImage(runtime *Runtime) *graph.Image {
 	return imgs[0]
 }
 
-func TestCreate(t *testing.T) {
+func TestRuntimeCreate(t *testing.T) {
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)
@@ -269,7 +268,7 @@ func TestRestore(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	runtime1, err := NewFromDirectory(root)
+	runtime1, err := NewRuntimeFromDirectory(root)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -294,7 +293,7 @@ func TestRestore(t *testing.T) {
 
 	// Here are are simulating a docker restart - that is, reloading all containers
 	// from scratch
-	runtime2, err := NewFromDirectory(root)
+	runtime2, err := NewRuntimeFromDirectory(root)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 17 - 25
graph/tags.go → tags.go

@@ -1,4 +1,4 @@
-package graph
+package docker
 
 import (
 	"encoding/json"
@@ -6,33 +6,31 @@ import (
 	"path/filepath"
 )
 
-type RepoStore struct {
+type TagStore struct {
 	path         string
 	graph        *Graph
-	Repositories map[string]*Repository
+	Repositories map[string]Repository
 }
 
-type Repository struct {
-	Tags map[string]string
-}
+type Repository map[string]string
 
-func NewRepoStore(path string, graph *Graph) (*RepoStore, error) {
+func NewTagStore(path string, graph *Graph) (*TagStore, error) {
 	abspath, err := filepath.Abs(path)
 	if err != nil {
 		return nil, err
 	}
-	store := &RepoStore{
+	store := &TagStore{
 		path:         abspath,
 		graph:        graph,
-		Repositories: make(map[string]*Repository),
+		Repositories: make(map[string]Repository),
 	}
-	if err := store.Reload(); err != nil {
+	if err := store.Save(); err != nil {
 		return nil, err
 	}
 	return store, nil
 }
 
-func (store *RepoStore) Save() error {
+func (store *TagStore) Save() error {
 	// Store the json ball
 	jsonData, err := json.Marshal(store)
 	if err != nil {
@@ -44,7 +42,7 @@ func (store *RepoStore) Save() error {
 	return nil
 }
 
-func (store *RepoStore) Reload() error {
+func (store *TagStore) Reload() error {
 	jsonData, err := ioutil.ReadFile(store.path)
 	if err != nil {
 		return err
@@ -55,22 +53,22 @@ func (store *RepoStore) Reload() error {
 	return nil
 }
 
-func (store *RepoStore) SetTag(repoName, tag, revision string) error {
+func (store *TagStore) Set(repoName, tag, revision string) error {
 	if err := store.Reload(); err != nil {
 		return err
 	}
-	var repo *Repository
+	var repo Repository
 	if r, exists := store.Repositories[repoName]; exists {
 		repo = r
 	} else {
-		repo = NewRepository()
+		repo = make(map[string]string)
 		store.Repositories[repoName] = repo
 	}
-	repo.Tags[tag] = revision
+	repo[tag] = revision
 	return store.Save()
 }
 
-func (store *RepoStore) Get(repoName string) (*Repository, error) {
+func (store *TagStore) Get(repoName string) (Repository, error) {
 	if err := store.Reload(); err != nil {
 		return nil, err
 	}
@@ -80,21 +78,15 @@ func (store *RepoStore) Get(repoName string) (*Repository, error) {
 	return nil, nil
 }
 
-func (store *RepoStore) GetImage(repoName, tag string) (*Image, error) {
+func (store *TagStore) GetImage(repoName, tag string) (*Image, error) {
 	repo, err := store.Get(repoName)
 	if err != nil {
 		return nil, err
 	} else if repo == nil {
 		return nil, nil
 	}
-	if revision, exists := repo.Tags[tag]; exists {
+	if revision, exists := repo[tag]; exists {
 		return store.graph.Get(revision)
 	}
 	return nil, nil
 }
-
-func NewRepository() *Repository {
-	return &Repository{
-		Tags: make(map[string]string),
-	}
-}