mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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.
This commit is contained in:
parent
ac70c2cc5c
commit
13f4b7e9cf
@ -35,7 +35,7 @@ log = log_mgr.get_logger(__name__)
|
|||||||
class IntegrationTest(object):
|
class IntegrationTest(object):
|
||||||
num_replicas = 0
|
num_replicas = 0
|
||||||
num_clients = 0
|
num_clients = 0
|
||||||
topology = 'none'
|
topology = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_class(cls):
|
def setup_class(cls):
|
||||||
@ -78,14 +78,11 @@ class IntegrationTest(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def install(cls):
|
def install(cls):
|
||||||
if cls.topology == 'none':
|
if cls.topology is None:
|
||||||
return
|
return
|
||||||
elif cls.topology == 'star':
|
|
||||||
tasks.install_master(cls.master)
|
|
||||||
for replica in cls.replicas:
|
|
||||||
tasks.install_replica(cls.master, replica)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown topology %s' % cls.topology)
|
tasks.install_topo(cls.topology,
|
||||||
|
cls.master, cls.replicas, cls.clients)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def teardown_class(cls):
|
def teardown_class(cls):
|
||||||
|
@ -162,6 +162,10 @@ class Host(object):
|
|||||||
|
|
||||||
self.log_collectors = []
|
self.log_collectors = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
template = ('<{s.__class__.__name__} {s.hostname} ({s.role})>')
|
||||||
|
return template.format(s=self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
template = ('<{s.__module__}.{s.__class__.__name__} '
|
template = ('<{s.__module__}.{s.__class__.__name__} '
|
||||||
'{s.hostname} ({s.role})>')
|
'{s.hostname} ({s.role})>')
|
||||||
@ -222,9 +226,11 @@ class Host(object):
|
|||||||
:param raiseonerr: If true, an exception will be raised if the command
|
:param raiseonerr: If true, an exception will be raised if the command
|
||||||
does not exit with return code 0
|
does not exit with return code 0
|
||||||
"""
|
"""
|
||||||
|
assert self.transport
|
||||||
|
|
||||||
|
self._command_index += 1
|
||||||
command = RemoteCommand(self, argv, index=self._command_index,
|
command = RemoteCommand(self, argv, index=self._command_index,
|
||||||
log_stdout=log_stdout)
|
log_stdout=log_stdout)
|
||||||
self._command_index += 1
|
|
||||||
|
|
||||||
if cwd is None:
|
if cwd is None:
|
||||||
cwd = self.config.test_dir
|
cwd = self.config.test_dir
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
import os
|
import os
|
||||||
import textwrap
|
import textwrap
|
||||||
import re
|
import re
|
||||||
|
import collections
|
||||||
|
import itertools
|
||||||
|
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
from ipapython.ipa_log_manager import log_mgr
|
from ipapython.ipa_log_manager import log_mgr
|
||||||
@ -234,3 +236,146 @@ def uninstall_client(host):
|
|||||||
host.run_command(['ipa-client-install', '--uninstall', '-U'],
|
host.run_command(['ipa-client-install', '--uninstall', '-U'],
|
||||||
raiseonerr=False)
|
raiseonerr=False)
|
||||||
unapply_fixes(host)
|
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)
|
||||||
|
98
ipatests/test_integration/test_topologies.py
Normal file
98
ipatests/test_integration/test_topologies.py
Normal file
@ -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', [])) == []
|
Loading…
Reference in New Issue
Block a user