mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
First integration of the actual docker package into the server. Pull and put create actual containers. Rm actually removes them. The rest is still fake.
This commit is contained in:
parent
11b65a00c6
commit
b397ce5dea
2 changed files with 220 additions and 184 deletions
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/rcli"
|
||||
"github.com/dotcloud/docker/fake"
|
||||
"github.com/dotcloud/docker/future"
|
||||
|
@ -9,10 +10,8 @@ import (
|
|||
"log"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/kr/pty"
|
||||
"strings"
|
||||
"bytes"
|
||||
"text/tabwriter"
|
||||
|
@ -23,11 +22,11 @@ import (
|
|||
)
|
||||
|
||||
|
||||
func (docker *Docker) Name() string {
|
||||
func (srv *Server) Name() string {
|
||||
return "docker"
|
||||
}
|
||||
|
||||
func (docker *Docker) Help() string {
|
||||
func (srv *Server) Help() string {
|
||||
help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
|
||||
for _, cmd := range [][]interface{}{
|
||||
{"run", "Run a command in a container"},
|
||||
|
@ -50,7 +49,7 @@ func (docker *Docker) Help() string {
|
|||
}
|
||||
|
||||
|
||||
func (docker *Docker) CmdList(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdList(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout, "list", "[OPTIONS] [NAME]", "List containers")
|
||||
limit := flags.Int("l", 0, "Only show the N most recent versions of each name")
|
||||
quiet := flags.Bool("q", false, "only show numeric IDs")
|
||||
|
@ -64,7 +63,7 @@ func (docker *Docker) CmdList(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
nameFilter = flags.Arg(0)
|
||||
}
|
||||
var names []string
|
||||
for name := range docker.containersByName {
|
||||
for name := range srv.containersByName {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
@ -76,20 +75,20 @@ func (docker *Docker) CmdList(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
if nameFilter != "" && nameFilter != name {
|
||||
continue
|
||||
}
|
||||
for idx, container := range *docker.containersByName[name] {
|
||||
for idx, container := range *srv.containersByName[name] {
|
||||
if *limit > 0 && idx >= *limit {
|
||||
break
|
||||
}
|
||||
if !*quiet {
|
||||
for idx, field := range []string{
|
||||
/* NAME */ container.Name,
|
||||
/* NAME */ container.GetUserData("name"),
|
||||
/* ID */ container.Id,
|
||||
/* CREATED */ future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
|
||||
/* SOURCE */ container.Source,
|
||||
/* SIZE */ fmt.Sprintf("%.1fM", float32(container.Size) / 1024 / 1024),
|
||||
/* CHANGES */ fmt.Sprintf("%.1fM", float32(container.BytesChanged) / 1024 / 1024),
|
||||
/* RUNNING */ fmt.Sprintf("%v", container.Running),
|
||||
/* COMMAND */ container.CmdString(),
|
||||
/* SOURCE */ container.GetUserData("source"),
|
||||
/* SIZE */ fmt.Sprintf("%.1fM", float32(fake.RandomContainerSize()) / 1024 / 1024),
|
||||
/* CHANGES */ fmt.Sprintf("%.1fM", float32(fake.RandomBytesChanged() / 1024 / 1024)),
|
||||
/* RUNNING */ fmt.Sprintf("%v", fake.ContainerRunning()),
|
||||
/* COMMAND */ fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")),
|
||||
} {
|
||||
if idx == 0 {
|
||||
w.Write([]byte(field))
|
||||
|
@ -109,33 +108,33 @@ func (docker *Docker) CmdList(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) findContainer(name string) (*Container, bool) {
|
||||
func (srv *Server) findContainer(name string) (*fake.Container, bool) {
|
||||
// 1: look for container by ID
|
||||
if container, exists := docker.containers[name]; exists {
|
||||
return container, true
|
||||
if container := srv.docker.Get(name); container != nil {
|
||||
return fake.NewContainer(container), true
|
||||
}
|
||||
// 2: look for a container by name (and pick the most recent)
|
||||
if containers, exists := docker.containersByName[name]; exists {
|
||||
return (*containers)[0], true
|
||||
if containers, exists := srv.containersByName[name]; exists {
|
||||
return fake.NewContainer((*containers)[0]), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
||||
func (docker *Docker) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout, "rm", "[OPTIONS] CONTAINER", "Remove a container")
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, name := range flags.Args() {
|
||||
if _, err := docker.rm(name); err != nil {
|
||||
if _, err := srv.rm(name); err != nil {
|
||||
fmt.Fprintln(stdout, "Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("Not enough arguments")
|
||||
}
|
||||
|
@ -143,31 +142,42 @@ func (docker *Docker) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layer, err := docker.layers.AddLayer(resp.Body, stdout)
|
||||
layer, err := srv.layers.AddLayer(resp.Body, stdout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
docker.addContainer(args[0], "download", 0)
|
||||
fmt.Fprintln(stdout, layer.Id())
|
||||
container, err := srv.addContainer(layer.Id(), []string{layer.Path}, args[0], "download")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(stdout, container.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdPut(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdPut(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
if len(args) < 1 {
|
||||
return errors.New("Not enough arguments")
|
||||
}
|
||||
fmt.Printf("Adding layer\n")
|
||||
layer, err := docker.layers.AddLayer(stdin, stdout)
|
||||
layer, err := srv.layers.AddLayer(stdin, stdout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
docker.addContainer(args[0], "upload", 0)
|
||||
fmt.Fprintln(stdout, layer.Id())
|
||||
id := layer.Id()
|
||||
if !srv.docker.Exists(id) {
|
||||
log.Println("Creating new container: " + id)
|
||||
log.Printf("%v\n", srv.docker.List())
|
||||
_, err := srv.addContainer(id, []string{layer.Path}, args[0], "upload")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(stdout, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (docker *Docker) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout,
|
||||
"fork", "[OPTIONS] CONTAINER [DEST]",
|
||||
"Duplicate a container")
|
||||
|
@ -183,15 +193,15 @@ func (docker *Docker) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...s
|
|||
if dstName == "" {
|
||||
dstName = srcName
|
||||
}
|
||||
if src, exists := docker.findContainer(srcName); exists {
|
||||
dst := docker.addContainer(dstName, "snapshot:" + src.Id, src.Size)
|
||||
fmt.Fprintln(stdout, dst.Id)
|
||||
if _, exists := srv.findContainer(srcName); exists {
|
||||
//dst := srv.addContainer(dstName, "snapshot:" + src.Id, src.Size)
|
||||
//fmt.Fprintln(stdout, dst.Id)
|
||||
return nil
|
||||
}
|
||||
return errors.New("No such container: " + srcName)
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout,
|
||||
"tar", "CONTAINER",
|
||||
"Stream the contents of a container as a tar archive")
|
||||
|
@ -199,14 +209,14 @@ func (docker *Docker) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
|||
return nil
|
||||
}
|
||||
name := flags.Arg(0)
|
||||
if _, exists := docker.findContainer(name); exists {
|
||||
if _, exists := srv.findContainer(name); exists {
|
||||
// Stream the entire contents of the container (basically a volatile snapshot)
|
||||
return fake.WriteFakeTar(stdout)
|
||||
}
|
||||
return errors.New("No such container: " + name)
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout,
|
||||
"diff", "CONTAINER [OPTIONS]",
|
||||
"Inspect changes on a container's filesystem")
|
||||
|
@ -219,7 +229,7 @@ func (docker *Docker) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
if flags.NArg() < 1 {
|
||||
return errors.New("Not enough arguments")
|
||||
}
|
||||
if container, exists := docker.findContainer(flags.Arg(0)); !exists {
|
||||
if container, exists := srv.findContainer(flags.Arg(0)); !exists {
|
||||
return errors.New("No such container")
|
||||
} else if *fl_bytes {
|
||||
fmt.Fprintf(stdout, "%d\n", container.BytesChanged)
|
||||
|
@ -242,7 +252,7 @@ diff --git a/dockerd/dockerd.go b/dockerd/dockerd.go
|
|||
index 2dae694..e43caca 100644
|
||||
--- a/dockerd/dockerd.go
|
||||
+++ b/dockerd/dockerd.go
|
||||
@@ -158,6 +158,7 @@ func (docker *Docker) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||
@@ -158,6 +158,7 @@ func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...str
|
||||
flags := rcli.Subcmd(stdout,
|
||||
"diff", "CONTAINER [OPTIONS]",
|
||||
"Inspect changes on a container's filesystem")
|
||||
|
@ -262,7 +272,7 @@ index 2dae694..e43caca 100644
|
|||
|
||||
// ByDate wraps an array of layers so they can be sorted by date (most recent first)
|
||||
|
||||
type ByDate []*Container
|
||||
type ByDate []*docker.Container
|
||||
|
||||
func (c *ByDate) Len() int {
|
||||
return len(*c)
|
||||
|
@ -280,7 +290,7 @@ func (c *ByDate) Swap(i, j int) {
|
|||
containers[j] = tmp
|
||||
}
|
||||
|
||||
func (c *ByDate) Add(container *Container) {
|
||||
func (c *ByDate) Add(container *docker.Container) {
|
||||
*c = append(*c, container)
|
||||
sort.Sort(c)
|
||||
}
|
||||
|
@ -294,46 +304,38 @@ func (c *ByDate) Del(id string) {
|
|||
}
|
||||
|
||||
|
||||
func (docker *Docker) addContainer(name string, source string, size uint) *Container {
|
||||
if size == 0 {
|
||||
size = fake.RandomContainerSize()
|
||||
func (srv *Server) addContainer(id string, layers []string, name string, source string) (*fake.Container, error) {
|
||||
c, err := srv.docker.Create(id, "", nil, layers, &docker.Config{Hostname: id, Ram: 512 * 1024 * 1024})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &Container{
|
||||
Id: future.RandomId(),
|
||||
Name: name,
|
||||
Created: time.Now(),
|
||||
Source: source,
|
||||
Size: size,
|
||||
stdinLog: new(bytes.Buffer),
|
||||
stdoutLog: new(bytes.Buffer),
|
||||
if err := c.SetUserData("name", name); err != nil {
|
||||
srv.docker.Destroy(c)
|
||||
return nil, err
|
||||
}
|
||||
docker.containers[c.Id] = c
|
||||
if _, exists := docker.containersByName[c.Name]; !exists {
|
||||
docker.containersByName[c.Name] = new(ByDate)
|
||||
if _, exists := srv.containersByName[name]; !exists {
|
||||
srv.containersByName[name] = new(ByDate)
|
||||
}
|
||||
docker.containersByName[c.Name].Add(c)
|
||||
return c
|
||||
|
||||
srv.containersByName[name].Add(c)
|
||||
return fake.NewContainer(c), nil
|
||||
}
|
||||
|
||||
|
||||
func (docker *Docker) rm(id string) (*Container, error) {
|
||||
if container, exists := docker.containers[id]; exists {
|
||||
if container.Running {
|
||||
return nil, errors.New("Container is running: " + id)
|
||||
} else {
|
||||
// Remove from name lookup
|
||||
docker.containersByName[container.Name].Del(container.Id)
|
||||
// Remove from id lookup
|
||||
delete(docker.containers, container.Id)
|
||||
return container, nil
|
||||
}
|
||||
func (srv *Server) rm(id string) (*docker.Container, error) {
|
||||
container := srv.docker.Get(id)
|
||||
if container == nil {
|
||||
return nil, errors.New("No such continer: " + id)
|
||||
}
|
||||
return nil, errors.New(fmt.Sprintf("No such container: %s", id))
|
||||
// Remove from name lookup
|
||||
srv.containersByName[container.GetUserData("name")].Del(container.Id)
|
||||
if err := srv.docker.Destroy(container); err != nil {
|
||||
return container, err
|
||||
}
|
||||
return container, nil
|
||||
}
|
||||
|
||||
|
||||
func (docker *Docker) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout, "logs", "[OPTIONS] CONTAINER", "Fetch the logs of a container")
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -343,7 +345,7 @@ func (docker *Docker) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
return nil
|
||||
}
|
||||
name := flags.Arg(0)
|
||||
if container, exists := docker.findContainer(name); exists {
|
||||
if container, exists := srv.findContainer(name); exists {
|
||||
if _, err := io.Copy(stdout, container.StdoutLog()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -352,7 +354,7 @@ func (docker *Docker) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...str
|
|||
return errors.New("No such container: " + flags.Arg(0))
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout, "run", "[OPTIONS] CONTAINER COMMAND [ARG...]", "Run a command in a container")
|
||||
fl_attach := flags.Bool("a", false, "Attach stdin and stdout")
|
||||
fl_tty := flags.Bool("t", false, "Allocate a pseudo-tty")
|
||||
|
@ -364,7 +366,7 @@ func (docker *Docker) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
|||
return nil
|
||||
}
|
||||
name, cmd := flags.Arg(0), flags.Args()[1:]
|
||||
if container, exists := docker.findContainer(name); exists {
|
||||
if container, exists := srv.findContainer(name); exists {
|
||||
if container.Running {
|
||||
return errors.New("Already running: " + name)
|
||||
}
|
||||
|
@ -379,47 +381,24 @@ func (docker *Docker) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
|||
return errors.New("No such container: " + name)
|
||||
}
|
||||
|
||||
func startCommand(cmd *exec.Cmd, interactive bool) (io.WriteCloser, io.ReadCloser, error) {
|
||||
if interactive {
|
||||
term, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return term, term, nil
|
||||
}
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return stdin, stdout, nil
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
future.Seed()
|
||||
flag.Parse()
|
||||
docker, err := New()
|
||||
d, err := New()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
if err := rcli.ListenAndServeHTTP(":8080", docker); err != nil {
|
||||
if err := rcli.ListenAndServeHTTP(":8080", d); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
if err := rcli.ListenAndServeTCP(":4242", docker); err != nil {
|
||||
if err := rcli.ListenAndServeTCP(":4242", d); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func New() (*Docker, error) {
|
||||
func New() (*Server, error) {
|
||||
store, err := future.NewStore("/var/lib/docker/layers")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -427,20 +406,35 @@ func New() (*Docker, error) {
|
|||
if err := store.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Docker{
|
||||
d, err := docker.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv := &Server{
|
||||
containersByName: make(map[string]*ByDate),
|
||||
containers: make(map[string]*Container),
|
||||
layers: store,
|
||||
}, nil
|
||||
docker: d,
|
||||
}
|
||||
// Update name index
|
||||
log.Printf("Building name index from %s...\n")
|
||||
for _, container := range srv.docker.List() {
|
||||
log.Printf("Indexing %s to %s\n", container.Id, container.GetUserData("name"))
|
||||
name := container.GetUserData("name")
|
||||
if _, exists := srv.containersByName[name]; !exists {
|
||||
srv.containersByName[name] = new(ByDate)
|
||||
}
|
||||
srv.containersByName[name].Add(container)
|
||||
}
|
||||
log.Printf("Done building index\n")
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
|
||||
func (docker *Docker) CmdMirror(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdMirror(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
_, err := io.Copy(stdout, stdin)
|
||||
return err
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdDebug(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdDebug(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
for {
|
||||
if line, err := bufio.NewReader(stdin).ReadString('\n'); err == nil {
|
||||
fmt.Printf("--- %s", line)
|
||||
|
@ -456,7 +450,7 @@ func (docker *Docker) CmdDebug(stdin io.ReadCloser, stdout io.Writer, args ...st
|
|||
return nil
|
||||
}
|
||||
|
||||
func (docker *Docker) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
func (srv *Server) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
flags := rcli.Subcmd(stdout, "web", "[OPTIONS]", "A web UI for docker")
|
||||
showurl := flags.Bool("u", false, "Return the URL of the web UI")
|
||||
if err := flags.Parse(args); err != nil {
|
||||
|
@ -475,85 +469,9 @@ func (docker *Docker) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
|||
}
|
||||
|
||||
|
||||
type Docker struct {
|
||||
containers map[string]*Container
|
||||
type Server struct {
|
||||
containersByName map[string]*ByDate
|
||||
layers *future.Store
|
||||
}
|
||||
|
||||
type Container struct {
|
||||
Id string
|
||||
Name string
|
||||
Created time.Time
|
||||
Source string
|
||||
Size uint
|
||||
FilesChanged uint
|
||||
BytesChanged uint
|
||||
Running bool
|
||||
Cmd string
|
||||
Args []string
|
||||
stdoutLog *bytes.Buffer
|
||||
stdinLog *bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *Container) Run(command string, args []string, stdin io.ReadCloser, stdout io.Writer, tty bool) error {
|
||||
// Not thread-safe
|
||||
if c.Running {
|
||||
return errors.New("Already running")
|
||||
}
|
||||
c.Cmd = command
|
||||
c.Args = args
|
||||
// Reset logs
|
||||
c.stdoutLog.Reset()
|
||||
c.stdinLog.Reset()
|
||||
cmd := exec.Command(c.Cmd, c.Args...)
|
||||
cmd_stdin, cmd_stdout, err := startCommand(cmd, tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Running = true
|
||||
// ADD FAKE RANDOM CHANGES
|
||||
c.FilesChanged = fake.RandomFilesChanged()
|
||||
c.BytesChanged = fake.RandomBytesChanged()
|
||||
copy_out := future.Go(func() error {
|
||||
_, err := io.Copy(io.MultiWriter(stdout, c.stdoutLog), cmd_stdout)
|
||||
return err
|
||||
})
|
||||
future.Go(func() error {
|
||||
_, err := io.Copy(io.MultiWriter(cmd_stdin, c.stdinLog), stdin)
|
||||
cmd_stdin.Close()
|
||||
stdin.Close()
|
||||
return err
|
||||
})
|
||||
wait := future.Go(func() error {
|
||||
err := cmd.Wait()
|
||||
c.Running = false
|
||||
return err
|
||||
})
|
||||
if err := <-copy_out; err != nil {
|
||||
if c.Running {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := <-wait; err != nil {
|
||||
if status, ok := err.(*exec.ExitError); ok {
|
||||
fmt.Fprintln(stdout, status)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Container) StdoutLog() io.Reader {
|
||||
return strings.NewReader(c.stdoutLog.String())
|
||||
}
|
||||
|
||||
func (c *Container) StdinLog() io.Reader {
|
||||
return strings.NewReader(c.stdinLog.String())
|
||||
}
|
||||
|
||||
func (c *Container) CmdString() string {
|
||||
return strings.Join(append([]string{c.Cmd}, c.Args...), " ")
|
||||
docker *docker.Docker
|
||||
}
|
||||
|
||||
|
|
118
fake/fake.go
118
fake/fake.go
|
@ -5,6 +5,13 @@ import (
|
|||
"math/rand"
|
||||
"io"
|
||||
"archive/tar"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/future"
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"fmt"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
|
||||
|
@ -47,3 +54,114 @@ func RandomFilesChanged() uint {
|
|||
func RandomContainerSize() uint {
|
||||
return uint(rand.Int31n(142 * 1024 * 1024))
|
||||
}
|
||||
|
||||
func ContainerRunning() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Container struct {
|
||||
*docker.Container
|
||||
Name string
|
||||
Source string
|
||||
Size uint
|
||||
FilesChanged uint
|
||||
BytesChanged uint
|
||||
Running bool
|
||||
stdoutLog *bytes.Buffer
|
||||
stdinLog *bytes.Buffer
|
||||
}
|
||||
|
||||
func NewContainer(c *docker.Container) *Container {
|
||||
return &Container{
|
||||
Container: c,
|
||||
Name: c.GetUserData("name"),
|
||||
stdoutLog: new(bytes.Buffer),
|
||||
stdinLog: new(bytes.Buffer),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Container) Run(command string, args []string, stdin io.ReadCloser, stdout io.Writer, tty bool) error {
|
||||
// Not thread-safe
|
||||
if c.Running {
|
||||
return errors.New("Already running")
|
||||
}
|
||||
c.Path = command
|
||||
c.Args = args
|
||||
// Reset logs
|
||||
c.stdoutLog.Reset()
|
||||
c.stdinLog.Reset()
|
||||
cmd := exec.Command(c.Path, c.Args...)
|
||||
cmd_stdin, cmd_stdout, err := startCommand(cmd, tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Running = true
|
||||
// ADD FAKE RANDOM CHANGES
|
||||
c.FilesChanged = RandomFilesChanged()
|
||||
c.BytesChanged = RandomBytesChanged()
|
||||
copy_out := future.Go(func() error {
|
||||
_, err := io.Copy(io.MultiWriter(stdout, c.stdoutLog), cmd_stdout)
|
||||
return err
|
||||
})
|
||||
future.Go(func() error {
|
||||
_, err := io.Copy(io.MultiWriter(cmd_stdin, c.stdinLog), stdin)
|
||||
cmd_stdin.Close()
|
||||
stdin.Close()
|
||||
return err
|
||||
})
|
||||
wait := future.Go(func() error {
|
||||
err := cmd.Wait()
|
||||
c.Running = false
|
||||
return err
|
||||
})
|
||||
if err := <-copy_out; err != nil {
|
||||
if c.Running {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := <-wait; err != nil {
|
||||
if status, ok := err.(*exec.ExitError); ok {
|
||||
fmt.Fprintln(stdout, status)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Container) StdoutLog() io.Reader {
|
||||
return strings.NewReader(c.stdoutLog.String())
|
||||
}
|
||||
|
||||
func (c *Container) StdinLog() io.Reader {
|
||||
return strings.NewReader(c.stdinLog.String())
|
||||
}
|
||||
|
||||
func (c *Container) CmdString() string {
|
||||
return strings.Join(append([]string{c.Path}, c.Args...), " ")
|
||||
}
|
||||
|
||||
|
||||
func startCommand(cmd *exec.Cmd, interactive bool) (io.WriteCloser, io.ReadCloser, error) {
|
||||
if interactive {
|
||||
term, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return term, term, nil
|
||||
}
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return stdin, stdout, nil
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue