yats.git

commit 76869f9f18d8363624df6944378e258c5244de67

Author: Paolo Lulli <paolo@lulli.net>

Enable TLS without balancer

 server/config/config.go | 4 +
 server/rest/mtls.go | 22 +++++++
 server/rest/rest-event.go | 101 +++++++++++++++++++-----------------
 server/rest/rest-metric.go | 110 +++++++++++++++++++++------------------
 server/service-rest.go | 25 +++++---


diff --git a/server/config/config.go b/server/config/config.go
index 2864005276045c5cbed4eceb7bd29f990621cbdb..7e276b83e953a62216c91c25dc00e9f343111cfb 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -48,6 +48,10 @@
 	ArchiveFrequency string `json:"archiveFrequency"`
 	ArchiveDirectory string `json:"archiveDirectory"`
 	IsArchiveNode    string `json:"archiveNode"`
+
+	TlsActive      string `json:"tlsActive"`
+	TlsKeyFile     string `json:"tlsKeyFile"`
+	TlsCertificate string `json:"tlsCertificate"`
 }
 
 func GetConfig(fileName string) Configuration {




diff --git a/server/rest/mtls.go b/server/rest/mtls.go
index bc68bb775d3d5954b4d960b3c41436338a0a917e..49d2a01f4bd6f1c51a14b78830863d9f9779aaab 100644
--- a/server/rest/mtls.go
+++ b/server/rest/mtls.go
@@ -10,8 +10,26 @@  */
 
 package rest
 
-import "github.com/gin-gonic/gin"
+import (
+	"github.com/gin-gonic/gin"
+	"yats-server/config"
+)
 
-func GetClientCN(c *gin.Context) string {
+func GetClientCN(c *gin.Context, cfg config.Configuration) string {
+	if cfg.TlsActive == "true" {
+		s, done := extractCommonName(c)
+		if done {
+			return s
+		}
+		panic("Could not extract common name")
+	}
 	return c.Request.Header.Get("X-SSL-Client-CN")
 }
+
+func extractCommonName(c *gin.Context) (string, bool) {
+	certificates := c.Request.TLS.PeerCertificates
+	if len(certificates) > 0 {
+		return certificates[0].Subject.CommonName, true
+	}
+	panic("Could not extract common name")
+}




diff --git a/server/rest/rest-event.go b/server/rest/rest-event.go
index 46d947ff442c27a21507f4b813c8fbb5c3739d5a..7cac661564009aefb5ec3aaf9bdec3380e5f54cb 100644
--- a/server/rest/rest-event.go
+++ b/server/rest/rest-event.go
@@ -16,6 +16,7 @@ 	"github.com/gin-gonic/gin"
 	"net/http"
 	"strconv"
 	"time"
+	"yats-server/config"
 	"yats-server/db"
 	"yats-server/model"
 )
@@ -31,23 +32,25 @@ // @Param event1 body model.EventModel true "Event body data"
 // @Produce json
 // @Success 202 {string} WriteEvent
 // @Router /event [post]
-func WriteEvent(c *gin.Context) {
-	var event model.EventModel
+func WriteEvent(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var event model.EventModel
 
-	if err := c.BindJSON(&event); err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-		return
-	}
+		if err := c.BindJSON(&event); err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+			return
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("%s / %s ", clientCN, event.Name)
-	if event.Etime == 0 {
-		db.SaveEvent(clientCN, event.Name)
-	} else {
-		unixTimeUTC := time.Unix(event.Etime, 0)
-		db.SaveEventAt(clientCN, unixTimeUTC, event.Name)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("%s / %s ", clientCN, event.Name)
+		if event.Etime == 0 {
+			db.SaveEvent(clientCN, event.Name)
+		} else {
+			unixTimeUTC := time.Unix(event.Etime, 0)
+			db.SaveEventAt(clientCN, unixTimeUTC, event.Name)
+		}
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"})
 	}
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"})
 }
 
 // SearchEvents  godoc
@@ -61,30 +64,32 @@ // @Param event2 body model.EventSearchRequest true "Event query filters"
 // @Produce json
 // @Success 200 {string} SearchEvents
 // @Router /event/search [post]
-func SearchEvents(c *gin.Context) {
-	var event model.EventSearchRequest
+func SearchEvents(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var event model.EventSearchRequest
 
-	if err := c.BindJSON(&event); err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-		return
-	}
+		if err := c.BindJSON(&event); err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+			return
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("Client ID: %s\n ", clientCN)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("Client ID: %s\n ", clientCN)
 
-	var eventsPack []model.EventModel
-	if event.To == 0 {
-		unixTimeUTC := time.Unix(event.From, 0)
-		timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
-		eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100)
-	} else if event.From != 0 {
-		fromUnixTimeUTC := time.Unix(event.From, 0)
-		toUnixTimeUTC := time.Unix(event.To, 0)
-		fromInBytes, _ := fromUnixTimeUTC.UTC().MarshalText()
-		toInBytes, _ := toUnixTimeUTC.UTC().MarshalText()
-		eventsPack = db.EventsBetween(db.Session, clientCN, string(fromInBytes), string(toInBytes), 100)
+		var eventsPack []model.EventModel
+		if event.To == 0 {
+			unixTimeUTC := time.Unix(event.From, 0)
+			timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
+			eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100)
+		} else if event.From != 0 {
+			fromUnixTimeUTC := time.Unix(event.From, 0)
+			toUnixTimeUTC := time.Unix(event.To, 0)
+			fromInBytes, _ := fromUnixTimeUTC.UTC().MarshalText()
+			toInBytes, _ := toUnixTimeUTC.UTC().MarshalText()
+			eventsPack = db.EventsBetween(db.Session, clientCN, string(fromInBytes), string(toInBytes), 100)
+		}
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack})
 	}
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack})
 }
 
 // GetEventsFrom godoc
