mirror of https://github.com/docker/docs.git
First integration of runtime with repositories & tags
This commit is contained in:
parent
680f40c37e
commit
44faa07b6c
130
commands.go
130
commands.go
|
@ -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 _, image := range images {
|
for name, repository := range srv.runtime.repositories.Repositories {
|
||||||
fmt.Fprintln(stdout, image.Id)
|
if nameFilter != "" && name != nameFilter {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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 {
|
} else {
|
||||||
// FIXME:
|
stdout.Write([]byte(image.Id + "\n"))
|
||||||
// paths, err := srv.images.Paths()
|
}
|
||||||
// if err != nil {
|
}
|
||||||
// return err
|
}
|
||||||
// }
|
if !*quiet {
|
||||||
// for _, name := range paths {
|
w.Flush()
|
||||||
// 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()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
10
runtime.go
10
runtime.go
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue