Skip to content

Commit

Permalink
common web, refactor route finding/handling
Browse files Browse the repository at this point in the history
* less duplication between alertmanager api and rest of the web handlers
* no need to replicate the context key
  • Loading branch information
BuJo committed Jan 29, 2024
1 parent 3df7001 commit 0df62b4
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 53 deletions.
3 changes: 2 additions & 1 deletion pkg/web/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"path/filepath"
"strings"

"github.com/synyx/tuwat/pkg/web/common"
"github.com/uptrace/opentelemetry-go-extra/otelzap"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
Expand Down Expand Up @@ -87,7 +88,7 @@ func (h *webHandler) ssealerts(w http.ResponseWriter, req *http.Request) {
}
}()

dashboardName := getField(req, 0)
dashboardName := common.GetField(req, 0)

renderer, cancel := h.sseRenderer(w, req, "alerts.gohtml")
defer cancel()
Expand Down
22 changes: 2 additions & 20 deletions pkg/web/api/alertmanager/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"net/http"
"slices"
"strings"
"time"

"github.com/synyx/tuwat/pkg/aggregation"
Expand Down Expand Up @@ -48,29 +47,12 @@ func (h *alertmanagerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
}

http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)

}
}()

var allow []string
for _, route := range h.routes {
matches := route.Regex.FindStringSubmatch(r.URL.Path)
if len(matches) > 0 {
if r.Method != route.Method {
allow = append(allow, route.Method)
continue
}
route.Handler(w, r.WithContext(r.Context()))
return
}
}
if len(allow) > 0 {
w.Header().Set("Allow", strings.Join(allow, ", "))
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
return
if ok := common.HandleRoute(h.routes, w, r); !ok {
http.Error(w, "404 not found", http.StatusNotFound)
}

http.Error(w, "404 not found", http.StatusNotFound)
}

func (h *alertmanagerHandler) status(w http.ResponseWriter, _ *http.Request) {
Expand Down
33 changes: 33 additions & 0 deletions pkg/web/common/routing.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package common

import (
"context"
"net/http"
"regexp"
"strings"
)

func NewRoute(method, pattern string, handler http.HandlerFunc) Route {
Expand All @@ -14,3 +16,34 @@ type Route struct {
Regex *regexp.Regexp
Handler http.HandlerFunc
}

func HandleRoute(routes []Route, w http.ResponseWriter, r *http.Request) bool {

var allow []string
for _, route := range routes {
matches := route.Regex.FindStringSubmatch(r.URL.Path)
if len(matches) > 0 {
if r.Method != route.Method {
allow = append(allow, route.Method)
continue
}
ctx := context.WithValue(r.Context(), ctxKey{}, matches[1:])
route.Handler(w, r.WithContext(ctx))
return true
}
}
if len(allow) > 0 {
w.Header().Set("Allow", strings.Join(allow, ", "))
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
return true
}

return false
}

type ctxKey struct{}

func GetField(r *http.Request, index int) string {
fields := r.Context().Value(ctxKey{}).([]string)
return fields[index]
}
10 changes: 7 additions & 3 deletions pkg/web/silence.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package web

import "net/http"
import (
"net/http"

"github.com/synyx/tuwat/pkg/web/common"
)

func (h *webHandler) silence(w http.ResponseWriter, req *http.Request) {

Expand All @@ -9,12 +13,12 @@ func (h *webHandler) silence(w http.ResponseWriter, req *http.Request) {
user = hdr
}

alertId := getField(req, 0)
alertId := common.GetField(req, 0)

h.aggregator.Silence(req.Context(), alertId, user)

if req.Header.Get("Accept") == "text/vnd.turbo-stream.html" {
dashboardName := getField(req, 0)
dashboardName := common.GetField(req, 0)
renderer := h.partialRenderer(req, "alerts.gohtml")
aggregate := h.aggregator.Alerts(dashboardName)
renderer(w, 200, webContent{Content: aggregate})
Expand Down
32 changes: 3 additions & 29 deletions pkg/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ import (
"embed"
"encoding/json"
"fmt"
"github.com/synyx/tuwat/pkg/web/common"
html "html/template"
"io/fs"
"net/http"
"os"
"path"
"runtime"
"strings"
"time"

"github.com/synyx/tuwat/pkg/aggregation"
"github.com/synyx/tuwat/pkg/config"
"github.com/synyx/tuwat/pkg/version"
"github.com/synyx/tuwat/pkg/web/common"
"github.com/uptrace/opentelemetry-go-extra/otelzap"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
Expand Down Expand Up @@ -89,30 +88,12 @@ func (h *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)

}
}()

var allow []string
for _, route := range h.routes {
matches := route.Regex.FindStringSubmatch(r.URL.Path)
if len(matches) > 0 {
if r.Method != route.Method {
allow = append(allow, route.Method)
continue
}
ctx := context.WithValue(r.Context(), ctxKey{}, matches[1:])
route.Handler(w, r.WithContext(ctx))
return
}
if ok := common.HandleRoute(h.routes, w, r); !ok {
h.notFound(w, r)
}
if len(allow) > 0 {
w.Header().Set("Allow", strings.Join(allow, ", "))
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
return
}

h.notFound(w, r)
}

type renderFunc func(w http.ResponseWriter, statusCode int, data webContent)
Expand Down Expand Up @@ -312,13 +293,6 @@ func (h *webHandler) wsRenderer(s *websocket.Conn, patterns ...string) wsRenderF
}
}

type ctxKey struct{}

func getField(r *http.Request, index int) string {
fields := r.Context().Value(ctxKey{}).([]string)
return fields[index]
}

func niceDuration(d time.Duration) string {
if d > 2*time.Hour*24 {
return fmt.Sprintf("%.0fd", d.Hours()/24)
Expand Down

0 comments on commit 0df62b4

Please sign in to comment.