Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to benchmark Elasticsearch with and without x-pack #485

Merged
merged 12 commits into from
Apr 27, 2018
15 changes: 7 additions & 8 deletions esrally/mechanic/mechanic.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,7 @@ def receiveMsg_NodesStopped(self, msg, sender):
self.transition_when_all_children_responded(sender, msg, "cluster_stopping", "cluster_stopped", self.on_all_nodes_stopped)

def on_all_nodes_started(self):
plugin_handler = PostLaunchPluginHandler(self.plugins)
self.cluster_launcher = launcher.ClusterLauncher(self.cfg, self.metrics_store, on_post_launch=plugin_handler)
self.cluster_launcher = launcher.ClusterLauncher(self.cfg, self.metrics_store, on_post_launch=PostLaunchHandler(self.plugins))
# Workaround because we could raise a LaunchError here and thespian will attempt to retry a failed message.
# In that case, we will get a followup RallyAssertionError because on the second attempt, Rally will check
# the status which is now "nodes_started" but we expected the status to be "nodes_starting" previously.
Expand Down Expand Up @@ -409,19 +408,19 @@ def on_all_nodes_stopped(self):
# do not self-terminate, let the parent actor handle this


class PostLaunchPluginHandler:
def __init__(self, plugins, hook_handler_class=team.PluginBootstrapHookHandler):
class PostLaunchHandler:
def __init__(self, components, hook_handler_class=team.BootstrapHookHandler):
self.handlers = []
if plugins:
for plugin in plugins:
handler = hook_handler_class(plugin)
if components:
for component in components:
handler = hook_handler_class(component)
if handler.can_load():
handler.load()
self.handlers.append(handler)

def __call__(self, client):
for handler in self.handlers:
handler.invoke(team.PluginBootstrapPhase.post_launch.name, client=client)
handler.invoke(team.BootstrapPhase.post_launch.name, client=client)


@thespian.actors.requireCapability('coordinator')
Expand Down
4 changes: 2 additions & 2 deletions esrally/mechanic/provisioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def prepare(self, binary):

for installer in self.plugin_installers:
# Never let install hooks modify our original provisioner variables and just provide a copy!
installer.invoke_install_hook(team.PluginBootstrapPhase.post_install, provisioner_vars.copy())
installer.invoke_install_hook(team.BootstrapPhase.post_install, provisioner_vars.copy())

return NodeConfiguration(self.es_installer.car, self.es_installer.node_ip, self.es_installer.node_name,
self.es_installer.node_root_dir, self.es_installer.es_home_path, self.es_installer.node_log_dir,
Expand Down Expand Up @@ -283,7 +283,7 @@ def _data_paths(self):


class PluginInstaller:
def __init__(self, plugin, hook_handler_class=team.PluginBootstrapHookHandler):
def __init__(self, plugin, hook_handler_class=team.BootstrapHookHandler):
self.plugin = plugin
self.hook_handler = hook_handler_class(self.plugin)
if self.hook_handler.can_load():
Expand Down
42 changes: 27 additions & 15 deletions esrally/mechanic/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ def __init__(self, name, core_plugin=False, config=None, root_path=None, config_
self.root_path = root_path
self.config_paths = config_paths
self.variables = variables
# name of the initial Python file to load for plugins.
self.entry_point = "plugin"

def __str__(self):
return "Plugin descriptor for [%s]" % self.name
Expand All @@ -344,28 +346,37 @@ def __eq__(self, other):
return isinstance(other, type(self)) and (self.name, self.config, self.core_plugin) == (other.name, other.config, other.core_plugin)


class PluginBootstrapPhase(Enum):
class BootstrapPhase(Enum):
post_install = 10
post_launch = 20

@classmethod
def valid(cls, name):
for n in PluginBootstrapPhase.names():
for n in BootstrapPhase.names():
if n == name:
return True
return False

@classmethod
def names(cls):
return [p.name for p in list(PluginBootstrapPhase)]
return [p.name for p in list(BootstrapPhase)]


class PluginBootstrapHookHandler:
def __init__(self, plugin, loader_class=modules.ComponentLoader):
self.plugin = plugin
class BootstrapHookHandler:
"""
Responsible for loading and executing component-specific intitialization code.
"""
def __init__(self, component, loader_class=modules.ComponentLoader):
"""
Creates a new BootstrapHookHandler.

:param component: The component that should be loaded. In practice, this is a PluginDescriptor instance.
:param loader_class: The implementation that loads the provided component's code.
"""
self.component = component
# Don't allow the loader to recurse. The subdirectories may contain Elasticsearch specific files which we do not want to add to
# Rally's Python load path. We may need to define a more advanced strategy in the future.
self.loader = loader_class(root_path=self.plugin.root_path, component_entry_point="plugin", recurse=False)
self.loader = loader_class(root_path=self.component.root_path, component_entry_point=self.component.entry_point, recurse=False)
self.hooks = {}

def can_load(self):
Expand All @@ -380,24 +391,25 @@ def load(self):
# just pass our own exceptions transparently.
raise
except BaseException:
msg = "Could not load plugin bootstrap hooks in [{}]".format(self.loader.root_path)
msg = "Could not load bootstrap hooks in [{}]".format(self.loader.root_path)
logger.exception(msg)
raise exceptions.SystemSetupError(msg)

def register(self, phase, hook):
logger.info("Registering plugin bootstrap hook [%s] for phase [%s] in plugin [%s]", hook.__name__, phase, self.plugin.name)
if not PluginBootstrapPhase.valid(phase):
raise exceptions.SystemSetupError("Phase [{}] is unknown. Valid phases are: {}.".format(phase, PluginBootstrapPhase.names()))
logger.info("Registering bootstrap hook [%s] for phase [%s] in component [%s]", hook.__name__, phase, self.component.name)
if not BootstrapPhase.valid(phase):
raise exceptions.SystemSetupError("Unknown bootstrap phase [{}]. Valid phases are: {}.".format(phase, BootstrapPhase.names()))
if phase not in self.hooks:
self.hooks[phase] = []
self.hooks[phase].append(hook)

def invoke(self, phase, **kwargs):
if phase in self.hooks:
logger.info("Invoking phase [%s] for plugin [%s] in config [%s]", phase, self.plugin.name, self.plugin.config)
logger.info("Invoking phase [%s] for component [%s] in config [%s]", phase, self.component.name, self.component.config)
for hook in self.hooks[phase]:
logger.info("Invoking hook [%s].", hook.__name__)
logger.info("Invoking bootstrap hook [%s].", hook.__name__)
# hooks should only take keyword arguments to be forwards compatible with Rally!
hook(config_names=self.plugin.config, **kwargs)
hook(config_names=self.component.config, **kwargs)
else:
logger.debug("Plugin [%s] in config [%s] has no hook registered for phase [%s].", self.plugin.name, self.plugin.config, phase)
logger.debug("Component [%s] in config [%s] has no hook registered for phase [%s].",
self.component.name, self.component.config, phase)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline missing as pointed by GitHub

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline missing here

2 changes: 1 addition & 1 deletion tests/mechanic/provisioner_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def test_invokes_hook(self):
installer = provisioner.PluginInstaller(plugin, hook_handler_class=PluginInstallerTests.NoopHookHandler)

self.assertEqual(0, len(installer.hook_handler.hook_calls))
installer.invoke_install_hook(team.PluginBootstrapPhase.post_install, {"foo": "bar"})
installer.invoke_install_hook(team.BootstrapPhase.post_install, {"foo": "bar"})
self.assertEqual(1, len(installer.hook_handler.hook_calls))
self.assertEqual({"foo": "bar"}, installer.hook_handler.hook_calls["post_install"])

Expand Down
12 changes: 6 additions & 6 deletions tests/mechanic/team_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_loads_configured_plugin(self):
}, plugin.variables)


class PluginBootstrapHookHandlerTests(TestCase):
class BootstrapHookHandlerTests(TestCase):
class UnitTestComponentLoader:
def __init__(self, root_path, component_entry_point, recurse):
self.root_path = root_path
Expand All @@ -146,8 +146,8 @@ def register(self, handler):

def test_loads_module(self):
plugin = team.PluginDescriptor("unittest-plugin")
hook = PluginBootstrapHookHandlerTests.UnitTestHook()
handler = team.PluginBootstrapHookHandler(plugin, loader_class=PluginBootstrapHookHandlerTests.UnitTestComponentLoader)
hook = BootstrapHookHandlerTests.UnitTestHook()
handler = team.BootstrapHookHandler(plugin, loader_class=BootstrapHookHandlerTests.UnitTestComponentLoader)

handler.loader.registration_function = hook
handler.load()
Expand All @@ -159,11 +159,11 @@ def test_loads_module(self):

def test_cannot_register_for_unknown_phase(self):
plugin = team.PluginDescriptor("unittest-plugin")
hook = PluginBootstrapHookHandlerTests.UnitTestHook(phase="this_is_an_unknown_install_phase")
handler = team.PluginBootstrapHookHandler(plugin, loader_class=PluginBootstrapHookHandlerTests.UnitTestComponentLoader)
hook = BootstrapHookHandlerTests.UnitTestHook(phase="this_is_an_unknown_install_phase")
handler = team.BootstrapHookHandler(plugin, loader_class=BootstrapHookHandlerTests.UnitTestComponentLoader)

handler.loader.registration_function = hook
with self.assertRaises(exceptions.SystemSetupError) as ctx:
handler.load()
self.assertEqual("Phase [this_is_an_unknown_install_phase] is unknown. Valid phases are: ['post_install', 'post_launch'].",
self.assertEqual("Unknown bootstrap phase [this_is_an_unknown_install_phase]. Valid phases are: ['post_install', 'post_launch'].",
ctx.exception.args[0])