@@ -99,22 +104,24 @@ // @Produce json
 // @Success 200 {string} SearchEvents
 // @Router /event/{from} [get]
 // @Param from path string true "Starting from timestamp :from"
-func GetEventsFrom(c *gin.Context) {
+func GetEventsFrom(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
 
-	fromParam := c.Param("from")
-	fromParamInt64, err := strconv.ParseInt(fromParam, 10, 64)
-	if err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-	}
+		fromParam := c.Param("from")
+		fromParamInt64, err := strconv.ParseInt(fromParam, 10, 64)
+		if err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("Client ID: %s\n ", clientCN)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("Client ID: %s\n ", clientCN)
 
-	var eventsPack []model.EventModel
+		var eventsPack []model.EventModel
 
-	unixTimeUTC := time.Unix(fromParamInt64, 0)
-	timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
-	eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100)
+		unixTimeUTC := time.Unix(fromParamInt64, 0)
+		timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
+		eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100)
 
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack})
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack})
+	}
 }




diff --git a/server/rest/rest-metric.go b/server/rest/rest-metric.go
index 260775b52f8fcb5985460f3b64281dc414711ee9..1d971744337b0abb0f5f16e0ef8e1864e471c1c2 100644
--- a/server/rest/rest-metric.go
+++ b/server/rest/rest-metric.go
@@ -16,6 +16,7 @@ 	"github.com/gin-gonic/gin"
 	"net/http"
 	"strconv"
 	"time"
+	"yats-server/config"
 	"yats-server/db"
 	"yats-server/model"
 )
@@ -33,25 +34,27 @@ // @Param metric2 body model.MetricModel true "Metric request body"
 // @Produce json
 // @Success 202 {string} WriteMetric
 // @Router /metric [post]
-func WriteMetric(c *gin.Context) {
-	var metric model.MetricModel
+func WriteMetric(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var metric model.MetricModel
 
-	if err := c.BindJSON(&metric); err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-		return
-	}
+		if err := c.BindJSON(&metric); err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+			return
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("%s / %s / %s", clientCN, metric.Name, metric.Value)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("%s / %s / %s", clientCN, metric.Name, metric.Value)
 
-	if metric.Mtime != 0 {
-		unixTimeUTC := time.Unix(metric.Mtime, 0)
-		db.SaveMetricAt(clientCN, unixTimeUTC, metric.Name, metric.Value)
-	} else {
-		db.SaveMetric(clientCN, metric.Name, metric.Value)
+		if metric.Mtime != 0 {
+			unixTimeUTC := time.Unix(metric.Mtime, 0)
+			db.SaveMetricAt(clientCN, unixTimeUTC, metric.Name, metric.Value)
+		} else {
+			db.SaveMetric(clientCN, metric.Name, metric.Value)
+		}
+
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"})
 	}
-
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"})
 }
 
 // SearchMetrics  godoc
@@ -65,36 +68,38 @@ // @Param metric1 body model.MetricSearchRequest true "Metric query filters"
 // @Produce json
 // @Success 200 {string} WriteMetric
 // @Router /metric/search [post]
-func SearchMetrics(c *gin.Context) {
-	var metric model.MetricSearchRequest
+func SearchMetrics(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var metric model.MetricSearchRequest
 
-	if err := c.BindJSON(&metric); err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-		return
-	}
+		if err := c.BindJSON(&metric); err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+			return
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("%s / %s ", clientCN, metric.Name)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("%s / %s ", clientCN, metric.Name)
 
-	var metricsPack []model.MetricModel
+		var metricsPack []model.MetricModel
 
-	if metric.To == 0 {
-		unixTimeUTC := time.Unix(metric.From, 0)
-		timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
-		metricsPack = db.MetricsFrom(db.Session, clientCN, metric.Name, string(timeAsBytes), 100)
-	} else if metric.From != 0 {
-		fromUnixTimeUTC := time.Unix(metric.From, 0)
-		toUnixTimeUTC := time.Unix(metric.To, 0)
-		fromInBytes, _ := fromUnixTimeUTC.UTC().MarshalText()
-		toInBytes, _ := toUnixTimeUTC.UTC().MarshalText()
-		metricsPack = db.MetricsBetween(db.Session, clientCN, metric.Name, string(fromInBytes), string(toInBytes), 100)
+		if metric.To == 0 {
+			unixTimeUTC := time.Unix(metric.From, 0)
+			timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
+			metricsPack = db.MetricsFrom(db.Session, clientCN, metric.Name, string(timeAsBytes), 100)
+		} else if metric.From != 0 {
+			fromUnixTimeUTC := time.Unix(metric.From, 0)
+			toUnixTimeUTC := time.Unix(metric.To, 0)
+			fromInBytes, _ := fromUnixTimeUTC.UTC().MarshalText()
+			toInBytes, _ := toUnixTimeUTC.UTC().MarshalText()
+			metricsPack = db.MetricsBetween(db.Session, clientCN, metric.Name, string(fromInBytes), string(toInBytes), 100)
+		}
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": metricsPack})
 	}
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": metricsPack})
 }
 
 // SearchMetricsFrom SearchMetrics  godoc
 // @Param X-SSL-Client-CN header string true "clientCN"
