...

Source file src/edge-infra.dev/pkg/edge/datasync/cushion/server.go

Documentation: edge-infra.dev/pkg/edge/datasync/cushion

     1  package cushion
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/http"
     7  
     8  	"github.com/gin-gonic/gin"
     9  	"github.com/prometheus/client_golang/prometheus/promhttp"
    10  )
    11  
    12  // todo - stolen from chariot which also has a server_test.go
    13  
    14  func init() {
    15  	gin.SetMode(gin.ReleaseMode)
    16  	gin.DisableConsoleColor()
    17  }
    18  
    19  // ServerConfig contains unexported configuration parameters for a Chariot server.
    20  // The fields are set using ServerOption functions.
    21  type ServerConfig struct {
    22  	port     int
    23  	listener net.Listener
    24  }
    25  
    26  // ServerOption functions set unexported private fields in the ServerConfig.
    27  // Use it to set things like the storage backend and port.
    28  type ServerOption func(*ServerConfig) error
    29  
    30  // ServerOptionPort sets the port to listen on. Omitting the ServerOptionPort causes the server to use port 80.
    31  func ServerOptionPort(port int) ServerOption {
    32  	return func(cfg *ServerConfig) error {
    33  		if port <= 0 || port > 65535 {
    34  			return fmt.Errorf("Invalid port number %q", port)
    35  		}
    36  		cfg.port = port
    37  		return nil
    38  	}
    39  }
    40  
    41  // ServerOptionListener is used to set a custom net.Listener for the server.
    42  // This server option is used in tests because some CICD environments don't allow ports to be opened.
    43  func ServerOptionListener(l net.Listener) ServerOption {
    44  	return func(cfg *ServerConfig) error {
    45  		cfg.listener = l
    46  		return nil
    47  	}
    48  }
    49  
    50  // Server represents the Chariot HTTP server.
    51  type Server struct {
    52  	Router *gin.Engine
    53  
    54  	Config ServerConfig
    55  }
    56  
    57  // HealthzEndpoints contains the Server type's http health endpoints for k8s that returns 200 OK.
    58  var HealthzEndpoints = []string{"/healthz", "/cushion/healthz"}
    59  
    60  // MetricsEndpoints contains the Server type's http endpoints for time series metrics (prometheus).
    61  var MetricsEndpoints = []string{"/metrics", "/cushion/metrics"}
    62  
    63  // NewServer creates a Chariot server that runs on the desired port.
    64  func NewServer(options ...ServerOption) (*Server, error) {
    65  	s := &Server{
    66  		Router: gin.New(),
    67  	}
    68  
    69  	for _, option := range options {
    70  		if err := option(&s.Config); err != nil {
    71  			return nil, err
    72  		}
    73  	}
    74  
    75  	// Set port to default HTTP port 80 if not provided as an option.
    76  	if s.Config.port == 0 {
    77  		s.Config.port = 80
    78  	}
    79  
    80  	// healthz endpoints
    81  	for _, hzep := range HealthzEndpoints {
    82  		s.Router.GET(hzep, s.HealthHandlerFunction)
    83  	}
    84  
    85  	// metrics (prometheus) endpoints
    86  	metricsHandlerFunc := gin.WrapH(promhttp.Handler())
    87  	for _, mep := range MetricsEndpoints {
    88  		s.Router.GET(mep, metricsHandlerFunc)
    89  	}
    90  
    91  	return s, nil
    92  }
    93  
    94  // HealthHandlerFunction returns status `200 OK`.
    95  func (s *Server) HealthHandlerFunction(c *gin.Context) {
    96  	c.JSON(http.StatusOK, "UP")
    97  }
    98  
    99  // Run runs the Gin server on the configured port or listener.
   100  func (s *Server) Run() error {
   101  	if s.Config.listener != nil {
   102  		return s.Router.RunListener(s.Config.listener)
   103  	}
   104  	addr := fmt.Sprintf(":%d", s.Config.port)
   105  	return s.Router.Run(addr)
   106  }
   107  

View as plain text