Add doc links for metrics endpoint

pull/3369/head
Kyle Havlovitz 2017-08-08 13:05:38 -07:00
parent 5b998cacb1
commit c1c883f441
No known key found for this signature in database
GPG Key ID: 8A5E6B173056AD6C
5 changed files with 47 additions and 22 deletions

View File

@ -54,6 +54,21 @@ func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (int
}, nil }, nil
} }
func (s *HTTPServer) AgentMetrics(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 s.agent.MemSink.DisplayMetrics(resp, req)
}
func (s *HTTPServer) AgentReload(resp http.ResponseWriter, req *http.Request) (interface{}, error) { func (s *HTTPServer) AgentReload(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "PUT" { if req.Method != "PUT" {
resp.WriteHeader(http.StatusMethodNotAllowed) resp.WriteHeader(http.StatusMethodNotAllowed)

View File

@ -239,6 +239,34 @@ func TestAgent_Self_ACLDeny(t *testing.T) {
}) })
} }
func TestAgent_Metrics_ACLDeny(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), TestACLConfig())
defer a.Shutdown()
t.Run("no token", func(t *testing.T) {
req, _ := http.NewRequest("GET", "/v1/agent/metrics", nil)
if _, err := a.srv.AgentSelf(nil, req); !isPermissionDenied(err) {
t.Fatalf("err: %v", err)
}
})
t.Run("agent master token", func(t *testing.T) {
req, _ := http.NewRequest("GET", "/v1/agent/metrics?token=towel", nil)
if _, err := a.srv.AgentSelf(nil, req); err != nil {
t.Fatalf("err: %v", err)
}
})
t.Run("read-only token", func(t *testing.T) {
ro := makeReadOnlyAgentACL(t, a.srv)
req, _ := http.NewRequest("GET", fmt.Sprintf("/v1/agent/metrics?token=%s", ro), nil)
if _, err := a.srv.AgentSelf(nil, req); err != nil {
t.Fatalf("err: %v", err)
}
})
}
func TestAgent_Reload(t *testing.T) { func TestAgent_Reload(t *testing.T) {
t.Parallel() t.Parallel()
cfg := TestConfig() cfg := TestConfig()

View File

@ -98,7 +98,7 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler {
handleFuncMetrics("/v1/agent/maintenance", s.wrap(s.AgentNodeMaintenance)) handleFuncMetrics("/v1/agent/maintenance", s.wrap(s.AgentNodeMaintenance))
handleFuncMetrics("/v1/agent/reload", s.wrap(s.AgentReload)) handleFuncMetrics("/v1/agent/reload", s.wrap(s.AgentReload))
handleFuncMetrics("/v1/agent/monitor", s.wrap(s.AgentMonitor)) handleFuncMetrics("/v1/agent/monitor", s.wrap(s.AgentMonitor))
handleFuncMetrics("/v1/agent/metrics", s.wrap(s.requireAgentRead(s.agent.MemSink.DisplayMetrics))) handleFuncMetrics("/v1/agent/metrics", s.wrap(s.AgentMetrics))
handleFuncMetrics("/v1/agent/services", s.wrap(s.AgentServices)) handleFuncMetrics("/v1/agent/services", s.wrap(s.AgentServices))
handleFuncMetrics("/v1/agent/checks", s.wrap(s.AgentChecks)) handleFuncMetrics("/v1/agent/checks", s.wrap(s.AgentChecks))
handleFuncMetrics("/v1/agent/members", s.wrap(s.AgentMembers)) handleFuncMetrics("/v1/agent/members", s.wrap(s.AgentMembers))
@ -264,26 +264,6 @@ 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 // marshalJSON marshals the object into JSON, respecting the user's pretty-ness
// configuration. // configuration.
func (s *HTTPServer) marshalJSON(req *http.Request, obj interface{}) ([]byte, error) { func (s *HTTPServer) marshalJSON(req *http.Request, obj interface{}) ([]byte, error) {

View File

@ -1345,3 +1345,4 @@ items which are reloaded include:
* Watches * Watches
* HTTP Client Address * HTTP Client Address
* <a href="#node_meta">Node Metadata</a> * <a href="#node_meta">Node Metadata</a>
* <a href="#telemetry-prefix_filter">Metric Prefix Filter</a>

View File

@ -22,7 +22,8 @@ getting a better view of what Consul is doing.
Additionally, if the [`telemetry` configuration options](/docs/agent/options.html#telemetry) Additionally, if the [`telemetry` configuration options](/docs/agent/options.html#telemetry)
are provided, the telemetry information will be streamed to a are provided, the telemetry information will be streamed to a
[statsite](http://github.com/armon/statsite) or [statsd](http://github.com/etsy/statsd) server where [statsite](http://github.com/armon/statsite) or [statsd](http://github.com/etsy/statsd) server where
it can be aggregated and flushed to Graphite or any other metrics store. it can be aggregated and flushed to Graphite or any other metrics store. This
information can also be viewed with the [metrics endpoint](/api/agent.html#view-metrics)
Below is sample output of a telemetry dump: Below is sample output of a telemetry dump: