mirror of
https://github.com/prymitive/karma
synced 2026-05-11 03:46:48 +00:00
Fixes #190. With this feature unsee can be configured to proxy requests to selected Alertmanager instances, if it's enabled unsee silence form will send a request via unsee rather than directly. This allows users to manage silences in environments where they have access to unsee but not to Alertmanager. Only silences endpoints on Alertmanager API are proxied.
164 lines
4.1 KiB
Go
164 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cloudflare/unsee/internal/alertmanager"
|
|
"github.com/cloudflare/unsee/internal/config"
|
|
"github.com/cloudflare/unsee/internal/models"
|
|
"github.com/cloudflare/unsee/internal/transform"
|
|
|
|
"github.com/DeanThompson/ginpprof"
|
|
"github.com/gin-contrib/gzip"
|
|
"github.com/gin-contrib/static"
|
|
"github.com/gin-gonic/contrib/sentry"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/patrickmn/go-cache"
|
|
|
|
raven "github.com/getsentry/raven-go"
|
|
ginprometheus "github.com/mcuadros/go-gin-prometheus"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
version = "dev"
|
|
|
|
// ticker is a timer used by background loop that will keep pulling
|
|
// data from Alertmanager
|
|
ticker *time.Ticker
|
|
|
|
// apiCache will be used to keep short lived copy of JSON reponses generated for the UI
|
|
// If there are requests with the same filter we should respond from cache
|
|
// rather than do all the filtering every time
|
|
apiCache *cache.Cache
|
|
)
|
|
|
|
func getViewURL(sub string) string {
|
|
u := path.Join(config.Config.Listen.Prefix, sub)
|
|
if strings.HasSuffix(sub, "/") {
|
|
// if sub path had trailing slash then add it here, since path.Join will
|
|
// skip it
|
|
return u + "/"
|
|
}
|
|
return u
|
|
}
|
|
|
|
func setupRouter(router *gin.Engine) {
|
|
router.Use(gzip.Gzip(gzip.DefaultCompression))
|
|
router.Use(static.Serve(getViewURL("/static"), newBinaryFileSystem("static")))
|
|
|
|
router.GET(getViewURL("/favicon.ico"), favicon)
|
|
router.GET(getViewURL("/"), index)
|
|
router.GET(getViewURL("/help"), help)
|
|
router.GET(getViewURL("/alerts.json"), alerts)
|
|
router.GET(getViewURL("/autocomplete.json"), autocomplete)
|
|
}
|
|
|
|
func setupUpstreams() {
|
|
for _, s := range config.Config.Alertmanager.Servers {
|
|
err := alertmanager.NewAlertmanager(s.Name, s.URI, s.Timeout, s.Proxy)
|
|
if err != nil {
|
|
log.Fatalf("Failed to configure Alertmanager '%s' with URI '%s': %s", s.Name, s.URI, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupLogger() {
|
|
switch config.Config.Log.Level {
|
|
case "debug":
|
|
log.SetLevel(log.DebugLevel)
|
|
case "info":
|
|
log.SetLevel(log.InfoLevel)
|
|
case "warning":
|
|
log.SetLevel(log.WarnLevel)
|
|
case "error":
|
|
log.SetLevel(log.ErrorLevel)
|
|
case "fatal":
|
|
log.SetLevel(log.FatalLevel)
|
|
case "panic":
|
|
log.SetLevel(log.PanicLevel)
|
|
default:
|
|
log.Fatalf("Unknown log level '%s'", config.Config.Log.Level)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
config.Config.Read()
|
|
setupLogger()
|
|
|
|
// timer duration cannot be zero second or a negative one
|
|
if config.Config.Alertmanager.Interval <= time.Second*0 {
|
|
log.Fatalf("Invalid AlertmanagerTTL value '%v'", config.Config.Alertmanager.Interval)
|
|
}
|
|
|
|
log.Infof("Version: %s", version)
|
|
if config.Config.Log.Config {
|
|
config.Config.LogValues()
|
|
}
|
|
|
|
jiraRules := []models.JiraRule{}
|
|
for _, rule := range config.Config.JIRA {
|
|
jiraRules = append(jiraRules, models.JiraRule{Regex: rule.Regex, URI: rule.URI})
|
|
}
|
|
transform.ParseRules(jiraRules)
|
|
|
|
apiCache = cache.New(cache.NoExpiration, 10*time.Second)
|
|
|
|
setupUpstreams()
|
|
|
|
if len(alertmanager.GetAlertmanagers()) == 0 {
|
|
log.Fatal("No valid Alertmanager URIs defined")
|
|
}
|
|
|
|
// before we start try to fetch data from Alertmanager
|
|
log.Info("Initial Alertmanager query")
|
|
pullFromAlertmanager()
|
|
log.Info("Done, starting HTTP server")
|
|
|
|
// background loop that will fetch updates from Alertmanager
|
|
ticker = time.NewTicker(config.Config.Alertmanager.Interval)
|
|
go Tick()
|
|
|
|
switch config.Config.Debug {
|
|
case true:
|
|
gin.SetMode(gin.DebugMode)
|
|
case false:
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
|
|
router := gin.New()
|
|
|
|
var t *template.Template
|
|
t = loadTemplates(t, "templates")
|
|
t = loadTemplates(t, "static/dist/templates")
|
|
router.SetHTMLTemplate(t)
|
|
|
|
prom := ginprometheus.NewPrometheus("gin")
|
|
prom.MetricsPath = getViewURL("/metrics")
|
|
prom.Use(router)
|
|
|
|
if config.Config.Debug {
|
|
ginpprof.Wrapper(router)
|
|
}
|
|
|
|
if config.Config.Sentry.Public != "" {
|
|
raven.SetRelease(version)
|
|
router.Use(sentry.Recovery(raven.DefaultClient, false))
|
|
}
|
|
|
|
setupRouter(router)
|
|
for _, am := range alertmanager.GetAlertmanagers() {
|
|
setupRouterProxyHandlers(router, am)
|
|
}
|
|
listen := fmt.Sprintf("%s:%d", config.Config.Listen.Address, config.Config.Listen.Port)
|
|
log.Infof("Listening on %s", listen)
|
|
err := router.Run(listen)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|