Skip to content

Commit 69a7720

Browse files
Restrict SetCapabilities after Start()
Only certain capabilities can be changed after Start(), see spec change: open-telemetry/opamp-spec#306
1 parent 1c36d7a commit 69a7720

File tree

3 files changed

+101
-9
lines changed

3 files changed

+101
-9
lines changed

client/clientimpl_test.go

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,9 +1928,8 @@ func TestSetCapabilities(t *testing.T) {
19281928
}
19291929
})
19301930

1931-
newCapabilities = protobufs.AgentCapabilities_AgentCapabilities_AcceptsRestartCommand |
1932-
protobufs.AgentCapabilities_AgentCapabilities_ReportsEffectiveConfig |
1933-
protobufs.AgentCapabilities_AgentCapabilities_AcceptsRemoteConfig |
1931+
// Remove AcceptsRemoteConfig
1932+
newCapabilities = protobufs.AgentCapabilities_AgentCapabilities_ReportsEffectiveConfig |
19341933
protobufs.AgentCapabilities_AgentCapabilities_ReportsStatus
19351934
newSetErr := client.SetCapabilities(&newCapabilities)
19361935
assert.NoError(t, newSetErr)
@@ -1941,10 +1940,8 @@ func TestSetCapabilities(t *testing.T) {
19411940
assert.True(t, protobufs.AgentCapabilities(msg.Capabilities)&protobufs.AgentCapabilities_AgentCapabilities_ReportsStatus != 0)
19421941
// ReportsEffectiveConfig should present.
19431942
assert.True(t, protobufs.AgentCapabilities(msg.Capabilities)&protobufs.AgentCapabilities_AgentCapabilities_ReportsEffectiveConfig != 0)
1944-
// AcceptsRemoteConfig should now be present
1945-
assert.True(t, protobufs.AgentCapabilities(msg.Capabilities)&protobufs.AgentCapabilities_AgentCapabilities_AcceptsRemoteConfig != 0)
1946-
// AcceptsRestartCommand should now be present
1947-
assert.True(t, protobufs.AgentCapabilities(msg.Capabilities)&protobufs.AgentCapabilities_AgentCapabilities_AcceptsRestartCommand != 0)
1943+
// AcceptsRemoteConfig should not be present
1944+
assert.False(t, protobufs.AgentCapabilities(msg.Capabilities)&protobufs.AgentCapabilities_AgentCapabilities_AcceptsRemoteConfig != 0)
19481945
// Send a custom message response and ask client for full state again.
19491946
return &protobufs.ServerToAgent{
19501947
InstanceUid: msg.InstanceUid,
@@ -2630,7 +2627,7 @@ func TestSetAvailableComponents(t *testing.T) {
26302627
}
26312628
}
26322629

2633-
func TestValidateCapabilities(t *testing.T) {
2630+
func TestValidateCapabilitiesBeforeStart(t *testing.T) {
26342631
testCases := []struct {
26352632
name string
26362633
capabilities protobufs.AgentCapabilities
@@ -2714,7 +2711,89 @@ func TestValidateCapabilities(t *testing.T) {
27142711
tc.setupFunc(t, client)
27152712
require.NoError(t, client.SetAgentDescription(createAgentDescr()))
27162713

2717-
// Minimal caps for PrepareStart; validateCapabilities on SetCapabilities runs only once started.
2714+
caps := tc.capabilities
2715+
err := client.SetCapabilities(&caps)
2716+
require.NoError(t, err)
2717+
2718+
settings := types.StartSettings{
2719+
OpAMPServerURL: "ws://" + srv.Endpoint,
2720+
Callbacks: types.Callbacks{
2721+
OnMessage: func(ctx context.Context, msg *types.MessageData) {},
2722+
},
2723+
}
2724+
prepareSettings(t, &settings, client)
2725+
2726+
err = client.Start(context.Background(), settings)
2727+
assert.Equal(t, tc.expectedError, err)
2728+
2729+
if err == nil {
2730+
assert.NoError(t, client.Stop(context.Background()))
2731+
}
2732+
})
2733+
})
2734+
}
2735+
}
2736+
2737+
func TestSetCapabilitiesAfterStart(t *testing.T) {
2738+
testCases := []struct {
2739+
name string
2740+
capabilities protobufs.AgentCapabilities
2741+
setupFunc func(t *testing.T, client OpAMPClient)
2742+
expectedError error
2743+
}{
2744+
{
2745+
// These are the only capabilities that are permitted to be changed after Start()
2746+
name: "Change AcceptsRemoteConfig and ReportsRemoteConfig",
2747+
capabilities: protobufs.AgentCapabilities_AgentCapabilities_AcceptsRemoteConfig |
2748+
protobufs.AgentCapabilities_AgentCapabilities_ReportsRemoteConfig,
2749+
setupFunc: func(t *testing.T, client OpAMPClient) {
2750+
},
2751+
expectedError: nil,
2752+
},
2753+
{
2754+
name: "No capabilities set",
2755+
capabilities: protobufs.AgentCapabilities_AgentCapabilities_Unspecified,
2756+
setupFunc: func(t *testing.T, client OpAMPClient) {
2757+
// No setup needed
2758+
},
2759+
expectedError: nil,
2760+
},
2761+
// Test a few other attempts to change capabilities that must fail. We will create
2762+
// the correct condition for ErrCapabilityChangeNotPermitted to be returned
2763+
// instead of some other specific validation error. Those specific validation errors
2764+
// are checked by corresponding test cases in TestValidateCapabilitiesBeforeStart.
2765+
{
2766+
name: "Change ReportsHealth",
2767+
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsHealth,
2768+
setupFunc: func(t *testing.T, client OpAMPClient) {
2769+
// Need to SetHealth otherwise will get ErrHealthMissing
2770+
err := client.SetHealth(&protobufs.ComponentHealth{})
2771+
require.NoError(t, err)
2772+
},
2773+
expectedError: internal.ErrCapabilityChangeNotPermitted,
2774+
},
2775+
{
2776+
name: "Change ReportsAvailableComponents",
2777+
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents,
2778+
setupFunc: func(t *testing.T, client OpAMPClient) {
2779+
// Need to SetAvailableComponents otherwise will get ErrAvailableComponentsMissing
2780+
err := client.SetAvailableComponents(generateTestAvailableComponents())
2781+
require.NoError(t, err)
2782+
},
2783+
expectedError: internal.ErrCapabilityChangeNotPermitted,
2784+
},
2785+
}
2786+
2787+
for _, tc := range testCases {
2788+
t.Run(tc.name, func(t *testing.T) {
2789+
testClients(t, func(t *testing.T, client OpAMPClient) {
2790+
srv := internal.StartMockServer(t)
2791+
defer srv.Close()
2792+
2793+
tc.setupFunc(t, client)
2794+
require.NoError(t, client.SetAgentDescription(createAgentDescr()))
2795+
2796+
// Minimal caps for PrepareStart; validateCapabilities runs only once started.
27182797
initialCaps := coreCapabilities
27192798
err := client.SetCapabilities(&initialCaps)
27202799
require.NoError(t, err)

client/internal/clientcommon.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var (
2323
ErrCapabilitiesNotSet = errors.New("Capabilities is not set")
2424
ErrAcceptsPackagesNotSet = errors.New("AcceptsPackages and ReportsPackageStatuses must be set")
2525
ErrAvailableComponentsMissing = errors.New("AvailableComponents is nil")
26+
ErrCapabilityChangeNotPermitted = errors.New("only changes to AcceptsRemoteConfig and ReportsRemoteConfig capabilities are permitted after Start")
2627

2728
errAlreadyStarted = errors.New("already started")
2829
errCannotStopNotStarted = errors.New("cannot stop because not started")
@@ -555,6 +556,11 @@ func (c *ClientCommon) SetCapabilities(capabilities *protobufs.AgentCapabilities
555556
if err := c.validateCapabilities(*capabilities); err != nil {
556557
return err
557558
}
559+
// Verify that only permitted capabilities are changing.
560+
changedCapabilities := c.ClientSyncedState.Capabilities() ^ *capabilities
561+
if (changedCapabilities & ^permittedCapabilityChanges) != 0 {
562+
return ErrCapabilityChangeNotPermitted
563+
}
558564
}
559565
// store the capabilities to send
560566
if err := c.ClientSyncedState.SetCapabilities(capabilities); err != nil {

client/internal/consts.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package internal
22

3+
import "github.com/open-telemetry/opamp-go/protobufs"
4+
35
const (
46
headerContentType = "Content-Type"
57
contentTypeProtobuf = "application/x-protobuf"
68
headerOpAMPInstanceUID = "OpAMP-Instance-UID"
79
)
10+
11+
// Only these capabilities are allowed to be changed after Start().
12+
// See https://github.com/open-telemetry/opamp-spec/pull/306
13+
const permittedCapabilityChanges = protobufs.AgentCapabilities_AgentCapabilities_AcceptsRemoteConfig |
14+
protobufs.AgentCapabilities_AgentCapabilities_ReportsRemoteConfig

0 commit comments

Comments
 (0)