From fde82f448f6b1508e03f419a3ce4c9b80311d466 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 17 Jun 2013 18:13:40 +0000 Subject: [PATCH 01/17] use go 1.1 cookiejar and revome ResetClient --- registry/registry.go | 15 +++++---------- server.go | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 131b02708e..21979fad8b 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -7,10 +7,10 @@ import ( "fmt" "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/utils" - "github.com/shin-/cookiejar" "io" "io/ioutil" "net/http" + "net/http/cookiejar" "net/url" "strings" ) @@ -438,11 +438,6 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { return result, err } -func (r *Registry) ResetClient(authConfig *auth.AuthConfig) { - r.authConfig = authConfig - r.client.Jar = cookiejar.NewCookieJar() -} - func (r *Registry) GetAuthConfig(withPasswd bool) *auth.AuthConfig { password := "" if withPasswd { @@ -478,18 +473,18 @@ type Registry struct { authConfig *auth.AuthConfig } -func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry { +func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err error) { httpTransport := &http.Transport{ DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment, } - r := &Registry{ + r = &Registry{ authConfig: authConfig, client: &http.Client{ Transport: httpTransport, }, } - r.client.Jar = cookiejar.NewCookieJar() - return r + r.client.Jar, err = cookiejar.New(nil) + return r, err } diff --git a/server.go b/server.go index 30e3ec6b3a..7b7eabe321 100644 --- a/server.go +++ b/server.go @@ -54,8 +54,11 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error { } func (srv *Server) ImagesSearch(term string) ([]APISearch, error) { - - results, err := registry.NewRegistry(srv.runtime.root, nil).SearchRepositories(term) + r, err := registry.NewRegistry(srv.runtime.root, nil) + if err != nil { + return nil, err + } + results, err := r.SearchRepositories(term) if err != nil { return nil, err } @@ -402,7 +405,10 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re } func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { - r := registry.NewRegistry(srv.runtime.root, authConfig) + r, err := registry.NewRegistry(srv.runtime.root, authConfig) + if err != nil { + return err + } out = utils.NewWriteFlusher(out) if endpoint != "" { if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil { @@ -596,8 +602,10 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(name) - r := registry.NewRegistry(srv.runtime.root, authConfig) - + r, err2 := registry.NewRegistry(srv.runtime.root, authConfig) + if err2 != nil { + return err2 + } if err != nil { out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name]))) // If it fails, try to get the repository From 13e03a691145921ffc17c56db24f06eacca99a77 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 11:29:02 -0700 Subject: [PATCH 02/17] Fix the auth tests and add the offline mode --- auth/auth_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/auth/auth_test.go b/auth/auth_test.go index 6c8d032cf7..e49ec03721 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -10,8 +10,8 @@ import ( func TestEncodeAuth(t *testing.T) { newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"} - authStr := EncodeAuth(newAuthConfig) - decAuthConfig, err := DecodeAuth(authStr) + authStr := encodeAuth(newAuthConfig) + decAuthConfig, err := decodeAuth(authStr) if err != nil { t.Fatal(err) } @@ -27,10 +27,13 @@ func TestEncodeAuth(t *testing.T) { } func TestLogin(t *testing.T) { + if os.Getenv("OFFLINE") != "" { + t.Skip("Offline mode, skipping.") + } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") authConfig := NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", "/tmp") - status, err := Login(authConfig) + status, err := Login(authConfig, false) if err != nil { t.Fatal(err) } @@ -40,6 +43,9 @@ func TestLogin(t *testing.T) { } func TestCreateAccount(t *testing.T) { + if os.Getenv("OFFLINE") != "" { + t.Skip("Offline mode, skipping.") + } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") tokenBuffer := make([]byte, 16) @@ -50,7 +56,7 @@ func TestCreateAccount(t *testing.T) { token := hex.EncodeToString(tokenBuffer)[:12] username := "ut" + token authConfig := NewAuthConfig(username, "test42", "docker-ut+"+token+"@example.com", "/tmp") - status, err := Login(authConfig) + status, err := Login(authConfig, false) if err != nil { t.Fatal(err) } @@ -60,7 +66,7 @@ func TestCreateAccount(t *testing.T) { t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status) } - status, err = Login(authConfig) + status, err = Login(authConfig, false) if err == nil { t.Fatalf("Expected error but found nil instead") } From 3a0ffbc77267e395676860db265ee3476c45b3c2 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 14:44:35 -0700 Subject: [PATCH 03/17] - Runtime: Fixes #884 enforce stdout/err sync by merging the stream --- commands.go | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/commands.go b/commands.go index ce15fd6cf1..abe91f6eab 100644 --- a/commands.go +++ b/commands.go @@ -1058,37 +1058,23 @@ func (cli *DockerCli) CmdAttach(args ...string) error { return err } - splitStderr := container.Config.Tty - - connections := 1 - if splitStderr { - connections += 1 - } - chErrors := make(chan error, connections) + chErrors := make(chan error) if container.Config.Tty { cli.monitorTtySize(cmd.Arg(0)) } - if splitStderr { - go func() { - chErrors <- cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?stream=1&stderr=1", false, nil, os.Stderr) - }() - } + v := url.Values{} v.Set("stream", "1") v.Set("stdin", "1") v.Set("stdout", "1") - if !splitStderr { - v.Set("stderr", "1") - } + v.Set("stderr", "1") + go func() { chErrors <- cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, os.Stdin, os.Stdout) }() - for connections > 0 { - err := <-chErrors - if err != nil { - return err - } - connections -= 1 + + if err := <-chErrors; err != nil { + return err } return nil } From 3dc93e390ad3d310dede84948b726ce67e261375 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Tue, 18 Jun 2013 10:10:03 -0700 Subject: [PATCH 04/17] Remove useless goroutine --- commands.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/commands.go b/commands.go index abe91f6eab..19fb32f966 100644 --- a/commands.go +++ b/commands.go @@ -1058,7 +1058,6 @@ func (cli *DockerCli) CmdAttach(args ...string) error { return err } - chErrors := make(chan error) if container.Config.Tty { cli.monitorTtySize(cmd.Arg(0)) } @@ -1069,11 +1068,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error { v.Set("stdout", "1") v.Set("stderr", "1") - go func() { - chErrors <- cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, os.Stdin, os.Stdout) - }() - - if err := <-chErrors; err != nil { + if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, os.Stdin, os.Stdout); err != nil { return err } return nil From 3adf9ce04ef1632f82f7bd1585c135bb141aa450 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 18 Jun 2013 18:59:56 +0000 Subject: [PATCH 05/17] add basic support for unix sockets --- api.go | 19 +++++++++-- builder_client.go | 4 +-- commands.go | 47 +++++++++++++++++--------- docker/docker.go | 84 ++++++++++++++++++++++++++++++++--------------- utils/utils.go | 2 ++ 5 files changed, 110 insertions(+), 46 deletions(-) diff --git a/api.go b/api.go index e870ca7723..0b89fcf323 100644 --- a/api.go +++ b/api.go @@ -8,12 +8,16 @@ import ( "github.com/gorilla/mux" "io" "log" + "net" "net/http" + "os" "strconv" "strings" ) const APIVERSION = 1.2 +const DEFAULTHTTPHOST string = "127.0.0.1" +const DEFAULTHTTPPORT int = 4243 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() @@ -848,12 +852,21 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) { return r, nil } -func ListenAndServe(addr string, srv *Server, logging bool) error { - log.Printf("Listening for HTTP on %s\n", addr) +func ListenAndServe(proto, addr string, srv *Server, logging bool) error { + log.Printf("Listening for HTTP on %s (%s)\n", addr, proto) r, err := createRouter(srv, logging) if err != nil { return err } - return http.ListenAndServe(addr, r) + l, e := net.Listen(proto, addr) + if e != nil { + return e + } + //as the daemon is launched as root, change to permission of the socket to allow non-root to connect + if proto == "unix" { + os.Chmod(addr, 0777) + } + httpSrv := http.Server{Addr: addr, Handler: r} + return httpSrv.Serve(l) } diff --git a/builder_client.go b/builder_client.go index dc9528ff41..d11e7fc995 100644 --- a/builder_client.go +++ b/builder_client.go @@ -304,9 +304,9 @@ func (b *builderClient) Build(dockerfile, context io.Reader) (string, error) { return "", fmt.Errorf("An error occured during the build\n") } -func NewBuilderClient(addr string, port int) BuildFile { +func NewBuilderClient(proto, addr string) BuildFile { return &builderClient{ - cli: NewDockerCli(addr, port), + cli: NewDockerCli(proto, addr), config: &Config{}, tmpContainers: make(map[string]struct{}), tmpImages: make(map[string]struct{}), diff --git a/commands.go b/commands.go index cf23a8d65e..2c33485ecb 100644 --- a/commands.go +++ b/commands.go @@ -40,8 +40,8 @@ func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) { return reflect.TypeOf(cli).MethodByName(methodName) } -func ParseCommands(addr string, port int, args ...string) error { - cli := NewDockerCli(addr, port) +func ParseCommands(proto, addr string, args ...string) error { + cli := NewDockerCli(proto, addr) if len(args) > 0 { method, exists := cli.getMethod(args[0]) @@ -74,7 +74,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { return nil } } - help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=\"%s:%d\": Host:port to bind/connect to\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", cli.host, cli.port) + help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=\"%s:%d\": Host:port to bind/connect to\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT) for _, command := range [][2]string{ {"attach", "Attach to a running container"}, {"build", "Build a container from a Dockerfile"}, @@ -197,7 +197,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { v := &url.Values{} v.Set("t", *tag) // Send the multipart request with correct content-type - req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s?%s", cli.host, cli.port, "/build", v.Encode()), multipartBody) + req, err := http.NewRequest("POST", fmt.Sprintf("/v%s/build?%s", APIVERSION, v.Encode()), multipartBody) if err != nil { return err } @@ -206,8 +206,13 @@ func (cli *DockerCli) CmdBuild(args ...string) error { req.Header.Set("X-Docker-Context-Compression", compression.Flag()) fmt.Println("Uploading Context...") } - - resp, err := http.DefaultClient.Do(req) + dial, err := net.Dial(cli.proto, cli.addr) + if err != nil { + return err + } + clientconn := httputil.NewClientConn(dial, nil) + resp, err := clientconn.Do(req) + defer clientconn.Close() if err != nil { return err } @@ -1339,7 +1344,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, params = bytes.NewBuffer(buf) } - req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), params) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), params) if err != nil { return nil, -1, err } @@ -1349,7 +1354,13 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, } else if method == "POST" { req.Header.Set("Content-Type", "plain/text") } - resp, err := http.DefaultClient.Do(req) + dial, err := net.Dial(cli.proto, cli.addr) + if err != nil { + return nil, -1, err + } + clientconn := httputil.NewClientConn(dial, nil) + resp, err := clientconn.Do(req) + defer clientconn.Close() if err != nil { if strings.Contains(err.Error(), "connection refused") { return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?") @@ -1374,7 +1385,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e if (method == "POST" || method == "PUT") && in == nil { in = bytes.NewReader([]byte{}) } - req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), in) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), in) if err != nil { return err } @@ -1382,7 +1393,13 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e if method == "POST" { req.Header.Set("Content-Type", "plain/text") } - resp, err := http.DefaultClient.Do(req) + dial, err := net.Dial(cli.proto, cli.addr) + if err != nil { + return err + } + clientconn := httputil.NewClientConn(dial, nil) + resp, err := clientconn.Do(req) + defer clientconn.Close() if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?") @@ -1432,7 +1449,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi return err } req.Header.Set("Content-Type", "plain/text") - dial, err := net.Dial("tcp", fmt.Sprintf("%s:%d", cli.host, cli.port)) + dial, err := net.Dial(cli.proto, cli.addr) if err != nil { return err } @@ -1515,13 +1532,13 @@ func Subcmd(name, signature, description string) *flag.FlagSet { return flags } -func NewDockerCli(addr string, port int) *DockerCli { +func NewDockerCli(proto, addr string) *DockerCli { authConfig, _ := auth.LoadConfig(os.Getenv("HOME")) - return &DockerCli{addr, port, authConfig} + return &DockerCli{proto, addr, authConfig} } type DockerCli struct { - host string - port int + proto string + addr string authConfig *auth.AuthConfig } diff --git a/docker/docker.go b/docker/docker.go index 2e23999ad8..85c78c89da 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -24,15 +24,13 @@ func main() { docker.SysInit() return } - host := "127.0.0.1" - port := 4243 // FIXME: Switch d and D ? (to be more sshd like) flDaemon := flag.Bool("d", false, "Daemon mode") flDebug := flag.Bool("D", false, "Debug mode") flAutoRestart := flag.Bool("r", false, "Restart previously running containers") bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") - flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") + flHost := flag.String("H", fmt.Sprintf("%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT), "Host:port to bind/connect to") flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.") flDns := flag.String("dns", "", "Set custom dns servers") flag.Parse() @@ -42,21 +40,8 @@ func main() { docker.NetworkBridgeIface = docker.DefaultNetworkBridge } - if strings.Contains(*flHost, ":") { - hostParts := strings.Split(*flHost, ":") - if len(hostParts) != 2 { - log.Fatal("Invalid bind address format.") - os.Exit(-1) - } - if hostParts[0] != "" { - host = hostParts[0] - } - if p, err := strconv.Atoi(hostParts[1]); err == nil { - port = p - } - } else { - host = *flHost - } + protoAddr := parseHost(*flHost) + protoAddrs := []string{protoAddr} if *flDebug { os.Setenv("DEBUG", "1") @@ -67,12 +52,13 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors, *flDns); err != nil { + if err := daemon(*pidfile, protoAddrs, *flAutoRestart, *flEnableCors, *flDns); err != nil { log.Fatal(err) os.Exit(-1) } } else { - if err := docker.ParseCommands(host, port, flag.Args()...); err != nil { + protoAddrParts := strings.SplitN(protoAddrs[0], "://", 2) + if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil { log.Fatal(err) os.Exit(-1) } @@ -106,10 +92,7 @@ func removePidFile(pidfile string) { } } -func daemon(pidfile, addr string, port int, autoRestart, enableCors bool, flDns string) error { - if addr != "127.0.0.1" { - log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") - } +func daemon(pidfile string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error { if err := createPidFile(pidfile); err != nil { log.Fatal(err) } @@ -131,6 +114,55 @@ func daemon(pidfile, addr string, port int, autoRestart, enableCors bool, flDns if err != nil { return err } - - return docker.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), server, true) + chErrors := make(chan error, len(protoAddrs)) + for _, protoAddr := range protoAddrs { + protoAddrParts := strings.SplitN(protoAddr, "://", 2) + if protoAddrParts[0] == "unix" { + syscall.Unlink(protoAddrParts[1]); + } else if protoAddrParts[0] == "tcp" { + if !strings.HasPrefix(protoAddrParts[1], "127.0.0.1") { + log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") + } + } else { + log.Fatal("Invalid protocol format.") + os.Exit(-1) + } + go func() { + chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true) + }() + } + for i :=0 ; i < len(protoAddrs); i+=1 { + err := <-chErrors + if err != nil { + return err + } + } + return nil +} + +func parseHost(addr string) string { + if strings.HasPrefix(addr, "unix://") { + return addr + } + host := docker.DEFAULTHTTPHOST + port := docker.DEFAULTHTTPPORT + if strings.HasPrefix(addr, "tcp://") { + addr = strings.TrimPrefix(addr, "tcp://") + } + if strings.Contains(addr, ":") { + hostParts := strings.Split(addr, ":") + if len(hostParts) != 2 { + log.Fatal("Invalid bind address format.") + os.Exit(-1) + } + if hostParts[0] != "" { + host = hostParts[0] + } + if p, err := strconv.Atoi(hostParts[1]); err == nil { + port = p + } + } else { + host = addr + } + return fmt.Sprintf("tcp://%s:%d", host, port) } diff --git a/utils/utils.go b/utils/utils.go index b77c1ea053..da848c45bc 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -652,3 +652,5 @@ func CheckLocalDns() bool { } return false } + + From 6dccdd657f715c164f2fe6fc786c8274a2425f1b Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Tue, 18 Jun 2013 17:09:47 -0700 Subject: [PATCH 06/17] remove offline mode from auth unit tests --- auth/auth_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/auth/auth_test.go b/auth/auth_test.go index e49ec03721..ead69e8913 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -27,9 +27,6 @@ func TestEncodeAuth(t *testing.T) { } func TestLogin(t *testing.T) { - if os.Getenv("OFFLINE") != "" { - t.Skip("Offline mode, skipping.") - } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") authConfig := NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", "/tmp") @@ -43,9 +40,6 @@ func TestLogin(t *testing.T) { } func TestCreateAccount(t *testing.T) { - if os.Getenv("OFFLINE") != "" { - t.Skip("Offline mode, skipping.") - } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") tokenBuffer := make([]byte, 16) From dede1585ee00f957e153691c464aab293c2dc469 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 19 Jun 2013 12:31:54 +0000 Subject: [PATCH 07/17] add the possibility to use multiple -H --- commands.go | 2 +- docker/docker.go | 48 +++++++++++++++--------------------------------- utils/utils.go | 26 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/commands.go b/commands.go index 2c33485ecb..84af648f13 100644 --- a/commands.go +++ b/commands.go @@ -74,7 +74,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { return nil } } - help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=\"%s:%d\": Host:port to bind/connect to\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT) + help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socker to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT) for _, command := range [][2]string{ {"attach", "Attach to a running container"}, {"build", "Build a container from a Dockerfile"}, diff --git a/docker/docker.go b/docker/docker.go index 85c78c89da..6d79972bd6 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -30,19 +30,23 @@ func main() { flAutoRestart := flag.Bool("r", false, "Restart previously running containers") bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") - flHost := flag.String("H", fmt.Sprintf("%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT), "Host:port to bind/connect to") flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.") flDns := flag.String("dns", "", "Set custom dns servers") + flHosts := docker.ListOpts{fmt.Sprintf("tcp://%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT)} + flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use") flag.Parse() + if len(flHosts) > 1 { + flHosts = flHosts[1:len(flHosts)] //trick to display a nice defaul value in the usage + } + for i, flHost := range flHosts { + flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost) + } + if *bridgeName != "" { docker.NetworkBridgeIface = *bridgeName } else { docker.NetworkBridgeIface = docker.DefaultNetworkBridge } - - protoAddr := parseHost(*flHost) - protoAddrs := []string{protoAddr} - if *flDebug { os.Setenv("DEBUG", "1") } @@ -52,12 +56,16 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, protoAddrs, *flAutoRestart, *flEnableCors, *flDns); err != nil { + if err := daemon(*pidfile, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil { log.Fatal(err) os.Exit(-1) } } else { - protoAddrParts := strings.SplitN(protoAddrs[0], "://", 2) + if len(flHosts) > 1 { + log.Fatal("Please specify only one -H") + return + } + protoAddrParts := strings.SplitN(flHosts[0], "://", 2) if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil { log.Fatal(err) os.Exit(-1) @@ -140,29 +148,3 @@ func daemon(pidfile string, protoAddrs []string, autoRestart, enableCors bool, f return nil } -func parseHost(addr string) string { - if strings.HasPrefix(addr, "unix://") { - return addr - } - host := docker.DEFAULTHTTPHOST - port := docker.DEFAULTHTTPPORT - if strings.HasPrefix(addr, "tcp://") { - addr = strings.TrimPrefix(addr, "tcp://") - } - if strings.Contains(addr, ":") { - hostParts := strings.Split(addr, ":") - if len(hostParts) != 2 { - log.Fatal("Invalid bind address format.") - os.Exit(-1) - } - if hostParts[0] != "" { - host = hostParts[0] - } - if p, err := strconv.Atoi(hostParts[1]); err == nil { - port = p - } - } else { - host = addr - } - return fmt.Sprintf("tcp://%s:%d", host, port) -} diff --git a/utils/utils.go b/utils/utils.go index da848c45bc..37fda5c1c8 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -10,6 +10,7 @@ import ( "index/suffixarray" "io" "io/ioutil" + "log" "net/http" "os" "os/exec" @@ -653,4 +654,29 @@ func CheckLocalDns() bool { return false } +func ParseHost(host string, port int, addr string) string { + if strings.HasPrefix(addr, "unix://") { + return addr + } + if strings.HasPrefix(addr, "tcp://") { + addr = strings.TrimPrefix(addr, "tcp://") + } + if strings.Contains(addr, ":") { + hostParts := strings.Split(addr, ":") + if len(hostParts) != 2 { + log.Fatal("Invalid bind address format.") + os.Exit(-1) + } + if hostParts[0] != "" { + host = hostParts[0] + } + if p, err := strconv.Atoi(hostParts[1]); err == nil { + port = p + } + } else { + host = addr + } + return fmt.Sprintf("tcp://%s:%d", host, port) +} + From 9632bf228744dddfae2c303a0f2e8b962b6e0673 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 19 Jun 2013 12:40:01 +0000 Subject: [PATCH 08/17] add tests --- utils/utils_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/utils/utils_test.go b/utils/utils_test.go index eec06d5134..623f08e383 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -274,3 +274,21 @@ func TestHumanSize(t *testing.T) { t.Errorf("1024 -> expected 1.024 kB, got %s", size1024) } } + +func TestParseHost(t *testing.T) { + if addr := ParseHost("127.0.0.1", 4243, "0.0.0.0"); addr != "tcp://0.0.0.0:4243" { + t.Errorf("0.0.0.0 -> expected tcp://0.0.0.0:4243, got %s", addr) + } + if addr := ParseHost("127.0.0.1", 4243, "0.0.0.1:5555"); addr != "tcp://0.0.0.1:5555" { + t.Errorf("0.0.0.1:5555 -> expected tcp://0.0.0.1:5555, got %s", addr) + } + if addr := ParseHost("127.0.0.1", 4243, ":6666"); addr != "tcp://127.0.0.1:6666" { + t.Errorf(":6666 -> expected tcp://127.0.0.1:6666, got %s", addr) + } + if addr := ParseHost("127.0.0.1", 4243, "tcp://:7777"); addr != "tcp://127.0.0.1:7777" { + t.Errorf("tcp://:7777 -> expected tcp://127.0.0.1:7777, got %s", addr) + } + if addr := ParseHost("127.0.0.1", 4243, "unix:///var/run/docker.sock"); addr != "unix:///var/run/docker.sock" { + t.Errorf("unix:///var/run/docker.sock -> expected unix:///var/run/docker.sock, got %s", addr) + } +} From 063c838c927615e9507eca2a5c2f38a5fc4c35b2 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 19 Jun 2013 12:48:50 +0000 Subject: [PATCH 09/17] update docs --- docs/sources/api/docker_remote_api_v1.2.rst | 2 +- docs/sources/commandline/cli.rst | 2 +- docs/sources/use/basics.rst | 22 ++++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/sources/api/docker_remote_api_v1.2.rst b/docs/sources/api/docker_remote_api_v1.2.rst index fb69168120..a34ee01e0e 100644 --- a/docs/sources/api/docker_remote_api_v1.2.rst +++ b/docs/sources/api/docker_remote_api_v1.2.rst @@ -1026,5 +1026,5 @@ In this version of the API, /attach, uses hijacking to transport stdin, stdout a To enable cross origin requests to the remote api add the flag "-api-enable-cors" when running docker in daemon mode. - docker -d -H="192.168.1.9:4243" -api-enable-cors + docker -d -H="tcp://192.168.1.9:4243" -api-enable-cors diff --git a/docs/sources/commandline/cli.rst b/docs/sources/commandline/cli.rst index 02691b4f56..118f42f6e8 100644 --- a/docs/sources/commandline/cli.rst +++ b/docs/sources/commandline/cli.rst @@ -15,7 +15,7 @@ To list available commands, either run ``docker`` with no parameters or execute $ docker Usage: docker [OPTIONS] COMMAND [arg...] - -H="127.0.0.1:4243": Host:port to bind/connect to + -H=[tcp://127.0.0.1:4243]: tcp://host:port to bind/connect to or unix://path/to/socket to use A self-sufficient runtime for linux containers. diff --git a/docs/sources/use/basics.rst b/docs/sources/use/basics.rst index 444b74db51..0f64ec4cf8 100644 --- a/docs/sources/use/basics.rst +++ b/docs/sources/use/basics.rst @@ -33,11 +33,16 @@ Running an interactive shell # allocate a tty, attach stdin and stdout docker run -i -t base /bin/bash -Bind Docker to another host/port --------------------------------- +Bind Docker to another host/port or a unix socket +------------------------------------------------- If you want Docker to listen to another port and bind to another ip -use -host and -port on both deamon and client +use -H on both deamon and client. +-H could be (if no sheme, tcp is assumed): +* tcp://host -> tcp connection on host:4243 +* tcp://host:port -> tcp connection on host:port +* tcp://:port -> tcp connection on 127.0.0.1:port +* unix://path/to/socket -> unix socket located at path/to/socket .. code-block:: bash @@ -46,6 +51,17 @@ use -host and -port on both deamon and client # Download a base image docker -H :5555 pull base +You can use multiple -H, for exemple, if you want to listen +on both tcp and a unix socket + +.. code-block:: bash + + # Run docker in daemon mode + sudo /docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock + # Download a base image + docker pull base + # OR + docker -H unix:///var/run/docker.sock pull base Starting a long-running worker process -------------------------------------- From 5dcab2d361956e75d00d5bee18371395f17a663f Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 19 Jun 2013 14:50:58 +0000 Subject: [PATCH 10/17] gofmt and test sub directories in makefile --- Makefile | 2 +- auth/auth.go | 2 +- registry/registry.go | 2 +- term/termios_darwin.go | 20 ++++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 8676014ad4..ee85221175 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ else ifneq ($(DOCKER_DIR), $(realpath $(DOCKER_DIR))) endif test: all - @(cd $(DOCKER_DIR); sudo -E go test $(GO_OPTIONS)) + @(cd $(DOCKER_DIR); sudo -E go test ./... $(GO_OPTIONS)) fmt: @gofmt -s -l -w . diff --git a/auth/auth.go b/auth/auth.go index b7ad73b9ed..159c80f73a 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -82,7 +82,7 @@ func decodeAuth(authStr string) (*AuthConfig, error) { func LoadConfig(rootPath string) (*AuthConfig, error) { confFile := path.Join(rootPath, CONFIGFILE) if _, err := os.Stat(confFile); err != nil { - return &AuthConfig{rootPath:rootPath}, ErrConfigFileMissing + return &AuthConfig{rootPath: rootPath}, ErrConfigFileMissing } b, err := ioutil.ReadFile(confFile) if err != nil { diff --git a/registry/registry.go b/registry/registry.go index 131b02708e..23aef432c7 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -481,7 +481,7 @@ type Registry struct { func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry { httpTransport := &http.Transport{ DisableKeepAlives: true, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, } r := &Registry{ diff --git a/term/termios_darwin.go b/term/termios_darwin.go index ac18aab692..24e79de4b2 100644 --- a/term/termios_darwin.go +++ b/term/termios_darwin.go @@ -9,16 +9,16 @@ const ( getTermios = syscall.TIOCGETA setTermios = syscall.TIOCSETA - ECHO = 0x00000008 - ONLCR = 0x2 - ISTRIP = 0x20 - INLCR = 0x40 - ISIG = 0x80 - IGNCR = 0x80 - ICANON = 0x100 - ICRNL = 0x100 - IXOFF = 0x400 - IXON = 0x200 + ECHO = 0x00000008 + ONLCR = 0x2 + ISTRIP = 0x20 + INLCR = 0x40 + ISIG = 0x80 + IGNCR = 0x80 + ICANON = 0x100 + ICRNL = 0x100 + IXOFF = 0x400 + IXON = 0x200 ) type Termios struct { From 2d6a49215c15e7649f8b041e5a04e75b4d360c94 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 19 Jun 2013 18:21:46 +0000 Subject: [PATCH 11/17] add testall rule --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index ee85221175..44497d7d32 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,9 @@ else ifneq ($(DOCKER_DIR), $(realpath $(DOCKER_DIR))) endif test: all + @(cd $(DOCKER_DIR); sudo -E go test $(GO_OPTIONS)) + +testall: all @(cd $(DOCKER_DIR); sudo -E go test ./... $(GO_OPTIONS)) fmt: From 88279439af6b5196aaeb9bcb3d7a7154be04d4bc Mon Sep 17 00:00:00 2001 From: unclejack Date: Wed, 19 Jun 2013 22:07:56 +0300 Subject: [PATCH 12/17] batch apt-get install operations for speed The dockerbuilder Dockerfile was installing one package per apt-get install operation. This changes it so that consecutive run apt-get install operations are batched into a single operation. --- hack/dockerbuilder/Dockerfile | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hack/dockerbuilder/Dockerfile b/hack/dockerbuilder/Dockerfile index 5ccd293ca2..f377f0be76 100644 --- a/hack/dockerbuilder/Dockerfile +++ b/hack/dockerbuilder/Dockerfile @@ -19,19 +19,14 @@ run add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) run add-apt-repository -y ppa:dotcloud/docker-golang/ubuntu run apt-get update # Packages required to checkout, build and upload docker -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q s3cmd -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q curl +run DEBIAN_FRONTEND=noninteractive apt-get install -y -q s3cmd curl run curl -s -o /go.tar.gz https://go.googlecode.com/files/go1.1.1.linux-amd64.tar.gz run tar -C /usr/local -xzf /go.tar.gz run echo "export PATH=/usr/local/go/bin:$PATH" > /.bashrc run echo "export PATH=/usr/local/go/bin:$PATH" > /.bash_profile -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q build-essential +run DEBIAN_FRONTEND=noninteractive apt-get install -y -q git build-essential # Packages required to build an ubuntu package -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang-stable -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q debhelper -run DEBIAN_FRONTEND=noninteractive apt-get install -y -q autotools-dev -run apt-get install -y -q devscripts +run DEBIAN_FRONTEND=noninteractive apt-get install -y -q golang-stable debhelper autotools-dev devscripts # Copy dockerbuilder files into the container add . /src run cp /src/dockerbuilder /usr/local/bin/ && chmod +x /usr/local/bin/dockerbuilder From 0312bbc535de01cade67299dd41a69935c7241ba Mon Sep 17 00:00:00 2001 From: shin- Date: Wed, 19 Jun 2013 13:48:49 -0700 Subject: [PATCH 13/17] Use opaque requests when we need to preserve urlencoding in registry requests --- registry/registry.go | 19 ++++++++++++++----- server.go | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 276c9f8658..81b16d8d13 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -156,7 +156,7 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ } for _, host := range registries { endpoint := fmt.Sprintf("https://%s/v1/repositories/%s/tags", host, repository) - req, err := http.NewRequest("GET", endpoint, nil) + req, err := r.opaqueRequest("GET", endpoint, nil) if err != nil { return nil, err } @@ -190,7 +190,7 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) { repositoryTarget := auth.IndexServerAddress() + "/repositories/" + remote + "/images" - req, err := http.NewRequest("GET", repositoryTarget, nil) + req, err := r.opaqueRequest("GET", repositoryTarget, nil) if err != nil { return nil, err } @@ -309,6 +309,15 @@ func (r *Registry) PushImageLayerRegistry(imgId string, layer io.Reader, registr return nil } +func (r *Registry) opaqueRequest(method, urlStr string, body io.Reader) (*http.Request, error) { + req, err := http.NewRequest(method, urlStr, body) + if err != nil { + return nil, err + } + req.URL.Opaque = strings.Replace(urlStr, req.URL.Scheme + ":", "", 1) + return req, err +} + // push a tag on the registry. // Remote has the format '/ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token []string) error { @@ -316,7 +325,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token revision = "\"" + revision + "\"" registry = "https://" + registry + "/v1" - req, err := http.NewRequest("PUT", registry+"/repositories/"+remote+"/tags/"+tag, strings.NewReader(revision)) + req, err := r.opaqueRequest("PUT", registry+"/repositories/"+remote+"/tags/"+tag, strings.NewReader(revision)) if err != nil { return err } @@ -346,7 +355,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat utils.Debugf("Image list pushed to index:\n%s\n", imgListJSON) - req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON)) + req, err := r.opaqueRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON)) if err != nil { return nil, err } @@ -366,7 +375,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat // Redirect if necessary for res.StatusCode >= 300 && res.StatusCode < 400 { utils.Debugf("Redirected to %s\n", res.Header.Get("Location")) - req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJSON)) + req, err = r.opaqueRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJSON)) if err != nil { return nil, err } diff --git a/server.go b/server.go index 7375dddd90..df20c36b8a 100644 --- a/server.go +++ b/server.go @@ -532,7 +532,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri // FIXME: Continue on error? return err } - out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/users/"+srvName+"/"+elem.Tag)) + out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/repositories/"+srvName+"/tags/"+elem.Tag)) if err := r.PushRegistryTag(srvName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil { return err } From 05796bed57d4e1de352e02fcd6b28aed14f1b670 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 20 Jun 2013 12:31:48 +0000 Subject: [PATCH 14/17] update docs --- docs/sources/use/basics.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/sources/use/basics.rst b/docs/sources/use/basics.rst index 0f64ec4cf8..11d55a5bea 100644 --- a/docs/sources/use/basics.rst +++ b/docs/sources/use/basics.rst @@ -36,9 +36,13 @@ Running an interactive shell Bind Docker to another host/port or a unix socket ------------------------------------------------- -If you want Docker to listen to another port and bind to another ip -use -H on both deamon and client. --H could be (if no sheme, tcp is assumed): +With -H it is possible to make the Docker daemon to listen on a specific ip and port. By default, it will listen on 127.0.0.1:4243 to allow only local connections but you can set it to 0.0.0.0:4243 or a specific host ip to give access to everybody. + +Similarly, the Docker client can use -H to connect to a custom port. + +-H accepts host and port assignment in the following format: tcp://[host][:port] or unix://path +For example: + * tcp://host -> tcp connection on host:4243 * tcp://host:port -> tcp connection on host:port * tcp://:port -> tcp connection on 127.0.0.1:port @@ -51,7 +55,7 @@ use -H on both deamon and client. # Download a base image docker -H :5555 pull base -You can use multiple -H, for exemple, if you want to listen +You can use multiple -H, for example, if you want to listen on both tcp and a unix socket .. code-block:: bash From 1c841d4feed99ad568b7a5b04cedf8d65c3bb92c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 20 Jun 2013 15:45:30 +0000 Subject: [PATCH 15/17] add warning when you rm a running container --- server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server.go b/server.go index e9be3a1668..e51613e2cf 100644 --- a/server.go +++ b/server.go @@ -751,6 +751,9 @@ func (srv *Server) ContainerRestart(name string, t int) error { func (srv *Server) ContainerDestroy(name string, removeVolume bool) error { if container := srv.runtime.Get(name); container != nil { + if container.State.Running { + return fmt.Errorf("Impossible to remove a running container, please stop it first") + } volumes := make(map[string]struct{}) // Store all the deleted containers volumes for _, volumeId := range container.Volumes { From d8887f34888c1e6c1a846d54e3e8afc4791d88d0 Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Thu, 20 Jun 2013 08:57:28 -0700 Subject: [PATCH 16/17] Packaging|ubuntu, issue #960: Add docker PPA staging in release process --- packaging/ubuntu/Makefile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packaging/ubuntu/Makefile b/packaging/ubuntu/Makefile index f82892c813..582d5bcb25 100644 --- a/packaging/ubuntu/Makefile +++ b/packaging/ubuntu/Makefile @@ -2,11 +2,11 @@ # # Dependencies: debhelper autotools-dev devscripts golang-stable # Notes: -# Use 'make ubuntu' to create the ubuntu package -# GPG_KEY environment variable needs to contain a GPG private key for package to be signed -# and uploaded to docker PPA. -# If GPG_KEY is not defined, make ubuntu will create docker package and exit with -# status code 2 +# Use 'make ubuntu' to create the ubuntu package and push it to stating PPA by +# default. To push to production, set PUBLISH_PPA=1 before doing 'make ubuntu' +# GPG_KEY environment variable needs to contain a GPG private key for package +# to be signed and uploaded to docker PPA. If GPG_KEY is not defined, +# make ubuntu will create docker package and exit with status code 2 PKG_NAME=lxc-docker GITHUB_PATH=github.com/dotcloud/docker @@ -52,9 +52,11 @@ ubuntu: if /usr/bin/test "$${GPG_KEY}" == ""; then exit 2; fi mkdir ${BUILD_SRC} # Import gpg signing key - echo "$${GPG_KEY}" | gpg --allow-secret-key-import --import + echo "$${GPG_KEY}" | gpg --allow-secret-key-import --import || true # Sign the package cd ${BUILD_SRC}; dpkg-source -x ${BUILD_SRC}/../${PKG_NAME}_${VERSION}-1.dsc cd ${BUILD_SRC}/${PKG_NAME}-${VERSION}; debuild -S -sa - cd ${BUILD_SRC};dput ppa:dotcloud/lxc-docker ${PKG_NAME}_${VERSION}-1_source.changes + # Upload to PPA + if [ "${PUBLISH_PPA}" = "1" ]; then cd ${BUILD_SRC};dput ppa:dotcloud/lxc-docker ${PKG_NAME}_${VERSION}-1_source.changes; fi + if [ "${PUBLISH_PPA}" != "1" ]; then cd ${BUILD_SRC};dput ppa:dotcloud/docker-staging ${PKG_NAME}_${VERSION}-1_source.changes; fi rm -rf ${BUILD_SRC} From da5bb4db96b369365c4b913d9009d8bb1d0f51f4 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Wed, 19 Jun 2013 14:27:54 -0700 Subject: [PATCH 17/17] Bumped version to 0.4.3 --- CHANGELOG.md | 20 ++++++++++++++++++++ commands.go | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e2112218b..fa255e7c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.4.3 (2013-06-19) + + Builder: ADD of a local file will detect tar archives and unpack them + * Runtime: Remove bsdtar dependency + * Runtime: Add unix socket and multiple -H support + * Runtime: Prevent rm of running containers + * Runtime: Use go1.1 cookiejar + * Builder: ADD improvements: use tar for copy + automatically unpack local archives + * Builder: ADD uses tar/untar for copies instead of calling 'cp -ar' + * Builder: nicer output for 'docker build' + * Builder: fixed the behavior of ADD to be (mostly) reverse-compatible, predictable and well-documented. + * Client: HumanReadable ProgressBar sizes in pull + * Client: Fix docker version's git commit output + * API: Send all tags on History API call + * API: Add tag lookup to history command. Fixes #882 + - Runtime: Fix issue detaching from running TTY container + - Runtime: Forbid parralel push/pull for a single image/repo. Fixes #311 + - Runtime: Fix race condition within Run command when attaching. + - Builder: fix a bug which caused builds to fail if ADD was the first command + - Documentation: fix missing command in irc bouncer example + ## 0.4.2 (2013-06-17) - Packaging: Bumped version to work around an Ubuntu bug diff --git a/commands.go b/commands.go index cce2ec8557..6ff9ac4425 100644 --- a/commands.go +++ b/commands.go @@ -29,7 +29,7 @@ import ( "unicode" ) -const VERSION = "0.4.2" +const VERSION = "0.4.3" var ( GITCOMMIT string