Skip to content

Commit 2c460e5

Browse files
ozgengreenbonebot
authored andcommitted
change: align modify_agent_control_scan_config with new XML shape
wrapping values under <config_defaults> serializing nested <agent_defaults> serializing <agent_control_defaults> encoding update_to_latest as 1 / 0 handling scheduler_cron_time as a list with is_list="1"
1 parent 5afc7d3 commit 2c460e5

File tree

5 files changed

+630
-288
lines changed

5 files changed

+630
-288
lines changed

gvm/protocols/gmp/_gmpnext.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def modify_agent_control_scan_config(
166166
return self._send_request_and_transform_response(
167167
Agents.modify_agent_control_scan_config(
168168
agent_control_id=agent_control_id,
169-
config=config,
169+
config_defaults=config,
170170
)
171171
)
172172

gvm/protocols/gmp/requests/next/_agents.py

Lines changed: 140 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
from typing import Any, Mapping, Optional, Sequence
66

7-
from gvm.errors import RequiredArgument
7+
from gvm.errors import InvalidArgumentType, RequiredArgument
88
from gvm.protocols.core import Request
99
from gvm.protocols.gmp.requests._entity_id import EntityID
1010
from gvm.utils import to_bool
1111
from gvm.xml import XmlCommand
1212

1313

1414
class Agents:
15-
1615
@staticmethod
1716
def _add_element(element, name: str, value: Any) -> None:
1817
"""
@@ -24,8 +23,14 @@ def _add_element(element, name: str, value: Any) -> None:
2423
value: Value to set as the text of the sub-element. If None, the
2524
element will not be created.
2625
"""
27-
if value is not None:
28-
element.add_element(name, str(value))
26+
if value is None:
27+
return
28+
if isinstance(value, bool):
29+
value = "1" if value else "0"
30+
else:
31+
value = str(value)
32+
33+
element.add_element(name, value)
2934

3035
@classmethod
3136
def _validate_agent_config(
@@ -67,7 +72,11 @@ def valid_value(d: Mapping[str, Any], key: str, path: str) -> Any:
6772
valid_value(se, "indexer_dir_depth", "agent_script_executor.")
6873

6974
sched = se.get("scheduler_cron_time")
70-
if isinstance(sched, Sequence) and not isinstance(sched, (str, bytes)):
75+
if isinstance(sched, str):
76+
items = [sched]
77+
elif isinstance(sched, Sequence) and not isinstance(
78+
sched, (str, bytes)
79+
):
7180
items = [str(x) for x in sched]
7281
else:
7382
items = []
@@ -83,7 +92,58 @@ def valid_value(d: Mapping[str, Any], key: str, path: str) -> Any:
8392
valid_value(hb, "miss_until_inactive", "heartbeat.")
8493

8594
@classmethod
86-
def _append_agent_config(cls, parent, config: Mapping[str, Any]) -> None:
95+
def _validate_config_defaults(
96+
cls, config_defaults: Mapping[str, Any], *, caller: str
97+
) -> None:
98+
"""Ensure agent config defaults structure is valid."""
99+
100+
def valid_map(d: Any, key: str, path: str) -> Mapping[str, Any]:
101+
if not isinstance(d, Mapping):
102+
raise RequiredArgument(
103+
function=caller,
104+
argument=path.rstrip("."),
105+
)
106+
v = d.get(key)
107+
if not isinstance(v, Mapping):
108+
raise RequiredArgument(
109+
function=caller,
110+
argument=f"{path}{key}",
111+
)
112+
return v
113+
114+
def valid_bool(d: Mapping[str, Any], key: str, path: str) -> bool:
115+
v = d.get(key)
116+
if not isinstance(v, bool):
117+
raise InvalidArgumentType(
118+
function=caller,
119+
argument=f"{path}{key}",
120+
arg_type="bool",
121+
)
122+
return v
123+
124+
agent_defaults = valid_map(
125+
config_defaults, "agent_defaults", "config_defaults."
126+
)
127+
cls._validate_agent_config(agent_defaults, caller=caller)
128+
129+
agent_control_defaults = valid_map(
130+
config_defaults,
131+
"agent_control_defaults",
132+
"config_defaults.",
133+
)
134+
valid_bool(
135+
agent_control_defaults,
136+
"update_to_latest",
137+
"config_defaults.agent_control_defaults.",
138+
)
139+
140+
@classmethod
141+
def _append_agent_config(
142+
cls,
143+
parent,
144+
config: Mapping[str, Any],
145+
wrapper_tag: Optional[str] = "config",
146+
) -> None:
87147
"""
88148
Append an agent configuration block to the given XML parent element.
89149
@@ -110,12 +170,18 @@ def _append_agent_config(cls, parent, config: Mapping[str, Any]) -> None:
110170
}
111171
112172
Args:
113-
parent: The XML parent element to which the `<config>` element
173+
parent: The XML parent element to which the wrapper element
114174
should be appended.
115175
config: Mapping containing the agent configuration fields to
116176
serialize.
177+
wrapper_tag: Optional wrapper element name. If None, fields are
178+
appended directly to parent.
117179
"""
118-
xml_config = parent.add_element("config")
180+
xml_config = (
181+
parent.add_element(wrapper_tag)
182+
if wrapper_tag is not None
183+
else parent
184+
)
119185

120186
# agent_control.retry
121187
ac = config["agent_control"]
@@ -145,9 +211,18 @@ def _append_agent_config(cls, parent, config: Mapping[str, Any]) -> None:
145211
xml_se, "indexer_dir_depth", se.get("indexer_dir_depth")
146212
)
147213
sched = se.get("scheduler_cron_time")
148-
xml_sched = xml_se.add_element("scheduler_cron_time")
149-
for item in sched:
150-
xml_sched.add_element("item", str(item))
214+
if isinstance(sched, str):
215+
sched_items = [sched]
216+
else:
217+
sched_items = list(sched or [])
218+
219+
if sched_items:
220+
xml_sched = xml_se.add_element(
221+
"scheduler_cron_time",
222+
attrs={"is_list": "1"},
223+
)
224+
for item in sched_items:
225+
xml_sched.add_element("item", str(item))
151226

152227
# heartbeat
153228
hb = config["heartbeat"]
@@ -159,6 +234,29 @@ def _append_agent_config(cls, parent, config: Mapping[str, Any]) -> None:
159234
xml_hb, "miss_until_inactive", hb.get("miss_until_inactive")
160235
)
161236

