Skip to content

Commit a483c24

Browse files
committed
Add helpers for handling of ReportFullState ServerToAgent flag
Introducing basic handling of the ReportsEffectiveConfig capability
1 parent dd8a74f commit a483c24

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
| opamp_pb2.AgentCapabilities.AgentCapabilities_ReportsHeartbeat
4747
| opamp_pb2.AgentCapabilities.AgentCapabilities_AcceptsRemoteConfig
4848
| opamp_pb2.AgentCapabilities.AgentCapabilities_ReportsRemoteConfig
49+
| opamp_pb2.AgentCapabilities.AgentCapabilities_ReportsEffectiveConfig
4950
)
5051

5152

@@ -87,6 +88,7 @@ def __init__(
8788
self._sequence_num: int = 0
8889
self._instance_uid: bytes = uuid7().bytes
8990
self._remote_config_status: opamp_pb2.RemoteConfigStatus | None = None
91+
self._effective_config: opamp_pb2.EffectiveConfig | None = None
9092

9193
def build_connection_message(self) -> bytes:
9294
message = messages.build_presentation_message(
@@ -116,6 +118,14 @@ def build_heartbeat_message(self) -> bytes:
116118
data = messages.encode_message(message)
117119
return data
118120

121+
def update_effective_config(
122+
self, effective_config: dict[str, dict[str, str]], content_type: str
123+
) -> opamp_pb2.EffectiveConfig:
124+
self._effective_config = messages.build_effective_config_message(
125+
config=effective_config, content_type=content_type
126+
)
127+
return self._effective_config
128+
119129
def update_remote_config_status(
120130
self,
121131
remote_config_hash: bytes,
@@ -158,6 +168,18 @@ def build_remote_config_status_response_message(
158168
data = messages.encode_message(message)
159169
return data
160170

171+
def build_full_state_message(self) -> bytes:
172+
message = messages.build_full_state_message(
173+
instance_uid=self._instance_uid,
174+
agent_description=self._agent_description,
175+
remote_config_status=self._remote_config_status,
176+
sequence_num=self._sequence_num,
177+
effective_config=self._effective_config,
178+
capabilities=_HANDLED_CAPABILITIES,
179+
)
180+
data = messages.encode_message(message)
181+
return data
182+
161183
def send(self, data: bytes):
162184
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
163185
try:

opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/messages.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,39 @@ def build_remote_config_status_response_message(
144144
return command
145145

146146

147+
def build_effective_config_message(
148+
config: dict[str, dict[str, str]], content_type: str
149+
):
150+
agent_config_map = opamp_pb2.AgentConfigMap()
151+
for filename, value in config.items():
152+
if content_type == "application/json":
153+
body = json.dumps(value)
154+
agent_config_map.config_map[filename].body = body.encode("utf-8")
155+
agent_config_map.config_map[filename].content_type = content_type
156+
return opamp_pb2.EffectiveConfig(
157+
config_map=agent_config_map,
158+
)
159+
160+
161+
def build_full_state_message(
162+
instance_uid: bytes,
163+
sequence_num: int,
164+
agent_description: opamp_pb2.AgentDescription,
165+
capabilities: int,
166+
remote_config_status: opamp_pb2.RemoteConfigStatus | None,
167+
effective_config: opamp_pb2.EffectiveConfig | None,
168+
) -> opamp_pb2.AgentToServer:
169+
command = opamp_pb2.AgentToServer(
170+
instance_uid=instance_uid,
171+
sequence_num=sequence_num,
172+
agent_description=agent_description,
173+
remote_config_status=remote_config_status,
174+
effective_config=effective_config,
175+
capabilities=capabilities,
176+
)
177+
return command
178+
179+
147180
def encode_message(data: opamp_pb2.AgentToServer) -> bytes:
148181
return data.SerializeToString()
149182

opamp/opentelemetry-opamp-client/tests/opamp/test_client.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,78 @@ def test_build_remote_config_status_response_message_with_error_message(
317317
assert message.remote_config_status.error_message == "an error message"
318318

319319

320+
def test_update_effective_config_json_content_type(client):
321+
config = {"filename": {"a": "config"}}
322+
client.update_effective_config(config, content_type="application/json")
323+
324+
assert isinstance(client._effective_config, opamp_pb2.EffectiveConfig)
325+
326+
decoded_config = {}
327+
for (
328+
file_name,
329+
config_file,
330+
) in client._effective_config.config_map.config_map.items():
331+
body = config_file.body.decode()
332+
decoded_config[file_name] = json.loads(body)
333+
334+
assert config == decoded_config
335+
336+
337+
def test_build_full_state_message(client):
338+
client.update_remote_config_status(
339+
remote_config_hash=b"12345678",
340+
status=opamp_pb2.RemoteConfigStatuses_APPLIED,
341+
)
342+
config = {"filename": {"a": "config"}}
343+
client.update_effective_config(config, content_type="application/json")
344+
345+
data = client.build_full_state_message()
346+
347+
message = opamp_pb2.AgentToServer()
348+
message.ParseFromString(data)
349+
350+
assert message
351+
assert message.instance_uid == client._instance_uid
352+
assert message.sequence_num == 0
353+
assert message.capabilities == _HANDLED_CAPABILITIES
354+
assert message.agent_description.identifying_attributes == [
355+
PB2KeyValue(key="foo", value=PB2AnyValue(string_value="bar")),
356+
]
357+
assert message.remote_config_status
358+
assert message.remote_config_status.last_remote_config_hash == b"12345678"
359+
assert (
360+
message.remote_config_status.status
361+
== opamp_pb2.RemoteConfigStatuses_APPLIED
362+
)
363+
assert "filename" in message.effective_config.config_map.config_map
364+
config_file = message.effective_config.config_map.config_map["filename"]
365+
assert config_file.content_type == "application/json"
366+
body = config_file.body.decode()
367+
assert config["filename"] == json.loads(body)
368+
369+
370+
def test_build_full_state_message_no_config(client):
371+
data = client.build_full_state_message()
372+
373+
message = opamp_pb2.AgentToServer()
374+
message.ParseFromString(data)
375+
376+
assert message
377+
assert message.instance_uid == client._instance_uid
378+
assert message.sequence_num == 0
379+
assert message.capabilities == _HANDLED_CAPABILITIES
380+
assert message.agent_description.identifying_attributes == [
381+
PB2KeyValue(key="foo", value=PB2AnyValue(string_value="bar")),
382+
]
383+
assert message.remote_config_status
384+
assert message.remote_config_status.last_remote_config_hash == b""
385+
assert (
386+
message.remote_config_status.status
387+
== opamp_pb2.RemoteConfigStatuses_UNSET
388+
)
389+
assert message.effective_config.config_map.config_map == {}
390+
391+
320392
def test_message_sequence_num_increases_in_send(client):
321393
client._transport = mock.Mock()
322394
for index in range(2):

0 commit comments

Comments
 (0)