pingera-cli 0.1.13__tar.gz → 0.1.15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pingera_cli-0.1.13/pingera_cli.egg-info → pingera_cli-0.1.15}/PKG-INFO +2 -2
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/__init__.py +1 -1
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/checks.py +74 -27
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/on_demand_checks.py +172 -37
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/__init__.py +2 -1
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/base_formatter.py +7 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/multistep_formatter.py +30 -31
- pingera_cli-0.1.15/pingera_cli/formatters/portscan_formatter.py +189 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/registry.py +2 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/ssl_formatter.py +77 -27
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/web_formatter.py +37 -32
- pingera_cli-0.1.15/pingera_cli/main.py +455 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/utils/config.py +26 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15/pingera_cli.egg-info}/PKG-INFO +2 -2
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli.egg-info/SOURCES.txt +2 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli.egg-info/requires.txt +1 -1
- pingera_cli-0.1.15/pwscript.js +14 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pyproject.toml +1 -1
- pingera_cli-0.1.13/pingera_cli/main.py +0 -226
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/.gitignore +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/.replit +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/LICENSE +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/README.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/assert +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/docs/cli-commands.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/docs/example-check.yaml +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/docs/example-synthetic-screenshot.json +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/docs/example-web-check.json +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/__main__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/auth.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/base.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/check_groups.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/check_secrets.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/execution_groups.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/commands/secrets.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/dns_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/generic_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/icmp_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/formatters/synthetic_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/utils/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/utils/console.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli/utils/file_utils.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli.egg-info/dependency_links.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli.egg-info/entry_points.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/pingera_cli.egg-info/top_level.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/replit.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/run_tests.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/setup.cfg +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/setup.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/conftest.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/requirements.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/test_auth.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/test_checks.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/test_config.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.15}/tests/test_on_demand_checks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pingera-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK
|
|
5
5
|
Home-page: https://github.com/pingera/pingera-cli
|
|
6
6
|
Author: PingeraCLI Team
|
|
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: typer[all]>=0.9.0
|
|
33
33
|
Requires-Dist: rich>=13.0.0
|
|
34
|
-
Requires-Dist: pingera-sdk>=1.0.
|
|
34
|
+
Requires-Dist: pingera-sdk>=1.0.13
|
|
35
35
|
Requires-Dist: click>=8.0.0
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Pingera CLI - A beautiful CLI tool for Pingera Platform
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.1.
|
|
5
|
+
__version__ = "0.1.15"
|
|
6
6
|
__author__ = "Pingera Team"
|
|
7
7
|
__description__ = "A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK"
|
|
8
8
|
|
|
@@ -14,6 +14,9 @@ from rich.prompt import Confirm
|
|
|
14
14
|
from .base import BaseCommand
|
|
15
15
|
from ..utils.config import get_api_key
|
|
16
16
|
|
|
17
|
+
# Supported check types
|
|
18
|
+
SUPPORTED_CHECK_TYPES = ["web", "api", "tcp", "ssl", "dns", "icmp", "portscan", "synthetic", "multistep"]
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
class ChecksCommand(BaseCommand):
|
|
19
22
|
"""
|
|
@@ -412,7 +415,7 @@ class ChecksCommand(BaseCommand):
|
|
|
412
415
|
self.display_error(str(e))
|
|
413
416
|
raise typer.Exit(1)
|
|
414
417
|
|
|
415
|
-
def create_check(self, name: str, check_type: str, url: Optional[str] = None, host: Optional[str] = None, port: Optional[int] = None, interval: int = 300, timeout: int = 30, parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None):
|
|
418
|
+
def create_check(self, name: str, check_type: str, url: Optional[str] = None, host: Optional[str] = None, port: Optional[int] = None, interval: int = 300, timeout: int = 30, parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None, regions: Optional[str] = None):
|
|
416
419
|
"""Create a new monitoring check"""
|
|
417
420
|
try:
|
|
418
421
|
import json
|
|
@@ -525,7 +528,14 @@ class ChecksCommand(BaseCommand):
|
|
|
525
528
|
self.display_error(f"Failed to read Playwright script file: {str(e)}")
|
|
526
529
|
raise typer.Exit(1)
|
|
527
530
|
|
|
528
|
-
#
|
|
531
|
+
# Handle regions parameter - add to params_dict if provided and not in parameters
|
|
532
|
+
if regions is not None and parameters is None:
|
|
533
|
+
# Parse comma-separated regions into a list
|
|
534
|
+
regions_list = [r.strip() for r in regions.split(',') if r.strip()]
|
|
535
|
+
if regions_list:
|
|
536
|
+
params_dict["regions"] = regions_list
|
|
537
|
+
|
|
538
|
+
# Parse parameters JSON if provided (this takes precedence over --regions)
|
|
529
539
|
if parameters is not None:
|
|
530
540
|
try:
|
|
531
541
|
parsed_params = json.loads(parameters)
|
|
@@ -583,7 +593,7 @@ class ChecksCommand(BaseCommand):
|
|
|
583
593
|
self.display_error(f"Failed to create check: {str(e)}")
|
|
584
594
|
raise typer.Exit(1)
|
|
585
595
|
|
|
586
|
-
def update_check(self, check_id: str, name: Optional[str] = None, url: Optional[str] = None, host: Optional[str] = None, port: Optional[int] = None, interval: Optional[int] = None, timeout: Optional[int] = None, active: Optional[bool] = None, parameters: Optional[str] = None, pw_script_file: Optional[str] = None):
|
|
596
|
+
def update_check(self, check_id: str, name: Optional[str] = None, url: Optional[str] = None, host: Optional[str] = None, port: Optional[int] = None, interval: Optional[int] = None, timeout: Optional[int] = None, active: Optional[bool] = None, parameters: Optional[str] = None, pw_script_file: Optional[str] = None, regions: Optional[str] = None):
|
|
587
597
|
"""Update an existing check"""
|
|
588
598
|
try:
|
|
589
599
|
import json
|
|
@@ -629,7 +639,14 @@ class ChecksCommand(BaseCommand):
|
|
|
629
639
|
self.display_error(f"Failed to read Playwright script file: {str(e)}")
|
|
630
640
|
raise typer.Exit(1)
|
|
631
641
|
|
|
632
|
-
#
|
|
642
|
+
# Handle regions parameter - add to params_dict if provided and not in parameters
|
|
643
|
+
if regions is not None and parameters is None:
|
|
644
|
+
# Parse comma-separated regions into a list
|
|
645
|
+
regions_list = [r.strip() for r in regions.split(',') if r.strip()]
|
|
646
|
+
if regions_list:
|
|
647
|
+
params_dict["regions"] = regions_list
|
|
648
|
+
|
|
649
|
+
# Parse parameters JSON if provided (this takes precedence over --regions)
|
|
633
650
|
if parameters is not None:
|
|
634
651
|
try:
|
|
635
652
|
parsed_params = json.loads(parameters)
|
|
@@ -749,7 +766,7 @@ class ChecksCommand(BaseCommand):
|
|
|
749
766
|
# If result_id was specified, we're fetching a single result - display it with full formatting
|
|
750
767
|
if result_id and len(response.results) == 1:
|
|
751
768
|
result = response.results[0]
|
|
752
|
-
|
|
769
|
+
|
|
753
770
|
if self.output_format in ['json', 'yaml']:
|
|
754
771
|
result_dict = {
|
|
755
772
|
"id": str(result.id) if hasattr(result, 'id') and result.id else None,
|
|
@@ -901,10 +918,8 @@ class ChecksCommand(BaseCommand):
|
|
|
901
918
|
|
|
902
919
|
# Provide helpful hints based on context
|
|
903
920
|
hints = []
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
else:
|
|
907
|
-
hints.append("Use 'pngr checks results --result-id <result-id>' for detailed result info")
|
|
921
|
+
hints.append("Use 'pngr checks result <result-id>' for detailed result info")
|
|
922
|
+
if not check_id:
|
|
908
923
|
hints.append("Use 'pngr checks list' to see all available checks and their IDs")
|
|
909
924
|
hints.append("Filter results: --type <type>, --status <status>, --region <region>")
|
|
910
925
|
|
|
@@ -935,16 +950,19 @@ class ChecksCommand(BaseCommand):
|
|
|
935
950
|
self.display_error(f"Failed to get result details: {str(e)}")
|
|
936
951
|
raise typer.Exit(1)
|
|
937
952
|
|
|
938
|
-
def get_check_result_detailed(self,
|
|
939
|
-
"""Get detailed information for a specific check result using
|
|
953
|
+
def get_check_result_detailed(self, result_id: str, verbose: bool = False):
|
|
954
|
+
"""Get detailed information for a specific check result using result_id"""
|
|
940
955
|
try:
|
|
941
|
-
|
|
956
|
+
unified_api = self.get_unified_results_client()
|
|
942
957
|
|
|
943
|
-
# Use the
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
958
|
+
# Use the unified results API with result_id filter
|
|
959
|
+
response = unified_api.v1_checks_all_results_get(result_id=result_id)
|
|
960
|
+
|
|
961
|
+
if not hasattr(response, 'results') or not response.results or len(response.results) == 0:
|
|
962
|
+
self.display_error(f"Result {result_id} not found")
|
|
963
|
+
raise typer.Exit(1)
|
|
964
|
+
|
|
965
|
+
result = response.results[0]
|
|
948
966
|
|
|
949
967
|
if self.output_format in ['json', 'yaml']:
|
|
950
968
|
# Full result data for JSON/YAML
|
|
@@ -979,7 +997,7 @@ class ChecksCommand(BaseCommand):
|
|
|
979
997
|
response_time_display = f"{result.response_time}ms"
|
|
980
998
|
else:
|
|
981
999
|
response_time_display = 'N/A'
|
|
982
|
-
|
|
1000
|
+
|
|
983
1001
|
basic_info = f"""[bold cyan]Basic Information:[/bold cyan]
|
|
984
1002
|
• Result ID: [white]{result.id}[/white]
|
|
985
1003
|
• Check ID: [white]{result.check_id}[/white]
|
|
@@ -1058,6 +1076,7 @@ class ChecksCommand(BaseCommand):
|
|
|
1058
1076
|
region_dict = {
|
|
1059
1077
|
"id": str(region.id) if hasattr(region, 'id') and region.id else None,
|
|
1060
1078
|
"display_name": region.display_name if hasattr(region, 'display_name') and region.display_name else None,
|
|
1079
|
+
"aliases": region.aliases if hasattr(region, 'aliases') and region.aliases else None,
|
|
1061
1080
|
"available_check_types": region.available_check_types if hasattr(region, 'available_check_types') and region.available_check_types else None
|
|
1062
1081
|
}
|
|
1063
1082
|
regions_data.append(region_dict)
|
|
@@ -1073,6 +1092,7 @@ class ChecksCommand(BaseCommand):
|
|
|
1073
1092
|
table = Table(title=table_title)
|
|
1074
1093
|
table.add_column("Region ID", style="cyan", min_width=15)
|
|
1075
1094
|
table.add_column("Display Name", style="green", min_width=25)
|
|
1095
|
+
table.add_column("Aliases", style="yellow", min_width=20)
|
|
1076
1096
|
table.add_column("Available Check Types", style="white")
|
|
1077
1097
|
|
|
1078
1098
|
for region in response.regions:
|
|
@@ -1080,6 +1100,14 @@ class ChecksCommand(BaseCommand):
|
|
|
1080
1100
|
region_id = str(region.id) if hasattr(region, 'id') and region.id else "-"
|
|
1081
1101
|
display_name = region.display_name if hasattr(region, 'display_name') and region.display_name else "-"
|
|
1082
1102
|
|
|
1103
|
+
# Handle aliases
|
|
1104
|
+
aliases_display = "-"
|
|
1105
|
+
if hasattr(region, 'aliases') and region.aliases:
|
|
1106
|
+
if isinstance(region.aliases, list):
|
|
1107
|
+
aliases_display = ", ".join(region.aliases)
|
|
1108
|
+
else:
|
|
1109
|
+
aliases_display = str(region.aliases)
|
|
1110
|
+
|
|
1083
1111
|
# Handle available check types
|
|
1084
1112
|
available_types = "-"
|
|
1085
1113
|
if hasattr(region, 'available_check_types') and region.available_check_types:
|
|
@@ -1091,6 +1119,7 @@ class ChecksCommand(BaseCommand):
|
|
|
1091
1119
|
table.add_row(
|
|
1092
1120
|
region_id,
|
|
1093
1121
|
display_name,
|
|
1122
|
+
aliases_display,
|
|
1094
1123
|
available_types
|
|
1095
1124
|
)
|
|
1096
1125
|
|
|
@@ -1169,15 +1198,15 @@ def list_checks(
|
|
|
1169
1198
|
):
|
|
1170
1199
|
"""List monitoring checks with advanced filtering options"""
|
|
1171
1200
|
from ..utils.config import get_output_format
|
|
1172
|
-
|
|
1201
|
+
|
|
1173
1202
|
# Validate name length
|
|
1174
1203
|
if name and len(name) > 100:
|
|
1175
1204
|
typer.echo("Error: Name filter cannot exceed 100 characters", err=True)
|
|
1176
1205
|
raise typer.Exit(1)
|
|
1177
1206
|
|
|
1178
1207
|
# Validate check type
|
|
1179
|
-
if check_type and check_type not in
|
|
1180
|
-
typer.echo("Error: Invalid check type. Must be one of:
|
|
1208
|
+
if check_type and check_type not in SUPPORTED_CHECK_TYPES:
|
|
1209
|
+
typer.echo(f"Error: Invalid check type '{check_type}'. Must be one of: {', '.join(SUPPORTED_CHECK_TYPES)}", err=True)
|
|
1181
1210
|
raise typer.Exit(1)
|
|
1182
1211
|
|
|
1183
1212
|
# Validate status values if provided
|
|
@@ -1214,7 +1243,8 @@ def create_check(
|
|
|
1214
1243
|
timeout: int = typer.Option(30, "--timeout", help="Timeout in seconds"),
|
|
1215
1244
|
parameters: Optional[str] = typer.Option(None, "--parameters", help="JSON string with check parameters (e.g., '{\"regions\": [\"US\", \"EU\"]}')"),
|
|
1216
1245
|
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks"),
|
|
1217
|
-
from_file: Optional[str] = typer.Option(None, "--from-file", "-f", help="Path to JSON or YAML file containing check configuration")
|
|
1246
|
+
from_file: Optional[str] = typer.Option(None, "--from-file", "-f", help="Path to JSON or YAML file containing check configuration"),
|
|
1247
|
+
regions: Optional[str] = typer.Option(None, "--regions", help="Comma-separated list of regions (e.g., 'ru-central1,eu-west1')"),
|
|
1218
1248
|
):
|
|
1219
1249
|
"""Create a new monitoring check. Can be created from command line options or from a JSON/YAML file.
|
|
1220
1250
|
|
|
@@ -1236,8 +1266,13 @@ def create_check(
|
|
|
1236
1266
|
typer.echo("Error: --name is required when not using --from-file", err=True)
|
|
1237
1267
|
raise typer.Exit(1)
|
|
1238
1268
|
|
|
1269
|
+
# Validate check type
|
|
1270
|
+
if check_type not in SUPPORTED_CHECK_TYPES:
|
|
1271
|
+
typer.echo(f"Error: Invalid check type '{check_type}'. Must be one of: {', '.join(SUPPORTED_CHECK_TYPES)}", err=True)
|
|
1272
|
+
raise typer.Exit(1)
|
|
1273
|
+
|
|
1239
1274
|
checks_cmd = ChecksCommand(get_output_format())
|
|
1240
|
-
checks_cmd.create_check(name, check_type, url, host, port, interval, timeout, parameters, pw_script_file, from_file)
|
|
1275
|
+
checks_cmd.create_check(name, check_type, url, host, port, interval, timeout, parameters, pw_script_file, from_file, regions)
|
|
1241
1276
|
|
|
1242
1277
|
|
|
1243
1278
|
@app.command("update")
|
|
@@ -1251,12 +1286,13 @@ def update_check(
|
|
|
1251
1286
|
timeout: Optional[int] = typer.Option(None, "--timeout", help="New timeout in seconds"),
|
|
1252
1287
|
active: bool = typer.Option(None, "--active/--inactive", help="Enable or disable the check"),
|
|
1253
1288
|
parameters: Optional[str] = typer.Option(None, "--parameters", help="JSON string with check parameters (e.g., '{\"pw_script\": \"...\", \"regions\": [\"US\", \"EU\"]}')"),
|
|
1254
|
-
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks")
|
|
1289
|
+
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks"),
|
|
1290
|
+
regions: Optional[str] = typer.Option(None, "--regions", help="Comma-separated list of regions (e.g., 'ru-central1,eu-west1')"),
|
|
1255
1291
|
):
|
|
1256
1292
|
"""Update an existing check. Use --parameters to provide complex parameters like Playwright scripts, regions, etc."""
|
|
1257
1293
|
from ..utils.config import get_output_format
|
|
1258
1294
|
checks_cmd = ChecksCommand(get_output_format())
|
|
1259
|
-
checks_cmd.update_check(check_id, name, url, host, port, interval, timeout, active, parameters, pw_script_file)
|
|
1295
|
+
checks_cmd.update_check(check_id, name, url, host, port, interval, timeout, active, parameters, pw_script_file, regions)
|
|
1260
1296
|
|
|
1261
1297
|
|
|
1262
1298
|
@app.command("delete")
|
|
@@ -1284,20 +1320,25 @@ def get_results(
|
|
|
1284
1320
|
):
|
|
1285
1321
|
"""Get check results with advanced filtering. If no check_id is provided, returns unified results across all checks. Use --result-id to fetch a specific result."""
|
|
1286
1322
|
from ..utils.config import get_output_format
|
|
1323
|
+
|
|
1324
|
+
# Validate check type
|
|
1325
|
+
if check_type and check_type not in SUPPORTED_CHECK_TYPES:
|
|
1326
|
+
typer.echo(f"Error: Invalid check type '{check_type}'. Must be one of: {', '.join(SUPPORTED_CHECK_TYPES)}", err=True)
|
|
1327
|
+
raise typer.Exit(1)
|
|
1328
|
+
|
|
1287
1329
|
checks_cmd = ChecksCommand(get_output_format())
|
|
1288
1330
|
checks_cmd.get_check_results(check_id, from_date, to_date, page, page_size, status, check_type, region, result_id)
|
|
1289
1331
|
|
|
1290
1332
|
|
|
1291
1333
|
@app.command("result")
|
|
1292
1334
|
def get_result(
|
|
1293
|
-
check_id: str = typer.Argument(..., help="Check ID"),
|
|
1294
1335
|
result_id: str = typer.Argument(..., help="Result ID to retrieve detailed information for"),
|
|
1295
1336
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show full detailed information including network requests"),
|
|
1296
1337
|
):
|
|
1297
1338
|
"""Get detailed information for a specific check result"""
|
|
1298
1339
|
from ..utils.config import get_output_format
|
|
1299
1340
|
checks_cmd = ChecksCommand(get_output_format())
|
|
1300
|
-
checks_cmd.get_check_result_detailed(
|
|
1341
|
+
checks_cmd.get_check_result_detailed(result_id, verbose)
|
|
1301
1342
|
|
|
1302
1343
|
|
|
1303
1344
|
@app.command("list-regions")
|
|
@@ -1306,6 +1347,12 @@ def list_regions(
|
|
|
1306
1347
|
):
|
|
1307
1348
|
"""List available regions for monitoring checks"""
|
|
1308
1349
|
from ..utils.config import get_output_format
|
|
1350
|
+
|
|
1351
|
+
# Validate check type
|
|
1352
|
+
if check_type and check_type not in SUPPORTED_CHECK_TYPES:
|
|
1353
|
+
typer.echo(f"Error: Invalid check type '{check_type}'. Must be one of: {', '.join(SUPPORTED_CHECK_TYPES)}", err=True)
|
|
1354
|
+
raise typer.Exit(1)
|
|
1355
|
+
|
|
1309
1356
|
checks_cmd = ChecksCommand(get_output_format())
|
|
1310
1357
|
checks_cmd.list_regions(check_type)
|
|
1311
1358
|
|
|
@@ -13,14 +13,18 @@ from rich.panel import Panel
|
|
|
13
13
|
from .base import BaseCommand
|
|
14
14
|
from ..utils.config import get_api_key
|
|
15
15
|
|
|
16
|
+
# Supported check types for on-demand execution
|
|
17
|
+
SUPPORTED_CHECK_TYPES = ["web", "api", "tcp", "ssl", "dns", "icmp", "portscan", "synthetic", "multistep"]
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
class OnDemandChecksCommand(BaseCommand):
|
|
18
21
|
"""
|
|
19
22
|
Commands for managing on-demand monitoring checks
|
|
20
23
|
"""
|
|
21
24
|
|
|
22
|
-
def __init__(self, output_format: Optional[str] = None):
|
|
25
|
+
def __init__(self, output_format: Optional[str] = None, verbose: bool = False):
|
|
23
26
|
super().__init__(output_format)
|
|
27
|
+
self.verbose = verbose
|
|
24
28
|
|
|
25
29
|
def _parse_check_file(self, file_path: str) -> dict:
|
|
26
30
|
"""Parse check configuration from JSON or YAML file (local or URL)"""
|
|
@@ -63,7 +67,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
63
67
|
self.display_error(f"Failed to initialize client: {str(e)}")
|
|
64
68
|
raise typer.Exit(1)
|
|
65
69
|
|
|
66
|
-
def execute_custom_check(self, url: Optional[str] = None, check_type: str = "web", host: Optional[str] = None, port: Optional[int] = None, timeout: int =
|
|
70
|
+
def execute_custom_check(self, url: Optional[str] = None, check_type: str = "web", host: Optional[str] = None, port: Optional[int] = None, timeout: Optional[int] = None, name: str = "On-demand check", regions: Optional[str] = None, parameters: Optional[str] = None, pw_script_file: Optional[str] = None, from_file: Optional[str] = None, wait_for_result: bool = True, ports: Optional[str] = None):
|
|
67
71
|
"""Execute custom on-demand check"""
|
|
68
72
|
try:
|
|
69
73
|
import json
|
|
@@ -85,10 +89,15 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
85
89
|
# Command line options take precedence over file data
|
|
86
90
|
check_data = {
|
|
87
91
|
"name": filtered_file_data.get("name", name),
|
|
88
|
-
"type": filtered_file_data.get("type", check_type)
|
|
89
|
-
"timeout": filtered_file_data.get("timeout", timeout)
|
|
92
|
+
"type": filtered_file_data.get("type", check_type)
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
# Handle timeout - only set if explicitly provided or in file
|
|
96
|
+
if timeout is not None:
|
|
97
|
+
check_data["timeout"] = timeout
|
|
98
|
+
elif "timeout" in filtered_file_data:
|
|
99
|
+
check_data["timeout"] = filtered_file_data["timeout"]
|
|
100
|
+
|
|
92
101
|
# Override with command line values if provided
|
|
93
102
|
if name != "On-demand check": # Only override if name was explicitly provided
|
|
94
103
|
check_data["name"] = name
|
|
@@ -141,9 +150,12 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
141
150
|
# Build check data normally
|
|
142
151
|
check_data = {
|
|
143
152
|
"name": name,
|
|
144
|
-
"type": check_type
|
|
145
|
-
"timeout": timeout
|
|
153
|
+
"type": check_type
|
|
146
154
|
}
|
|
155
|
+
|
|
156
|
+
# Only set timeout if explicitly provided by user
|
|
157
|
+
if timeout is not None:
|
|
158
|
+
check_data["timeout"] = timeout
|
|
147
159
|
|
|
148
160
|
# Add URL if provided (required for web, api, ssl checks)
|
|
149
161
|
if url is not None:
|
|
@@ -177,7 +189,18 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
177
189
|
self.display_error(f"Failed to read Playwright script file: {str(e)}")
|
|
178
190
|
raise typer.Exit(1)
|
|
179
191
|
|
|
180
|
-
#
|
|
192
|
+
# Handle regions parameter - add to params_dict if provided and not in parameters
|
|
193
|
+
if regions is not None and parameters is None:
|
|
194
|
+
# Parse comma-separated regions into a list
|
|
195
|
+
regions_list = [r.strip() for r in regions.split(',') if r.strip()]
|
|
196
|
+
if regions_list:
|
|
197
|
+
params_dict["regions"] = regions_list
|
|
198
|
+
|
|
199
|
+
# Handle ports parameter - add to params_dict if provided and not in parameters
|
|
200
|
+
if ports is not None and parameters is None:
|
|
201
|
+
params_dict["ports"] = ports
|
|
202
|
+
|
|
203
|
+
# Parse parameters JSON if provided (this takes precedence over --regions and --ports)
|
|
181
204
|
if parameters is not None:
|
|
182
205
|
try:
|
|
183
206
|
parsed_params = json.loads(parameters)
|
|
@@ -194,11 +217,17 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
194
217
|
|
|
195
218
|
# Validation based on check type - use the actual type from check_data
|
|
196
219
|
actual_check_type = check_data.get("type", check_type)
|
|
220
|
+
|
|
221
|
+
# Validate check type is supported
|
|
222
|
+
if actual_check_type not in SUPPORTED_CHECK_TYPES:
|
|
223
|
+
self.display_error(f"Invalid check type: {actual_check_type}. Supported types: {', '.join(SUPPORTED_CHECK_TYPES)}")
|
|
224
|
+
raise typer.Exit(1)
|
|
225
|
+
|
|
197
226
|
if actual_check_type in ['web', 'api'] and not url:
|
|
198
227
|
self.display_error(f"URL is required for {actual_check_type} checks")
|
|
199
228
|
raise typer.Exit(1)
|
|
200
229
|
|
|
201
|
-
if actual_check_type in ['tcp'] and not host:
|
|
230
|
+
if actual_check_type in ['tcp', 'portscan', 'dns', 'icmp'] and not host:
|
|
202
231
|
self.display_error(f"Host is required for {actual_check_type} checks")
|
|
203
232
|
raise typer.Exit(1)
|
|
204
233
|
|
|
@@ -446,15 +475,17 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
446
475
|
}
|
|
447
476
|
self.output_data(job_data)
|
|
448
477
|
else:
|
|
449
|
-
# Rich formatted detailed view
|
|
450
|
-
self.
|
|
478
|
+
# Rich formatted detailed view - fetch and display with results
|
|
479
|
+
self._fetch_and_display_job_result(job_id, job_status, verbose=self.verbose)
|
|
451
480
|
|
|
452
481
|
except Exception as e:
|
|
453
482
|
self.display_error(f"Failed to get job status: {str(e)}")
|
|
454
483
|
raise typer.Exit(1)
|
|
455
484
|
|
|
456
|
-
def _fetch_and_display_job_result(self, job_id: str, job_status):
|
|
485
|
+
def _fetch_and_display_job_result(self, job_id: str, job_status, verbose: bool = False):
|
|
457
486
|
"""Fetch detailed results from the new results endpoint and display them"""
|
|
487
|
+
import time
|
|
488
|
+
|
|
458
489
|
try:
|
|
459
490
|
# Extract result_id(s) from job response
|
|
460
491
|
result_ids = []
|
|
@@ -463,14 +494,56 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
463
494
|
if hasattr(job_status, 'result') and job_status.result:
|
|
464
495
|
result = job_status.result
|
|
465
496
|
|
|
497
|
+
# Debug: Print the raw result to see what we're getting (only in verbose mode)
|
|
498
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
499
|
+
import json
|
|
500
|
+
self.console.print(f"[dim]DEBUG: Raw result from job status:[/dim]")
|
|
501
|
+
self.console.print(f"[dim]{json.dumps(result, indent=2, default=str)}[/dim]")
|
|
502
|
+
|
|
466
503
|
# Check if this is a multi-region result
|
|
467
504
|
if isinstance(result, dict):
|
|
468
505
|
if 'regional_summary' in result and result['regional_summary']:
|
|
469
506
|
# Multi-region execution
|
|
470
507
|
is_multi_region = True
|
|
471
|
-
|
|
508
|
+
regional_summary = result['regional_summary']
|
|
509
|
+
|
|
510
|
+
# Debug: Show what we found (only in verbose mode)
|
|
511
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
512
|
+
self.console.print(f"[dim]DEBUG: Found {len(regional_summary)} regions in regional_summary[/dim]")
|
|
513
|
+
|
|
514
|
+
for regional_result in regional_summary:
|
|
472
515
|
if 'result_id' in regional_result:
|
|
473
516
|
result_ids.append(regional_result['result_id'])
|
|
517
|
+
|
|
518
|
+
# Check if we might be missing results (race condition detection)
|
|
519
|
+
total_regions = result.get('total_regions', len(regional_summary))
|
|
520
|
+
completed_regions = result.get('completed_regions', len(regional_summary))
|
|
521
|
+
|
|
522
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
523
|
+
self.console.print(f"[dim]DEBUG: total_regions={total_regions}, completed_regions={completed_regions}, found result_ids={len(result_ids)}[/dim]")
|
|
524
|
+
|
|
525
|
+
# If we're missing results, wait a bit and refetch
|
|
526
|
+
if len(result_ids) < total_regions:
|
|
527
|
+
if self.output_format not in ['json', 'yaml']:
|
|
528
|
+
self.console.print(f"[yellow]⚠ Race condition detected: {len(result_ids)}/{total_regions} results ready. Waiting 2s and retrying...[/yellow]")
|
|
529
|
+
time.sleep(2)
|
|
530
|
+
|
|
531
|
+
# Refetch job status
|
|
532
|
+
checks_api = self.get_client()
|
|
533
|
+
job_status = checks_api.v1_checks_jobs_job_id_get(job_id=job_id)
|
|
534
|
+
|
|
535
|
+
# Re-extract result_ids
|
|
536
|
+
result_ids = []
|
|
537
|
+
if hasattr(job_status, 'result') and job_status.result:
|
|
538
|
+
result = job_status.result
|
|
539
|
+
if isinstance(result, dict) and 'regional_summary' in result:
|
|
540
|
+
for regional_result in result['regional_summary']:
|
|
541
|
+
if 'result_id' in regional_result:
|
|
542
|
+
result_ids.append(regional_result['result_id'])
|
|
543
|
+
|
|
544
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
545
|
+
self.console.print(f"[dim]DEBUG: After retry, found {len(result_ids)} result_ids[/dim]")
|
|
546
|
+
|
|
474
547
|
elif 'result_id' in result:
|
|
475
548
|
# Single-region execution
|
|
476
549
|
result_ids.append(result['result_id'])
|
|
@@ -487,14 +560,14 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
487
560
|
raise typer.Exit(1)
|
|
488
561
|
|
|
489
562
|
from pingera import ApiClient, Configuration
|
|
490
|
-
from pingera.api import
|
|
563
|
+
from pingera.api import ChecksUnifiedResultsApi
|
|
491
564
|
from ..utils.config import get_config
|
|
492
565
|
|
|
493
566
|
configuration = Configuration()
|
|
494
567
|
configuration.host = get_config().get('base_url', 'https://api.pingera.ru')
|
|
495
568
|
configuration.api_key['apiKeyAuth'] = api_key
|
|
496
569
|
api_client = ApiClient(configuration)
|
|
497
|
-
checks_api =
|
|
570
|
+
checks_api = ChecksUnifiedResultsApi(api_client)
|
|
498
571
|
|
|
499
572
|
# Fetch detailed results for each result_id
|
|
500
573
|
if is_multi_region:
|
|
@@ -547,13 +620,15 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
547
620
|
self.console.print(f"\n[bold cyan]Multi-Region Execution Result[/bold cyan]")
|
|
548
621
|
self.console.print(f"• Job ID: [white]{job_id}[/white]")
|
|
549
622
|
self.console.print(f"• Status: [{status_color}]{status_emoji} {job_status.status}[/{status_color}]")
|
|
550
|
-
self.console.print(f"• Regions: [white]{len(result_ids)}[/white]")
|
|
551
623
|
|
|
552
624
|
# Extract and display aggregated statistics
|
|
553
625
|
if hasattr(job_status, 'result') and isinstance(job_status.result, dict):
|
|
554
626
|
result = job_status.result
|
|
555
627
|
regional_summary = result.get('regional_summary', [])
|
|
556
628
|
|
|
629
|
+
# Display region count from actual regional_summary
|
|
630
|
+
self.console.print(f"• Regions: [white]{len(regional_summary)}[/white]")
|
|
631
|
+
|
|
557
632
|
if regional_summary:
|
|
558
633
|
# Calculate aggregated statistics
|
|
559
634
|
response_times = []
|
|
@@ -616,19 +691,68 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
616
691
|
|
|
617
692
|
def _display_detailed_result_with_job_info(self, job_status, job_id: str, detailed_result):
|
|
618
693
|
"""Display detailed result information combined with job info"""
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
694
|
+
from rich.panel import Panel
|
|
695
|
+
from ..formatters.registry import FormatterRegistry
|
|
696
|
+
|
|
697
|
+
# Determine status color and emoji
|
|
698
|
+
status_emoji = "✅" if hasattr(detailed_result, 'status') and detailed_result.status == 'ok' else "❌"
|
|
699
|
+
status_color = "green" if hasattr(detailed_result, 'status') and detailed_result.status == 'ok' else "red"
|
|
622
700
|
|
|
623
|
-
#
|
|
701
|
+
# Basic information
|
|
702
|
+
basic_info = f"""[bold cyan]Basic Information:[/bold cyan]
|
|
703
|
+
• Result ID: [white]{detailed_result.id if hasattr(detailed_result, 'id') else 'Unknown'}[/white]
|
|
704
|
+
• Check ID: [white]{detailed_result.check_id if hasattr(detailed_result, 'check_id') and detailed_result.check_id else 'None'}[/white]
|
|
705
|
+
• Status: [{status_color}]{status_emoji} {detailed_result.status if hasattr(detailed_result, 'status') else 'Unknown'}[/{status_color}]
|
|
706
|
+
• Timestamp: [white]{detailed_result.created_at.strftime('%Y-%m-%d %H:%M:%S UTC') if hasattr(detailed_result, 'created_at') and detailed_result.created_at else 'Unknown'}[/white]"""
|
|
707
|
+
|
|
708
|
+
if hasattr(detailed_result, 'response_time') and detailed_result.response_time:
|
|
709
|
+
basic_info += f"\n• Response Time: [yellow]{detailed_result.response_time}ms[/yellow]"
|
|
710
|
+
|
|
711
|
+
# Server information
|
|
712
|
+
if hasattr(detailed_result, 'check_server') and detailed_result.check_server:
|
|
713
|
+
server = detailed_result.check_server
|
|
714
|
+
server_info = f"""• Check Server: [white]{server.id if hasattr(server, 'id') else 'Unknown'}[/white]
|
|
715
|
+
• Server IP: [white]{server.ip_address if hasattr(server, 'ip_address') else 'Unknown'}[/white]
|
|
716
|
+
• Server Country: [white]{server.country if hasattr(server, 'country') else 'Unknown'}[/white]
|
|
717
|
+
• Server Region: [white]{server.region if hasattr(server, 'region') else 'Unknown'}[/white]"""
|
|
718
|
+
basic_info += f"\n{server_info}"
|
|
719
|
+
|
|
720
|
+
# Error information
|
|
721
|
+
error_info = ""
|
|
722
|
+
if hasattr(detailed_result, 'error_message') and detailed_result.error_message:
|
|
723
|
+
error_info = f"""
|
|
724
|
+
[bold red]Error Information:[/bold red]
|
|
725
|
+
• Error: [red]{detailed_result.error_message}[/red]"""
|
|
726
|
+
|
|
727
|
+
# Metadata analysis using formatters
|
|
728
|
+
metadata_info = ""
|
|
624
729
|
if hasattr(detailed_result, 'check_metadata') and detailed_result.check_metadata:
|
|
625
|
-
|
|
626
|
-
registry = FormatterRegistry(verbose=False)
|
|
627
|
-
metadata_formatted = registry.format_metadata(detailed_result.check_metadata)
|
|
730
|
+
metadata = detailed_result.check_metadata
|
|
628
731
|
|
|
629
|
-
if
|
|
630
|
-
|
|
631
|
-
|
|
732
|
+
if isinstance(metadata, dict):
|
|
733
|
+
# Add result_id to metadata for formatters to use in truncation notice
|
|
734
|
+
metadata_with_id = metadata.copy()
|
|
735
|
+
if hasattr(detailed_result, 'id'):
|
|
736
|
+
metadata_with_id['result_id'] = detailed_result.id
|
|
737
|
+
|
|
738
|
+
registry = FormatterRegistry(verbose=self.verbose)
|
|
739
|
+
metadata_info = registry.format_metadata(metadata_with_id)
|
|
740
|
+
|
|
741
|
+
# Combine all sections
|
|
742
|
+
full_info = basic_info
|
|
743
|
+
if error_info:
|
|
744
|
+
full_info += error_info
|
|
745
|
+
if metadata_info:
|
|
746
|
+
full_info += metadata_info
|
|
747
|
+
|
|
748
|
+
panel = Panel(
|
|
749
|
+
full_info,
|
|
750
|
+
title=f"🔍 Result Details: {detailed_result.id if hasattr(detailed_result, 'id') else 'Unknown'}",
|
|
751
|
+
border_style="blue",
|
|
752
|
+
padding=(1, 2),
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
self.console.print(panel)
|
|
632
756
|
|
|
633
757
|
def _display_detailed_job_status(self, job_status, job_id: str):
|
|
634
758
|
"""Display detailed job status information in a rich format"""
|
|
@@ -806,7 +930,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
806
930
|
time.sleep(0.5) # Brief pause to show completion
|
|
807
931
|
|
|
808
932
|
# Fetch and display the actual result
|
|
809
|
-
self._fetch_and_display_job_result(job_id, job_status)
|
|
933
|
+
self._fetch_and_display_job_result(job_id, job_status, verbose=self.verbose)
|
|
810
934
|
return
|
|
811
935
|
|
|
812
936
|
elif job_status.status == 'running':
|
|
@@ -858,14 +982,22 @@ def get_output_format():
|
|
|
858
982
|
return get_config().get('output_format', 'table')
|
|
859
983
|
|
|
860
984
|
|
|
985
|
+
def get_verbose_mode():
|
|
986
|
+
"""Get verbose mode from config"""
|
|
987
|
+
from ..utils.config import get_verbose_mode as _get_verbose_mode
|
|
988
|
+
return _get_verbose_mode()
|
|
989
|
+
|
|
990
|
+
|
|
861
991
|
@run_app.command("custom")
|
|
862
992
|
def run_custom_check(
|
|
863
993
|
url: Optional[str] = typer.Option(None, "--url", "-u", help="URL to monitor (required for web, api, ssl checks)"),
|
|
864
|
-
check_type: str = typer.Option("web", "--type", "-t", help="Check type
|
|
865
|
-
host: Optional[str] = typer.Option(None, "--host", help="Hostname/IP for TCP/SSL checks (max 255 characters)"),
|
|
866
|
-
port: Optional[int] = typer.Option(None, "--port", help="Port number for TCP checks (1-65535)"),
|
|
867
|
-
|
|
994
|
+
check_type: str = typer.Option("web", "--type", "-t", help=f"Check type: {', '.join(SUPPORTED_CHECK_TYPES)}"),
|
|
995
|
+
host: Optional[str] = typer.Option(None, "--host", help="Hostname/IP for TCP/SSL/portscan/DNS/ICMP checks (max 255 characters)"),
|
|
996
|
+
port: Optional[int] = typer.Option(None, "--port", "-p", help="Port number for TCP/SSL checks (1-65535)"),
|
|
997
|
+
ports: Optional[str] = typer.Option(None, "--ports", help="Ports to scan for portscan checks (e.g., '80,443' or '1-1024'). Overridden by --parameters if both are specified."),
|
|
998
|
+
timeout: Optional[int] = typer.Option(None, "--timeout", help="Timeout in seconds (optional - backend will use defaults if not specified)"),
|
|
868
999
|
name: str = typer.Option("On-demand check", "--name", "-n", help="Check name"),
|
|
1000
|
+
regions: Optional[str] = typer.Option(None, "--regions", "-r", help="Comma-separated list of regions (e.g., 'ru-central1,eu-west1'). Overridden by --parameters if both are specified."),
|
|
869
1001
|
parameters: Optional[str] = typer.Option(None, "--parameters", help="JSON string with check parameters (e.g., '{\"regions\": [\"US\", \"EU\"]}')"),
|
|
870
1002
|
pw_script_file: Optional[str] = typer.Option(None, "--pw-script-file", help="Path to file containing Playwright script for synthetic/multistep checks"),
|
|
871
1003
|
from_file: Optional[str] = typer.Option(None, "--from-file", "-f", help="Path to JSON or YAML file containing check configuration"),
|
|
@@ -883,10 +1015,13 @@ def run_custom_check(
|
|
|
883
1015
|
Parameters vary by check type:
|
|
884
1016
|
- web/api: --url required
|
|
885
1017
|
- tcp: --host required, --port optional
|
|
886
|
-
- ssl: --url or --host required
|
|
887
|
-
-
|
|
888
|
-
|
|
889
|
-
|
|
1018
|
+
- ssl: --url or --host required, --port optional
|
|
1019
|
+
- portscan: --host required, --ports optional
|
|
1020
|
+
- synthetic/multistep: --pw-script-file or --parameters with pw_script required
|
|
1021
|
+
|
|
1022
|
+
Timeout is optional - if not specified, backend will use appropriate defaults for each check type."""
|
|
1023
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
1024
|
+
on_demand_cmd.execute_custom_check(url, check_type, host, port, timeout, name, regions, parameters, pw_script_file, from_file, not no_wait, ports)
|
|
890
1025
|
|
|
891
1026
|
|
|
892
1027
|
@run_app.command("existing")
|
|
@@ -895,7 +1030,7 @@ def run_existing_check(
|
|
|
895
1030
|
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for job completion, just queue the check and return job ID"),
|
|
896
1031
|
):
|
|
897
1032
|
"""Execute existing check on demand. By default, waits for job completion and shows result immediately (max 5 minutes). Use --no-wait to just queue the check."""
|
|
898
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
1033
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
899
1034
|
on_demand_cmd.execute_existing_check(check_id, not no_wait)
|
|
900
1035
|
|
|
901
1036
|
|
|
@@ -905,7 +1040,7 @@ def list_jobs(
|
|
|
905
1040
|
page_size: int = typer.Option(20, "--page-size", "-s", help="Items per page"),
|
|
906
1041
|
):
|
|
907
1042
|
"""List check jobs"""
|
|
908
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
1043
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
909
1044
|
on_demand_cmd.list_jobs(page, page_size)
|
|
910
1045
|
|
|
911
1046
|
|
|
@@ -914,5 +1049,5 @@ def get_job_status(
|
|
|
914
1049
|
job_id: str = typer.Argument(..., help="Job ID to get status for"),
|
|
915
1050
|
):
|
|
916
1051
|
"""Get job status and results. For multi-region executions, shows aggregated statistics and regional summary."""
|
|
917
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
1052
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
918
1053
|
on_demand_cmd.get_job_status(job_id)
|