lib/htmlcomponents: use relative links for the top page and for favicon.ico

This allows hiding VictoriaMetrics components behind proxies with arbitrary path prefixes.
For example, vmagent HTTP handlers can be served via /vmagent/ path prefix:

- http://proxy/vmagent/targets
- http://proxy/vmagent/service-discovery

The path prefix can be arbitrary. For example, below are vmagent urls
for /tenantID/vmagent/ path prefix:

- http://proxy/tenantID/vmagent/targets
- http://proxy/tenantID/vmagent/service-discovery

While at it, consistently serve favicon.ico from any path directory.

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5306
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5307
This commit is contained in:
Aliaksandr Valialkin 2023-11-13 20:13:50 +01:00
parent cf23dc6480
commit 8af56ea2ed
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
6 changed files with 61 additions and 53 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -104,6 +104,7 @@ The sandbox cluster installation is running under the constant load generated by
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly parse `ca`, `cert` and `key` options at `tls_config` section inside [http client settings](https://docs.victoriametrics.com/sd_configs.html#http-api-client-options). Previously string values couldn't be parsed for these options, since the parser was mistakenly expecting a list of `uint8` values instead.
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly drop samples if `-streamAggr.dropInput` command-line flag is set and `-remoteWrite.streamAggr.config` contains an empty file. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5207).
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): do not print redundant error logs when failed to scrape consul or nomad target. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5239).
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): generate proper link to the main page and to `favicon.ico` at http pages served by `vmagent` such as `/targets` or `/service-discovery` when `vmagent` sits behind an http proxy with custom http path prefixes. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5306).
* BUGFIX: [vmstorage](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html): prevent deleted series to be searchable via `/api/v1/series` API if they were re-ingested with staleness markers. This situation could happen if user deletes the series from the target and from VM, and then vmagent sends stale markers for absent series. Thanks to @ilyatrefilov for the [issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5069) and [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5174).
* BUGFIX: [vmstorage](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html): log warning about switching to ReadOnly mode only on state change. Before, vmstorage would log this warning every 1s. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5159) for details.
* BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth.html): show browser authorization window for unauthorized requests to unsupported paths if the `unauthorized_user` section is specified. This allows properly authorizing the user. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5236) for details.

View file

@ -5,13 +5,14 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="static/css/bootstrap.min.css" rel="stylesheet" />
<link rel="icon" href="favicon.ico"/>
{% endfunc %}
// Navbar writes navigation bar for /targets-like pages
{% func Navbar() %}
<div class="navbar navbar-dark bg-dark box-shadow">
<div class="d-flex justify-content-between">
<a href="/" class="navbar-brand d-flex align-items-center ms-3" title="The High Performance Open Source Time Series Database &amp; Monitoring Solution ">
<a href="." class="navbar-brand d-flex align-items-center ms-3" title="The High Performance Open Source Time Series Database &amp; Monitoring Solution ">
<svg xmlns="http://www.w3.org/2000/svg" id="VM_logo" viewBox="0 0 464.61 533.89" width="20" height="20" class="me-1"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M459.86,467.77c9,7.67,24.12,13.49,39.3,13.69v0h1.68v0c15.18-.2,30.31-6,39.3-13.69,47.43-40.45,184.65-166.24,184.65-166.24,36.84-34.27-65.64-68.28-223.95-68.47h-1.68c-158.31.19-260.79,34.2-224,68.47C275.21,301.53,412.43,427.32,459.86,467.77Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,535.88c-9,7.67-24.12,13.5-39.3,13.7h-1.6c-15.18-.2-30.31-6-39.3-13.7-32.81-28-148.56-132.93-192.16-172.7v60.74c0,6.67,2.55,15.52,7.09,19.68,29.64,27.18,143.94,131.8,185.07,166.88,9,7.67,24.12,13.49,39.3,13.69v0h1.6v0c15.18-.2,30.31-6,39.3-13.69,41.13-35.08,155.43-139.7,185.07-166.88,4.54-4.16,7.09-13,7.09-19.68V363.18C688.66,403,572.91,507.9,540.1,535.88Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,678.64c-9,7.67-24.12,13.49-39.3,13.69v0h-1.6v0c-15.18-.2-30.31-6-39.3-13.69-32.81-28-148.56-132.94-192.16-172.7v60.73c0,6.67,2.55,15.53,7.09,19.69,29.64,27.17,143.94,131.8,185.07,166.87,9,7.67,24.12,13.5,39.3,13.7h1.6c15.18-.2,30.31-6,39.3-13.7,41.13-35.07,155.43-139.7,185.07-166.87,4.54-4.16,7.09-13,7.09-19.69V505.94C688.66,545.7,572.91,650.66,540.1,678.64Z" transform="translate(-267.7 -233.05)"/></svg>
<strong>VictoriaMetrics</strong>
</a>

View file

@ -22,106 +22,106 @@ var (
//line lib/htmlcomponents/components.qtpl:4
func StreamCommonHeader(qw422016 *qt422016.Writer) {
//line lib/htmlcomponents/components.qtpl:4
qw422016.N().S(`<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link href="static/css/bootstrap.min.css" rel="stylesheet" />`)
//line lib/htmlcomponents/components.qtpl:8
qw422016.N().S(`<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link href="static/css/bootstrap.min.css" rel="stylesheet" /><link rel="icon" href="favicon.ico"/>`)
//line lib/htmlcomponents/components.qtpl:9
}
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
func WriteCommonHeader(qq422016 qtio422016.Writer) {
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
qw422016 := qt422016.AcquireWriter(qq422016)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
StreamCommonHeader(qw422016)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
qt422016.ReleaseWriter(qw422016)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
}
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
func CommonHeader() string {
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
qb422016 := qt422016.AcquireByteBuffer()
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
WriteCommonHeader(qb422016)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
qs422016 := string(qb422016.B)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
qt422016.ReleaseByteBuffer(qb422016)
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
return qs422016
//line lib/htmlcomponents/components.qtpl:8
//line lib/htmlcomponents/components.qtpl:9
}
// Navbar writes navigation bar for /targets-like pages
//line lib/htmlcomponents/components.qtpl:11
//line lib/htmlcomponents/components.qtpl:12
func StreamNavbar(qw422016 *qt422016.Writer) {
//line lib/htmlcomponents/components.qtpl:11
qw422016.N().S(`<div class="navbar navbar-dark bg-dark box-shadow"><div class="d-flex justify-content-between"><a href="/" class="navbar-brand d-flex align-items-center ms-3" title="The High Performance Open Source Time Series Database &amp; Monitoring Solution "><svg xmlns="http://www.w3.org/2000/svg" id="VM_logo" viewBox="0 0 464.61 533.89" width="20" height="20" class="me-1"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M459.86,467.77c9,7.67,24.12,13.49,39.3,13.69v0h1.68v0c15.18-.2,30.31-6,39.3-13.69,47.43-40.45,184.65-166.24,184.65-166.24,36.84-34.27-65.64-68.28-223.95-68.47h-1.68c-158.31.19-260.79,34.2-224,68.47C275.21,301.53,412.43,427.32,459.86,467.77Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,535.88c-9,7.67-24.12,13.5-39.3,13.7h-1.6c-15.18-.2-30.31-6-39.3-13.7-32.81-28-148.56-132.93-192.16-172.7v60.74c0,6.67,2.55,15.52,7.09,19.68,29.64,27.18,143.94,131.8,185.07,166.88,9,7.67,24.12,13.49,39.3,13.69v0h1.6v0c15.18-.2,30.31-6,39.3-13.69,41.13-35.08,155.43-139.7,185.07-166.88,4.54-4.16,7.09-13,7.09-19.68V363.18C688.66,403,572.91,507.9,540.1,535.88Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,678.64c-9,7.67-24.12,13.49-39.3,13.69v0h-1.6v0c-15.18-.2-30.31-6-39.3-13.69-32.81-28-148.56-132.94-192.16-172.7v60.73c0,6.67,2.55,15.53,7.09,19.69,29.64,27.17,143.94,131.8,185.07,166.87,9,7.67,24.12,13.5,39.3,13.7h1.6c15.18-.2,30.31-6,39.3-13.7,41.13-35.07,155.43-139.7,185.07-166.87,4.54-4.16,7.09-13,7.09-19.69V505.94C688.66,545.7,572.91,650.66,540.1,678.64Z" transform="translate(-267.7 -233.05)"/></svg><strong>VictoriaMetrics</strong></a></div></div>`)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:12
qw422016.N().S(`<div class="navbar navbar-dark bg-dark box-shadow"><div class="d-flex justify-content-between"><a href="." class="navbar-brand d-flex align-items-center ms-3" title="The High Performance Open Source Time Series Database &amp; Monitoring Solution "><svg xmlns="http://www.w3.org/2000/svg" id="VM_logo" viewBox="0 0 464.61 533.89" width="20" height="20" class="me-1"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M459.86,467.77c9,7.67,24.12,13.49,39.3,13.69v0h1.68v0c15.18-.2,30.31-6,39.3-13.69,47.43-40.45,184.65-166.24,184.65-166.24,36.84-34.27-65.64-68.28-223.95-68.47h-1.68c-158.31.19-260.79,34.2-224,68.47C275.21,301.53,412.43,427.32,459.86,467.77Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,535.88c-9,7.67-24.12,13.5-39.3,13.7h-1.6c-15.18-.2-30.31-6-39.3-13.7-32.81-28-148.56-132.93-192.16-172.7v60.74c0,6.67,2.55,15.52,7.09,19.68,29.64,27.18,143.94,131.8,185.07,166.88,9,7.67,24.12,13.49,39.3,13.69v0h1.6v0c15.18-.2,30.31-6,39.3-13.69,41.13-35.08,155.43-139.7,185.07-166.88,4.54-4.16,7.09-13,7.09-19.68V363.18C688.66,403,572.91,507.9,540.1,535.88Z" transform="translate(-267.7 -233.05)"/><path class="cls-1" d="M540.1,678.64c-9,7.67-24.12,13.49-39.3,13.69v0h-1.6v0c-15.18-.2-30.31-6-39.3-13.69-32.81-28-148.56-132.94-192.16-172.7v60.73c0,6.67,2.55,15.53,7.09,19.69,29.64,27.17,143.94,131.8,185.07,166.87,9,7.67,24.12,13.5,39.3,13.7h1.6c15.18-.2,30.31-6,39.3-13.7,41.13-35.07,155.43-139.7,185.07-166.87,4.54-4.16,7.09-13,7.09-19.69V505.94C688.66,545.7,572.91,650.66,540.1,678.64Z" transform="translate(-267.7 -233.05)"/></svg><strong>VictoriaMetrics</strong></a></div></div>`)
//line lib/htmlcomponents/components.qtpl:21
}
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
func WriteNavbar(qq422016 qtio422016.Writer) {
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
qw422016 := qt422016.AcquireWriter(qq422016)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
StreamNavbar(qw422016)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
qt422016.ReleaseWriter(qw422016)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
}
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
func Navbar() string {
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
qb422016 := qt422016.AcquireByteBuffer()
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
WriteNavbar(qb422016)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
qs422016 := string(qb422016.B)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
qt422016.ReleaseByteBuffer(qb422016)
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
return qs422016
//line lib/htmlcomponents/components.qtpl:20
//line lib/htmlcomponents/components.qtpl:21
}
// ErrorNotification writes the given err as error notification
//line lib/htmlcomponents/components.qtpl:23
//line lib/htmlcomponents/components.qtpl:24
func StreamErrorNotification(qw422016 *qt422016.Writer, err error) {
//line lib/htmlcomponents/components.qtpl:23
//line lib/htmlcomponents/components.qtpl:24
qw422016.N().S(`<div class="alert alert-danger d-flex align-items-center" role="alert"><svg class="bi flex-shrink-0 me-2" width="24" height="24" role="img" aria-label="Danger:"><use xlink:href="#exclamation-triangle-fill"/></svg><div>`)
//line lib/htmlcomponents/components.qtpl:28
//line lib/htmlcomponents/components.qtpl:29
qw422016.E().S(err.Error())
//line lib/htmlcomponents/components.qtpl:28
//line lib/htmlcomponents/components.qtpl:29
qw422016.N().S(`</div></div>`)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
}
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
func WriteErrorNotification(qq422016 qtio422016.Writer, err error) {
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
qw422016 := qt422016.AcquireWriter(qq422016)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
StreamErrorNotification(qw422016, err)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
qt422016.ReleaseWriter(qw422016)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
}
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
func ErrorNotification(err error) string {
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
qb422016 := qt422016.AcquireByteBuffer()
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
WriteErrorNotification(qb422016, err)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
qs422016 := string(qb422016.B)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
qt422016.ReleaseByteBuffer(qb422016)
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
return qs422016
//line lib/htmlcomponents/components.qtpl:31
//line lib/htmlcomponents/components.qtpl:32
}

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -3,6 +3,7 @@ package httpserver
import (
"context"
"crypto/tls"
_ "embed"
"errors"
"flag"
"fmt"
@ -259,6 +260,12 @@ func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh Reques
h.Set("Connection", "close")
}
path := r.URL.Path
if strings.HasSuffix(path, "/favicon.ico") {
w.Header().Set("Cache-Control", "max-age=3600")
faviconRequests.Inc()
w.Write(faviconData)
return
}
prefix := GetPathPrefix()
if prefix != "" {
// Trim -http.pathPrefix from path
@ -306,10 +313,6 @@ func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh Reques
}
w.WriteHeader(status)
return
case "/favicon.ico":
faviconRequests.Inc()
w.WriteHeader(http.StatusNoContent)
return
case "/metrics":
metricsRequests.Inc()
if !CheckAuthFlag(w, r, *metricsAuthKey, "metricsAuthKey") {
@ -446,7 +449,7 @@ var (
pprofTraceRequests = metrics.NewCounter(`vm_http_requests_total{path="/debug/pprof/trace"}`)
pprofMutexRequests = metrics.NewCounter(`vm_http_requests_total{path="/debug/pprof/mutex"}`)
pprofDefaultRequests = metrics.NewCounter(`vm_http_requests_total{path="/debug/pprof/default"}`)
faviconRequests = metrics.NewCounter(`vm_http_requests_total{path="/favicon.ico"}`)
faviconRequests = metrics.NewCounter(`vm_http_requests_total{path="*/favicon.ico"}`)
authBasicRequestErrors = metrics.NewCounter(`vm_http_request_errors_total{path="*", reason="wrong_basic_auth"}`)
authKeyRequestErrors = metrics.NewCounter(`vm_http_request_errors_total{path="*", reason="wrong_auth_key"}`)
@ -455,6 +458,9 @@ var (
requestsTotal = metrics.NewCounter(`vm_http_requests_all_total`)
)
//go:embed favicon.ico
var faviconData []byte
// GetQuotedRemoteAddr returns quoted remote address.
func GetQuotedRemoteAddr(r *http.Request) string {
remoteAddr := r.RemoteAddr