Skip to content

Commit

Permalink
Remote Host name resolution (#26985)
Browse files Browse the repository at this point in the history
  • Loading branch information
dineshg13 committed Jun 24, 2024
1 parent eb1b1dc commit 6ca5917
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 25 deletions.
30 changes: 5 additions & 25 deletions cmd/otel-agent/subcommands/run/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
"github.com/DataDog/datadog-agent/cmd/otel-agent/subcommands"
"github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl"
coreconfig "github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/comp/core/hostname/hostnameimpl"
"github.com/DataDog/datadog-agent/comp/core/hostname/hostnameinterface"
"github.com/DataDog/datadog-agent/comp/core/hostname/remotehostnameimpl"
corelog "github.com/DataDog/datadog-agent/comp/core/log"
corelogimpl "github.com/DataDog/datadog-agent/comp/core/log/logimpl"
"github.com/DataDog/datadog-agent/comp/core/log/tracelogimpl"
Expand Down Expand Up @@ -44,7 +45,6 @@ import (
traceconfig "github.com/DataDog/datadog-agent/comp/trace/config"
pkgconfigenv "github.com/DataDog/datadog-agent/pkg/config/env"
pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup"
"github.com/DataDog/datadog-agent/pkg/security/utils"
"github.com/DataDog/datadog-agent/pkg/serializer"
"github.com/DataDog/datadog-agent/pkg/trace/telemetry"
"github.com/DataDog/datadog-agent/pkg/util/fxutil"
Expand Down Expand Up @@ -87,31 +87,12 @@ func (o *orchestratorinterfaceimpl) Reset() {
o.f = nil
}

// TODO create a alternative implementation for hostname.Component that uses the remote host
// The logic is used by other agents, and so having it exposed as Component would be useful
type remotehostimpl struct {
hostname string
}

func (r *remotehostimpl) Get(ctx context.Context) (string, error) {
if r.hostname != "" {
return r.hostname, nil
}
hostname, err := utils.GetHostnameWithContextAndFallback(ctx)
if err != nil {
return "", err
}
r.hostname = hostname
return hostname, nil
}

func runOTelAgentCommand(ctx context.Context, params *subcommands.GlobalParams, opts ...fx.Option) error {
err := fxutil.Run(
forwarder.Bundle(),
tracelogimpl.Module(), // cannot have corelogimpl and tracelogimpl at the same time
inventoryagentimpl.Module(),
workloadmetafx.Module(),
hostnameimpl.Module(),
statsd.Module(),
sysprobeconfig.NoneModule(),
fetchonlyimpl.Module(),
Expand All @@ -135,11 +116,10 @@ func runOTelAgentCommand(ctx context.Context, params *subcommands.GlobalParams,
fx.Provide(func() []string {
return append(params.ConfPaths, params.Sets...)
}),
fx.Provide(func() (serializerexporter.SourceProviderFunc, error) {
rh := &remotehostimpl{}
return rh.Get, nil
fx.Provide(func(h hostnameinterface.Component) (serializerexporter.SourceProviderFunc, error) {
return h.Get, nil
}),

remotehostnameimpl.Module(),
fx.Supply(optional.NewNoneOption[secrets.Component]()),

fx.Provide(func(c coreconfig.Component) corelogimpl.Params {
Expand Down
133 changes: 133 additions & 0 deletions comp/core/hostname/remotehostnameimpl/hostname.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2023-present Datadog, Inc.

// Package remotehostnameimpl provides a function to get the hostname from core agent.
package remotehostnameimpl

import (
"context"
"time"

"github.com/avast/retry-go/v4"

"github.com/DataDog/datadog-agent/pkg/config"
pbgo "github.com/DataDog/datadog-agent/pkg/proto/pbgo/core"
"github.com/DataDog/datadog-agent/pkg/util/fxutil"
"github.com/DataDog/datadog-agent/pkg/util/grpc"
"github.com/DataDog/datadog-agent/pkg/util/hostname"
"github.com/DataDog/datadog-agent/pkg/util/log"

"github.com/DataDog/datadog-agent/comp/core/hostname/hostnameinterface"
cache "github.com/patrickmn/go-cache"
"go.uber.org/fx"
)

const (
defaultExpire = 15 * time.Minute
defaultPurge = 30 * time.Second
// AgentCachePrefix is the common root to use to prefix all the cache
// keys for any value regarding the Agent
AgentCachePrefix = "agent"

// encapsulate the cache module for easy refactoring

// NoExpiration maps to go-cache corresponding value
NoExpiration = cache.NoExpiration
// maxAttempts is the maximum number of times we try to get the hostname
// from the core-agent before bailing out.
maxAttempts = 6
)

// Module defines the fx options for this component.
func Module() fxutil.Module {
return fxutil.Component(
fx.Provide(newRemoteHostImpl))
}

var cachKey = "hostname"

type remotehostimpl struct {
cache *cache.Cache
}

func newRemoteHostImpl() hostnameinterface.Component {
return &remotehostimpl{
cache: cache.New(defaultExpire, defaultPurge),
}
}

func (r *remotehostimpl) Get(ctx context.Context) (string, error) {
if hostname, found := r.cache.Get(cachKey); found {
return hostname.(string), nil
}
hostname, err := getHostnameWithContextAndFallback(ctx)
if err != nil {
return "", err
}
r.cache.Set(cachKey, hostname, NoExpiration)
return hostname, nil
}

func (r *remotehostimpl) GetSafe(ctx context.Context) string {
h, _ := r.Get(ctx)
return h
}

func (r *remotehostimpl) GetWithProvider(ctx context.Context) (hostnameinterface.Data, error) {
h, err := r.Get(ctx)
if err != nil {
return hostnameinterface.Data{}, err
}
return hostnameinterface.Data{
Hostname: h,
Provider: "remote",
}, nil
}

// getHostnameWithContext attempts to acquire a hostname by connecting to the
// core agent's gRPC endpoints extending the given context.
func getHostnameWithContext(ctx context.Context) (string, error) {
var hostname string
err := retry.Do(func() error {
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()

ipcAddress, err := config.GetIPCAddress()
if err != nil {
return err
}

client, err := grpc.GetDDAgentClient(ctx, ipcAddress, config.GetIPCPort())
if err != nil {
return err
}

reply, err := client.GetHostname(ctx, &pbgo.HostnameRequest{})
if err != nil {
return err
}

log.Debugf("Acquired hostname from gRPC: %s", reply.Hostname)

hostname = reply.Hostname
return nil
}, retry.LastErrorOnly(true), retry.Attempts(maxAttempts), retry.Context(ctx))
return hostname, err
}

// getHostnameWithContextAndFallback attempts to acquire a hostname by connecting to the
// core agent's gRPC endpoints extending the given context, or falls back to local resolution
func getHostnameWithContextAndFallback(ctx context.Context) (string, error) {
hostnameDetected, err := getHostnameWithContext(ctx)
if err != nil {
log.Warnf("Could not resolve hostname from core-agent: %v", err)
hostnameDetected, err = hostname.Get(ctx)
if err != nil {
return "", err
}
}
log.Infof("Hostname is: %s", hostnameDetected)
return hostnameDetected, nil
}

0 comments on commit 6ca5917

Please sign in to comment.