readiness.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package metrics
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "github.com/google/uuid"
  7. "github.com/cloudflare/cloudflared/tunnelstate"
  8. )
  9. // ReadyServer serves HTTP 200 if the tunnel can serve traffic. Intended for k8s readiness checks.
  10. type ReadyServer struct {
  11. clientID uuid.UUID
  12. tracker *tunnelstate.ConnTracker
  13. }
  14. // NewReadyServer initializes a ReadyServer and starts listening for dis/connection events.
  15. func NewReadyServer(
  16. clientID uuid.UUID,
  17. tracker *tunnelstate.ConnTracker,
  18. ) *ReadyServer {
  19. return &ReadyServer{
  20. clientID,
  21. tracker,
  22. }
  23. }
  24. type body struct {
  25. Status int `json:"status"`
  26. ReadyConnections uint `json:"readyConnections"`
  27. ConnectorID uuid.UUID `json:"connectorId"`
  28. }
  29. // ServeHTTP responds with HTTP 200 if the tunnel is connected to the edge.
  30. func (rs *ReadyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  31. statusCode, readyConnections := rs.makeResponse()
  32. w.WriteHeader(statusCode)
  33. body := body{
  34. Status: statusCode,
  35. ReadyConnections: readyConnections,
  36. ConnectorID: rs.clientID,
  37. }
  38. msg, err := json.Marshal(body)
  39. if err != nil {
  40. _, _ = fmt.Fprintf(w, `{"error": "%s"}`, err)
  41. }
  42. _, _ = w.Write(msg)
  43. }
  44. // This is the bulk of the logic for ServeHTTP, broken into its own pure function
  45. // to make unit testing easy.
  46. func (rs *ReadyServer) makeResponse() (statusCode int, readyConnections uint) {
  47. readyConnections = rs.tracker.CountActiveConns()
  48. if readyConnections > 0 {
  49. return http.StatusOK, readyConnections
  50. } else {
  51. return http.StatusServiceUnavailable, readyConnections
  52. }
  53. }