mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-26 08:51:50 -06:00
c91a1a078a
Samba 4.13+ in Fedora 33+ and RHEL 8.4+ defaults to Kerberos authentication. This means user name used for authentication must be mapped to a target realm. We have to remove trust on AD side first before removing it locally or otherwise MIT Kerberos might not be able to locate DCs from AD as removal of the trust information would cause SSSD to clear the details for a KDC locator plugin as well. For the test that modifies AD DNS zone on IPA side to inject unreachable DCs addresses, the configuration has to be reverted first, to allow plain 'kinit' during removal of trust to reach AD DCs directly. Fixes: https://pagure.io/freeipa/issue/8678 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
457 lines
18 KiB
Python
Executable File
457 lines
18 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
# 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 __future__ import print_function
|
|
|
|
import logging
|
|
import sys
|
|
import os
|
|
import argparse
|
|
|
|
from ipapython.ipa_log_manager import standard_logging_setup
|
|
from ipatests.pytest_ipa.integration import config
|
|
from ipatests.pytest_ipa.integration import tasks
|
|
from ipatests.pytest_ipa.integration.host import Host
|
|
from ipatests.pytest_ipa.integration import collect_logs
|
|
|
|
try:
|
|
from pytest_beakerlib import BeakerLibProcess
|
|
except ImportError:
|
|
BeakerLibProcess = None
|
|
|
|
logger = logging.getLogger(os.path.basename(__file__))
|
|
|
|
|
|
class TaskRunner(object):
|
|
def __init__(self):
|
|
self._prepared_hosts = set()
|
|
|
|
def get_parser(self):
|
|
parser = argparse.ArgumentParser(
|
|
description="Perform an operation for integration testing. "
|
|
"All operations are performed on configured hosts, see "
|
|
"http://www.freeipa.org/page/V3/Integration_testing "
|
|
"for configuration details")
|
|
|
|
parser.add_argument('--with-beakerlib', action='store_true',
|
|
dest='with_beakerlib',
|
|
help="""Issue BeakerLib commands for logging
|
|
and log collection""")
|
|
|
|
parser.add_argument('--logfile-dir', dest='logfile_dir',
|
|
help="""Directory to collect logs in""")
|
|
|
|
subparsers = parser.add_subparsers(
|
|
metavar='SUBCOMMAND',
|
|
help='The action to perform (* indicates an idempotent operation)')
|
|
|
|
subparser = subparsers.add_parser(
|
|
'install-topo',
|
|
help='Install IPA in a given topology')
|
|
subparser.add_argument('topo',
|
|
metavar='TOPO',
|
|
help='Desired topology '
|
|
'(see `ipa-test-task list-topos` for details)',
|
|
choices=tasks.topologies)
|
|
subparser.add_argument('--skip-master', action='store_true',
|
|
help='Skip installing master')
|
|
subparser.add_argument('--skip-clients', action='store_true',
|
|
help='Skip installing clients')
|
|
subparser.add_argument('--master', type=str,
|
|
help='Master to use (Default: from config)')
|
|
subparser.add_argument('--replicas', type=str, nargs='*',
|
|
help='Replicas to install (Default: from config)')
|
|
subparser.add_argument('--clients', type=str, nargs='*',
|
|
help='Clients to install (Default: from config)')
|
|
subparser.set_defaults(func=self.install_topo)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'list-topos',
|
|
help='List the available topologies')
|
|
subparser.set_defaults(func=self.list_topos)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'install-master',
|
|
help='Install IPA on the master')
|
|
subparser.add_argument('--host', type=str,
|
|
help='Host to use (Default: from config)')
|
|
subparser.set_defaults(func=self.install_master)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'install-replica',
|
|
help='Install an IPA replica')
|
|
subparser.add_argument('replica', type=str,
|
|
help='Replica to install')
|
|
subparser.add_argument('--master', type=str,
|
|
help="""Master to replicate from
|
|
(Default: from config)""")
|
|
subparser.set_defaults(func=self.install_replica)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'install-client',
|
|
help='Install an IPA client')
|
|
subparser.add_argument('client', type=str,
|
|
help='Client to install')
|
|
subparser.add_argument('--master', type=str,
|
|
help="""Master to replicate from
|
|
(Default: from config)""")
|
|
subparser.set_defaults(func=self.install_client)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'connect-replica',
|
|
help='Connect two IPA masters')
|
|
subparser.add_argument('host1', type=str,
|
|
help='First replica to connect')
|
|
subparser.add_argument('host2', type=str,
|
|
help='Second replica to connect')
|
|
subparser.set_defaults(func=self.connect_replica)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'disconnect-replica',
|
|
help='Disconnect two IPA masters')
|
|
subparser.add_argument('host1', type=str,
|
|
help='First replica to disconnect')
|
|
subparser.add_argument('host2', type=str,
|
|
help='Second replica to disconnect')
|
|
subparser.set_defaults(func=self.disconnect_replica)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'uninstall-server',
|
|
help='Uninstall IPA server *')
|
|
subparser.add_argument('host', type=str, nargs='*',
|
|
help="""Host to use
|
|
(Default: master and all replicas
|
|
from config)""")
|
|
subparser.set_defaults(func=self.uninstall_master)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'uninstall-client',
|
|
help='Uninstall IPA client *')
|
|
subparser.add_argument('host', type=str, nargs='*',
|
|
help="""Host to use
|
|
(Default: all clients from config)""")
|
|
subparser.set_defaults(func=self.uninstall_client)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'uninstall-all',
|
|
help='Uninstall all hosts, according to config *')
|
|
subparser.set_defaults(func=self.uninstall_all, host=None)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'cleanup',
|
|
help='Clean up a host *')
|
|
subparser.add_argument('host', type=str, nargs='*',
|
|
help="""Host to clean up
|
|
(Default: all hosts from config)""")
|
|
subparser.set_defaults(func=self.cleanup)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'install-adtrust',
|
|
help='Runs ipa-adtrust-install on the host')
|
|
subparser.add_argument('host', type=str,
|
|
help='Host to run ipa-adtrust-install on')
|
|
subparser.set_defaults(func=self.install_adtrust)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'configure-dns-for-trust',
|
|
help='Sets DNS on the given host for trust with the given AD')
|
|
subparser.add_argument('host', type=str,
|
|
help='Host to change DNS configuration on')
|
|
subparser.add_argument('ad', type=str,
|
|
help='AD that trust will be established with')
|
|
subparser.set_defaults(func=self.configure_dns_for_trust)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'establish-trust-with-ad',
|
|
help='Establishes trust between IPA host and AD')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to establish AD trust on')
|
|
subparser.add_argument('ad', type=str,
|
|
help='AD to establish trust with')
|
|
subparser.set_defaults(func=self.establish_trust_with_ad)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'remove-trust-with-ad',
|
|
help='Removes trust between IPA host and AD')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to remove AD trust on')
|
|
subparser.add_argument('ad', type=str,
|
|
help='AD to remove trust with')
|
|
subparser.set_defaults(func=self.remove_trust_with_ad)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'configure-auth-to-local-rule',
|
|
help='Configures auth_to_local rule on IPA host with respect to AD')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to configure auth_to_local rule on')
|
|
subparser.add_argument('ad', type=str,
|
|
help='AD to configure the rule with')
|
|
subparser.set_defaults(func=self.configure_auth_to_local_rule)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'clear-sssd-cache',
|
|
help='Clears SSSD cache on the IPA host.')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to clear SSSD cache on')
|
|
subparser.set_defaults(func=self.clear_sssd_cache)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'setup-sssd-debugging',
|
|
help='Turns on SSSD debugging levels.')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to turn SSSD debugging on')
|
|
subparser.set_defaults(func=self.setup_sssd_debugging)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'sync-time',
|
|
help='Synchronize time on host with respect to server')
|
|
subparser.add_argument('host', type=str,
|
|
help='IPA Host to set the time on')
|
|
subparser.add_argument('server', type=str,
|
|
help='Server that serves as a time source')
|
|
subparser.set_defaults(func=self.sync_time)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'add-a-records-in-master-domain',
|
|
help='Adds A records to the IPA master for all the hosts in the '
|
|
'master domain.')
|
|
subparser.add_argument('master', type=str,
|
|
help='IPA master to add records on')
|
|
subparser.set_defaults(
|
|
func=self.add_a_records_for_hosts_in_master_domain)
|
|
|
|
subparser = subparsers.add_parser(
|
|
'add-a-record',
|
|
help='Adds A record for the host to the IPA master')
|
|
subparser.add_argument('master', type=str,
|
|
help='IPA master to add record on')
|
|
subparser.add_argument('host', type=str,
|
|
help='Host whose record should be added')
|
|
subparser.set_defaults(func=self.add_a_record)
|
|
|
|
return parser
|
|
|
|
def main(self, argv):
|
|
parser = self.get_parser()
|
|
args = parser.parse_args(argv)
|
|
self.config = config.Config.from_env(os.environ)
|
|
if not self.config:
|
|
raise EnvironmentError('Multihost environment not configured')
|
|
|
|
logs_to_collect = {}
|
|
|
|
def collect_log(host, filename):
|
|
logs_to_collect.setdefault(host, []).append(filename)
|
|
|
|
self.collect_log = collect_log
|
|
|
|
if args.with_beakerlib:
|
|
if BeakerLibProcess is None:
|
|
parser.error(
|
|
'pytest_beakerlib not installed, cannot use BeakerLib')
|
|
beakerlib_process = BeakerLibProcess()
|
|
args.verbose = True
|
|
|
|
standard_logging_setup(
|
|
console_format='%(name)s: %(levelname)s: %(message)s',
|
|
debug=True)
|
|
|
|
if not self.config.domains:
|
|
raise SystemExit('No configuration available')
|
|
|
|
args.domain = self.config.domains[0]
|
|
|
|
if self.config.ad_domains:
|
|
args.ad_domain = self.config.ad_domains[0]
|
|
else:
|
|
args.ad_domain = None
|
|
|
|
import logging; logging.basicConfig()
|
|
|
|
try:
|
|
return args.func(args)
|
|
except Exception as e:
|
|
if args.with_beakerlib:
|
|
beakerlib_process.log_exception()
|
|
beakerlib_process.run_beakerlib_command(
|
|
['rlFail', 'Unhandled exception'])
|
|
raise
|
|
finally:
|
|
if args.with_beakerlib:
|
|
collect_logs('ipa-test-task', logs_to_collect,
|
|
logfile_dir=args.logfile_dir,
|
|
beakerlib_plugin=beakerlib_process)
|
|
beakerlib_process.end()
|
|
for host in self._prepared_hosts:
|
|
host.remove_log_collector(self.collect_log)
|
|
|
|
def get_host(self, host_name, default=None):
|
|
if host_name is None:
|
|
host = default
|
|
else:
|
|
host = self.config.host_by_name(host_name)
|
|
return self.prepare_host(host)
|
|
|
|
def get_hosts(self, host_names, default=()):
|
|
if host_names is None:
|
|
host_names = ()
|
|
hosts = [self.get_host(host_name) for host_name in host_names]
|
|
if hosts:
|
|
return hosts
|
|
else:
|
|
return [self.prepare_host(h) for h in default]
|
|
|
|
def prepare_host(self, host):
|
|
# Prepare only UNIX hosts
|
|
if host not in self._prepared_hosts and isinstance(host, Host):
|
|
host.add_log_collector(self.collect_log)
|
|
tasks.prepare_host(host)
|
|
self._prepared_hosts.add(host)
|
|
return host
|
|
|
|
def require_ad_domain(self, args):
|
|
if not args.ad_domain:
|
|
SystemExit("At least one AD domain is required for this task")
|
|
|
|
def install_master(self, args):
|
|
master = self.get_host(args.host, default=args.domain.master)
|
|
logger.info('Installing master %s', master.hostname)
|
|
tasks.install_master(master)
|
|
|
|
def install_replica(self, args):
|
|
replica = self.get_host(args.replica)
|
|
master = self.get_host(args.master, default=args.domain.master)
|
|
logger.info('Installing replica %s from %s',
|
|
replica.hostname, master.hostname)
|
|
tasks.install_replica(master, replica)
|
|
|
|
def install_client(self, args):
|
|
client = self.get_host(args.client)
|
|
master = self.get_host(args.master, default=args.domain.master)
|
|
logger.info('Installing client %s on %s',
|
|
client.hostname, master.hostname)
|
|
tasks.install_client(master, client)
|
|
|
|
def uninstall_master(self, args):
|
|
default_hosts = [args.domain.master] + args.domain.replicas
|
|
hosts = self.get_hosts(args.host, default=default_hosts)
|
|
logger.info('Uninstalling masters: %s', [h.hostname for h in hosts])
|
|
for master in hosts:
|
|
logger.info('Uninstalling %s', master.hostname)
|
|
tasks.uninstall_master(master)
|
|
|
|
def uninstall_client(self, args):
|
|
default_hosts = args.domain.clients
|
|
hosts = self.get_hosts(args.host, default=default_hosts)
|
|
logger.info('Uninstalling clients: %s', [h.hostname for h in hosts])
|
|
for client in hosts:
|
|
logger.info('Uninstalling %s', client.hostname)
|
|
tasks.uninstall_client(client)
|
|
|
|
def uninstall_all(self, args):
|
|
self.uninstall_master(args)
|
|
self.uninstall_client(args)
|
|
|
|
def cleanup(self, args):
|
|
default_hosts = args.domain.hosts
|
|
hosts = self.get_hosts(args.host, default=default_hosts)
|
|
logger.info('Cleaning up hosts: %s', [h.hostname for h in hosts])
|
|
for host in hosts:
|
|
logger.info('Cleaning up %s', host.hostname)
|
|
tasks.unapply_fixes(host)
|
|
|
|
def connect_replica(self, args):
|
|
host1 = self.get_host(args.host1)
|
|
host2 = self.get_host(args.host2)
|
|
tasks.connect_replica(host1, host2)
|
|
|
|
def disconnect_replica(self, args):
|
|
host1 = self.get_host(args.host1)
|
|
host2 = self.get_host(args.host2)
|
|
tasks.disconnect_replica(host1, host2)
|
|
|
|
def list_topos(self, args):
|
|
for name, topo in tasks.topologies.items():
|
|
print('%s: %s' % (name, topo.__doc__))
|
|
|
|
def install_topo(self, args):
|
|
master = self.get_host(args.master, default=args.domain.master)
|
|
replicas = self.get_hosts(args.replicas, default=args.domain.replicas)
|
|
clients = self.get_hosts(args.clients, default=args.domain.clients)
|
|
if args.skip_clients:
|
|
clients = []
|
|
tasks.install_topo(args.topo, master, replicas, clients,
|
|
skip_master=args.skip_master)
|
|
|
|
def install_adtrust(self, args):
|
|
master = self.get_host(args.host, default=args.domain.master)
|
|
logger.info('Configuring AD trust support on %s', master.hostname)
|
|
tasks.install_adtrust(master)
|
|
|
|
def configure_dns_for_trust(self, args):
|
|
self.require_ad_domain(args)
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
ad = self.get_host(args.ad, default=args.ad_domain.ads[0])
|
|
tasks.configure_dns_for_trust(host, ad)
|
|
|
|
def establish_trust_with_ad(self, args):
|
|
self.require_ad_domain(args)
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
ad = self.get_host(args.ad, default=args.ad_domain.ads[0])
|
|
tasks.establish_trust_with_ad(host, ad)
|
|
|
|
def remove_trust_with_ad(self, args):
|
|
self.require_ad_domain(args)
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
ad = self.get_host(args.ad, default=args.ad_domain.ads[0])
|
|
tasks.remove_trust_with_ad(host, ad.domain.name, ad.name)
|
|
|
|
def configure_auth_to_local_rule(self, args):
|
|
self.require_ad_domain(args)
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
ad = self.get_host(args.ad, default=args.ad_domain.ads[0])
|
|
tasks.configure_auth_to_local_rule(host, ad)
|
|
|
|
def clear_sssd_cache(self, args):
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
tasks.clear_sssd_cache(host)
|
|
|
|
def setup_sssd_debugging(self, args):
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
tasks.setup_sssd_debugging(host)
|
|
|
|
def sync_time(self, args):
|
|
host = self.get_host(args.host, default=args.domain.master)
|
|
server = self.get_host(args.server)
|
|
tasks.sync_time(host, server)
|
|
|
|
def add_a_records_for_hosts_in_master_domain(self, args):
|
|
master = self.get_host(args.master, default=args.domain.master)
|
|
tasks.add_a_records_for_hosts_in_master_domain(master)
|
|
|
|
def add_a_record(self, args):
|
|
master = self.get_host(args.master, default=args.domain.master)
|
|
host = self.get_host(args.host)
|
|
tasks.add_a_record(master, host)
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(TaskRunner().main(sys.argv[1:]))
|