redisbench-admin 0.11.40__py3-none-any.whl → 0.11.42__py3-none-any.whl
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.
- redisbench_admin/compare/args.py +1 -0
- redisbench_admin/compare/compare.py +7 -10
- redisbench_admin/run_remote/args.py +27 -0
- redisbench_admin/run_remote/run_remote.py +67 -6
- redisbench_admin/run_remote/standalone.py +504 -2
- redisbench_admin/utils/remote.py +9 -0
- {redisbench_admin-0.11.40.dist-info → redisbench_admin-0.11.42.dist-info}/METADATA +1 -1
- {redisbench_admin-0.11.40.dist-info → redisbench_admin-0.11.42.dist-info}/RECORD +11 -11
- {redisbench_admin-0.11.40.dist-info → redisbench_admin-0.11.42.dist-info}/LICENSE +0 -0
- {redisbench_admin-0.11.40.dist-info → redisbench_admin-0.11.42.dist-info}/WHEEL +0 -0
- {redisbench_admin-0.11.40.dist-info → redisbench_admin-0.11.42.dist-info}/entry_points.txt +0 -0
redisbench_admin/compare/args.py
CHANGED
|
@@ -131,6 +131,7 @@ def create_compare_arguments(parser):
|
|
|
131
131
|
parser.add_argument("--simple-table", type=bool, default=False)
|
|
132
132
|
parser.add_argument("--use_metric_context_path", type=bool, default=False)
|
|
133
133
|
parser.add_argument("--testname_regex", type=str, default=".*", required=False)
|
|
134
|
+
parser.add_argument("--test-regex", type=str, default=".*", required=False)
|
|
134
135
|
parser.add_argument(
|
|
135
136
|
"--regressions-percent-lower-limit",
|
|
136
137
|
type=float,
|
|
@@ -254,7 +254,9 @@ def compare_command_logic(args, project_name, project_version):
|
|
|
254
254
|
uid = args.grafana_uid
|
|
255
255
|
if tf_github_repo.lower() in grafana_dashboards_uids and uid is None:
|
|
256
256
|
uid = grafana_dashboards_uids[tf_github_repo.lower()]
|
|
257
|
-
logging.info(
|
|
257
|
+
logging.info(
|
|
258
|
+
f"Using uid from grafana_dashboards_uids. {grafana_dashboards_uids}. uid={uid}"
|
|
259
|
+
)
|
|
258
260
|
else:
|
|
259
261
|
logging.info(f"Using uid from args. uid={uid}")
|
|
260
262
|
grafana_link_base = None
|
|
@@ -324,9 +326,7 @@ def compare_command_logic(args, project_name, project_version):
|
|
|
324
326
|
comparison_summary = "In summary:\n"
|
|
325
327
|
if total_stable > 0:
|
|
326
328
|
comparison_summary += (
|
|
327
|
-
"- Detected a total of {} stable tests between versions.\n"
|
|
328
|
-
total_stable,
|
|
329
|
-
)
|
|
329
|
+
f"- Detected a total of {total_stable} stable tests between versions.\n"
|
|
330
330
|
)
|
|
331
331
|
|
|
332
332
|
if total_unstable > 0:
|
|
@@ -388,13 +388,10 @@ def compare_command_logic(args, project_name, project_version):
|
|
|
388
388
|
|
|
389
389
|
comparison_summary += f" - {test_display_name}: {', '.join(commands_info)}{confidence_indicator}\n"
|
|
390
390
|
if total_improvements > 0:
|
|
391
|
-
comparison_summary += "- Detected a total of {} improvements above the improvement water line.\n"
|
|
392
|
-
total_improvements
|
|
393
|
-
)
|
|
391
|
+
comparison_summary += f"- Detected a total of {total_improvements} improvements above the improvement water line.\n"
|
|
394
392
|
if total_regressions > 0:
|
|
395
|
-
comparison_summary += "- Detected a total of {} regressions bellow the regression water line {}
|
|
396
|
-
|
|
397
|
-
)
|
|
393
|
+
comparison_summary += f"- Detected a total of {total_regressions} regressions bellow the regression water line {args.regressions_percent_lower_limit}%.\n"
|
|
394
|
+
comparison_summary += "\n"
|
|
398
395
|
|
|
399
396
|
comment_body += comparison_summary
|
|
400
397
|
comment_body += "\n"
|
|
@@ -130,5 +130,32 @@ def create_run_remote_arguments(parser):
|
|
|
130
130
|
action="store_true",
|
|
131
131
|
help="Continue running benchmarks even if module check failed",
|
|
132
132
|
)
|
|
133
|
+
parser.add_argument(
|
|
134
|
+
"--redis-conf",
|
|
135
|
+
required=False,
|
|
136
|
+
default=None,
|
|
137
|
+
type=str,
|
|
138
|
+
help="Path to custom redis.conf file to copy to remote host",
|
|
139
|
+
)
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"--redis-server-binary",
|
|
142
|
+
required=False,
|
|
143
|
+
default=None,
|
|
144
|
+
type=str,
|
|
145
|
+
help="Path to custom redis-server binary to copy to remote host",
|
|
146
|
+
)
|
|
147
|
+
parser.add_argument(
|
|
148
|
+
"--spin-test",
|
|
149
|
+
default=False,
|
|
150
|
+
action="store_true",
|
|
151
|
+
help="Setup standalone Redis server, run INFO SERVER, print output as markdown and exit",
|
|
152
|
+
)
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"--spin-test-config",
|
|
155
|
+
required=False,
|
|
156
|
+
default=None,
|
|
157
|
+
type=str,
|
|
158
|
+
help="Optional benchmark configuration file for spin-test mode (to execute install_steps)",
|
|
159
|
+
)
|
|
133
160
|
|
|
134
161
|
return parser
|
|
@@ -51,6 +51,7 @@ from redisbench_admin.run_remote.remote_db import (
|
|
|
51
51
|
remote_db_spin,
|
|
52
52
|
db_error_artifacts,
|
|
53
53
|
)
|
|
54
|
+
from redisbench_admin.run_remote.standalone import spin_test_standalone_redis
|
|
54
55
|
from redisbench_admin.run_remote.remote_env import remote_env_setup
|
|
55
56
|
from redisbench_admin.run_remote.remote_failures import failed_remote_run_artifact_store
|
|
56
57
|
from redisbench_admin.run_remote.terraform import (
|
|
@@ -122,12 +123,15 @@ def run_remote_command_logic(args, project_name, project_version):
|
|
|
122
123
|
tf_setup_name_sufix = "{}-{}".format(args.setup_name_sufix, tf_github_sha)
|
|
123
124
|
s3_bucket_name = args.s3_bucket_name
|
|
124
125
|
local_module_files = args.module_path
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
if local_module_files is not None:
|
|
127
|
+
for pos, module_file in enumerate(local_module_files):
|
|
128
|
+
if " " in module_file:
|
|
129
|
+
logging.info(
|
|
130
|
+
"Detected multiple files in single module path {}".format(
|
|
131
|
+
module_file
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
local_module_files[pos] = module_file.split(" ")
|
|
131
135
|
dbdir_folder = args.dbdir_folder
|
|
132
136
|
private_key = args.private_key
|
|
133
137
|
grafana_profile_dashboard = args.grafana_profile_dashboard
|
|
@@ -238,6 +242,63 @@ def run_remote_command_logic(args, project_name, project_version):
|
|
|
238
242
|
|
|
239
243
|
ssh_pem_check(EC2_PRIVATE_PEM, private_key)
|
|
240
244
|
|
|
245
|
+
# Handle spin-test mode
|
|
246
|
+
if args.spin_test:
|
|
247
|
+
logging.info(
|
|
248
|
+
"🚀 Spin-test mode detected - setting up standalone Redis and running INFO SERVER"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Parse inventory to get server details
|
|
252
|
+
if args.inventory is None:
|
|
253
|
+
logging.error(
|
|
254
|
+
"❌ --spin-test requires --inventory to specify the remote server"
|
|
255
|
+
)
|
|
256
|
+
exit(1)
|
|
257
|
+
|
|
258
|
+
# Parse inventory string
|
|
259
|
+
inventory_parts = args.inventory.split(",")
|
|
260
|
+
server_public_ip = None
|
|
261
|
+
|
|
262
|
+
for part in inventory_parts:
|
|
263
|
+
if "=" in part:
|
|
264
|
+
key, value = part.split("=", 1)
|
|
265
|
+
if key.strip() == "server_public_ip":
|
|
266
|
+
server_public_ip = value.strip()
|
|
267
|
+
break
|
|
268
|
+
|
|
269
|
+
if server_public_ip is None:
|
|
270
|
+
logging.error("❌ --spin-test requires server_public_ip in --inventory")
|
|
271
|
+
exit(1)
|
|
272
|
+
|
|
273
|
+
# Load benchmark config if provided
|
|
274
|
+
benchmark_config = None
|
|
275
|
+
if args.spin_test_config:
|
|
276
|
+
try:
|
|
277
|
+
import yaml
|
|
278
|
+
with open(args.spin_test_config, 'r') as config_file:
|
|
279
|
+
benchmark_config = yaml.safe_load(config_file)
|
|
280
|
+
logging.info(f"📋 Loaded benchmark config from {args.spin_test_config}")
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logging.error(f"❌ Failed to load benchmark config: {e}")
|
|
283
|
+
exit(1)
|
|
284
|
+
|
|
285
|
+
# Run spin test
|
|
286
|
+
success = spin_test_standalone_redis(
|
|
287
|
+
server_public_ip=server_public_ip,
|
|
288
|
+
username=args.user,
|
|
289
|
+
private_key=private_key,
|
|
290
|
+
db_ssh_port=args.db_ssh_port,
|
|
291
|
+
redis_port=args.db_port,
|
|
292
|
+
local_module_files=local_module_files,
|
|
293
|
+
redis_configuration_parameters=None,
|
|
294
|
+
modules_configuration_parameters_map=None,
|
|
295
|
+
custom_redis_conf_path=args.redis_conf,
|
|
296
|
+
custom_redis_server_path=args.redis_server_binary,
|
|
297
|
+
benchmark_config=benchmark_config,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
exit(0 if success else 1)
|
|
301
|
+
|
|
241
302
|
(
|
|
242
303
|
benchmark_defs_result,
|
|
243
304
|
benchmark_definitions,
|
|
@@ -13,6 +13,7 @@ from redisbench_admin.utils.remote import (
|
|
|
13
13
|
)
|
|
14
14
|
from redisbench_admin.utils.ssh import SSHSession
|
|
15
15
|
from redisbench_admin.utils.utils import redis_server_config_module_part
|
|
16
|
+
import tempfile
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def ensure_redis_server_available(server_public_ip, username, private_key, port=22):
|
|
@@ -148,6 +149,123 @@ def ensure_memtier_benchmark_available(
|
|
|
148
149
|
logging.error("Failed to check memtier_benchmark availability")
|
|
149
150
|
|
|
150
151
|
|
|
152
|
+
def validate_remote_host_compatibility(
|
|
153
|
+
server_public_ip, username, private_key, custom_redis_server_path=None, port=22
|
|
154
|
+
):
|
|
155
|
+
"""
|
|
156
|
+
Validate remote host compatibility by checking OS version, stdlib version,
|
|
157
|
+
and optionally testing a custom redis-server binary.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
server_public_ip: IP address of the remote server
|
|
161
|
+
username: SSH username
|
|
162
|
+
private_key: Path to SSH private key
|
|
163
|
+
custom_redis_server_path: Optional path to custom redis-server binary on remote host
|
|
164
|
+
port: SSH port (default 22)
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
tuple: (success: bool, validation_info: dict)
|
|
168
|
+
"""
|
|
169
|
+
logging.info("Validating remote host compatibility...")
|
|
170
|
+
|
|
171
|
+
validation_info = {}
|
|
172
|
+
success = True
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
# Check OS version
|
|
176
|
+
os_commands = [
|
|
177
|
+
"uname -a", # System information
|
|
178
|
+
"cat /etc/os-release", # OS release info
|
|
179
|
+
"ldd --version", # glibc version
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
os_results = execute_remote_commands(
|
|
183
|
+
server_public_ip, username, private_key, os_commands, port
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Process OS information
|
|
187
|
+
for i, (recv_exit_status, stdout, stderr) in enumerate(os_results):
|
|
188
|
+
if recv_exit_status == 0:
|
|
189
|
+
if i == 0: # uname -a
|
|
190
|
+
validation_info["system_info"] = "".join(stdout).strip()
|
|
191
|
+
logging.info(f"System info: {validation_info['system_info']}")
|
|
192
|
+
elif i == 1: # /etc/os-release
|
|
193
|
+
os_release = "".join(stdout).strip()
|
|
194
|
+
validation_info["os_release"] = os_release
|
|
195
|
+
logging.info(f"OS release info: {os_release}")
|
|
196
|
+
elif i == 2: # ldd --version (glibc)
|
|
197
|
+
glibc_info = "".join(stdout).strip()
|
|
198
|
+
validation_info["glibc_version"] = glibc_info
|
|
199
|
+
logging.info(f"glibc version: {glibc_info}")
|
|
200
|
+
else:
|
|
201
|
+
logging.warning(
|
|
202
|
+
f"Command {os_commands[i]} failed with exit code {recv_exit_status}"
|
|
203
|
+
)
|
|
204
|
+
if i == 2: # glibc check failed, try alternative
|
|
205
|
+
alt_result = execute_remote_commands(
|
|
206
|
+
server_public_ip,
|
|
207
|
+
username,
|
|
208
|
+
private_key,
|
|
209
|
+
["getconf GNU_LIBC_VERSION"],
|
|
210
|
+
port,
|
|
211
|
+
)
|
|
212
|
+
if alt_result and alt_result[0][0] == 0:
|
|
213
|
+
glibc_alt = "".join(alt_result[0][1]).strip()
|
|
214
|
+
validation_info["glibc_version"] = glibc_alt
|
|
215
|
+
logging.info(f"glibc version (alternative): {glibc_alt}")
|
|
216
|
+
|
|
217
|
+
# Test custom redis-server binary if provided
|
|
218
|
+
if custom_redis_server_path:
|
|
219
|
+
logging.info(
|
|
220
|
+
f"Testing custom redis-server binary: {custom_redis_server_path}"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Check if the binary exists and is executable
|
|
224
|
+
check_commands = [
|
|
225
|
+
f"test -f {custom_redis_server_path}",
|
|
226
|
+
f"test -x {custom_redis_server_path}",
|
|
227
|
+
f"{custom_redis_server_path} --version",
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
check_results = execute_remote_commands(
|
|
231
|
+
server_public_ip, username, private_key, check_commands, port
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
for i, (recv_exit_status, stdout, stderr) in enumerate(check_results):
|
|
235
|
+
if recv_exit_status != 0:
|
|
236
|
+
if i == 0:
|
|
237
|
+
logging.error(
|
|
238
|
+
f"Custom redis-server binary not found: {custom_redis_server_path}"
|
|
239
|
+
)
|
|
240
|
+
success = False
|
|
241
|
+
elif i == 1:
|
|
242
|
+
logging.error(
|
|
243
|
+
f"Custom redis-server binary not executable: {custom_redis_server_path}"
|
|
244
|
+
)
|
|
245
|
+
success = False
|
|
246
|
+
elif i == 2:
|
|
247
|
+
logging.error(
|
|
248
|
+
f"Custom redis-server binary --version failed: {stderr}"
|
|
249
|
+
)
|
|
250
|
+
success = False
|
|
251
|
+
break
|
|
252
|
+
elif i == 2: # --version succeeded
|
|
253
|
+
version_output = "".join(stdout).strip()
|
|
254
|
+
validation_info["custom_redis_version"] = version_output
|
|
255
|
+
logging.info(f"Custom redis-server version: {version_output}")
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
logging.error(f"Remote host validation failed with exception: {e}")
|
|
259
|
+
success = False
|
|
260
|
+
|
|
261
|
+
if success:
|
|
262
|
+
logging.info("✅ Remote host validation passed")
|
|
263
|
+
else:
|
|
264
|
+
logging.error("❌ Remote host validation failed")
|
|
265
|
+
|
|
266
|
+
return success, validation_info
|
|
267
|
+
|
|
268
|
+
|
|
151
269
|
def spin_up_standalone_remote_redis(
|
|
152
270
|
temporary_dir,
|
|
153
271
|
server_public_ip,
|
|
@@ -290,10 +408,24 @@ def generate_remote_standalone_redis_cmd(
|
|
|
290
408
|
modules_configuration_parameters_map,
|
|
291
409
|
enable_redis_7_config_directives=True,
|
|
292
410
|
enable_debug_command="yes",
|
|
411
|
+
custom_redis_server_path=None,
|
|
412
|
+
custom_redis_conf_path=None,
|
|
293
413
|
):
|
|
294
|
-
|
|
295
|
-
|
|
414
|
+
# Use custom redis-server binary if provided, otherwise use default
|
|
415
|
+
redis_server_binary = (
|
|
416
|
+
custom_redis_server_path if custom_redis_server_path else "redis-server"
|
|
296
417
|
)
|
|
418
|
+
|
|
419
|
+
# If custom config file is provided, use it; otherwise use command line parameters
|
|
420
|
+
if custom_redis_conf_path:
|
|
421
|
+
initial_redis_cmd = "{} {} --daemonize yes".format(
|
|
422
|
+
redis_server_binary, custom_redis_conf_path
|
|
423
|
+
)
|
|
424
|
+
logging.info(f"Using custom redis.conf: {custom_redis_conf_path}")
|
|
425
|
+
else:
|
|
426
|
+
initial_redis_cmd = "{} --save '' --logfile {} --dir {} --daemonize yes --protected-mode no ".format(
|
|
427
|
+
redis_server_binary, logfile, temporary_dir
|
|
428
|
+
)
|
|
297
429
|
if enable_redis_7_config_directives:
|
|
298
430
|
extra_str = " --enable-debug-command {} ".format(enable_debug_command)
|
|
299
431
|
initial_redis_cmd = initial_redis_cmd + extra_str
|
|
@@ -323,3 +455,373 @@ def generate_remote_standalone_redis_cmd(
|
|
|
323
455
|
if remote_module_files is not None:
|
|
324
456
|
initial_redis_cmd += " " + " ".join(command)
|
|
325
457
|
return full_logfile, initial_redis_cmd
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def execute_install_steps(benchmark_config, server_public_ip, username, private_key, db_ssh_port):
|
|
461
|
+
"""
|
|
462
|
+
Execute install_steps from dbconfig and clientconfig sections.
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
benchmark_config: The benchmark configuration dictionary
|
|
466
|
+
server_public_ip: IP address of the remote server
|
|
467
|
+
username: SSH username
|
|
468
|
+
private_key: Path to SSH private key
|
|
469
|
+
db_ssh_port: SSH port
|
|
470
|
+
"""
|
|
471
|
+
install_commands = []
|
|
472
|
+
|
|
473
|
+
# Extract install_steps from dbconfig
|
|
474
|
+
if "dbconfig" in benchmark_config:
|
|
475
|
+
dbconfig = benchmark_config["dbconfig"]
|
|
476
|
+
if isinstance(dbconfig, list):
|
|
477
|
+
for config_item in dbconfig:
|
|
478
|
+
if "install_steps" in config_item:
|
|
479
|
+
steps = config_item["install_steps"]
|
|
480
|
+
if isinstance(steps, list):
|
|
481
|
+
install_commands.extend(steps)
|
|
482
|
+
logging.info(f"📦 Found {len(steps)} install steps in dbconfig")
|
|
483
|
+
elif isinstance(dbconfig, dict):
|
|
484
|
+
if "install_steps" in dbconfig:
|
|
485
|
+
steps = dbconfig["install_steps"]
|
|
486
|
+
if isinstance(steps, list):
|
|
487
|
+
install_commands.extend(steps)
|
|
488
|
+
logging.info(f"📦 Found {len(steps)} install steps in dbconfig")
|
|
489
|
+
|
|
490
|
+
# Extract install_steps from clientconfig
|
|
491
|
+
if "clientconfig" in benchmark_config:
|
|
492
|
+
clientconfig = benchmark_config["clientconfig"]
|
|
493
|
+
if isinstance(clientconfig, list):
|
|
494
|
+
for config_item in clientconfig:
|
|
495
|
+
if "install_steps" in config_item:
|
|
496
|
+
steps = config_item["install_steps"]
|
|
497
|
+
if isinstance(steps, list):
|
|
498
|
+
install_commands.extend(steps)
|
|
499
|
+
logging.info(f"📦 Found {len(steps)} install steps in clientconfig")
|
|
500
|
+
elif isinstance(clientconfig, dict):
|
|
501
|
+
if "install_steps" in clientconfig:
|
|
502
|
+
steps = clientconfig["install_steps"]
|
|
503
|
+
if isinstance(steps, list):
|
|
504
|
+
install_commands.extend(steps)
|
|
505
|
+
logging.info(f"📦 Found {len(steps)} install steps in clientconfig")
|
|
506
|
+
|
|
507
|
+
# Execute all install commands
|
|
508
|
+
if install_commands:
|
|
509
|
+
logging.info(f"🔧 Executing {len(install_commands)} installation commands...")
|
|
510
|
+
for i, command in enumerate(install_commands, 1):
|
|
511
|
+
logging.info(f"📋 Step {i}/{len(install_commands)}: {command}")
|
|
512
|
+
|
|
513
|
+
install_result = execute_remote_commands(
|
|
514
|
+
server_public_ip, username, private_key, install_commands, db_ssh_port
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
# Check results
|
|
518
|
+
for i, (recv_exit_status, stdout, stderr) in enumerate(install_result):
|
|
519
|
+
if recv_exit_status != 0:
|
|
520
|
+
logging.warning(
|
|
521
|
+
f"⚠️ Install step {i+1} returned exit code {recv_exit_status}"
|
|
522
|
+
)
|
|
523
|
+
logging.warning(f"Command: {install_commands[i]}")
|
|
524
|
+
if stderr:
|
|
525
|
+
logging.warning(f"STDERR: {''.join(stderr).strip()}")
|
|
526
|
+
if stdout:
|
|
527
|
+
logging.warning(f"STDOUT: {''.join(stdout).strip()}")
|
|
528
|
+
else:
|
|
529
|
+
logging.info(f"✅ Install step {i+1} completed successfully")
|
|
530
|
+
|
|
531
|
+
logging.info("🎯 All installation steps completed")
|
|
532
|
+
else:
|
|
533
|
+
logging.info("📦 No install_steps found in configuration")
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def spin_test_standalone_redis(
|
|
537
|
+
server_public_ip,
|
|
538
|
+
username,
|
|
539
|
+
private_key,
|
|
540
|
+
db_ssh_port=22,
|
|
541
|
+
redis_port=6379,
|
|
542
|
+
local_module_files=None,
|
|
543
|
+
redis_configuration_parameters=None,
|
|
544
|
+
modules_configuration_parameters_map=None,
|
|
545
|
+
custom_redis_conf_path=None,
|
|
546
|
+
custom_redis_server_path=None,
|
|
547
|
+
benchmark_config=None,
|
|
548
|
+
):
|
|
549
|
+
"""
|
|
550
|
+
Setup standalone Redis server, run INFO SERVER, print output as markdown and exit.
|
|
551
|
+
|
|
552
|
+
Args:
|
|
553
|
+
server_public_ip: IP address of the remote server
|
|
554
|
+
username: SSH username
|
|
555
|
+
private_key: Path to SSH private key
|
|
556
|
+
db_ssh_port: SSH port (default 22)
|
|
557
|
+
redis_port: Redis port (default 6379)
|
|
558
|
+
local_module_files: List of local module files to copy
|
|
559
|
+
redis_configuration_parameters: Dict of Redis configuration parameters
|
|
560
|
+
modules_configuration_parameters_map: Dict of module configuration parameters
|
|
561
|
+
custom_redis_conf_path: Path to custom redis.conf file
|
|
562
|
+
custom_redis_server_path: Path to custom redis-server binary
|
|
563
|
+
"""
|
|
564
|
+
logging.info("🚀 Starting spin-test mode...")
|
|
565
|
+
|
|
566
|
+
try:
|
|
567
|
+
# Create temporary directory on remote host
|
|
568
|
+
temporary_dir = "/tmp/redisbench-spin-test"
|
|
569
|
+
create_dir_commands = [f"mkdir -p {temporary_dir}"]
|
|
570
|
+
execute_remote_commands(
|
|
571
|
+
server_public_ip, username, private_key, create_dir_commands, db_ssh_port
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
# Execute install_steps from dbconfig and clientconfig if present
|
|
575
|
+
if benchmark_config is not None:
|
|
576
|
+
execute_install_steps(
|
|
577
|
+
benchmark_config, server_public_ip, username, private_key, db_ssh_port
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
# Ensure Redis server is available (only if not using custom binary)
|
|
581
|
+
if custom_redis_server_path is None:
|
|
582
|
+
ensure_redis_server_available(
|
|
583
|
+
server_public_ip, username, private_key, db_ssh_port
|
|
584
|
+
)
|
|
585
|
+
else:
|
|
586
|
+
logging.info(
|
|
587
|
+
"🔧 Using custom Redis binary - skipping system Redis installation"
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
# Copy custom Redis files if provided
|
|
591
|
+
remote_redis_conf_path = None
|
|
592
|
+
remote_redis_server_path = None
|
|
593
|
+
|
|
594
|
+
if custom_redis_conf_path:
|
|
595
|
+
if not os.path.exists(custom_redis_conf_path):
|
|
596
|
+
logging.error(
|
|
597
|
+
f"❌ Custom redis.conf file not found: {custom_redis_conf_path}"
|
|
598
|
+
)
|
|
599
|
+
return False
|
|
600
|
+
|
|
601
|
+
remote_redis_conf_path = f"{temporary_dir}/redis.conf"
|
|
602
|
+
logging.info(f"📁 Copying custom redis.conf to remote host...")
|
|
603
|
+
|
|
604
|
+
copy_result = copy_file_to_remote_setup(
|
|
605
|
+
server_public_ip,
|
|
606
|
+
username,
|
|
607
|
+
private_key,
|
|
608
|
+
custom_redis_conf_path,
|
|
609
|
+
remote_redis_conf_path,
|
|
610
|
+
None,
|
|
611
|
+
db_ssh_port,
|
|
612
|
+
False, # don't continue on error
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
if not copy_result:
|
|
616
|
+
logging.error("❌ Failed to copy redis.conf to remote host")
|
|
617
|
+
return False
|
|
618
|
+
|
|
619
|
+
if custom_redis_server_path:
|
|
620
|
+
if not os.path.exists(custom_redis_server_path):
|
|
621
|
+
logging.error(
|
|
622
|
+
f"❌ Custom redis-server binary not found: {custom_redis_server_path}"
|
|
623
|
+
)
|
|
624
|
+
return False
|
|
625
|
+
|
|
626
|
+
remote_redis_server_path = f"{temporary_dir}/redis-server"
|
|
627
|
+
logging.info(f"📁 Copying custom redis-server binary to remote host...")
|
|
628
|
+
|
|
629
|
+
copy_result = copy_file_to_remote_setup(
|
|
630
|
+
server_public_ip,
|
|
631
|
+
username,
|
|
632
|
+
private_key,
|
|
633
|
+
custom_redis_server_path,
|
|
634
|
+
remote_redis_server_path,
|
|
635
|
+
None,
|
|
636
|
+
db_ssh_port,
|
|
637
|
+
False, # don't continue on error
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
if not copy_result:
|
|
641
|
+
logging.error("❌ Failed to copy redis-server binary to remote host")
|
|
642
|
+
return False
|
|
643
|
+
|
|
644
|
+
# Make the binary executable
|
|
645
|
+
chmod_commands = [f"chmod +x {remote_redis_server_path}"]
|
|
646
|
+
chmod_results = execute_remote_commands(
|
|
647
|
+
server_public_ip, username, private_key, chmod_commands, db_ssh_port
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
recv_exit_status, stdout, stderr = chmod_results[0]
|
|
651
|
+
if recv_exit_status != 0:
|
|
652
|
+
logging.warning(
|
|
653
|
+
f"⚠️ Failed to make redis-server binary executable: {stderr}"
|
|
654
|
+
)
|
|
655
|
+
else:
|
|
656
|
+
logging.info("✅ Redis-server binary made executable")
|
|
657
|
+
|
|
658
|
+
# Copy modules if provided
|
|
659
|
+
remote_module_files = None
|
|
660
|
+
if local_module_files:
|
|
661
|
+
remote_module_file_dir = f"{temporary_dir}/modules"
|
|
662
|
+
create_module_dir_commands = [f"mkdir -p {remote_module_file_dir}"]
|
|
663
|
+
execute_remote_commands(
|
|
664
|
+
server_public_ip,
|
|
665
|
+
username,
|
|
666
|
+
private_key,
|
|
667
|
+
create_module_dir_commands,
|
|
668
|
+
db_ssh_port,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
remote_module_files = remote_module_files_cp(
|
|
672
|
+
local_module_files,
|
|
673
|
+
db_ssh_port,
|
|
674
|
+
private_key,
|
|
675
|
+
remote_module_file_dir,
|
|
676
|
+
server_public_ip,
|
|
677
|
+
username,
|
|
678
|
+
continue_on_module_check_error=True,
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
# Generate Redis startup command
|
|
682
|
+
logfile = "redis-spin-test.log"
|
|
683
|
+
_, redis_cmd = generate_remote_standalone_redis_cmd(
|
|
684
|
+
logfile,
|
|
685
|
+
redis_configuration_parameters,
|
|
686
|
+
remote_module_files,
|
|
687
|
+
temporary_dir,
|
|
688
|
+
modules_configuration_parameters_map or {},
|
|
689
|
+
enable_redis_7_config_directives=True,
|
|
690
|
+
enable_debug_command="yes",
|
|
691
|
+
custom_redis_server_path=remote_redis_server_path,
|
|
692
|
+
custom_redis_conf_path=remote_redis_conf_path,
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
# Override port if specified
|
|
696
|
+
if redis_port != 6379:
|
|
697
|
+
redis_cmd += f" --port {redis_port}"
|
|
698
|
+
|
|
699
|
+
logging.info(f"🔧 Starting Redis with command: {redis_cmd}")
|
|
700
|
+
|
|
701
|
+
# Start Redis server
|
|
702
|
+
start_commands = [redis_cmd]
|
|
703
|
+
start_result = execute_remote_commands(
|
|
704
|
+
server_public_ip, username, private_key, start_commands, db_ssh_port
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
# Check if Redis started successfully
|
|
708
|
+
recv_exit_status, stdout, stderr = start_result[0]
|
|
709
|
+
if recv_exit_status != 0:
|
|
710
|
+
logging.error(
|
|
711
|
+
f"❌ Failed to start Redis server. Exit code: {recv_exit_status}"
|
|
712
|
+
)
|
|
713
|
+
logging.error(f"STDOUT: {stdout}")
|
|
714
|
+
logging.error(f"STDERR: {stderr}")
|
|
715
|
+
return False
|
|
716
|
+
|
|
717
|
+
# Wait a moment for Redis to fully start
|
|
718
|
+
import time
|
|
719
|
+
|
|
720
|
+
time.sleep(2)
|
|
721
|
+
|
|
722
|
+
# Collect system information
|
|
723
|
+
logging.info("📊 Collecting system information...")
|
|
724
|
+
system_commands = [
|
|
725
|
+
"uname -a", # System information
|
|
726
|
+
"cat /etc/os-release", # OS release info
|
|
727
|
+
"ldd --version 2>/dev/null || getconf GNU_LIBC_VERSION 2>/dev/null || echo 'glibc version not available'", # glibc version
|
|
728
|
+
"cat /proc/version", # Kernel version
|
|
729
|
+
"cat /proc/cpuinfo | grep 'model name' | head -1", # CPU info
|
|
730
|
+
"free -h", # Memory info
|
|
731
|
+
"df -h /", # Disk space
|
|
732
|
+
]
|
|
733
|
+
|
|
734
|
+
system_results = execute_remote_commands(
|
|
735
|
+
server_public_ip, username, private_key, system_commands, db_ssh_port
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
# Run INFO SERVER command
|
|
739
|
+
info_commands = [f"redis-cli -p {redis_port} INFO SERVER"]
|
|
740
|
+
info_result = execute_remote_commands(
|
|
741
|
+
server_public_ip, username, private_key, info_commands, db_ssh_port
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
recv_exit_status, stdout, stderr = info_result[0]
|
|
745
|
+
if recv_exit_status != 0:
|
|
746
|
+
logging.error(
|
|
747
|
+
f"❌ Failed to run INFO SERVER. Exit code: {recv_exit_status}"
|
|
748
|
+
)
|
|
749
|
+
logging.error(f"STDOUT: {stdout}")
|
|
750
|
+
logging.error(f"STDERR: {stderr}")
|
|
751
|
+
return False
|
|
752
|
+
|
|
753
|
+
# Format output as markdown
|
|
754
|
+
info_output = "".join(stdout).strip()
|
|
755
|
+
|
|
756
|
+
print("\n" + "=" * 80)
|
|
757
|
+
print("🎯 REDIS SPIN-TEST RESULTS")
|
|
758
|
+
print("=" * 80)
|
|
759
|
+
print()
|
|
760
|
+
|
|
761
|
+
# Display system information
|
|
762
|
+
print("## 🖥️ System Information")
|
|
763
|
+
print()
|
|
764
|
+
|
|
765
|
+
system_labels = [
|
|
766
|
+
"System Info",
|
|
767
|
+
"OS Release",
|
|
768
|
+
"glibc Version",
|
|
769
|
+
"Kernel Version",
|
|
770
|
+
"CPU Model",
|
|
771
|
+
"Memory",
|
|
772
|
+
"Disk Space",
|
|
773
|
+
]
|
|
774
|
+
|
|
775
|
+
for label, (recv_exit_status, stdout, stderr) in zip(
|
|
776
|
+
system_labels, system_results
|
|
777
|
+
):
|
|
778
|
+
if recv_exit_status == 0 and stdout:
|
|
779
|
+
output = "".join(stdout).strip()
|
|
780
|
+
if output:
|
|
781
|
+
print(f"**{label}:**")
|
|
782
|
+
print("```")
|
|
783
|
+
print(output)
|
|
784
|
+
print("```")
|
|
785
|
+
print()
|
|
786
|
+
else:
|
|
787
|
+
print(f"**{label}:** ⚠️ Not available")
|
|
788
|
+
print()
|
|
789
|
+
|
|
790
|
+
# Display Redis information
|
|
791
|
+
print("## 🔴 Redis Server Information")
|
|
792
|
+
print()
|
|
793
|
+
print("```")
|
|
794
|
+
print(info_output)
|
|
795
|
+
print("```")
|
|
796
|
+
print()
|
|
797
|
+
print("✅ Spin-test completed successfully!")
|
|
798
|
+
print("=" * 80)
|
|
799
|
+
|
|
800
|
+
# Cleanup: Stop Redis server
|
|
801
|
+
cleanup_commands = [
|
|
802
|
+
f"redis-cli -p {redis_port} shutdown nosave",
|
|
803
|
+
f"rm -rf {temporary_dir}",
|
|
804
|
+
]
|
|
805
|
+
execute_remote_commands(
|
|
806
|
+
server_public_ip, username, private_key, cleanup_commands, db_ssh_port
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
logging.info("🧹 Cleanup completed")
|
|
810
|
+
return True
|
|
811
|
+
|
|
812
|
+
except Exception as e:
|
|
813
|
+
logging.error(f"❌ Spin-test failed with error: {e}")
|
|
814
|
+
|
|
815
|
+
# Attempt cleanup on error
|
|
816
|
+
try:
|
|
817
|
+
cleanup_commands = [
|
|
818
|
+
f"redis-cli -p {redis_port} shutdown nosave",
|
|
819
|
+
f"rm -rf {temporary_dir}",
|
|
820
|
+
]
|
|
821
|
+
execute_remote_commands(
|
|
822
|
+
server_public_ip, username, private_key, cleanup_commands, db_ssh_port
|
|
823
|
+
)
|
|
824
|
+
except:
|
|
825
|
+
pass # Ignore cleanup errors
|
|
826
|
+
|
|
827
|
+
return False
|
redisbench_admin/utils/remote.py
CHANGED
|
@@ -629,6 +629,15 @@ def push_data_to_redistimeseries(rts, time_series_dict: dict, expire_msecs=0):
|
|
|
629
629
|
)
|
|
630
630
|
for timeseries_name, time_series in time_series_dict.items():
|
|
631
631
|
try:
|
|
632
|
+
arch = "x86_64"
|
|
633
|
+
if "arch" in time_series["labels"]:
|
|
634
|
+
arch = time_series["labels"]["arch"]
|
|
635
|
+
if arch == "aarch64" and "aarch64" not in timeseries_name:
|
|
636
|
+
original_timeseries_name = timeseries_name
|
|
637
|
+
timeseries_name = f"{timeseries_name}/arch/{arch}"
|
|
638
|
+
logging.warning(
|
|
639
|
+
f"overriding key named {original_timeseries_name} given it does not contain arch and it's not x86_64. new key={timeseries_name}"
|
|
640
|
+
)
|
|
632
641
|
exporter_create_ts(rts, time_series, timeseries_name)
|
|
633
642
|
for timestamp, value in time_series["data"].items():
|
|
634
643
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: redisbench-admin
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.42
|
|
4
4
|
Summary: Redis benchmark run helper. A wrapper around Redis and Redis Modules benchmark tools ( ftsb_redisearch, memtier_benchmark, redis-benchmark, aibench, etc... ).
|
|
5
5
|
Author: filipecosta90
|
|
6
6
|
Author-email: filipecosta.90@gmail.com
|
|
@@ -3,8 +3,8 @@ redisbench_admin/cli.py,sha256=LAS5qnqScXKhxHYfXWB0mvAYaUYrSurIwadhexEa9g4,7740
|
|
|
3
3
|
redisbench_admin/commands/__init__.py,sha256=mzVrEtqefFdopyzR-W6xx3How95dyZfToGKm1-_YzeY,95
|
|
4
4
|
redisbench_admin/commands/commands.json.py,sha256=mzVrEtqefFdopyzR-W6xx3How95dyZfToGKm1-_YzeY,95
|
|
5
5
|
redisbench_admin/compare/__init__.py,sha256=DtBXRp0Q01XgCFmY-1OIePMyyYihVNAjZ1Y8zwqSDN0,101
|
|
6
|
-
redisbench_admin/compare/args.py,sha256=
|
|
7
|
-
redisbench_admin/compare/compare.py,sha256=
|
|
6
|
+
redisbench_admin/compare/args.py,sha256=rOP8td_GYPYsZiYN4olyYmUsku-oizggEZNRTB_fVro,6336
|
|
7
|
+
redisbench_admin/compare/compare.py,sha256=NvC7RbQUJUKlPdJQj9TjUmk2k8UtiA9wnZWNDV7IM_Q,103315
|
|
8
8
|
redisbench_admin/deploy/__init__.py,sha256=DtBXRp0Q01XgCFmY-1OIePMyyYihVNAjZ1Y8zwqSDN0,101
|
|
9
9
|
redisbench_admin/deploy/args.py,sha256=neLUcQqI__HkJItkQg2C293hl5g3yHG40t171r7-E5Y,1732
|
|
10
10
|
redisbench_admin/deploy/deploy.py,sha256=MtfJbsL97DLrbBYut6zRCzyEMebX4xWoZE-m4-JDRB8,3885
|
|
@@ -211,7 +211,7 @@ redisbench_admin/run_local/local_db.py,sha256=9vINqKOs-wDMFEuEHT0I8KO9YnEo_h4NWN
|
|
|
211
211
|
redisbench_admin/run_local/local_helpers.py,sha256=JyqLW2-Sbm35BXjxxfOB1yK7ADdLfcVrq08NLNdIwac,7026
|
|
212
212
|
redisbench_admin/run_local/run_local.py,sha256=QHnGfVAaVuct7t0WrWyQpbirC3MWX7fQF5-kXU_pJBs,34834
|
|
213
213
|
redisbench_admin/run_remote/__init__.py,sha256=DtBXRp0Q01XgCFmY-1OIePMyyYihVNAjZ1Y8zwqSDN0,101
|
|
214
|
-
redisbench_admin/run_remote/args.py,sha256=
|
|
214
|
+
redisbench_admin/run_remote/args.py,sha256=gJux_1udR6d5BUMMnIewl62hS0b2WnQ_7WQF4hElX7c,5051
|
|
215
215
|
redisbench_admin/run_remote/consts.py,sha256=bCMkwyeBD-EmOpoHKni7LjWy5WuaxGJhGhqpi4AL0RQ,386
|
|
216
216
|
redisbench_admin/run_remote/log.py,sha256=cD7zfXt0VEmy0b7452HvcAxX_9kVj6Vm213yNdUHP20,95
|
|
217
217
|
redisbench_admin/run_remote/notifications.py,sha256=-W9fLaftEFNfplBl2clHk37jbYxliDbHftQ62khN31k,2157
|
|
@@ -220,23 +220,23 @@ redisbench_admin/run_remote/remote_db.py,sha256=EEDeiOZk-godr5EINscEkOJLGWUN3gFf
|
|
|
220
220
|
redisbench_admin/run_remote/remote_env.py,sha256=Ux_0QT1unNRlKl3cakzjG5Px1uuxOOfBoF_pnalx_T8,4936
|
|
221
221
|
redisbench_admin/run_remote/remote_failures.py,sha256=IOo6DyxarcwwMPCeN4gWB2JrhuC9iBLwq0nCROqr5ak,1567
|
|
222
222
|
redisbench_admin/run_remote/remote_helpers.py,sha256=skWeGyDJBmyx_UwUekT3N3_nOJvF2-Hvu-E7vKlO9gg,10598
|
|
223
|
-
redisbench_admin/run_remote/run_remote.py,sha256=
|
|
224
|
-
redisbench_admin/run_remote/standalone.py,sha256=
|
|
223
|
+
redisbench_admin/run_remote/run_remote.py,sha256=7B-x-AI1pVon8ccfRio8q6EXTXaqPPMj_PxytpiICUs,76045
|
|
224
|
+
redisbench_admin/run_remote/standalone.py,sha256=Or2GaSccxEyIl0z833RWi-fylSQ71Z6E1R2vbN0rHMM,31593
|
|
225
225
|
redisbench_admin/run_remote/terraform.py,sha256=vV3eWXNwj7vsnFNqUgCir5ueZS4VYopEyzWiTtoSq0Q,4018
|
|
226
226
|
redisbench_admin/utils/__init__.py,sha256=DtBXRp0Q01XgCFmY-1OIePMyyYihVNAjZ1Y8zwqSDN0,101
|
|
227
227
|
redisbench_admin/utils/benchmark_config.py,sha256=bC2C6rnj89wkkSlOXyyfe0N15unn_M1t1zfskfVkb98,21387
|
|
228
228
|
redisbench_admin/utils/local.py,sha256=zUvyVI9LZMT3qyxs1pO3mXL6Bt_1z9EZUGppaRcWNRA,3890
|
|
229
229
|
redisbench_admin/utils/redisearch.py,sha256=lchUEzpt0zB1rHwlDlw9LLifAnxFWcLP-PePw7TjL-0,1602
|
|
230
230
|
redisbench_admin/utils/redisgraph_benchmark_go.py,sha256=os7EJt6kBxsFJLKkSoANbjMT7-cEq4-Ns-49alk2Tf8,2048
|
|
231
|
-
redisbench_admin/utils/remote.py,sha256=
|
|
231
|
+
redisbench_admin/utils/remote.py,sha256=RAQ2VxfmlK7swN7ujCuwSI2soGSycjnxbQw_IrLxIFE,42205
|
|
232
232
|
redisbench_admin/utils/results.py,sha256=uKk3uNJ--bSXlUj_HGQ2OaV6MVqmXJVM8xTzFV6EOw4,3267
|
|
233
233
|
redisbench_admin/utils/ssh.py,sha256=QW4AwlocMHJt05QMdN_4f8WeDmxiEwR80ny8VBThq6k,6533
|
|
234
234
|
redisbench_admin/utils/utils.py,sha256=XVSvo1_DdcYwk2jOxL3VPVPbnDnhGYt8ieYfANo6rTo,15085
|
|
235
235
|
redisbench_admin/watchdog/__init__.py,sha256=cD7zfXt0VEmy0b7452HvcAxX_9kVj6Vm213yNdUHP20,95
|
|
236
236
|
redisbench_admin/watchdog/args.py,sha256=nKsG1G6ATOZlAMHMtT9u3kXxduKCbejSZ5x8oB_ynZ8,1312
|
|
237
237
|
redisbench_admin/watchdog/watchdog.py,sha256=0wWYge3x_OMxWrzazNhJif2NK4tKsI963HVZqjczRag,6189
|
|
238
|
-
redisbench_admin-0.11.
|
|
239
|
-
redisbench_admin-0.11.
|
|
240
|
-
redisbench_admin-0.11.
|
|
241
|
-
redisbench_admin-0.11.
|
|
242
|
-
redisbench_admin-0.11.
|
|
238
|
+
redisbench_admin-0.11.42.dist-info/LICENSE,sha256=AAMtfs82zOOvmG68vILivm6lxi2rcOlGObmA8jzxQvw,10768
|
|
239
|
+
redisbench_admin-0.11.42.dist-info/METADATA,sha256=s_waYOA4L1z-YQOS-p7DPaW8QWK2zzr2rsMSEAIVD7Y,5596
|
|
240
|
+
redisbench_admin-0.11.42.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
241
|
+
redisbench_admin-0.11.42.dist-info/entry_points.txt,sha256=UUawXk_AS-PlieKJ1QxPQXGsRLb6OW_F0MtmA1W0KE8,113
|
|
242
|
+
redisbench_admin-0.11.42.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|