Skip to content

Commit cb116ca

Browse files
committed
squash commits
1 parent ac72fb4 commit cb116ca

36 files changed

+6403
-0
lines changed

.github/CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ extension/awsproxy/ @open-telemetry
9191
extension/basicauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @frzifus
9292
extension/bearertokenauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @frzifus
9393
extension/cgroupruntimeextension/ @open-telemetry/collector-contrib-approvers @mx-psi @rogercoll
94+
extension/datadogfleetautomationextension/ @open-telemetry/collector-contrib-approvers @jackgopack4 @dineshg13 @mx-psi
9495
extension/encoding/ @open-telemetry/collector-contrib-approvers @atoulme @dao-jun @dmitryax @MovieStoreGuy @VihasMakwana
9596
extension/encoding/avrologencodingextension/ @open-telemetry/collector-contrib-approvers @thmshmm
9697
extension/encoding/googlecloudlogentryencodingextension/ @open-telemetry/collector-contrib-approvers @alexvanboxel

.github/ISSUE_TEMPLATE/bug_report.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ body:
9393
- extension/basicauth
9494
- extension/bearertokenauth
9595
- extension/cgroupruntime
96+
- extension/datadogfleetautomation
9697
- extension/encoding
9798
- extension/encoding/avrologencoding
9899
- extension/encoding/googlecloudlogentryencoding

.github/ISSUE_TEMPLATE/feature_request.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ body:
8787
- extension/basicauth
8888
- extension/bearertokenauth
8989
- extension/cgroupruntime
90+
- extension/datadogfleetautomation
9091
- extension/encoding
9192
- extension/encoding/avrologencoding
9293
- extension/encoding/googlecloudlogentryencoding

.github/ISSUE_TEMPLATE/other.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ body:
8787
- extension/basicauth
8888
- extension/bearertokenauth
8989
- extension/cgroupruntime
90+
- extension/datadogfleetautomation
9091
- extension/encoding
9192
- extension/encoding/avrologencoding
9293
- extension/encoding/googlecloudlogentryencoding

.github/ISSUE_TEMPLATE/unmaintained.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ body:
9292
- extension/basicauth
9393
- extension/bearertokenauth
9494
- extension/cgroupruntime
95+
- extension/datadogfleetautomation
9596
- extension/encoding
9697
- extension/encoding/avrologencoding
9798
- extension/encoding/googlecloudlogentryencoding

cmd/otelcontribcol/builder-config.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extensions:
2020
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsproxy v0.120.1
2121
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.120.1
2222
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.120.1
23+
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/datadogfleetautomationextension v0.120.1
2324
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/googleclientauthextension v0.120.1
2425
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.120.1
2526
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.120.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../Makefile.Common
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This is the POC for the Datadog Fleet Automation Extension.
2+
3+
You can configure this extension in service, using the following configuration values:
4+
`api::key`: a Datadog API Key, required
5+
`api::site`: your Datadog site value (e.g. us5.datadoghq.com), defaults to "datadoghq.com"
6+
`hostname`: custom hostname; if you do not specify one, the extension will try to infer one. Note: this must match any hostname value set in the `host_metadata` section of Datadog Exporter, if enabled in your collector.
7+
`reporter_period`: A value (given in time notation, e.g. "20m") of time between sending fleet automation data to Datadog backend. Must be 5 minutes or greater.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package datadogfleetautomationextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/datadogfleetautomationextension"
5+
6+
import (
7+
"compress/gzip"
8+
"strings"
9+
10+
coreconfig "github.com/DataDog/datadog-agent/comp/core/config"
11+
corelog "github.com/DataDog/datadog-agent/comp/core/log/def"
12+
"github.com/DataDog/datadog-agent/comp/forwarder/defaultforwarder"
13+
pkgconfigmodel "github.com/DataDog/datadog-agent/pkg/config/model"
14+
"github.com/DataDog/datadog-agent/pkg/config/viperconfig"
15+
"github.com/DataDog/datadog-agent/pkg/serializer"
16+
"github.com/DataDog/datadog-agent/pkg/util/compression"
17+
"github.com/DataDog/datadog-agent/pkg/util/compression/selector"
18+
"go.opentelemetry.io/collector/component"
19+
20+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/datadog"
21+
)
22+
23+
func newLogComponent(set component.TelemetrySettings) corelog.Component {
24+
zlog := &datadog.Zaplogger{
25+
Logger: set.Logger,
26+
}
27+
return zlog
28+
}
29+
30+
// The Forwarder sends the payloads to Datadog backend
31+
func newForwarder(cfg coreconfig.Component, log corelog.Component) defaultforwarder.Forwarder {
32+
keysPerDomain := map[string][]string{"https://api." + cfg.GetString("site"): {cfg.GetString("api_key")}}
33+
return defaultforwarder.NewDefaultForwarder(cfg, log, defaultforwarder.NewOptions(cfg, log, keysPerDomain))
34+
}
35+
36+
// create compressor with Gzip strategy, best compression
37+
func newCompressor() compression.Compressor {
38+
return selector.NewCompressor(compression.GzipKind, gzip.BestCompression)
39+
}
40+
41+
// The Serializer serializes the payloads prior to being forwarded by the Forwarder
42+
func newSerializer(fwd defaultforwarder.Forwarder, cmp compression.Compressor, cfg coreconfig.Component, logger corelog.Component, hostname string) *serializer.Serializer {
43+
return serializer.NewSerializer(fwd, nil, cmp, cfg, logger, hostname)
44+
}
45+
46+
// Config component from datadog-agent is required to use forwarder and serializer components
47+
func newConfigComponent(set component.TelemetrySettings, cfg *Config) coreconfig.Component {
48+
pkgconfig := viperconfig.NewConfig("DD", "DD", strings.NewReplacer(".", "_"))
49+
50+
// Set the API Key
51+
pkgconfig.Set("api_key", string(cfg.API.Key), pkgconfigmodel.SourceFile)
52+
pkgconfig.Set("site", cfg.API.Site, pkgconfigmodel.SourceFile)
53+
pkgconfig.Set("logs_enabled", true, pkgconfigmodel.SourceDefault)
54+
pkgconfig.Set("log_level", set.Logger.Level().String(), pkgconfigmodel.SourceFile)
55+
// Set values for serializer
56+
pkgconfig.Set("enable_payloads.events", true, pkgconfigmodel.SourceDefault)
57+
pkgconfig.Set("enable_payloads.json_to_v1_intake", true, pkgconfigmodel.SourceDefault)
58+
pkgconfig.Set("enable_sketch_stream_payload_serialization", true, pkgconfigmodel.SourceDefault)
59+
pkgconfig.Set("forwarder_apikey_validation_interval", 60, pkgconfigmodel.SourceDefault)
60+
pkgconfig.Set("forwarder_num_workers", 1, pkgconfigmodel.SourceDefault)
61+
pkgconfig.Set("logging_frequency", 2, pkgconfigmodel.SourceDefault)
62+
pkgconfig.Set("forwarder_backoff_factor", 2, pkgconfigmodel.SourceDefault)
63+
pkgconfig.Set("forwarder_backoff_base", 2, pkgconfigmodel.SourceDefault)
64+
pkgconfig.Set("forwarder_backoff_max", 64, pkgconfigmodel.SourceDefault)
65+
pkgconfig.Set("forwarder_recovery_interval", 2, pkgconfigmodel.SourceDefault)
66+
return pkgconfig
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package datadogfleetautomationextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/datadogfleetautomationextension"
5+
6+
import (
7+
"testing"
8+
9+
"github.com/DataDog/datadog-agent/comp/forwarder/defaultforwarder"
10+
implgzip "github.com/DataDog/datadog-agent/pkg/util/compression/impl-gzip"
11+
"github.com/stretchr/testify/assert"
12+
"go.opentelemetry.io/collector/component"
13+
"go.uber.org/zap"
14+
"go.uber.org/zap/zapcore"
15+
16+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/datadog"
17+
)
18+
19+
func TestAgentComponents_NewSerializer(t *testing.T) {
20+
// Create a zap logger for testing
21+
config := zap.NewProductionConfig()
22+
config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
23+
logger, err := config.Build()
24+
if err != nil {
25+
t.Fatalf("Failed to build logger: %v", err)
26+
}
27+
28+
// Create a TelemetrySettings with the test logger
29+
telemetrySettings := component.TelemetrySettings{
30+
Logger: logger,
31+
}
32+
zlog := &datadog.Zaplogger{
33+
Logger: logger,
34+
}
35+
36+
// Create a test Config
37+
cfg := &Config{}
38+
cfg.API.Key = "test-api-key"
39+
cfg.API.Site = "test-site"
40+
41+
// Create a config component
42+
configComponent := newConfigComponent(telemetrySettings, cfg)
43+
44+
// Create a log component
45+
logComponent := newLogComponent(telemetrySettings)
46+
47+
// Create a forwarder
48+
forwarder := newForwarder(configComponent, logComponent)
49+
50+
// Create a compressor
51+
compressor := newCompressor()
52+
53+
// Call newSerializer
54+
serial := newSerializer(forwarder, compressor, configComponent, zlog, "test-hostname")
55+
56+
// Assert that the returned serializer is not nil
57+
assert.NotNil(t, serial)
58+
59+
// Assert that the serializer has the correct configuration
60+
assert.Equal(t, forwarder, serial.Forwarder)
61+
assert.Equal(t, compressor, serial.Strategy)
62+
}
63+
64+
func TestAgentComponents_NewCompressor(t *testing.T) {
65+
// Call newCompressor
66+
compressor := newCompressor()
67+
68+
// Assert that the returned compressor is not nil
69+
assert.NotNil(t, compressor)
70+
71+
// Assert that the returned compressor is of type *compression.GzipCompressor
72+
_, ok := compressor.(*implgzip.GzipStrategy)
73+
assert.True(t, ok, "Expected compressor to be of type *compression.GzipCompressor")
74+
}
75+
76+
func TestAgentComponents_NewForwarder(t *testing.T) {
77+
// Create a zap logger for testing
78+
config := zap.NewProductionConfig()
79+
config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
80+
logger, err := config.Build()
81+
if err != nil {
82+
t.Fatalf("Failed to build logger: %v", err)
83+
}
84+
85+
// Create a TelemetrySettings with the test logger
86+
telemetrySettings := component.TelemetrySettings{
87+
Logger: logger,
88+
}
89+
90+
// Create a test Config
91+
cfg := &Config{}
92+
cfg.API.Key = "test-api-key"
93+
cfg.API.Site = "test-site"
94+
95+
// Create a config component
96+
configComponent := newConfigComponent(telemetrySettings, cfg)
97+
98+
// Create a log component
99+
logComponent := newLogComponent(telemetrySettings)
100+
101+
// Call newForwarder
102+
forwarder := newForwarder(configComponent, logComponent)
103+
104+
// Assert that the returned forwarder is not nil
105+
assert.NotNil(t, forwarder)
106+
107+
// Assert that the returned forwarder is of type *defaultforwarder.DefaultForwarder
108+
_, ok := forwarder.(*defaultforwarder.DefaultForwarder)
109+
assert.True(t, ok, "Expected forwarder to be of type *defaultforwarder.DefaultForwarder")
110+
111+
// Assert that forwarder implements defaultForwarderInterface
112+
_, ok = forwarder.(defaultForwarderInterface)
113+
assert.True(t, ok, "Expected forwarder to implement defaultForwarderInterface")
114+
}
115+
116+
func TestAgentComponents_NewLogComponent(t *testing.T) {
117+
// Create a zap logger for testing
118+
config := zap.NewProductionConfig()
119+
config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
120+
logger, err := config.Build()
121+
if err != nil {
122+
t.Fatalf("Failed to build logger: %v", err)
123+
}
124+
125+
// Create a TelemetrySettings with the test logger
126+
telemetrySettings := component.TelemetrySettings{
127+
Logger: logger,
128+
}
129+
130+
// Call newLogComponent
131+
logComponent := newLogComponent(telemetrySettings)
132+
133+
// Assert that the returned component is not nil
134+
assert.NotNil(t, logComponent)
135+
136+
// Assert that the returned component is of type *datadog.Zaplogger
137+
zlog, ok := logComponent.(*datadog.Zaplogger)
138+
assert.True(t, ok, "Expected logComponent to be of type *datadog.Zaplogger")
139+
140+
// Assert that the logger is correctly set
141+
assert.Equal(t, logger, zlog.Logger)
142+
}
143+
144+
func TestAgentComponents_NewConfigComponent(t *testing.T) {
145+
// Create a zap logger for testing
146+
config := zap.NewProductionConfig()
147+
config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
148+
logger, err := config.Build()
149+
if err != nil {
150+
t.Fatalf("Failed to build logger: %v", err)
151+
}
152+
153+
// Create a TelemetrySettings with the test logger
154+
telemetrySettings := component.TelemetrySettings{
155+
Logger: logger,
156+
}
157+
158+
// Create a test Config
159+
cfg := &Config{}
160+
cfg.API.Key = "test-api-key"
161+
cfg.API.Site = "test-site"
162+
163+
// Call newConfigComponent
164+
configComponent := newConfigComponent(telemetrySettings, cfg)
165+
166+
// Assert that the returned component is not nil
167+
assert.NotNil(t, configComponent)
168+
169+
// Assert that the configuration values are set correctly
170+
assert.Equal(t, "test-api-key", configComponent.GetString("api_key"))
171+
assert.Equal(t, "test-site", configComponent.GetString("site"))
172+
assert.Equal(t, "info", configComponent.GetString("log_level"))
173+
assert.True(t, configComponent.GetBool("logs_enabled"))
174+
assert.True(t, configComponent.GetBool("enable_payloads.events"))
175+
assert.True(t, configComponent.GetBool("enable_payloads.json_to_v1_intake"))
176+
assert.True(t, configComponent.GetBool("enable_sketch_stream_payload_serialization"))
177+
assert.Equal(t, 60, configComponent.GetInt("forwarder_apikey_validation_interval"))
178+
assert.Equal(t, 1, configComponent.GetInt("forwarder_num_workers"))
179+
assert.Equal(t, 2, configComponent.GetInt("logging_frequency"))
180+
assert.Equal(t, 2, configComponent.GetInt("forwarder_backoff_factor"))
181+
assert.Equal(t, 2, configComponent.GetInt("forwarder_backoff_base"))
182+
assert.Equal(t, 64, configComponent.GetInt("forwarder_backoff_max"))
183+
assert.Equal(t, 2, configComponent.GetInt("forwarder_recovery_interval"))
184+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package datadogfleetautomationextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/datadogfleetautomationextension"
5+
6+
import (
7+
"errors"
8+
"fmt"
9+
"strings"
10+
"time"
11+
12+
"go.opentelemetry.io/collector/component"
13+
"go.opentelemetry.io/collector/config/confighttp"
14+
15+
datadogconfig "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/datadog/config"
16+
)
17+
18+
var (
19+
// ErrUnsetAPIKey is returned when the API key is not set.
20+
ErrUnsetAPIKey = datadogconfig.ErrUnsetAPIKey
21+
// ErrEmptyEndpoint is returned when endpoint is empty
22+
ErrEmptyEndpoint = datadogconfig.ErrEmptyEndpoint
23+
// ErrAPIKeyFormat is returned if API key contains invalid characters
24+
ErrAPIKeyFormat = datadogconfig.ErrAPIKeyFormat
25+
// NonHexRegex is a regex of characters that are always invalid in a Datadog API Key
26+
NonHexRegex = datadogconfig.NonHexRegex
27+
)
28+
29+
var _ component.Config = (*Config)(nil)
30+
31+
const (
32+
// DefaultSite is the default site for the Datadog API.
33+
DefaultSite = datadogconfig.DefaultSite
34+
// NonHexChars is a regex of characters that are always invalid in a Datadog API key.
35+
NonHexChars = datadogconfig.NonHexChars
36+
// DefaultReporterPeriod is the default amount of time between sending fleet automation payloads to Datadog.
37+
DefaultReporterPeriod = 20 * time.Minute
38+
)
39+
40+
// Config contains the information necessary for enabling the Datadog Fleet
41+
// Automation Extension.
42+
type Config struct {
43+
confighttp.ClientConfig `mapstructure:",squash"`
44+
API APIConfig `mapstructure:"api"`
45+
// If Hostname is empty extension will use available system APIs and cloud provider endpoints.
46+
Hostname string `mapstructure:"hostname"`
47+
// ReporterPeriod sets the amount of time between sending fleet automation payloads to Datadog.
48+
ReporterPeriod time.Duration `mapstructure:"reporter_period"`
49+
}
50+
51+
// APIConfig contains the information necessary for configuring the Datadog API.
52+
type APIConfig = datadogconfig.APIConfig
53+
54+
// Validate ensures that the configuration is valid.
55+
func (c *Config) Validate() error {
56+
if c.API.Site == "" {
57+
return ErrEmptyEndpoint
58+
}
59+
if c.API.Key == "" {
60+
return ErrUnsetAPIKey
61+
}
62+
invalidAPIKeyChars := NonHexRegex.FindAllString(string(c.API.Key), -1)
63+
if len(invalidAPIKeyChars) > 0 {
64+
return fmt.Errorf("%w: invalid characters: %s", ErrAPIKeyFormat, strings.Join(invalidAPIKeyChars, ", "))
65+
}
66+
if c.ReporterPeriod < 5*time.Minute {
67+
return errors.New("reporter_period must be 5 minutes or higher")
68+
}
69+
return nil
70+
}

0 commit comments

Comments
 (0)