Bläddra i källkod

Merge branch 'master' into tty_resize

Conflicts:
	commands.go
Guillaume J. Charmes 12 år sedan
förälder
incheckning
ffd9e06deb

+ 4 - 5
api.go

@@ -60,7 +60,7 @@ func getBoolParam(value string) (bool, error) {
 }
 
 func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	b, err := json.Marshal(srv.registry.GetAuthConfig())
+	b, err := json.Marshal(srv.registry.GetAuthConfig(false))
 	if err != nil {
 		return err
 	}
@@ -73,9 +73,9 @@ func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Reque
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
 		return err
 	}
-
-	if config.Username == srv.registry.GetAuthConfig().Username {
-		config.Password = srv.registry.GetAuthConfig().Password
+	authConfig := srv.registry.GetAuthConfig(true)
+	if config.Username == authConfig.Username {
+		config.Password = authConfig.Password
 	}
 
 	newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root)
@@ -686,6 +686,5 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
 			r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
 		}
 	}
-
 	return http.ListenAndServe(addr, r)
 }

+ 1 - 1
api_test.go

@@ -56,7 +56,7 @@ func TestGetAuth(t *testing.T) {
 		t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
 	}
 
-	newAuthConfig := srv.registry.GetAuthConfig()
+	newAuthConfig := srv.registry.GetAuthConfig(false)
 	if newAuthConfig.Username != authConfig.Username ||
 		newAuthConfig.Email != authConfig.Email {
 		t.Fatalf("The auth configuration hasn't been set correctly")

+ 70 - 40
commands.go

@@ -32,15 +32,19 @@ var (
 	GIT_COMMIT string
 )
 
-func ParseCommands(args ...string) error {
-	cli := NewDockerCli("0.0.0.0", 4243)
+func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
+	methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])
+	return reflect.TypeOf(cli).MethodByName(methodName)
+}
+
+func ParseCommands(addr string, port int, args ...string) error {
+	cli := NewDockerCli(addr, port)
 
 	if len(args) > 0 {
-		methodName := "Cmd" + strings.ToUpper(args[0][:1]) + strings.ToLower(args[0][1:])
-		method, exists := reflect.TypeOf(cli).MethodByName(methodName)
+		method, exists := cli.getMethod(args[0])
 		if !exists {
 			fmt.Println("Error: Command not found:", args[0])
-			return cli.CmdHelp(args...)
+			return cli.CmdHelp(args[1:]...)
 		}
 		ret := method.Func.CallSlice([]reflect.Value{
 			reflect.ValueOf(cli),
@@ -55,7 +59,19 @@ func ParseCommands(args ...string) error {
 }
 
 func (cli *DockerCli) CmdHelp(args ...string) error {
-	help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n"
+	if len(args) > 0 {
+		method, exists := cli.getMethod(args[0])
+		if !exists {
+			fmt.Println("Error: Command not found:", args[0])
+		} else {
+			method.Func.CallSlice([]reflect.Value{
+				reflect.ValueOf(cli),
+				reflect.ValueOf([]string{"--help"}),
+			})[0].Interface()
+			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.addr, cli.port)
 	for cmd, description := range map[string]string{
 		"attach":  "Attach to a running container",
 		"build":   "Build a container from Dockerfile or via stdin",
@@ -609,39 +625,13 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 		return nil
 	}
 
-	body, _, err := cli.call("GET", "/auth", nil)
-	if err != nil {
-		return err
-	}
-
-	var out auth.AuthConfig
-	err = json.Unmarshal(body, &out)
+	username, err := cli.checkIfLogged(*registry == "", "push")
 	if err != nil {
 		return err
 	}
 
-	// If the login failed AND we're using the index, abort
-	if *registry == "" && out.Username == "" {
-		if err := cli.CmdLogin(args...); err != nil {
-			return err
-		}
-
-		body, _, err = cli.call("GET", "/auth", nil)
-		if err != nil {
-			return err
-		}
-		err = json.Unmarshal(body, &out)
-		if err != nil {
-			return err
-		}
-
-		if out.Username == "" {
-			return fmt.Errorf("Please login prior to push. ('docker login')")
-		}
-	}
-
 	if len(strings.SplitN(name, "/", 2)) == 1 {
-		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", out.Username, name)
+		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
 	}
 
 	v := url.Values{}
@@ -672,6 +662,12 @@ func (cli *DockerCli) CmdPull(args ...string) error {
 		remote = remoteParts[0]
 	}
 
+	if strings.Contains(remote, "/") {
+		if _, err := cli.checkIfLogged(true, "pull"); err != nil {
+			return err
+		}
+	}
+
 	v := url.Values{}
 	v.Set("fromImage", remote)
 	v.Set("tag", *tag)
@@ -1161,6 +1157,40 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 	return nil
 }
 
+func (cli *DockerCli) checkIfLogged(condition bool, action string) (string, error) {
+	body, _, err := cli.call("GET", "/auth", nil)
+	if err != nil {
+		return "", err
+	}
+
+	var out auth.AuthConfig
+	err = json.Unmarshal(body, &out)
+	if err != nil {
+		return "", err
+	}
+
+	// If condition AND the login failed
+	if condition && out.Username == "" {
+		if err := cli.CmdLogin(""); err != nil {
+			return "", err
+		}
+
+		body, _, err = cli.call("GET", "/auth", nil)
+		if err != nil {
+			return "", err
+		}
+		err = json.Unmarshal(body, &out)
+		if err != nil {
+			return "", err
+		}
+
+		if out.Username == "" {
+			return "", fmt.Errorf("Please login prior to %s. ('docker login')", action)
+		}
+	}
+	return out.Username, nil
+}
+
 func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) {
 	var params io.Reader
 	if data != nil {
@@ -1171,7 +1201,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%f", cli.host, cli.port, API_VERSION)+path, params)
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.addr, cli.port, API_VERSION, path), params)
 	if err != nil {
 		return nil, -1, err
 	}
@@ -1203,7 +1233,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%f%s", cli.host, cli.port, API_VERSION, path), in)
+	req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.addr, cli.port, API_VERSION, path), in)
 	if err != nil {
 		return err
 	}
@@ -1234,12 +1264,12 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
 }
 
 func (cli *DockerCli) hijack(method, path string, setRawTerminal bool) error {
-	req, err := http.NewRequest(method, fmt.Sprintf("/v%f%s", API_VERSION, path), nil)
+	req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", API_VERSION, path), nil)
 	if err != nil {
 		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("tcp", fmt.Sprintf("%s:%d", cli.addr, cli.port))
 	if err != nil {
 		return err
 	}
@@ -1320,8 +1350,8 @@ func Subcmd(name, signature, description string) *flag.FlagSet {
 	return flags
 }
 
-func NewDockerCli(host string, port int) *DockerCli {
-	return &DockerCli{host, port}
+func NewDockerCli(addr string, port int) *DockerCli {
+	return &DockerCli{addr, port}
 }
 
 type DockerCli struct {

+ 28 - 4
docker/docker.go

@@ -10,6 +10,7 @@ import (
 	"os"
 	"os/signal"
 	"strconv"
+	"strings"
 	"syscall"
 )
 
@@ -23,18 +24,38 @@ 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")
 	flag.Parse()
 	if *bridgeName != "" {
 		docker.NetworkBridgeIface = *bridgeName
 	} else {
 		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
+	}
+
 	if *flDebug {
 		os.Setenv("DEBUG", "1")
 	}
@@ -44,12 +65,12 @@ func main() {
 			flag.Usage()
 			return
 		}
-		if err := daemon(*pidfile, *flAutoRestart); err != nil {
+		if err := daemon(*pidfile, host, port, *flAutoRestart); err != nil {
 			log.Fatal(err)
 			os.Exit(-1)
 		}
 	} else {
-		if err := docker.ParseCommands(flag.Args()...); err != nil {
+		if err := docker.ParseCommands(host, port, flag.Args()...); err != nil {
 			log.Fatal(err)
 			os.Exit(-1)
 		}
@@ -83,7 +104,10 @@ func removePidFile(pidfile string) {
 	}
 }
 
-func daemon(pidfile string, autoRestart bool) error {
+func daemon(pidfile, addr string, port int, autoRestart bool) 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 /!\\")
+	}
 	if err := createPidFile(pidfile); err != nil {
 		log.Fatal(err)
 	}
@@ -103,5 +127,5 @@ func daemon(pidfile string, autoRestart bool) error {
 		return err
 	}
 
-	return docker.ListenAndServe("0.0.0.0:4243", server, true)
+	return docker.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), server, true)
 }

+ 2 - 1
docs/sources/commandline/cli.rst

@@ -14,7 +14,8 @@ To list available commands, either run ``docker`` with no parameters or execute
 ``docker help``::
 
   $ docker
-    Usage: docker COMMAND [arg...]
+    Usage: docker [OPTIONS] COMMAND [arg...]
+      -H="127.0.0.1:4243": Host:port to bind/connect to
 
     A self-sufficient runtime for linux containers.
 

+ 1 - 1
docs/sources/installation/ubuntulinux.rst

@@ -38,7 +38,7 @@ Due to a bug in LXC docker works best on the 3.8 kernel. Precise comes with a 3.
 .. code-block:: bash
 
    # install the backported kernel
-   sudo apt-get update && sudo apt-get install linux-image-3.8.0-19-generic
+   sudo apt-get update && sudo apt-get install linux-image-generic-lts-raring
 
    # reboot
    sudo reboot

+ 13 - 0
docs/sources/use/basics.rst

@@ -33,6 +33,19 @@ Running an interactive shell
   # allocate a tty, attach stdin and stdout
   docker run -i -t base /bin/bash
 
+Bind Docker to another host/port
+--------------------------------
+
+If you want Docker to listen to another port and bind to another ip
+use -host and -port on both deamon and client
+
+.. code-block:: bash
+
+   # Run docker in daemon mode
+   sudo <path to>/docker -H 0.0.0.0:5555 &
+   # Download a base image
+   docker -H :5555 pull base
+
 
 Starting a long-running worker process
 --------------------------------------

+ 6 - 1
registry/registry.go

@@ -428,9 +428,14 @@ func (r *Registry) ResetClient(authConfig *auth.AuthConfig) {
 	r.client.Jar = cookiejar.NewCookieJar()
 }
 
-func (r *Registry) GetAuthConfig() *auth.AuthConfig {
+func (r *Registry) GetAuthConfig(withPasswd bool) *auth.AuthConfig {
+	password := ""
+	if withPasswd {
+		password = r.authConfig.Password
+	}
 	return &auth.AuthConfig{
 		Username: r.authConfig.Username,
+		Password: password,
 		Email:    r.authConfig.Email,
 	}
 }