diff options
author | Robert Guo <robert.guo@mongodb.com> | 2021-10-12 04:23:31 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-10-12 04:46:33 +0000 |
commit | 9c46c72e17e11a31089342abc9f56348aeaf4b87 (patch) | |
tree | 853197a50430b0a4a54139403e6f55405d9e61c6 /buildscripts/task_generation | |
parent | b9e2784da82fef8e45b95b88e4ac1443649a5b0c (diff) | |
download | mongo-9c46c72e17e11a31089342abc9f56348aeaf4b87.tar.gz |
SERVER-55857 Use explicit task definitions for implicit multiversion tasks
Diffstat (limited to 'buildscripts/task_generation')
-rw-r--r-- | buildscripts/task_generation/evg_config_builder.py | 38 | ||||
-rw-r--r-- | buildscripts/task_generation/gen_task_service.py | 55 | ||||
-rw-r--r-- | buildscripts/task_generation/multiversion_util.py | 44 | ||||
-rw-r--r-- | buildscripts/task_generation/resmoke_proxy.py | 29 | ||||
-rw-r--r-- | buildscripts/task_generation/suite_split.py | 116 | ||||
-rw-r--r-- | buildscripts/task_generation/task_types/fuzzer_tasks.py | 57 | ||||
-rw-r--r-- | buildscripts/task_generation/task_types/multiversion_tasks.py | 143 | ||||
-rw-r--r-- | buildscripts/task_generation/task_types/resmoke_tasks.py | 104 |
8 files changed, 138 insertions, 448 deletions
diff --git a/buildscripts/task_generation/evg_config_builder.py b/buildscripts/task_generation/evg_config_builder.py index a1f9b299b98..c3fc3cb403a 100644 --- a/buildscripts/task_generation/evg_config_builder.py +++ b/buildscripts/task_generation/evg_config_builder.py @@ -14,7 +14,6 @@ from buildscripts.task_generation.resmoke_proxy import ResmokeProxyService from buildscripts.task_generation.suite_split import SuiteSplitService, GeneratedSuite, \ SuiteSplitParameters from buildscripts.task_generation.task_types.fuzzer_tasks import FuzzerTask -from buildscripts.task_generation.task_types.multiversion_tasks import MultiversionGenTaskParams # pylint: disable=too-many-instance-attributes @@ -67,10 +66,8 @@ class EvgConfigBuilder: :param generated_suite: Generated suite to create config files for. :return: The suites files and evergreen configuration for the generated task. """ - test_list = generated_suite.get_test_list() - return self.resmoke_proxy.render_suite_files( - generated_suite.sub_suites, generated_suite.suite_name, generated_suite.filename, - test_list, self.gen_options.create_misc_suite, generated_suite) + return self.resmoke_proxy.render_suite_files(generated_suite, + self.gen_options.create_misc_suite) def generate_suite(self, split_params: SuiteSplitParameters, gen_params: ResmokeGenTaskParams) -> None: @@ -86,37 +83,6 @@ class EvgConfigBuilder: self.evg_config_gen_service.generate_task(generated_suite, build_variant, gen_params) self.generated_files.extend(self._generate_suites_config(generated_suite)) - def add_multiversion_suite(self, split_params: SuiteSplitParameters, - gen_params: MultiversionGenTaskParams) -> None: - """ - Add a multiversion suite to the builder. - - :param split_params: Parameters for how suite should be split. - :param gen_params: Parameters for how subtasks should be generated. - """ - generated_suite = self.suite_split_service.split_suite(split_params) - with self.lock: - build_variant = self.get_build_variant(generated_suite.build_variant) - self.evg_config_gen_service.generate_multiversion_task(generated_suite, build_variant, - gen_params) - self.generated_files.extend(self._generate_suites_config(generated_suite)) - - def add_multiversion_burn_in_test(self, split_params: SuiteSplitParameters, - gen_params: MultiversionGenTaskParams) -> Set[Task]: - """ - Add a multiversion burn_in suite to the builder. - - :param split_params: Parameters for how suite should be split. - :param gen_params: Parameters for how subtasks should be generated. - """ - generated_suite = self.suite_split_service.split_suite(split_params) - with self.lock: - build_variant = self.get_build_variant(generated_suite.build_variant) - tasks = self.evg_config_gen_service.generate_multiversion_burnin_task( - generated_suite, gen_params, build_variant) - self.generated_files.extend(self._generate_suites_config(generated_suite)) - return tasks - def generate_fuzzer(self, fuzzer_params: FuzzerGenTaskParams) -> FuzzerTask: """ Add configuration to generate the specified fuzzer task. diff --git a/buildscripts/task_generation/gen_task_service.py b/buildscripts/task_generation/gen_task_service.py index b6231f825a9..349ec0ebae0 100644 --- a/buildscripts/task_generation/gen_task_service.py +++ b/buildscripts/task_generation/gen_task_service.py @@ -13,8 +13,6 @@ if __name__ == "__main__" and __package__ is None: sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # pylint: disable=wrong-import-position -from buildscripts.task_generation.task_types.multiversion_tasks import MultiversionGenTaskParams, \ - MultiversionGenTaskService from buildscripts.task_generation.task_types.fuzzer_tasks import FuzzerGenTaskParams, FuzzerTask, \ FuzzerGenTaskService from buildscripts.task_generation.task_types.gentask_options import GenTaskOptions @@ -50,7 +48,6 @@ class GenTaskService: def __init__(self, evg_api: EvergreenApi, gen_task_options: GenTaskOptions, gen_config: GenerationConfiguration, resmoke_gen_task_service: ResmokeGenTaskService, - multiversion_gen_task_service: MultiversionGenTaskService, fuzzer_gen_task_service: FuzzerGenTaskService) -> None: """ Initialize the service. @@ -59,14 +56,12 @@ class GenTaskService: :param gen_task_options: Options for how tasks should be generated. :param gen_config: :param resmoke_gen_task_service: Service for generating standard resmoke tasks. - :param multiversion_gen_task_service: Service for generating multiversion resmoke tasks. :param fuzzer_gen_task_service: Service for generating fuzzer tasks. """ self.evg_api = evg_api self.gen_task_options = gen_task_options self.gen_config = gen_config self.resmoke_gen_task_service = resmoke_gen_task_service - self.multiversion_gen_task_service = multiversion_gen_task_service self.fuzzer_gen_task_service = fuzzer_gen_task_service def generate_fuzzer_task(self, params: FuzzerGenTaskParams, @@ -80,15 +75,12 @@ class GenTaskService: fuzzer_task = self.fuzzer_gen_task_service.generate_tasks(params) distros = self._get_distro(build_variant.name, params.use_large_distro, params.large_distro_name) - if params.add_to_display_task: - build_variant.display_task(fuzzer_task.task_name, fuzzer_task.sub_tasks, - distros=distros, activate=False) - else: - build_variant.add_tasks(fuzzer_task.sub_tasks, distros=distros, activate=False) + build_variant.display_task(fuzzer_task.task_name, fuzzer_task.sub_tasks, distros=distros, + activate=False) return fuzzer_task def generate_task(self, generated_suite: GeneratedSuite, build_variant: BuildVariant, - gen_params: ResmokeGenTaskParams) -> None: + gen_params: ResmokeGenTaskParams) -> List[Task]: """ Generate evergreen configuration for the given suite and add it to the build_variant. @@ -99,45 +91,10 @@ class GenTaskService: execution_tasks = self.resmoke_gen_task_service.generate_tasks(generated_suite, gen_params) distros = self._get_distro(build_variant.name, gen_params.use_large_distro, gen_params.large_distro_name) - build_variant.display_task(generated_suite.display_task_name(), - execution_tasks=execution_tasks, distros=distros, activate=False) + build_variant.display_task(generated_suite.task_name, execution_tasks=execution_tasks, + distros=distros, activate=False) - def generate_multiversion_task(self, generated_suite: GeneratedSuite, - build_variant: BuildVariant, - gen_params: MultiversionGenTaskParams) -> None: - """ - Generate evergreen configuration for the given suite and add it to the build_variant. - - :param generated_suite: Suite to add. - :param build_variant: Build variant to add generated configuration to. - :param gen_params: Parameters to configuration how tasks are generated. - """ - execution_tasks = self.multiversion_gen_task_service.generate_tasks( - generated_suite, gen_params) - distros = self._get_distro(build_variant.name, gen_params.use_large_distro, - gen_params.large_distro_name) - build_variant.display_task(generated_suite.display_task_name(), - execution_tasks=execution_tasks, distros=distros, activate=False) - - def generate_multiversion_burnin_task(self, generated_suite: GeneratedSuite, - gen_params: MultiversionGenTaskParams, - build_variant: BuildVariant) -> Set[Task]: - """ - Generate burn_in configuration for the given suite and add it to the build_variant. - - :param generated_suite: Suite to add. - :param build_variant: Build variant to add generated configuration to. - :param gen_params: Parameters to configuration how tasks are generated. - :return: Set of tasks that were generated. - """ - tasks = self.multiversion_gen_task_service.generate_tasks(generated_suite, gen_params) - distros = self._get_distro(build_variant.name, gen_params.use_large_distro, - gen_params.large_distro_name) - if gen_params.add_to_display_task: - build_variant.display_task(generated_suite.task_name, tasks, distros=distros) - else: - build_variant.add_tasks(tasks, distros=distros) - return tasks + return execution_tasks def _get_distro(self, build_variant: str, use_large_distro: bool, large_distro_name: Optional[str]) -> Optional[List[str]]: diff --git a/buildscripts/task_generation/multiversion_util.py b/buildscripts/task_generation/multiversion_util.py deleted file mode 100644 index f690d7247d1..00000000000 --- a/buildscripts/task_generation/multiversion_util.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Utilities for generating with multiversion tests.""" -from typing import List - -import inject - -from buildscripts.task_generation.resmoke_proxy import ResmokeProxyService - -REPL_MIXED_VERSION_CONFIGS = ["new-old-new", "new-new-old", "old-new-new"] -SHARDED_MIXED_VERSION_CONFIGS = ["new-old-old-new"] - - -class MultiversionUtilService: - """Utilities to working with multiversion tests.""" - - @inject.autoparams() - def __init__(self, resmoke_proxy: ResmokeProxyService) -> None: - """ - Initialize the service. - - :param resmoke_proxy: Resmoke proxy service. - """ - self.resmoke_proxy = resmoke_proxy - - def is_suite_sharded(self, suite_name: str) -> bool: - """Return true if a suite uses ShardedClusterFixture.""" - source_config = self.resmoke_proxy.read_suite_config(suite_name) - return source_config["executor"]["fixture"]["class"] == "ShardedClusterFixture" - - def get_version_configs_for_suite(self, suite_name: str) -> List[str]: - """ - Get the version configs that apply for the given suite. - - :param suite_name: Suite to get version configs for. - :return: List of version configs. - """ - is_sharded = self.is_suite_sharded(suite_name) - return self.get_version_configs(is_sharded) - - @staticmethod - def get_version_configs(is_sharded: bool) -> List[str]: - """Get the version configurations to use.""" - if is_sharded: - return SHARDED_MIXED_VERSION_CONFIGS - return REPL_MIXED_VERSION_CONFIGS diff --git a/buildscripts/task_generation/resmoke_proxy.py b/buildscripts/task_generation/resmoke_proxy.py index 820e63fb284..34a30c0ae02 100644 --- a/buildscripts/task_generation/resmoke_proxy.py +++ b/buildscripts/task_generation/resmoke_proxy.py @@ -58,38 +58,37 @@ class ResmokeProxyService: """ return self._suite_config.SuiteFinder.get_config_obj(suite_name) - def render_suite_files(self, suites: List["SubSuite"], suite_name: str, - generated_suite_filename: str, test_list: List[str], - create_misc_suite: bool, suite: "GeneratedSuite") -> List[GeneratedFile]: + def render_suite_files(self, suite: "GeneratedSuite", + create_misc_suite: bool) -> List[GeneratedFile]: """ Render the given list of suites. This will create a dictionary of all the resmoke config files to create with the filename of each file as the key and the contents as the value. - :param suites: List of suites to render. - :param suite_name: Base name of suites. - :param generated_suite_filename: The name to use as the file name for generated suite file. - :param test_list: List of tests used in suites. - :param create_misc_suite: Whether or not a _misc suite file should be created. :param suite: Generated suite files belong to. + :param create_misc_suite: Whether to create the file for the _misc task. :return: Dictionary of rendered resmoke config files. """ # pylint: disable=too-many-arguments - source_config = self._suite_config.SuiteFinder.get_config_obj(suite_name) + original_suite_name = suite.suite_name + test_list = suite.get_test_list() + + source_config = self._suite_config.SuiteFinder.get_config_obj(original_suite_name) suite_configs = [ - GeneratedFile(file_name=f"{suite.sub_suite_config_file(i)}.yml", - content=sub_suite.generate_resmoke_config(source_config)) - for i, sub_suite in enumerate(suites) + GeneratedFile( + file_name=suite.sub_suite_config_file(i), + content=sub_suite.generate_resmoke_config(source_config)) + for i, sub_suite in enumerate(suite.sub_suites) ] if create_misc_suite: suite_configs.append( GeneratedFile( - file_name=f"{suite.sub_suite_config_file(None)}.yml", - content=generate_resmoke_suite_config(source_config, generated_suite_filename, + file_name=suite.sub_suite_config_file(None), + content=generate_resmoke_suite_config(source_config, original_suite_name, excludes=test_list))) - LOGGER.debug("Generated files for suite", suite=suite_name, + LOGGER.debug("Generated files for suite", suite=original_suite_name, files=[f.file_name for f in suite_configs]) return suite_configs diff --git a/buildscripts/task_generation/suite_split.py b/buildscripts/task_generation/suite_split.py index 78a2e0c0486..75f24ba74e9 100644 --- a/buildscripts/task_generation/suite_split.py +++ b/buildscripts/task_generation/suite_split.py @@ -24,8 +24,7 @@ LOGGER = structlog.getLogger(__name__) CLEAN_EVERY_N_HOOK = "CleanEveryN" HEADER_TEMPLATE = """# DO NOT EDIT THIS FILE. All manual edits will be lost. -# This file was generated by {file} from -# {suite_file}. +# This file was generated by {file}. """ # pylint: disable=too-many-arguments @@ -62,48 +61,14 @@ def update_suite_config(suite_config, roots=None, excludes=None): class SubSuite(object): """A suite of tests that can be run by evergreen.""" - def __init__( - self, - index: int, - suite_name: str, - test_list: List[str], - tests_with_runtime_info: int, - max_test_runtime: float, - historic_runtime: float, - task_overhead: float, - ) -> None: + def __init__(self, test_list: List[str], task_overhead: float, + runtime_list: Optional[List[TestRuntime]] = None) -> None: """ Initialize the object. - :param index: Sub-suite index. - :param suite_name: Name of suite. :param test_list: List of tests to include in this sub-suite. - :param tests_with_runtime_info: Number of tests that that historic runtime info. - :param max_test_runtime: Runtime of the longest running test. - :param historic_runtime: Sum of the average runtime of all tests. - :param task_overhead: Runtime overhead to expect from task level hooks. - """ - self.index = index - self.suite_name = suite_name - self.test_list = test_list - self.tests_with_runtime_info = tests_with_runtime_info - self.max_test_runtime = max_test_runtime - self.historic_runtime = historic_runtime - self.task_overhead = task_overhead - - @classmethod - def from_test_list(cls, index: int, suite_name: str, test_list: List[str], - task_overhead: Optional[float], - runtime_list: Optional[List[TestRuntime]] = None) -> SubSuite: - """ - Create a sub-suite from the given test list. - - :param index: Index of sub-suite being created. - :param suite_name: Name of suite. - :param test_list: List of tests to include. :param task_overhead: Runtime overhead to expect from task level hooks. :param runtime_list: List of historic runtimes for tests in test_list. - :return: Sub-suite for the given tests. """ runtime_count = 0 total_runtime = 0.0 @@ -116,8 +81,10 @@ class SubSuite(object): total_runtime += runtime_map[test] max_runtime = max(max_runtime, runtime_map[test]) - return cls(index, suite_name, test_list, runtime_count, max_runtime, total_runtime, - task_overhead or 0.0) + self.test_list = test_list + self.tests_with_runtime_info = runtime_count + self.max_test_runtime = max_runtime + self.expected_runtime = total_runtime + task_overhead def should_overwrite_timeout(self) -> bool: """ @@ -131,26 +98,12 @@ class SubSuite(object): """Get the estimated runtime of this task to for timeouts.""" if self.should_overwrite_timeout(): return TimeoutEstimate(max_test_runtime=self.max_test_runtime, - expected_task_runtime=self.historic_runtime + self.task_overhead) + expected_task_runtime=self.expected_runtime) return TimeoutEstimate.no_timeouts() - def get_runtime(self): - """Get the current average runtime of all the tests currently in this suite.""" - return self.historic_runtime - - def get_test_count(self) -> int: - """Get the number of tests currently in this suite.""" - return len(self) - def __len__(self) -> int: return len(self.test_list) - def name(self, total_suites: int, suite_name: Optional[str] = None) -> str: - """Get the name of this suite.""" - if suite_name is None: - suite_name = self.suite_name - return taskname.name_generated_task(suite_name, self.index, total_suites) - def generate_resmoke_config(self, source_config: Dict) -> str: """ Generate the contents of resmoke config for this suite. @@ -159,7 +112,7 @@ class SubSuite(object): :return: Resmoke config to run this suite. """ suite_config = update_suite_config(deepcopy(source_config), roots=self.test_list) - contents = HEADER_TEMPLATE.format(file=__file__, suite_file=self.suite_name) + contents = HEADER_TEMPLATE.format(file=__file__) contents += yaml.safe_dump(suite_config, default_flow_style=False) return contents @@ -181,14 +134,6 @@ class GeneratedSuite(NamedTuple): task_name: str suite_name: str filename: str - include_build_variant_in_name: bool = False - - def display_task_name(self) -> str: - """Get the display name to use for this task.""" - base_name = remove_gen_suffix(self.task_name) - if self.include_build_variant_in_name: - return f"{base_name}_{self.build_variant}" - return base_name def get_test_list(self) -> List[str]: """Get the list of tests that will be run by this suite.""" @@ -203,12 +148,20 @@ class GeneratedSuite(NamedTuple): Get the name of the file to store the resmoke configuration. :param index: Index of suite or None for '_misc' suite. - :return: Name resmoke configuration for subtask should stored. + :return: Name of generated resmoke.py configuration file. """ - if index is not None: - return taskname.name_generated_task(self.display_task_name(), index, - len(self.sub_suites)) - return f"{self.display_task_name()}_misc" + # Use self.task_name here instead of self.suite_name since multiple tasks can have the same resmoke.py suite. + return f"{taskname.name_generated_task(self.task_name, index, len(self.sub_suites))}.yml" + + def sub_suite_task_name(self, index: Optional[int] = None) -> str: + """ + Get the name of the task that runs one of the generated sub-suites. + + :param index: Index of suite or None for '_misc' suite. + :return: Name of generated Evergreen task. + """ + return taskname.name_generated_task(self.task_name, index, len(self.sub_suites), + self.build_variant) class SuiteSplitParameters(NamedTuple): @@ -354,24 +307,23 @@ class SuiteSplitService: :param test_stats: Other historic task data. :return: Generated suite for the sub-suites specified. """ - suites = [ - SubSuite.from_test_list( - index, - params.suite_name, - test_list, - self.get_task_hook_overhead(params.suite_name, params.is_asan, len(test_list), - test_stats), - tests_runtimes, - ) for index, test_list in enumerate(test_lists) - ] + + sub_suites = [] + for _, test_list in enumerate(test_lists): + task_overhead = self.get_task_hook_overhead(params.suite_name, params.is_asan, + len(test_list), test_stats) + sub_suites.append(SubSuite(test_list, task_overhead, tests_runtimes)) + + task_name = params.task_name + if self.config.include_build_variant_in_name: + task_name = f"{params.task_name}_{params.build_variant}" return GeneratedSuite( - sub_suites=suites, + sub_suites=sub_suites, build_variant=params.build_variant, - task_name=params.task_name, + task_name=task_name, suite_name=params.suite_name, filename=params.filename, - include_build_variant_in_name=self.config.include_build_variant_in_name, ) def filter_tests(self, tests_runtimes: List[TestRuntime], diff --git a/buildscripts/task_generation/task_types/fuzzer_tasks.py b/buildscripts/task_generation/task_types/fuzzer_tasks.py index 313e21275ac..df096f97191 100644 --- a/buildscripts/task_generation/task_types/fuzzer_tasks.py +++ b/buildscripts/task_generation/task_types/fuzzer_tasks.py @@ -1,5 +1,5 @@ """Task generation for fuzzer tasks.""" -from typing import NamedTuple, Set, Optional, Dict, List +from typing import NamedTuple, Set, Optional, Dict from shrub.v2 import Task, FunctionCall, TaskDependency @@ -8,13 +8,6 @@ from buildscripts.task_generation.constants import ARCHIVE_DIST_TEST_DEBUG_TASK from buildscripts.util import taskname -def get_multiversion_resmoke_args(is_sharded: bool) -> str: - """Return resmoke args used to configure a cluster for multiversion testing.""" - if is_sharded: - return "--numShards=2 --numReplSetNodes=2 " - return "--numReplSetNodes=3 --linearChain=on " - - class FuzzerTask(NamedTuple): """ Evergreen configuration for a generated fuzzer command. @@ -43,9 +36,8 @@ class FuzzerGenTaskParams(NamedTuple): resmoke_jobs_max: Maximum number of jobs resmoke should execute in parallel. should_shuffle: Should tests be executed out of order. timeout_secs: Timeout before test execution is considered hung. - require_multiversion: Requires downloading Multiversion binaries. + require_multiversion_setup: Requires downloading Multiversion binaries. use_large_distro: Should tests be generated on a large distro. - add_to_display_task: Should generated tasks be grouped in a display task. """ task_name: str @@ -60,13 +52,10 @@ class FuzzerGenTaskParams(NamedTuple): resmoke_jobs_max: int should_shuffle: bool timeout_secs: int - require_multiversion: Optional[bool] + require_multiversion_setup: Optional[bool] use_large_distro: Optional[bool] large_distro_name: Optional[str] config_location: str - add_to_display_task: bool = True - version_config: Optional[List[str]] = None - is_sharded: Optional[bool] = None def jstestfuzz_params(self) -> Dict[str, str]: """Build a dictionary of parameters to pass to jstestfuzz.""" @@ -75,17 +64,8 @@ class FuzzerGenTaskParams(NamedTuple): "npm_command": self.npm_command, } - def get_task_name(self, version: str) -> str: - """Get the name to use for generated tasks.""" - if version: - return f"{self.suite}_multiversion_{version}" - return self.task_name - def get_resmoke_args(self) -> str: """Get the resmoke arguments to use for generated tasks.""" - if self.is_sharded is not None: - mv_args = get_multiversion_resmoke_args(self.is_sharded) - return f"{self.resmoke_args or ''} --mixedBinVersions={self.version_config} {mv_args}" return self.resmoke_args @@ -99,31 +79,24 @@ class FuzzerGenTaskService: :param params: Parameters for how task should be generated. :return: Set of shrub tasks. """ - version_list = params.version_config - if version_list is None: - version_list = [""] - sub_tasks = set() - for version in version_list: - sub_tasks = sub_tasks.union({ - self.build_fuzzer_sub_task(index, params, version) - for index in range(params.num_tasks) - }) + sub_tasks = sub_tasks.union( + {self.build_fuzzer_sub_task(index, params) + for index in range(params.num_tasks)}) - return FuzzerTask(task_name=params.get_task_name(""), sub_tasks=sub_tasks) + return FuzzerTask(task_name=params.task_name, sub_tasks=sub_tasks) @staticmethod - def build_fuzzer_sub_task(task_index: int, params: FuzzerGenTaskParams, version: str) -> Task: + def build_fuzzer_sub_task(task_index: int, params: FuzzerGenTaskParams) -> Task: """ Build a shrub task to run the fuzzer. :param task_index: Index of sub task being generated. :param params: Parameters describing how tasks should be generated. - :param version: Multiversion version to generate against. :return: Shrub task to run the fuzzer. """ - sub_task_name = taskname.name_generated_task( - params.get_task_name(version), task_index, params.num_tasks, params.variant) + sub_task_name = taskname.name_generated_task(params.task_name, task_index, params.num_tasks, + params.variant) suite_arg = f"--suites={params.suite}" run_tests_vars = { @@ -131,9 +104,9 @@ class FuzzerGenTaskService: "resmoke_args": f"{suite_arg} {params.get_resmoke_args()}", "resmoke_jobs_max": params.resmoke_jobs_max, "should_shuffle": params.should_shuffle, - "require_multiversion": params.require_multiversion, + "require_multiversion_setup": params.require_multiversion_setup, "timeout_secs": params.timeout_secs, - "task": params.get_task_name(version), + "task": params.task_name, "gen_task_config_location": params.config_location, } # yapf: disable @@ -141,7 +114,7 @@ class FuzzerGenTaskService: commands = [] - if params.require_multiversion: + if params.require_multiversion_setup: commands += [FunctionCall("git get project no modules")] commands += [FunctionCall("add git tag")] @@ -149,8 +122,8 @@ class FuzzerGenTaskService: timeout_info.cmd, FunctionCall("do setup"), FunctionCall("configure evergreen api credentials") - if params.require_multiversion else None, - FunctionCall("do multiversion setup") if params.require_multiversion else None, + if params.require_multiversion_setup else None, + FunctionCall("do multiversion setup") if params.require_multiversion_setup else None, FunctionCall("setup jstestfuzz"), FunctionCall("run jstestfuzz", params.jstestfuzz_params()), FunctionCall("run generated tests", run_tests_vars) diff --git a/buildscripts/task_generation/task_types/multiversion_tasks.py b/buildscripts/task_generation/task_types/multiversion_tasks.py deleted file mode 100644 index 0cb0fd17742..00000000000 --- a/buildscripts/task_generation/task_types/multiversion_tasks.py +++ /dev/null @@ -1,143 +0,0 @@ -"""Task generation for multiversion resmoke tasks.""" -from typing import NamedTuple, Set, List, Optional - -import inject -from shrub.v2 import Task, FunctionCall, TaskDependency - -from buildscripts.resmokelib.multiversionconstants import REQUIRES_FCV_TAG -from buildscripts.task_generation.constants import ARCHIVE_DIST_TEST_DEBUG_TASK -from buildscripts.task_generation.suite_split import GeneratedSuite -from buildscripts.task_generation.task_types.gentask_options import GenTaskOptions - -BACKPORT_REQUIRED_TAG = "backport_required_multiversion" -EXCLUDE_TAGS = f"{REQUIRES_FCV_TAG},multiversion_incompatible,{BACKPORT_REQUIRED_TAG}" -EXCLUDE_TAGS_FILE = "multiversion_exclude_tags.yml" - - -class MultiversionGenTaskParams(NamedTuple): - """ - Parameters for how multiversion tests should be generated. - - mixed_version_configs: List of version configuration to generate. - is_sharded: Whether sharded tests are being generated. - resmoke_args: Arguments to pass to resmoke. - parent_task_name: Name of parent task containing all sub tasks. - origin_suite: Resmoke suite generated tests are based off. - """ - - mixed_version_configs: List[str] - is_sharded: bool - resmoke_args: str - parent_task_name: str - origin_suite: str - use_large_distro: bool - large_distro_name: Optional[str] - config_location: str - name_prefix: Optional[str] = None - test_list: Optional[str] = None - create_misc_suite: bool = True - add_to_display_task: bool = True - - def get_multiversion_resmoke_args(self) -> str: - """Return resmoke args used to configure a cluster for multiversion testing.""" - if self.is_sharded: - return "--numShards=2 --numReplSetNodes=2 " - return "--numReplSetNodes=3 --linearChain=on " - - -class MultiversionGenTaskService: - """A service for generating multiversion tests.""" - - @inject.autoparams() - def __init__(self, gen_task_options: GenTaskOptions) -> None: - """ - Initialize the service. - - :param gen_task_options: Options for how tasks should be generated. - """ - self.gen_task_options = gen_task_options - - def generate_tasks(self, suite: GeneratedSuite, params: MultiversionGenTaskParams) -> Set[Task]: - """ - Generate multiversion tasks for the given suite. - - :param suite: Suite to generate multiversion tasks for. - :param params: Parameters for how tasks should be generated. - :return: Evergreen configuration to generate the specified tasks. - """ - sub_tasks = set() - for version_config in params.mixed_version_configs: - for index, sub_suite in enumerate(suite.sub_suites): - # Generate the newly divided test suites - sub_suite_name = sub_suite.name(len(suite)) - sub_task_name = f"{sub_suite_name}_{version_config}_{suite.build_variant}" - if params.name_prefix is not None: - sub_task_name = f"{params.name_prefix}:{sub_task_name}" - - sub_tasks.add( - self._generate_task(sub_task_name, version_config, params, suite, index)) - - if params.create_misc_suite: - # Also generate the misc task. - misc_suite_name = f"{params.origin_suite}_misc" - misc_task_name = f"{misc_suite_name}_{version_config}_{suite.build_variant}" - sub_tasks.add( - self._generate_task(misc_task_name, version_config, params, suite, None)) - - return sub_tasks - - # pylint: disable=too-many-arguments - def _generate_task(self, sub_task_name: str, mixed_version_config: str, - params: MultiversionGenTaskParams, suite: GeneratedSuite, - index: Optional[int]) -> Task: - """ - Generate a sub task to be run with the provided suite and mixed version config. - - :param sub_task_name: Name of task being generated. - :param mixed_version_config: Versions task is being generated for. - :param params: Parameters for how tasks should be generated. - :return: Shrub configuration for task specified. - """ - suite_file = self.gen_task_options.suite_location(suite.sub_suite_config_file(index)) - - run_tests_vars = { - "resmoke_args": self._build_resmoke_args(suite_file, mixed_version_config, params), - "task": params.parent_task_name, - "gen_task_config_location": params.config_location, - "require_multiversion": True, - } - - commands = [ - FunctionCall("git get project no modules"), - FunctionCall("add git tag"), - FunctionCall("do setup"), - # Fetch and download the proper mongod binaries before running multiversion tests. - FunctionCall("configure evergreen api credentials"), - FunctionCall("do multiversion setup"), - FunctionCall("run generated tests", run_tests_vars), - ] - - return Task(sub_task_name, commands, {TaskDependency(ARCHIVE_DIST_TEST_DEBUG_TASK)}) - - def _build_resmoke_args(self, suite_file: str, mixed_version_config: str, - params: MultiversionGenTaskParams) -> str: - """ - Get the resmoke args needed to run the specified task. - - :param suite_file: Path to resmoke suite configuration to run. - :param mixed_version_config: Versions task is being generated for. - :param params: Parameters for how tasks should be generated. - :return: Arguments to pass to resmoke to run the generated task. - """ - - tag_file_location = self.gen_task_options.generated_file_location(EXCLUDE_TAGS_FILE) - - return ( - f"{params.resmoke_args} " - f" --suite={suite_file}.yml " - f" --mixedBinVersions={mixed_version_config}" - f" --excludeWithAnyTags={EXCLUDE_TAGS},{params.parent_task_name}_{BACKPORT_REQUIRED_TAG} " - f" --tagFile={tag_file_location} " - f" --originSuite={params.origin_suite} " - f" {params.get_multiversion_resmoke_args()} " - f" {params.test_list if params.test_list else ''} ") diff --git a/buildscripts/task_generation/task_types/resmoke_tasks.py b/buildscripts/task_generation/task_types/resmoke_tasks.py index 7df492be8d4..cdc7576872d 100644 --- a/buildscripts/task_generation/task_types/resmoke_tasks.py +++ b/buildscripts/task_generation/task_types/resmoke_tasks.py @@ -7,14 +7,18 @@ import structlog from shrub.v2 import Task, TaskDependency from buildscripts.patch_builds.task_generation import resmoke_commands +from buildscripts.resmokelib.multiversionconstants import REQUIRES_FCV_TAG from buildscripts.task_generation.constants import ARCHIVE_DIST_TEST_DEBUG_TASK -from buildscripts.task_generation.suite_split import GeneratedSuite, SubSuite +from buildscripts.task_generation.suite_split import GeneratedSuite from buildscripts.task_generation.task_types.gentask_options import GenTaskOptions from buildscripts.task_generation.timeout import TimeoutEstimate -from buildscripts.util import taskname LOGGER = structlog.getLogger(__name__) +BACKPORT_REQUIRED_TAG = "backport_required_multiversion" +EXCLUDE_TAGS = f"{REQUIRES_FCV_TAG},multiversion_incompatible,{BACKPORT_REQUIRED_TAG}" +EXCLUDE_TAGS_FILE = "multiversion_exclude_tags.yml" + def string_contains_any_of_args(string: str, args: List[str]) -> bool: """ @@ -32,7 +36,7 @@ class ResmokeGenTaskParams(NamedTuple): Parameters describing how a specific resmoke suite should be generated. use_large_distro: Whether generated tasks should be run on a "large" distro. - require_multiversion: Requires downloading Multiversion binaries. + require_multiversion_setup: Requires downloading Multiversion binaries. repeat_suites: How many times generated suites should be repeated. resmoke_args: Arguments to pass to resmoke in generated tasks. resmoke_jobs_max: Max number of jobs that resmoke should execute in parallel. @@ -41,7 +45,7 @@ class ResmokeGenTaskParams(NamedTuple): use_large_distro: bool large_distro_name: Optional[str] - require_multiversion: Optional[bool] + require_multiversion_setup: Optional[bool] repeat_suites: int resmoke_args: str resmoke_jobs_max: Optional[int] @@ -86,41 +90,38 @@ class ResmokeGenTaskService: :return: Set of shrub tasks to generate the given suite. """ tasks = { - self._create_sub_task(suite, generated_suite, params) - for suite in generated_suite.sub_suites + self._create_sub_task(index, suite.get_timeout_estimate(), generated_suite, params) + for index, suite in enumerate(generated_suite.sub_suites) } if self.gen_task_options.create_misc_suite: - # Add the misc suite - misc_task_name = f"{generated_suite.task_name}_misc_{generated_suite.build_variant}" tasks.add( - self._generate_task(None, misc_task_name, TimeoutEstimate.no_timeouts(), params, - generated_suite)) + self._create_sub_task(None, est_timeout=TimeoutEstimate.no_timeouts(), + suite=generated_suite, params=params)) return tasks - def _create_sub_task(self, sub_suite: SubSuite, suite: GeneratedSuite, - params: ResmokeGenTaskParams) -> Task: + def _create_sub_task(self, index: Optional[int], est_timeout: TimeoutEstimate, + suite: GeneratedSuite, params: ResmokeGenTaskParams) -> Task: """ Create the sub task for the given suite. - :param sub_suite: Sub-Suite to generate. + :param index: index of sub_suite. + :param est_timeout: timeout estimate. :param suite: Parent suite being created. :param params: Parameters describing how tasks should be generated. :return: Shrub configuration for the sub-suite. """ - sub_task_name = taskname.name_generated_task(suite.task_name, sub_suite.index, len(suite), - suite.build_variant) - return self._generate_task(sub_suite.index, sub_task_name, sub_suite.get_timeout_estimate(), - params, suite) - - def _generate_task(self, sub_suite_index: Optional[int], sub_task_name: str, - timeout_est: TimeoutEstimate, params: ResmokeGenTaskParams, - suite: GeneratedSuite) -> Task: + return self._generate_task( + suite.sub_suite_config_file(index), suite.sub_suite_task_name(index), est_timeout, + params, suite) + + def _generate_task(self, sub_suite_file, sub_task_name: str, timeout_est: TimeoutEstimate, + params: ResmokeGenTaskParams, suite: GeneratedSuite) -> Task: """ Generate a shrub evergreen config for a resmoke task. - :param sub_suite_index: Index of suite being generated. + :param sub_suite_file: Name of the suite file to run in the generated task. :param sub_task_name: Name of task to generate. :param timeout_est: Estimated runtime to use for calculating timeouts. :param params: Parameters describing how tasks should be generated. @@ -128,46 +129,75 @@ class ResmokeGenTaskService: :return: Shrub configuration for the described task. """ # pylint: disable=too-many-arguments - LOGGER.debug("Generating task", suite=suite.display_task_name(), index=sub_suite_index) + LOGGER.debug("Generating task running suite", sub_task_name=sub_task_name, + sub_suite_file=sub_suite_file) - target_suite_file = self.gen_task_options.suite_location( - suite.sub_suite_config_file(sub_suite_index)) - run_tests_vars = self._get_run_tests_vars(target_suite_file, suite.suite_name, params) + sub_suite_file_path = self.gen_task_options.suite_location(sub_suite_file) + run_tests_vars = self._get_run_tests_vars(sub_suite_file_path=sub_suite_file_path, + suite_file=suite.suite_name, + task_name=suite.task_name, params=params) - require_multiversion = params.require_multiversion + require_multiversion_setup = params.require_multiversion_setup timeout_cmd = timeout_est.generate_timeout_cmd(self.gen_task_options.is_patch, params.repeat_suites, self.gen_task_options.use_default_timeouts) commands = resmoke_commands("run generated tests", run_tests_vars, timeout_cmd, - require_multiversion) + require_multiversion_setup) return Task(sub_task_name, commands, self._get_dependencies()) - @staticmethod + def generate_resmoke_args(self, sub_suite_file: str, original_suite: str, task_name: str, + params: ResmokeGenTaskParams) -> str: + """ + Generate the resmoke args for the given suite. + + :param sub_suite_file: File containing configuration for test suite. + :param original_suite: Name of source suite of the generated suite files. + :param task_name: Name of the task. + :param params: task generation parameters. + + :return: arguments to pass to resmoke. + """ + resmoke_args = f"--suite={sub_suite_file} --originSuite={original_suite} {params.resmoke_args}" + if params.repeat_suites and not string_contains_any_of_args(resmoke_args, + ["repeatSuites", "repeat"]): + resmoke_args += f" --repeatSuites={params.repeat_suites} " + + if params.require_multiversion_setup: + tag_file = self.gen_task_options.generated_file_location(EXCLUDE_TAGS_FILE) + resmoke_args += f" --tagFile={tag_file}" + resmoke_args += f" --excludeWithAnyTags={EXCLUDE_TAGS},{task_name}_{BACKPORT_REQUIRED_TAG} " + + return resmoke_args + def _get_run_tests_vars( + self, + sub_suite_file_path: str, suite_file: str, - suite_name: str, + task_name: str, params: ResmokeGenTaskParams, ) -> Dict[str, Any]: """ Generate a dictionary of the variables to pass to the task. - :param suite_file: Suite being generated. - :param suite_name: Name of suite being generated + :param sub_suite_file_path: path to the generated suite file. + :param suite_file: name of the original suite file. + :param task_name: Name of the task. :param params: Parameters describing how tasks should be generated. :return: Dictionary containing variables and value to pass to generated task. """ variables = { - "resmoke_args": params.generate_resmoke_args(suite_file, suite_name), - "gen_task_config_location": params.config_location, + "resmoke_args": + self.generate_resmoke_args(sub_suite_file=sub_suite_file_path, + original_suite=suite_file, task_name=task_name, + params=params), "gen_task_config_location": + params.config_location, "require_multiversion_setup": + params.require_multiversion_setup } if params.resmoke_jobs_max: variables["resmoke_jobs_max"] = params.resmoke_jobs_max - if params.require_multiversion: - variables["require_multiversion"] = params.require_multiversion - return variables @staticmethod |