diff --git a/agent/agent.go b/agent/agent.go index f59a55e4ec..1b3bc959ac 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -2248,5 +2248,8 @@ func (a *Agent) ReloadConfig(newCfg *Config) error { return fmt.Errorf("Failed reloading watches: %v", err) } + // Update filtered metrics + metrics.UpdateFilter(newCfg.Telemetry.AllowedPrefixes, newCfg.Telemetry.BlockedPrefixes) + return nil } diff --git a/agent/config.go b/agent/config.go index 116835cf9a..ee57b47796 100644 --- a/agent/config.go +++ b/agent/config.go @@ -1483,7 +1483,7 @@ func DecodeConfig(r io.Reader) (*Config, error) { case '-': result.Telemetry.BlockedPrefixes = append(result.Telemetry.BlockedPrefixes, rule[1:]) default: - return nil, fmt.Errorf("Filter rule must begin with either '+' or '-': %s", rule) + return nil, fmt.Errorf("Filter rule must begin with either '+' or '-': %q", rule) } } diff --git a/agent/http.go b/agent/http.go index 2d43209b18..968f2100d3 100644 --- a/agent/http.go +++ b/agent/http.go @@ -98,7 +98,7 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler { handleFuncMetrics("/v1/agent/maintenance", s.wrap(s.AgentNodeMaintenance)) handleFuncMetrics("/v1/agent/reload", s.wrap(s.AgentReload)) handleFuncMetrics("/v1/agent/monitor", s.wrap(s.AgentMonitor)) - handleFuncMetrics("/v1/agent/metrics", s.wrap(s.agent.MemSink.DisplayMetrics)) + handleFuncMetrics("/v1/agent/metrics", s.wrap(s.requireAgentRead(s.agent.MemSink.DisplayMetrics))) handleFuncMetrics("/v1/agent/services", s.wrap(s.AgentServices)) handleFuncMetrics("/v1/agent/checks", s.wrap(s.AgentChecks)) handleFuncMetrics("/v1/agent/members", s.wrap(s.AgentMembers)) @@ -264,6 +264,26 @@ func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Reque } } +type handlerFunc func(resp http.ResponseWriter, req *http.Request) (interface{}, error) + +// requireAgentRead wraps the given function, requiring a token with agent read permissions +func (s *HTTPServer) requireAgentRead(handler handlerFunc) handlerFunc { + return func(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + // Fetch the ACL token, if any, and enforce agent policy. + var token string + s.parseToken(req, &token) + acl, err := s.agent.resolveToken(token) + if err != nil { + return nil, err + } + if acl != nil && !acl.AgentRead(s.agent.config.NodeName) { + return nil, errPermissionDenied + } + + return handler(resp, req) + } +} + // marshalJSON marshals the object into JSON, respecting the user's pretty-ness // configuration. func (s *HTTPServer) marshalJSON(req *http.Request, obj interface{}) ([]byte, error) { diff --git a/website/source/api/agent.html.md b/website/source/api/agent.html.md index 78876c84fa..ea09e231ca 100644 --- a/website/source/api/agent.html.md +++ b/website/source/api/agent.html.md @@ -355,6 +355,21 @@ $ curl \ } ``` +- `Timestamp` is the timestamp of the interval for the displayed metrics. Metrics are +aggregated on a ten second interval, so this value (along with the displayed metrics) +will change every ten seconds. + +- `Gauges` is a list of gauges which store one value that is updated as time goes on, +such as the amount of memory allocated. + +- `Points` is a list of point metrics, which each store a series of points under a given name. + +- `Counters` is a list of counters, which store info about a metric that is incremented +over time such as the number of requests to an HTTP endpoint. + +- `Samples` is a list of samples, which store info about the amount of time spent on an +operation, such as the time taken to serve a request to a specific http endpoint. + ## Stream Logs This endpoint streams logs from the local agent until the connection is closed.