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"
"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"))
}
}
} 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()
// }
//
}
// 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"))
}
}
}
if !*quiet {
w.Flush()
}
return nil
}
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)
}
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 {

View File

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

View File

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

View File

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