Skip to content

Commit ab06524

Browse files
committed
add extensions framework to supervisor
1 parent 0e292e1 commit ab06524

File tree

16 files changed

+698
-29
lines changed

16 files changed

+698
-29
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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. receiver/filelog)
7+
component: cmd/opampsupervisor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Adds a framework for the supervisor to utilize extensions from the collector ecosystem
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [47690]
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:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[comment]: <> (Code generated by mdatagen. DO NOT EDIT.)
2+
3+
# opampsupervisor
4+
5+
## Feature Gates
6+
7+
This component has the following feature gates:
8+
9+
| Feature Gate | Stage | Description | From Version | To Version | Reference |
10+
| ------------ | ----- | ----------- | ------------ | ---------- | --------- |
11+
| `opampsupervisor.Extensions` | alpha | When enabled, the opampsupervisor can be configured with and use specific extensions from the collector ecosystem. | v0.151.0 | N/A | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/47690) |
12+
13+
For more information about feature gates, see the [Feature Gates](https://github.com/open-telemetry/opentelemetry-collector/blob/main/featuregate/README.md) documentation.

cmd/opampsupervisor/e2e_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ import (
4141
"github.com/open-telemetry/opamp-go/server/types"
4242
"github.com/stretchr/testify/assert"
4343
"github.com/stretchr/testify/require"
44+
"go.opentelemetry.io/collector/featuregate"
4445
"go.opentelemetry.io/collector/pdata/ptrace"
4546
"go.uber.org/zap"
4647
"go.uber.org/zap/zapcore"
4748
"google.golang.org/protobuf/proto"
4849

50+
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/internal/metadata"
4951
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor"
5052
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor/config"
5153
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor/telemetry"
@@ -2694,3 +2696,54 @@ func TestSupervisorValidatesConfigBeforeApplying(t *testing.T) {
26942696
})
26952697
}
26962698
}
2699+
2700+
func TestSupervisorExtensionsFeatureGateRequired(t *testing.T) {
2701+
t.Run("feature-gate disabled", func(t *testing.T) {
2702+
// Render configuration with nop extension
2703+
cfgFile := getSupervisorConfig(t, "extensions", map[string]string{
2704+
"url": "localhost:0",
2705+
})
2706+
cfg, err := config.Load(cfgFile.Name())
2707+
require.NoError(t, err)
2708+
2709+
// Attempt to create a supervisor with an extensions config. The feature
2710+
// gate is disabled by default, so supervisor.NewSupervisor must fail with an error
2711+
// that references the feature gate and how to enable it.
2712+
s, err := supervisor.NewSupervisor(t.Context(), zap.NewNop(), cfg)
2713+
require.Nil(t, s)
2714+
require.Contains(t, err.Error(), metadata.OpampsupervisorExtensionsFeatureGate.ID())
2715+
require.Contains(t, err.Error(), "--feature-gates=")
2716+
})
2717+
2718+
t.Run("feature-gate enabled", func(t *testing.T) {
2719+
// Create basic opamp server to check that the supervisor connects
2720+
connected := atomic.Bool{}
2721+
server := newOpAMPServer(t, defaultConnectingHandler, types.ConnectionCallbacks{
2722+
OnConnected: func(context.Context, types.Connection) {
2723+
connected.Store(true)
2724+
},
2725+
})
2726+
2727+
// Enable extensions feature-gate
2728+
err := featuregate.GlobalRegistry().Set(metadata.OpampsupervisorExtensionsFeatureGate.ID(), true)
2729+
require.NoError(t, err)
2730+
t.Cleanup(func() {
2731+
require.NoError(t, featuregate.GlobalRegistry().Set(metadata.OpampsupervisorExtensionsFeatureGate.ID(), false))
2732+
})
2733+
2734+
// Create supervisor with configuration that has nop extension
2735+
s, _ := newSupervisor(t,
2736+
"extensions",
2737+
map[string]string{
2738+
"url": server.addr,
2739+
},
2740+
)
2741+
2742+
// Start supervisor and wait for successful connection
2743+
t.Cleanup(s.Shutdown)
2744+
require.NoError(t, s.Start(t.Context()))
2745+
2746+
waitForSupervisorConnection(server.supervisorConnected, true)
2747+
require.True(t, connected.Load(), "Supervisor failed to connect")
2748+
})
2749+
}

cmd/opampsupervisor/go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/open-telemetry/opentelemetry-collector-contrib/testbed v0.150.0
1414
github.com/stretchr/testify v1.11.1
1515
go.opentelemetry.io/collector/component v1.56.1-0.20260415114935-307e3abdbae9
16+
go.opentelemetry.io/collector/component/componenttest v0.150.1-0.20260415114935-307e3abdbae9
1617
go.opentelemetry.io/collector/config/confighttp v0.150.1-0.20260415114935-307e3abdbae9
1718
go.opentelemetry.io/collector/config/confignet v1.56.1-0.20260415114935-307e3abdbae9
1819
go.opentelemetry.io/collector/config/configopaque v1.56.1-0.20260415114935-307e3abdbae9
@@ -21,6 +22,10 @@ require (
2122
go.opentelemetry.io/collector/confmap v1.56.1-0.20260415114935-307e3abdbae9
2223
go.opentelemetry.io/collector/confmap/provider/envprovider v1.56.1-0.20260415114935-307e3abdbae9
2324
go.opentelemetry.io/collector/confmap/provider/fileprovider v1.56.1-0.20260415114935-307e3abdbae9
25+
go.opentelemetry.io/collector/confmap/xconfmap v0.150.1-0.20260415114935-307e3abdbae9
26+
go.opentelemetry.io/collector/extension v1.56.1-0.20260415114935-307e3abdbae9
27+
go.opentelemetry.io/collector/extension/extensiontest v0.150.1-0.20260415114935-307e3abdbae9
28+
go.opentelemetry.io/collector/featuregate v1.56.1-0.20260415114935-307e3abdbae9
2429
go.opentelemetry.io/collector/pdata v1.56.1-0.20260415114935-307e3abdbae9
2530
go.opentelemetry.io/collector/service v0.150.1-0.20260415114935-307e3abdbae9
2631
go.opentelemetry.io/contrib/bridges/otelzap v0.18.0
@@ -154,14 +159,12 @@ require (
154159
go.opentelemetry.io/collector v0.150.1-0.20260415114935-307e3abdbae9 // indirect
155160
go.opentelemetry.io/collector/client v1.56.1-0.20260415114935-307e3abdbae9 // indirect
156161
go.opentelemetry.io/collector/component/componentstatus v0.150.1-0.20260415114935-307e3abdbae9 // indirect
157-
go.opentelemetry.io/collector/component/componenttest v0.150.1-0.20260415114935-307e3abdbae9 // indirect
158162
go.opentelemetry.io/collector/config/configauth v1.56.1-0.20260415114935-307e3abdbae9 // indirect
159163
go.opentelemetry.io/collector/config/configcompression v1.56.1-0.20260415114935-307e3abdbae9 // indirect
160164
go.opentelemetry.io/collector/config/configgrpc v0.150.1-0.20260415114935-307e3abdbae9 // indirect
161165
go.opentelemetry.io/collector/config/configmiddleware v1.56.1-0.20260415114935-307e3abdbae9 // indirect
162166
go.opentelemetry.io/collector/config/configoptional v1.56.1-0.20260415114935-307e3abdbae9 // indirect
163167
go.opentelemetry.io/collector/config/configretry v1.56.1-0.20260415114935-307e3abdbae9 // indirect
164-
go.opentelemetry.io/collector/confmap/xconfmap v0.150.1-0.20260415114935-307e3abdbae9 // indirect
165168
go.opentelemetry.io/collector/connector v0.150.1-0.20260415114935-307e3abdbae9 // indirect
166169
go.opentelemetry.io/collector/connector/connectortest v0.150.1-0.20260415114935-307e3abdbae9 // indirect
167170
go.opentelemetry.io/collector/connector/xconnector v0.150.1-0.20260415114935-307e3abdbae9 // indirect
@@ -178,14 +181,11 @@ require (
178181
go.opentelemetry.io/collector/exporter/otlpexporter v0.150.1-0.20260415114935-307e3abdbae9 // indirect
179182
go.opentelemetry.io/collector/exporter/otlphttpexporter v0.150.1-0.20260415114935-307e3abdbae9 // indirect
180183
go.opentelemetry.io/collector/exporter/xexporter v0.150.1-0.20260415114935-307e3abdbae9 // indirect
181-
go.opentelemetry.io/collector/extension v1.56.1-0.20260415114935-307e3abdbae9 // indirect
182184
go.opentelemetry.io/collector/extension/extensionauth v1.56.1-0.20260415114935-307e3abdbae9 // indirect
183185
go.opentelemetry.io/collector/extension/extensioncapabilities v0.150.1-0.20260415114935-307e3abdbae9 // indirect
184186
go.opentelemetry.io/collector/extension/extensionmiddleware v0.150.1-0.20260415114935-307e3abdbae9 // indirect
185-
go.opentelemetry.io/collector/extension/extensiontest v0.150.1-0.20260415114935-307e3abdbae9 // indirect
186187
go.opentelemetry.io/collector/extension/xextension v0.150.1-0.20260415114935-307e3abdbae9 // indirect
187188
go.opentelemetry.io/collector/extension/zpagesextension v0.150.1-0.20260415114935-307e3abdbae9 // indirect
188-
go.opentelemetry.io/collector/featuregate v1.56.1-0.20260415114935-307e3abdbae9 // indirect
189189
go.opentelemetry.io/collector/internal/componentalias v0.150.1-0.20260415114935-307e3abdbae9 // indirect
190190
go.opentelemetry.io/collector/internal/fanoutconsumer v0.150.1-0.20260415114935-307e3abdbae9 // indirect
191191
go.opentelemetry.io/collector/internal/memorylimiter v0.150.1-0.20260415114935-307e3abdbae9 // indirect

cmd/opampsupervisor/internal/metadata/generated_feature_gates.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/opampsupervisor/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"os"
1212
"os/signal"
1313

14+
"go.opentelemetry.io/collector/featuregate"
15+
1416
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor"
1517
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor/config"
1618
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor/telemetry"
@@ -24,6 +26,7 @@ func main() {
2426

2527
func runInteractive() error {
2628
configFlag := flag.String("config", "", "Path to a supervisor configuration file")
29+
featuregate.GlobalRegistry().RegisterFlags(flag.CommandLine)
2730
flag.Parse()
2831

2932
cfg, err := config.Load(*configFlag)

cmd/opampsupervisor/metadata.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ status:
77
alpha: [metrics]
88
codeowners:
99
active: [evan-bradley, atoulme, tigrannajaryan]
10+
11+
feature_gates:
12+
- id: opampsupervisor.Extensions
13+
stage: alpha
14+
description: >-
15+
When enabled, the opampsupervisor can be configured with and use specific extensions from the collector ecosystem.
16+
from_version: v0.151.0
17+
reference_url: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/47690

cmd/opampsupervisor/supervisor/config/config.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,19 @@ import (
3131
"go.opentelemetry.io/collector/service/telemetry/otelconftelemetry"
3232
config "go.opentelemetry.io/contrib/otelconf/v0.3.0"
3333
"go.uber.org/zap/zapcore"
34+
35+
"github.com/open-telemetry/opentelemetry-collector-contrib/cmd/opampsupervisor/supervisor/extensions"
3436
)
3537

3638
// Supervisor is the Supervisor config file format.
3739
type Supervisor struct {
38-
Server OpAMPServer `mapstructure:"server"`
39-
Agent Agent `mapstructure:"agent"`
40-
Capabilities Capabilities `mapstructure:"capabilities"`
41-
Storage Storage `mapstructure:"storage"`
42-
Telemetry Telemetry `mapstructure:"telemetry"`
43-
HealthCheck HealthCheck `mapstructure:"healthcheck"`
40+
Server OpAMPServer `mapstructure:"server"`
41+
Agent Agent `mapstructure:"agent"`
42+
Capabilities Capabilities `mapstructure:"capabilities"`
43+
Storage Storage `mapstructure:"storage"`
44+
Telemetry Telemetry `mapstructure:"telemetry"`
45+
HealthCheck HealthCheck `mapstructure:"healthcheck"`
46+
Extensions map[string]any `mapstructure:"extensions,omitempty"`
4447
}
4548

4649
// Load loads the Supervisor config from a file.
@@ -74,13 +77,10 @@ func Load(configFile string) (Supervisor, error) {
7477
return Supervisor{}, err
7578
}
7679

77-
if err := cfg.Validate(); err != nil {
78-
return Supervisor{}, fmt.Errorf("cannot validate supervisor config %s: %w", configFile, err)
79-
}
80-
8180
return cfg, nil
8281
}
8382

83+
// Validate validates the Supervisor configuration
8484
func (s Supervisor) Validate() error {
8585
if err := s.Server.Validate(); err != nil {
8686
return err
@@ -94,6 +94,11 @@ func (s Supervisor) Validate() error {
9494
return err
9595
}
9696

97+
// extensions have their own validation in the extensions package
98+
if err := extensions.ValidateConfigs(s.Extensions); err != nil {
99+
return err
100+
}
101+
97102
return nil
98103
}
99104

cmd/opampsupervisor/supervisor/config/config_test.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"go.opentelemetry.io/collector/config/confignet"
2020
"go.opentelemetry.io/collector/config/configopaque"
2121
"go.opentelemetry.io/collector/config/configtls"
22+
"go.opentelemetry.io/collector/confmap"
2223
"go.uber.org/zap/zapcore"
2324
)
2425

@@ -558,6 +559,30 @@ func TestValidate(t *testing.T) {
558559
}
559560
}
560561

562+
func TestSupervisor_UnmarshalExtensionsRawMap(t *testing.T) {
563+
conf := confmap.NewFromStringMap(map[string]any{
564+
"extensions": map[string]any{
565+
"foo": map[string]any{
566+
"key": "value",
567+
},
568+
"bar/named": map[string]any{
569+
"token": "secret",
570+
},
571+
},
572+
})
573+
574+
cfg := DefaultSupervisor()
575+
require.NoError(t, conf.Unmarshal(&cfg))
576+
require.Equal(t, map[string]any{
577+
"foo": map[string]any{
578+
"key": "value",
579+
},
580+
"bar/named": map[string]any{
581+
"token": "secret",
582+
},
583+
}, cfg.Extensions)
584+
}
585+
561586
func TestOpAMPServer_OpaqueHeaders(t *testing.T) {
562587
testCases := []struct {
563588
name string
@@ -867,20 +892,6 @@ agent:
867892
runSupervisorConfigLoadTest(t, cfgPath, Supervisor{}, errors.New("cannot retrieve the configuration: unable to read the file"))
868893
},
869894
},
870-
{
871-
desc: "Failed Validation Supervisor",
872-
testFunc: func(t *testing.T) {
873-
config := `
874-
server:
875-
876-
agent:
877-
executable: %s
878-
`
879-
config = fmt.Sprintf(config, executablePath)
880-
cfgPath := setupSupervisorConfigFile(t, tmpDir, config)
881-
runSupervisorConfigLoadTest(t, cfgPath, Supervisor{}, errors.New("cannot validate supervisor config"))
882-
},
883-
},
884895
}
885896

886897
for _, tc := range testCases {

0 commit comments

Comments
 (0)