Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[processor/resourcedetection]: add "cname" and "lookup" hostname sources #10015

Merged
merged 4 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- `transformprocessor`: Add new `limit` function to allow limiting the number of items in a map, such as the number of attributes in `attributes` or `resource.attributes` (#9552)
- `processor/attributes`: Support attributes set by server authenticator (#9420)
- `datadogexporter`: Experimental support for Exponential Histograms with delta aggregation temporality (#8350)
- `resourcedetectionprocessor`: Add "cname" and "lookup" hostname sources

### 🧰 Bug fixes 🧰

Expand Down
26 changes: 25 additions & 1 deletion processor/resourcedetectionprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ processors:

### System metadata

Note: use the Docker detector (see below) if running the Collector as a Docker container.

Queries the host machine to retrieve the following resource attributes:

* host.name
Expand All @@ -47,8 +49,30 @@ processors:
* all valid options for `hostname_sources`:
* "dns"
* "os"
* "cname"
* "lookup"

Note: use the Docker detector (see below) if running the Collector as a Docker container.
#### Hostname Sources

##### dns

The "dns" hostname source uses multiple sources to get the fully qualified domain name. First, it looks up the
host name in the local machine's `hosts` file. If that fails, it looks up the CNAME. Lastly, if that fails,
it does a reverse DNS query. Note: this hostname source may produce unreliable results on Windows. To produce
a FQDN, Windows hosts might have better results using the "lookup" hostname source, which is mentioned below.

##### os

The "os" hostname source provides the hostname provided by the local machine's kernel.

##### cname

The "cname" hostname source provides the canonical name, as provided by net.LookupCNAME in the Go standard library.
Note: this hostname source may produce unreliable results on Windows.

##### lookup

The "lookup" hostname source does a reverse DNS lookup of the current host's IP address.

### Docker metadata

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package system // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourcedetectionprocessor/internal/system"

import (
"fmt"
"net"
"os"
"runtime"

Expand All @@ -32,6 +34,10 @@ type systemMetadata interface {

// OSType returns the host operating system
OSType() (string, error)

LookupCNAME() (string, error)

ReverseLookupHost() (string, error)
}

type systemMetadataImpl struct{}
Expand All @@ -47,3 +53,53 @@ func (*systemMetadataImpl) FQDN() (string, error) {
func (*systemMetadataImpl) Hostname() (string, error) {
return os.Hostname()
}

func (m *systemMetadataImpl) LookupCNAME() (string, error) {
hostname, err := m.Hostname()
if err != nil {
return "", fmt.Errorf("LookupCNAME failed to get hostname: %w", err)
}
cname, err := net.LookupCNAME(hostname)
if err != nil {
return "", fmt.Errorf("LookupCNAME failed to get CNAME: %w", err)
}
return stripTrailingDot(cname), nil
}

func (m *systemMetadataImpl) ReverseLookupHost() (string, error) {
hostname, err := m.Hostname()
if err != nil {
return "", fmt.Errorf("ReverseLookupHost failed to get hostname: %w", err)
}
return hostnameToDomainName(hostname)
}

func hostnameToDomainName(hostname string) (string, error) {
ipAddresses, err := net.LookupHost(hostname)
if err != nil {
return "", fmt.Errorf("hostnameToDomainName failed to convert hostname to IP addresses: %w", err)
}
return reverseLookup(ipAddresses)
}

func reverseLookup(ipAddresses []string) (string, error) {
var err error
for _, ip := range ipAddresses {
var names []string
names, err = net.LookupAddr(ip)
if err != nil {
continue
}
return stripTrailingDot(names[0]), nil
dmitryax marked this conversation as resolved.
Show resolved Hide resolved
}
return "", fmt.Errorf("reverseLookup failed to convert IP address to name: %w", err)
}

func stripTrailingDot(name string) string {
nameLen := len(name)
lastIdx := nameLen - 1
if nameLen > 0 && name[lastIdx] == '.' {
name = name[:lastIdx]
}
return name
}
27 changes: 23 additions & 4 deletions processor/resourcedetectionprocessor/internal/system/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ const (
)

var hostnameSourcesMap = map[string]func(*Detector) (string, error){
"dns": getFQDN,
"os": getHostname,
"os": getHostname,
"dns": getFQDN,
"cname": lookupCNAME,
"lookup": reverseLookupHost,
}

var _ internal.Detector = (*Detector)(nil)
Expand All @@ -52,6 +54,7 @@ func NewDetector(p component.ProcessorCreateSettings, dcfg internal.DetectorConf
if len(cfg.HostnameSources) == 0 {
cfg.HostnameSources = []string{"dns", "os"}
}

return &Detector{provider: &systemMetadataImpl{}, logger: p.Logger, hostnameSources: cfg.HostnameSources}, nil
}

Expand All @@ -78,7 +81,7 @@ func (d *Detector) Detect(_ context.Context) (resource pcommon.Resource, schemaU
d.logger.Debug(err.Error())
}

return res, "", errors.New("all hostname sources are failed to get hostname")
return res, "", errors.New("all hostname sources failed to get hostname")
}

// getHostname returns OS hostname
Expand All @@ -94,7 +97,23 @@ func getHostname(d *Detector) (string, error) {
func getFQDN(d *Detector) (string, error) {
hostname, err := d.provider.FQDN()
if err != nil {
return "", fmt.Errorf("failed getting FQDN: %w", err)
return "", fmt.Errorf("getFQDN failed getting FQDN: %w", err)
}
return hostname, nil
}

func lookupCNAME(d *Detector) (string, error) {
cname, err := d.provider.LookupCNAME()
if err != nil {
return "", fmt.Errorf("lookupCNAME failed to get CNAME: %w", err)
}
return cname, nil
}

func reverseLookupHost(d *Detector) (string, error) {
hostname, err := d.provider.ReverseLookupHost()
if err != nil {
return "", fmt.Errorf("reverseLookupHost failed to lookup host: %w", err)
}
return hostname, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ func (m *mockMetadata) OSType() (string, error) {
return args.String(0), args.Error(1)
}

func (m *mockMetadata) LookupCNAME() (string, error) {
args := m.MethodCalled("LookupCNAME")
return args.String(0), args.Error(1)
}

func (m *mockMetadata) ReverseLookupHost() (string, error) {
args := m.MethodCalled("ReverseLookupHost")
return args.String(0), args.Error(1)
}

func TestNewDetector(t *testing.T) {
tests := []struct {
name string
Expand Down