summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Fayans <ofayans@redhat.com>2015-08-27 19:19:28 +0200
committerMartin Basti <mbasti@redhat.com>2015-08-28 16:12:25 +0200
commitc7408f67f6cff7bd3ac14b7661472898f8e7dd73 (patch)
treea48c4664fea638b7200cffc03384a78efa46538c
parent0914cb663e6ea72628776e79d93f20bf979c7b68 (diff)
downloadfreeipa-c7408f67f6cff7bd3ac14b7661472898f8e7dd73.tar.gz
freeipa-c7408f67f6cff7bd3ac14b7661472898f8e7dd73.tar.xz
freeipa-c7408f67f6cff7bd3ac14b7661472898f8e7dd73.zip
Integration tests for topology plugin
Reviewed-By: Martin Basti <mbasti@redhat.com> Reviewed-By: Tomas Babej <tbabej@redhat.com>
-rw-r--r--ipatests/test_integration/tasks.py98
-rw-r--r--ipatests/test_integration/test_topology.py148
-rw-r--r--ipatests/test_ipaserver/test_topology_plugin.py16
3 files changed, 241 insertions, 21 deletions
diff --git a/ipatests/test_integration/tasks.py b/ipatests/test_integration/tasks.py
index fc81d46f7..820507022 100644
--- a/ipatests/test_integration/tasks.py
+++ b/ipatests/test_integration/tasks.py
@@ -40,6 +40,24 @@ from ipatests.test_integration.host import Host
log = log_mgr.get_logger(__name__)
+def check_arguments_are(slice, instanceof):
+ """
+ :param: slice - tuple of integers denoting the beginning and the end
+ of argument list to be checked
+ :param: instanceof - name of the class the checked arguments should be
+ instances of
+ Example: @check_arguments_are((1, 3), int) will check that the second
+ and third arguments are integers
+ """
+ def wrapper(func):
+ def wrapped(*args):
+ for i in args[slice[0]:slice[1]]:
+ assert isinstance(i, instanceof), "Wrong type: %s: %s" % (i, type(i))
+ return func(*args)
+ return wrapped
+ return wrapper
+
+
def prepare_host(host):
if isinstance(host, Host):
env_filename = os.path.join(host.config.test_dir, 'env.sh')
@@ -118,7 +136,8 @@ def fix_apache_semaphores(master):
if systemd_available:
master.run_command(['systemctl', 'stop', 'httpd'], raiseonerr=False)
else:
- master.run_command([paths.SBIN_SERVICE, 'httpd', 'stop'], raiseonerr=False)
+ master.run_command([paths.SBIN_SERVICE, 'httpd', 'stop'],
+ raiseonerr=False)
master.run_command('for line in `ipcs -s | grep apache | cut -d " " -f 2`; '
'do ipcrm -s $line; done', raiseonerr=False)
@@ -261,7 +280,7 @@ def install_client(master, client, extra_args=()):
'-p', client.config.admin_name,
'-w', client.config.admin_password,
'--server', master.hostname]
- + list(extra_args))
+ + list(extra_args))
setup_sssd_debugging(client)
kinit_admin(client)
@@ -298,10 +317,9 @@ def install_adtrust(host):
else:
host.run_command(['systemctl', 'restart', 'named'])
-
# Check that named is running and has loaded the information from LDAP
dig_command = ['dig', 'SRV', '+short', '@localhost',
- '_ldap._tcp.%s' % host.domain.name]
+ '_ldap._tcp.%s' % host.domain.name]
dig_output = '0 100 389 %s.' % host.hostname
dig_test = lambda x: re.search(re.escape(dig_output), x)
@@ -373,9 +391,9 @@ def establish_trust_with_ad(master, ad, extra_args=()):
master.run_command(['smbcontrol', 'all', 'debug', '100'])
util.run_repeatedly(master,
['ipa', 'trust-add',
- '--type', 'ad', ad.domain.name,
- '--admin', 'Administrator',
- '--password'] + list(extra_args),
+ '--type', 'ad', ad.domain.name,
+ '--admin', 'Administrator',
+ '--password'] + list(extra_args),
stdin_text=master.config.ad_admin_password)
master.run_command(['smbcontrol', 'all', 'debug', '1'])
clear_sssd_cache(master)
@@ -428,15 +446,14 @@ def setup_sssd_debugging(host):
# First, remove any previous occurences
host.run_command(['sed', '-i',
'/debug_level = 7/d',
- paths.SSSD_CONF
- ], raiseonerr=False)
+ paths.SSSD_CONF],
+ raiseonerr=False)
# Add the debug directive to each section
host.run_command(['sed', '-i',
'/\[*\]/ a\debug_level = 7',
- paths.SSSD_CONF
- ], raiseonerr=False)
-
+ paths.SSSD_CONF],
+ raiseonerr=False)
host.collect_log('/var/log/sssd/*')
@@ -492,7 +509,7 @@ def disconnect_replica(master, replica):
def kinit_admin(host):
host.run_command(['kinit', 'admin'],
- stdin_text=host.config.admin_password)
+ stdin_text=host.config.admin_password)
def uninstall_master(host):
@@ -507,8 +524,9 @@ def uninstall_master(host):
paths.SYSCONFIG_PKI_TOMCAT,
paths.SYSCONFIG_PKI_TOMCAT_PKI_TOMCAT_DIR,
paths.VAR_LIB_PKI_TOMCAT_DIR,
- paths.PKI_TOMCAT],
- raiseonerr=False)
+ paths.PKI_TOMCAT,
+ paths.REPLICA_INFO_GPG_TEMPLATE % host.hostname],
+ raiseonerr=False)
unapply_fixes(host)
@@ -520,6 +538,56 @@ def uninstall_client(host):
unapply_fixes(host)
+@check_arguments_are((0, 2), Host)
+def clean_replication_agreement(master, replica):
+ """
+ Performs `ipa-replica-manage del replica_hostname --force`.
+ """
+ master.run_command(['ipa-replica-manage',
+ 'del',
+ replica.hostname,
+ '--force'])
+
+
+@check_arguments_are((0, 3), Host)
+def create_segment(master, leftnode, rightnode):
+ """
+ creates a topology segment. The first argument is a node to run the command
+ :returns: a hash object containing segment's name, leftnode, rightnode
+ information and an error string.
+ """
+ kinit_admin(master)
+ lefthost = leftnode.hostname
+ righthost = rightnode.hostname
+ segment_name = "%s-to-%s" % (lefthost, righthost)
+ result = master.run_command(["ipa", "topologysegment-add", "realm",
+ segment_name,
+ "--leftnode=%s" % lefthost,
+ "--rightnode=%s" % righthost], raiseonerr=False)
+ if result.returncode == 0:
+ return {'leftnode': lefthost,
+ 'rightnode': righthost,
+ 'name': segment_name}, ""
+ else:
+ return {}, result.stderr_text
+
+
+def destroy_segment(master, segment_name):
+ """
+ Destroys topology segment.
+ :param master: reference to master object of class Host
+ :param segment_name: name of the segment to be created
+ """
+ assert isinstance(master, Host), "master should be an instance of Host"
+ kinit_admin(master)
+ command = ["ipa",
+ "topologysegment-del",
+ "realm",
+ segment_name]
+ result = master.run_command(command, raiseonerr=False)
+ return result.returncode, result.stderr_text
+
+
def get_topo(name_or_func):
"""Get a topology function by name
diff --git a/ipatests/test_integration/test_topology.py b/ipatests/test_integration/test_topology.py
new file mode 100644
index 000000000..0d304fcb3
--- /dev/null
+++ b/ipatests/test_integration/test_topology.py
@@ -0,0 +1,148 @@
+#
+# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
+#
+
+import re
+import time
+
+from ipatests.test_integration.base import IntegrationTest
+from ipatests.test_integration import tasks
+
+
+class TestTopologyOptions(IntegrationTest):
+ num_replicas = 2
+ topology = 'star'
+ rawsegment_re = ('Segment name: (?P<name>.*?)',
+ '\s+Left node: (?P<lnode>.*?)',
+ '\s+Right node: (?P<rnode>.*?)',
+ '\s+Connectivity: (?P<connectivity>\S+)')
+ segment_re = re.compile("\n".join(rawsegment_re))
+ noentries_re = re.compile("Number of entries returned (\d+)")
+
+ @classmethod
+ def install(cls, mh):
+ tasks.install_topo(cls.topology, cls.master,
+ cls.replicas[:-1],
+ cls.clients)
+
+ def tokenize_topologies(self, command_output):
+ """
+ takes an output of `ipa topologysegment-find` and returns an array of
+ segment hashes
+ """
+ segments = command_output.split("-----------------")[2]
+ raw_segments = segments.split('\n\n')
+ result = []
+ for i in raw_segments:
+ matched = self.segment_re.search(i)
+ if matched:
+ result.append({'leftnode': matched.group('lnode'),
+ 'rightnode': matched.group('rnode'),
+ 'name': matched.group('name'),
+ 'connectivity': matched.group('connectivity')
+ }
+ )
+ return result
+
+ def test_topology_updated_on_replica_install_remove(self):
+ """
+ Install and remove a replica and make sure topology information is
+ updated on all other replicas
+ Testcase: http://www.freeipa.org/page/V4/Manage_replication_topology/
+ Test_plan#Test_case:
+ _Replication_topology_should_be_saved_in_the_LDAP_tree
+ """
+ tasks.kinit_admin(self.master)
+ result1 = self.master.run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ first_segment_name = "%s-to-%s" % (self.master.hostname,
+ self.replicas[0].hostname)
+ output1 = result1.stdout_text
+ firstsegment = self.tokenize_topologies(output1)[0]
+ assert(firstsegment['name'] == first_segment_name)
+ assert(self.noentries_re.search(output1).group(1) == "1")
+ assert(firstsegment['leftnode'] == self.master.hostname)
+ assert(firstsegment['rightnode'] == self.replicas[0].hostname)
+ tasks.install_replica(self.master, self.replicas[1], setup_ca=False,
+ setup_dns=False)
+ # We need to make sure topology information is consistent across all
+ # replicas
+ result2 = self.master.run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ result3 = self.replicas[0].run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ result4 = self.replicas[1].run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ segments = self.tokenize_topologies(result2.stdout_text)
+ assert(len(segments) == 2)
+ assert(result2.stdout_text == result3.stdout_text)
+ assert(result3.stdout_text == result4.stdout_text)
+ # Now let's check that uninstalling the replica will update the topology
+ # info on the rest of replicas.
+ tasks.uninstall_master(self.replicas[1])
+ tasks.clean_replication_agreement(self.master, self.replicas[1])
+ result5 = self.master.run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ assert(self.noentries_re.search(result5.stdout_text).group(1) == "1")
+
+ def test_add_remove_segment(self):
+ """
+ Make sure a topology segment can be manually created and deleted
+ with the influence on the real topology
+ Testcase http://www.freeipa.org/page/V4/Manage_replication_topology/
+ Test_plan#Test_case:_Basic_CRUD_test
+ """
+ tasks.kinit_admin(self.master)
+ # Install the second replica
+ tasks.install_replica(self.master, self.replicas[1], setup_ca=False,
+ setup_dns=False)
+ # turn a star into a ring
+ segment, err = tasks.create_segment(self.master,
+ self.replicas[0],
+ self.replicas[1])
+ assert err == "", err
+ # Make sure the new segment is shown by `ipa topologysegment-find`
+ result1 = self.master.run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ assert(result1.stdout_text.find(segment['name']) > 0)
+ # Remove master <-> replica2 segment and make sure that the changes get
+ # there through replica1
+ deleteme = "%s-to-%s" % (self.master.hostname,
+ self.replicas[1].hostname)
+ returncode, error = tasks.destroy_segment(self.master, deleteme)
+ assert returncode == 0, error
+ # make sure replica1 does not have segment that was deleted on master
+ result3 = self.replicas[0].run_command(['ipa', 'topologysegment-find',
+ 'realm'])
+ assert(result3.stdout_text.find(deleteme) < 0)
+ # Create test data on master and make sure it gets all the way down to
+ # replica2 through replica1
+ self.master.run_command(['ipa', 'user-add', 'someuser',
+ '--first', 'test',
+ '--last', 'user'])
+ time.sleep(60) # replication requires some time
+ users_on_replica2 = self.replicas[1].run_command(['ipa',
+ 'user-find'])
+ assert(users_on_replica2.find('someuser') > 0)
+ # We end up having a line topology: master <-> replica1 <-> replica2
+
+ def test_remove_the_only_connection(self):
+ """
+ Testcase: http://www.freeipa.org/page/V4/Manage_replication_topology/
+ Test_plan#Test_case:
+ _Removal_of_a_topology_segment_is_allowed_only_if_there_is_at_least_one_more_segment_connecting_the_given_replica
+ """
+ text = "Removal of Segment disconnects topology"
+ error1 = "The system should not have let you remove the segment"
+ error2 = "Wrong error message thrown during segment removal: \"%s\""
+ replicas = (self.replicas[0].hostname, self.replicas[1].hostname)
+
+ returncode, error = tasks.destroy_segment(self.master, "%s-to-%s" % replicas)
+ assert returncode != 0, error1
+ assert error.count(text) == 1, error2 % error
+ newseg, err = tasks.create_segment(self.master,
+ self.master,
+ self.replicas[1])
+ assert err == "", err
+ returncode, error = tasks.destroy_segment(self.master, "%s-to-%s" % replicas)
+ assert returncode == 0, error
diff --git a/ipatests/test_ipaserver/test_topology_plugin.py b/ipatests/test_ipaserver/test_topology_plugin.py
index 667897499..b162822e0 100644
--- a/ipatests/test_ipaserver/test_topology_plugin.py
+++ b/ipatests/test_ipaserver/test_topology_plugin.py
@@ -2,18 +2,23 @@
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
#
+import io
import os
from ipaserver.plugins.ldap2 import ldap2
from ipalib import api
from ipapython import ipautil
from ipapython.dn import DN
-import nose
+import pytest
class TestTopologyPlugin(object):
"""
Test Topology plugin from the DS point of view
+ Testcase: http://www.freeipa.org/page/V4/Manage_replication_topology/
+ Test_plan#Test_case:
+ _Replication_Topology_is_listed_among_directory_server_plugins
"""
+ pwfile = os.path.join(api.env.dot_ipa, ".dmpw")
def setup(self):
"""
@@ -25,6 +30,8 @@ class TestTopologyPlugin(object):
if self.conn and self.conn.isconnected():
self.conn.disconnect()
+ @pytest.mark.skipif(ipautil.file_exists(pwfile) is False,
+ reason="You did not provide a .dmpw file with the DM password")
def test_topologyplugin(self):
pluginattrs = {
u'nsslapd-pluginPath': [u'libtopology'],
@@ -56,11 +63,8 @@ class TestTopologyPlugin(object):
('cn', 'plugins'),
('cn', 'config'))
pwfile = os.path.join(api.env.dot_ipa, ".dmpw")
- if ipautil.file_exists(pwfile):
- with open(pwfile, "r") as f:
- dm_password = f.read().rstrip()
- else:
- raise nose.SkipTest("No directory manager password in %s" % pwfile)
+ with io.open(pwfile, "r") as f:
+ dm_password = f.read().rstrip()
self.conn = ldap2(api)
self.conn.connect(bind_dn=DN(('cn', 'directory manager')),
bind_pw=dm_password)