This function was only being used from a single place opts/opts.go. This
change moves it from a incohesive package (parsers) to the single place it
is used.
Also made a bunch of the helper methods private because they are not used
by any external modules.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,146 @@ |
| 0 |
+package opts |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "net" |
|
| 5 |
+ "net/url" |
|
| 6 |
+ "runtime" |
|
| 7 |
+ "strconv" |
|
| 8 |
+ "strings" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+var ( |
|
| 12 |
+ // DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp:// |
|
| 13 |
+ // TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter |
|
| 14 |
+ // is not supplied. A better longer term solution would be to use a named |
|
| 15 |
+ // pipe as the default on the Windows daemon. |
|
| 16 |
+ // These are the IANA registered port numbers for use with Docker |
|
| 17 |
+ // see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker |
|
| 18 |
+ DefaultHTTPPort = 2375 // Default HTTP Port |
|
| 19 |
+ // DefaultTLSHTTPPort Default HTTP Port used when TLS enabled |
|
| 20 |
+ DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port |
|
| 21 |
+ // DefaultUnixSocket Path for the unix socket. |
|
| 22 |
+ // Docker daemon by default always listens on the default unix socket |
|
| 23 |
+ DefaultUnixSocket = "/var/run/docker.sock" |
|
| 24 |
+ // DefaultTCPHost constant defines the default host string used by docker on Windows |
|
| 25 |
+ DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
|
|
| 26 |
+ // DefaultTLSHost constant defines the default host string used by docker for TLS sockets |
|
| 27 |
+ DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
|
|
| 28 |
+) |
|
| 29 |
+ |
|
| 30 |
+// ValidateHost validates that the specified string is a valid host and returns it. |
|
| 31 |
+func ValidateHost(val string) (string, error) {
|
|
| 32 |
+ _, err := parseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val) |
|
| 33 |
+ if err != nil {
|
|
| 34 |
+ return val, err |
|
| 35 |
+ } |
|
| 36 |
+ // Note: unlike most flag validators, we don't return the mutated value here |
|
| 37 |
+ // we need to know what the user entered later (using ParseHost) to adjust for tls |
|
| 38 |
+ return val, nil |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+// ParseHost and set defaults for a Daemon host string |
|
| 42 |
+func ParseHost(defaultHost, val string) (string, error) {
|
|
| 43 |
+ host, err := parseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val) |
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ return val, err |
|
| 46 |
+ } |
|
| 47 |
+ return host, nil |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// parseDockerDaemonHost parses the specified address and returns an address that will be used as the host. |
|
| 51 |
+// Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr |
|
| 52 |
+// defaultUnixAddr must be a absolute file path (no `unix://` prefix) |
|
| 53 |
+// defaultTCPAddr must be the full `tcp://host:port` form |
|
| 54 |
+func parseDockerDaemonHost(defaultTCPAddr, defaultTLSHost, defaultUnixAddr, defaultAddr, addr string) (string, error) {
|
|
| 55 |
+ addr = strings.TrimSpace(addr) |
|
| 56 |
+ if addr == "" {
|
|
| 57 |
+ if defaultAddr == defaultTLSHost {
|
|
| 58 |
+ return defaultTLSHost, nil |
|
| 59 |
+ } |
|
| 60 |
+ if runtime.GOOS != "windows" {
|
|
| 61 |
+ return fmt.Sprintf("unix://%s", defaultUnixAddr), nil
|
|
| 62 |
+ } |
|
| 63 |
+ return defaultTCPAddr, nil |
|
| 64 |
+ } |
|
| 65 |
+ addrParts := strings.Split(addr, "://") |
|
| 66 |
+ if len(addrParts) == 1 {
|
|
| 67 |
+ addrParts = []string{"tcp", addrParts[0]}
|
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ switch addrParts[0] {
|
|
| 71 |
+ case "tcp": |
|
| 72 |
+ return parseTCPAddr(addrParts[1], defaultTCPAddr) |
|
| 73 |
+ case "unix": |
|
| 74 |
+ return parseUnixAddr(addrParts[1], defaultUnixAddr) |
|
| 75 |
+ case "fd": |
|
| 76 |
+ return addr, nil |
|
| 77 |
+ default: |
|
| 78 |
+ return "", fmt.Errorf("Invalid bind address format: %s", addr)
|
|
| 79 |
+ } |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+// parseUnixAddr parses and validates that the specified address is a valid UNIX |
|
| 83 |
+// socket address. It returns a formatted UNIX socket address, either using the |
|
| 84 |
+// address parsed from addr, or the contents of defaultAddr if addr is a blank |
|
| 85 |
+// string. |
|
| 86 |
+func parseUnixAddr(addr string, defaultAddr string) (string, error) {
|
|
| 87 |
+ addr = strings.TrimPrefix(addr, "unix://") |
|
| 88 |
+ if strings.Contains(addr, "://") {
|
|
| 89 |
+ return "", fmt.Errorf("Invalid proto, expected unix: %s", addr)
|
|
| 90 |
+ } |
|
| 91 |
+ if addr == "" {
|
|
| 92 |
+ addr = defaultAddr |
|
| 93 |
+ } |
|
| 94 |
+ return fmt.Sprintf("unix://%s", addr), nil
|
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+// parseTCPAddr parses and validates that the specified address is a valid TCP |
|
| 98 |
+// address. It returns a formatted TCP address, either using the address parsed |
|
| 99 |
+// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string. |
|
| 100 |
+// tryAddr is expected to have already been Trim()'d |
|
| 101 |
+// defaultAddr must be in the full `tcp://host:port` form |
|
| 102 |
+func parseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
|
|
| 103 |
+ if tryAddr == "" || tryAddr == "tcp://" {
|
|
| 104 |
+ return defaultAddr, nil |
|
| 105 |
+ } |
|
| 106 |
+ addr := strings.TrimPrefix(tryAddr, "tcp://") |
|
| 107 |
+ if strings.Contains(addr, "://") || addr == "" {
|
|
| 108 |
+ return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
|
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://") |
|
| 112 |
+ defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr) |
|
| 113 |
+ if err != nil {
|
|
| 114 |
+ return "", err |
|
| 115 |
+ } |
|
| 116 |
+ // url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but |
|
| 117 |
+ // not 1.4. See https://github.com/golang/go/issues/12200 and |
|
| 118 |
+ // https://github.com/golang/go/issues/6530. |
|
| 119 |
+ if strings.HasSuffix(addr, "]:") {
|
|
| 120 |
+ addr += defaultPort |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ u, err := url.Parse("tcp://" + addr)
|
|
| 124 |
+ if err != nil {
|
|
| 125 |
+ return "", err |
|
| 126 |
+ } |
|
| 127 |
+ |
|
| 128 |
+ host, port, err := net.SplitHostPort(u.Host) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 133 |
+ if host == "" {
|
|
| 134 |
+ host = defaultHost |
|
| 135 |
+ } |
|
| 136 |
+ if port == "" {
|
|
| 137 |
+ port = defaultPort |
|
| 138 |
+ } |
|
| 139 |
+ p, err := strconv.Atoi(port) |
|
| 140 |
+ if err != nil && p == 0 {
|
|
| 141 |
+ return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
|
|
| 145 |
+} |
| 0 | 146 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,164 @@ |
| 0 |
+package opts |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "runtime" |
|
| 4 |
+ "testing" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func TestParseHost(t *testing.T) {
|
|
| 8 |
+ invalid := map[string]string{
|
|
| 9 |
+ "anything": "Invalid bind address format: anything", |
|
| 10 |
+ "something with spaces": "Invalid bind address format: something with spaces", |
|
| 11 |
+ "://": "Invalid bind address format: ://", |
|
| 12 |
+ "unknown://": "Invalid bind address format: unknown://", |
|
| 13 |
+ "tcp://:port": "Invalid bind address format: :port", |
|
| 14 |
+ "tcp://invalid": "Invalid bind address format: invalid", |
|
| 15 |
+ "tcp://invalid:port": "Invalid bind address format: invalid:port", |
|
| 16 |
+ } |
|
| 17 |
+ const defaultHTTPHost = "tcp://127.0.0.1:2375" |
|
| 18 |
+ var defaultHOST = "unix:///var/run/docker.sock" |
|
| 19 |
+ |
|
| 20 |
+ if runtime.GOOS == "windows" {
|
|
| 21 |
+ defaultHOST = defaultHTTPHost |
|
| 22 |
+ } |
|
| 23 |
+ valid := map[string]string{
|
|
| 24 |
+ "": defaultHOST, |
|
| 25 |
+ "fd://": "fd://", |
|
| 26 |
+ "fd://something": "fd://something", |
|
| 27 |
+ "tcp://host:": "tcp://host:2375", |
|
| 28 |
+ "tcp://": "tcp://localhost:2375", |
|
| 29 |
+ "tcp://:2375": "tcp://localhost:2375", // default ip address |
|
| 30 |
+ "tcp://:2376": "tcp://localhost:2376", // default ip address |
|
| 31 |
+ "tcp://0.0.0.0:8080": "tcp://0.0.0.0:8080", |
|
| 32 |
+ "tcp://192.168.0.0:12000": "tcp://192.168.0.0:12000", |
|
| 33 |
+ "tcp://192.168:8080": "tcp://192.168:8080", |
|
| 34 |
+ "tcp://0.0.0.0:1234567890": "tcp://0.0.0.0:1234567890", // yeah it's valid :P |
|
| 35 |
+ "tcp://docker.com:2375": "tcp://docker.com:2375", |
|
| 36 |
+ "unix://": "unix:///var/run/docker.sock", // default unix:// value |
|
| 37 |
+ "unix://path/to/socket": "unix://path/to/socket", |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ for value, errorMessage := range invalid {
|
|
| 41 |
+ if _, err := ParseHost(defaultHTTPHost, value); err == nil || err.Error() != errorMessage {
|
|
| 42 |
+ t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err)
|
|
| 43 |
+ } |
|
| 44 |
+ } |
|
| 45 |
+ for value, expected := range valid {
|
|
| 46 |
+ if actual, err := ParseHost(defaultHTTPHost, value); err != nil || actual != expected {
|
|
| 47 |
+ t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err)
|
|
| 48 |
+ } |
|
| 49 |
+ } |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+func TestParseDockerDaemonHost(t *testing.T) {
|
|
| 53 |
+ var ( |
|
| 54 |
+ defaultHTTPHost = "tcp://localhost:2375" |
|
| 55 |
+ defaultHTTPSHost = "tcp://localhost:2376" |
|
| 56 |
+ defaultUnix = "/var/run/docker.sock" |
|
| 57 |
+ defaultHOST = "unix:///var/run/docker.sock" |
|
| 58 |
+ ) |
|
| 59 |
+ if runtime.GOOS == "windows" {
|
|
| 60 |
+ defaultHOST = defaultHTTPHost |
|
| 61 |
+ } |
|
| 62 |
+ invalids := map[string]string{
|
|
| 63 |
+ "0.0.0.0": "Invalid bind address format: 0.0.0.0", |
|
| 64 |
+ "tcp:a.b.c.d": "Invalid bind address format: tcp:a.b.c.d", |
|
| 65 |
+ "tcp:a.b.c.d/path": "Invalid bind address format: tcp:a.b.c.d/path", |
|
| 66 |
+ "udp://127.0.0.1": "Invalid bind address format: udp://127.0.0.1", |
|
| 67 |
+ "udp://127.0.0.1:2375": "Invalid bind address format: udp://127.0.0.1:2375", |
|
| 68 |
+ "tcp://unix:///run/docker.sock": "Invalid bind address format: unix", |
|
| 69 |
+ "tcp": "Invalid bind address format: tcp", |
|
| 70 |
+ "unix": "Invalid bind address format: unix", |
|
| 71 |
+ "fd": "Invalid bind address format: fd", |
|
| 72 |
+ } |
|
| 73 |
+ valids := map[string]string{
|
|
| 74 |
+ "0.0.0.1:": "tcp://0.0.0.1:2375", |
|
| 75 |
+ "0.0.0.1:5555": "tcp://0.0.0.1:5555", |
|
| 76 |
+ "0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path", |
|
| 77 |
+ "[::1]:": "tcp://[::1]:2375", |
|
| 78 |
+ "[::1]:5555/path": "tcp://[::1]:5555/path", |
|
| 79 |
+ "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2375", |
|
| 80 |
+ "[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path", |
|
| 81 |
+ ":6666": "tcp://localhost:6666", |
|
| 82 |
+ ":6666/path": "tcp://localhost:6666/path", |
|
| 83 |
+ "": defaultHOST, |
|
| 84 |
+ " ": defaultHOST, |
|
| 85 |
+ " ": defaultHOST, |
|
| 86 |
+ "tcp://": defaultHTTPHost, |
|
| 87 |
+ "tcp://:7777": "tcp://localhost:7777", |
|
| 88 |
+ "tcp://:7777/path": "tcp://localhost:7777/path", |
|
| 89 |
+ " tcp://:7777/path ": "tcp://localhost:7777/path", |
|
| 90 |
+ "unix:///run/docker.sock": "unix:///run/docker.sock", |
|
| 91 |
+ "unix://": "unix:///var/run/docker.sock", |
|
| 92 |
+ "fd://": "fd://", |
|
| 93 |
+ "fd://something": "fd://something", |
|
| 94 |
+ "localhost:": "tcp://localhost:2375", |
|
| 95 |
+ "localhost:5555": "tcp://localhost:5555", |
|
| 96 |
+ "localhost:5555/path": "tcp://localhost:5555/path", |
|
| 97 |
+ } |
|
| 98 |
+ for invalidAddr, expectedError := range invalids {
|
|
| 99 |
+ if addr, err := parseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", invalidAddr); err == nil || err.Error() != expectedError {
|
|
| 100 |
+ t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
|
|
| 101 |
+ } |
|
| 102 |
+ } |
|
| 103 |
+ for validAddr, expectedAddr := range valids {
|
|
| 104 |
+ if addr, err := parseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", validAddr); err != nil || addr != expectedAddr {
|
|
| 105 |
+ t.Errorf("%v -> expected %v, got (%v) addr (%v)", validAddr, expectedAddr, err, addr)
|
|
| 106 |
+ } |
|
| 107 |
+ } |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+func TestParseTCP(t *testing.T) {
|
|
| 111 |
+ var ( |
|
| 112 |
+ defaultHTTPHost = "tcp://127.0.0.1:2376" |
|
| 113 |
+ ) |
|
| 114 |
+ invalids := map[string]string{
|
|
| 115 |
+ "0.0.0.0": "Invalid bind address format: 0.0.0.0", |
|
| 116 |
+ "tcp:a.b.c.d": "Invalid bind address format: tcp:a.b.c.d", |
|
| 117 |
+ "tcp:a.b.c.d/path": "Invalid bind address format: tcp:a.b.c.d/path", |
|
| 118 |
+ "udp://127.0.0.1": "Invalid proto, expected tcp: udp://127.0.0.1", |
|
| 119 |
+ "udp://127.0.0.1:2375": "Invalid proto, expected tcp: udp://127.0.0.1:2375", |
|
| 120 |
+ } |
|
| 121 |
+ valids := map[string]string{
|
|
| 122 |
+ "": defaultHTTPHost, |
|
| 123 |
+ "tcp://": defaultHTTPHost, |
|
| 124 |
+ "0.0.0.1:": "tcp://0.0.0.1:2376", |
|
| 125 |
+ "0.0.0.1:5555": "tcp://0.0.0.1:5555", |
|
| 126 |
+ "0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path", |
|
| 127 |
+ ":6666": "tcp://127.0.0.1:6666", |
|
| 128 |
+ ":6666/path": "tcp://127.0.0.1:6666/path", |
|
| 129 |
+ "tcp://:7777": "tcp://127.0.0.1:7777", |
|
| 130 |
+ "tcp://:7777/path": "tcp://127.0.0.1:7777/path", |
|
| 131 |
+ "[::1]:": "tcp://[::1]:2376", |
|
| 132 |
+ "[::1]:5555": "tcp://[::1]:5555", |
|
| 133 |
+ "[::1]:5555/path": "tcp://[::1]:5555/path", |
|
| 134 |
+ "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2376", |
|
| 135 |
+ "[0:0:0:0:0:0:0:1]:5555": "tcp://[0:0:0:0:0:0:0:1]:5555", |
|
| 136 |
+ "[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path", |
|
| 137 |
+ "localhost:": "tcp://localhost:2376", |
|
| 138 |
+ "localhost:5555": "tcp://localhost:5555", |
|
| 139 |
+ "localhost:5555/path": "tcp://localhost:5555/path", |
|
| 140 |
+ } |
|
| 141 |
+ for invalidAddr, expectedError := range invalids {
|
|
| 142 |
+ if addr, err := parseTCPAddr(invalidAddr, defaultHTTPHost); err == nil || err.Error() != expectedError {
|
|
| 143 |
+ t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
|
|
| 144 |
+ } |
|
| 145 |
+ } |
|
| 146 |
+ for validAddr, expectedAddr := range valids {
|
|
| 147 |
+ if addr, err := parseTCPAddr(validAddr, defaultHTTPHost); err != nil || addr != expectedAddr {
|
|
| 148 |
+ t.Errorf("%v -> expected %v, got %v and addr %v", validAddr, expectedAddr, err, addr)
|
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+} |
|
| 152 |
+ |
|
| 153 |
+func TestParseInvalidUnixAddrInvalid(t *testing.T) {
|
|
| 154 |
+ if _, err := parseUnixAddr("tcp://127.0.0.1", "unix:///var/run/docker.sock"); err == nil || err.Error() != "Invalid proto, expected unix: tcp://127.0.0.1" {
|
|
| 155 |
+ t.Fatalf("Expected an error, got %v", err)
|
|
| 156 |
+ } |
|
| 157 |
+ if _, err := parseUnixAddr("unix://tcp://127.0.0.1", "/var/run/docker.sock"); err == nil || err.Error() != "Invalid proto, expected unix: tcp://127.0.0.1" {
|
|
| 158 |
+ t.Fatalf("Expected an error, got %v", err)
|
|
| 159 |
+ } |
|
| 160 |
+ if v, err := parseUnixAddr("", "/var/run/docker.sock"); err != nil || v != "unix:///var/run/docker.sock" {
|
|
| 161 |
+ t.Fatalf("Expected an %v, got %v", v, "unix:///var/run/docker.sock")
|
|
| 162 |
+ } |
|
| 163 |
+} |
| ... | ... |
@@ -17,22 +17,6 @@ import ( |
| 17 | 17 |
var ( |
| 18 | 18 |
alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) |
| 19 | 19 |
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`) |
| 20 |
- // DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp:// |
|
| 21 |
- // TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter |
|
| 22 |
- // is not supplied. A better longer term solution would be to use a named |
|
| 23 |
- // pipe as the default on the Windows daemon. |
|
| 24 |
- // These are the IANA registered port numbers for use with Docker |
|
| 25 |
- // see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker |
|
| 26 |
- DefaultHTTPPort = 2375 // Default HTTP Port |
|
| 27 |
- // DefaultTLSHTTPPort Default HTTP Port used when TLS enabled |
|
| 28 |
- DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port |
|
| 29 |
- // DefaultUnixSocket Path for the unix socket. |
|
| 30 |
- // Docker daemon by default always listens on the default unix socket |
|
| 31 |
- DefaultUnixSocket = "/var/run/docker.sock" |
|
| 32 |
- // DefaultTCPHost constant defines the default host string used by docker on Windows |
|
| 33 |
- DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
|
|
| 34 |
- // DefaultTLSHost constant defines the default host string used by docker for TLS sockets |
|
| 35 |
- DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
|
|
| 36 | 20 |
) |
| 37 | 21 |
|
| 38 | 22 |
// ListOpts holds a list of values and a validation function. |
| ... | ... |
@@ -391,26 +375,6 @@ func ValidateLabel(val string) (string, error) {
|
| 391 | 391 |
return val, nil |
| 392 | 392 |
} |
| 393 | 393 |
|
| 394 |
-// ValidateHost validates that the specified string is a valid host and returns it. |
|
| 395 |
-func ValidateHost(val string) (string, error) {
|
|
| 396 |
- _, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val) |
|
| 397 |
- if err != nil {
|
|
| 398 |
- return val, err |
|
| 399 |
- } |
|
| 400 |
- // Note: unlike most flag validators, we don't return the mutated value here |
|
| 401 |
- // we need to know what the user entered later (using ParseHost) to adjust for tls |
|
| 402 |
- return val, nil |
|
| 403 |
-} |
|
| 404 |
- |
|
| 405 |
-// ParseHost and set defaults for a Daemon host string |
|
| 406 |
-func ParseHost(defaultHost, val string) (string, error) {
|
|
| 407 |
- host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val) |
|
| 408 |
- if err != nil {
|
|
| 409 |
- return val, err |
|
| 410 |
- } |
|
| 411 |
- return host, nil |
|
| 412 |
-} |
|
| 413 |
- |
|
| 414 | 394 |
func doesEnvExist(name string) bool {
|
| 415 | 395 |
for _, entry := range os.Environ() {
|
| 416 | 396 |
parts := strings.SplitN(entry, "=", 2) |
| ... | ... |
@@ -3,7 +3,6 @@ package opts |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"os" |
| 6 |
- "runtime" |
|
| 7 | 6 |
"strings" |
| 8 | 7 |
"testing" |
| 9 | 8 |
) |
| ... | ... |
@@ -372,51 +371,6 @@ func TestValidateLabel(t *testing.T) {
|
| 372 | 372 |
} |
| 373 | 373 |
} |
| 374 | 374 |
|
| 375 |
-func TestParseHost(t *testing.T) {
|
|
| 376 |
- invalid := map[string]string{
|
|
| 377 |
- "anything": "Invalid bind address format: anything", |
|
| 378 |
- "something with spaces": "Invalid bind address format: something with spaces", |
|
| 379 |
- "://": "Invalid bind address format: ://", |
|
| 380 |
- "unknown://": "Invalid bind address format: unknown://", |
|
| 381 |
- "tcp://:port": "Invalid bind address format: :port", |
|
| 382 |
- "tcp://invalid": "Invalid bind address format: invalid", |
|
| 383 |
- "tcp://invalid:port": "Invalid bind address format: invalid:port", |
|
| 384 |
- } |
|
| 385 |
- const defaultHTTPHost = "tcp://127.0.0.1:2375" |
|
| 386 |
- var defaultHOST = "unix:///var/run/docker.sock" |
|
| 387 |
- |
|
| 388 |
- if runtime.GOOS == "windows" {
|
|
| 389 |
- defaultHOST = defaultHTTPHost |
|
| 390 |
- } |
|
| 391 |
- valid := map[string]string{
|
|
| 392 |
- "": defaultHOST, |
|
| 393 |
- "fd://": "fd://", |
|
| 394 |
- "fd://something": "fd://something", |
|
| 395 |
- "tcp://host:": "tcp://host:2375", |
|
| 396 |
- "tcp://": "tcp://localhost:2375", |
|
| 397 |
- "tcp://:2375": "tcp://localhost:2375", // default ip address |
|
| 398 |
- "tcp://:2376": "tcp://localhost:2376", // default ip address |
|
| 399 |
- "tcp://0.0.0.0:8080": "tcp://0.0.0.0:8080", |
|
| 400 |
- "tcp://192.168.0.0:12000": "tcp://192.168.0.0:12000", |
|
| 401 |
- "tcp://192.168:8080": "tcp://192.168:8080", |
|
| 402 |
- "tcp://0.0.0.0:1234567890": "tcp://0.0.0.0:1234567890", // yeah it's valid :P |
|
| 403 |
- "tcp://docker.com:2375": "tcp://docker.com:2375", |
|
| 404 |
- "unix://": "unix:///var/run/docker.sock", // default unix:// value |
|
| 405 |
- "unix://path/to/socket": "unix://path/to/socket", |
|
| 406 |
- } |
|
| 407 |
- |
|
| 408 |
- for value, errorMessage := range invalid {
|
|
| 409 |
- if _, err := ParseHost(defaultHTTPHost, value); err == nil || err.Error() != errorMessage {
|
|
| 410 |
- t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err)
|
|
| 411 |
- } |
|
| 412 |
- } |
|
| 413 |
- for value, expected := range valid {
|
|
| 414 |
- if actual, err := ParseHost(defaultHTTPHost, value); err != nil || actual != expected {
|
|
| 415 |
- t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err)
|
|
| 416 |
- } |
|
| 417 |
- } |
|
| 418 |
-} |
|
| 419 |
- |
|
| 420 | 375 |
func logOptsValidator(val string) (string, error) {
|
| 421 | 376 |
allowedKeys := map[string]string{"max-size": "1", "max-file": "2"}
|
| 422 | 377 |
vals := strings.Split(val, "=") |
| ... | ... |
@@ -5,111 +5,11 @@ package parsers |
| 5 | 5 |
|
| 6 | 6 |
import ( |
| 7 | 7 |
"fmt" |
| 8 |
- "net" |
|
| 9 |
- "net/url" |
|
| 10 | 8 |
"path" |
| 11 |
- "runtime" |
|
| 12 | 9 |
"strconv" |
| 13 | 10 |
"strings" |
| 14 | 11 |
) |
| 15 | 12 |
|
| 16 |
-// ParseDockerDaemonHost parses the specified address and returns an address that will be used as the host. |
|
| 17 |
-// Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr |
|
| 18 |
-// defaultUnixAddr must be a absolute file path (no `unix://` prefix) |
|
| 19 |
-// defaultTCPAddr must be the full `tcp://host:port` form |
|
| 20 |
-func ParseDockerDaemonHost(defaultTCPAddr, defaultTLSHost, defaultUnixAddr, defaultAddr, addr string) (string, error) {
|
|
| 21 |
- addr = strings.TrimSpace(addr) |
|
| 22 |
- if addr == "" {
|
|
| 23 |
- if defaultAddr == defaultTLSHost {
|
|
| 24 |
- return defaultTLSHost, nil |
|
| 25 |
- } |
|
| 26 |
- if runtime.GOOS != "windows" {
|
|
| 27 |
- return fmt.Sprintf("unix://%s", defaultUnixAddr), nil
|
|
| 28 |
- } |
|
| 29 |
- return defaultTCPAddr, nil |
|
| 30 |
- } |
|
| 31 |
- addrParts := strings.Split(addr, "://") |
|
| 32 |
- if len(addrParts) == 1 {
|
|
| 33 |
- addrParts = []string{"tcp", addrParts[0]}
|
|
| 34 |
- } |
|
| 35 |
- |
|
| 36 |
- switch addrParts[0] {
|
|
| 37 |
- case "tcp": |
|
| 38 |
- return ParseTCPAddr(addrParts[1], defaultTCPAddr) |
|
| 39 |
- case "unix": |
|
| 40 |
- return ParseUnixAddr(addrParts[1], defaultUnixAddr) |
|
| 41 |
- case "fd": |
|
| 42 |
- return addr, nil |
|
| 43 |
- default: |
|
| 44 |
- return "", fmt.Errorf("Invalid bind address format: %s", addr)
|
|
| 45 |
- } |
|
| 46 |
-} |
|
| 47 |
- |
|
| 48 |
-// ParseUnixAddr parses and validates that the specified address is a valid UNIX |
|
| 49 |
-// socket address. It returns a formatted UNIX socket address, either using the |
|
| 50 |
-// address parsed from addr, or the contents of defaultAddr if addr is a blank |
|
| 51 |
-// string. |
|
| 52 |
-func ParseUnixAddr(addr string, defaultAddr string) (string, error) {
|
|
| 53 |
- addr = strings.TrimPrefix(addr, "unix://") |
|
| 54 |
- if strings.Contains(addr, "://") {
|
|
| 55 |
- return "", fmt.Errorf("Invalid proto, expected unix: %s", addr)
|
|
| 56 |
- } |
|
| 57 |
- if addr == "" {
|
|
| 58 |
- addr = defaultAddr |
|
| 59 |
- } |
|
| 60 |
- return fmt.Sprintf("unix://%s", addr), nil
|
|
| 61 |
-} |
|
| 62 |
- |
|
| 63 |
-// ParseTCPAddr parses and validates that the specified address is a valid TCP |
|
| 64 |
-// address. It returns a formatted TCP address, either using the address parsed |
|
| 65 |
-// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string. |
|
| 66 |
-// tryAddr is expected to have already been Trim()'d |
|
| 67 |
-// defaultAddr must be in the full `tcp://host:port` form |
|
| 68 |
-func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
|
|
| 69 |
- if tryAddr == "" || tryAddr == "tcp://" {
|
|
| 70 |
- return defaultAddr, nil |
|
| 71 |
- } |
|
| 72 |
- addr := strings.TrimPrefix(tryAddr, "tcp://") |
|
| 73 |
- if strings.Contains(addr, "://") || addr == "" {
|
|
| 74 |
- return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
|
|
| 75 |
- } |
|
| 76 |
- |
|
| 77 |
- defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://") |
|
| 78 |
- defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr) |
|
| 79 |
- if err != nil {
|
|
| 80 |
- return "", err |
|
| 81 |
- } |
|
| 82 |
- // url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but |
|
| 83 |
- // not 1.4. See https://github.com/golang/go/issues/12200 and |
|
| 84 |
- // https://github.com/golang/go/issues/6530. |
|
| 85 |
- if strings.HasSuffix(addr, "]:") {
|
|
| 86 |
- addr += defaultPort |
|
| 87 |
- } |
|
| 88 |
- |
|
| 89 |
- u, err := url.Parse("tcp://" + addr)
|
|
| 90 |
- if err != nil {
|
|
| 91 |
- return "", err |
|
| 92 |
- } |
|
| 93 |
- |
|
| 94 |
- host, port, err := net.SplitHostPort(u.Host) |
|
| 95 |
- if err != nil {
|
|
| 96 |
- return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
| 97 |
- } |
|
| 98 |
- |
|
| 99 |
- if host == "" {
|
|
| 100 |
- host = defaultHost |
|
| 101 |
- } |
|
| 102 |
- if port == "" {
|
|
| 103 |
- port = defaultPort |
|
| 104 |
- } |
|
| 105 |
- p, err := strconv.Atoi(port) |
|
| 106 |
- if err != nil && p == 0 {
|
|
| 107 |
- return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
|
|
| 108 |
- } |
|
| 109 |
- |
|
| 110 |
- return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
|
|
| 111 |
-} |
|
| 112 |
- |
|
| 113 | 13 |
// PartParser parses and validates the specified string (data) using the specified template |
| 114 | 14 |
// e.g. ip:public:private -> 192.168.0.1:80:8000 |
| 115 | 15 |
func PartParser(template, data string) (map[string]string, error) {
|
| ... | ... |
@@ -2,124 +2,10 @@ package parsers |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"reflect" |
| 5 |
- "runtime" |
|
| 6 | 5 |
"strings" |
| 7 | 6 |
"testing" |
| 8 | 7 |
) |
| 9 | 8 |
|
| 10 |
-func TestParseDockerDaemonHost(t *testing.T) {
|
|
| 11 |
- var ( |
|
| 12 |
- defaultHTTPHost = "tcp://localhost:2375" |
|
| 13 |
- defaultHTTPSHost = "tcp://localhost:2376" |
|
| 14 |
- defaultUnix = "/var/run/docker.sock" |
|
| 15 |
- defaultHOST = "unix:///var/run/docker.sock" |
|
| 16 |
- ) |
|
| 17 |
- if runtime.GOOS == "windows" {
|
|
| 18 |
- defaultHOST = defaultHTTPHost |
|
| 19 |
- } |
|
| 20 |
- invalids := map[string]string{
|
|
| 21 |
- "0.0.0.0": "Invalid bind address format: 0.0.0.0", |
|
| 22 |
- "tcp:a.b.c.d": "Invalid bind address format: tcp:a.b.c.d", |
|
| 23 |
- "tcp:a.b.c.d/path": "Invalid bind address format: tcp:a.b.c.d/path", |
|
| 24 |
- "udp://127.0.0.1": "Invalid bind address format: udp://127.0.0.1", |
|
| 25 |
- "udp://127.0.0.1:2375": "Invalid bind address format: udp://127.0.0.1:2375", |
|
| 26 |
- "tcp://unix:///run/docker.sock": "Invalid bind address format: unix", |
|
| 27 |
- "tcp": "Invalid bind address format: tcp", |
|
| 28 |
- "unix": "Invalid bind address format: unix", |
|
| 29 |
- "fd": "Invalid bind address format: fd", |
|
| 30 |
- } |
|
| 31 |
- valids := map[string]string{
|
|
| 32 |
- "0.0.0.1:": "tcp://0.0.0.1:2375", |
|
| 33 |
- "0.0.0.1:5555": "tcp://0.0.0.1:5555", |
|
| 34 |
- "0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path", |
|
| 35 |
- "[::1]:": "tcp://[::1]:2375", |
|
| 36 |
- "[::1]:5555/path": "tcp://[::1]:5555/path", |
|
| 37 |
- "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2375", |
|
| 38 |
- "[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path", |
|
| 39 |
- ":6666": "tcp://localhost:6666", |
|
| 40 |
- ":6666/path": "tcp://localhost:6666/path", |
|
| 41 |
- "": defaultHOST, |
|
| 42 |
- " ": defaultHOST, |
|
| 43 |
- " ": defaultHOST, |
|
| 44 |
- "tcp://": defaultHTTPHost, |
|
| 45 |
- "tcp://:7777": "tcp://localhost:7777", |
|
| 46 |
- "tcp://:7777/path": "tcp://localhost:7777/path", |
|
| 47 |
- " tcp://:7777/path ": "tcp://localhost:7777/path", |
|
| 48 |
- "unix:///run/docker.sock": "unix:///run/docker.sock", |
|
| 49 |
- "unix://": "unix:///var/run/docker.sock", |
|
| 50 |
- "fd://": "fd://", |
|
| 51 |
- "fd://something": "fd://something", |
|
| 52 |
- "localhost:": "tcp://localhost:2375", |
|
| 53 |
- "localhost:5555": "tcp://localhost:5555", |
|
| 54 |
- "localhost:5555/path": "tcp://localhost:5555/path", |
|
| 55 |
- } |
|
| 56 |
- for invalidAddr, expectedError := range invalids {
|
|
| 57 |
- if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", invalidAddr); err == nil || err.Error() != expectedError {
|
|
| 58 |
- t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
|
|
| 59 |
- } |
|
| 60 |
- } |
|
| 61 |
- for validAddr, expectedAddr := range valids {
|
|
| 62 |
- if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", validAddr); err != nil || addr != expectedAddr {
|
|
| 63 |
- t.Errorf("%v -> expected %v, got (%v) addr (%v)", validAddr, expectedAddr, err, addr)
|
|
| 64 |
- } |
|
| 65 |
- } |
|
| 66 |
-} |
|
| 67 |
- |
|
| 68 |
-func TestParseTCP(t *testing.T) {
|
|
| 69 |
- var ( |
|
| 70 |
- defaultHTTPHost = "tcp://127.0.0.1:2376" |
|
| 71 |
- ) |
|
| 72 |
- invalids := map[string]string{
|
|
| 73 |
- "0.0.0.0": "Invalid bind address format: 0.0.0.0", |
|
| 74 |
- "tcp:a.b.c.d": "Invalid bind address format: tcp:a.b.c.d", |
|
| 75 |
- "tcp:a.b.c.d/path": "Invalid bind address format: tcp:a.b.c.d/path", |
|
| 76 |
- "udp://127.0.0.1": "Invalid proto, expected tcp: udp://127.0.0.1", |
|
| 77 |
- "udp://127.0.0.1:2375": "Invalid proto, expected tcp: udp://127.0.0.1:2375", |
|
| 78 |
- } |
|
| 79 |
- valids := map[string]string{
|
|
| 80 |
- "": defaultHTTPHost, |
|
| 81 |
- "tcp://": defaultHTTPHost, |
|
| 82 |
- "0.0.0.1:": "tcp://0.0.0.1:2376", |
|
| 83 |
- "0.0.0.1:5555": "tcp://0.0.0.1:5555", |
|
| 84 |
- "0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path", |
|
| 85 |
- ":6666": "tcp://127.0.0.1:6666", |
|
| 86 |
- ":6666/path": "tcp://127.0.0.1:6666/path", |
|
| 87 |
- "tcp://:7777": "tcp://127.0.0.1:7777", |
|
| 88 |
- "tcp://:7777/path": "tcp://127.0.0.1:7777/path", |
|
| 89 |
- "[::1]:": "tcp://[::1]:2376", |
|
| 90 |
- "[::1]:5555": "tcp://[::1]:5555", |
|
| 91 |
- "[::1]:5555/path": "tcp://[::1]:5555/path", |
|
| 92 |
- "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2376", |
|
| 93 |
- "[0:0:0:0:0:0:0:1]:5555": "tcp://[0:0:0:0:0:0:0:1]:5555", |
|
| 94 |
- "[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path", |
|
| 95 |
- "localhost:": "tcp://localhost:2376", |
|
| 96 |
- "localhost:5555": "tcp://localhost:5555", |
|
| 97 |
- "localhost:5555/path": "tcp://localhost:5555/path", |
|
| 98 |
- } |
|
| 99 |
- for invalidAddr, expectedError := range invalids {
|
|
| 100 |
- if addr, err := ParseTCPAddr(invalidAddr, defaultHTTPHost); err == nil || err.Error() != expectedError {
|
|
| 101 |
- t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
|
|
| 102 |
- } |
|
| 103 |
- } |
|
| 104 |
- for validAddr, expectedAddr := range valids {
|
|
| 105 |
- if addr, err := ParseTCPAddr(validAddr, defaultHTTPHost); err != nil || addr != expectedAddr {
|
|
| 106 |
- t.Errorf("%v -> expected %v, got %v and addr %v", validAddr, expectedAddr, err, addr)
|
|
| 107 |
- } |
|
| 108 |
- } |
|
| 109 |
-} |
|
| 110 |
- |
|
| 111 |
-func TestParseInvalidUnixAddrInvalid(t *testing.T) {
|
|
| 112 |
- if _, err := ParseUnixAddr("tcp://127.0.0.1", "unix:///var/run/docker.sock"); err == nil || err.Error() != "Invalid proto, expected unix: tcp://127.0.0.1" {
|
|
| 113 |
- t.Fatalf("Expected an error, got %v", err)
|
|
| 114 |
- } |
|
| 115 |
- if _, err := ParseUnixAddr("unix://tcp://127.0.0.1", "/var/run/docker.sock"); err == nil || err.Error() != "Invalid proto, expected unix: tcp://127.0.0.1" {
|
|
| 116 |
- t.Fatalf("Expected an error, got %v", err)
|
|
| 117 |
- } |
|
| 118 |
- if v, err := ParseUnixAddr("", "/var/run/docker.sock"); err != nil || v != "unix:///var/run/docker.sock" {
|
|
| 119 |
- t.Fatalf("Expected an %v, got %v", v, "unix:///var/run/docker.sock")
|
|
| 120 |
- } |
|
| 121 |
-} |
|
| 122 |
- |
|
| 123 | 9 |
func TestParseKeyValueOpt(t *testing.T) {
|
| 124 | 10 |
invalids := map[string]string{
|
| 125 | 11 |
"": "Unable to parse key/value option: ", |