Skip to content

Commit a7c0579

Browse files
authored
Measurement creation new fields (#255)
* Measurement new fields for auto-topup, target refresh and aggregator client id * Ruff format
1 parent a613646 commit a7c0579

File tree

4 files changed

+87
-11
lines changed

4 files changed

+87
-11
lines changed

ripe/atlas/tools/commands/measure/base.py

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import os
1818
import re
1919
import webbrowser
20+
import hashlib
2021

2122
from collections import OrderedDict
2223

@@ -43,7 +44,6 @@
4344

4445

4546
class Command(BaseCommand):
46-
4747
NAME = "measure"
4848

4949
DESCRIPTION = "Create a measurement and optionally wait for the results"
@@ -61,14 +61,12 @@ class Command(BaseCommand):
6161
)
6262

6363
def __init__(self, *args, **kwargs):
64-
6564
self._type = None
6665
self._is_oneoff = True
6766

6867
BaseCommand.__init__(self, *args, **kwargs)
6968

7069
def _modify_parser_args(self, args):
71-
7270
kinds = self.CREATION_CLASSES.keys()
7371
error = (
7472
"Usage: ripe-atlas measure <{}> [options]\n"
@@ -90,7 +88,6 @@ def _modify_parser_args(self, args):
9088
return BaseCommand._modify_parser_args(self, args)
9189

9290
def add_arguments(self):
93-
9491
self.parser.add_argument(
9592
"--renderer",
9693
choices=Renderer.get_available(),
@@ -238,6 +235,43 @@ def add_arguments(self):
238235
help="Exclude probes that are marked with these tags. "
239236
"Example: --exclude-tag=system-ipv6-works",
240237
)
238+
self.add_flag(
239+
parser=self.parser,
240+
name="auto-topup",
241+
default=conf["specification"]["auto_topup"],
242+
help="Automatic top-up measurements probes."
243+
"Applicable to periodic measurements only.",
244+
)
245+
self.parser.add_argument(
246+
"--auto-topup-prb-days-off",
247+
type=ArgumentType.integer_range(1, 30),
248+
default=conf["specification"]["auto_topup_prb_days_off"],
249+
help="Threshold in days to replace a disconnected probe."
250+
"Applicable to periodic measurements only."
251+
"Example: --auto-topup-prb-days-off=7",
252+
)
253+
self.parser.add_argument(
254+
"--auto-topup-prb-similarity",
255+
type=ArgumentType.float_range(minimum=0, maximum=1),
256+
default=conf["specification"]["auto_topup_prb_similarity"],
257+
help="Minimum similarity for replacement probes"
258+
"Applicable to periodic measurements only."
259+
"Example: --auto-topup-prb-similarity=0.5",
260+
)
261+
self.parser.add_argument(
262+
"--target-update-hours",
263+
type=ArgumentType.integer_range(22, 720),
264+
default=conf["specification"]["target_update_hours"],
265+
help="Number of hours to re-lookup a target DNS record."
266+
"Example: --target-update-hours=24",
267+
)
268+
self.parser.add_argument(
269+
"--aggregator-client-id",
270+
type=str,
271+
default=conf["specification"]["aggregator_client_id"],
272+
help="Client ID for measurement aggregators."
273+
"The value is hashed on transmission.",
274+
)
241275

242276
self.parser.add_argument(
243277
"--group-id",
@@ -280,7 +314,6 @@ def add_arguments(self):
280314
Renderer.add_arguments_for_available_renderers(self.parser)
281315

282316
def run(self) -> None:
283-
284317
self._account_for_selected_probes()
285318

286319
if self.arguments.dry_run:
@@ -315,7 +348,6 @@ def run(self) -> None:
315348
self.stream(msm_id)
316349

317350
def dry_run(self):
318-
319351
print(colourise("\nDefinitions:\n{}".format("=" * 80), "bold"))
320352

321353
for param, val in self._get_measurement_kwargs().items():
@@ -371,7 +403,6 @@ def stream(self, msm_id: int) -> None:
371403
self.ok("Disconnected from stream")
372404

373405
def clean_target(self):
374-
375406
if not self.arguments.target:
376407
raise RipeAtlasToolsException(
377408
"You must specify a target for that kind of measurement"
@@ -389,7 +420,6 @@ def clean_description(self):
389420
)
390421

391422
def _get_measurement_kwargs(self):
392-
393423
# This is kept apart from the r = {} because dns measurements don't
394424
# require a target attribute
395425
target = self.clean_target()
@@ -404,6 +434,16 @@ def _get_measurement_kwargs(self):
404434
r["interval"] = self.arguments.interval
405435
self._is_oneoff = False
406436
self.arguments.no_report = True
437+
# auto-topup is applicable only to periodic measurements
438+
if self.arguments.auto_topup is not None:
439+
r["auto_topup"] = self.arguments.auto_topup
440+
if self.arguments.auto_topup_prb_days_off is not None:
441+
r["auto_topup_prb_days_off"] = self.arguments.auto_topup_prb_days_off
442+
if self.arguments.auto_topup_prb_similarity is not None:
443+
r["auto_topup_prb_similarity"] = (
444+
self.arguments.auto_topup_prb_similarity
445+
)
446+
407447
elif not spec["times"]["one-off"]:
408448
raise RipeAtlasToolsException(
409449
"Your configuration file appears to be setup to not create "
@@ -427,10 +467,17 @@ def _get_measurement_kwargs(self):
427467
if self.arguments.resolve_on_probe is not None:
428468
r["resolve_on_probe"] = self.arguments.resolve_on_probe
429469

470+
if self.arguments.target_update_hours:
471+
r["target_update_hours"] = self.arguments.target_update_hours
472+
473+
if self.arguments.aggregator_client_id:
474+
r["aggregator_client_id"] = hashlib.sha256(
475+
self.arguments.aggregator_client_id.encode("utf-8")
476+
).hexdigest()
477+
430478
return r
431479

432480
def _get_source_kwargs(self):
433-
434481
r = conf["specification"]["source"]
435482

436483
r["requested"] = self.arguments.probes
@@ -505,7 +552,6 @@ def _account_for_selected_probes(self):
505552

506553
@staticmethod
507554
def _handle_api_error(response):
508-
509555
message = "There was a problem communicating with the RIPE Atlas API."
510556

511557
if isinstance(response, dict):
@@ -517,7 +563,6 @@ def _handle_api_error(response):
517563
"using:\n\n"
518564
" ripe-atlas configure --set authorisation.create=MY_API_KEY\n"
519565
)
520-
521566
message += f"\n\n{json.dumps(response, indent=2)}"
522567

523568
raise RipeAtlasToolsException(message)

ripe/atlas/tools/commands/measurement_info.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ def render_basic(cls, measurement):
8282
("is_all_scheduled", "Fully Scheduled?", cls._prettify_boolean),
8383
("resolved_ips", "Resolved IPs", lambda _: ", ".join(_)),
8484
("resolve_on_probe", "Resolve on the Probe", cls._prettify_boolean),
85+
("auto_topup", "Auto-topup probes", cls._prettify_boolean),
86+
("auto_topup_prb_days_off", "Auto-topup min disconnected days"),
87+
("auto_topup_prb_similarity", "Auto-topup probe similarity"),
88+
("target_update_hours", "Target update hours"),
8589
),
8690
)
8791

ripe/atlas/tools/helpers/validators.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ def __call__(self, string):
123123

124124
return integer
125125

126+
class float_range(object):
127+
def __init__(self, minimum=float("-inf"), maximum=float("inf")):
128+
self.minimum = minimum
129+
self.maximum = maximum
130+
131+
def __call__(self, string):
132+
133+
message = "The number must be between {} and {}.".format(
134+
self.minimum, self.maximum
135+
)
136+
if self.maximum == float("inf"):
137+
message = "The number must be greater than {}.".format(self.minimum)
138+
139+
try:
140+
number = float(string)
141+
if number < self.minimum or number > self.maximum:
142+
raise argparse.ArgumentTypeError(message)
143+
except ValueError:
144+
raise argparse.ArgumentTypeError("A number must be specified.")
145+
146+
return number
147+
126148
class comma_separated_integers(object):
127149
def __init__(self, minimum=float("-inf"), maximum=float("inf")):
128150
self.minimum = minimum

ripe/atlas/tools/settings/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ class Configuration(UserSettingsParser):
8181
},
8282
"spread": None,
8383
"resolve_on_probe": None,
84+
"auto_topup": None,
85+
"auto_topup_prb_days_off": None,
86+
"auto_topup_prb_similarity": None,
87+
"target_update_hours": None,
88+
"aggregator_client_id": None,
8489
"times": {
8590
"one-off": True,
8691
"interval": None,

0 commit comments

Comments
 (0)