diff options
author | Petr Viktorin <pviktori@redhat.com> | 2013-06-27 15:28:13 +0200 |
---|---|---|
committer | Petr Viktorin <pviktori@redhat.com> | 2013-07-25 12:32:35 +0200 |
commit | 13f4b7e9cf8f0f9f0c33775ac8b64d28d9c82323 (patch) | |
tree | d853510dce1287d2366763efe38a6bff0f40015e /ipatests | |
parent | ac70c2cc5cf6434045dcb8c7f54b4b0b59873c47 (diff) | |
download | freeipa-13f4b7e9cf8f0f9f0c33775ac8b64d28d9c82323.tar.gz freeipa-13f4b7e9cf8f0f9f0c33775ac8b64d28d9c82323.tar.xz freeipa-13f4b7e9cf8f0f9f0c33775ac8b64d28d9c82323.zip |
Add install_topo to test tasks
This allows a cluster of replicas and clients to be installed
in a named topology.
Several named topologies are available (star, line, complete, tree,
tree2) and new ones can be defined as a simple function.
Diffstat (limited to 'ipatests')
-rw-r--r-- | ipatests/test_integration/base.py | 11 | ||||
-rw-r--r-- | ipatests/test_integration/host.py | 8 | ||||
-rw-r--r-- | ipatests/test_integration/tasks.py | 145 | ||||
-rw-r--r-- | ipatests/test_integration/test_topologies.py | 98 |
4 files changed, 254 insertions, 8 deletions
diff --git a/ipatests/test_integration/base.py b/ipatests/test_integration/base.py index 86acbcce1..43360a83a 100644 --- a/ipatests/test_integration/base.py +++ b/ipatests/test_integration/base.py @@ -35,7 +35,7 @@ log = log_mgr.get_logger(__name__) class IntegrationTest(object): num_replicas = 0 num_clients = 0 - topology = 'none' + topology = None @classmethod def setup_class(cls): @@ -78,14 +78,11 @@ class IntegrationTest(object): @classmethod def install(cls): - if cls.topology == 'none': + if cls.topology is None: return - elif cls.topology == 'star': - tasks.install_master(cls.master) - for replica in cls.replicas: - tasks.install_replica(cls.master, replica) else: - raise ValueError('Unknown topology %s' % cls.topology) + tasks.install_topo(cls.topology, + cls.master, cls.replicas, cls.clients) @classmethod def teardown_class(cls): diff --git a/ipatests/test_integration/host.py b/ipatests/test_integration/host.py index e3cc4c924..38e6a34e0 100644 --- a/ipatests/test_integration/host.py +++ b/ipatests/test_integration/host.py @@ -162,6 +162,10 @@ class Host(object): self.log_collectors = [] + def __str__(self): + template = ('<{s.__class__.__name__} {s.hostname} ({s.role})>') + return template.format(s=self) + def __repr__(self): template = ('<{s.__module__}.{s.__class__.__name__} ' '{s.hostname} ({s.role})>') @@ -222,9 +226,11 @@ class Host(object): :param raiseonerr: If true, an exception will be raised if the command does not exit with return code 0 """ + assert self.transport + + self._command_index += 1 command = RemoteCommand(self, argv, index=self._command_index, log_stdout=log_stdout) - self._command_index += 1 if cwd is None: cwd = self.config.test_dir diff --git a/ipatests/test_integration/tasks.py b/ipatests/test_integration/tasks.py index ebdd0b813..609df8130 100644 --- a/ipatests/test_integration/tasks.py +++ b/ipatests/test_integration/tasks.py @@ -22,6 +22,8 @@ import os import textwrap import re +import collections +import itertools from ipapython import ipautil from ipapython.ipa_log_manager import log_mgr @@ -234,3 +236,146 @@ def uninstall_client(host): host.run_command(['ipa-client-install', '--uninstall', '-U'], raiseonerr=False) unapply_fixes(host) + + +def get_topo(name_or_func): + """Get a topology function by name + + A topology function receives a master and list of replicas, and yields + (parent, child) pairs, where "child" should be installed from "parent" + (or just connected if already installed) + + If a callable is given instead of name, it is returned directly + """ + if callable(name_or_func): + return name_or_func + return topologies[name_or_func] + + +def _topo(name): + """Decorator that registers a function in topologies under a given name""" + def add_topo(func): + topologies[name] = func + return func + return add_topo +topologies = collections.OrderedDict() + + +@_topo('star') +def star_topo(master, replicas): + r"""All replicas are connected to the master + + Rn R1 R2 + \ | / + R7-- M -- R3 + / | \ + R6 R5 R4 + """ + for replica in replicas: + yield master, replica + + +@_topo('line') +def line_topo(master, replicas): + r"""Line topology + + M + \ + R1 + \ + R2 + \ + R3 + \ + ... + """ + for replica in replicas: + yield master, replica + master = replica + + +@_topo('complete') +def complete_topo(master, replicas): + r"""Each host connected to each other host + + M--R1 + |\/| + |/\| + R2-R3 + """ + for replica in replicas: + yield master, replica + for replica1, replica2 in itertools.combinations(replicas, 2): + yield replica1, replica2 + + +@_topo('tree') +def tree_topo(master, replicas): + r"""Binary tree topology + + M + / \ + / \ + R1 R2 + / \ / \ + R3 R4 R5 R6 + / + R7 ... + + """ + replicas = list(replicas) + + def _masters(): + for host in [master] + replicas: + yield host + yield host + + for parent, child in zip(_masters(), replicas): + yield parent, child + + +@_topo('tree2') +def tree2_topo(master, replicas): + r"""First replica connected directly to master, the rest in a line + + M + / \ + R1 R2 + \ + R3 + \ + R4 + \ + ... + + """ + if replicas: + yield master, replicas[0] + for replica in replicas[1:]: + yield master, replica + master = replica + + +def install_topo(topo, master, replicas, clients, + skip_master=False, setup_replica_cas=True): + """Install IPA servers and clients in the given topology""" + replicas = list(replicas) + installed = {master} + if not skip_master: + install_master(master) + for parent, child in get_topo(topo)(master, replicas): + if child in installed: + log.info('Connecting replica %s to %s' % (parent, child)) + connect_replica(parent, child) + else: + log.info('Installing replica %s from %s' % (parent, child)) + install_replica(parent, child, setup_ca=setup_replica_cas) + installed.add(child) + install_clients([master] + replicas, clients) + + +def install_clients(servers, clients): + """Install IPA clients, distributing them among the given servers""" + for server, client in itertools.izip(itertools.cycle(servers), clients): + log.info('Installing client %s on %s' % (server, client)) + install_client(server, client) diff --git a/ipatests/test_integration/test_topologies.py b/ipatests/test_integration/test_topologies.py new file mode 100644 index 000000000..86ca1904f --- /dev/null +++ b/ipatests/test_integration/test_topologies.py @@ -0,0 +1,98 @@ +# Authors: +# Petr Viktorin <pviktori@redhat.com> +# +# Copyright (C) 2013 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from ipatests.test_integration import tasks + + +def test_topology_star(): + topo = tasks.get_topo('star') + assert topo == tasks.star_topo + assert list(topo('M', [1, 2, 3, 4, 5])) == [ + ('M', 1), + ('M', 2), + ('M', 3), + ('M', 4), + ('M', 5), + ] + assert list(topo('M', [])) == [] + + +def test_topology_line(): + topo = tasks.get_topo('line') + assert topo == tasks.line_topo + assert list(topo('M', [1, 2, 3, 4, 5])) == [ + ('M', 1), + (1, 2), + (2, 3), + (3, 4), + (4, 5), + ] + assert list(topo('M', [])) == [] + + +def test_topology_tree(): + topo = tasks.get_topo('tree') + assert topo == tasks.tree_topo + assert list(topo('M', [1, 2, 3, 4, 5])) == [ + ('M', 1), + ('M', 2), + (1, 3), + (1, 4), + (2, 5), + ] + assert list(topo('M', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) == [ + ('M', 1), + ('M', 2), + (1, 3), + (1, 4), + (2, 5), + (2, 6), + (3, 7), + (3, 8), + (4, 9), + (4, 10), + ] + assert list(topo('M', [])) == [] + + +def test_topology_tree2(): + topo = tasks.get_topo('tree2') + assert topo == tasks.tree2_topo + assert list(topo('M', [1, 2, 3, 4, 5])) == [ + ('M', 1), + ('M', 2), + (2, 3), + (3, 4), + (4, 5), + ] + assert list(topo('M', [])) == [] + + +def test_topology_complete(): + topo = tasks.get_topo('complete') + assert topo == tasks.complete_topo + assert list(topo('M', [1, 2, 3])) == [ + ('M', 1), + ('M', 2), + ('M', 3), + (1, 2), + (1, 3), + (2, 3), + ] + assert list(topo('M', [])) == [] |