Explorar o código

First integration of runtime with repositories & tags

Solomon Hykes %!s(int64=12) %!d(string=hai) anos
pai
achega
44faa07b6c
Modificáronse 5 ficheiros con 113 adicións e 96 borrados
  1. 75 69
      commands.go
  2. 13 0
      graph/graph.go
  3. 16 24
      graph/tags.go
  4. 8 2
      runtime.go
  5. 1 1
      runtime_test.go

+ 75 - 69
commands.go

@@ -12,7 +12,6 @@ import (
 	"math/rand"
 	"net/http"
 	"net/url"
-	"path"
 	"runtime"
 	"strconv"
 	"strings"
@@ -356,32 +355,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()
@@ -391,11 +384,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
 }
@@ -411,68 +410,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 {

+ 13 - 0
graph/graph.go

@@ -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 {

+ 16 - 24
graph/tags.go

@@ -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),
-	}
-}

+ 8 - 2
runtime.go

@@ -20,6 +20,7 @@ type Runtime struct {
 	containers     *list.List
 	networkManager *NetworkManager
 	graph          *graph.Graph
+	repositories   *graph.TagStore
 }
 
 var sysInitPath string
@@ -201,10 +202,14 @@ func NewFromDirectory(root string) (*Runtime, error) {
 		return nil, err
 	}
 
-	graph, err := graph.New(path.Join(root, "graph"))
+	g, err := graph.New(path.Join(root, "graph"))
 	if err != nil {
 		return nil, err
 	}
+	repositories, err := graph.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 +220,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 {

+ 1 - 1
runtime_test.go

@@ -11,7 +11,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