vmalert: make UI and assets links relative (#2831)

* make all links in vmalert relative, so links continue to work even if vmalert sits behind the proxy;
* update vmalert's routing to always have component-unique path prefix, e.g. /vmalert;

See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2825

Signed-off-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
Roman Khavronenko 2022-07-06 10:46:01 +02:00 committed by GitHub
parent edc76286ac
commit 84e7c517d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 716 additions and 690 deletions

View file

@ -1,12 +1,19 @@
{% import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"net/http"
"strings"
) %}
{% func Footer() %}
{% code pathPrefix := httpserver.GetPathPrefix() %}
{% func Footer(r *http.Request) %}
{%code
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
%}
</main>
<script src="{%s pathPrefix %}/static/js/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src="{%s pathPrefix %}/static/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script src="{%s prefix %}static/js/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src="{%s prefix %}static/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script type="text/javascript">
function expandAll() {
$('.collapse').addClass('show');

View file

@ -6,43 +6,47 @@ package tpl
//line app/vmalert/tpl/footer.qtpl:1
import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"net/http"
"strings"
)
//line app/vmalert/tpl/footer.qtpl:5
//line app/vmalert/tpl/footer.qtpl:7
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line app/vmalert/tpl/footer.qtpl:5
//line app/vmalert/tpl/footer.qtpl:7
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line app/vmalert/tpl/footer.qtpl:5
func StreamFooter(qw422016 *qt422016.Writer) {
//line app/vmalert/tpl/footer.qtpl:5
//line app/vmalert/tpl/footer.qtpl:7
func StreamFooter(qw422016 *qt422016.Writer, r *http.Request) {
//line app/vmalert/tpl/footer.qtpl:7
qw422016.N().S(`
`)
//line app/vmalert/tpl/footer.qtpl:6
pathPrefix := httpserver.GetPathPrefix()
`)
//line app/vmalert/tpl/footer.qtpl:9
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
//line app/vmalert/tpl/footer.qtpl:6
//line app/vmalert/tpl/footer.qtpl:13
qw422016.N().S(`
</main>
<script src="`)
//line app/vmalert/tpl/footer.qtpl:8
qw422016.E().S(pathPrefix)
//line app/vmalert/tpl/footer.qtpl:8
qw422016.N().S(`/static/js/jquery-3.6.0.min.js" type="text/javascript"></script>
//line app/vmalert/tpl/footer.qtpl:15
qw422016.E().S(prefix)
//line app/vmalert/tpl/footer.qtpl:15
qw422016.N().S(`static/js/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src="`)
//line app/vmalert/tpl/footer.qtpl:9
qw422016.E().S(pathPrefix)
//line app/vmalert/tpl/footer.qtpl:9
qw422016.N().S(`/static/js/bootstrap.bundle.min.js" type="text/javascript"></script>
//line app/vmalert/tpl/footer.qtpl:16
qw422016.E().S(prefix)
//line app/vmalert/tpl/footer.qtpl:16
qw422016.N().S(`static/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script type="text/javascript">
function expandAll() {
$('.collapse').addClass('show');
@ -75,31 +79,31 @@ func StreamFooter(qw422016 *qt422016.Writer) {
</body>
</html>
`)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
}
//line app/vmalert/tpl/footer.qtpl:41
func WriteFooter(qq422016 qtio422016.Writer) {
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
func WriteFooter(qq422016 qtio422016.Writer, r *http.Request) {
//line app/vmalert/tpl/footer.qtpl:48
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/tpl/footer.qtpl:41
StreamFooter(qw422016)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
StreamFooter(qw422016, r)
//line app/vmalert/tpl/footer.qtpl:48
qt422016.ReleaseWriter(qw422016)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
}
//line app/vmalert/tpl/footer.qtpl:41
func Footer() string {
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
func Footer(r *http.Request) string {
//line app/vmalert/tpl/footer.qtpl:48
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/tpl/footer.qtpl:41
WriteFooter(qb422016)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
WriteFooter(qb422016, r)
//line app/vmalert/tpl/footer.qtpl:48
qs422016 := string(qb422016.B)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
return qs422016
//line app/vmalert/tpl/footer.qtpl:41
//line app/vmalert/tpl/footer.qtpl:48
}

View file

@ -1,14 +1,21 @@
{% import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"strings"
"net/http"
"path"
) %}
{% func Header(title string, pages []NavItem) %}
{% code pathPrefix := httpserver.GetPathPrefix() %}
{% func Header(r *http.Request, navItems []NavItem, title string) %}
{%code
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
%}
<!DOCTYPE html>
<html lang="en">
<head>
<title>vmalert{% if title != "" %} - {%s title %}{% endif %}</title>
<link href="{%s pathPrefix %}/static/css/bootstrap.min.css" rel="stylesheet" />
<link href="{%s prefix %}static/css/bootstrap.min.css" rel="stylesheet" />
<style>
body{
min-height: 75rem;
@ -57,6 +64,37 @@
</style>
</head>
<body>
{%= PrintNavItems(title, pages) %}
{%= printNavItems(r, title, navItems) %}
<main class="px-2">
{% endfunc %}
{% code
type NavItem struct {
Name string
Url string
}
%}
{% func printNavItems(r *http.Request, current string, items []NavItem) %}
{%code
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
%}
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
{% for _, item := range items %}
<li class="nav-item">
<a class="nav-link{% if current == item.Name %} active{% endif %}" href="{%s path.Join(prefix,item.Url) %}">
{%s item.Name %}
</a>
</li>
{% endfor %}
</ul>
</div>
</nav>
{% endfunc %}

View file

@ -6,51 +6,56 @@ package tpl
//line app/vmalert/tpl/header.qtpl:1
import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"net/http"
"path"
"strings"
)
//line app/vmalert/tpl/header.qtpl:5
//line app/vmalert/tpl/header.qtpl:7
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line app/vmalert/tpl/header.qtpl:5
//line app/vmalert/tpl/header.qtpl:7
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line app/vmalert/tpl/header.qtpl:5
func StreamHeader(qw422016 *qt422016.Writer, title string, pages []NavItem) {
//line app/vmalert/tpl/header.qtpl:5
//line app/vmalert/tpl/header.qtpl:7
func StreamHeader(qw422016 *qt422016.Writer, r *http.Request, navItems []NavItem, title string) {
//line app/vmalert/tpl/header.qtpl:7
qw422016.N().S(`
`)
//line app/vmalert/tpl/header.qtpl:6
pathPrefix := httpserver.GetPathPrefix()
//line app/vmalert/tpl/header.qtpl:9
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
//line app/vmalert/tpl/header.qtpl:6
//line app/vmalert/tpl/header.qtpl:13
qw422016.N().S(`
<!DOCTYPE html>
<html lang="en">
<head>
<title>vmalert`)
//line app/vmalert/tpl/header.qtpl:10
//line app/vmalert/tpl/header.qtpl:17
if title != "" {
//line app/vmalert/tpl/header.qtpl:10
//line app/vmalert/tpl/header.qtpl:17
qw422016.N().S(` - `)
//line app/vmalert/tpl/header.qtpl:10
//line app/vmalert/tpl/header.qtpl:17
qw422016.E().S(title)
//line app/vmalert/tpl/header.qtpl:10
//line app/vmalert/tpl/header.qtpl:17
}
//line app/vmalert/tpl/header.qtpl:10
//line app/vmalert/tpl/header.qtpl:17
qw422016.N().S(`</title>
<link href="`)
//line app/vmalert/tpl/header.qtpl:11
qw422016.E().S(pathPrefix)
//line app/vmalert/tpl/header.qtpl:11
qw422016.N().S(`/static/css/bootstrap.min.css" rel="stylesheet" />
//line app/vmalert/tpl/header.qtpl:18
qw422016.E().S(prefix)
//line app/vmalert/tpl/header.qtpl:18
qw422016.N().S(`static/css/bootstrap.min.css" rel="stylesheet" />
<style>
body{
min-height: 75rem;
@ -100,37 +105,124 @@ func StreamHeader(qw422016 *qt422016.Writer, title string, pages []NavItem) {
</head>
<body>
`)
//line app/vmalert/tpl/header.qtpl:60
StreamPrintNavItems(qw422016, title, pages)
//line app/vmalert/tpl/header.qtpl:60
//line app/vmalert/tpl/header.qtpl:67
streamprintNavItems(qw422016, r, title, navItems)
//line app/vmalert/tpl/header.qtpl:67
qw422016.N().S(`
<main class="px-2">
`)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
}
//line app/vmalert/tpl/header.qtpl:62
func WriteHeader(qq422016 qtio422016.Writer, title string, pages []NavItem) {
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
func WriteHeader(qq422016 qtio422016.Writer, r *http.Request, navItems []NavItem, title string) {
//line app/vmalert/tpl/header.qtpl:69
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/tpl/header.qtpl:62
StreamHeader(qw422016, title, pages)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
StreamHeader(qw422016, r, navItems, title)
//line app/vmalert/tpl/header.qtpl:69
qt422016.ReleaseWriter(qw422016)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
}
//line app/vmalert/tpl/header.qtpl:62
func Header(title string, pages []NavItem) string {
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
func Header(r *http.Request, navItems []NavItem, title string) string {
//line app/vmalert/tpl/header.qtpl:69
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/tpl/header.qtpl:62
WriteHeader(qb422016, title, pages)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
WriteHeader(qb422016, r, navItems, title)
//line app/vmalert/tpl/header.qtpl:69
qs422016 := string(qb422016.B)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
return qs422016
//line app/vmalert/tpl/header.qtpl:62
//line app/vmalert/tpl/header.qtpl:69
}
//line app/vmalert/tpl/header.qtpl:73
type NavItem struct {
Name string
Url string
}
//line app/vmalert/tpl/header.qtpl:79
func streamprintNavItems(qw422016 *qt422016.Writer, r *http.Request, current string, items []NavItem) {
//line app/vmalert/tpl/header.qtpl:79
qw422016.N().S(`
`)
//line app/vmalert/tpl/header.qtpl:81
prefix := "/vmalert/"
if strings.HasPrefix(r.URL.Path, prefix) {
prefix = ""
}
//line app/vmalert/tpl/header.qtpl:85
qw422016.N().S(`
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
`)
//line app/vmalert/tpl/header.qtpl:90
for _, item := range items {
//line app/vmalert/tpl/header.qtpl:90
qw422016.N().S(`
<li class="nav-item">
<a class="nav-link`)
//line app/vmalert/tpl/header.qtpl:92
if current == item.Name {
//line app/vmalert/tpl/header.qtpl:92
qw422016.N().S(` active`)
//line app/vmalert/tpl/header.qtpl:92
}
//line app/vmalert/tpl/header.qtpl:92
qw422016.N().S(`" href="`)
//line app/vmalert/tpl/header.qtpl:92
qw422016.E().S(path.Join(prefix, item.Url))
//line app/vmalert/tpl/header.qtpl:92
qw422016.N().S(`">
`)
//line app/vmalert/tpl/header.qtpl:93
qw422016.E().S(item.Name)
//line app/vmalert/tpl/header.qtpl:93
qw422016.N().S(`
</a>
</li>
`)
//line app/vmalert/tpl/header.qtpl:96
}
//line app/vmalert/tpl/header.qtpl:96
qw422016.N().S(`
</ul>
</div>
</nav>
`)
//line app/vmalert/tpl/header.qtpl:100
}
//line app/vmalert/tpl/header.qtpl:100
func writeprintNavItems(qq422016 qtio422016.Writer, r *http.Request, current string, items []NavItem) {
//line app/vmalert/tpl/header.qtpl:100
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/tpl/header.qtpl:100
streamprintNavItems(qw422016, r, current, items)
//line app/vmalert/tpl/header.qtpl:100
qt422016.ReleaseWriter(qw422016)
//line app/vmalert/tpl/header.qtpl:100
}
//line app/vmalert/tpl/header.qtpl:100
func printNavItems(r *http.Request, current string, items []NavItem) string {
//line app/vmalert/tpl/header.qtpl:100
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/tpl/header.qtpl:100
writeprintNavItems(qb422016, r, current, items)
//line app/vmalert/tpl/header.qtpl:100
qs422016 := string(qb422016.B)
//line app/vmalert/tpl/header.qtpl:100
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/tpl/header.qtpl:100
return qs422016
//line app/vmalert/tpl/header.qtpl:100
}

View file

@ -1,25 +0,0 @@
{% code
type NavItem struct {
Name string
Url string
}
%}
{% func PrintNavItems(current string, items []NavItem) %}
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
{% for _, item := range items %}
<li class="nav-item">
<a class="nav-link{% if current == item.Name %} active{% endif %}" href="{%s item.Url %}">
{%s item.Name %}
</a>
</li>
{% endfor %}
</ul>
</div>
</nav>
{% endfunc %}

View file

@ -1,96 +0,0 @@
// Code generated by qtc from "nav.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line app/vmalert/tpl/nav.qtpl:1
package tpl
//line app/vmalert/tpl/nav.qtpl:1
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line app/vmalert/tpl/nav.qtpl:1
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line app/vmalert/tpl/nav.qtpl:2
type NavItem struct {
Name string
Url string
}
//line app/vmalert/tpl/nav.qtpl:8
func StreamPrintNavItems(qw422016 *qt422016.Writer, current string, items []NavItem) {
//line app/vmalert/tpl/nav.qtpl:8
qw422016.N().S(`
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
`)
//line app/vmalert/tpl/nav.qtpl:13
for _, item := range items {
//line app/vmalert/tpl/nav.qtpl:13
qw422016.N().S(`
<li class="nav-item">
<a class="nav-link`)
//line app/vmalert/tpl/nav.qtpl:15
if current == item.Name {
//line app/vmalert/tpl/nav.qtpl:15
qw422016.N().S(` active`)
//line app/vmalert/tpl/nav.qtpl:15
}
//line app/vmalert/tpl/nav.qtpl:15
qw422016.N().S(`" href="`)
//line app/vmalert/tpl/nav.qtpl:15
qw422016.E().S(item.Url)
//line app/vmalert/tpl/nav.qtpl:15
qw422016.N().S(`">
`)
//line app/vmalert/tpl/nav.qtpl:16
qw422016.E().S(item.Name)
//line app/vmalert/tpl/nav.qtpl:16
qw422016.N().S(`
</a>
</li>
`)
//line app/vmalert/tpl/nav.qtpl:19
}
//line app/vmalert/tpl/nav.qtpl:19
qw422016.N().S(`
</ul>
</div>
</nav>
`)
//line app/vmalert/tpl/nav.qtpl:23
}
//line app/vmalert/tpl/nav.qtpl:23
func WritePrintNavItems(qq422016 qtio422016.Writer, current string, items []NavItem) {
//line app/vmalert/tpl/nav.qtpl:23
qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/tpl/nav.qtpl:23
StreamPrintNavItems(qw422016, current, items)
//line app/vmalert/tpl/nav.qtpl:23
qt422016.ReleaseWriter(qw422016)
//line app/vmalert/tpl/nav.qtpl:23
}
//line app/vmalert/tpl/nav.qtpl:23
func PrintNavItems(current string, items []NavItem) string {
//line app/vmalert/tpl/nav.qtpl:23
qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/tpl/nav.qtpl:23
WritePrintNavItems(qb422016, current, items)
//line app/vmalert/tpl/nav.qtpl:23
qs422016 := string(qb422016.B)
//line app/vmalert/tpl/nav.qtpl:23
qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/tpl/nav.qtpl:23
return qs422016
//line app/vmalert/tpl/nav.qtpl:23
}

View file

@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"net/http"
"path"
"sort"
"strconv"
"strings"
@ -24,30 +23,24 @@ var (
navItems []tpl.NavItem
)
var (
//go:embed static
staticFiles embed.FS
staticServer = http.FileServer(http.FS(staticFiles))
)
func initLinks() {
pathPrefix := httpserver.GetPathPrefix()
if pathPrefix == "" {
pathPrefix = "/"
}
apiLinks = [][2]string{
{path.Join(pathPrefix, "api/v1/rules"), "list all loaded groups and rules"},
{path.Join(pathPrefix, "api/v1/alerts"), "list all active alerts"},
{path.Join(pathPrefix, "api/v1/groupID/alertID/status"), "get alert status by ID"},
{path.Join(pathPrefix, "flags"), "command-line flags"},
{path.Join(pathPrefix, "metrics"), "list of application metrics"},
{path.Join(pathPrefix, "-/reload"), "reload configuration"},
// api links are relative since they can be used by external clients
// such as Grafana and proxied via vmselect.
{"api/v1/rules", "list all loaded groups and rules"},
{"api/v1/alerts", "list all active alerts"},
{"api/v1/groupID/alertID/status", "get alert status by ID"},
// system links
{"/flags", "command-line flags"},
{"/metrics", "list of application metrics"},
{"/-/reload", "reload configuration"},
}
navItems = []tpl.NavItem{
{Name: "vmalert", Url: path.Join(pathPrefix, "/")},
{Name: "Groups", Url: path.Join(pathPrefix, "groups")},
{Name: "Alerts", Url: path.Join(pathPrefix, "alerts")},
{Name: "Notifiers", Url: path.Join(pathPrefix, "notifiers")},
{Name: "vmalert", Url: "home"},
{Name: "Groups", Url: "groups"},
{Name: "Alerts", Url: "alerts"},
{Name: "Notifiers", Url: "notifiers"},
{Name: "Docs", Url: "https://docs.victoriametrics.com/vmalert.html"},
}
}
@ -56,33 +49,50 @@ type requestHandler struct {
m *manager
}
var (
//go:embed static
staticFiles embed.FS
staticHandler = http.FileServer(http.FS(staticFiles))
staticServer = http.StripPrefix("/vmalert", staticHandler)
)
func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
once.Do(func() {
initLinks()
})
pathPrefix := httpserver.GetPathPrefix()
if pathPrefix == "" {
pathPrefix = "/"
if strings.HasPrefix(r.URL.Path, "/vmalert/static") {
staticServer.ServeHTTP(w, r)
return true
}
switch r.URL.Path {
case "/":
case "/", "/vmalert", "/vmalert/home":
if r.Method != "GET" {
return false
}
WriteWelcome(w)
WriteWelcome(w, r)
return true
case "/alerts":
WriteListAlerts(w, pathPrefix, rh.groupAlerts())
case "/vmalert/alerts":
WriteListAlerts(w, r, rh.groupAlerts())
return true
case "/groups", "/rules":
WriteListGroups(w, rh.groups())
case "/vmalert/groups":
WriteListGroups(w, r, rh.groups())
return true
case "/notifiers":
WriteListTargets(w, notifier.GetTargets())
case "/vmalert/notifiers":
WriteListTargets(w, r, notifier.GetTargets())
return true
case "/api/v1/rules":
// special cases for Grafana requests,
// served without `vmalert` prefix:
case "/rules":
// Grafana makes an extra request to `/rules`
// handler in addition to `/api/v1/rules` calls in alerts UI,
WriteListGroups(w, r, rh.groups())
return true
case "/vmalert/api/v1/rules", "/api/v1/rules":
// path used by Grafana for ng alerting
data, err := rh.listGroups()
if err != nil {
httpserver.Errorf(w, r, "%s", err)
@ -91,7 +101,8 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
w.Header().Set("Content-Type", "application/json")
w.Write(data)
return true
case "/api/v1/alerts":
case "/vmalert/api/v1/alerts", "/api/v1/alerts":
// path used by Grafana for ng alerting
data, err := rh.listAlerts()
if err != nil {
httpserver.Errorf(w, r, "%s", err)
@ -100,17 +111,14 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
w.Header().Set("Content-Type", "application/json")
w.Write(data)
return true
case "/-/reload":
logger.Infof("api config reload was called, sending sighup")
procutil.SelfSIGHUP()
w.WriteHeader(http.StatusOK)
return true
default:
if strings.HasPrefix(r.URL.Path, "/static") {
staticServer.ServeHTTP(w, r)
return true
}
default:
if !strings.HasSuffix(r.URL.Path, "/status") {
return false
}
@ -133,7 +141,7 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
}
// <groupID>/<alertID>/status
WriteAlert(w, pathPrefix, alert)
WriteAlert(w, r, alert)
return true
}
}

View file

@ -4,14 +4,15 @@
"time"
"sort"
"path"
"net/http"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/tpl"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier"
) %}
{% func Welcome() %}
{%= tpl.Header("vmalert", navItems) %}
{% func Welcome(r *http.Request) %}
{%= tpl.Header(r, navItems, "vmalert") %}
<p>
API:<br>
{% for _, p := range apiLinks %}
@ -21,11 +22,11 @@
<a href="{%s p %}">{%s p %}</a> - {%s doc %}<br/>
{% endfor %}
</p>
{%= tpl.Footer() %}
{%= tpl.Footer(r) %}
{% endfunc %}
{% func ListGroups(groups []APIGroup) %}
{%= tpl.Header("Groups", navItems) %}
{% func ListGroups(r *http.Request, groups []APIGroup) %}
{%= tpl.Header(r, navItems, "Groups") %}
{% if len(groups) > 0 %}
{%code
rOk := make(map[string]int)
@ -112,13 +113,13 @@
</div>
{% endif %}
{%= tpl.Footer() %}
{%= tpl.Footer(r) %}
{% endfunc %}
{% func ListAlerts(pathPrefix string, groupAlerts []GroupAlerts) %}
{%= tpl.Header("Alerts", navItems) %}
{% func ListAlerts(r *http.Request, groupAlerts []GroupAlerts) %}
{%= tpl.Header(r, navItems, "Alerts") %}
{% if len(groupAlerts) > 0 %}
<a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
<a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
@ -182,7 +183,7 @@
</td>
<td>{%s ar.Value %}</td>
<td>
<a href="{%s path.Join(pathPrefix, g.ID, ar.ID, "status") %}">Details</a>
<a href="{%s path.Join(g.ID, ar.ID, "status") %}">Details</a>
</td>
</tr>
{% endfor %}
@ -199,12 +200,12 @@
</div>
{% endif %}
{%= tpl.Footer() %}
{%= tpl.Footer(r) %}
{% endfunc %}
{% func ListTargets(targets map[notifier.TargetType][]notifier.Target) %}
{%= tpl.Header("Notifiers", navItems) %}
{% func ListTargets(r *http.Request, targets map[notifier.TargetType][]notifier.Target) %}
{%= tpl.Header(r, navItems, "Notifiers") %}
{% if len(targets) > 0 %}
<a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
<a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
@ -255,12 +256,12 @@
</div>
{% endif %}
{%= tpl.Footer() %}
{%= tpl.Footer(r) %}
{% endfunc %}
{% func Alert(pathPrefix string, alert *APIAlert) %}
{%= tpl.Header("", navItems) %}
{% func Alert(r *http.Request, alert *APIAlert) %}
{%= tpl.Header(r, navItems, "") %}
{%code
var labelKeys []string
for k := range alert.Labels {
@ -326,7 +327,7 @@
Group
</div>
<div class="col">
<a target="_blank" href="{%s path.Join(pathPrefix,"groups") %}#group-{%s alert.GroupID %}">{%s alert.GroupID %}</a>
<a target="_blank" href="/groups#group-{%s alert.GroupID %}">{%s alert.GroupID %}</a>
</div>
</div>
</div>
@ -340,7 +341,7 @@
</div>
</div>
</div>
{%= tpl.Footer() %}
{%= tpl.Footer(r) %}
{% endfunc %}

File diff suppressed because it is too large Load diff