From b62f7a71a9c4dad3ab5b9a66a36babcc46237edd Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Fri, 9 May 2014 00:46:04 -0400 Subject: Allow ipa-replica-install to be used for installing replicas --- install/tools/ipa-ca-install | 58 +++++++++------------------------ install/tools/ipa-drm-install | 65 +++++++++++++++++++++++++++---------- install/tools/ipa-replica-install | 52 ++++++----------------------- install/tools/ipa-upgradeconfig | 2 +- ipaserver/install/dogtaginstance.py | 29 +++++++++++++++++ ipaserver/install/installutils.py | 36 ++++++++++++++++++++ 6 files changed, 140 insertions(+), 102 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index d4a287951..a3ed6e5d3 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -19,22 +19,19 @@ # import sys -import socket - -import os, shutil +import os +import shutil from ipapython import ipautil from ipapython import services as ipaservices -from ipaserver.install import installutils, service -from ipaserver.install import certs -from ipaserver.install.installutils import (HostnameLocalhost, ReplicaConfig, - expand_replica_info, read_replica_info, get_host_name, BadHostError, - private_ccache, read_replica_info_dogtag_port) +from ipaserver.install import installutils +from ipaserver.install.installutils import ( + private_ccache, create_replica_config) from ipaserver.install import dsinstance, cainstance, bindinstance from ipaserver.install.replication import replica_conn_check from ipapython import version -from ipalib import api, util +from ipalib import api from ipapython.dn import DN from ipapython.config import IPAOptionParser from ipapython import sysrestore @@ -44,6 +41,7 @@ from ipapython.ipa_log_manager import * log_file_name = "/var/log/ipareplica-ca-install.log" REPLICA_INFO_TOP_DIR = None + def parse_options(): usage = "%prog [options] REPLICA_FILE" parser = IPAOptionParser(usage=usage, version=version.VERSION) @@ -71,9 +69,11 @@ def parse_options(): return safe_options, options, args[0] + def get_dirman_password(): return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) + def install_dns_records(config, options): if not bindinstance.dns_container_exists(config.master_host_name, @@ -88,7 +88,8 @@ def install_dns_records(config, options): bind.add_ipa_ca_dns_records(config.host_name, config.domain_name) finally: if api.Backend.ldap2.isconnected(): - api.Backend.ldap2.disconnect() + api.Backend.ldap2.disconnect() + def main(): safe_options, options, filename = parse_options() @@ -129,38 +130,11 @@ def main(): sys.exit("Directory Manager password required") if not options.admin_password and not options.skip_conncheck and \ - options.unattended: - sys.exit('admin password required') - - try: - top_dir, dir = expand_replica_info(filename, dirman_password) - global REPLICA_INFO_TOP_DIR - REPLICA_INFO_TOP_DIR = top_dir - except Exception, e: - print "ERROR: Failed to decrypt or open the replica file." - print "Verify you entered the correct Directory Manager password." - sys.exit(1) + options.unattended: + sys.exit('admin password required') - config = ReplicaConfig() - read_replica_info(dir, config) - config.dirman_password = dirman_password - try: - host = get_host_name(options.no_host_dns) - except BadHostError, e: - root_logger.error(str(e)) - sys.exit(1) - if config.host_name != host: - try: - print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) - if not ipautil.user_input("This may cause problems. Continue?", True): - sys.exit(0) - config.host_name = host - print "" - except KeyboardInterrupt: - sys.exit(0) - config.dir = dir + config = create_replica_config(dirman_password, filename, options) config.setup_ca = True - config.ca_ds_port = read_replica_info_dogtag_port(config.dir) if not ipautil.file_exists(config.dir + "/cacert.p12"): print 'CA cannot be installed in CA-less setup.' @@ -212,8 +186,8 @@ if __name__ == '__main__': try: with private_ccache(): installutils.run_script(main, log_file_name=log_file_name, - operation_name='ipa-ca-install', - fail_message=fail_message) + operation_name='ipa-ca-install', + fail_message=fail_message) finally: # always try to remove decrypted replica file try: diff --git a/install/tools/ipa-drm-install b/install/tools/ipa-drm-install index 2a2b2a727..b4b308d60 100644 --- a/install/tools/ipa-drm-install +++ b/install/tools/ipa-drm-install @@ -24,17 +24,21 @@ import sys from ConfigParser import SafeConfigParser, NoOptionError from ipalib import api -from ipaserver.install import drminstance -from ipaserver.install import dsinstance -from ipaserver.install import installutils from ipapython import version -from ipaserver.install.installutils import read_password from ipapython import certmonger -from ipapython.ipa_log_manager import * from ipapython import dogtag -from ipapython.config import IPAOptionParser +from ipapython import ipautil from ipapython import services as ipaservices - +from ipapython.config import IPAOptionParser +from ipapython.ipa_log_manager import * +from ipaserver.install import dogtaginstance +from ipaserver.install import drminstance +from ipaserver.install import dsinstance +from ipaserver.install import installutils +from ipaserver.install import service +from ipaserver.install.installutils import ( + read_password, read_replica_info_drm_enabled, + create_replica_config) log_file_name = "/var/log/ipa-drm-install.log" @@ -62,12 +66,15 @@ def uninstall(realm_name): def parse_options(): - usage = "%prog [options]" + usage = "%prog [options] [replica_file]" parser = IPAOptionParser(usage=usage, version=version.VERSION) parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="gather extra debugging information") parser.add_option("-p", "--password", dest="password", sensitive=True, help="Directory Manager (existing master) password") + parser.add_option("--no-host-dns", dest="no_host_dns", action="store_true", + default=False, + help="Do not use DNS for hostname lookup during installation") parser.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") @@ -79,12 +86,13 @@ def parse_options(): options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) - return safe_options, options + fname = args[0] if len(args) > 0 else None + return safe_options, options, fname def main(): log_file = "/var/log/ipa-drm-install.log" - safe_options, options = parse_options() + safe_options, options, replica_file = parse_options() if os.geteuid() != 0: sys.exit("\nYou must be root to run this script.\n") @@ -103,7 +111,7 @@ def main(): " in unattended mode") dm_password = options.password or \ - read_password("Directory Manager", confirm=False) + read_password("Directory Manager", confirm=False) if dm_password is None: sys.exit("Directory Manager password required") @@ -142,8 +150,10 @@ def main(): if enable_drm is not None and enable_drm == 'True': sys.exit("DRM is already installed.") - if enable_ra is not None and enable_ra == "True" and \ - ra_plugin is not None and ra_plugin == "dogtag": + ca_installed = enable_ra is not None and enable_ra == "True" and \ + ra_plugin is not None and ra_plugin == "dogtag" + + if ca_installed: if dogtag_version is not None and dogtag_version >= 10: # correct dogtag version of CA installed pass @@ -152,6 +162,13 @@ def main(): else: sys.exit("Dogtag CA is not installed. Please install the CA first") + installing_replica = dogtaginstance.is_installing_replica("KRA") + if installing_replica: + if replica_file is None: + sys.exit("A replica file is required.") + if not ipautil.file_exists(replica_file): + sys.exit("Replica file %s does not exist" % replica_file) + # Initialize the ipalib api cfg = dict( in_server=True, @@ -164,11 +181,25 @@ def main(): print "This program will setup Dogtag DRM for the FreeIPA Server." print "" - drm = drminstance.DRMInstance(realm_name, - dogtag_constants=dogtag.install_constants) + if not installing_replica: + drm = drminstance.DRMInstance( + realm_name, + dogtag_constants=dogtag.install_constants) + + drm.configure_instance(host_name, domain_name, dm_password, + dm_password, subject_base=subject) + else: + replica_config = create_replica_config(dm_password, replica_file, options) + + if not read_replica_info_drm_enabled(replica_config.dir): + sys.exit("Either DRM is not installed on the master system or " + "your replica file is out of date") + + drm = drminstance.install_replica_drm(replica_config) + service.print_msg("Restarting the directory server") - drm.configure_instance(host_name, domain_name, dm_password, - dm_password, subject_base=subject) + ds = dsinstance.DsInstance() + ds.restart() drm.enable_client_auth_to_db(drm.dogtag_constants.DRM_CS_CFG_PATH) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index 0beca24d9..fbc5824f6 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -36,9 +36,8 @@ from ipaserver.install import bindinstance, httpinstance, ntpinstance from ipaserver.install import memcacheinstance from ipaserver.install import otpdinstance from ipaserver.install.replication import replica_conn_check, ReplicationManager -from ipaserver.install.installutils import (ReplicaConfig, expand_replica_info, - read_replica_info, get_host_name, BadHostError, private_ccache, - read_replica_info_dogtag_port, read_replica_info_drm_enabled) +from ipaserver.install.installutils import (private_ccache, + read_replica_info_drm_enabled, create_replica_config) from ipaserver.plugins.ldap2 import ldap2 from ipaserver.install import cainstance from ipaserver.install import drminstance @@ -506,39 +505,8 @@ def main(): if dirman_password is None: sys.exit("Directory Manager password required") - try: - top_dir, dir = expand_replica_info(filename, dirman_password) - global REPLICA_INFO_TOP_DIR - REPLICA_INFO_TOP_DIR = top_dir - except Exception, e: - print "ERROR: Failed to decrypt or open the replica file." - print "Verify you entered the correct Directory Manager password." - sys.exit(1) - - config = ReplicaConfig() - read_replica_info(dir, config) - root_logger.debug('Installing replica file with version %d (0 means no version in prepared file).' % config.version) - if config.version and config.version > version.NUM_VERSION: - root_logger.error('A replica file from a newer release (%d) cannot be installed on an older version (%d)' % (config.version, version.NUM_VERSION)) - sys.exit(1) - config.dirman_password = dirman_password - try: - host = get_host_name(options.no_host_dns) - except BadHostError, e: - root_logger.error(str(e)) - sys.exit(1) - if config.host_name != host: - try: - print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) - if not ipautil.user_input("This may cause problems. Continue?", False): - sys.exit(0) - config.host_name = host - print "" - except KeyboardInterrupt: - sys.exit(0) - config.dir = dir + config = create_replica_config(dirman_password, filename, options) config.setup_ca = options.setup_ca - config.ca_ds_port = read_replica_info_dogtag_port(config.dir) if config.setup_ca and not ipautil.file_exists(config.dir + "/cacert.p12"): print 'CA cannot be installed in CA-less setup.' @@ -619,7 +587,7 @@ def main(): # Check that we don't already have a replication agreement try: - (agreement_cn, agreement_dn) = replman.agreement_dn(host) + (agreement_cn, agreement_dn) = replman.agreement_dn(config.host_name) entry = conn.get_entry(agreement_dn, ['*']) except errors.NotFound: pass @@ -629,20 +597,20 @@ def main(): print ('A replication agreement for this host already exists. ' 'It needs to be removed.') print "Run this on the master that generated the info file:" - print " %% ipa-replica-manage del %s --force" % host + print " %% ipa-replica-manage del %s --force" % config.host_name exit(3) # Check pre-existing host entry try: - entry = conn.find_entries(u'fqdn=%s' % host, ['fqdn'], DN(api.env.container_host, api.env.basedn)) + entry = conn.find_entries(u'fqdn=%s' % config.host_name, ['fqdn'], DN(api.env.container_host, api.env.basedn)) except errors.NotFound: pass else: root_logger.info( - 'Error: Host %s already exists on the master server.' % host) - print 'The host %s already exists on the master server.' % host + 'Error: Host %s already exists on the master server.' % config.host_name) + print 'The host %s already exists on the master server.' % config.host_name print "You should remove it before proceeding:" - print " %% ipa host-del %s" % host + print " %% ipa host-del %s" % config.host_name exit(3) # If remote host has DNS, check forward/reverse resolution @@ -710,7 +678,7 @@ def main(): if CA: CA.configure_certmonger_renewal() - CA.import_ra_cert(dir + "/ra.p12") + CA.import_ra_cert(config.dir + "/ra.p12") CA.fix_ra_perms() ipaservices.knownservices.httpd.restart() diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig index 0dbe892d3..b45b3179a 100644 --- a/install/tools/ipa-upgradeconfig +++ b/install/tools/ipa-upgradeconfig @@ -675,7 +675,7 @@ def certificate_renewal_update(ca): # Ok, now we need to stop tracking, then we can start tracking them # again with new configuration: - ca.stop_tracking_system_certificates(dogtag_constants) + ca.stop_tracking_certificates(dogtag_constants) if not sysupgrade.get_upgrade_state('dogtag', 'certificate_renewal_update_1'): diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py index 66a76c75d..89e4ad4e6 100644 --- a/ipaserver/install/dogtaginstance.py +++ b/ipaserver/install/dogtaginstance.py @@ -23,6 +23,9 @@ import shutil import tempfile import traceback +from pki.client import PKIConnection +import pki.system + from ipapython import certmonger from ipapython import dogtag from ipapython import ipaldap @@ -58,6 +61,32 @@ def check_inst(subsystem): return True +def get_security_domain(): + """ + Get the security domain from the REST interface on the local Dogtag CA + This function will succeed if the local dogtag CA is up. + """ + connection = PKIConnection() + domain_client = pki.system.SecurityDomainClient(connection) + info = domain_client.get_security_domain_info() + return info + + +def is_installing_replica(sys_type): + """ + We expect only one of each type of Dogtag subsystem in an IPA deployment. + That means that if a subsystem of the specified type has already been deployed - + and therefore appears in the security domain - then we must be installing + a replica. + """ + info = get_security_domain() + try: + sys_list = info.systems[sys_type] + return len(sys_list) > 0 + except KeyError: + return False + + class DogtagInstance(service.Service): """ This is the base class for a Dogtag 10+ instance, which uses a diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index e2d785881..675050ce4 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -42,6 +42,7 @@ from ipapython import config from ipalib import errors from ipaserver.install import certs from ipapython import services as ipaservices +from ipapython import version # Used to determine install status IPA_MODULES = [ @@ -570,6 +571,41 @@ def read_replica_info_drm_enabled(config_dir): return enable_drm +def create_replica_config(dirman_password, filename, options): + try: + top_dir, dir = expand_replica_info(filename, dirman_password) + global REPLICA_INFO_TOP_DIR + REPLICA_INFO_TOP_DIR = top_dir + except Exception, e: + print "ERROR: Failed to decrypt or open the replica file." + print "Verify you entered the correct Directory Manager password." + sys.exit(1) + config = ReplicaConfig() + read_replica_info(dir, config) + root_logger.debug('Installing replica file with version %d (0 means no version in prepared file).' % config.version) + if config.version and config.version > version.NUM_VERSION: + root_logger.error('A replica file from a newer release (%d) cannot be installed on an older version (%d)' % ( + config.version, version.NUM_VERSION)) + sys.exit(1) + config.dirman_password = dirman_password + try: + host = get_host_name(options.no_host_dns) + except BadHostError, e: + root_logger.error(str(e)) + sys.exit(1) + if config.host_name != host: + try: + print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) + if not ipautil.user_input("This may cause problems. Continue?", False): + sys.exit(0) + config.host_name = host + print "" + except KeyboardInterrupt: + sys.exit(0) + config.dir = dir + config.ca_ds_port = read_replica_info_dogtag_port(config.dir) + return config + def check_server_configuration(): """ Check if IPA server is configured on the system. -- cgit