Skip to content

Commit

Permalink
fix(pkg/server): run metrics server under HTTPS
Browse files Browse the repository at this point in the history
Signed-off-by: Stefano Scafiti <[email protected]>
  • Loading branch information
ostafen committed Aug 30, 2024
1 parent 2a3d382 commit ba68847
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 32 deletions.
32 changes: 22 additions & 10 deletions pkg/server/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package server

import (
"context"
"crypto/tls"
"encoding/json"
"expvar"
"net/http"
Expand Down Expand Up @@ -61,16 +62,20 @@ type MetricsCollection struct {
RemoteStorageKind *prometheus.GaugeVec

computeLoadedDBSize func() float64
LoadedDatabases prometheus.Gauge
LoadedDatabases prometheus.Gauge

computeSessionCount func() float64
ActiveSessions prometheus.Gauge
ActiveSessions prometheus.Gauge
}

var metricsNamespace = "immudb"

// WithUptimeCounter ...
func (mc *MetricsCollection) WithUptimeCounter(f func() float64) {
if mc.UptimeCounter != nil {
return
}

mc.UptimeCounter = promauto.NewCounterFunc(
prometheus.CounterOpts{
Namespace: metricsNamespace,
Expand Down Expand Up @@ -196,6 +201,7 @@ var Metrics = MetricsCollection{
func StartMetrics(
updateInterval time.Duration,
addr string,
tlsConfig *tls.Config,
l logger.Logger,
uptimeCounter func() float64,
computeDBSizes func() map[string]float64,
Expand All @@ -204,7 +210,6 @@ func StartMetrics(
computeSessionCount func() float64,
addPProf bool,
) *http.Server {

Metrics.WithUptimeCounter(uptimeCounter)
Metrics.WithComputeDBSizes(computeDBSizes)
Metrics.WithComputeDBEntries(computeDBEntries)
Expand Down Expand Up @@ -232,19 +237,26 @@ func StartMetrics(
mux.HandleFunc("/readyz", corsHandlerFunc(ImmudbHealthHandlerFunc()))
mux.HandleFunc("/livez", corsHandlerFunc(ImmudbHealthHandlerFunc()))
mux.HandleFunc("/version", corsHandlerFunc(ImmudbVersionHandlerFunc))

server := &http.Server{Addr: addr, Handler: mux}
server.TLSConfig = tlsConfig

go func() {
if err := server.ListenAndServe(); err != nil {
if err == http.ErrServerClosed {
l.Debugf("Metrics http server closed")
} else {
l.Errorf("Metrics error: %s", err)
}
var err error
if tlsConfig != nil && len(tlsConfig.Certificates) > 0 {
l.Infof("metrics server enabled on %s (https)", addr)
err = server.ListenAndServeTLS("", "")
} else {
l.Infof("metrics server enabled on %s (http)", addr)
err = server.ListenAndServe()
}

if err == http.ErrServerClosed {
l.Debugf("Metrics http server closed")
} else {
l.Errorf("Metrics error: %s", err)
}
}()

return server
}

Expand Down
38 changes: 37 additions & 1 deletion pkg/server/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package server

import (
"context"
"crypto/tls"
"encoding/json"
"net"
"net/http"
Expand All @@ -31,10 +32,16 @@ import (
"google.golang.org/grpc/peer"
)

func TestStartMetrics(t *testing.T) {
func TestStartMetricsHTTP(t *testing.T) {
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{},
ClientAuth: tls.VerifyClientCertIfGiven,
}

server := StartMetrics(
100*time.Millisecond,
"0.0.0.0:9999",
tlsConfig,
&mockLogger{},
func() float64 { return 0 },
func() map[string]float64 { return make(map[string]float64) },
Expand All @@ -49,6 +56,34 @@ func TestStartMetrics(t *testing.T) {
require.IsType(t, &http.Server{}, server)
}

func TestStartMetricsHTTPS(t *testing.T) {
tlsConfig := tlsConfigTest(t)

server := StartMetrics(
100*time.Millisecond,
"0.0.0.0:9999",
tlsConfig,
&mockLogger{},
func() float64 { return 0 },
func() map[string]float64 { return make(map[string]float64) },
func() map[string]float64 { return make(map[string]float64) },
func() float64 { return 1.0 },
func() float64 { return 2.0 },
false,
)
time.Sleep(200 * time.Millisecond)
defer server.Close()

require.IsType(t, &http.Server{}, server)

tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
client := &http.Client{Transport: tr}
require.Eventually(t, func() bool {
_, err := client.Get("https://0.0.0.0:9999")
return err == nil
}, 10*time.Second, 30*time.Millisecond)
}

func TestStartMetricsFail(t *testing.T) {
save_metricsNamespace := metricsNamespace
metricsNamespace = "failimmudb"
Expand All @@ -57,6 +92,7 @@ func TestStartMetricsFail(t *testing.T) {
server := StartMetrics(
100*time.Millisecond,
"999.999.999.999:9999",
nil,
&mockLogger{},
func() float64 { return 0 },
func() map[string]float64 { return make(map[string]float64) },
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func (s *ImmuServer) Start() (err error) {
startedAt = time.Now()

if s.Options.MetricsServer {
s.metricsServer = StartMetrics(1*time.Minute, s.Options.MetricsBind(), s.Logger, s.metricFuncServerUptimeCounter,
s.metricsServer = StartMetrics(1*time.Minute, s.Options.MetricsBind(), s.Options.TLSConfig, s.Logger, s.metricFuncServerUptimeCounter,
s.metricFuncComputeDBSizes, s.metricFuncComputeDBEntries, s.metricFuncComputeLoadedDBSize, s.metricFuncComputeSessionCount,
s.Options.PProf)
defer func() {
Expand Down
44 changes: 24 additions & 20 deletions pkg/server/webserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,8 @@ func TestStartWebServerHTTPS(t *testing.T) {

options := DefaultOptions().WithDir(dir)
server := DefaultServer().WithOptions(options).(*ImmuServer)
certPem := []byte(`-----BEGIN CERTIFICATE-----
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
6MF9+Yw1Yy0t
-----END CERTIFICATE-----`)
keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
-----END EC PRIVATE KEY-----`)

cert, err := tls.X509KeyPair(certPem, keyPem)
require.NoError(t, err)
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}

tlsConfig := tlsConfigTest(t)
webServer, err := startWebServer(
context.Background(),
options.Bind(),
Expand All @@ -101,3 +82,26 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
return err == nil
}, 10*time.Second, 30*time.Millisecond)
}

func tlsConfigTest(t *testing.T) *tls.Config {
certPem := []byte(`-----BEGIN CERTIFICATE-----
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
6MF9+Yw1Yy0t
-----END CERTIFICATE-----`)
keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
-----END EC PRIVATE KEY-----`)

cert, err := tls.X509KeyPair(certPem, keyPem)
require.NoError(t, err)
return &tls.Config{Certificates: []tls.Certificate{cert}}
}

0 comments on commit ba68847

Please sign in to comment.