summaryrefslogtreecommitdiffstats
path: root/ipaserver
diff options
context:
space:
mode:
Diffstat (limited to 'ipaserver')
-rw-r--r--ipaserver/install/bindinstance.py110
-rw-r--r--ipaserver/install/installutils.py124
-rw-r--r--ipaserver/install/ipa_replica_prepare.py82
3 files changed, 188 insertions, 128 deletions
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index cece85ec6..2e8836ec6 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -22,6 +22,7 @@ import os
import pwd
import netaddr
import re
+import sys
import ldap
@@ -250,7 +251,6 @@ def verify_reverse_zone(zone, ip_address):
try:
get_reverse_record_name(zone, ip_address)
except ValueError:
- print "Invalid reverse zone %s" % zone
return False
return True
@@ -276,6 +276,8 @@ def read_reverse_zone(default, ip_address):
return None
if verify_reverse_zone(zone, ip_address):
break
+ else:
+ print "Invalid reverse zone %s for IP address %s" % (zone, ip_address)
return normalize_zone(zone)
@@ -378,6 +380,48 @@ def zonemgr_callback(option, opt_str, value, parser):
parser.values.zonemgr = value
+def check_reverse_zones(ip_addresses, reverse_zones, options, unattended, search_reverse_zones=False):
+ reverse_asked = False
+
+ ret_reverse_zones = []
+ # check that there is IP address in every reverse zone
+ if reverse_zones:
+ for rz in reverse_zones:
+ for ip in ip_addresses:
+ if verify_reverse_zone(rz, ip):
+ ret_reverse_zones.append(normalize_zone(rz))
+ break
+ else:
+ # no ip matching reverse zone found
+ sys.exit("There is no IP address matching reverse zone %s." % rz)
+ if not options.no_reverse:
+ # check that there is reverse zone for every IP
+ for ip in ip_addresses:
+ if search_reverse_zones and find_reverse_zone(str(ip)):
+ # reverse zone is already in LDAP
+ continue
+ for rz in ret_reverse_zones:
+ if verify_reverse_zone(rz, ip):
+ # reverse zone was entered by user
+ break
+ else:
+ # no reverse zone for ip found
+ if not reverse_asked:
+ if not unattended and not reverse_zones:
+ # user did not specify reverse_zone nor no_reverse
+ options.no_reverse = not create_reverse()
+ if options.no_reverse:
+ # user decided not to create reverse zone
+ return []
+ reverse_asked = True
+ rz = get_reverse_zone_default(str(ip))
+ if not unattended:
+ rz = read_reverse_zone(rz, str(ip))
+ ret_reverse_zones.append(rz)
+
+ return ret_reverse_zones
+
+
class DnsBackup(object):
def __init__(self, service):
self.service = service
@@ -437,11 +481,11 @@ class BindInstance(service.Service):
self.named_user = None
self.domain = None
self.host = None
- self.ip_address = None
+ self.ip_addresses = []
self.realm = None
self.forwarders = None
self.sub_dict = None
- self.reverse_zone = None
+ self.reverse_zones = []
self.dm_password = dm_password
if fstore:
@@ -451,19 +495,19 @@ class BindInstance(service.Service):
suffix = ipautil.dn_attribute_property('_suffix')
- def setup(self, fqdn, ip_address, realm_name, domain_name, forwarders, ntp,
- reverse_zone, named_user="named", zonemgr=None,
+ def setup(self, fqdn, ip_addresses, realm_name, domain_name, forwarders, ntp,
+ reverse_zones, named_user="named", zonemgr=None,
ca_configured=None):
self.named_user = named_user
self.fqdn = fqdn
- self.ip_address = ip_address
+ self.ip_addresses = ip_addresses
self.realm = realm_name
self.domain = domain_name
self.forwarders = forwarders
self.host = fqdn.split(".")[0]
self.suffix = ipautil.realm_to_suffix(self.realm)
self.ntp = ntp
- self.reverse_zone = reverse_zone
+ self.reverse_zones = reverse_zones
self.ca_configured = ca_configured
if not zonemgr:
@@ -509,8 +553,9 @@ class BindInstance(service.Service):
# get a connection to the DS
self.ldap_connect()
- if installutils.record_in_hosts(self.ip_address, self.fqdn) is None:
- installutils.add_record_to_hosts(self.ip_address, self.fqdn)
+ for ip_address in self.ip_addresses:
+ if installutils.record_in_hosts(str(ip_address), self.fqdn) is None:
+ installutils.add_record_to_hosts(str(ip_address), self.fqdn)
# Make sure generate-rndc-key.sh runs before named restart
self.step("generating rndc key file", self.__generate_rndc_key)
@@ -520,8 +565,7 @@ class BindInstance(service.Service):
if not dns_zone_exists(self.domain):
self.step("setting up our zone", self.__setup_zone)
-
- if self.reverse_zone is not None:
+ if self.reverse_zones:
self.step("setting up reverse zone", self.__setup_reverse_zone)
self.step("setting up our own record", self.__add_self)
@@ -574,18 +618,17 @@ class BindInstance(service.Service):
else:
optional_ntp = ""
- addr = netaddr.IPAddress(self.ip_address)
- if addr.version in (4, 6):
- ipa_ca = "%s\t\t\tIN %s\t\t\t%s\n" % (
- IPA_CA_RECORD,
- "A" if addr.version == 4 else "AAAA",
- self.ip_address)
- else:
- ipa_ca = ""
+ ipa_ca = ""
+ for addr in self.ip_addresses:
+ if addr.version in (4, 6):
+ ipa_ca += "%s\t\t\tIN %s\t\t\t%s\n" % (
+ IPA_CA_RECORD,
+ "A" if addr.version == 4 else "AAAA",
+ str(addr))
self.sub_dict = dict(
FQDN=self.fqdn,
- IP=self.ip_address,
+ IP=[str(ip) for ip in self.ip_addresses],
DOMAIN=self.domain,
HOST=self.host,
REALM=self.realm,
@@ -618,7 +661,8 @@ class BindInstance(service.Service):
def __setup_reverse_zone(self):
# Always use force=True as named is not set up yet
- add_zone(self.reverse_zone, self.zonemgr, ns_hostname=api.env.host,
+ for reverse_zone in self.reverse_zones:
+ add_zone(reverse_zone, self.zonemgr, ns_hostname=api.env.host,
dns_backup=self.dns_backup, force=True)
def __add_master_records(self, fqdn, addrs):
@@ -665,7 +709,7 @@ class BindInstance(service.Service):
add_ptr_rr(reverse_zone, addr, fqdn)
def __add_self(self):
- self.__add_master_records(self.fqdn, [self.ip_address])
+ self.__add_master_records(self.fqdn, self.ip_addresses)
def __add_others(self):
entries = self.admin_conn.get_entries(
@@ -710,7 +754,7 @@ class BindInstance(service.Service):
pass
def __add_ipa_ca_record(self):
- self.__add_ipa_ca_records(self.fqdn, [self.ip_address],
+ self.__add_ipa_ca_records(self.fqdn, self.ip_addresses,
self.ca_configured)
if self.first_instance:
@@ -798,7 +842,17 @@ class BindInstance(service.Service):
def __setup_resolv_conf(self):
self.fstore.backup_file(RESOLV_CONF)
- resolv_txt = "search "+self.domain+"\nnameserver "+self.ip_address+"\n"
+ resolv_txt = "search "+self.domain+"\n"
+
+ for ip_address in self.ip_addresses:
+ if ip_address.version == 4:
+ resolv_txt += "nameserver 127.0.0.1\n"
+ break
+
+ for ip_address in self.ip_addresses:
+ if ip_address.version == 6:
+ resolv_txt += "nameserver ::1\n"
+ break
try:
resolv_fd = open(RESOLV_CONF, 'w')
resolv_fd.seek(0)
@@ -812,16 +866,16 @@ class BindInstance(service.Service):
installutils.check_entropy()
ipautil.run(['/usr/libexec/generate-rndc-key.sh'])
- def add_master_dns_records(self, fqdn, ip_address, realm_name, domain_name,
- reverse_zone, ntp=False, ca_configured=None):
+ def add_master_dns_records(self, fqdn, ip_addresses, realm_name, domain_name,
+ reverse_zones, ntp=False, ca_configured=None):
self.fqdn = fqdn
- self.ip_address = ip_address
+ self.ip_addresses = ip_addresses
self.realm = realm_name
self.domain = domain_name
self.host = fqdn.split(".")[0]
self.suffix = ipautil.realm_to_suffix(self.realm)
self.ntp = ntp
- self.reverse_zone = reverse_zone
+ self.reverse_zones = reverse_zones
self.ca_configured = ca_configured
self.first_instance = False
self.zonemgr = 'hostmaster.%s' % self.domain
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 34ae30624..c8e1a8de9 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -222,6 +222,7 @@ def add_record_to_hosts(ip, host_name, conf_file=paths.HOSTS):
hosts_fd.write(ip+'\t'+host_name+' '+host_name.split('.')[0]+'\n')
hosts_fd.close()
+# TODO: Remove when removing usage from ipa-adtrust-install
def read_ip_address(host_name, fstore):
while True:
ip = ipautil.user_input("Please provide the IP address to be used for this host name", allow_empty = False)
@@ -235,6 +236,22 @@ def read_ip_address(host_name, fstore):
return ip_parsed
+def read_ip_addresses(host_name, fstore):
+ ips = []
+ print "Enter the IP address to use, or press Enter to finish."
+ while True:
+ ip = ipautil.user_input("Please provide the IP address to be used for this host name", allow_empty = True)
+ if not ip:
+ break
+ try:
+ ip_parsed = ipautil.CheckedIPAddress(ip, match_local=True)
+ except Exception, e:
+ print "Error: Invalid IP Address %s: %s" % (ip, e)
+ continue
+ ips.append(ip)
+
+ return ips
+
def read_dns_forwarders():
addrs = []
if ipautil.user_input("Do you want to configure DNS forwarders?", True):
@@ -426,7 +443,7 @@ def get_host_name(no_host_dns):
verify_fqdn(hostname, no_host_dns)
return hostname
-def get_server_ip_address(host_name, fstore, unattended, options):
+def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses):
# Check we have a public IP that is associated with the hostname
try:
hostaddr = resolve_host(host_name)
@@ -441,74 +458,59 @@ def get_server_ip_address(host_name, fstore, unattended, options):
ip_add_to_hosts = False
- if len(hostaddr) > 1:
- print >> sys.stderr, "The server hostname resolves to more than one address:"
- for addr in hostaddr:
- print >> sys.stderr, " %s" % addr
+ ips = []
+ if len(hostaddr):
+ for ha in hostaddr:
+ try:
+ ips.append(ipautil.CheckedIPAddress(ha, match_local=True))
+ except ValueError, e:
+ root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e))
- if options.ip_address:
- if str(options.ip_address) not in hostaddr:
- print >> sys.stderr, "Address passed in --ip-address did not match any resolved"
- print >> sys.stderr, "address!"
- sys.exit(1)
- print "Selected IP address:", str(options.ip_address)
- ip = options.ip_address
+ if not ips and not ip_addresses:
+ if not unattended:
+ ip_addresses = read_ip_addresses(host_name, fstore)
+
+ if ip_addresses:
+ if setup_dns:
+ ips = ip_addresses
else:
- if unattended:
- print >> sys.stderr, "Please use --ip-address option to specify the address"
- sys.exit(1)
+ # all specified addresses was resolved for this host
+ if set(ip_addresses) <= set(ips):
+ ips = ip_addresses
else:
- ip = read_ip_address(host_name, fstore)
- elif len(hostaddr) == 1:
- try:
- ip = ipautil.CheckedIPAddress(hostaddr[0], match_local=True)
- except ValueError, e:
- sys.exit("Invalid IP Address %s for %s: %s" % (hostaddr[0], host_name, unicode(e)))
- else:
- # hostname is not resolvable
- ip = options.ip_address
+ print >>sys.stderr, "Error: the hostname resolves to IP address(es) that are different"
+ print >>sys.stderr, "from those provided on the command line. Please fix your DNS"
+ print >>sys.stderr, "or /etc/hosts file and restart the installation."
+ print >>sys.stderr, "Provided but not resolved address(es): %s" % \
+ ", ".join(str(ip) for ip in (set(ip_addresses) - set(ips)))
+ sys.exit(1)
ip_add_to_hosts = True
- if ip is None:
- print "Unable to resolve IP address for host name"
- if unattended:
- sys.exit(1)
-
- if options.ip_address:
- if options.ip_address != ip and not options.setup_dns:
- print >>sys.stderr, "Error: the hostname resolves to an IP address that is different"
- print >>sys.stderr, "from the one provided on the command line. Please fix your DNS"
- print >>sys.stderr, "or /etc/hosts file and restart the installation."
- sys.exit(1)
-
- ip = options.ip_address
-
- if ip is None:
- ip = read_ip_address(host_name, fstore)
- root_logger.debug("read ip_address: %s\n" % str(ip))
+ if not ips:
+ print >> sys.stderr, "No usable IP address provided nor resolved."
+ sys.exit(1)
- ip_address = str(ip)
+ for ip_address in ips:
+ # check /etc/hosts sanity, add a record when needed
+ hosts_record = record_in_hosts(str(ip_address))
- # check /etc/hosts sanity, add a record when needed
- hosts_record = record_in_hosts(ip_address)
+ if hosts_record is None:
+ if ip_add_to_hosts:
+ print "Adding ["+str(ip_address)+" "+host_name+"] to your /etc/hosts file"
+ fstore.backup_file(paths.HOSTS)
+ add_record_to_hosts(str(ip_address), host_name)
+ else:
+ primary_host = hosts_record[1][0]
+ if primary_host != host_name:
+ print >>sys.stderr, "Error: there is already a record in /etc/hosts for IP address %s:" \
+ % ip_address
+ print >>sys.stderr, hosts_record[0], " ".join(hosts_record[1])
+ print >>sys.stderr, "Chosen hostname %s does not match configured canonical hostname %s" \
+ % (host_name, primary_host)
+ print >>sys.stderr, "Please fix your /etc/hosts file and restart the installation."
+ sys.exit(1)
- if hosts_record is None:
- if ip_add_to_hosts or options.setup_dns:
- print "Adding ["+ip_address+" "+host_name+"] to your /etc/hosts file"
- fstore.backup_file(paths.HOSTS)
- add_record_to_hosts(ip_address, host_name)
- else:
- primary_host = hosts_record[1][0]
- if primary_host != host_name:
- print >>sys.stderr, "Error: there is already a record in /etc/hosts for IP address %s:" \
- % ip_address
- print >>sys.stderr, hosts_record[0], " ".join(hosts_record[1])
- print >>sys.stderr, "Chosen hostname %s does not match configured canonical hostname %s" \
- % (host_name, primary_host)
- print >>sys.stderr, "Please fix your /etc/hosts file and restart the installation."
- sys.exit(1)
-
- return ip
+ return ips
def expand_replica_info(filename, password):
"""
diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py
index 7768fd311..e27eb6dd4 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -54,9 +54,11 @@ class ReplicaPrepare(admintool.AdminTool):
parser.add_option("-p", "--password", dest="password",
help="Directory Manager password (for the existing master)")
- parser.add_option("--ip-address", dest="ip_address", type="ip",
+ parser.add_option("--ip-address", dest="ip_addresses", type="ip",
+ action="append", default=[],
help="add A and PTR records of the future replica")
- parser.add_option("--reverse-zone", dest="reverse_zone",
+ parser.add_option("--reverse-zone", dest="reverse_zones",
+ action="append", default=[],
help="the reverse DNS zone to use")
parser.add_option("--no-reverse", dest="no_reverse",
action="store_true", default=False,
@@ -95,14 +97,14 @@ class ReplicaPrepare(admintool.AdminTool):
super(ReplicaPrepare, self).validate_options(needs_root=True)
installutils.check_server_configuration()
- if not options.ip_address:
- if options.reverse_zone:
+ if not options.ip_addresses:
+ if options.reverse_zones:
self.option_parser.error("You cannot specify a --reverse-zone "
"option without the --ip-address option")
if options.no_reverse:
self.option_parser.error("You cannot specify a --no-reverse "
"option without the --ip-address option")
- elif options.reverse_zone and options.no_reverse:
+ elif options.reverse_zones and options.no_reverse:
self.option_parser.error("You cannot specify a --reverse-zone "
"option together with --no-reverse")
@@ -192,7 +194,7 @@ class ReplicaPrepare(admintool.AdminTool):
except installutils.BadHostError, e:
msg = str(e)
if isinstance(e, installutils.HostLookupError):
- if options.ip_address is None:
+ if not options.ip_addresses:
if dns_container_exists(
api.env.host, api.env.basedn,
dm_password=self.dirman_password,
@@ -206,7 +208,7 @@ class ReplicaPrepare(admintool.AdminTool):
else:
raise
- if options.ip_address:
+ if options.ip_addresses:
if not dns_container_exists(api.env.host, api.env.basedn,
dm_password=self.dirman_password,
ldapi=True, realm=api.env.realm):
@@ -215,9 +217,19 @@ class ReplicaPrepare(admintool.AdminTool):
"because DNS is not managed by IPA. Please create DNS "
"record manually and then omit --ip-address option.")
raise admintool.ScriptError("Cannot add DNS record")
- if options.reverse_zone and not bindinstance.verify_reverse_zone(
- options.reverse_zone, options.ip_address):
- raise admintool.ScriptError("Invalid reverse zone")
+
+ disconnect = False
+ if not api.Backend.ldap2.isconnected():
+ api.Backend.ldap2.connect(
+ bind_dn=DN(('cn', 'Directory Manager')),
+ bind_pw=self.dirman_password)
+ disconnect = True
+
+ options.reverse_zones = bindinstance.check_reverse_zones(
+ options.ip_addresses, options.reverse_zones, options, False,
+ True)
+ if disconnect:
+ api.Backend.ldap2.disconnect()
if options.http_pkcs12:
if options.http_pin is None:
@@ -293,7 +305,7 @@ class ReplicaPrepare(admintool.AdminTool):
finally:
shutil.rmtree(self.top_dir)
- if options.ip_address:
+ if options.ip_addresses:
self.add_dns_records()
if options.wait_for_dns:
@@ -420,46 +432,38 @@ class ReplicaPrepare(admintool.AdminTool):
options = self.options
self.log.info("Adding DNS records for %s", self.replica_fqdn)
- api.Backend.ldap2.connect(
- bind_dn=DN(('cn', 'Directory Manager')),
- bind_pw=self.dirman_password)
-
name, domain = self.replica_fqdn.split(".", 1)
- 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)
-
+ if not api.Backend.ldap2.isconnected():
+ api.Backend.ldap2.connect(
+ bind_dn=DN(('cn', 'Directory Manager')),
+ bind_pw=self.dirman_password)
try:
add_zone(domain)
except errors.PublicError, e:
raise admintool.ScriptError(
"Could not create forward DNS zone for the replica: %s" % e)
- try:
- add_fwd_rr(domain, name, ip_address)
- except errors.PublicError, e:
- raise admintool.ScriptError(
- "Could not add forward DNS record for the replica: %s" % e)
+ for reverse_zone in options.reverse_zones:
+ self.log.info("Adding reverse zone %s", reverse_zone)
+ add_zone(reverse_zone)
- if reverse_zone is not None:
- self.log.info("Using reverse zone %s", reverse_zone)
+ for ip in options.ip_addresses:
+ ip_address = str(ip)
try:
- add_zone(reverse_zone)
+ add_fwd_rr(domain, name, ip_address)
except errors.PublicError, e:
raise admintool.ScriptError(
- "Could not create reverse DNS zone for replica: %s" % e)
- try:
- add_ptr_rr(reverse_zone, ip_address, self.replica_fqdn)
- except errors.PublicError, e:
- raise admintool.ScriptError(
- "Could not add reverse DNS record for the replica: %s" % e)
+ "Could not add forward DNS record for the replica: %s" % e)
+
+ if not options.no_reverse:
+ reverse_zone = bindinstance.find_reverse_zone(ip)
+ try:
+ add_ptr_rr(reverse_zone, ip_address, self.replica_fqdn)
+ except errors.PublicError, e:
+ raise admintool.ScriptError(
+ "Could not add reverse DNS record for the replica: %s"
+ % e)
def check_dns(self, replica_fqdn):
"""Return true if the replica hostname is resolvable"""