Added webserver tests
This commit is contained in:
+27
-17
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/render"
|
||||
log "scm.yoorie.de/go-lib/gelf"
|
||||
)
|
||||
|
||||
@@ -16,6 +16,7 @@ type healthChecker struct {
|
||||
message string
|
||||
healthy bool
|
||||
lastChecked time.Time
|
||||
startTime time.Time
|
||||
period int
|
||||
ticker *time.Ticker
|
||||
done chan bool
|
||||
@@ -23,9 +24,15 @@ type healthChecker struct {
|
||||
checkFunc func() (bool, string)
|
||||
}
|
||||
|
||||
type HealthData struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
LastChecked time.Time `json:"lastChecked"`
|
||||
}
|
||||
|
||||
func newHealthChecker(checkFunction func() (bool, string)) *healthChecker {
|
||||
hc := &healthChecker{}
|
||||
hc.checkFunc = checkFunction
|
||||
hc.startTime = time.Now()
|
||||
return hc
|
||||
}
|
||||
|
||||
@@ -66,40 +73,43 @@ func (h *healthChecker) doCheck() {
|
||||
h.lastChecked = time.Now()
|
||||
}
|
||||
|
||||
// Routes add routes for liveness and readyness probes
|
||||
/* Routes add routes for liveness and readyness probes
|
||||
func (h *healthChecker) Routes() *chi.Mux {
|
||||
router := chi.NewRouter()
|
||||
router.Get("/healthz", h.healthyEndpoint)
|
||||
router.Get("/readyz", h.readinessEndpoint)
|
||||
return router
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
GetHealthyEndpoint is this service healthy
|
||||
*/
|
||||
func (h *healthChecker) healthyEndpoint(response http.ResponseWriter, req *http.Request) {
|
||||
func (h *healthChecker) healthyEndpoint(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
t := time.Now()
|
||||
status := http.StatusOK
|
||||
healtData := &HealthData{
|
||||
Message: "service up and running",
|
||||
LastChecked: h.lastChecked,
|
||||
}
|
||||
if t.Sub(h.lastChecked) > (time.Second * time.Duration(2*h.period)) {
|
||||
h.healthy = false
|
||||
h.message = "Healthcheck not running"
|
||||
}
|
||||
response.Header().Add("Content-Type", "application/json")
|
||||
if h.healthy {
|
||||
response.WriteHeader(http.StatusOK)
|
||||
message := fmt.Sprintf(`{ "message": "service up and running", "lastCheck": "%s" }`, h.lastChecked.String())
|
||||
response.Write([]byte(message))
|
||||
} else {
|
||||
response.WriteHeader(http.StatusServiceUnavailable)
|
||||
message := fmt.Sprintf(`{ "message": "service is unavailable: %s", "lastCheck": "%s" }`, h.message, h.lastChecked.String())
|
||||
response.Write([]byte(message))
|
||||
if !h.healthy {
|
||||
status = http.StatusServiceUnavailable
|
||||
healtData.Message = fmt.Sprintf("service is unavailable: %s", h.message)
|
||||
}
|
||||
responseWriter.WriteHeader(status)
|
||||
render.JSON(responseWriter, request, healtData)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
GetReadinessEndpoint is this service ready for taking requests
|
||||
*/
|
||||
func (h *healthChecker) readinessEndpoint(response http.ResponseWriter, req *http.Request) {
|
||||
response.Header().Add("Content-Type", "application/json")
|
||||
response.WriteHeader(http.StatusOK)
|
||||
response.Write([]byte(`{ "message": "service started" }`))
|
||||
func (h *healthChecker) readinessEndpoint(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
render.JSON(responseWriter, request, &HealthData{
|
||||
Message: "service is ready",
|
||||
LastChecked: h.startTime,
|
||||
})
|
||||
}
|
||||
|
||||
+38
-14
@@ -4,6 +4,7 @@ import (
|
||||
"compress/flate"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
@@ -21,11 +23,11 @@ import (
|
||||
|
||||
type WebServerConfiguration struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Port int `default:"7080" yaml:"port"`
|
||||
SslPort int `yaml:"sslport"`
|
||||
SslCert string `yaml:"sslcert"`
|
||||
SslKey string `yaml:"sslkey"`
|
||||
HealthCheckPeriod int `yaml:"healthcheckperiod"`
|
||||
HealthCheckPeriod int `default:"30" yaml:"healthcheckperiod"`
|
||||
CertificateGenerationParams TLSCertificateGenerationParams `yaml:"tlsgenerationparams"`
|
||||
}
|
||||
|
||||
@@ -39,7 +41,6 @@ type WebServer struct {
|
||||
serviceConfig *WebServerConfiguration
|
||||
sslsrv *http.Server
|
||||
srv *http.Server
|
||||
ssl bool
|
||||
healthChecker *healthChecker
|
||||
router *chi.Mux
|
||||
healthRouter *chi.Mux
|
||||
@@ -47,6 +48,17 @@ type WebServer struct {
|
||||
HealthCheck func() (bool, string)
|
||||
}
|
||||
|
||||
func NewWebServer(config *WebServerConfiguration) (*WebServer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config may not be null")
|
||||
}
|
||||
defaults.Set(config)
|
||||
return &WebServer{
|
||||
serviceConfig: config,
|
||||
mounts: make(map[string]http.Handler),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (server *WebServer) healthRoutes() *chi.Mux {
|
||||
compressor := middleware.NewCompressor(flate.DefaultCompression)
|
||||
router := chi.NewRouter()
|
||||
@@ -55,10 +67,15 @@ func (server *WebServer) healthRoutes() *chi.Mux {
|
||||
compressor.Handler,
|
||||
middleware.Recoverer,
|
||||
)
|
||||
router.Mount("/", server.healthChecker.Routes())
|
||||
router.Get("/healthz", server.healthChecker.healthyEndpoint)
|
||||
router.Get("/readyz", server.healthChecker.readinessEndpoint)
|
||||
return router
|
||||
}
|
||||
|
||||
func (server *WebServer) isSsl() bool {
|
||||
return server.serviceConfig.SslPort > 0
|
||||
}
|
||||
|
||||
func (server *WebServer) Mount(pattern string, handler http.Handler) {
|
||||
server.mounts[pattern] = handler
|
||||
}
|
||||
@@ -83,6 +100,8 @@ func (server *WebServer) routes() *chi.Mux {
|
||||
for pattern, handler := range server.mounts {
|
||||
router.Mount(pattern, handler)
|
||||
}
|
||||
// clean map
|
||||
server.mounts = make(map[string]http.Handler)
|
||||
return router
|
||||
}
|
||||
|
||||
@@ -157,22 +176,27 @@ func (server *WebServer) performHealthCheck() (bool, string) {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (server *WebServer) Start(config *WebServerConfiguration) error {
|
||||
server.serviceConfig = config
|
||||
hc := newHealthChecker(server.performHealthCheck)
|
||||
hc.start(config.HealthCheckPeriod)
|
||||
func (server *WebServer) Start() error {
|
||||
if server.serviceConfig == nil {
|
||||
return errors.New("use NewWebServer(config) for initialising the web server")
|
||||
}
|
||||
if len(server.mounts) == 0 {
|
||||
return errors.New("No mounts points added")
|
||||
}
|
||||
|
||||
server.ssl = server.serviceConfig.SslPort > 0
|
||||
if server.ssl {
|
||||
server.healthChecker = newHealthChecker(server.performHealthCheck)
|
||||
server.healthChecker.start(server.serviceConfig.HealthCheckPeriod)
|
||||
|
||||
ssl := server.isSsl()
|
||||
if ssl {
|
||||
log.Debugf("Running in SSL mode")
|
||||
}
|
||||
|
||||
server.router = server.routes()
|
||||
|
||||
server.healthRouter = server.healthRoutes()
|
||||
server.router = server.routes()
|
||||
server.DebugRoutes("Main", server.router)
|
||||
server.DebugRoutes("Health", server.healthRouter)
|
||||
if server.ssl {
|
||||
if ssl {
|
||||
err := server.setupSsl()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -268,7 +292,7 @@ func (server *WebServer) Stop() {
|
||||
|
||||
log.Info("Shutting down server ...")
|
||||
server.srv.Shutdown(ctx)
|
||||
if server.ssl {
|
||||
if server.isSsl() {
|
||||
server.sslsrv.Shutdown(ctx)
|
||||
}
|
||||
log.Info("Server has been shutted down")
|
||||
|
||||
Reference in New Issue
Block a user