Add prometheus load parameters #185

Merged
d.zayakin merged 1 commit from abereziny/frostfs-testlib:feature-add-export-settings-for-load into master 2024-02-26 06:57:11 +00:00
3 changed files with 67 additions and 13 deletions

View file

@ -61,7 +61,7 @@ class K6:
self._k6_dir: str = k6_dir self._k6_dir: str = k6_dir
command = ( command = (
f"{self._k6_dir}/k6 run {self._generate_env_variables()} " f"{self._generate_env_variables()}{self._k6_dir}/k6 run {self._generate_k6_variables()} "
f"{self._k6_dir}/scenarios/{self.load_params.scenario.value}.js" f"{self._k6_dir}/scenarios/{self.load_params.scenario.value}.js"
) )
user = STORAGE_USER_NAME if self.load_params.scenario == LoadScenario.LOCAL else None user = STORAGE_USER_NAME if self.load_params.scenario == LoadScenario.LOCAL else None
@ -75,12 +75,12 @@ class K6:
def _get_fill_percents(self): def _get_fill_percents(self):
fill_percents = self.shell.exec("df -H --output=source,pcent,target | grep frostfs").stdout.split("\n") fill_percents = self.shell.exec("df -H --output=source,pcent,target | grep frostfs").stdout.split("\n")
return [line.split() for line in fill_percents][:-1] return [line.split() for line in fill_percents][:-1]
def check_fill_percent(self): def check_fill_percent(self):
fill_percents = self._get_fill_percents() fill_percents = self._get_fill_percents()
percent_mean = 0 percent_mean = 0
for line in fill_percents: for line in fill_percents:
percent_mean += float(line[1].split('%')[0]) percent_mean += float(line[1].split("%")[0])
percent_mean = percent_mean / len(fill_percents) percent_mean = percent_mean / len(fill_percents)
logger.info(f"{self.loader.ip} mean fill percent is {percent_mean}") logger.info(f"{self.loader.ip} mean fill percent is {percent_mean}")
return percent_mean >= self.load_params.fill_percent return percent_mean >= self.load_params.fill_percent
@ -125,9 +125,9 @@ class K6:
self.preset_output = result.stdout.strip("\n") self.preset_output = result.stdout.strip("\n")
return self.preset_output return self.preset_output
@reporter.step("Generate K6 command") @reporter.step("Generate K6 variables")
def _generate_env_variables(self) -> str: def _generate_k6_variables(self) -> str:
env_vars = self.load_params.get_env_vars() env_vars = self.load_params.get_k6_vars()
env_vars[f"{self.load_params.load_type.value.upper()}_ENDPOINTS"] = ",".join(self.endpoints) env_vars[f"{self.load_params.load_type.value.upper()}_ENDPOINTS"] = ",".join(self.endpoints)
env_vars["SUMMARY_JSON"] = self.summary_json env_vars["SUMMARY_JSON"] = self.summary_json
@ -135,6 +135,14 @@ class K6:
reporter.attach("\n".join(f"{param}: {value}" for param, value in env_vars.items()), "K6 ENV variables") 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]) return " ".join([f"-e {param}='{value}'" for param, value in env_vars.items() if value is not None])
@reporter.step("Generate env variables")
def _generate_env_variables(self) -> str:
env_vars = self.load_params.get_env_vars()
if not env_vars:
return ""
reporter.attach("\n".join(f"{param}: {value}" for param, value in env_vars.items()), "ENV variables")
return " ".join([f"{param}='{value}'" for param, value in env_vars.items() if value is not None]) + " "
def get_start_time(self) -> datetime: def get_start_time(self) -> datetime:
return datetime.fromtimestamp(self._k6_process.start_time()) return datetime.fromtimestamp(self._k6_process.start_time())
@ -188,23 +196,25 @@ class K6:
wait_interval = min_wait_interval wait_interval = min_wait_interval
if self._k6_process is None: if self._k6_process is None:
assert "No k6 instances were executed" assert "No k6 instances were executed"
while timeout > 0: while timeout > 0:
if not self.load_params.fill_percent is None: if not self.load_params.fill_percent is None:
with reporter.step(f"Check the percentage of filling of all data disks on the node"): with reporter.step(f"Check the percentage of filling of all data disks on the node"):
if self.check_fill_percent(): if self.check_fill_percent():
logger.info(f"Stopping load on because disks is filled more then {self.load_params.fill_percent}%") logger.info(
f"Stopping load on because disks is filled more then {self.load_params.fill_percent}%"
)
event.set() event.set()
self.stop() self.stop()
return return
if event.is_set(): if event.is_set():
self.stop() self.stop()
return return
if not self._k6_process.running(): if not self._k6_process.running():
return return
remaining_time_hours = f"{timeout//3600}h" if timeout // 3600 != 0 else "" remaining_time_hours = f"{timeout//3600}h" if timeout // 3600 != 0 else ""
remaining_time_minutes = f"{timeout//60%60}m" if timeout // 60 % 60 != 0 else "" remaining_time_minutes = f"{timeout//60%60}m" if timeout // 60 % 60 != 0 else ""
logger.info( logger.info(

View file

@ -94,16 +94,18 @@ def metadata_field(
string_repr: Optional[bool] = True, string_repr: Optional[bool] = True,
distributed: Optional[bool] = False, distributed: Optional[bool] = False,
formatter: Optional[Callable] = None, formatter: Optional[Callable] = None,
env_variable: Optional[str] = None,
): ):
return field( return field(
default=None, default=None,
metadata={ metadata={
"applicable_scenarios": applicable_scenarios, "applicable_scenarios": applicable_scenarios,
"preset_argument": preset_param, "preset_argument": preset_param,
"env_variable": scenario_variable, "scenario_variable": scenario_variable,
"string_repr": string_repr, "string_repr": string_repr,
"distributed": distributed, "distributed": distributed,
"formatter": formatter, "formatter": formatter,
"env_variable": env_variable,
}, },
) )
@ -172,6 +174,20 @@ class Preset:
local: Optional[bool] = metadata_field(grpc_preset_scenarios, "local", None, False) local: Optional[bool] = metadata_field(grpc_preset_scenarios, "local", None, False)
@dataclass
class PrometheusParams:
# Prometheus server URL
server_url: Optional[str] = metadata_field(
all_load_scenarios, env_variable="K6_PROMETHEUS_RW_SERVER_URL", string_repr=False
)
# Prometheus trend stats
trend_stats: Optional[str] = metadata_field(
all_load_scenarios, env_variable="K6_PROMETHEUS_RW_TREND_STATS", string_repr=False
)
# Additional tags
metrics_tags: Optional[str] = metadata_field(all_load_scenarios, None, "METRIC_TAGS", False)
@dataclass @dataclass
class LoadParams: class LoadParams:
# ------- CONTROL PARAMS ------- # ------- CONTROL PARAMS -------
@ -223,6 +239,10 @@ class LoadParams:
fill_percent: Optional[float] = None fill_percent: Optional[float] = None
# if set, the payload is generated on the fly and is not read into memory fully. # if set, the payload is generated on the fly and is not read into memory fully.
streaming: Optional[int] = metadata_field(all_load_scenarios, None, "STREAMING", False) streaming: Optional[int] = metadata_field(all_load_scenarios, None, "STREAMING", False)
# Output format
output: Optional[str] = metadata_field(all_load_scenarios, None, "K6_OUT", False)
# Prometheus params
prometheus: Optional[PrometheusParams] = None
# ------- COMMON SCENARIO PARAMS ------- # ------- COMMON SCENARIO PARAMS -------
# Load time is the maximum duration for k6 to give load. Default is the BACKGROUND_LOAD_DEFAULT_TIME value. # Load time is the maximum duration for k6 to give load. Default is the BACKGROUND_LOAD_DEFAULT_TIME value.
@ -339,6 +359,17 @@ class LoadParams:
if self.preset: if self.preset:
self.preset.pregen_json = os.path.join(self.working_dir, f"{load_id}_prepare.json") self.preset.pregen_json = os.path.join(self.working_dir, f"{load_id}_prepare.json")
def get_k6_vars(self):
env_vars = {
meta_field.metadata["scenario_variable"]: meta_field.value
for meta_field in self._get_meta_fields(self)
if self.scenario in meta_field.metadata["applicable_scenarios"]
and meta_field.metadata["scenario_variable"]
and meta_field.value is not None
}
return env_vars
def get_env_vars(self): def get_env_vars(self):
env_vars = { env_vars = {
meta_field.metadata["env_variable"]: meta_field.value meta_field.metadata["env_variable"]: meta_field.value

View file

@ -157,6 +157,7 @@ class TestLoadConfig:
"DELETERS": 8, "DELETERS": 8,
"READ_AGE": 8, "READ_AGE": 8,
"STREAMING": 9, "STREAMING": 9,
"K6_OUT": "output",
"PREGEN_JSON": "pregen_json", "PREGEN_JSON": "pregen_json",
"PREPARE_LOCALLY": True, "PREPARE_LOCALLY": True,
} }
@ -181,6 +182,7 @@ class TestLoadConfig:
expected_env_vars = { expected_env_vars = {
"DURATION": 9, "DURATION": 9,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"K6_OUT": "output",
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
"K6_SETUP_TIMEOUT": "setup_timeout", "K6_SETUP_TIMEOUT": "setup_timeout",
@ -221,6 +223,7 @@ class TestLoadConfig:
"DURATION": 9, "DURATION": 9,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_OUT": "output",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
"K6_SETUP_TIMEOUT": "setup_timeout", "K6_SETUP_TIMEOUT": "setup_timeout",
"WRITERS": 7, "WRITERS": 7,
@ -254,6 +257,7 @@ class TestLoadConfig:
"DURATION": 183900, "DURATION": 183900,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_OUT": "output",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
"K6_SETUP_TIMEOUT": "setup_timeout", "K6_SETUP_TIMEOUT": "setup_timeout",
"NO_VERIFY_SSL": True, "NO_VERIFY_SSL": True,
@ -293,6 +297,7 @@ class TestLoadConfig:
"DURATION": 9, "DURATION": 9,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_OUT": "output",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
"K6_SETUP_TIMEOUT": "setup_timeout", "K6_SETUP_TIMEOUT": "setup_timeout",
"NO_VERIFY_SSL": True, "NO_VERIFY_SSL": True,
@ -332,6 +337,7 @@ class TestLoadConfig:
expected_env_vars = { expected_env_vars = {
"DURATION": 9, "DURATION": 9,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"K6_OUT": "output",
"NO_VERIFY_SSL": True, "NO_VERIFY_SSL": True,
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
@ -365,6 +371,7 @@ class TestLoadConfig:
"CONFIG_FILE": "config_file", "CONFIG_FILE": "config_file",
"DURATION": 9, "DURATION": 9,
"WRITE_OBJ_SIZE": 11, "WRITE_OBJ_SIZE": 11,
"K6_OUT": "output",
"REGISTRY_FILE": "registry_file", "REGISTRY_FILE": "registry_file",
"K6_MIN_ITERATION_DURATION": "min_iteration_duration", "K6_MIN_ITERATION_DURATION": "min_iteration_duration",
"K6_SETUP_TIMEOUT": "setup_timeout", "K6_SETUP_TIMEOUT": "setup_timeout",
@ -419,6 +426,7 @@ class TestLoadConfig:
"DURATION": 0, "DURATION": 0,
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"WRITERS": 0, "WRITERS": 0,
@ -449,6 +457,7 @@ class TestLoadConfig:
"DURATION": 0, "DURATION": 0,
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"MAX_WRITERS": 0, "MAX_WRITERS": 0,
@ -486,6 +495,7 @@ class TestLoadConfig:
"DURATION": 0, "DURATION": 0,
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"WRITERS": 0, "WRITERS": 0,
@ -516,6 +526,7 @@ class TestLoadConfig:
"DURATION": 0, "DURATION": 0,
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"NO_VERIFY_SSL": False, "NO_VERIFY_SSL": False,
@ -554,6 +565,7 @@ class TestLoadConfig:
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"NO_VERIFY_SSL": False, "NO_VERIFY_SSL": False,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"WRITERS": 0, "WRITERS": 0,
@ -584,6 +596,7 @@ class TestLoadConfig:
"DURATION": 0, "DURATION": 0,
"WRITE_OBJ_SIZE": 0, "WRITE_OBJ_SIZE": 0,
"REGISTRY_FILE": "", "REGISTRY_FILE": "",
"K6_OUT": "",
"K6_MIN_ITERATION_DURATION": "", "K6_MIN_ITERATION_DURATION": "",
"K6_SETUP_TIMEOUT": "", "K6_SETUP_TIMEOUT": "",
"WRITERS": 0, "WRITERS": 0,
@ -655,7 +668,7 @@ class TestLoadConfig:
assert sorted(preset_parameters) == sorted(expected_preset_args) assert sorted(preset_parameters) == sorted(expected_preset_args)
def _check_env_vars(self, load_params: LoadParams, expected_env_vars: dict[str, str]): def _check_env_vars(self, load_params: LoadParams, expected_env_vars: dict[str, str]):
env_vars = load_params.get_env_vars() env_vars = load_params.get_k6_vars()
assert env_vars == expected_env_vars assert env_vars == expected_env_vars
def _check_all_values_none(self, dataclass, skip_fields=None): def _check_all_values_none(self, dataclass, skip_fields=None):