237+
@classmethod
238+
def _append_config_defaults(
239+
cls, parent, config_defaults: Mapping[str, Any]
240+
) -> None:
241+
xml_defaults = parent.add_element("config_defaults")
242+
243+
cls._append_agent_config(
244+
xml_defaults,
245+
config_defaults["agent_defaults"],
246+
wrapper_tag="agent_defaults",
247+
)
248+
249+
control_defaults = config_defaults.get("agent_control_defaults")
250+
if control_defaults:
251+
xml_control_defaults = xml_defaults.add_element(
252+
"agent_control_defaults"
253+
)
254+
cls._add_element(
255+
xml_control_defaults,
256+
"update_to_latest",
257+
control_defaults.get("update_to_latest"),
258+
)
259+
162260
@classmethod
163261
def get_agents(
164262
cls,
@@ -273,54 +371,57 @@ def delete_agents(cls, agent_ids: list[EntityID]) -> Request:
273371
def modify_agent_control_scan_config(
274372
cls,
275373
agent_control_id: EntityID,
276-
config: Mapping[str, Any],
374+
config_defaults: Mapping[str, Any],
277375
) -> Request:
278376
"""
279377
Modify agent control scan config.
280378
281379
Args:
282380
agent_control_id: The agent control UUID.
283-
config: Nested config, e.g.:
381+
config_defaults: Nested config, e.g.:
284382
{
285-
"agent_control": {
286-
"retry": {
287-
"attempts": 6,
288-
"delay_in_seconds": 60,
289-
"max_jitter_in_seconds": 10,
290-
}
291-
},
292-
"agent_script_executor": {
293-
"bulk_size": 2,
294-
"bulk_throttle_time_in_ms": 300,
295-
"indexer_dir_depth": 100,
296-
"scheduler_cron_time": ["0 */12 * * *"], # str or list[str]
297-
},
298-
"heartbeat": {
299-
"interval_in_seconds": 300,
300-
"miss_until_inactive": 1,
301-
},
383+
"agent_defaults": {
384+
"agent_control": {
385+
"retry": {
386+
"attempts": 6,
387+
"delay_in_seconds": 60,
388+
"max_jitter_in_seconds": 10,
389+
}
390+
},
391+
"agent_script_executor": {
392+
"bulk_size": 2,
393+
"bulk_throttle_time_in_ms": 300,
394+
"indexer_dir_depth": 100,
395+
"scheduler_cron_time": ["0 */12 * * *"],
396+
},
397+
"heartbeat": {
398+
"interval_in_seconds": 300,
399+
"miss_until_inactive": 1,
400+
},
401+
},
402+
"agent_control_defaults": {
403+
"update_to_latest": False,
404+
},
302405
}
303406
"""
304407
if not agent_control_id:
305408
raise RequiredArgument(
306409
function=cls.modify_agent_control_scan_config.__name__,
307410
argument="agent_control_id",
308411
)
309-
if not config:
412+
if not config_defaults:
310413
raise RequiredArgument(
311414
function=cls.modify_agent_control_scan_config.__name__,
312-
argument="config",
415+
argument="config_defaults",
313416
)
314417

315-
cls._validate_agent_config(
316-
config, caller=cls.modify_agent_control_scan_config.__name__
418+
cls._validate_config_defaults(
419+
config_defaults,
420+
caller=cls.modify_agent_control_scan_config.__name__,
317421
)
318422

319-
cmd = XmlCommand(
320-
"modify_agent_control_scan_config",
321-
)
423+
cmd = XmlCommand("modify_agent_control_scan_config")
322424
cmd.set_attribute("agent_control_id", str(agent_control_id))
323-
324-
cls._append_agent_config(cmd, config)
425+
cls._append_config_defaults(cmd, config_defaults)
325426

326427
return cmd

0 commit comments

Comments
 (0)