Allow selecting nodes by group name regular expression
Change-Id: Icf1dd91a5c1d3052a258b42fa4460533a251d448
This commit is contained in:
parent
81618412de
commit
6258ec1e7c
@ -15,7 +15,7 @@ from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import re
|
||||
import typing # noqa
|
||||
import typing
|
||||
import weakref
|
||||
|
||||
import netaddr
|
||||
@ -40,21 +40,31 @@ from tobiko.openstack.topology import _exception
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def list_openstack_nodes(topology=None, group=None, hostnames=None, **kwargs):
|
||||
PatternType = type(re.compile(r'.*'))
|
||||
OpenstackGroupNameType = typing.Union[str, typing.Pattern]
|
||||
OpenstackGroupNamesType = typing.Union[OpenstackGroupNameType, typing.Iterable[
|
||||
OpenstackGroupNameType]]
|
||||
|
||||
|
||||
def list_openstack_nodes(topology: 'OpenStackTopology' = None,
|
||||
group: OpenstackGroupNamesType = None,
|
||||
hostnames=None, **kwargs):
|
||||
topology = topology or get_openstack_topology()
|
||||
if group is None:
|
||||
nodes = topology.nodes
|
||||
elif isinstance(group, str):
|
||||
nodes = topology.get_group(group=group)
|
||||
elif isinstance(group, PatternType):
|
||||
nodes = topology.get_groups(groups=[group])
|
||||
else:
|
||||
assert isinstance(group, collections.Iterable)
|
||||
nodes = topology.get_groups(groups=group)
|
||||
|
||||
if hostnames:
|
||||
names = {node_name_from_hostname(hostname)
|
||||
for hostname in hostnames}
|
||||
nodes = [node
|
||||
for node in nodes
|
||||
if node.name in names]
|
||||
nodes = nodes.select(lambda node: node.name in names)
|
||||
|
||||
if kwargs:
|
||||
nodes = nodes.with_attributes(**kwargs)
|
||||
return nodes
|
||||
@ -412,18 +422,29 @@ class OpenStackTopology(tobiko.SharedFixture):
|
||||
def create_group() -> tobiko.Selection[OpenStackTopologyNode]:
|
||||
return tobiko.Selection()
|
||||
|
||||
def get_group(self, group) -> tobiko.Selection[OpenStackTopologyNode]:
|
||||
def get_group(self, group: str) \
|
||||
-> tobiko.Selection[OpenStackTopologyNode]:
|
||||
tobiko.check_valid_type(group, str)
|
||||
try:
|
||||
return self._groups[group]
|
||||
return tobiko.Selection(self._groups[group])
|
||||
except KeyError as ex:
|
||||
raise _exception.NoSuchOpenStackTopologyNodeGroup(
|
||||
group=group) from ex
|
||||
|
||||
def get_groups(self, groups) -> tobiko.Selection[OpenStackTopologyNode]:
|
||||
nodes: tobiko.Selection[OpenStackTopologyNode] = tobiko.Selection()
|
||||
for group in groups:
|
||||
nodes.extend(self.get_group(group))
|
||||
return nodes
|
||||
def list_group_names(self,
|
||||
*matchers: 'MatchStringType') \
|
||||
-> typing.List[str]:
|
||||
group_names: typing.List[str] = list(self._groups.keys())
|
||||
if matchers and group_names:
|
||||
group_names = match_strings(group_names, *matchers)
|
||||
return group_names
|
||||
|
||||
def get_groups(self, groups: typing.Iterable['MatchStringType']) -> \
|
||||
tobiko.Selection[OpenStackTopologyNode]:
|
||||
node_names: typing.Set[str] = set()
|
||||
for group in self.list_group_names(*groups):
|
||||
node_names.update(node.name for node in self.get_group(group))
|
||||
return self.nodes.select(lambda node: node.name in node_names)
|
||||
|
||||
@property
|
||||
def groups(self) -> typing.List[str]:
|
||||
@ -600,3 +621,23 @@ def skip_unless_osp_version(version, higher=False, lower=False):
|
||||
skip_msg = "OSP version doesn't match the requirement"
|
||||
return tobiko.skip_unless(skip_msg, verify_osp_version,
|
||||
version, higher, lower)
|
||||
|
||||
|
||||
MatchStringType = typing.Union[str, typing.Pattern]
|
||||
|
||||
|
||||
def match_strings(strings: typing.Iterable[str],
|
||||
*matchers: MatchStringType) -> \
|
||||
typing.List[str]:
|
||||
matching: typing.List[str] = []
|
||||
for matcher in matchers:
|
||||
tobiko.check_valid_type(matcher, str, PatternType)
|
||||
if isinstance(matcher, str):
|
||||
if matcher in strings:
|
||||
matching.append(matcher)
|
||||
else:
|
||||
assert isinstance(matcher, PatternType)
|
||||
for string in strings:
|
||||
if matcher.match(string):
|
||||
matching.append(string)
|
||||
return matching
|
||||
|
@ -15,7 +15,9 @@
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import random
|
||||
import re
|
||||
|
||||
import testtools
|
||||
|
||||
@ -27,6 +29,9 @@ from tobiko.shell import ping
|
||||
from tobiko.shell import sh
|
||||
|
||||
|
||||
PatternType = type(re.compile(r''))
|
||||
|
||||
|
||||
@keystone.skip_unless_has_keystone_credentials()
|
||||
class OpenStackTopologyTest(testtools.TestCase):
|
||||
|
||||
@ -74,9 +79,23 @@ class OpenStackTopologyTest(testtools.TestCase):
|
||||
nodes = topology.list_openstack_nodes(
|
||||
topology=self.topology, group=group, hostnames=hostnames)
|
||||
self.assertTrue(set(nodes).issubset(set(self.topology.nodes)))
|
||||
self.assertEqual(len(set(nodes)), len(nodes),
|
||||
f"Repeated node found: {nodes}")
|
||||
for node in nodes:
|
||||
if group:
|
||||
if isinstance(group, str):
|
||||
self.assertIn(group, node.groups)
|
||||
elif isinstance(group, PatternType):
|
||||
for actual_group in node.groups:
|
||||
if group.match(actual_group):
|
||||
break
|
||||
else:
|
||||
self.fail(f"Any node {node.name} group matches "
|
||||
f"'{group}': {node.groups}")
|
||||
elif isinstance(group, collections.Iterable):
|
||||
matching_groups = set(group) & set(node.groups)
|
||||
self.assertNotEqual(set(), matching_groups,
|
||||
f"Any group of node {node.name} "
|
||||
f"matches '{group}': {node.groups}")
|
||||
if hostnames:
|
||||
hostnames = [node_name_from_hostname(h)
|
||||
for h in hostnames]
|
||||
@ -84,7 +103,27 @@ class OpenStackTopologyTest(testtools.TestCase):
|
||||
return nodes
|
||||
|
||||
def test_list_openstack_topology_with_group(self):
|
||||
self.test_list_openstack_topology(group='compute')
|
||||
group = self.topology.groups[0]
|
||||
expected_nodes = set(self.topology.get_group(group))
|
||||
actual_nodes = set(self.test_list_openstack_topology(group=group))
|
||||
self.assertEqual(expected_nodes, actual_nodes)
|
||||
|
||||
def test_list_openstack_topology_with_group_pattern(self):
|
||||
groups = list(self.topology.groups)[:2]
|
||||
pattern = re.compile('|'.join(groups))
|
||||
expected_nodes = set()
|
||||
for group in groups:
|
||||
expected_nodes.update(self.topology.get_group(group))
|
||||
actual_nodes = set(self.test_list_openstack_topology(group=pattern))
|
||||
self.assertEqual(expected_nodes, actual_nodes)
|
||||
|
||||
def test_list_openstack_topology_with_groups(self):
|
||||
groups = list(self.topology.groups)[:2]
|
||||
expected_nodes = set()
|
||||
for group in groups:
|
||||
expected_nodes.update(self.topology.get_group(group))
|
||||
actual_nodes = set(self.test_list_openstack_topology(group=groups))
|
||||
self.assertEqual(expected_nodes, actual_nodes)
|
||||
|
||||
def test_list_openstack_topology_with_hostnames(self):
|
||||
expected_nodes = self.topology.nodes[0::2]
|
||||
|
Loading…
Reference in New Issue
Block a user