First integration of runtime with repositories & tags

This commit is contained in:
Solomon Hykes 2013-03-21 17:35:49 -07:00
parent 680f40c37e
commit 44faa07b6c
5 changed files with 113 additions and 96 deletions

View File

@ -12,7 +12,6 @@ import (
"math/rand" "math/rand"
"net/http" "net/http"
"net/url" "net/url"
"path"
"runtime" "runtime"
"strconv" "strconv"
"strings" "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 { 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") cmd := rcli.Subcmd(stdout, "import", "[OPTIONS] URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
fl_stdin := cmd.Bool("stdin", false, "Read tarball from stdin")
var archive io.Reader var archive io.Reader
var resp *http.Response var resp *http.Response
if err := cmd.Parse(args); err != nil { if err := cmd.Parse(args); err != nil {
return nil return nil
} }
name := cmd.Arg(0) src := cmd.Arg(0)
if name == "" { if src == "" {
return errors.New("Not enough arguments") return errors.New("Not enough arguments")
} } else if src == "-" {
if *fl_stdin {
archive = stdin archive = stdin
} else { } else {
u, err := url.Parse(name) u, err := url.Parse(src)
if err != nil { if err != nil {
return err return err
} }
if u.Scheme == "" { if u.Scheme == "" {
u.Scheme = "http" 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()) fmt.Fprintf(stdout, "Downloading from %s\n", u.String())
// Download with curl (pretty progress bar) // Download with curl (pretty progress bar)
// If curl is not available, fallback to http.Get() // 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) archive = ProgressReader(resp.Body, int(resp.ContentLength), stdout)
} }
fmt.Fprintf(stdout, "Unpacking to %s\n", name) img, err := srv.runtime.graph.Create(archive, "", "Imported from "+src)
img, err := srv.runtime.graph.Create(archive, "", "")
if err != nil { if err != nil {
return err 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) fmt.Fprintln(stdout, img.Id)
return nil return nil
} }
@ -411,68 +410,75 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
cmd.Usage() cmd.Usage()
return nil return nil
} }
/* var nameFilter string
var nameFilter string if cmd.NArg() == 1 {
if cmd.NArg() == 1 { nameFilter = cmd.Arg(0)
nameFilter = cmd.Arg(0) }
}
*/
w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0) w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
if !*quiet { if !*quiet {
fmt.Fprintf(w, "NAME\tID\tCREATED\tPARENT\n") fmt.Fprintf(w, "REPOSITORY\tTAG\tID\tCREATED\tPARENT\n")
} }
if *quiet { allImages, err := srv.runtime.graph.Map()
images, err := srv.runtime.graph.All() if err != nil {
if err != nil { return err
return err }
for name, repository := range srv.runtime.repositories.Repositories {
if nameFilter != "" && name != nameFilter {
continue
} }
for _, image := range images { for tag, id := range repository {
fmt.Fprintln(stdout, image.Id) 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"))
}
} }
} else { }
// FIXME: // Display images which aren't part of a
// paths, err := srv.images.Paths() if nameFilter != "" {
// if err != nil { for id, image := range allImages {
// return err if !*quiet {
// } for idx, field := range []string{
// for _, name := range paths { /* REPOSITORY */ "",
// if nameFilter != "" && nameFilter != name { /* TAG */ "",
// continue /* ID */ id,
// } /* CREATED */ HumanDuration(time.Now().Sub(image.Created)) + " ago",
// ids, err := srv.images.List(name) /* PARENT */ image.Parent,
// if err != nil { } {
// return err if idx == 0 {
// } w.Write([]byte(field))
// for idx, img := range ids { } else {
// if *limit > 0 && idx >= *limit { w.Write([]byte("\t" + field))
// break }
// } }
// if !*quiet { } else {
// for idx, field := range []string{ stdout.Write([]byte(image.Id + "\n"))
// /* NAME */ name, }
// /* ID */ img.Id, }
// /* CREATED */ HumanDuration(time.Now().Sub(time.Unix(img.Created, 0))) + " ago", }
// /* PARENT */ img.Parent, if !*quiet {
// } { w.Flush()
// 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()
// }
//
} }
return nil return nil
} }
func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error { func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {

View File

@ -122,6 +122,19 @@ func (graph *Graph) GarbageCollect() error {
return os.RemoveAll(garbage.Root) 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) { func (graph *Graph) All() ([]*Image, error) {
files, err := ioutil.ReadDir(graph.Root) files, err := ioutil.ReadDir(graph.Root)
if err != nil { if err != nil {

View File

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

View File

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

View File

@ -11,7 +11,7 @@ import (
) )
const testLayerPath string = "/var/lib/docker/docker-ut.tar" 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 unitTestStoreBase string
var srv *Server var srv *Server