From 8dd21e9b16aa03778bdfad311385d5a6b3a394bc Mon Sep 17 00:00:00 2001 From: Jeffrey Zhang Date: Mon, 26 Feb 2024 11:23:42 +0800 Subject: [PATCH] Support listen on vsock With this patch, node_exporter can run with `--web.listen-address=vsock: //:9100` to listen on vsock in qemu guest. Then host can get the metrics. Signed-off-by: Jeffrey Zhang --- go.mod | 2 ++ go.sum | 4 ++++ web/kingpinflag/flag.go | 2 +- web/tls_config.go | 47 +++++++++++++++++++++++++++++++++++------ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 29374daf..44dff9d7 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.4.0 github.com/coreos/go-systemd/v22 v22.5.0 github.com/go-kit/log v0.2.1 + github.com/mdlayher/vsock v1.2.1 github.com/prometheus/common v0.51.1 golang.org/x/crypto v0.21.0 golang.org/x/sync v0.6.0 @@ -20,6 +21,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/client_golang v1.19.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect diff --git a/go.sum b/go.sum index ccbd62c8..b434d6a9 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/web/kingpinflag/flag.go b/web/kingpinflag/flag.go index 3d5dbb63..e5dd4b42 100644 --- a/web/kingpinflag/flag.go +++ b/web/kingpinflag/flag.go @@ -33,7 +33,7 @@ func AddFlags(a *kingpin.Application, defaultAddress string) *web.FlagConfig { flags := web.FlagConfig{ WebListenAddresses: a.Flag( "web.listen-address", - "Addresses on which to expose metrics and web interface. Repeatable for multiple addresses.", + "Addresses on which to expose metrics and web interface. Repeatable for multiple addresses. Examples: `:9100` or `127.0.0.1:9100` for http, `vsock://:9100` for vsock", ).Default(defaultAddress).HintOptions(defaultAddress).Strings(), WebSystemdSocket: systemdSocket, WebConfigFile: a.Flag( diff --git a/web/tls_config.go b/web/tls_config.go index 61383bce..00dae1e4 100644 --- a/web/tls_config.go +++ b/web/tls_config.go @@ -20,12 +20,16 @@ import ( "fmt" "net" "net/http" + "net/url" "os" "path/filepath" + "strconv" + "strings" "github.com/coreos/go-systemd/v22/activation" "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/mdlayher/vsock" config_util "github.com/prometheus/common/config" "golang.org/x/sync/errgroup" "gopkg.in/yaml.v2" @@ -275,9 +279,11 @@ func ServeMultiple(listeners []net.Listener, server *http.Server, flags *FlagCon } // ListenAndServe starts the server on addresses given in WebListenAddresses in -// the FlagConfig or instead uses systemd socket activated listeners if -// WebSystemdSocket in the FlagConfig is true. The FlagConfig is also passed on -// to ServeMultiple. +// the FlagConfig. When address starts looks like vsock://:{port}, it listens on +// vsock. More info check https://wiki.qemu.org/Features/VirtioVsock . +// Or instead uses systemd socket activated listeners if WebSystemdSocket in the +// FlagConfig is true. +// The FlagConfig is also passed on to ServeMultiple. func ListenAndServe(server *http.Server, flags *FlagConfig, logger log.Logger) error { if flags.WebSystemdSocket == nil && (flags.WebListenAddresses == nil || len(*flags.WebListenAddresses) == 0) { return ErrNoListeners @@ -297,9 +303,22 @@ func ListenAndServe(server *http.Server, flags *FlagConfig, logger log.Logger) e listeners := make([]net.Listener, 0, len(*flags.WebListenAddresses)) for _, address := range *flags.WebListenAddresses { - listener, err := net.Listen("tcp", address) - if err != nil { - return err + var err error + var listener net.Listener + if strings.HasPrefix(address, "vsock://") { + port, err := parseVsockPort(address) + if err != nil { + return err + } + listener, err = vsock.Listen(port, nil) + if err != nil { + return err + } + } else { + listener, err = net.Listen("tcp", address) + if err != nil { + return nil + } } defer listener.Close() listeners = append(listeners, listener) @@ -307,6 +326,22 @@ func ListenAndServe(server *http.Server, flags *FlagConfig, logger log.Logger) e return ServeMultiple(listeners, server, flags, logger) } +func parseVsockPort(address string) (uint32, error) { + uri, err := url.Parse(address) + if err != nil { + return 0, err + } + _, portStr, err := net.SplitHostPort(uri.Host) + if err != nil { + return 0, err + } + port, err := strconv.ParseUint(portStr, 10, 32) + if err != nil { + return 0, err + } + return uint32(port), nil +} + // Server starts the server on the given listener. Based on the file path // WebConfigFile in the FlagConfig, TLS or basic auth could be enabled. func Serve(l net.Listener, server *http.Server, flags *FlagConfig, logger log.Logger) error {