diff options
author | Petr Viktorin <pviktori@redhat.com> | 2012-12-18 07:42:18 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2013-02-01 13:44:59 -0500 |
commit | 26c498736ec8eabb8dafbc090811c92c79a8c318 (patch) | |
tree | f4c2187920025a5f98b26e699179e3fdcd9d7b62 /install/tools | |
parent | 55cfd06e3a9cb730220836b07207f4e650de3a03 (diff) | |
download | freeipa-26c498736ec8eabb8dafbc090811c92c79a8c318.tar.gz freeipa-26c498736ec8eabb8dafbc090811c92c79a8c318.tar.xz freeipa-26c498736ec8eabb8dafbc090811c92c79a8c318.zip |
Port ipa-replica-prepare to the admintool framework
Break the script into several smaller methods.
Use modern idioms: os.path.join instead of string addition; the with statement
for closing files.
Add --quiet, --verbose, and --log-file options. Use logging instead of print
statements. (http://freeipa.org/page/V3/Logging_and_output)
Part of: https://fedorahosted.org/freeipa/ticket/2652
Fixes: https://fedorahosted.org/freeipa/ticket/3285
Diffstat (limited to 'install/tools')
-rwxr-xr-x | install/tools/ipa-replica-prepare | 492 |
1 files changed, 4 insertions, 488 deletions
diff --git a/install/tools/ipa-replica-prepare b/install/tools/ipa-replica-prepare index 274e8456a..21df34109 100755 --- a/install/tools/ipa-replica-prepare +++ b/install/tools/ipa-replica-prepare @@ -1,7 +1,7 @@ #! /usr/bin/python -E -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> +# Authors: Petr Viktorin <pviktori@redhat.com> # -# Copyright (C) 2007 Red Hat +# Copyright (C) 2012 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify @@ -18,490 +18,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import sys +from ipaserver.install.ipa_replica_prepare import ReplicaPrepare -import tempfile, shutil, os, pwd -from ipapython.ipa_log_manager import * -import traceback -from ConfigParser import SafeConfigParser -import krbV - -from ipapython import ipautil -from ipaserver.install import bindinstance, dsinstance, installutils, certs -from ipaserver.install.bindinstance import add_zone, add_fwd_rr, add_ptr_rr, dns_container_exists -from ipaserver.install.replication import enable_replication_version_checking -from ipaserver.install.installutils import resolve_host, BadHostError, HostLookupError -from ipaserver.plugins.ldap2 import ldap2 -from ipapython import version -from ipapython import dogtag -from ipapython.config import IPAOptionParser -from ipalib import api, errors, util -from ipapython.dn import DN - -def parse_options(): - usage = "%prog [options] FQDN (e.g. replica.example.com)" - parser = IPAOptionParser(usage=usage, version=version.VERSION) - - parser.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12", - help="install certificate for the directory server") - parser.add_option("--http_pkcs12", dest="http_pkcs12", - help="install certificate for the http server") - parser.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12", - help="install certificate for the KDC") - parser.add_option("--dirsrv_pin", dest="dirsrv_pin", - help="PIN for the Directory Server PKCS#12 file") - parser.add_option("--http_pin", dest="http_pin", - help="PIN for the Apache Server PKCS#12 file") - parser.add_option("--pkinit_pin", dest="pkinit_pin", - help="PIN for the KDC pkinit PKCS#12 file") - parser.add_option("-p", "--password", dest="password", - help="Directory Manager (existing master) password") - parser.add_option("--ip-address", dest="ip_address", - type="ip", help="Add A and PTR records of the future replica") - parser.add_option("--reverse-zone", dest="reverse_zone", - help="The reverse DNS zone to use") - parser.add_option("--no-reverse", dest="no_reverse", action="store_true", - default=False, help="Do not create reverse DNS zone") - parser.add_option("--ca", dest="ca_file", default="/root/cacert.p12", - help="Location of CA PKCS#12 file, default /root/cacert.p12") - parser.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", - default=True, help="disables pkinit setup steps") - parser.add_option("--debug", dest="debug", action="store_true", - default=False, help="enable debugging") - - options, args = parser.parse_args() - - if not options.ip_address: - if options.reverse_zone: - parser.error("You cannot specify a --reverse-zone option without the --ip-address option") - if options.no_reverse: - parser.error("You cannot specify a --no-reverse option without the --ip-address option") - elif options.reverse_zone and options.no_reverse: - parser.error("You cannot specify a --reverse-zone option together with --no-reverse") - - # If any of the PKCS#12 options are selected, all are required. Create a - # list of the options and count it to enforce that all are required without - # having a huge set of it blocks. - if options.setup_pkinit: - pkcs12 = [options.dirsrv_pkcs12, options.dirsrv_pin, - options.http_pkcs12, options.http_pin, - options.pkinit_pkcs12, options.pkinit_pin] - num = 6 - else: - pkcs12 = [options.dirsrv_pkcs12, options.dirsrv_pin, - options.http_pkcs12, options.http_pin] - num = 4 - cnt = pkcs12.count(None) - if cnt > 0 and cnt < num: - parser.error("All PKCS#12 options are required if any are used.") - - if len(args) != 1: - parser.error("must provide the fully-qualified name of the replica") - - return options, args - -def get_subject_base(host_name, dm_password, suffix): - try: - conn = ldap2(shared_instance=False, base_dn=suffix) - conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) - except errors.ExecutionError, e: - root_logger.critical("Could not connect to the Directory Server on %s" % host_name) - raise e - (dn, entry_attrs) = conn.get_ipa_config() - conn.disconnect() - subject_base = entry_attrs.get('ipacertificatesubjectbase', [None])[0] - if subject_base is not None: - subject_base = DN(subject_base) - return subject_base - -def check_ipa_configuration(realm_name): - config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name)) - if not ipautil.dir_exists(config_dir): - root_logger.error("could not find directory instance: %s" % config_dir) - sys.exit(1) - -def export_certdb(realm_name, ds_dir, dir, passwd_fname, fname, hostname, subject_base=None, is_kdc=False): - """realm is the kerberos realm for the IPA server. - ds_dir is the location of the master DS we are creating a replica for. - dir is the location of the files for the replica we are creating. - passwd_fname is the file containing the PKCS#12 password - fname is the filename of the PKCS#12 file for this cert (minus the .p12). - hostname is the FQDN of the server we're creating a cert for. - - The subject is handled by certs.CertDB:create_server_cert() - """ - - if is_kdc: - nickname = "KDC-Cert" - else: - nickname = "Server-Cert" - - try: - self_signed = certs.ipa_self_signed() - - db = certs.CertDB(realm_name, nssdir=dir, subject_base=subject_base) - db.create_passwd_file() - ca_db = certs.CertDB(realm_name, host_name=api.env.host, subject_base=subject_base) - if is_kdc: - ca_db.create_kdc_cert("KDC-Cert", hostname, dir) - else: - db.create_from_cacert(ca_db.cacert_fname) - db.create_server_cert(nickname, hostname, ca_db) - except Exception, e: - raise e - - pkcs12_fname = dir + "/" + fname + ".p12" - - try: - if is_kdc: - ca_db.export_pem_p12(pkcs12_fname, passwd_fname, - nickname, dir + "/kdc.pem") - else: - db.export_pkcs12(pkcs12_fname, passwd_fname, nickname) - except ipautil.CalledProcessError, e: - print "error exporting Server certificate: " + str(e) - remove_file(pkcs12_fname) - remove_file(passwd_fname) - - remove_file(dir + "/cert8.db") - remove_file(dir + "/key3.db") - remove_file(dir + "/secmod.db") - remove_file(dir + "/noise.txt") - if is_kdc: - remove_file(dir + "/kdc.pem") - if ipautil.file_exists(passwd_fname + ".orig"): - remove_file(passwd_fname + ".orig") - -def export_ra_pkcs12(dir, dm_password): - """ - dir is the location of the files for the replica we are creating. - dm_password is the Directory Manager password - - If this install is using dogtag/RHCS then export the RA certificate. - """ - if certs.ipa_self_signed(): - return - - (agent_fd, agent_name) = tempfile.mkstemp() - os.write(agent_fd, dm_password) - os.close(agent_fd) - - try: - try: - db = certs.CertDB(api.env.realm, host_name=api.env.host) - - if db.has_nickname("ipaCert"): - pkcs12_fname = "%s/ra.p12" % dir - db.export_pkcs12(pkcs12_fname, agent_name, "ipaCert") - except Exception, e: - raise e - finally: - os.remove(agent_name) - -def save_config(dir, realm_name, host_name, - domain_name, dest_host, - subject_base): - config = SafeConfigParser() - config.add_section("realm") - config.set("realm", "realm_name", realm_name) - config.set("realm", "master_host_name", host_name) - config.set("realm", "domain_name", domain_name) - config.set("realm", "destination_host", dest_host) - config.set("realm", "subject_base", str(subject_base)) - config.set("realm", "version", str(version.NUM_VERSION)) - with open(dir + "/realm_info", "w") as fd: - config.write(fd) - -def remove_file(fname, ignore_errors=True): - try: - os.remove(fname) - except OSError, e: - if not ignore_errors: - raise e - -def copy_files(realm_name, dir): - config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name)) - - try: - shutil.copy("/usr/share/ipa/html/ca.crt", dir + "/ca.crt") - if ipautil.file_exists("/usr/share/ipa/html/preferences.html"): - shutil.copy("/usr/share/ipa/html/krb.js", dir + "/krb.js") - shutil.copy("/usr/share/ipa/html/kerberosauth.xpi", dir + "/kerberosauth.xpi") - shutil.copy("/usr/share/ipa/html/preferences.html", dir + "/preferences.html") - shutil.copy("/usr/share/ipa/html/configure.jar", dir + "/configure.jar") - if ipautil.file_exists("/var/kerberos/krb5kdc/cacert.pem"): - shutil.copy("/var/kerberos/krb5kdc/cacert.pem", dir + "/cacert.pem") - except Exception, e: - print "error copying files: " + str(e) - sys.exit(1) - -def get_dirman_password(): - return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) - -def main(): - installutils.check_server_configuration() - options, args = parse_options() - - replica_fqdn = args[0] - - standard_logging_setup(None, debug=options.debug) - - # Just initialize the environment. This is so the installer can have - # access to the plugin environment - api.bootstrap(in_server=True, debug=options.debug) - api.finalize() - - #Automatically disable pkinit w/ dogtag until that is supported - #[certs.ipa_self_signed() must be called only after api.finalize()] - if not options.pkinit_pkcs12 and not certs.ipa_self_signed(): - options.setup_pkinit = False - - if certs.ipa_self_signed_master() == False: - sys.exit('A selfsign CA backend can only prepare on the original master') - - # get the directory manager password - dirman_password = options.password - if not options.password: - try: - dirman_password = get_dirman_password() - except KeyboardInterrupt: - sys.exit(0) - if dirman_password is None: - sys.exit("\nDirectory Manager password required") - - # Try out the password - try: - conn = ldap2(shared_instance=False) - conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password) - conn.disconnect() - except errors.ACIError: - sys.exit("\nThe password provided is incorrect for LDAP server %s" % api.env.host) - except errors.LDAPError: - sys.exit("\nUnable to connect to LDAP server %s" % api.env.host) - except errors.DatabaseError, e: - sys.exit("\n"+e.desc) - - try: - installutils.verify_fqdn(replica_fqdn, local_hostname=False) - except BadHostError, e: - msg = str(e) - if isinstance(e, HostLookupError): - if options.ip_address is None: - if dns_container_exists(api.env.host, api.env.basedn, - dm_password=dirman_password, - ldapi=True, realm=api.env.realm): - msg += '\nAdd the --ip-address argument to create a DNS entry.' - sys.exit(msg) - else: - # The host doesn't exist in DNS but we're adding it. - pass - else: - sys.exit(msg) - - if options.ip_address: - if not dns_container_exists(api.env.host, api.env.basedn, - dm_password=dirman_password, - ldapi=True, realm=api.env.realm): - print "You can't add a DNS record because DNS is not set up." - sys.exit(1) - if options.reverse_zone and not bindinstance.verify_reverse_zone(options.reverse_zone, options.ip_address): - sys.exit(1) - - if (not certs.ipa_self_signed() and - not ipautil.file_exists(dogtag.configured_constants().CS_CFG_PATH) and - not options.dirsrv_pin): - sys.exit("The replica must be created on the primary IPA server.\nIf you installed IPA with your own certificates using PKCS#12 files you must provide PKCS#12 files for any replicas you create as well.") - - check_ipa_configuration(api.env.realm) - - if api.env.host == replica_fqdn: - print "You can't create a replica on itself" - sys.exit(1) - ds_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(api.env.realm)) - - print "Preparing replica for %s from %s" % (replica_fqdn, api.env.host) - enable_replication_version_checking(api.env.host, api.env.realm, - dirman_password) - - subject_base = get_subject_base(api.env.host, dirman_password, ipautil.realm_to_suffix(api.env.realm)) - - top_dir = tempfile.mkdtemp("ipa") - dir = top_dir + "/realm_info" - os.mkdir(dir, 0700) - - if options.dirsrv_pin: - passwd = options.dirsrv_pin - else: - passwd = "" - - passwd_fname = dir + "/dirsrv_pin.txt" - fd = open(passwd_fname, "w") - fd.write("%s\n" % passwd) - fd.close() - - if options.dirsrv_pkcs12: - print "Copying SSL certificate for the Directory Server from %s" % options.dirsrv_pkcs12 - try: - shutil.copy(options.dirsrv_pkcs12, dir + "/dscert.p12") - except IOError, e: - print "Copy failed %s" % e - sys.exit(1) - else: - try: - if not certs.ipa_self_signed(): - # FIXME, need option for location of CA backup - if ipautil.file_exists(options.ca_file): - shutil.copy(options.ca_file, dir + "/cacert.p12") - else: - raise RuntimeError("Root CA PKCS#12 not found in %s" % options.ca_file) - except IOError, e: - print "Copy failed %s" % e - sys.exit(1) - print "Creating SSL certificate for the Directory Server" - try: - export_certdb(api.env.realm, ds_dir, dir, passwd_fname, "dscert", replica_fqdn, subject_base) - except errors.CertificateOperationError, e: - print "%s" % e - sys.exit(1) - - if not certs.ipa_self_signed(): - print "Creating SSL certificate for the dogtag Directory Server" - try: - export_certdb(api.env.realm, ds_dir, dir, passwd_fname, "dogtagcert", replica_fqdn, subject_base) - except errors.CertificateOperationError, e: - print "%s" % e - sys.exit(1) - print "Saving dogtag Directory Server port" - port_fname = dir + "/dogtag_directory_port.txt" - with open(port_fname, "w") as fd: - fd.write("%s\n" % str(dogtag.configured_constants().DS_PORT)) - - if options.http_pin: - passwd = options.http_pin - else: - passwd = "" - - passwd_fname = dir + "/http_pin.txt" - fd = open(passwd_fname, "w") - fd.write("%s\n" % passwd) - fd.close() - - if options.http_pkcs12: - print "Copying SSL certificate for the Web Server from %s" % options.http_pkcs12 - try: - shutil.copy(options.http_pkcs12, dir + "/httpcert.p12") - except IOError, e: - print "Copy failed %s" % e - sys.exit(1) - else: - print "Creating SSL certificate for the Web Server" - try: - export_certdb(api.env.realm, ds_dir, dir, passwd_fname, "httpcert", replica_fqdn, subject_base) - except errors.CertificateOperationError, e: - print "%s" % e - sys.exit(1) - print "Exporting RA certificate" - export_ra_pkcs12(dir, dirman_password) - - if options.setup_pkinit: - if options.pkinit_pin: - passwd = options.pkinit_pin - else: - passwd = "" - - passwd_fname = dir + "/pkinit_pin.txt" - fd = open(passwd_fname, "w") - fd.write("%s\n" % passwd) - fd.close() - - if options.pkinit_pkcs12: - print "Copying SSL certificate for the KDC from %s" % options.pkinit_pkcs12 - try: - shutil.copy(options.pkinit_pkcs12, dir + "/pkinitcert.p12") - except IOError, e: - print "Copy failed %s" % e - sys.exit(1) - else: - print "Creating SSL certificate for the KDC" - try: - export_certdb(api.env.realm, ds_dir, dir, - passwd_fname, "pkinitcert", - replica_fqdn, subject_base, - is_kdc=True) - except errors.CertificateOperationError, e: - print "%s" % e - sys.exit(1) - - print "Copying additional files" - copy_files(api.env.realm, dir) - print "Finalizing configuration" - save_config(dir, api.env.realm, api.env.host, api.env.domain, replica_fqdn, subject_base) - - replicafile = "/var/lib/ipa/replica-info-" + replica_fqdn - encfile = replicafile+".gpg" - - print "Packaging replica information into %s" % encfile - ipautil.run(["/bin/tar", "cf", replicafile, "-C", top_dir, "realm_info"]) - ipautil.encrypt_file(replicafile, encfile, dirman_password, top_dir) - - os.chmod(encfile, 0600) - - remove_file(replicafile) - shutil.rmtree(dir) - - if options.ip_address: - print "Adding DNS records for %s" % replica_fqdn - api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dirman_password) - - domain = replica_fqdn.split(".") - name = domain.pop(0) - domain = ".".join(domain) - - ip = options.ip_address - ip_address = str(ip) - - if options.reverse_zone: - reverse_zone = bindinstance.normalize_zone(options.reverse_zone) - else: - reverse_zone = bindinstance.find_reverse_zone(ip) - if reverse_zone is None and not options.no_reverse: - reverse_zone = bindinstance.get_reverse_zone_default(ip) - - try: - add_zone(domain) - except errors.PublicError, e: - sys.exit("Could not create forward DNS zone for the replica: %s" % e) - - try: - add_fwd_rr(domain, name, ip_address) - except errors.PublicError, e: - sys.exit("Could not add forward DNS record for the replica: %s" % e) - - if reverse_zone is not None: - print "Using reverse zone %s" % reverse_zone - try: - add_zone(reverse_zone) - except errors.PublicError, e: - sys.exit("Could not create reverse DNS zone for the replica: %s" % e) - try: - add_ptr_rr(reverse_zone, ip_address, replica_fqdn) - except errors.PublicError, e: - sys.exit("Could not add reverse DNS record for the replica: %s" % e) - -try: - if not os.geteuid()==0: - sys.exit("\nYou must be root to run this script.\n") - - main() -except SystemExit, e: - sys.exit(e) -except RuntimeError, e: - sys.exit(e) -except Exception, e: - print "preparation of replica failed: %s" % str(e) - message = str(e) - for str in traceback.format_tb(sys.exc_info()[2]): - message = message + "\n" + str - root_logger.debug(message) - print message - sys.exit(1) +ReplicaPrepare.run_cli() |