Browse code

Merge pull request #16437 from runcom/invalid-logger-address

daemon: logger: error out on daemon start if invalid logger address

Tibor Vass authored on 2015/09/22 03:53:47
Showing 4 changed files
... ...
@@ -94,7 +94,11 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
94 94
 		return fmt.Errorf("Missing parameter")
95 95
 	}
96 96
 
97
-	// Validate args here, because we can't return not StatusOK after job.Run() call
97
+	// Args are validated before the stream starts because when it starts we're
98
+	// sending HTTP 200 by writing an empty chunk of data to tell the client that
99
+	// daemon is going to stream. By sending this initial HTTP 200 we can't report
100
+	// any error after the stream starts (i.e. container not found, wrong parameters)
101
+	// with the appropriate status code.
98 102
 	stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
99 103
 	if !(stdout || stderr) {
100 104
 		return fmt.Errorf("Bad parameters: you must choose at least one stream")
... ...
@@ -38,44 +38,20 @@ func init() {
38 38
 	}
39 39
 }
40 40
 
41
-func parseConfig(ctx logger.Context) (string, int, string, error) {
42
-	host := defaultHostName
43
-	port := defaultPort
44
-
45
-	config := ctx.Config
46
-
47
-	tag, err := loggerutils.ParseLogTag(ctx, "docker.{{.ID}}")
48
-	if err != nil {
49
-		return "", 0, "", err
50
-	}
51
-
52
-	if address := config["fluentd-address"]; address != "" {
53
-		if h, p, err := net.SplitHostPort(address); err != nil {
54
-			if !strings.Contains(err.Error(), "missing port in address") {
55
-				return "", 0, "", err
56
-			}
57
-			host = h
58
-		} else {
59
-			portnum, err := strconv.Atoi(p)
60
-			if err != nil {
61
-				return "", 0, "", err
62
-			}
63
-			host = h
64
-			port = portnum
65
-		}
66
-	}
67
-
68
-	return host, port, tag, nil
69
-}
70
-
71 41
 // New creates a fluentd logger using the configuration passed in on
72 42
 // the context. Supported context configuration variables are
73 43
 // fluentd-address & fluentd-tag.
74 44
 func New(ctx logger.Context) (logger.Logger, error) {
75
-	host, port, tag, err := parseConfig(ctx)
45
+	host, port, err := parseAddress(ctx.Config["fluentd-address"])
46
+	if err != nil {
47
+		return nil, err
48
+	}
49
+
50
+	tag, err := loggerutils.ParseLogTag(ctx, "docker.{{.ID}}")
76 51
 	if err != nil {
77 52
 		return nil, err
78 53
 	}
54
+
79 55
 	logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s.", ctx.ContainerID, host, port, tag)
80 56
 
81 57
 	// logger tries to recoonect 2**32 - 1 times
... ...
@@ -104,6 +80,14 @@ func (f *fluentd) Log(msg *logger.Message) error {
104 104
 	return f.writer.PostWithTime(f.tag, msg.Timestamp, data)
105 105
 }
106 106
 
107
+func (f *fluentd) Close() error {
108
+	return f.writer.Close()
109
+}
110
+
111
+func (f *fluentd) Name() string {
112
+	return name
113
+}
114
+
107 115
 // ValidateLogOpt looks for fluentd specific log options fluentd-address & fluentd-tag.
108 116
 func ValidateLogOpt(cfg map[string]string) error {
109 117
 	for key := range cfg {
... ...
@@ -115,13 +99,30 @@ func ValidateLogOpt(cfg map[string]string) error {
115 115
 			return fmt.Errorf("unknown log opt '%s' for fluentd log driver", key)
116 116
 		}
117 117
 	}
118
+
119
+	if _, _, err := parseAddress(cfg["fluentd-address"]); err != nil {
120
+		return err
121
+	}
122
+
118 123
 	return nil
119 124
 }
120 125
 
121
-func (f *fluentd) Close() error {
122
-	return f.writer.Close()
123
-}
126
+func parseAddress(address string) (string, int, error) {
127
+	if address == "" {
128
+		return defaultHostName, defaultPort, nil
129
+	}
124 130
 
125
-func (f *fluentd) Name() string {
126
-	return name
131
+	host, port, err := net.SplitHostPort(address)
132
+	if err != nil {
133
+		if !strings.Contains(err.Error(), "missing port in address") {
134
+			return "", 0, fmt.Errorf("invalid fluentd-address %s: %s", address, err)
135
+		}
136
+		return host, defaultPort, nil
137
+	}
138
+
139
+	portnum, err := strconv.Atoi(port)
140
+	if err != nil {
141
+		return "", 0, fmt.Errorf("invalid fluentd-address %s: %s", address, err)
142
+	}
143
+	return host, portnum, nil
127 144
 }
... ...
@@ -147,28 +147,35 @@ func ValidateLogOpt(cfg map[string]string) error {
147 147
 			return fmt.Errorf("unknown log opt '%s' for gelf log driver", key)
148 148
 		}
149 149
 	}
150
+
151
+	if _, err := parseAddress(cfg["gelf-address"]); err != nil {
152
+		return err
153
+	}
154
+
150 155
 	return nil
151 156
 }
152 157
 
153 158
 func parseAddress(address string) (string, error) {
154
-	if urlutil.IsTransportURL(address) {
155
-		url, err := url.Parse(address)
156
-		if err != nil {
157
-			return "", err
158
-		}
159
-
160
-		// we support only udp
161
-		if url.Scheme != "udp" {
162
-			return "", fmt.Errorf("gelf: endpoint needs to be UDP")
163
-		}
159
+	if address == "" {
160
+		return "", nil
161
+	}
162
+	if !urlutil.IsTransportURL(address) {
163
+		return "", fmt.Errorf("gelf-address should be in form proto://address, got %v", address)
164
+	}
165
+	url, err := url.Parse(address)
166
+	if err != nil {
167
+		return "", err
168
+	}
164 169
 
165
-		// get host and port
166
-		if _, _, err = net.SplitHostPort(url.Host); err != nil {
167
-			return "", fmt.Errorf("gelf: please provide gelf-address as udp://host:port")
168
-		}
170
+	// we support only udp
171
+	if url.Scheme != "udp" {
172
+		return "", fmt.Errorf("gelf: endpoint needs to be UDP")
173
+	}
169 174
 
170
-		return url.Host, nil
175
+	// get host and port
176
+	if _, _, err = net.SplitHostPort(url.Host); err != nil {
177
+		return "", fmt.Errorf("gelf: please provide gelf-address as udp://host:port")
171 178
 	}
172 179
 
173
-	return "", nil
180
+	return url.Host, nil
174 181
 }
... ...
@@ -1615,14 +1615,6 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithContainerWithRestartPolicyAlway
1615 1615
 	c.Assert(strings.TrimSpace(out), check.Equals, id[:12])
1616 1616
 }
1617 1617
 
1618
-func (s *DockerDaemonSuite) TestDaemonCorruptedSyslogAddress(c *check.C) {
1619
-	c.Assert(s.d.Start("--log-driver=syslog", "--log-opt", "syslog-address=corrupted:1234"), check.NotNil)
1620
-	runCmd := exec.Command("grep", "Failed to set log opts: syslog-address should be in form proto://address", s.d.LogfileName())
1621
-	if out, _, err := runCommandWithOutput(runCmd); err != nil {
1622
-		c.Fatalf("Expected 'Error starting daemon' message; but doesn't exist in log: %q, err: %v", out, err)
1623
-	}
1624
-}
1625
-
1626 1618
 func (s *DockerDaemonSuite) TestDaemonWideLogConfig(c *check.C) {
1627 1619
 	if err := s.d.StartWithBusybox("--log-driver=json-file", "--log-opt=max-size=1k"); err != nil {
1628 1620
 		c.Fatal(err)
... ...
@@ -1697,3 +1689,27 @@ func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *check.C) {
1697 1697
 	_, err = s.d.Cmd("volume", "inspect", "test")
1698 1698
 	c.Assert(err, check.IsNil)
1699 1699
 }
1700
+
1701
+func (s *DockerDaemonSuite) TestDaemonCorruptedLogDriverAddress(c *check.C) {
1702
+	for _, driver := range []string{
1703
+		"syslog",
1704
+		"gelf",
1705
+	} {
1706
+		args := []string{"--log-driver=" + driver, "--log-opt", driver + "-address=corrupted:42"}
1707
+		c.Assert(s.d.Start(args...), check.NotNil, check.Commentf(fmt.Sprintf("Expected daemon not to start with invalid %s-address provided", driver)))
1708
+		expected := fmt.Sprintf("Failed to set log opts: %s-address should be in form proto://address", driver)
1709
+		runCmd := exec.Command("grep", expected, s.d.LogfileName())
1710
+		if out, _, err := runCommandWithOutput(runCmd); err != nil {
1711
+			c.Fatalf("Expected %q message; but doesn't exist in log: %q, err: %v", expected, out, err)
1712
+		}
1713
+	}
1714
+}
1715
+
1716
+func (s *DockerDaemonSuite) TestDaemonCorruptedFluentdAddress(c *check.C) {
1717
+	c.Assert(s.d.Start("--log-driver=fluentd", "--log-opt", "fluentd-address=corrupted:c"), check.NotNil)
1718
+	expected := "Failed to set log opts: invalid fluentd-address corrupted:c: "
1719
+	runCmd := exec.Command("grep", expected, s.d.LogfileName())
1720
+	if out, _, err := runCommandWithOutput(runCmd); err != nil {
1721
+		c.Fatalf("Expected %q message; but doesn't exist in log: %q, err: %v", expected, out, err)
1722
+	}
1723
+}