telemetry: try guess hostname or external IP addr for metrics (#2412)

This commit is contained in:
wasaga 2021-08-03 18:10:14 -04:00 committed by GitHub
parent 94eb3c1149
commit 204aa30b6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 15 deletions

View file

@ -0,0 +1,67 @@
package registry
import (
"errors"
"fmt"
"net"
"os"
"strings"
)
func isFQDN(host string) bool {
return strings.Count(host, ".") > 1
}
func chooseIP(ips []net.IP) net.IP {
for _, ip := range ips {
if !ip.IsLoopback() && !ip.IsInterfaceLocalMulticast() && !ip.IsLinkLocalUnicast() && !ip.IsLinkLocalMulticast() {
return ip
}
}
return nil
}
// getViaLookup tries to lookup whether short hostname may be resolved into IP and back into a longer one
func getViaLookup(host string) (string, error) {
addrs, err := net.LookupIP(host)
if err != nil {
return "", err
}
if len(addrs) == 0 {
return "", errors.New("address lookup failed")
}
for _, addr := range addrs {
hosts, err := net.LookupAddr(addr.String())
if err != nil {
continue
}
for _, h := range hosts {
h = strings.TrimSuffix(h, ".")
if isFQDN(h) {
return h, nil
}
}
}
if ip := chooseIP(addrs); ip != nil {
return ip.String(), nil
}
return "", errors.New("lookup failed")
}
// getHostOrIP tries to fetch a publicly accessible IP address for the current host/container
func getHostOrIP() (string, error) {
host, err := os.Hostname()
if err != nil {
return "", fmt.Errorf("hostname: %w", err)
}
if isFQDN(host) {
return host, nil
}
if h, err := getViaLookup(host); err == nil {
return h, nil
}
return host, nil
}

View file

@ -81,9 +81,22 @@ func getReportedServices(cfg *config.Config) ([]*pb.Service, error) {
}
func metricsURL(o config.Options) (*url.URL, error) {
host, port, err := net.SplitHostPort(o.MetricsAddr)
if err != nil {
return nil, fmt.Errorf("invalid metrics address %q: %w", o.MetricsAddr, err)
}
if port == "" {
return nil, fmt.Errorf("invalid metrics value %q: port is required", o.MetricsAddr)
}
if host == "" {
if host, err = getHostOrIP(); err != nil {
return nil, fmt.Errorf("could not guess hostname: %w", err)
}
}
u := url.URL{
Scheme: "http",
Host: o.MetricsAddr,
Host: net.JoinHostPort(host, port),
Path: defaultMetricsPath,
}
@ -107,19 +120,6 @@ func metricsURL(o config.Options) (*url.URL, error) {
return nil, fmt.Errorf("no metrics address provided")
}
host, port, err := net.SplitHostPort(o.MetricsAddr)
if err != nil {
return nil, fmt.Errorf("invalid metrics address %q: %w", o.MetricsAddr, err)
}
if port == "" {
return nil, fmt.Errorf("invalid metrics value %q: port is required", o.MetricsAddr)
}
if host == "" {
return nil, fmt.Errorf("invalid metrics value %q: either host or IP address is required", o.MetricsAddr)
}
return &u, nil
}

View file

@ -24,7 +24,6 @@ func TestMetricsURL(t *testing.T) {
for _, opt := range []config.Options{
{MetricsAddr: "my.host:"},
{MetricsAddr: "my.host:9090", MetricsBasicAuth: "SMTH"},
{MetricsAddr: ":9090"},
{MetricsAddr: "my.host"},
} {
_, err := metricsURL(opt)