diff --git a/command/agent/command.go b/command/agent/command.go index 6a0e6508f..3550ba8b1 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -36,10 +36,11 @@ type Command struct { Ui cli.Ui ShutdownCh <-chan struct{} - args []string - agent *Agent - logFilter *logutils.LevelFilter - logOutput io.Writer + args []string + agent *Agent + httpServer *HTTPServer + logFilter *logutils.LevelFilter + logOutput io.Writer } func (c *Command) readConfig() *Config { @@ -145,6 +146,14 @@ func (c *Command) setupAgent(config *Config, logOutput io.Writer) error { } c.agent = agent + http, err := NewHTTPServer(agent, config, logOutput) + if err != nil { + agent.Shutdown() + c.Ui.Error(fmt.Sprintf("Error starting http server: %s", err)) + return err + } + c.httpServer = http + // Setup update checking if !config.DisableUpdateCheck { version := config.Version diff --git a/command/agent/config.go b/command/agent/config.go index 38330ff93..b1c443cb2 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -27,6 +27,9 @@ type Config struct { // If not specified, 127.0.0.1:4646 is used. HttpAddr string `hcl:"http_addr"` + // EnableDebug is used to enable debugging HTTP endpoints + EnableDebug bool `hcl:"enable_debug"` + // Client has our client related settings Client *ClientConfig `hcl:"client"` @@ -105,7 +108,9 @@ func DevConfig() *Config { Server: &ServerConfig{ Enabled: true, }, - DevMode: true, + DevMode: true, + EnableDebug: true, + DisableAnonymousSignature: true, } } diff --git a/command/agent/http.go b/command/agent/http.go new file mode 100644 index 000000000..41d1a1a52 --- /dev/null +++ b/command/agent/http.go @@ -0,0 +1,61 @@ +package agent + +import ( + "fmt" + "io" + "log" + "net" + "net/http" + "net/http/pprof" +) + +// HTTPServer is used to wrap an Agent and expose it over an HTTP interface +type HTTPServer struct { + agent *Agent + mux *http.ServeMux + listener net.Listener + logger *log.Logger +} + +// NewHTTPServer starts new HTTP server over the agent +func NewHTTPServer(agent *Agent, config *Config, logOutput io.Writer) (*HTTPServer, error) { + // Start the listener + ln, err := net.Listen("tcp", config.HttpAddr) + if err != nil { + return nil, fmt.Errorf("failed to start HTTP listener on %s: %v", config.HttpAddr, err) + } + + // Create the mux + mux := http.NewServeMux() + + // Create the server + srv := &HTTPServer{ + agent: agent, + mux: mux, + listener: ln, + logger: log.New(logOutput, "", log.LstdFlags), + } + srv.registerHandlers(config.EnableDebug) + + // Start the server + go http.Serve(ln, mux) + return srv, nil +} + +// Shutdown is used to shutdown the HTTP server +func (s *HTTPServer) Shutdown() { + if s != nil { + s.logger.Printf("[DEBUG] http: Shutting down http server") + s.listener.Close() + } +} + +// registerHandlers is used to attach our handlers to the mux +func (s *HTTPServer) registerHandlers(enableDebug bool) { + if enableDebug { + s.mux.HandleFunc("/debug/pprof/", pprof.Index) + s.mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + s.mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + } +}