Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[extension/opampextension] reports effective config #29277

Merged
27 changes: 27 additions & 0 deletions .chloggen/feat-27293-reports-effective-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: extension/opampextension

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Implement `extension.NotifyConfig` to be notified of the Collector's effective config and report it to the OpAMP server.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [27293]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
16 changes: 8 additions & 8 deletions cmd/opampsupervisor/specification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,33 +84,33 @@ server:
# If enabled the Supervisor will also report RemoteConfig status
# to the Server.
capabilities:
AcceptsRemoteConfig: # false if unspecified
accepts_remote_config: # false if unspecified

# The Supervisor will report EffectiveConfig to the Server.
ReportsEffectiveConfig: # true if unspecified
reports_effective_config: # true if unspecified

# The Supervisor can accept Collector executable package updates.
# If enabled the Supervisor will also report package status to the
# Server.
AcceptsPackages: # false if unspecified
accepts_packages: # false if unspecified

# The Collector will report own metrics to the destination specified by
# the Server.
ReportsOwnMetrics: # true if unspecified
reports_own_metrics: # true if unspecified

# The Collector will report own logs to the destination specified by
# the Server.
ReportsOwnLogs: # true if unspecified
reports_own_logs: # true if unspecified

# The Collector will accept connections settings for exporters
# from the Server.
AcceptsOtherConnectionSettings: # false if unspecified
accepts_other_connection_settings: # false if unspecified

# The Supervisor will accept restart requests.
AcceptsRestartCommand: # true if unspecified
accepts_restart_command: # true if unspecified

# The Collector will report Health.
ReportsHealth: # true if unspecified
reports_health: # true if unspecified

storage:
# A writable directory where the Supervisor can store data
Expand Down
2 changes: 2 additions & 0 deletions extension/opampextension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The following settings are optional:
- `instance_uid`: A ULID formatted as a 26 character string in canonical
representation. Auto-generated on start if missing. Setting this ensures the
instance UID remains constant across process restarts.
- `capabilities`: Keys with boolean true/false values that enable a particular OpAMP capability.
- `reports_effective_config`: Whether to enable the OpAMP ReportsEffectiveConfig capability. Default is `true`.

### Example

Expand Down
20 changes: 20 additions & 0 deletions extension/opampextension/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"

"github.com/oklog/ulid/v2"
"github.com/open-telemetry/opamp-go/protobufs"
"go.opentelemetry.io/collector/config/configopaque"
"go.opentelemetry.io/collector/config/configtls"
)
Expand All @@ -19,6 +20,25 @@ type Config struct {
// InstanceUID is a ULID formatted as a 26 character string in canonical
// representation. Auto-generated on start if missing.
InstanceUID string `mapstructure:"instance_uid"`

// Capabilities contains options to enable a particular OpAMP capability
Capabilities Capabilities `mapstructure:"capabilities"`
}

type Capabilities struct {
// ReportsEffectiveConfig enables the OpAMP ReportsEffectiveConfig Capability. (default: true)
ReportsEffectiveConfig bool `mapstructure:"reports_effective_config"`
haoqixu marked this conversation as resolved.
Show resolved Hide resolved
}

func (caps Capabilities) toAgentCapabilities() protobufs.AgentCapabilities {
// All Agents MUST report status.
agentCapabilities := protobufs.AgentCapabilities_AgentCapabilities_ReportsStatus

if caps.ReportsEffectiveConfig {
agentCapabilities |= protobufs.AgentCapabilities_AgentCapabilities_ReportsEffectiveConfig
}

return agentCapabilities
}

// OpAMPServer contains the OpAMP transport configuration.
Expand Down
3 changes: 3 additions & 0 deletions extension/opampextension/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ func TestUnmarshalConfig(t *testing.T) {
},
},
InstanceUID: "01BX5ZZKBKACTAV9WEVGEMMVRZ",
Capabilities: Capabilities{
ReportsEffectiveConfig: true,
},
}, cfg)
}

Expand Down
3 changes: 3 additions & 0 deletions extension/opampextension/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func createDefaultConfig() component.Config {
Server: &OpAMPServer{
WS: &OpAMPWebsocket{},
},
Capabilities: Capabilities{
ReportsEffectiveConfig: true,
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion extension/opampextension/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
go.opentelemetry.io/collector/pdata v1.0.0-rcv0018.0.20231127181443-575c5f5e2531
go.opentelemetry.io/collector/semconv v0.89.1-0.20231127181443-575c5f5e2531
go.uber.org/zap v1.26.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down Expand Up @@ -44,5 +45,4 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
72 changes: 43 additions & 29 deletions extension/opampextension/opamp_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,21 @@ import (
"net/http"
"os"
"runtime"
"sync"

"github.com/google/uuid"
"github.com/oklog/ulid/v2"
"github.com/open-telemetry/opamp-go/client"
"github.com/open-telemetry/opamp-go/client/types"
"github.com/open-telemetry/opamp-go/protobufs"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/confmap"
"go.opentelemetry.io/collector/pdata/pcommon"
semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)

// TODO: Replace with https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/27293
const localConfig = `
exporters:
otlp:
endpoint: localhost:1111
receivers:
otlp:
protocols:
grpc: {}
http: {}
service:
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [otlp]
`

type opampAgent struct {
cfg *Config
logger *zap.Logger
Expand All @@ -47,7 +32,10 @@ type opampAgent struct {

instanceID ulid.ULID

effectiveConfig string
eclk sync.RWMutex
effectiveConfig *confmap.Conf

capabilities Capabilities

agentDescription *protobufs.AgentDescription

Expand Down Expand Up @@ -88,9 +76,7 @@ func (o *opampAgent) Start(_ context.Context, _ component.Host) error {
},
OnMessageFunc: o.onMessage,
},
// TODO: Include ReportsEffectiveConfig once the extension has access to the
// collector's effective configuration.
Capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsStatus,
Capabilities: o.capabilities.toAgentCapabilities(),
}

if err := o.createAgentDescription(); err != nil {
Expand Down Expand Up @@ -121,6 +107,21 @@ func (o *opampAgent) Shutdown(ctx context.Context) error {
return o.opampClient.Stop(ctx)
}

func (o *opampAgent) NotifyConfig(ctx context.Context, conf *confmap.Conf) error {
if o.capabilities.ReportsEffectiveConfig {
o.updateEffectiveConfig(conf)
return o.opampClient.UpdateEffectiveConfig(ctx)
}
return nil
}

func (o *opampAgent) updateEffectiveConfig(conf *confmap.Conf) {
o.eclk.Lock()
defer o.eclk.Unlock()

o.effectiveConfig = conf
evan-bradley marked this conversation as resolved.
Show resolved Hide resolved
}

func newOpampAgent(cfg *Config, logger *zap.Logger, build component.BuildInfo, res pcommon.Resource) (*opampAgent, error) {
agentType := build.Command

Expand Down Expand Up @@ -156,12 +157,12 @@ func newOpampAgent(cfg *Config, logger *zap.Logger, build component.BuildInfo, r
}

agent := &opampAgent{
cfg: cfg,
logger: logger,
agentType: agentType,
agentVersion: agentVersion,
instanceID: uid,
effectiveConfig: localConfig, // TODO: Replace with https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/27293
cfg: cfg,
logger: logger,
agentType: agentType,
agentVersion: agentVersion,
instanceID: uid,
capabilities: cfg.Capabilities,
}

return agent, nil
Expand Down Expand Up @@ -210,10 +211,23 @@ func (o *opampAgent) updateAgentIdentity(instanceID ulid.ULID) {
}

func (o *opampAgent) composeEffectiveConfig() *protobufs.EffectiveConfig {
o.eclk.RLock()
defer o.eclk.RUnlock()

if !o.capabilities.ReportsEffectiveConfig || o.effectiveConfig == nil {
return nil
}

conf, err := yaml.Marshal(o.effectiveConfig.ToStringMap())
if err != nil {
o.logger.Error("cannot unmarshal effectiveConfig", zap.Any("conf", o.effectiveConfig), zap.Error(err))
return nil
}

return &protobufs.EffectiveConfig{
ConfigMap: &protobufs.AgentConfigMap{
ConfigMap: map[string]*protobufs.AgentConfigFile{
"": {Body: []byte(o.effectiveConfig)},
"": {Body: conf},
},
},
}
Expand Down
19 changes: 17 additions & 2 deletions extension/opampextension/opamp_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ package opampextension

import (
"context"
"os"
"path/filepath"
"testing"

"github.com/oklog/ulid/v2"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/confmap/confmaptest"
"go.opentelemetry.io/collector/extension/extensiontest"
semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
)
Expand All @@ -24,7 +27,8 @@ func TestNewOpampAgent(t *testing.T) {
assert.Equal(t, "otelcoltest", o.agentType)
assert.Equal(t, "test version", o.agentVersion)
assert.NotEmpty(t, o.instanceID.String())
assert.NotEmpty(t, o.effectiveConfig)
assert.True(t, o.capabilities.ReportsEffectiveConfig)
assert.Empty(t, o.effectiveConfig)
assert.Nil(t, o.agentDescription)
}

Expand Down Expand Up @@ -75,10 +79,21 @@ func TestComposeEffectiveConfig(t *testing.T) {
set := extensiontest.NewNopCreateSettings()
o, err := newOpampAgent(cfg.(*Config), set.Logger, set.BuildInfo, set.Resource)
assert.NoError(t, err)
assert.NotEmpty(t, o.effectiveConfig)
assert.Empty(t, o.effectiveConfig)

ec := o.composeEffectiveConfig()
assert.Nil(t, ec)

ecFileName := filepath.Join("testdata", "effective.yaml")
cm, err := confmaptest.LoadConf(ecFileName)
assert.NoError(t, err)
expected, err := os.ReadFile(ecFileName)
assert.NoError(t, err)

o.updateEffectiveConfig(cm)
ec = o.composeEffectiveConfig()
assert.NotNil(t, ec)
assert.YAMLEq(t, string(expected), string(ec.ConfigMap.ConfigMap[""].Body))
}

func TestShutdown(t *testing.T) {
Expand Down
14 changes: 14 additions & 0 deletions extension/opampextension/testdata/effective.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
exporters:
otlp:
endpoint: localhost:1111
receivers:
otlp:
protocols:
grpc: {}
http: {}
service:
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [otlp]