Skip to content

Commit

Permalink
add simpler system-probe client
Browse files Browse the repository at this point in the history
  • Loading branch information
brycekahle committed Nov 15, 2024
1 parent 718aea5 commit 8c1d827
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 150 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
/cmd/system-probe/modules/dynamic_instrumentation* @DataDog/debugger
/cmd/system-probe/windows_resources/ @DataDog/windows-kernel-integrations
/cmd/system-probe/main_windows*.go @DataDog/windows-kernel-integrations
/cmd/system-probe/api/client/client_windows.go @DataDog/windows-kernel-integrations
/cmd/systray/ @DataDog/windows-agent
/cmd/security-agent/ @DataDog/agent-security
/cmd/installer/ @DataDog/fleet @DataDog/windows-agent
Expand Down
25 changes: 23 additions & 2 deletions cmd/system-probe/api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,31 @@
package client

import (
"errors"
"net/http"
"time"

"github.com/DataDog/datadog-agent/pkg/util/funcs"
)

var (
// ErrNotImplemented is an error used when system-probe is attempted to be accessed on an unsupported OS
ErrNotImplemented = errors.New("system-probe unsupported")
)

// Get returns a http client configured to talk to the system-probe
func Get(socketPath string) *http.Client {
return newSystemProbeClient(socketPath)
var Get = funcs.MemoizeArgNoError[string, *http.Client](get)

func get(socketPath string) *http.Client {
return &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 2,
IdleConnTimeout: idleConnTimeout,
DialContext: DialContextFunc(socketPath),
TLSHandshakeTimeout: 1 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
ExpectContinueTimeout: 50 * time.Millisecond,
},
}
}
37 changes: 0 additions & 37 deletions cmd/system-probe/api/client/client_linux.go

This file was deleted.

23 changes: 6 additions & 17 deletions cmd/system-probe/api/client/client_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,23 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build !linux && !windows
//go:build !unix && !windows

package client

import (
"context"
"net"
"net/http"
"time"
)

const (
netType = "tcp"
idleConnTimeout = 30 * time.Second
)

// newSystemProbeClient returns a http client configured to talk to the system-probe
func newSystemProbeClient(socketPath string) *http.Client {
return &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(netType, socketPath)
},
TLSHandshakeTimeout: 1 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
ExpectContinueTimeout: 50 * time.Millisecond,
},
// DialContextFunc is not supported on this platform.
func DialContextFunc(_ string) func(context.Context, string, string) (net.Conn, error) {
return func(_ context.Context, _, _ string) (net.Conn, error) {
return nil, ErrNotImplemented
}
}
26 changes: 26 additions & 0 deletions cmd/system-probe/api/client/client_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 2016-present Datadog, Inc.

//go:build unix

package client

import (
"context"
"net"
"time"
)

const (
idleConnTimeout = 30 * time.Second
)

// DialContextFunc returns a function to be used in http.Transport.DialContext for connecting to system-probe.
// The result will be OS-specific.
func DialContextFunc(socketPath string) func(context.Context, string, string) (net.Conn, error) {
return func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", socketPath)
}
}
43 changes: 36 additions & 7 deletions cmd/system-probe/api/client/client_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,43 @@
package client

import (
"net/http"
"context"
"fmt"
"net"
"time"

processNet "github.com/DataDog/datadog-agent/pkg/process/net"
"github.com/Microsoft/go-winio"

"github.com/DataDog/datadog-agent/pkg/util/log"
)

const (
idleConnTimeout = 5 * time.Second
)

// newSystemProbeClient returns a http client configured to talk to the system-probe
// This is a simple wrapper around process_net.NewSystemProbeHttpClient because
// Linux is unable to import pkg/process/net due to size restrictions.
func newSystemProbeClient(_ string) *http.Client {
return processNet.NewSystemProbeClient()
var (
// SystemProbePipeName is the production named pipe for system probe
SystemProbePipeName = `\\.\pipe\dd_system_probe`
)

// DialContextFunc returns a function to be used in http.Transport.DialContext for connecting to system-probe.
// The result will be OS-specific.
func DialContextFunc(_ string) func(context.Context, string, string) (net.Conn, error) {
return func(_ context.Context, _, _ string) (net.Conn, error) {
// Go clients do not immediately close (named pipe) connections when done,
// they keep connections idle for a while. Make sure the idle time
// is not too high and the timeout is generous enough for pending connections.
var timeout = 30 * time.Second

namedPipe, err := winio.DialPipe(SystemProbePipeName, &timeout)
if err != nil {
// This important error may not get reported upstream, making connection failures
// very difficult to diagnose. Explicitly log the error here too for diagnostics.
var namedPipeErr = fmt.Errorf("error connecting to named pipe %q: %s", SystemProbePipeName, err)
log.Error(namedPipeErr.Error())
return nil, namedPipeErr
}

return namedPipe, nil
}
}
32 changes: 7 additions & 25 deletions pkg/process/net/common_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
package net

import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"os"
"time"

"github.com/DataDog/datadog-agent/cmd/system-probe/api/client"
sysconfig "github.com/DataDog/datadog-agent/cmd/system-probe/config"
)

