all: add support for specifying multiple -httpListenAddr options

This commit is contained in:
Aliaksandr Valialkin 2024-02-09 03:15:04 +02:00
parent b161e889b5
commit ae8a867924
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
14 changed files with 141 additions and 80 deletions

View file

@ -21,8 +21,8 @@ import (
) )
var ( var (
httpListenAddr = flag.String("httpListenAddr", ":9428", "TCP address to listen for http connections. See also -httpListenAddr.useProxyProtocol") httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP address to listen for incoming http requests. See also -httpListenAddr.useProxyProtocol")
useProxyProtocol = flag.Bool("httpListenAddr.useProxyProtocol", false, "Whether to use proxy protocol for connections accepted at -httpListenAddr . "+ useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the given -httpListenAddr . "+
"See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+
"With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing")
) )
@ -35,14 +35,18 @@ func main() {
buildinfo.Init() buildinfo.Init()
logger.Init() logger.Init()
logger.Infof("starting VictoriaLogs at %q...", *httpListenAddr) listenAddrs := *httpListenAddrs
if len(listenAddrs) == 0 {
listenAddrs = []string{":9428"}
}
logger.Infof("starting VictoriaLogs at %q...", listenAddrs)
startTime := time.Now() startTime := time.Now()
vlstorage.Init() vlstorage.Init()
vlselect.Init() vlselect.Init()
vlinsert.Init() vlinsert.Init()
go httpserver.Serve(*httpListenAddr, *useProxyProtocol, requestHandler) go httpserver.Serve(listenAddrs, useProxyProtocol, requestHandler)
logger.Infof("started VictoriaLogs in %.3f seconds; see https://docs.victoriametrics.com/VictoriaLogs/", time.Since(startTime).Seconds()) logger.Infof("started VictoriaLogs in %.3f seconds; see https://docs.victoriametrics.com/VictoriaLogs/", time.Since(startTime).Seconds())
pushmetrics.Init() pushmetrics.Init()
@ -50,9 +54,9 @@ func main() {
logger.Infof("received signal %s", sig) logger.Infof("received signal %s", sig)
pushmetrics.Stop() pushmetrics.Stop()
logger.Infof("gracefully shutting down webservice at %q", *httpListenAddr) logger.Infof("gracefully shutting down webservice at %q", listenAddrs)
startTime = time.Now() startTime = time.Now()
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop the webservice: %s", err) logger.Fatalf("cannot stop the webservice: %s", err)
} }
logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds())

View file

