handlers.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package diagnostic
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "os"
  7. "strconv"
  8. "time"
  9. "github.com/google/uuid"
  10. "github.com/rs/zerolog"
  11. "github.com/cloudflare/cloudflared/tunnelstate"
  12. )
  13. type Handler struct {
  14. log *zerolog.Logger
  15. timeout time.Duration
  16. systemCollector SystemCollector
  17. tunnelID uuid.UUID
  18. connectorID uuid.UUID
  19. tracker *tunnelstate.ConnTracker
  20. cliFlags map[string]string
  21. icmpSources []string
  22. }
  23. func NewDiagnosticHandler(
  24. log *zerolog.Logger,
  25. timeout time.Duration,
  26. systemCollector SystemCollector,
  27. tunnelID uuid.UUID,
  28. connectorID uuid.UUID,
  29. tracker *tunnelstate.ConnTracker,
  30. cliFlags map[string]string,
  31. icmpSources []string,
  32. ) *Handler {
  33. logger := log.With().Logger()
  34. if timeout == 0 {
  35. timeout = defaultCollectorTimeout
  36. }
  37. cliFlags[configurationKeyUID] = strconv.Itoa(os.Getuid())
  38. return &Handler{
  39. log: &logger,
  40. timeout: timeout,
  41. systemCollector: systemCollector,
  42. tunnelID: tunnelID,
  43. connectorID: connectorID,
  44. tracker: tracker,
  45. cliFlags: cliFlags,
  46. icmpSources: icmpSources,
  47. }
  48. }
  49. func (handler *Handler) InstallEndpoints(router *http.ServeMux) {
  50. router.HandleFunc(cliConfigurationEndpoint, handler.ConfigurationHandler)
  51. router.HandleFunc(tunnelStateEndpoint, handler.TunnelStateHandler)
  52. router.HandleFunc(systemInformationEndpoint, handler.SystemHandler)
  53. }
  54. type SystemInformationResponse struct {
  55. Info *SystemInformation `json:"info"`
  56. Err error `json:"errors"`
  57. }
  58. func (handler *Handler) SystemHandler(writer http.ResponseWriter, request *http.Request) {
  59. logger := handler.log.With().Str(collectorField, systemCollectorName).Logger()
  60. logger.Info().Msg("Collection started")
  61. defer logger.Info().Msg("Collection finished")
  62. ctx, cancel := context.WithTimeout(request.Context(), handler.timeout)
  63. defer cancel()
  64. info, err := handler.systemCollector.Collect(ctx)
  65. response := SystemInformationResponse{
  66. Info: info,
  67. Err: err,
  68. }
  69. encoder := json.NewEncoder(writer)
  70. err = encoder.Encode(response)
  71. if err != nil {
  72. logger.Error().Err(err).Msgf("error occurred whilst serializing information")
  73. writer.WriteHeader(http.StatusInternalServerError)
  74. }
  75. }
  76. type TunnelState struct {
  77. TunnelID uuid.UUID `json:"tunnelID,omitempty"`
  78. ConnectorID uuid.UUID `json:"connectorID,omitempty"`
  79. Connections []tunnelstate.IndexedConnectionInfo `json:"connections,omitempty"`
  80. ICMPSources []string `json:"icmp_sources,omitempty"`
  81. }
  82. func (handler *Handler) TunnelStateHandler(writer http.ResponseWriter, _ *http.Request) {
  83. log := handler.log.With().Str(collectorField, tunnelStateCollectorName).Logger()
  84. log.Info().Msg("Collection started")
  85. defer log.Info().Msg("Collection finished")
  86. body := TunnelState{
  87. handler.tunnelID,
  88. handler.connectorID,
  89. handler.tracker.GetActiveConnections(),
  90. handler.icmpSources,
  91. }
  92. encoder := json.NewEncoder(writer)
  93. err := encoder.Encode(body)
  94. if err != nil {
  95. handler.log.Error().Err(err).Msgf("error occurred whilst serializing information")
  96. writer.WriteHeader(http.StatusInternalServerError)
  97. }
  98. }
  99. func (handler *Handler) ConfigurationHandler(writer http.ResponseWriter, _ *http.Request) {
  100. log := handler.log.With().Str(collectorField, configurationCollectorName).Logger()
  101. log.Info().Msg("Collection started")
  102. defer func() {
  103. log.Info().Msg("Collection finished")
  104. }()
  105. encoder := json.NewEncoder(writer)
  106. err := encoder.Encode(handler.cliFlags)
  107. if err != nil {
  108. handler.log.Error().Err(err).Msgf("error occurred whilst serializing response")
  109. writer.WriteHeader(http.StatusInternalServerError)
  110. }
  111. }
  112. func writeResponse(w http.ResponseWriter, bytes []byte, logger *zerolog.Logger) {
  113. bytesWritten, err := w.Write(bytes)
  114. if err != nil {
  115. logger.Error().Err(err).Msg("error occurred writing response")
  116. } else if bytesWritten != len(bytes) {
  117. logger.Error().Msgf("error incomplete write response %d/%d", bytesWritten, len(bytes))
  118. }
  119. }