diff --git a/AUTHORS b/AUTHORS index 85decb361a..7aede7e5ee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,3 +11,4 @@ Ken Cochrane Charles Hooper Guillaume Charmes Daniel Mizyrycki +John Costa diff --git a/commands.go b/commands.go index a0a322afab..1f2c3650d7 100644 --- a/commands.go +++ b/commands.go @@ -283,7 +283,10 @@ func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string // 'docker rmi NAME' removes all images with the name NAME func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) (err error) { cmd := rcli.Subcmd(stdout, "rmimage", "[OPTIONS] IMAGE", "Remove an image") - if cmd.Parse(args) != nil || cmd.NArg() < 1 { + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { cmd.Usage() return nil } @@ -297,7 +300,10 @@ func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) func (srv *Server) CmdHistory(stdin io.ReadCloser, stdout io.Writer, args ...string) error { cmd := rcli.Subcmd(stdout, "history", "[OPTIONS] IMAGE", "Show the history of an image") - if cmd.Parse(args) != nil || cmd.NArg() != 1 { + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() != 1 { cmd.Usage() return nil } @@ -472,19 +478,15 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string } if srv.runtime.graph.LookupRemoteImage(remote, srv.runtime.authConfig) { - fmt.Fprintf(stdout, "Pulling %s...\n", remote) - if err := srv.runtime.graph.PullImage(remote, srv.runtime.authConfig); err != nil { + if err := srv.runtime.graph.PullImage(stdout, remote, srv.runtime.authConfig); err != nil { return err } - fmt.Fprintf(stdout, "Pulled\n") return nil } // FIXME: Allow pull repo:tag - fmt.Fprintf(stdout, "Pulling %s...\n", remote) if err := srv.runtime.graph.PullRepository(stdout, remote, "", srv.runtime.repositories, srv.runtime.authConfig); err != nil { return err } - fmt.Fprintf(stdout, "Pull completed\n") return nil } @@ -812,14 +814,16 @@ func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) } func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - config, err := ParseRun(args) + config, err := ParseRun(args, stdout) if err != nil { return err } if config.Image == "" { + fmt.Fprintln(stdout, "Error: Image not specified") return fmt.Errorf("Image not specified") } if len(config.Cmd) == 0 { + fmt.Fprintln(stdout, "Error: Command not specified") return fmt.Errorf("Command not specified") } // Create new container diff --git a/container.go b/container.go index 7e7077c123..785b351c22 100644 --- a/container.go +++ b/container.go @@ -3,8 +3,8 @@ package docker import ( "encoding/json" "errors" - "flag" "fmt" + "github.com/dotcloud/docker/rcli" "github.com/kr/pty" "io" "io/ioutil" @@ -60,9 +60,12 @@ type Config struct { Image string // Name of the image as it was passed by the operator (eg. could be symbolic) } -func ParseRun(args []string) (*Config, error) { - cmd := flag.NewFlagSet("", flag.ContinueOnError) - cmd.SetOutput(ioutil.Discard) +func ParseRun(args []string, stdout io.Writer) (*Config, error) { + cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container") + if len(args) > 0 && args[0] != "--help" { + cmd.SetOutput(ioutil.Discard) + } + fl_user := cmd.String("u", "", "Username or UID") fl_detach := cmd.Bool("d", false, "Detached mode: leave the container running in the background") fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached") @@ -255,6 +258,9 @@ func (container *Container) Start() error { var err error if container.Config.Tty { + container.cmd.Env = append(container.Config.Env, + "TERM=xterm", + ) err = container.startPty() } else { err = container.start() diff --git a/docs/Makefile b/docs/Makefile index a9006a062d..d7602ae826 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -64,6 +64,11 @@ push: @cd _build/html/ ; \ dotcloud push +github-deploy: docs + rm -fr github-deploy + git clone ssh://git@github.com/dotcloud/docker github-deploy + cd github-deploy && git checkout -f gh-pages && git rm -r * && rsync -avH ../_build/html/ ./ && touch .nojekyll && echo "docker.io" > CNAME && git add * && git commit -m "Updating docs" + $(VERSIONS): @echo "Hello world" diff --git a/docs/sources/documentation/commandline/basecommands.rst b/docs/sources/documentation/commandline/basecommands.rst index 7aa8973657..c764af6bb8 100644 --- a/docs/sources/documentation/commandline/basecommands.rst +++ b/docs/sources/documentation/commandline/basecommands.rst @@ -61,3 +61,7 @@ Expose a service on a TCP port # Verify that the network connection worked echo "Daemon received: $(docker logs $JOB)" + +Continue to the complete `Command Line Interface`_ + +.. _Command Line Interface: ../commandline/cli.html diff --git a/docs/sources/documentation/examples/python_web_app.rst b/docs/sources/documentation/examples/python_web_app.rst index 9d988b5160..5fac374889 100644 --- a/docs/sources/documentation/examples/python_web_app.rst +++ b/docs/sources/documentation/examples/python_web_app.rst @@ -6,7 +6,7 @@ Building a python web app ========================= -The goal of this example is to show you how you can author your own docker images using a parent image, making changes to it, and then saving the results as a new image. We will do that by making a simple hello flask web application image. +The goal of this example is to show you how you can author your own docker images using a parent image, making changes to it, and then saving the results as a new image. We will do that by making a simple hello flask web application image. **Steps:** @@ -64,3 +64,7 @@ See the example in action
+ +Continue to the `base commands`_ + +.. _base commands: ../commandline/basecommands.html diff --git a/docs/sources/documentation/faq.rst b/docs/sources/documentation/faq.rst index 7b2b54de5f..aa167acd97 100644 --- a/docs/sources/documentation/faq.rst +++ b/docs/sources/documentation/faq.rst @@ -3,27 +3,45 @@ FAQ Most frequently asked questions. ---------------------------------------------- +-------------------------------- -1. How much does Docker cost? +**1. How much does Docker cost?** Docker is 100% free, it is open source, so you can use it without paying. -2. What open source license are you using? +**2. What open source license are you using?** We are using the Apache License Version 2.0, see it here: https://github.com/dotcloud/docker/blob/master/LICENSE -3. Does Docker run on Mac OS X or Windows? +**3. Does Docker run on Mac OS X or Windows?** -Not at this time, Docker currently only runs on Linux, but you can use VirtualBox to run Docker in a virtual machine on your box, and get the best of both worlds. Check out the getting started guides for help on setting up your machine. +Not at this time, Docker currently only runs on Linux, but you can use VirtualBox to run Docker in a virtual machine on your box, and get the best of both worlds. Check out the MacOSX_ and Windows_ intallation guides. -4. How do containers compare to virtual machines? +**4. How do containers compare to virtual machines?** -Containers are more light weight and can start in less then a second, and are great for lots of different tasks, but they aren't as full featured as virtual machines. +Containers are more light weight and can start in less then a second, and are great for lots of different tasks, but they aren't as full featured as virtual machines. -5. Can I help by adding some questions and answers? +**5. Can I help by adding some questions and answers?** -Definitely! You can fork the repo and edit the documentation sources right there. +Definitely! You can fork `the repo`_ and edit the documentation sources. + + +**42. Where can I find more answers?** + +You can find more answers on: + +* `IRC: docker on freenode`_ +* `Github`_ +* `Ask questions on Stackoverflow`_ +* `Join the conversation on Twitter`_ + +.. _Windows: ../documentation/installation/windows.html +.. _MacOSX: ../documentation/installation/macos.html +.. _the repo: http://www.github.com/dotcloud/docker +.. _IRC\: docker on freenode: irc://chat.freenode.net#docker +.. _Github: http://www.github.com/dotcloud/docker +.. _Ask questions on Stackoverflow: http://stackoverflow.com/search?q=docker +.. _Join the conversation on Twitter: http://twitter.com/getdocker Looking for something else to read? Checkout the :ref:`hello_world` example. diff --git a/docs/sources/gettingstarted.html b/docs/sources/gettingstarted.html index ba2caf01d0..7d198629cd 100644 --- a/docs/sources/gettingstarted.html +++ b/docs/sources/gettingstarted.html @@ -62,13 +62,15 @@
+
+ Docker is still under heavy development. It should not yet be used in production. Check the repo for recent progress. +

- Installing on Ubuntu 12.04 and 12.10

-

Please note this project is currently under heavy development. It should not be used in production.

+ Installing on Ubuntu
  1. Install dependencies:

    diff --git a/docs/sources/index.html b/docs/sources/index.html index 6a3b363f9e..382f935781 100644 --- a/docs/sources/index.html +++ b/docs/sources/index.html @@ -72,11 +72,19 @@
-

Docker - the Linux container runtime

+

Docker

+

The Linux container runtime

-

Docker encapsulates heterogeneous payloads in Standard Containers, and runs them on any server with strong guarantees of isolation and repeatability.

+

+ Docker complements LXC with a high-level API which operates at the process level. + It runs unix processes with strong guarantees of isolation and repeatability across servers. +

+ +

+ Docker is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc. +

diff --git a/lxc_template.go b/lxc_template.go old mode 100755 new mode 100644 diff --git a/registry.go b/registry.go index ea4751bbbe..c7dd23b850 100644 --- a/registry.go +++ b/registry.go @@ -94,36 +94,38 @@ func (graph *Graph) LookupRemoteImage(imgId string, authConfig *auth.AuthConfig) // Retrieve an image from the Registry. // Returns the Image object as well as the layer as an Archive (io.Reader) -func (graph *Graph) getRemoteImage(imgId string, authConfig *auth.AuthConfig) (*Image, Archive, error) { +func (graph *Graph) getRemoteImage(stdout io.Writer, imgId string, authConfig *auth.AuthConfig) (*Image, Archive, error) { client := &http.Client{} + fmt.Fprintf(stdout, "Pulling %s metadata\n", imgId) // Get the Json req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/json", nil) if err != nil { - return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err) + return nil, nil, fmt.Errorf("Failed to download json: %s", err) } req.SetBasicAuth(authConfig.Username, authConfig.Password) res, err := client.Do(req) - if err != nil || res.StatusCode != 200 { - if res != nil { - return nil, nil, fmt.Errorf("Internal server error: %d trying to get image %s", res.StatusCode, imgId) - } - return nil, nil, err + if err != nil { + return nil, nil, fmt.Errorf("Failed to download json: %s", err) + } + if res.StatusCode != 200 { + return nil, nil, fmt.Errorf("HTTP code %d", res.StatusCode) } defer res.Body.Close() jsonString, err := ioutil.ReadAll(res.Body) if err != nil { - return nil, nil, fmt.Errorf("Error while reading the http response: %s\n", err) + return nil, nil, fmt.Errorf("Failed to download json: %s", err) } img, err := NewImgJson(jsonString) if err != nil { - return nil, nil, fmt.Errorf("Error while parsing the json: %s\n", err) + return nil, nil, fmt.Errorf("Failed to parse json: %s", err) } img.Id = imgId // Get the layer + fmt.Fprintf(stdout, "Pulling %s fs layer\n", imgId) req, err = http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/layer", nil) if err != nil { return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err) @@ -136,7 +138,7 @@ func (graph *Graph) getRemoteImage(imgId string, authConfig *auth.AuthConfig) (* return img, res.Body, nil } -func (graph *Graph) PullImage(imgId string, authConfig *auth.AuthConfig) error { +func (graph *Graph) PullImage(stdout io.Writer, imgId string, authConfig *auth.AuthConfig) error { history, err := graph.getRemoteHistory(imgId, authConfig) if err != nil { return err @@ -145,7 +147,7 @@ func (graph *Graph) PullImage(imgId string, authConfig *auth.AuthConfig) error { // FIXME: Lunch the getRemoteImage() in goroutines for _, j := range history { if !graph.Exists(j.Id) { - img, layer, err := graph.getRemoteImage(j.Id, authConfig) + img, layer, err := graph.getRemoteImage(stdout, j.Id, authConfig) if err != nil { // FIXME: Keep goging in case of error? return err @@ -162,7 +164,7 @@ func (graph *Graph) PullImage(imgId string, authConfig *auth.AuthConfig) error { func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, repositories *TagStore, authConfig *auth.AuthConfig) error { client := &http.Client{} - fmt.Fprintf(stdout, "Pulling repo: %s\n", REGISTRY_ENDPOINT+"/users/"+remote) + fmt.Fprintf(stdout, "Pulling repository %s\n", remote) var repositoryTarget string // If we are asking for 'root' repository, lookup on the Library's registry @@ -178,12 +180,12 @@ func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, re } req.SetBasicAuth(authConfig.Username, authConfig.Password) res, err := client.Do(req) - if err != nil || res.StatusCode != 200 { - if res != nil { - return fmt.Errorf("Internal server error: %d trying to pull %s", res.StatusCode, remote) - } + if err != nil { return err } + if res.StatusCode != 200 { + return fmt.Errorf("HTTP code: %d", res.StatusCode) + } defer res.Body.Close() rawJson, err := ioutil.ReadAll(res.Body) if err != nil { @@ -194,7 +196,8 @@ func (graph *Graph) PullRepository(stdout io.Writer, remote, askedTag string, re return err } for tag, rev := range t { - if err = graph.PullImage(rev, authConfig); err != nil { + fmt.Fprintf(stdout, "Pulling tag %s:%s\n", remote, tag) + if err = graph.PullImage(stdout, rev, authConfig); err != nil { return err } if err = repositories.Set(remote, tag, rev, true); err != nil { @@ -232,17 +235,20 @@ func (graph *Graph) PushImage(stdout io.Writer, imgOrig *Image, authConfig *auth req.SetBasicAuth(authConfig.Username, authConfig.Password) res, err := client.Do(req) if err != nil { - return fmt.Errorf("Failed to upload json: %s", err) + return fmt.Errorf("Failed to upload metadata: %s", err) } if res.StatusCode != 200 { - Debugf("Pushing return status: %d\n", res.StatusCode) switch res.StatusCode { case 204: // Case where the image is already on the Registry // FIXME: Do not be silent? return nil default: - return fmt.Errorf("Received HTTP code %d while uploading json", res.StatusCode) + errBody, err := ioutil.ReadAll(res.Body) + if err != nil { + errBody = []byte(err.Error()) + } + return fmt.Errorf("HTTP code %d while uploading metadata: %s", res.StatusCode, errBody) } } diff --git a/term/termios_linux.go b/term/termios_linux.go index 933ef84c4d..ef2c84c7e8 100644 --- a/term/termios_linux.go +++ b/term/termios_linux.go @@ -1,10 +1,29 @@ package term import ( - "syscall" - "unsafe" + "syscall" + "unsafe" ) +// #include +// #include +/* +void MakeRaw(int fd) { + struct termios t; + + // FIXME: Handle errors? + ioctl(fd, TCGETS, &t); + + t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + t.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + t.c_cflag &= ~(CSIZE | PARENB); + t.c_cflag |= CS8; + + ioctl(fd, TCSETS, &t); +} +*/ +import "C" + const ( getTermios = syscall.TCGETS setTermios = syscall.TCSETS @@ -14,19 +33,25 @@ const ( // mode and returns the previous state of the terminal so that it can be // restored. func MakeRaw(fd int) (*State, error) { - var oldState State - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { - return nil, err - } + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + C.MakeRaw(C.int(fd)) + return &oldState, nil - newState := oldState.termios - newState.Iflag &^= ISTRIP | IXON | IXOFF - newState.Iflag |= ICRNL - newState.Oflag |= ONLCR - newState.Lflag &^= ECHO | ICANON | ISIG - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { - return nil, err - } + // FIXME: post on goland issues this: very same as the C function bug non-working - return &oldState, nil -} \ No newline at end of file + // newState := oldState.termios + + // newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON) + // newState.Oflag &^= OPOST + // newState.Lflag &^= (ECHO | syscall.ECHONL | ICANON | ISIG | IEXTEN) + // newState.Cflag &^= (CSIZE | syscall.PARENB) + // newState.Cflag |= CS8 + + // if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&newState))); err != 0 { + // return nil, err + // } + // return &oldState, nil +}