@ -26,8 +26,8 @@ import (
) )
var ( var (
httpListenAddr = flag.String("httpListenAddr", ":8428", "TCP address to listen for http connections. See also -tls and -httpListenAddr.useProxyProtocol") httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP addresses to listen for incoming http requests. See also -tls and -httpListenAddr.useProxyProtocol")
useProxyProtocol = flag.Bool("httpListenAddr.useProxyProtocol", false, "Whether to use proxy protocol for connections accepted at -httpListenAddr . "+ useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the corresponding -httpListenAddr . "+
"See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+
"With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing")
minScrapeInterval = flag.Duration("dedup.minScrapeInterval", 0, "Leave only the last sample in every time series per each discrete interval "+ minScrapeInterval = flag.Duration("dedup.minScrapeInterval", 0, "Leave only the last sample in every time series per each discrete interval "+
@ -66,7 +66,11 @@ func main() {
return return
} }
logger.Infof("starting VictoriaMetrics at %q...", *httpListenAddr) listenAddrs := *httpListenAddrs
if len(listenAddrs) == 0 {
listenAddrs = []string{":8428"}
}
logger.Infof("starting VictoriaMetrics at %q...", listenAddrs)
startTime := time.Now() startTime := time.Now()
storage.SetDedupInterval(*minScrapeInterval) storage.SetDedupInterval(*minScrapeInterval)
storage.SetDataFlushInterval(*inmemoryDataFlushInterval) storage.SetDataFlushInterval(*inmemoryDataFlushInterval)
@ -76,7 +80,7 @@ func main() {
startSelfScraper() startSelfScraper()
go httpserver.Serve(*httpListenAddr, *useProxyProtocol, requestHandler) go httpserver.Serve(listenAddrs, useProxyProtocol, requestHandler)
logger.Infof("started VictoriaMetrics in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("started VictoriaMetrics in %.3f seconds", time.Since(startTime).Seconds())
pushmetrics.Init() pushmetrics.Init()
@ -86,9 +90,9 @@ func main() {
stopSelfScraper() stopSelfScraper()
logger.Infof("gracefully shutting down webservice at %q", *httpListenAddr) logger.Infof("gracefully shutting down webservice at %q", listenAddrs)
startTime = time.Now() startTime = time.Now()
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop the webservice: %s", err) logger.Fatalf("cannot stop the webservice: %s", err)
} }
logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds())

View file

@ -180,7 +180,7 @@ func setUp() {
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded) vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
vmselect.Init() vmselect.Init()
vminsert.Init() vminsert.Init()
go httpserver.Serve(*httpListenAddr, false, requestHandler) go httpserver.Serve(*httpListenAddrs, useProxyProtocol, requestHandler)
readyStorageCheckFunc := func() bool { readyStorageCheckFunc := func() bool {
resp, err := http.Get(testHealthHTTPPath) resp, err := http.Get(testHealthHTTPPath)
if err != nil { if err != nil {
@ -226,7 +226,7 @@ func waitFor(timeout time.Duration, f func() bool) error {
} }
func tearDown() { func tearDown() {
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(*httpListenAddrs); err != nil {
log.Printf("cannot stop the webservice: %s", err) log.Printf("cannot stop the webservice: %s", err)
} }
vminsert.Stop() vminsert.Stop()

View file

@ -46,10 +46,10 @@ import (
) )
var ( var (
httpListenAddr = flag.String("httpListenAddr", ":8429", "TCP address to listen for http connections. "+ httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP address to listen for incoming http requests. "+
"Set this flag to empty value in order to disable listening on any port. This mode may be useful for running multiple vmagent instances on the same server. "+ "Set this flag to empty value in order to disable listening on any port. This mode may be useful for running multiple vmagent instances on the same server. "+
"Note that /targets and /metrics pages aren't available if -httpListenAddr=''. See also -tls and -httpListenAddr.useProxyProtocol") "Note that /targets and /metrics pages aren't available if -httpListenAddr=''. See also -tls and -httpListenAddr.useProxyProtocol")
useProxyProtocol = flag.Bool("httpListenAddr.useProxyProtocol", false, "Whether to use proxy protocol for connections accepted at -httpListenAddr . "+ useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the corresponding -httpListenAddr . "+
"See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+
"With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing")
influxListenAddr = flag.String("influxListenAddr", "", "TCP and UDP address to listen for InfluxDB line protocol data. Usually :8089 must be set. Doesn't work if empty. "+ influxListenAddr = flag.String("influxListenAddr", "", "TCP and UDP address to listen for InfluxDB line protocol data. Usually :8089 must be set. Doesn't work if empty. "+
@ -120,7 +120,11 @@ func main() {
return return
} }
logger.Infof("starting vmagent at %q...", *httpListenAddr) listenAddrs := *httpListenAddrs
if len(listenAddrs) == 0 {
listenAddrs = []string{":8429"}
}
logger.Infof("starting vmagent at %q...", listenAddrs)
startTime := time.Now() startTime := time.Now()
remotewrite.Init() remotewrite.Init()
common.StartUnmarshalWorkers() common.StartUnmarshalWorkers()
@ -143,9 +147,7 @@ func main() {
promscrape.Init(remotewrite.PushDropSamplesOnFailure) promscrape.Init(remotewrite.PushDropSamplesOnFailure)
if len(*httpListenAddr) > 0 { go httpserver.Serve(listenAddrs, useProxyProtocol, requestHandler)
go httpserver.Serve(*httpListenAddr, *useProxyProtocol, requestHandler)
}
logger.Infof("started vmagent in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("started vmagent in %.3f seconds", time.Since(startTime).Seconds())
pushmetrics.Init() pushmetrics.Init()
@ -154,13 +156,11 @@ func main() {
pushmetrics.Stop() pushmetrics.Stop()
startTime = time.Now() startTime = time.Now()
if len(*httpListenAddr) > 0 { logger.Infof("gracefully shutting down webservice at %q", listenAddrs)
logger.Infof("gracefully shutting down webservice at %q", *httpListenAddr) if err := httpserver.Stop(listenAddrs); err != nil {
if err := httpserver.Stop(*httpListenAddr); err != nil { logger.Fatalf("cannot stop the webservice: %s", err)
logger.Fatalf("cannot stop the webservice: %s", err)
}
logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds())
} }
logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds())
promscrape.Stop() promscrape.Stop()

View file

@ -25,6 +25,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/prometheus" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/prometheus"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs" "github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver" "github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
@ -184,7 +185,8 @@ func processFlags() {
func setUp() { func setUp() {
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded) vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
go httpserver.Serve(httpListenAddr, false, func(w http.ResponseWriter, r *http.Request) bool { var ab flagutil.ArrayBool
go httpserver.Serve([]string{httpListenAddr}, &ab, func(w http.ResponseWriter, r *http.Request) bool {
switch r.URL.Path { switch r.URL.Path {
case "/prometheus/api/v1/query": case "/prometheus/api/v1/query":
if err := prometheus.QueryHandler(nil, time.Now(), w, r); err != nil { if err := prometheus.QueryHandler(nil, time.Now(), w, r); err != nil {
@ -225,7 +227,7 @@ checkCheck:
} }
func tearDown() { func tearDown() {
if err := httpserver.Stop(httpListenAddr); err != nil { if err := httpserver.Stop([]string{httpListenAddr}); err != nil {
logger.Errorf("cannot stop the webservice: %s", err) logger.Errorf("cannot stop the webservice: %s", err)
} }
vmstorage.Stop() vmstorage.Stop()

View file

@ -59,8 +59,8 @@ absolute path to all .tpl files in root.
configCheckInterval = flag.Duration("configCheckInterval", 0, "Interval for checking for changes in '-rule' or '-notifier.config' files. "+ configCheckInterval = flag.Duration("configCheckInterval", 0, "Interval for checking for changes in '-rule' or '-notifier.config' files. "+
"By default, the checking is disabled. Send SIGHUP signal in order to force config check for changes.") "By default, the checking is disabled. Send SIGHUP signal in order to force config check for changes.")
httpListenAddr = flag.String("httpListenAddr", ":8880", "Address to listen for http connections. See also -tls and -httpListenAddr.useProxyProtocol") httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "Address to listen for incoming http requests. See also -tls and -httpListenAddr.useProxyProtocol")
useProxyProtocol = flag.Bool("httpListenAddr.useProxyProtocol", false, "Whether to use proxy protocol for connections accepted at -httpListenAddr . "+ useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the corresponding -httpListenAddr . "+
"See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+
"With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing")
evaluationInterval = flag.Duration("evaluationInterval", time.Minute, "How often to evaluate the rules") evaluationInterval = flag.Duration("evaluationInterval", time.Minute, "How often to evaluate the rules")
@ -178,15 +178,19 @@ func main() {
go configReload(ctx, manager, groupsCfg, sighupCh) go configReload(ctx, manager, groupsCfg, sighupCh)
listenAddrs := *httpListenAddrs
if len(listenAddrs) == 0 {
listenAddrs = []string{":8880"}
}
rh := &requestHandler{m: manager} rh := &requestHandler{m: manager}
go httpserver.Serve(*httpListenAddr, *useProxyProtocol, rh.handler) go httpserver.Serve(listenAddrs, useProxyProtocol, rh.handler)
pushmetrics.Init() pushmetrics.Init()
sig := procutil.WaitForSigterm() sig := procutil.WaitForSigterm()
logger.Infof("service received signal %s", sig) logger.Infof("service received signal %s", sig)
pushmetrics.Stop() pushmetrics.Stop()
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop the webservice: %s", err) logger.Fatalf("cannot stop the webservice: %s", err)
} }
cancel() cancel()
@ -248,7 +252,13 @@ func newManager(ctx context.Context) (*manager, error) {
func getExternalURL(customURL string) (*url.URL, error) { func getExternalURL(customURL string) (*url.URL, error) {
if customURL == "" { if customURL == "" {
// use local hostname as external URL // use local hostname as external URL
return getHostnameAsExternalURL(*httpListenAddr, httpserver.IsTLS()) listenAddr := ":8880"
if len(*httpListenAddrs) > 0 {
listenAddr = (*httpListenAddrs)[0]
}
isTLS := httpserver.IsTLS(0)
return getHostnameAsExternalURL(listenAddr, isTLS)
} }
u, err := url.Parse(customURL) u, err := url.Parse(customURL)
if err != nil { if err != nil {
@ -260,13 +270,13 @@ func getExternalURL(customURL string) (*url.URL, error) {
return u, nil return u, nil
} }
func getHostnameAsExternalURL(httpListenAddr string, isSecure bool) (*url.URL, error) { func getHostnameAsExternalURL(addr string, isSecure bool) (*url.URL, error) {
hname, err := os.Hostname() hname, err := os.Hostname()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get hostname: %w", err) return nil, fmt.Errorf("failed to get hostname: %w", err)
} }
port := "" port := ""
if ipport := strings.Split(httpListenAddr, ":"); len(ipport) > 1 { if ipport := strings.Split(addr, ":"); len(ipport) > 1 {
port = ":" + ipport[1] port = ":" + ipport[1]
} }
schema := "http://" schema := "http://"

View file

@ -33,8 +33,8 @@ import (
) )
var ( var (
httpListenAddr = flag.String("httpListenAddr", ":8427", "TCP address to listen for http connections. See also -tls and -httpListenAddr.useProxyProtocol") httpListenAddrs = flagutil.NewArrayString("httpListenAddr", "TCP address to listen for incoming http requests. See also -tls and -httpListenAddr.useProxyProtocol")
useProxyProtocol = flag.Bool("httpListenAddr.useProxyProtocol", false, "Whether to use proxy protocol for connections accepted at -httpListenAddr . "+ useProxyProtocol = flagutil.NewArrayBool("httpListenAddr.useProxyProtocol", "Whether to use proxy protocol for connections accepted at the corresponding -httpListenAddr . "+
"See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+ "See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt . "+
"With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing") "With enabled proxy protocol http server cannot serve regular /metrics endpoint. Use -pushmetrics.url for metrics pushing")
maxIdleConnsPerBackend = flag.Int("maxIdleConnsPerBackend", 100, "The maximum number of idle connections vmauth can open per each backend host. "+ maxIdleConnsPerBackend = flag.Int("maxIdleConnsPerBackend", 100, "The maximum number of idle connections vmauth can open per each backend host. "+
@ -65,10 +65,14 @@ func main() {
buildinfo.Init() buildinfo.Init()
logger.Init() logger.Init()
logger.Infof("starting vmauth at %q...", *httpListenAddr) listenAddrs := *httpListenAddrs
if len(listenAddrs) == 0 {
listenAddrs = []string{":8427"}
}
logger.Infof("starting vmauth at %q...", listenAddrs)
startTime := time.Now() startTime := time.Now()
initAuthConfig() initAuthConfig()
go httpserver.Serve(*httpListenAddr, *useProxyProtocol, requestHandler) go httpserver.Serve(listenAddrs, useProxyProtocol, requestHandler)
logger.Infof("started vmauth in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("started vmauth in %.3f seconds", time.Since(startTime).Seconds())
pushmetrics.Init() pushmetrics.Init()
@ -77,8 +81,8 @@ func main() {
pushmetrics.Stop() pushmetrics.Stop()
startTime = time.Now() startTime = time.Now()
logger.Infof("gracefully shutting down webservice at %q", *httpListenAddr) logger.Infof("gracefully shutting down webservice at %q", listenAddrs)
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop the webservice: %s", err) logger.Fatalf("cannot stop the webservice: %s", err)
} }
logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("successfully shut down the webservice in %.3f seconds", time.Since(startTime).Seconds())

View file

@ -93,7 +93,8 @@ func main() {
} }
} }
go httpserver.Serve(*httpListenAddr, false, nil) listenAddrs := []string{*httpListenAddr}
go httpserver.Serve(listenAddrs, nil, nil)
pushmetrics.Init() pushmetrics.Init()
err := makeBackup() err := makeBackup()
@ -104,8 +105,8 @@ func main() {
pushmetrics.Stop() pushmetrics.Stop()
startTime := time.Now() startTime := time.Now()
logger.Infof("gracefully shutting down http server for metrics at %q", *httpListenAddr) logger.Infof("gracefully shutting down http server for metrics at %q", listenAddrs)
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop http server for metrics: %s", err) logger.Fatalf("cannot stop http server for metrics: %s", err)
} }
logger.Infof("successfully shut down http server for metrics in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("successfully shut down http server for metrics in %.3f seconds", time.Since(startTime).Seconds())

View file

@ -37,7 +37,8 @@ func main() {
buildinfo.Init() buildinfo.Init()
logger.Init() logger.Init()
go httpserver.Serve(*httpListenAddr, false, nil) listenAddrs := []string{*httpListenAddr}
go httpserver.Serve(listenAddrs, nil, nil)
srcFS, err := newSrcFS() srcFS, err := newSrcFS()
if err != nil { if err != nil {
@ -62,8 +63,8 @@ func main() {
dstFS.MustStop() dstFS.MustStop()
startTime := time.Now() startTime := time.Now()
logger.Infof("gracefully shutting down http server for metrics at %q", *httpListenAddr) logger.Infof("gracefully shutting down http server for metrics at %q", listenAddrs)
if err := httpserver.Stop(*httpListenAddr); err != nil { if err := httpserver.Stop(listenAddrs); err != nil {
logger.Fatalf("cannot stop http server for metrics: %s", err) logger.Fatalf("cannot stop http server for metrics: %s", err)
} }
logger.Infof("successfully shut down http server for metrics in %.3f seconds", time.Since(startTime).Seconds()) logger.Infof("successfully shut down http server for metrics in %.3f seconds", time.Since(startTime).Seconds())

View file

@ -31,6 +31,7 @@ The sandbox cluster installation is running under the constant load generated by
* SECURITY: upgrade Go builder from Go1.21.6 to Go1.21.7. See [the list of issues addressed in Go1.21.7](https://github.com/golang/go/issues?q=milestone%3AGo1.21.7+label%3ACherryPickApproved). * SECURITY: upgrade Go builder from Go1.21.6 to Go1.21.7. See [the list of issues addressed in Go1.21.7](https://github.com/golang/go/issues?q=milestone%3AGo1.21.7+label%3ACherryPickApproved).
* FEATURE: all VictoriaMetrics components: add support for TLS client certificate verification at `-httpListenAddr` (aka [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication)). See [these docs](https://docs.victoriametrics.com/#mtls-protection). See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5458). * FEATURE: all VictoriaMetrics components: add support for TLS client certificate verification at `-httpListenAddr` (aka [mTLS](https://en.wikipedia.org/wiki/Mutual_authentication)). See [these docs](https://docs.victoriametrics.com/#mtls-protection). See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5458).
* FEATURE: all VictoriaMetrics components: add support for accepting http requests over multiple distinct TCP addresses by starting VictoriaMetrics component with multiple `-httpListenAddr` command-line flags. For example, `./victoria-metrics -httpListenAddr=some-host:12345 -httpListenAddr=localhost:8428` starts VictoriaMetrics, which accepts incoming http requests at both `some-host:12345` and `localhost:8428`. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1470).
* FEATURE: all VictoriaMetrics components: add support for empty command flag values in short array notation. For example, `-remoteWrite.sendTimeout=',20s,'` specifies three `-remoteWrite.sendTimeout` values - the first and the last ones are default values (`30s` in this case), while the second one is `20s`. * FEATURE: all VictoriaMetrics components: add support for empty command flag values in short array notation. For example, `-remoteWrite.sendTimeout=',20s,'` specifies three `-remoteWrite.sendTimeout` values - the first and the last ones are default values (`30s` in this case), while the second one is `20s`.
* FEATURE: all VictoriaMetrics components: do not close connections to `-httpListenAddr` every 2 minutes. This behavior didn't help spreading load among multiple backend servers behind load-balancing TCP proxy. Instead, it could lead to hard-to-debug issues like [this one](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1304#issuecomment-1636997037). If you still need periodically closing client connections because of some reason, then pass the desired timeout to `-http.connTimeout` command-line flag. * FEATURE: all VictoriaMetrics components: do not close connections to `-httpListenAddr` every 2 minutes. This behavior didn't help spreading load among multiple backend servers behind load-balancing TCP proxy. Instead, it could lead to hard-to-debug issues like [this one](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1304#issuecomment-1636997037). If you still need periodically closing client connections because of some reason, then pass the desired timeout to `-http.connTimeout` command-line flag.
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html) and [single-node VictoriaMetrics](https://docs.victoriametrics.com): add support for data ingestion via [DataDog lambda extension](https://docs.datadoghq.com/serverless/libraries_integrations/extension/) aka `/api/beta/sketches` endpoint. See [these docs](https://docs.victoriametrics.com/#how-to-send-data-from-datadog-agent) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3091). Thanks to @AndrewChubatiuk for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5584). * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html) and [single-node VictoriaMetrics](https://docs.victoriametrics.com): add support for data ingestion via [DataDog lambda extension](https://docs.datadoghq.com/serverless/libraries_integrations/extension/) aka `/api/beta/sketches` endpoint. See [these docs](https://docs.victoriametrics.com/#how-to-send-data-from-datadog-agent) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3091). Thanks to @AndrewChubatiuk for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5584).

View file

@ -101,8 +101,8 @@ func (a *ArrayString) Set(value string) error {
} }
func parseArrayValues(s string) []string { func parseArrayValues(s string) []string {
if len(s) == 0 { if s == "" {
return nil return []string{""}
} }
var values []string var values []string
for { for {

View file

@ -174,7 +174,7 @@ func TestArrayDuration_Set(t *testing.T) {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", result, expectedResult) t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", result, expectedResult)
} }
} }
f("", "") f("", "42s")
f(`1m`, `1m0s`) f(`1m`, `1m0s`)
f(`5m,1s,1h`, `5m0s,1s,1h0m0s`) f(`5m,1s,1h`, `5m0s,1s,1h0m0s`)
f(`5m,,1h`, `5m0s,42s,1h0m0s`) f(`5m,,1h`, `5m0s,42s,1h0m0s`)
@ -211,7 +211,6 @@ func TestArrayDuration_String(t *testing.T) {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s) t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
} }
} }
f("")
f("10s,1m0s") f("10s,1m0s")
f("5m0s,1s") f("5m0s,1s")
} }
@ -237,7 +236,7 @@ func TestArrayBool_Set(t *testing.T) {
t.Fatalf("unexpected values parsed;\ngot\n%v\nwant\n%v", result, expectedResult) t.Fatalf("unexpected values parsed;\ngot\n%v\nwant\n%v", result, expectedResult)
} }
} }
f("", "") f("", "false")
f(`true`, `true`) f(`true`, `true`)
f(`false,True,False`, `false,true,false`) f(`false,True,False`, `false,true,false`)
f(`1,,False`, `true,false,false`) f(`1,,False`, `true,false,false`)
@ -273,7 +272,6 @@ func TestArrayBool_String(t *testing.T) {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s) t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
} }
} }
f("")
f("true") f("true")
f("true,false") f("true,false")
f("false,true") f("false,true")
@ -305,7 +303,7 @@ func TestArrayInt_Set(t *testing.T) {
t.Fatalf("unexpected values;\ngot\n%d\nwant\n%d", values, expectedValues) t.Fatalf("unexpected values;\ngot\n%d\nwant\n%d", values, expectedValues)
} }
} }
f("", "", nil) f("", "42", []int{42})
f(`1`, `1`, []int{1}) f(`1`, `1`, []int{1})
f(`-2,3,-64`, `-2,3,-64`, []int{-2, 3, -64}) f(`-2,3,-64`, `-2,3,-64`, []int{-2, 3, -64})
f(`,,-64,`, `42,42,-64,42`, []int{42, 42, -64, 42}) f(`,,-64,`, `42,42,-64,42`, []int{42, 42, -64, 42})
@ -342,7 +340,6 @@ func TestArrayInt_String(t *testing.T) {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s) t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
} }
} }
f("")
f("10,1") f("10,1")
f("-5,1,123") f("-5,1,123")
} }
@ -371,7 +368,7 @@ func TestArrayBytes_Set(t *testing.T) {
t.Fatalf("unexpected values parsed;\ngot\n%s\nwant\n%s", result, expectedResult) t.Fatalf("unexpected values parsed;\ngot\n%s\nwant\n%s", result, expectedResult)
} }
} }
f("", "") f("", "42")
f(`1`, `1`) f(`1`, `1`)
f(`-2,3,10kb`, `-2,3,10KB`) f(`-2,3,10kb`, `-2,3,10KB`)
f(`,,10kb`, `42,42,10KB`) f(`,,10kb`, `42,42,10KB`)
@ -409,7 +406,6 @@ func TestArrayBytes_String(t *testing.T) {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s) t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
} }
} }
f("")
f("10.5KiB,1") f("10.5KiB,1")
f("-5,1,123MB") f("-5,1,123MB")
} }

