Skip to content

Commit 8ebe098

Browse files
authored
[service] Allow running the Collector without any pipelines (#12613)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Adds a feature gate that allows starting the Collector without running any pipelines. This will mainly be used for OpAMP, where the Collector may need to be started with only extensions
1 parent da4512d commit 8ebe098

File tree

5 files changed

+72
-7
lines changed

5 files changed

+72
-7
lines changed

.chloggen/allow-no-pipelines.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: service
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add `service.AllowNoPipelines` feature gate to allow starting the Collector without pipelines.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [12613]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: This can be used to start with only extensions.
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: []

otelcol/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"go.opentelemetry.io/collector/component"
1111
"go.opentelemetry.io/collector/service"
12+
"go.opentelemetry.io/collector/service/pipelines"
1213
)
1314

1415
var (
@@ -50,13 +51,13 @@ func (cfg *Config) Validate() error {
5051

5152
// Currently, there is no default receiver enabled.
5253
// The configuration must specify at least one receiver to be valid.
53-
if len(cfg.Receivers) == 0 {
54+
if !pipelines.AllowNoPipelines.IsEnabled() && len(cfg.Receivers) == 0 {
5455
return errMissingReceivers
5556
}
5657

5758
// Currently, there is no default exporter enabled.
5859
// The configuration must specify at least one exporter to be valid.
59-
if len(cfg.Exporters) == 0 {
60+
if !pipelines.AllowNoPipelines.IsEnabled() && len(cfg.Exporters) == 0 {
6061
return errMissingExporters
6162
}
6263

otelcol/config_test.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import (
88
"fmt"
99
"testing"
1010

11-
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
1212
config "go.opentelemetry.io/contrib/otelconf/v0.3.0"
1313
"go.uber.org/zap/zapcore"
1414

1515
"go.opentelemetry.io/collector/component"
1616
"go.opentelemetry.io/collector/config/configtelemetry"
1717
"go.opentelemetry.io/collector/confmap/xconfmap"
18+
"go.opentelemetry.io/collector/featuregate"
1819
"go.opentelemetry.io/collector/pipeline"
1920
"go.opentelemetry.io/collector/service"
2021
"go.opentelemetry.io/collector/service/pipelines"
@@ -244,14 +245,31 @@ func TestConfigValidate(t *testing.T) {
244245
cfg := tt.cfgFn()
245246
err := xconfmap.Validate(cfg)
246247
if tt.expected != nil {
247-
assert.EqualError(t, err, tt.expected.Error())
248+
require.EqualError(t, err, tt.expected.Error())
248249
} else {
249-
assert.NoError(t, err)
250+
require.NoError(t, err)
250251
}
251252
})
252253
}
253254
}
254255

256+
func TestNoPipelinesFeatureGate(t *testing.T) {
257+
cfg := generateConfig()
258+
cfg.Receivers = nil
259+
cfg.Exporters = nil
260+
cfg.Service.Pipelines = pipelines.Config{}
261+
262+
require.Error(t, xconfmap.Validate(cfg))
263+
264+
gate := pipelines.AllowNoPipelines
265+
require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), true))
266+
defer func() {
267+
require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), false))
268+
}()
269+
270+
require.NoError(t, xconfmap.Validate(cfg))
271+
}
272+
255273
func generateConfig() *Config {
256274
return &Config{
257275
Receivers: map[component.ID]component.Config{

service/pipelines/config.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@ var (
2525
featuregate.WithRegisterFromVersion("v0.112.0"),
2626
featuregate.WithRegisterDescription("Controls whether profiles support can be enabled"),
2727
)
28+
AllowNoPipelines = featuregate.GlobalRegistry().MustRegister(
29+
"service.AllowNoPipelines",
30+
featuregate.StageAlpha,
31+
featuregate.WithRegisterFromVersion("v0.122.0"),
32+
featuregate.WithRegisterDescription("Allow starting the Collector without starting any pipelines."),
33+
)
2834
)
2935

3036
// Config defines the configurable settings for service telemetry.
3137
type Config map[pipeline.ID]*PipelineConfig
3238

3339
func (cfg Config) Validate() error {
34-
// Must have at least one pipeline.
35-
if len(cfg) == 0 {
40+
// Must have at least one pipeline unless explicitly disabled.
41+
if !AllowNoPipelines.IsEnabled() && len(cfg) == 0 {
3642
return errMissingServicePipelines
3743
}
3844

service/pipelines/config_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,21 @@ func TestConfigValidate(t *testing.T) {
120120
}
121121
}
122122

123+
func TestNoPipelinesFeatureGate(t *testing.T) {
124+
cfg := Config{}
125+
126+
require.Error(t, xconfmap.Validate(cfg))
127+
128+
gate := AllowNoPipelines
129+
err := featuregate.GlobalRegistry().Set(gate.ID(), true)
130+
require.NoError(t, err)
131+
defer func() {
132+
require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), false))
133+
}()
134+
135+
require.NoError(t, xconfmap.Validate(cfg))
136+
}
137+
123138
func generateConfig(t *testing.T) Config {
124139
t.Helper()
125140

0 commit comments

Comments
 (0)