-// @Summary Get the spcific metric {name} starting from the epoch {from}
+// @Summary Get the specific metric {name} starting from the epoch {from}
 // @Schemes
 // @Description search metrics after the specified timestamp
 // @Tags Metrics
@@ -103,24 +108,27 @@ // @Success 200 {string} []model.MetricModel
 // @Router /metric/{name}/{from} [get]
 // @Param name path string true "Metric Name :name"
 // @Param from path string true "Starting from epoch :from"
-func SearchMetricsFrom(c *gin.Context) {
-	var metric model.MetricSearchRequest
+func SearchMetricsFrom(cfg config.Configuration) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var metric model.MetricSearchRequest
 
-	nameParam := c.Param("name")
-	fromParam := c.Param("from")
-	fromParamInt64, err := strconv.ParseInt(fromParam, 10, 64)
-	if err != nil {
-		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
-	}
+		nameParam := c.Param("name")
+		fromParam := c.Param("from")
+		fromParamInt64, err := strconv.ParseInt(fromParam, 10, 64)
+		if err != nil {
+			c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"})
+		}
 
-	clientCN := GetClientCN(c)
-	fmt.Printf("%s / %s ", clientCN, metric.Name)
+		clientCN := GetClientCN(c, cfg)
+		fmt.Printf("%s / %s ", clientCN, metric.Name)
 
-	var metricsPack []model.MetricModel
+		var metricsPack []model.MetricModel
 
-	unixTimeUTC := time.Unix(fromParamInt64, 0)
-	timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
-	metricsPack = db.MetricsFrom(db.Session, clientCN, nameParam, string(timeAsBytes), 100)
+		unixTimeUTC := time.Unix(fromParamInt64, 0)
+		timeAsBytes, _ := unixTimeUTC.UTC().MarshalText()
+		metricsPack = db.MetricsFrom(db.Session, clientCN, nameParam, string(timeAsBytes), 100)
 
-	c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": metricsPack})
+		c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": metricsPack})
+	}
 }




diff --git a/server/service-rest.go b/server/service-rest.go
index 5baef4d6c5c455e5b50dfcc4713cefa87fc91aa9..e5dd75ce3689905199846e853b234ac5ba04071a 100644
--- a/server/service-rest.go
+++ b/server/service-rest.go
@@ -17,10 +17,10 @@
 	"github.com/gin-gonic/gin"
 )
 
-func RestService(c config.Configuration) {
+func RestService(cfg config.Configuration) {
 
 	//	session = DB
-	address := c.RestAddress
+	address := cfg.RestAddress
 
 	router := gin.Default()
 
@@ -29,16 +29,21 @@
 	router.SetTrustedProxies([]string{"127.0.0.1"})
 	gin.SetMode(gin.ReleaseMode)
 
-	router.POST("/metric", rest.WriteMetric)
-	router.POST("/metric/search", rest.SearchMetrics)
-	router.GET("/metric/:name/:from", rest.SearchMetricsFrom)
+	router.POST("/metric", rest.WriteMetric(cfg))
+	router.POST("/metric/search", rest.SearchMetrics(cfg))
+	router.GET("/metric/:name/:from", rest.SearchMetricsFrom(cfg))
+
+	router.POST("/event", rest.WriteEvent(cfg))
+	router.POST("/event/search", rest.SearchEvents(cfg))
+	router.GET("/event/:from", rest.GetEventsFrom(cfg))
 
-	router.POST("/event", rest.WriteEvent)
-	router.POST("/event/search", rest.SearchEvents)
-	router.GET("/event/:from", rest.GetEventsFrom)
+	router.POST("/position", rest.WritePosition(cfg))
 
 	enableSwaggerEndpoint(router)
 
-	router.Run(address)
-	//router.RunTLS(address, c.CertFile, c.KeyFile)
+	if cfg.TlsActive == "true" {
+		router.RunTLS(address, cfg.TlsCertificate, cfg.TlsKeyFile)
+	} else {
+		router.Run(address)
+	}
 }