diff --git a/api/agent.go b/api/agent.go index 5ae71ca72..811d45864 100644 --- a/api/agent.go +++ b/api/agent.go @@ -376,7 +376,7 @@ func (a *Agent) Trace(serverID, nodeID string, seconds int, q *QueryOptions) ([] // // The call blocks until the profile finishes, and returns the raw bytes of the // profile. -func (a *Agent) Profile(serverID, nodeID, profile string, debug int, q *QueryOptions) ([]byte, error) { +func (a *Agent) Profile(serverID, nodeID, profile string, debug, gc int, q *QueryOptions) ([]byte, error) { if q == nil { q = &QueryOptions{} } @@ -385,6 +385,7 @@ func (a *Agent) Profile(serverID, nodeID, profile string, debug int, q *QueryOpt } q.Params["debug"] = strconv.Itoa(debug) + q.Params["qc"] = strconv.Itoa(debug) q.Params["node_id"] = nodeID q.Params["server_id"] = serverID diff --git a/api/agent_test.go b/api/agent_test.go index 21a99eeb0..6e8154732 100644 --- a/api/agent_test.go +++ b/api/agent_test.go @@ -436,14 +436,14 @@ func TestAgentProfile(t *testing.T) { } { - resp, err := agent.Profile("", "", "goroutine", 0, q) + resp, err := agent.Profile("", "", "heap", 0, 1, q) require.NoError(t, err) require.NotNil(t, resp) } // unknown profile { - resp, err := agent.Profile("", "", "invalid", 1, q) + resp, err := agent.Profile("", "", "invalid", 1, 1, q) require.Error(t, err) require.Contains(t, err.Error(), "Unexpected response code: 404") require.Nil(t, resp) diff --git a/command/agent/http.go b/command/agent/http.go index 4000c8292..5cab3efea 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -363,6 +363,7 @@ func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Reque // wrapNonJSON is used to wrap functions returning non JSON // serializeable data to make them more convenient. It is primarily // responsible for setting nomad headers and logging. +// Handler functions are responsible for setting Content-Type Header func (s *HTTPServer) wrapNonJSON(handler func(resp http.ResponseWriter, req *http.Request) ([]byte, error)) func(resp http.ResponseWriter, req *http.Request) { f := func(resp http.ResponseWriter, req *http.Request) { setHeaders(resp, s.agent.config.HTTPAPIResponseHeaders) diff --git a/nomad/client_agent_endpoint.go b/nomad/client_agent_endpoint.go index ca2d00229..4d56d14ae 100644 --- a/nomad/client_agent_endpoint.go +++ b/nomad/client_agent_endpoint.go @@ -29,6 +29,14 @@ func (a *Agent) register() { } func (a *Agent) Profile(args *structs.AgentPprofRequest, reply *structs.AgentPprofResponse) error { + // Check ACL for agent write + aclObj, err := a.srv.ResolveToken(args.AuthToken) + if err != nil { + return err + } else if aclObj != nil && !aclObj.AllowAgentWrite() { + return structs.ErrPermissionDenied + } + // Forward to different region if necessary // this would typically be done in a.srv.forward() but since // we are targeting a specific server, not just the leader @@ -60,19 +68,9 @@ func (a *Agent) Profile(args *structs.AgentPprofRequest, reply *structs.AgentPpr } } - // Check ACL for agent write - aclObj, err := a.srv.ResolveToken(args.AuthToken) - if err != nil { - return err - } else if aclObj != nil && !aclObj.AllowAgentWrite() { - return structs.ErrPermissionDenied - } - // If ACLs are disabled, EnableDebug must be enabled - if aclObj == nil { - if !a.srv.config.EnableDebug { - return structs.ErrPermissionDenied - } + if aclObj == nil && !a.srv.config.EnableDebug { + return structs.ErrPermissionDenied } // Process the request on this server diff --git a/nomad/structs/errors.go b/nomad/structs/errors.go index c293eda15..2e3e1edd2 100644 --- a/nomad/structs/errors.go +++ b/nomad/structs/errors.go @@ -79,7 +79,7 @@ func IsErrUnknownMethod(err error) bool { } func IsErrRPCCoded(err error) bool { - return err != nil && strings.Contains(err.Error(), errRPCCodedErrorPrefix) + return err != nil && strings.HasPrefix(err.Error(), errRPCCodedErrorPrefix) } // NewErrUnknownAllocation returns a new error caused by the allocation being