View file

@ -64,7 +64,6 @@ func TestDictIntSetSuccess(t *testing.T) {
} }
} }
f("")
f("123") f("123")
f("-234") f("-234")
f("foo:123") f("foo:123")
@ -107,8 +106,6 @@ func TestDictIntGet(t *testing.T) {
} }
} }
f("", "", 123, 123)
f("", "foo", 123, 123)
f("foo:42", "", 123, 123) f("foo:42", "", 123, 123)
f("foo:42", "foo", 123, 42) f("foo:42", "foo", 123, 42)
f("532", "", 123, 532) f("532", "", 123, 532)

View file

@ -31,12 +31,14 @@ import (
) )
var ( var (
tlsEnable = flag.Bool("tls", false, "Whether to enable TLS for incoming HTTP requests at -httpListenAddr (aka https). -tlsCertFile and -tlsKeyFile must be set if -tls is set. "+ tlsEnable = flagutil.NewArrayBool("tls", "Whether to enable TLS for incoming HTTP requests at the given -httpListenAddr (aka https). -tlsCertFile and -tlsKeyFile must be set if -tls is set. "+
"See also -mtls") "See also -mtls")
tlsCertFile = flag.String("tlsCertFile", "", "Path to file with TLS certificate if -tls is set. Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated") tlsCertFile = flagutil.NewArrayString("tlsCertFile", "Path to file with TLS certificate for the corresponding -httpListenAddr if -tls is set. "+
tlsKeyFile = flag.String("tlsKeyFile", "", "Path to file with TLS key if -tls is set. The provided key file is automatically re-read every second, so it can be dynamically updated") "Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated")
tlsKeyFile = flagutil.NewArrayString("tlsKeyFile", "Path to file with TLS key for the corresponding -httpListenAddr if -tls is set. "+
"The provided key file is automatically re-read every second, so it can be dynamically updated")
tlsCipherSuites = flagutil.NewArrayString("tlsCipherSuites", "Optional list of TLS cipher suites for incoming requests over HTTPS if -tls is set. See the list of supported cipher suites at https://pkg.go.dev/crypto/tls#pkg-constants") tlsCipherSuites = flagutil.NewArrayString("tlsCipherSuites", "Optional list of TLS cipher suites for incoming requests over HTTPS if -tls is set. See the list of supported cipher suites at https://pkg.go.dev/crypto/tls#pkg-constants")
tlsMinVersion = flag.String("tlsMinVersion", "", "Optional minimum TLS version to use for incoming requests over HTTPS if -tls is set. "+ tlsMinVersion = flagutil.NewArrayString("tlsMinVersion", "Optional minimum TLS version to use for the corresponding -httpListenAddr if -tls is set. "+
"Supported values: TLS10, TLS11, TLS12, TLS13") "Supported values: TLS10, TLS11, TLS12, TLS13")
pathPrefix = flag.String("http.pathPrefix", "", "An optional prefix to add to all the paths handled by http server. For example, if '-http.pathPrefix=/foo/bar' is set, "+ pathPrefix = flag.String("http.pathPrefix", "", "An optional prefix to add to all the paths handled by http server. For example, if '-http.pathPrefix=/foo/bar' is set, "+
@ -77,35 +79,51 @@ type server struct {
// In such cases the caller must serve the request. // In such cases the caller must serve the request.
type RequestHandler func(w http.ResponseWriter, r *http.Request) bool type RequestHandler func(w http.ResponseWriter, r *http.Request) bool
// Serve starts an http server on the given addr with the given optional rh. // Serve starts an http server on the given addrs with the given optional rh.
// //
// By default all the responses are transparently compressed, since egress traffic is usually expensive. // By default all the responses are transparently compressed, since egress traffic is usually expensive.
// //
// The compression is also disabled if -http.disableResponseCompression flag is set. // The compression can be disabled by specifying -http.disableResponseCompression command-line flag.
// //
// If useProxyProtocol is set to true, then the incoming connections are accepted via proxy protocol. // If useProxyProtocol is set to true for the corresponding addr, then the incoming connections are accepted via proxy protocol.
// See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt // See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
func Serve(addr string, useProxyProtocol bool, rh RequestHandler) { func Serve(addrs []string, useProxyProtocol *flagutil.ArrayBool, rh RequestHandler) {
if rh == nil { if rh == nil {
rh = func(w http.ResponseWriter, r *http.Request) bool { rh = func(w http.ResponseWriter, r *http.Request) bool {
return false return false
} }
} }
for idx, addr := range addrs {
if addr == "" {
continue
}
useProxyProto := false
if useProxyProtocol != nil {
useProxyProto = useProxyProtocol.GetOptionalArg(idx)
}
go serve(addr, useProxyProto, rh, idx)
}
}
func serve(addr string, useProxyProtocol bool, rh RequestHandler, idx int) {
scheme := "http" scheme := "http"
if *tlsEnable { if tlsEnable.GetOptionalArg(idx) {
scheme = "https" scheme = "https"
} }
hostAddr := addr hostAddr := addr
if strings.HasPrefix(hostAddr, ":") { if strings.HasPrefix(hostAddr, ":") {
hostAddr = "127.0.0.1" + hostAddr hostAddr = "127.0.0.1" + hostAddr
} }
logger.Infof("starting http server at %s://%s/", scheme, hostAddr) logger.Infof("starting server at %s://%s/", scheme, hostAddr)
logger.Infof("pprof handlers are exposed at %s://%s/debug/pprof/", scheme, hostAddr) logger.Infof("pprof handlers are exposed at %s://%s/debug/pprof/", scheme, hostAddr)
var tlsConfig *tls.Config var tlsConfig *tls.Config
if *tlsEnable { if tlsEnable.GetOptionalArg(idx) {
tc, err := netutil.GetServerTLSConfig(*tlsCertFile, *tlsKeyFile, *tlsMinVersion, *tlsCipherSuites) certFile := tlsCertFile.GetOptionalArg(idx)
keyFile := tlsKeyFile.GetOptionalArg(idx)
minVersion := tlsMinVersion.GetOptionalArg(idx)
tc, err := netutil.GetServerTLSConfig(certFile, keyFile, minVersion, *tlsCipherSuites)
if err != nil { if err != nil {
logger.Fatalf("cannot load TLS cert from -tlsCertFile=%q, -tlsKeyFile=%q, -tlsMinVersion=%q: %s", *tlsCertFile, *tlsKeyFile, *tlsMinVersion, err) logger.Fatalf("cannot load TLS cert from -tlsCertFile=%q, -tlsKeyFile=%q, -tlsMinVersion=%q, -tlsCipherSuites=%q: %s", certFile, keyFile, minVersion, *tlsCipherSuites, err)
} }
tlsConfig = tc tlsConfig = tc
} }
@ -168,15 +186,38 @@ func whetherToCloseConn(r *http.Request) bool {
var connDeadlineTimeKey = interface{}("connDeadlineSecs") var connDeadlineTimeKey = interface{}("connDeadlineSecs")
// Stop stops the http server on the given addr, which has been started // Stop stops the http server on the given addrs, which has been started via Serve func.
// via Serve func. func Stop(addrs []string) error {
func Stop(addr string) error { var errGlobalLock sync.Mutex
var errGlobal error
var wg sync.WaitGroup
for _, addr := range addrs {
if addr == "" {
continue
}
wg.Add(1)
go func(addr string) {
if err := stop(addr); err != nil {
errGlobalLock.Lock()
errGlobal = err
errGlobalLock.Unlock()
}
wg.Done()
}(addr)
}
wg.Wait()
return errGlobal
}
func stop(addr string) error {
serversLock.Lock() serversLock.Lock()
s := servers[addr] s := servers[addr]
delete(servers, addr) delete(servers, addr)
serversLock.Unlock() serversLock.Unlock()
if s == nil { if s == nil {
err := fmt.Errorf("BUG: there is no http server at %q", addr) err := fmt.Errorf("BUG: there is no server at %q", addr)
logger.Panicf("%s", err) logger.Panicf("%s", err)
// The return is needed for golangci-lint: SA5011(related information): this check suggests that the pointer can be nil // The return is needed for golangci-lint: SA5011(related information): this check suggests that the pointer can be nil
return err return err
@ -593,9 +634,9 @@ func (e *ErrorWithStatusCode) Error() string {
return e.Err.Error() return e.Err.Error()
} }
// IsTLS indicates is tls enabled or not // IsTLS indicates is tls enabled or not for -httpListenAddr at the given idx.
func IsTLS() bool { func IsTLS(idx int) bool {
return *tlsEnable return tlsEnable.GetOptionalArg(idx)
} }
// GetPathPrefix - returns http server path prefix. // GetPathPrefix - returns http server path prefix.