Expand All @@ -34,14 +33,13 @@ const (
conntrackCachedURL = "http://unix/" + string(sysconfig.NetworkTracerModule) + "/debug/conntrack/cached"
conntrackHostURL = "http://unix/" + string(sysconfig.NetworkTracerModule) + "/debug/conntrack/host"
ebpfBTFLoaderURL = "http://unix/debug/ebpf_btf_loader_info"
netType = "unix"
)

// CheckPath is used in conjunction with calling the stats endpoint, since we are calling this
// From the main agent and want to ensure the socket exists
func CheckPath(path string) error {
if path == "" {
return fmt.Errorf("socket path is empty")
return errors.New("socket path is empty")
}

if _, err := os.Stat(path); err != nil {
Expand All @@ -53,34 +51,18 @@ func CheckPath(path string) error {
// newSystemProbe creates a group of clients to interact with system-probe.
func newSystemProbe(path string) *RemoteSysProbeUtil {
return &RemoteSysProbeUtil{
path: path,
httpClient: http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 2,
IdleConnTimeout: 30 * time.Second,
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(netType, path)
},
TLSHandshakeTimeout: 1 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
ExpectContinueTimeout: 50 * time.Millisecond,
},
},
path: path,
httpClient: *client.Get(path),
pprofClient: http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(netType, path)
},
DialContext: client.DialContextFunc(path),
},
},
tracerouteClient: http.Client{
// no timeout set here, the expected usage of this client
// is that the caller will set a timeout on each request
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(netType, path)
},
DialContext: client.DialContextFunc(path),
},
},
}
Expand Down
37 changes: 5 additions & 32 deletions pkg/process/net/common_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@
package net

import (
"context"
"errors"
"fmt"
"net"
"net/http"
"time"

"github.com/DataDog/datadog-agent/cmd/system-probe/api/client"
sysconfig "github.com/DataDog/datadog-agent/cmd/system-probe/config"
)

Expand All @@ -26,7 +24,6 @@ const (
statsURL = "http://localhost:3333/debug/stats"
pprofURL = "http://localhost:3333/debug/pprof"
tracerouteURL = "http://localhost:3333/" + string(sysconfig.TracerouteModule) + "/traceroute/"
netType = "tcp"
telemetryURL = "http://localhost:3333/telemetry"

// discovery* is not used on Windows, the value is added to avoid a compilation error
Expand All @@ -40,9 +37,6 @@ const (
// conntrackHostURL is not used on Windows, the value is added to avoid a compilation error
conntrackHostURL = "http://localhost:3333/" + string(sysconfig.NetworkTracerModule) + "/debug/conntrack/host"

// SystemProbePipeName is the production named pipe for system probe
SystemProbePipeName = `\\.\pipe\dd_system_probe`

// systemProbeMaxIdleConns sets the maximum number of idle named pipe connections.
systemProbeMaxIdleConns = 2

Expand All @@ -55,40 +49,21 @@ const (
// CheckPath is used to make sure the globalSocketPath has been set before attempting to connect
func CheckPath(path string) error {
if path == "" {
return fmt.Errorf("socket path is empty")
return errors.New("socket path is empty")
}
return nil
}

// NewSystemProbeClient returns a http client configured to talk to the system-probe
func NewSystemProbeClient() *http.Client {
return &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: systemProbeMaxIdleConns,
IdleConnTimeout: systemProbeIdleConnTimeout,
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return DialSystemProbe()
},
TLSHandshakeTimeout: 1 * time.Second,
ResponseHeaderTimeout: 2 * time.Second,
ExpectContinueTimeout: 50 * time.Millisecond,
},
}
}

// newSystemProbe creates a group of clients to interact with system-probe.
func newSystemProbe(path string) *RemoteSysProbeUtil {
return &RemoteSysProbeUtil{
path: path,
httpClient: *NewSystemProbeClient(),
httpClient: *client.Get(path),
pprofClient: http.Client{
Transport: &http.Transport{
MaxIdleConns: systemProbeMaxIdleConns,
IdleConnTimeout: systemProbeIdleConnTimeout,
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return DialSystemProbe()
},
DialContext: client.DialContextFunc(path),
},
},
tracerouteClient: http.Client{
Expand All @@ -97,9 +72,7 @@ func newSystemProbe(path string) *RemoteSysProbeUtil {
Transport: &http.Transport{
MaxIdleConns: systemProbeMaxIdleConns,
IdleConnTimeout: systemProbeIdleConnTimeout,
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return DialSystemProbe()
},
DialContext: client.DialContextFunc(path),
},
},
}
Expand Down
Loading

0 comments on commit 8c1d827

Please sign in to comment.