Files
mongo/buildscripts/resmokelib/generate_fuzz_config/plugin.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

191 lines
6.9 KiB
Python
Raw Normal View History

"""Generate mongod.conf and mongos.conf using config fuzzer."""
import argparse
import os.path
import shutil
from buildscripts.resmokelib import config, utils
from buildscripts.resmokelib.generate_fuzz_config import mongo_fuzzer_configs
from buildscripts.resmokelib.plugin import PluginInterface, Subcommand
_HELP = """
Generate a mongod.conf and mongos.conf using config fuzzer.
"""
_COMMAND = "generate-fuzz-config"
class GenerateFuzzConfig(Subcommand):
"""Interact with generating fuzz config."""
def __init__(self, template_path, output_path, mongod_mode, mongos_mode, seed):
"""Constructor."""
self._template_path = template_path
self._output_path = output_path
self._mongod_mode = mongod_mode
self._mongos_mode = mongos_mode
self._seed = seed
def _generate_mongod_config(self) -> None:
filename = "mongod.conf"
output_file = os.path.join(self._output_path, filename)
user_param = utils.dump_yaml({})
(
set_parameters,
extra_configs,
wt_engine_config,
wt_coll_config,
wt_index_config,
encryption_config,
) = mongo_fuzzer_configs.fuzz_mongod_set_parameters(self._seed, user_param)
set_parameters = utils.load_yaml(set_parameters)
# This is moved from Jepsen mongod.conf to have only one setParameter key value pair.
set_parameters["enableTestCommands"] = True
# Increase the number of retry attempts for FCBIS due to the limitation of having only one
# $backupCursor open at a time. This restriction causes nodes to wait for others to complete
# their synchronization, leading to repeated failures.
set_parameters["numInitialSyncAttempts"] = 20
set_parameters["testingDiagnosticsEnabled"] = True
conf = {
"setParameter": set_parameters,
"storage": {
"directoryPerDB": extra_configs.pop("directoryperdb"),
"wiredTiger": {
"engineConfig": {
"configString": wt_engine_config,
"directoryForIndexes": extra_configs.pop("wiredTigerDirectoryForIndexes"),
},
"collectionConfig": {"configString": wt_coll_config},
"indexConfig": {"configString": wt_index_config},
},
},
}
if encryption_config:
# Convert empty string to True for config file compatibility.
# Resmoke uses an empty string to indicate a flag argument with no value,
# but the mongod configuration file expects a boolean for enableEncryption.
# https://www.mongodb.com/docs/manual/reference/configuration-options/#security-options
if encryption_config.get("enableEncryption") == "":
encryption_config["enableEncryption"] = True
conf["security"] = encryption_config
if self._template_path is not None:
try:
shutil.copy(os.path.join(self._template_path, filename), output_file)
except shutil.SameFileError:
pass
fuzz_config = utils.dump_yaml(conf)
with open(output_file, "a") as file:
file.write(fuzz_config)
file.write("\n")
def _generate_mongos_config(self) -> None:
filename = "mongos.conf"
output_file = os.path.join(self._output_path, filename)
user_param = utils.dump_yaml({})
set_parameters = mongo_fuzzer_configs.fuzz_mongos_set_parameters(self._seed, user_param)
set_parameters = utils.load_yaml(set_parameters)
set_parameters["enableTestCommands"] = True
conf = {"setParameter": set_parameters}
if self._template_path is not None:
try:
shutil.copy(os.path.join(self._template_path, filename), output_file)
except shutil.SameFileError:
pass
except FileNotFoundError:
print("There is no mongos template in the path, skip generating mongos.conf.")
return
fuzz_config = utils.dump_yaml(conf)
with open(output_file, "a") as file:
file.write(fuzz_config)
file.write("\n")
def execute(self) -> None:
"""
Generate mongod.conf and mongos.conf.
:return: None
"""
self._generate_mongod_config()
self._generate_mongos_config()
class GenerateFuzzConfigPlugin(PluginInterface):
"""Interact with generating fuzz config."""
def add_subcommand(self, subparsers):
"""
Add 'generate-fuzz-config' subcommand.
:param subparsers: argparse parser to add to
:return: None
"""
parser = subparsers.add_parser(_COMMAND, help=_HELP)
parser.add_argument(
"--template",
"-t",
type=str,
required=False,
help="Path to templates to append config-fuzzer-generated parameters.",
)
parser.add_argument(
"--output", "-o", type=str, required=True, help="Path to the output file."
)
parser.add_argument(
"--fuzzMongodConfigs",
dest="fuzz_mongod_configs",
help="Randomly chooses mongod parameters that were not specified.",
metavar="MODE",
choices=("normal"),
)
parser.add_argument(
"--fuzzMongosConfigs",
dest="fuzz_mongos_configs",
help="Randomly chooses mongos parameters that were not specified",
metavar="MODE",
choices=("normal",),
)
parser.add_argument(
"--configFuzzSeed",
dest="config_fuzz_seed",
metavar="PATH",
help="Sets the seed used by mongod and mongos config fuzzers",
)
parser.add_argument(
"--disableEncryptionFuzzing",
dest="disable_encryption_fuzzing",
action="store_true",
help="Disables the fuzzing that sometimes enables the encrypted storage engine.",
)
def parse(
self,
subcommand: str,
parser: argparse.ArgumentParser,
parsed_args: dict,
should_configure_otel: bool = True,
**kwargs,
):
"""
Return the GenerateFuzzConfig subcommand for execution.
:param subcommand: equivalent to parsed_args.command
:param parser: parser used
:param parsed_args: output of parsing
:param kwargs: additional args
:return: None or a Subcommand
"""
if subcommand != _COMMAND:
return None
config.DISABLE_ENCRYPTION_FUZZING = parsed_args["disable_encryption_fuzzing"]
return GenerateFuzzConfig(
parsed_args["template"],
parsed_args["output"],
parsed_args["fuzz_mongod_configs"],
parsed_args["fuzz_mongos_configs"],
parsed_args["config_fuzz_seed"],
)