* Runtime: Add unix socket and multiple -H
Guillaume J. Charmes authored on 2013/06/21 03:17:16... | ... |
@@ -8,12 +8,16 @@ import ( |
8 | 8 |
"github.com/gorilla/mux" |
9 | 9 |
"io" |
10 | 10 |
"log" |
11 |
+ "net" |
|
11 | 12 |
"net/http" |
13 |
+ "os" |
|
12 | 14 |
"strconv" |
13 | 15 |
"strings" |
14 | 16 |
) |
15 | 17 |
|
16 | 18 |
const APIVERSION = 1.2 |
19 |
+const DEFAULTHTTPHOST string = "127.0.0.1" |
|
20 |
+const DEFAULTHTTPPORT int = 4243 |
|
17 | 21 |
|
18 | 22 |
func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { |
19 | 23 |
conn, _, err := w.(http.Hijacker).Hijack() |
... | ... |
@@ -848,12 +852,21 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) { |
848 | 848 |
return r, nil |
849 | 849 |
} |
850 | 850 |
|
851 |
-func ListenAndServe(addr string, srv *Server, logging bool) error { |
|
852 |
- log.Printf("Listening for HTTP on %s\n", addr) |
|
851 |
+func ListenAndServe(proto, addr string, srv *Server, logging bool) error { |
|
852 |
+ log.Printf("Listening for HTTP on %s (%s)\n", addr, proto) |
|
853 | 853 |
|
854 | 854 |
r, err := createRouter(srv, logging) |
855 | 855 |
if err != nil { |
856 | 856 |
return err |
857 | 857 |
} |
858 |
- return http.ListenAndServe(addr, r) |
|
858 |
+ l, e := net.Listen(proto, addr) |
|
859 |
+ if e != nil { |
|
860 |
+ return e |
|
861 |
+ } |
|
862 |
+ //as the daemon is launched as root, change to permission of the socket to allow non-root to connect |
|
863 |
+ if proto == "unix" { |
|
864 |
+ os.Chmod(addr, 0777) |
|
865 |
+ } |
|
866 |
+ httpSrv := http.Server{Addr: addr, Handler: r} |
|
867 |
+ return httpSrv.Serve(l) |
|
859 | 868 |
} |
... | ... |
@@ -304,9 +304,9 @@ func (b *builderClient) Build(dockerfile, context io.Reader) (string, error) { |
304 | 304 |
return "", fmt.Errorf("An error occured during the build\n") |
305 | 305 |
} |
306 | 306 |
|
307 |
-func NewBuilderClient(addr string, port int) BuildFile { |
|
307 |
+func NewBuilderClient(proto, addr string) BuildFile { |
|
308 | 308 |
return &builderClient{ |
309 |
- cli: NewDockerCli(addr, port), |
|
309 |
+ cli: NewDockerCli(proto, addr), |
|
310 | 310 |
config: &Config{}, |
311 | 311 |
tmpContainers: make(map[string]struct{}), |
312 | 312 |
tmpImages: make(map[string]struct{}), |
... | ... |
@@ -40,8 +40,8 @@ func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) { |
40 | 40 |
return reflect.TypeOf(cli).MethodByName(methodName) |
41 | 41 |
} |
42 | 42 |
|
43 |
-func ParseCommands(addr string, port int, args ...string) error { |
|
44 |
- cli := NewDockerCli(addr, port) |
|
43 |
+func ParseCommands(proto, addr string, args ...string) error { |
|
44 |
+ cli := NewDockerCli(proto, addr) |
|
45 | 45 |
|
46 | 46 |
if len(args) > 0 { |
47 | 47 |
method, exists := cli.getMethod(args[0]) |
... | ... |
@@ -74,7 +74,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { |
74 | 74 |
return nil |
75 | 75 |
} |
76 | 76 |
} |
77 |
- 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) |
|
77 |
+ 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) |
|
78 | 78 |
for _, command := range [][2]string{ |
79 | 79 |
{"attach", "Attach to a running container"}, |
80 | 80 |
{"build", "Build a container from a Dockerfile"}, |
... | ... |
@@ -197,7 +197,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { |
197 | 197 |
v := &url.Values{} |
198 | 198 |
v.Set("t", *tag) |
199 | 199 |
// Send the multipart request with correct content-type |
200 |
- req, err := http.NewRequest("POST", fmt.Sprintf("http://%s:%d%s?%s", cli.host, cli.port, "/build", v.Encode()), multipartBody) |
|
200 |
+ req, err := http.NewRequest("POST", fmt.Sprintf("/v%s/build?%s", APIVERSION, v.Encode()), multipartBody) |
|
201 | 201 |
if err != nil { |
202 | 202 |
return err |
203 | 203 |
} |
... | ... |
@@ -206,8 +206,13 @@ func (cli *DockerCli) CmdBuild(args ...string) error { |
206 | 206 |
req.Header.Set("X-Docker-Context-Compression", compression.Flag()) |
207 | 207 |
fmt.Println("Uploading Context...") |
208 | 208 |
} |
209 |
- |
|
210 |
- resp, err := http.DefaultClient.Do(req) |
|
209 |
+ dial, err := net.Dial(cli.proto, cli.addr) |
|
210 |
+ if err != nil { |
|
211 |
+ return err |
|
212 |
+ } |
|
213 |
+ clientconn := httputil.NewClientConn(dial, nil) |
|
214 |
+ resp, err := clientconn.Do(req) |
|
215 |
+ defer clientconn.Close() |
|
211 | 216 |
if err != nil { |
212 | 217 |
return err |
213 | 218 |
} |
... | ... |
@@ -1302,7 +1307,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, |
1302 | 1302 |
params = bytes.NewBuffer(buf) |
1303 | 1303 |
} |
1304 | 1304 |
|
1305 |
- req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), params) |
|
1305 |
+ req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), params) |
|
1306 | 1306 |
if err != nil { |
1307 | 1307 |
return nil, -1, err |
1308 | 1308 |
} |
... | ... |
@@ -1312,7 +1317,13 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, |
1312 | 1312 |
} else if method == "POST" { |
1313 | 1313 |
req.Header.Set("Content-Type", "plain/text") |
1314 | 1314 |
} |
1315 |
- resp, err := http.DefaultClient.Do(req) |
|
1315 |
+ dial, err := net.Dial(cli.proto, cli.addr) |
|
1316 |
+ if err != nil { |
|
1317 |
+ return nil, -1, err |
|
1318 |
+ } |
|
1319 |
+ clientconn := httputil.NewClientConn(dial, nil) |
|
1320 |
+ resp, err := clientconn.Do(req) |
|
1321 |
+ defer clientconn.Close() |
|
1316 | 1322 |
if err != nil { |
1317 | 1323 |
if strings.Contains(err.Error(), "connection refused") { |
1318 | 1324 |
return nil, -1, fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?") |
... | ... |
@@ -1337,7 +1348,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e |
1337 | 1337 |
if (method == "POST" || method == "PUT") && in == nil { |
1338 | 1338 |
in = bytes.NewReader([]byte{}) |
1339 | 1339 |
} |
1340 |
- req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, APIVERSION, path), in) |
|
1340 |
+ req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), in) |
|
1341 | 1341 |
if err != nil { |
1342 | 1342 |
return err |
1343 | 1343 |
} |
... | ... |
@@ -1345,7 +1356,13 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e |
1345 | 1345 |
if method == "POST" { |
1346 | 1346 |
req.Header.Set("Content-Type", "plain/text") |
1347 | 1347 |
} |
1348 |
- resp, err := http.DefaultClient.Do(req) |
|
1348 |
+ dial, err := net.Dial(cli.proto, cli.addr) |
|
1349 |
+ if err != nil { |
|
1350 |
+ return err |
|
1351 |
+ } |
|
1352 |
+ clientconn := httputil.NewClientConn(dial, nil) |
|
1353 |
+ resp, err := clientconn.Do(req) |
|
1354 |
+ defer clientconn.Close() |
|
1349 | 1355 |
if err != nil { |
1350 | 1356 |
if strings.Contains(err.Error(), "connection refused") { |
1351 | 1357 |
return fmt.Errorf("Can't connect to docker daemon. Is 'docker -d' running on this host?") |
... | ... |
@@ -1395,7 +1412,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in *os.Fi |
1395 | 1395 |
return err |
1396 | 1396 |
} |
1397 | 1397 |
req.Header.Set("Content-Type", "plain/text") |
1398 |
- dial, err := net.Dial("tcp", fmt.Sprintf("%s:%d", cli.host, cli.port)) |
|
1398 |
+ dial, err := net.Dial(cli.proto, cli.addr) |
|
1399 | 1399 |
if err != nil { |
1400 | 1400 |
return err |
1401 | 1401 |
} |
... | ... |
@@ -1478,13 +1495,13 @@ func Subcmd(name, signature, description string) *flag.FlagSet { |
1478 | 1478 |
return flags |
1479 | 1479 |
} |
1480 | 1480 |
|
1481 |
-func NewDockerCli(addr string, port int) *DockerCli { |
|
1481 |
+func NewDockerCli(proto, addr string) *DockerCli { |
|
1482 | 1482 |
authConfig, _ := auth.LoadConfig(os.Getenv("HOME")) |
1483 |
- return &DockerCli{addr, port, authConfig} |
|
1483 |
+ return &DockerCli{proto, addr, authConfig} |
|
1484 | 1484 |
} |
1485 | 1485 |
|
1486 | 1486 |
type DockerCli struct { |
1487 |
- host string |
|
1488 |
- port int |
|
1487 |
+ proto string |
|
1488 |
+ addr string |
|
1489 | 1489 |
authConfig *auth.AuthConfig |
1490 | 1490 |
} |
... | ... |
@@ -24,40 +24,29 @@ func main() { |
24 | 24 |
docker.SysInit() |
25 | 25 |
return |
26 | 26 |
} |
27 |
- host := "127.0.0.1" |
|
28 |
- port := 4243 |
|
29 | 27 |
// FIXME: Switch d and D ? (to be more sshd like) |
30 | 28 |
flDaemon := flag.Bool("d", false, "Daemon mode") |
31 | 29 |
flDebug := flag.Bool("D", false, "Debug mode") |
32 | 30 |
flAutoRestart := flag.Bool("r", false, "Restart previously running containers") |
33 | 31 |
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") |
34 | 32 |
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") |
35 |
- flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") |
|
36 | 33 |
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.") |
37 | 34 |
flDns := flag.String("dns", "", "Set custom dns servers") |
35 |
+ flHosts := docker.ListOpts{fmt.Sprintf("tcp://%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT)} |
|
36 |
+ flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use") |
|
38 | 37 |
flag.Parse() |
38 |
+ if len(flHosts) > 1 { |
|
39 |
+ flHosts = flHosts[1:len(flHosts)] //trick to display a nice defaul value in the usage |
|
40 |
+ } |
|
41 |
+ for i, flHost := range flHosts { |
|
42 |
+ flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost) |
|
43 |
+ } |
|
44 |
+ |
|
39 | 45 |
if *bridgeName != "" { |
40 | 46 |
docker.NetworkBridgeIface = *bridgeName |
41 | 47 |
} else { |
42 | 48 |
docker.NetworkBridgeIface = docker.DefaultNetworkBridge |
43 | 49 |
} |
44 |
- |
|
45 |
- if strings.Contains(*flHost, ":") { |
|
46 |
- hostParts := strings.Split(*flHost, ":") |
|
47 |
- if len(hostParts) != 2 { |
|
48 |
- log.Fatal("Invalid bind address format.") |
|
49 |
- os.Exit(-1) |
|
50 |
- } |
|
51 |
- if hostParts[0] != "" { |
|
52 |
- host = hostParts[0] |
|
53 |
- } |
|
54 |
- if p, err := strconv.Atoi(hostParts[1]); err == nil { |
|
55 |
- port = p |
|
56 |
- } |
|
57 |
- } else { |
|
58 |
- host = *flHost |
|
59 |
- } |
|
60 |
- |
|
61 | 50 |
if *flDebug { |
62 | 51 |
os.Setenv("DEBUG", "1") |
63 | 52 |
} |
... | ... |
@@ -67,12 +56,17 @@ func main() { |
67 | 67 |
flag.Usage() |
68 | 68 |
return |
69 | 69 |
} |
70 |
- if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors, *flDns); err != nil { |
|
70 |
+ if err := daemon(*pidfile, flHosts, *flAutoRestart, *flEnableCors, *flDns); err != nil { |
|
71 | 71 |
log.Fatal(err) |
72 | 72 |
os.Exit(-1) |
73 | 73 |
} |
74 | 74 |
} else { |
75 |
- if err := docker.ParseCommands(host, port, flag.Args()...); err != nil { |
|
75 |
+ if len(flHosts) > 1 { |
|
76 |
+ log.Fatal("Please specify only one -H") |
|
77 |
+ return |
|
78 |
+ } |
|
79 |
+ protoAddrParts := strings.SplitN(flHosts[0], "://", 2) |
|
80 |
+ if err := docker.ParseCommands(protoAddrParts[0], protoAddrParts[1], flag.Args()...); err != nil { |
|
76 | 81 |
log.Fatal(err) |
77 | 82 |
os.Exit(-1) |
78 | 83 |
} |
... | ... |
@@ -106,10 +100,7 @@ func removePidFile(pidfile string) { |
106 | 106 |
} |
107 | 107 |
} |
108 | 108 |
|
109 |
-func daemon(pidfile, addr string, port int, autoRestart, enableCors bool, flDns string) error { |
|
110 |
- if addr != "127.0.0.1" { |
|
111 |
- log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") |
|
112 |
- } |
|
109 |
+func daemon(pidfile string, protoAddrs []string, autoRestart, enableCors bool, flDns string) error { |
|
113 | 110 |
if err := createPidFile(pidfile); err != nil { |
114 | 111 |
log.Fatal(err) |
115 | 112 |
} |
... | ... |
@@ -131,6 +122,29 @@ func daemon(pidfile, addr string, port int, autoRestart, enableCors bool, flDns |
131 | 131 |
if err != nil { |
132 | 132 |
return err |
133 | 133 |
} |
134 |
- |
|
135 |
- return docker.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), server, true) |
|
134 |
+ chErrors := make(chan error, len(protoAddrs)) |
|
135 |
+ for _, protoAddr := range protoAddrs { |
|
136 |
+ protoAddrParts := strings.SplitN(protoAddr, "://", 2) |
|
137 |
+ if protoAddrParts[0] == "unix" { |
|
138 |
+ syscall.Unlink(protoAddrParts[1]); |
|
139 |
+ } else if protoAddrParts[0] == "tcp" { |
|
140 |
+ if !strings.HasPrefix(protoAddrParts[1], "127.0.0.1") { |
|
141 |
+ log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") |
|
142 |
+ } |
|
143 |
+ } else { |
|
144 |
+ log.Fatal("Invalid protocol format.") |
|
145 |
+ os.Exit(-1) |
|
146 |
+ } |
|
147 |
+ go func() { |
|
148 |
+ chErrors <- docker.ListenAndServe(protoAddrParts[0], protoAddrParts[1], server, true) |
|
149 |
+ }() |
|
150 |
+ } |
|
151 |
+ for i :=0 ; i < len(protoAddrs); i+=1 { |
|
152 |
+ err := <-chErrors |
|
153 |
+ if err != nil { |
|
154 |
+ return err |
|
155 |
+ } |
|
156 |
+ } |
|
157 |
+ return nil |
|
136 | 158 |
} |
159 |
+ |
... | ... |
@@ -1027,5 +1027,5 @@ In this version of the API, /attach, uses hijacking to transport stdin, stdout a |
1027 | 1027 |
|
1028 | 1028 |
To enable cross origin requests to the remote api add the flag "-api-enable-cors" when running docker in daemon mode. |
1029 | 1029 |
|
1030 |
- docker -d -H="192.168.1.9:4243" -api-enable-cors |
|
1030 |
+ docker -d -H="tcp://192.168.1.9:4243" -api-enable-cors |
|
1031 | 1031 |
|
... | ... |
@@ -15,7 +15,7 @@ To list available commands, either run ``docker`` with no parameters or execute |
15 | 15 |
|
16 | 16 |
$ docker |
17 | 17 |
Usage: docker [OPTIONS] COMMAND [arg...] |
18 |
- -H="127.0.0.1:4243": Host:port to bind/connect to |
|
18 |
+ -H=[tcp://127.0.0.1:4243]: tcp://host:port to bind/connect to or unix://path/to/socket to use |
|
19 | 19 |
|
20 | 20 |
A self-sufficient runtime for linux containers. |
21 | 21 |
|
... | ... |
@@ -33,11 +33,20 @@ Running an interactive shell |
33 | 33 |
# allocate a tty, attach stdin and stdout |
34 | 34 |
docker run -i -t base /bin/bash |
35 | 35 |
|
36 |
-Bind Docker to another host/port |
|
36 |
+Bind Docker to another host/port or a unix socket |
|
37 |
+------------------------------------------------- |
|
37 | 38 |
|
38 |
-If you want Docker to listen to another port and bind to another ip |
|
39 |
-use -host and -port on both deamon and client |
|
39 |
+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. |
|
40 |
+ |
|
41 |
+Similarly, the Docker client can use -H to connect to a custom port. |
|
42 |
+ |
|
43 |
+-H accepts host and port assignment in the following format: tcp://[host][:port] or unix://path |
|
44 |
+For example: |
|
45 |
+ |
|
46 |
+* tcp://host -> tcp connection on host:4243 |
|
47 |
+* tcp://host:port -> tcp connection on host:port |
|
48 |
+* tcp://:port -> tcp connection on 127.0.0.1:port |
|
49 |
+* unix://path/to/socket -> unix socket located at path/to/socket |
|
40 | 50 |
|
41 | 51 |
.. code-block:: bash |
42 | 52 |
|
... | ... |
@@ -46,6 +55,17 @@ use -host and -port on both deamon and client |
46 | 46 |
# Download a base image |
47 | 47 |
docker -H :5555 pull base |
48 | 48 |
|
49 |
+You can use multiple -H, for example, if you want to listen |
|
50 |
+on both tcp and a unix socket |
|
51 |
+ |
|
52 |
+.. code-block:: bash |
|
53 |
+ |
|
54 |
+ # Run docker in daemon mode |
|
55 |
+ sudo <path to>/docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock |
|
56 |
+ # Download a base image |
|
57 |
+ docker pull base |
|
58 |
+ # OR |
|
59 |
+ docker -H unix:///var/run/docker.sock pull base |
|
49 | 60 |
|
50 | 61 |
Starting a long-running worker process |
51 | 62 |
-------------------------------------- |
... | ... |
@@ -10,6 +10,7 @@ import ( |
10 | 10 |
"index/suffixarray" |
11 | 11 |
"io" |
12 | 12 |
"io/ioutil" |
13 |
+ "log" |
|
13 | 14 |
"net/http" |
14 | 15 |
"os" |
15 | 16 |
"os/exec" |
... | ... |
@@ -652,3 +653,30 @@ func CheckLocalDns() bool { |
652 | 652 |
} |
653 | 653 |
return false |
654 | 654 |
} |
655 |
+ |
|
656 |
+func ParseHost(host string, port int, addr string) string { |
|
657 |
+ if strings.HasPrefix(addr, "unix://") { |
|
658 |
+ return addr |
|
659 |
+ } |
|
660 |
+ if strings.HasPrefix(addr, "tcp://") { |
|
661 |
+ addr = strings.TrimPrefix(addr, "tcp://") |
|
662 |
+ } |
|
663 |
+ if strings.Contains(addr, ":") { |
|
664 |
+ hostParts := strings.Split(addr, ":") |
|
665 |
+ if len(hostParts) != 2 { |
|
666 |
+ log.Fatal("Invalid bind address format.") |
|
667 |
+ os.Exit(-1) |
|
668 |
+ } |
|
669 |
+ if hostParts[0] != "" { |
|
670 |
+ host = hostParts[0] |
|
671 |
+ } |
|
672 |
+ if p, err := strconv.Atoi(hostParts[1]); err == nil { |
|
673 |
+ port = p |
|
674 |
+ } |
|
675 |
+ } else { |
|
676 |
+ host = addr |
|
677 |
+ } |
|
678 |
+ return fmt.Sprintf("tcp://%s:%d", host, port) |
|
679 |
+} |
|
680 |
+ |
|
681 |
+ |
... | ... |
@@ -274,3 +274,21 @@ func TestHumanSize(t *testing.T) { |
274 | 274 |
t.Errorf("1024 -> expected 1.024 kB, got %s", size1024) |
275 | 275 |
} |
276 | 276 |
} |
277 |
+ |
|
278 |
+func TestParseHost(t *testing.T) { |
|
279 |
+ if addr := ParseHost("127.0.0.1", 4243, "0.0.0.0"); addr != "tcp://0.0.0.0:4243" { |
|
280 |
+ t.Errorf("0.0.0.0 -> expected tcp://0.0.0.0:4243, got %s", addr) |
|
281 |
+ } |
|
282 |
+ if addr := ParseHost("127.0.0.1", 4243, "0.0.0.1:5555"); addr != "tcp://0.0.0.1:5555" { |
|
283 |
+ t.Errorf("0.0.0.1:5555 -> expected tcp://0.0.0.1:5555, got %s", addr) |
|
284 |
+ } |
|
285 |
+ if addr := ParseHost("127.0.0.1", 4243, ":6666"); addr != "tcp://127.0.0.1:6666" { |
|
286 |
+ t.Errorf(":6666 -> expected tcp://127.0.0.1:6666, got %s", addr) |
|
287 |
+ } |
|
288 |
+ if addr := ParseHost("127.0.0.1", 4243, "tcp://:7777"); addr != "tcp://127.0.0.1:7777" { |
|
289 |
+ t.Errorf("tcp://:7777 -> expected tcp://127.0.0.1:7777, got %s", addr) |
|
290 |
+ } |
|
291 |
+ if addr := ParseHost("127.0.0.1", 4243, "unix:///var/run/docker.sock"); addr != "unix:///var/run/docker.sock" { |
|
292 |
+ t.Errorf("unix:///var/run/docker.sock -> expected unix:///var/run/docker.sock, got %s", addr) |
|
293 |
+ } |
|
294 |
+} |