forked from TrueCloudLab/frostfs-testlib
[#137] Ability to control remote processes id and reports for load
Signed-off-by: Andrey Berezin <a.berezin@yadro.com>
This commit is contained in:
parent
e65fc359fe
commit
81dfc723da
5 changed files with 159 additions and 63 deletions
|
@ -34,7 +34,6 @@ class LoadResults:
|
|||
|
||||
class K6:
|
||||
_k6_process: RemoteProcess
|
||||
_start_time: datetime
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -61,6 +60,18 @@ class K6:
|
|||
|
||||
self._k6_dir: str = k6_dir
|
||||
|
||||
command = (
|
||||
f"{self._k6_dir}/k6 run {self._generate_env_variables()} "
|
||||
f"{self._k6_dir}/scenarios/{self.load_params.scenario.value}.js"
|
||||
)
|
||||
user = STORAGE_USER_NAME if self.load_params.scenario == LoadScenario.LOCAL else None
|
||||
process_id = (
|
||||
self.load_params.load_id
|
||||
if self.load_params.scenario != LoadScenario.VERIFY
|
||||
else f"{self.load_params.load_id}_verify"
|
||||
)
|
||||
self._k6_process = RemoteProcess.create(command, self.shell, self.load_params.working_dir, user, process_id)
|
||||
|
||||
@property
|
||||
def process_dir(self) -> str:
|
||||
return self._k6_process.process_dir
|
||||
|
@ -111,15 +122,15 @@ class K6:
|
|||
reporter.attach("\n".join(f"{param}: {value}" for param, value in env_vars.items()), "K6 ENV variables")
|
||||
return " ".join([f"-e {param}='{value}'" for param, value in env_vars.items() if value is not None])
|
||||
|
||||
def get_start_time(self) -> datetime:
|
||||
return datetime.fromtimestamp(self._k6_process.start_time())
|
||||
|
||||
def get_end_time(self) -> datetime:
|
||||
return datetime.fromtimestamp(self._k6_process.end_time())
|
||||
|
||||
def start(self) -> None:
|
||||
with reporter.step(f"Start load from loader {self.loader.ip} on endpoints {self.endpoints}"):
|
||||
self._start_time = int(datetime.utcnow().timestamp())
|
||||
command = (
|
||||
f"{self._k6_dir}/k6 run {self._generate_env_variables()} "
|
||||
f"{self._k6_dir}/scenarios/{self.load_params.scenario.value}.js"
|
||||
)
|
||||
user = STORAGE_USER_NAME if self.load_params.scenario == LoadScenario.LOCAL else None
|
||||
self._k6_process = RemoteProcess.create(command, self.shell, self.load_params.working_dir, user)
|
||||
self._k6_process.start()
|
||||
|
||||
def wait_until_finished(self, soft_timeout: int = 0) -> None:
|
||||
with reporter.step(f"Wait until load is finished from loader {self.loader.ip} on endpoints {self.endpoints}"):
|
||||
|
@ -128,8 +139,10 @@ class K6:
|
|||
else:
|
||||
timeout = self.load_params.load_time or 0
|
||||
|
||||
start_time = int(self.get_start_time().timestamp())
|
||||
|
||||
current_time = int(datetime.utcnow().timestamp())
|
||||
working_time = current_time - self._start_time
|
||||
working_time = current_time - start_time
|
||||
remaining_time = timeout - working_time
|
||||
|
||||
setup_teardown_time = (
|
||||
|
@ -146,7 +159,7 @@ class K6:
|
|||
original_timeout = timeout
|
||||
|
||||
timeouts = {
|
||||
"K6 start time": self._start_time,
|
||||
"K6 start time": start_time,
|
||||
"Current time": current_time,
|
||||
"K6 working time": working_time,
|
||||
"Remaining time for load": remaining_time,
|
||||
|
|
|
@ -17,11 +17,15 @@ class LoadReport:
|
|||
self.start_time: Optional[datetime] = None
|
||||
self.end_time: Optional[datetime] = None
|
||||
|
||||
def set_start_time(self):
|
||||
self.start_time = datetime.utcnow()
|
||||
def set_start_time(self, time: datetime = None):
|
||||
if time is None:
|
||||
time = datetime.utcnow()
|
||||
self.start_time = time
|
||||
|
||||
def set_end_time(self):
|
||||
self.end_time = datetime.utcnow()
|
||||
def set_end_time(self, time: datetime = None):
|
||||
if time is None:
|
||||
time = datetime.utcnow()
|
||||
self.end_time = time
|
||||
|
||||
def add_summaries(self, load_summaries: dict):
|
||||
self.load_summaries_list.append(load_summaries)
|
||||
|
@ -31,6 +35,7 @@ class LoadReport:
|
|||
|
||||
def get_report_html(self):
|
||||
report_sections = [
|
||||
[self.load_params, self._get_load_id_section_html],
|
||||
[self.load_test, self._get_load_params_section_html],
|
||||
[self.load_summaries_list, self._get_totals_section_html],
|
||||
[self.end_time, self._get_test_time_html],
|
||||
|
@ -44,9 +49,7 @@ class LoadReport:
|
|||
return html
|
||||
|
||||
def _get_load_params_section_html(self) -> str:
|
||||
params: str = yaml.safe_dump(
|
||||
[self.load_test], sort_keys=False, indent=2, explicit_start=True
|
||||
)
|
||||
params: str = yaml.safe_dump([self.load_test], sort_keys=False, indent=2, explicit_start=True)
|
||||
params = params.replace("\n", "<br>").replace(" ", " ")
|
||||
section_html = f"""<h3>Scenario params</h3>
|
||||
|
||||
|
@ -55,8 +58,17 @@ class LoadReport:
|
|||
|
||||
return section_html
|
||||
|
||||
def _get_load_id_section_html(self) -> str:
|
||||
section_html = f"""<h3>Load ID: {self.load_params.load_id}</h3>
|
||||
<hr>"""
|
||||
|
||||
return section_html
|
||||
|
||||
def _get_test_time_html(self) -> str:
|
||||
html = f"""<h3>Scenario duration in UTC time (from agent)</h3>
|
||||
if not self.start_time or not self.end_time:
|
||||
return ""
|
||||
|
||||
html = f"""<h3>Scenario duration</h3>
|
||||
{self.start_time} - {self.end_time}<br>
|
||||
<hr>
|
||||
"""
|
||||
|
@ -97,7 +109,7 @@ class LoadReport:
|
|||
LoadScenario.gRPC_CAR: "open model",
|
||||
LoadScenario.S3_CAR: "open model",
|
||||
LoadScenario.LOCAL: "local fill",
|
||||
LoadScenario.S3_LOCAL: "local fill"
|
||||
LoadScenario.S3_LOCAL: "local fill",
|
||||
}
|
||||
|
||||
return model_map[self.load_params.scenario]
|
||||
|
@ -124,10 +136,7 @@ class LoadReport:
|
|||
total_errors: int = 0
|
||||
for node_key, errors in errors.items():
|
||||
total_errors += errors
|
||||
if (
|
||||
self.load_params.k6_process_allocation_strategy
|
||||
== K6ProcessAllocationStrategy.PER_ENDPOINT
|
||||
):
|
||||
if self.load_params.k6_process_allocation_strategy == K6ProcessAllocationStrategy.PER_ENDPOINT:
|
||||
per_node_errors_html += self._row(f"At {node_key}", errors)
|
||||
|
||||
latency_html = ""
|
||||
|
@ -139,9 +148,7 @@ class LoadReport:
|
|||
for param_name, param_val in latency_dict.items():
|
||||
latency_values += f"{param_name}={param_val:.2f}ms "
|
||||
|
||||
latency_html += self._row(
|
||||
f"{operation_type} latency {node_key.split(':')[0]}", latency_values
|
||||
)
|
||||
latency_html += self._row(f"{operation_type} latency {node_key.split(':')[0]}", latency_values)
|
||||
|
||||
object_size, object_size_unit = calc_unit(self.load_params.object_size, 1)
|
||||
duration = self._seconds_to_formatted_duration(self.load_params.load_time)
|
||||
|
@ -180,9 +187,7 @@ class LoadReport:
|
|||
write_latency = {}
|
||||
write_errors = {}
|
||||
requested_write_rate = self.load_params.write_rate
|
||||
requested_write_rate_str = (
|
||||
f"{requested_write_rate}op/sec" if requested_write_rate else ""
|
||||
)
|
||||
requested_write_rate_str = f"{requested_write_rate}op/sec" if requested_write_rate else ""
|
||||
|
||||
read_operations = 0
|
||||
read_op_sec = 0
|
||||
|
@ -197,20 +202,12 @@ class LoadReport:
|
|||
delete_latency = {}
|
||||
delete_errors = {}
|
||||
requested_delete_rate = self.load_params.delete_rate
|
||||
requested_delete_rate_str = (
|
||||
f"{requested_delete_rate}op/sec" if requested_delete_rate else ""
|
||||
)
|
||||
requested_delete_rate_str = f"{requested_delete_rate}op/sec" if requested_delete_rate else ""
|
||||
|
||||
if self.load_params.scenario in [LoadScenario.gRPC_CAR, LoadScenario.S3_CAR]:
|
||||
delete_vus = max(
|
||||
self.load_params.preallocated_deleters or 0, self.load_params.max_deleters or 0
|
||||
)
|
||||
write_vus = max(
|
||||
self.load_params.preallocated_writers or 0, self.load_params.max_writers or 0
|
||||
)
|
||||
read_vus = max(
|
||||
self.load_params.preallocated_readers or 0, self.load_params.max_readers or 0
|
||||
)
|
||||
delete_vus = max(self.load_params.preallocated_deleters or 0, self.load_params.max_deleters or 0)
|
||||
write_vus = max(self.load_params.preallocated_writers or 0, self.load_params.max_writers or 0)
|
||||
read_vus = max(self.load_params.preallocated_readers or 0, self.load_params.max_readers or 0)
|
||||
else:
|
||||
write_vus = self.load_params.writers
|
||||
read_vus = self.load_params.readers
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue