Volans has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/366736 )
Change subject: Transports: convert hosts to ClusterShell's NodeSet
......................................................................
Transports: convert hosts to ClusterShell's NodeSet
Breaking change in the API.
- in preparation for the multi-query support, start moving the
transports to accept a ClusterShell's NodeSet instead of a list of
nodes. With the new multi-query support the backends too will return
only NodeSets.
Bug: T170394
Change-Id: I501b59d1dc2d9bd0c975de7ab5ccfe421c27c9ea
---
M cumin/cli.py
M cumin/tests/unit/transports/test_clustershell.py
M cumin/tests/unit/transports/test_init.py
M cumin/transports/__init__.py
M cumin/transports/clustershell.py
5 files changed, 26 insertions(+), 23 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/software/cumin
refs/changes/36/366736/1
diff --git a/cumin/cli.py b/cumin/cli.py
index 49b023c..10f5a91 100644
--- a/cumin/cli.py
+++ b/cumin/cli.py
@@ -310,7 +310,7 @@
return 0
worker = transport.Transport.new(config, logger)
- worker.hosts = hosts
+ worker.hosts = NodeSet.fromlist(hosts)
if args.timeout is not None:
worker.commands = [transports.Command(command, timeout=args.timeout)
for command in args.commands]
diff --git a/cumin/tests/unit/transports/test_clustershell.py
b/cumin/tests/unit/transports/test_clustershell.py
index b6f41b5..44dce32 100644
--- a/cumin/tests/unit/transports/test_clustershell.py
+++ b/cumin/tests/unit/transports/test_clustershell.py
@@ -34,8 +34,7 @@
'fanout': 3}}
self.worker = clustershell.worker_class(self.config)
- self.nodes = ['node1', 'node2']
- self.nodes_set = clustershell.NodeSet.NodeSet.fromlist(self.nodes)
+ self.nodes = clustershell.NodeSet.NodeSet('node[1-2]')
self.commands = [Command('command1'), Command('command2', ok_codes=[0,
100], timeout=5)]
self.task_self = task_self
# Mock default handlers
@@ -62,7 +61,7 @@
self.worker.handler = 'sync'
self.worker.execute()
self.worker.task.shell.assert_called_once_with(
- 'command1', nodes=self.nodes_set,
handler=self.worker._handler_instance, timeout=None)
+ 'command1', nodes=self.nodes,
handler=self.worker._handler_instance, timeout=None)
assert clustershell.DEFAULT_HANDLERS['sync'].called
def test_execute_default_async_handler(self):
@@ -70,7 +69,7 @@
self.worker.handler = 'async'
self.worker.execute()
self.worker.task.shell.assert_called_once_with(
- 'command1', nodes=self.nodes_set,
handler=self.worker._handler_instance, timeout=None)
+ 'command1', nodes=self.nodes,
handler=self.worker._handler_instance, timeout=None)
assert clustershell.DEFAULT_HANDLERS['async'].called
def test_execute_timeout(self):
@@ -86,7 +85,7 @@
self.worker.execute()
assert isinstance(self.worker._handler_instance,
ConcreteBaseEventHandler)
self.worker.task.shell.assert_called_once_with(
- 'command1', nodes=self.nodes_set,
handler=self.worker._handler_instance, timeout=None)
+ 'command1', nodes=self.nodes,
handler=self.worker._handler_instance, timeout=None)
def test_execute_no_commands(self):
"""Calling execute() without commands should return without doing
anything."""
@@ -112,8 +111,7 @@
self.worker.batch_size = 1
self.worker.execute()
self.worker.task.shell.assert_called_once_with(
- 'command1', nodes=clustershell.NodeSet.NodeSet(self.nodes[0]),
handler=self.worker._handler_instance,
- timeout=None)
+ 'command1', nodes=self.nodes[:1],
handler=self.worker._handler_instance, timeout=None)
def test_get_results(self):
"""Calling get_results() should call ClusterShell iter_buffers with
the right parameters."""
@@ -173,12 +171,12 @@
def setup_method(self, *args): # pylint: disable=arguments-differ
"""Initialize default properties and instances."""
- self.nodes = ['node1', 'node2']
+ self.nodes = clustershell.NodeSet.NodeSet('node[1-2]')
self.commands = [Command('command1', ok_codes=[0, 100]),
Command('command2', timeout=5)]
self.worker = mock.MagicMock()
self.worker.current_node = 'node1'
self.worker.command = 'command1'
- self.worker.nodes = clustershell.NodeSet.NodeSet.fromlist(self.nodes)
+ self.worker.nodes = self.nodes
self.handler = None
self.args = args
@@ -220,7 +218,7 @@
def test_instantiation(self):
"""An instance of ConcreteBaseEventHandler should be an instance of
BaseEventHandler and initialize colorama."""
- assert sorted(self.handler.nodes.keys()) == self.nodes
+ assert sorted(self.handler.nodes.keys()) == list(self.nodes)
self.colorama.init.assert_called_once_with()
@mock.patch('cumin.transports.clustershell.tqdm')
@@ -258,14 +256,13 @@
@mock.patch('cumin.transports.clustershell.tqdm')
def test_ev_read_single_host(self, tqdm):
"""Calling ev_read() should print the worker message if matching a
single host."""
- nodes = ['node1']
- self.nodes = nodes
+ self.nodes = clustershell.NodeSet.NodeSet('node1')
self.handler = ConcreteBaseEventHandler(
- nodes, self.commands, batch_size=len(self.nodes), batch_sleep=0.0,
first_batch=self.nodes)
+ self.nodes, self.commands, batch_size=len(self.nodes),
batch_sleep=0.0, first_batch=self.nodes)
output = 'node1 output'
- self.worker.nodes = clustershell.NodeSet.NodeSet.fromlist(nodes)
- self.worker.current_node = nodes[0]
+ self.worker.nodes = self.nodes
+ self.worker.current_node = self.nodes[0]
self.worker.current_msg = output
self.handler.ev_read(self.worker)
tqdm.write.assert_has_calls([mock.call(output)])
diff --git a/cumin/tests/unit/transports/test_init.py
b/cumin/tests/unit/transports/test_init.py
index 603a72c..bfd762f 100644
--- a/cumin/tests/unit/transports/test_init.py
+++ b/cumin/tests/unit/transports/test_init.py
@@ -3,6 +3,8 @@
import mock
import pytest
+from ClusterShell.NodeSet import NodeSet
+
import cumin # noqa: F401 (dynamically used in TestCommand)
from cumin import transports
@@ -332,7 +334,7 @@
"""Initialize default properties and instances."""
# pylint: disable=attribute-defined-outside-init
self.worker = ConcreteBaseWorker({})
- self.hosts = ['node1', 'node2']
+ self.hosts = NodeSet('node[1-2]')
self.commands = [transports.Command('command1'),
transports.Command('command2')]
def test_hosts_getter(self):
@@ -343,7 +345,7 @@
def test_hosts_setter(self):
"""Raise WorkerError if trying to set it not to an iterable, set it
otherwise."""
- with pytest.raises(transports.WorkerError, match='hosts must be a
list'):
+ with pytest.raises(transports.WorkerError, match="must be an instance
of ClusterShell's NodeSet or None"):
self.worker.hosts = 'not-list'
self.worker.hosts = self.hosts
diff --git a/cumin/transports/__init__.py b/cumin/transports/__init__.py
index 22d5596..fb5c4fe 100644
--- a/cumin/transports/__init__.py
+++ b/cumin/transports/__init__.py
@@ -5,6 +5,8 @@
from abc import ABCMeta, abstractmethod, abstractproperty
+from ClusterShell.NodeSet import NodeSet
+
from cumin import CuminError
@@ -274,9 +276,11 @@
"""Setter for the hosts property with validation, raise WorkerError if
not valid.
Arguments:
- value -- a list of hosts to target for the execution of the commands
+ value -- a ClusterShell.NodeSet.NodeSet instance or None to reset it.
"""
- validate_list('hosts', value)
+ if value is not None and not isinstance(value, NodeSet):
+ raise_error('hosts', "must be an instance of ClusterShell's
NodeSet or None", value)
+
self._hosts = value
@property
diff --git a/cumin/transports/clustershell.py b/cumin/transports/clustershell.py
index 2dbb368..b0a69ff 100644
--- a/cumin/transports/clustershell.py
+++ b/cumin/transports/clustershell.py
@@ -42,7 +42,7 @@
raise RuntimeError('An EventHandler is mandatory.')
# Schedule only the first command for the first batch, the following
ones must be handled by the EventHandler
- first_batch = NodeSet.NodeSet.fromlist(self.hosts[:self.batch_size])
+ first_batch = self.hosts[:self.batch_size]
# Instantiate handler
self._handler_instance = self.handler( # pylint: disable=not-callable
@@ -50,7 +50,7 @@
batch_sleep=self.batch_sleep, logger=self.logger,
first_batch=first_batch)
self.logger.info("Executing commands {commands} on '{num}' hosts:
{hosts}".format(
- commands=self.commands, num=len(self.hosts),
hosts=NodeSet.NodeSet.fromlist(self.hosts)))
+ commands=self.commands, num=len(self.hosts), hosts=self.hosts))
self.task.shell(self.commands[0].command, nodes=first_batch,
handler=self._handler_instance,
timeout=self.commands[0].timeout)
@@ -130,7 +130,7 @@
If subclasses defines a self.pbar_ko tqdm progress bar, it will be
updated on timeout.
Arguments:
- nodes -- the list of nodes with which this worker was initiliazed.
+ nodes -- the ClusterShell's NodeSet with which this worker was
initiliazed.
commands -- the list of Command objects that has to be executed on the
nodes.
**kwargs -- optional additional keyword arguments that might be used
by classes that extend this base class.
"""
--
To view, visit https://gerrit.wikimedia.org/r/366736
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I501b59d1dc2d9bd0c975de7ab5ccfe421c27c9ea
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/cumin
Gerrit-Branch: master
Gerrit-Owner: Volans <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits