On 09/12/2014 07:24 PM, Martin Basti wrote:
<snip />

Be careful, reviewed on friday! :-)

1)
whitespace error + pep8 error
patch:76: trailing whitespace.
     # there is reverse zone for every ip address
warning: 1 line adds whitespace errors.

./ipaserver/install/bindinstance.py:640:9: E265 block comment should
start with '# '


Stupid mistake, sorry.


2) (server install)
+    for ip in ip_addresses:
+        for rev_zone in reverse_zones:
+            if bindinstance.verify_reverse_zone(rev_zone, str(ip)):
+                break
+            else:
+                sys.exit(1)

Please add there error message instead 1 to exit function

You are right, it's better to say what's wrong.


3) (server install)
Code above, bindinstance.verify_reverse_zone(rev_zone, str(ip)):
IMHO this will cause errors (not tested) try:
rev-zones: [10.10.10.in-addr.arpa., 16.172.in-addr.arpa.]
ip_addreses: [10.10.10.1, 172.16.0.1]

it should be any() of zone can handle ip

I indented the else branch more that I wanted.


4) (replica-install)
I'm not sure about behavior of combination ip addresses, and reverse zones,
In original code, if user specify reverse zone, the ip address must match.

In patched version, you just add new zones for ip-addresses which
doesn't math the user zones.

IMO we should check if all addresses belongs to user specified zones,
otherwise raise an error.
But I'm open to suggestions.

The behavior now basically is:

Check if IP address matches any specified zone
  a. if yes we are good
  b. else search if there is existing zone that can be used
    ba. if yes we are good
    bb. else ask user for zone or create default if --unattended


5)
Code for ipa-replica-install, and ipa-server-install, differs in parts
where we expecting same behavior
   - ip addresses and reverse zones

The behavoir now should be almost the same. The only difference is that when installing replica we need to search for existing reverse zones as they could be added during on another server.


6)
<https://engineering.redhat.com/irc-services.txt>+    # there is at
least one ip address in every zone
+    if options.reverse_zones:
+        for reverse_zone in options.reverse_zones:
+            for ip in config.ips:
<----------------------------------------------------------------------------------
A
+                if bindinstance.verify_reverse_zone(reverse_zone, ip):
+ reverse_zones.append(bindinstance.normalize_zone(reverse_zone))
+                    break
+            else:
+                sys.exit(1)
<------------------------------------------------------------------------------------------------*
+    # there is reverse zone for every ip address
+    for ip in config.ips:
+        for reverse_zone in options.reverse_zones:
<------------------------------------------------------- B
+            if bindinstance.verify_reverse_zone(reverse_zone, ip):
+                if reverse_zone not in reverse_zones:
+ reverse_zones.append(bindinstance.normalize_zone(reverse_zone))
+                break
+        else:
<------------------------------------------------------------------------------------------------------------
C
+            reverse_zone = bindinstance.find_reverse_zone(ip)
+            if reverse_zone is None and not options.no_reverse:
+                reverse_zone = util.get_reverse_zone_default(ip)
<----------------------------------------- D1
+                if not options.unattended and
bindinstance.create_reverse(): <------------------------- D
+                    reverse_zone =
bindinstance.read_reverse_zone(reverse_zone, ip)
+ reverse_zones.append(bindinstance.normalize_zone(reverse_zone))
<------------- D2

You added all possible zones in step A,  B step is not needed.
If user doesn't specify reverse_zones you can just jump to C step
*add error message
C: elif not options.no_reverse
D: you asked user if wants to create zone, but you don't care about
answer, and in step D2 append zone from D1
note: --no-reverse and --reverse-zones cant be used together, you can
use it in new code, test it before cycle

Rewritten.


7)
          # Always use force=True as named is not set up yet
          add_zone(self.domain, self.zonemgr, dns_backup=self.dns_backup,
-                ns_hostname=api.env.host,
ns_ip_address=nameserver_ip_address,
-                force=True)
+                 ns_hostname=api.env.host, ns_ip_address=None, force=True)
+        #for ns_ip_address in nameserver_ip_address:
+        #    add_zone(self.domain, self.zonemgr,
dns_backup=self.dns_backup,
+        #            ns_hostname=api.env.host, ns_ip_address=ns_ip_address,
+        #            force=True)

Please remove commented section

I forget to clean the trash, thanks.


You can remove 'ns_ip_address=None' from function

8)
+            if set(options.ip_addresses) <= set(ips):
+                ips = options.ip_addresses
+            else:
+                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)

Could you write those extra addresses to output? We need to improve
usability of our error messages



UX is the king :)

--
Martin Basti


--
David Kupka
From 824fa9aea5660c5e2e048409723c02d796a55383 Mon Sep 17 00:00:00 2001
From: David Kupka <dku...@redhat.com>
Date: Wed, 27 Aug 2014 13:50:21 +0200
Subject: [PATCH] Detect and configure all usable IP addresses.

Find, verify and configure all IP addresses that can be used to reach the server
FreeIPA is being installed on. Ignore some IP address only if user specifies
subset of detected addresses using --ip-address option.
This change simplyfies FreeIPA installation on multihomed and dual-stacked servers.

https://fedorahosted.org/freeipa/ticket/3575
---
 install/tools/ipa-replica-install        | 86 +++++++++++++++++++---------
 install/tools/ipa-server-install         | 85 ++++++++++++++++++----------
 ipaserver/install/bindinstance.py        | 73 +++++++++++++-----------
 ipaserver/install/installutils.py        | 96 ++++++++++++++++----------------
 ipaserver/install/ipa_replica_prepare.py | 66 ++++++++++++----------
 5 files changed, 243 insertions(+), 163 deletions(-)

diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index e3b65b0963d92e4d102a1166aa001fe8cb164562..2c711cbf07ea0cb302ce23365e494fd991ef00fc 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -67,8 +67,8 @@ def parse_options():
                       default=False, help="configure a dogtag CA")
     basic_group.add_option("--setup-kra", dest="setup_kra", action="store_true",
                       default=False, help="configure a dogtag KRA")
-    basic_group.add_option("--ip-address", dest="ip_address",
-                      type="ip", ip_local=True,
+    basic_group.add_option("--ip-address", dest="ip_addresses",
+                      type="ip", ip_local=True, action="append", default=[],
                       help="Replica server IP Address")
     basic_group.add_option("-p", "--password", dest="password", sensitive=True,
                       help="Directory Manager (existing master) password")
@@ -112,7 +112,8 @@ def parse_options():
                       type="ip", help="Add a DNS forwarder")
     dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true",
                       default=False, help="Do not add any DNS forwarders, use root servers instead")
-    dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use")
+    dns_group.add_option("--reverse-zone", dest="reverse_zones", default=[],
+                         action="append", help="The reverse DNS zone to use")
     dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true",
                       default=False, help="Do not create new reverse DNS zone")
     dns_group.add_option("--no-host-dns", dest="no_host_dns", action="store_true",
@@ -133,7 +134,7 @@ def parse_options():
             parser.error("You cannot specify a --forwarder option without the --setup-dns option")
         if options.no_forwarders:
             parser.error("You cannot specify a --no-forwarders option without the --setup-dns option")
-        if options.reverse_zone:
+        if options.reverse_zones:
             parser.error("You cannot specify a --reverse-zone option without the --setup-dns option")
         if options.no_reverse:
             parser.error("You cannot specify a --no-reverse option without the --setup-dns option")
@@ -141,7 +142,7 @@ def parse_options():
         parser.error("You cannot specify a --forwarder option together with --no-forwarders")
     elif not options.forwarders and not options.no_forwarders:
         parser.error("You must specify at least one --forwarder option or --no-forwarders option")
-    elif options.reverse_zone and options.no_reverse:
+    elif options.reverse_zones and options.no_reverse:
         parser.error("You cannot specify a --reverse-zone option together with --no-reverse")
 
     return safe_options, options, args[0]
@@ -264,22 +265,53 @@ def install_bind(config, options):
         forwarders = ()
     bind = bindinstance.BindInstance(dm_password=config.dirman_password)
 
-    if options.reverse_zone:
-        if not bindinstance.verify_reverse_zone(options.reverse_zone, config.ip):
-            sys.exit(1)
-        reverse_zone = bindinstance.normalize_zone(options.reverse_zone)
-    else:
-        reverse_zone = bindinstance.find_reverse_zone(config.ip)
-        if reverse_zone is None and not options.no_reverse:
-            reverse_zone = util.get_reverse_zone_default(config.ip)
-            if not options.unattended and bindinstance.create_reverse():
-                reverse_zone = bindinstance.read_reverse_zone(reverse_zone, config.ip)
+    reverse_zones = []
 
-    if reverse_zone is not None:
-        print "Using reverse zone %s" % reverse_zone
+    # check that there is IP address in every reverse zone
+    if options.reverse_zones:
+        for rz in options.reverse_zones:
+            for ip in config.ip_addresses:
+                if bindinstance.verify_reverse_zone(rz, ip):
+                    reverse_zones.append(bindinstance.normalize_zone(rz))
+                    break
+            else:
+                sys.exit("There is no IP address matching reverze_zone %s." % rz)
+    if not options.no_reverse:
+        # check that there is reverse zone for every IP
+        if options.unattended:
+            for ip in config.ip_addresses:
+                if bindinstance.find_reverse_zone(str(ip)):
+                    # reverse zone is already in LDAP
+                    continue
+                for rz in reverse_zones:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        # reverse zone is entered by user
+                        break
+                else:
+                    rz = util.get_reverse_zone_default(str(ip))
+                    reverse_zones.append(rz)
+        elif options.reverse_zones or (not(options.no_reverse) and bindinstance.create_reverse()):
+            for ip in config.ip_addresses:
+                if bindinstance.find_reverse_zone(str(ip)):
+                    # reverse zone is already in LDAP
+                    continue
+                for rz in reverse_zones:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        # reverse zone is entered by user
+                        break
+                else:
+                    rz = util.get_reverse_zone_default(str(ip))
+                    rz = bindinstance.read_reverse_zone(rz, str(ip))
+                    reverse_zones.append(rz)
+        else:
+            options.no_reverse = True
+            reverse_zones = []
+
+    if reverse_zones is not None:
+        print "Using reverse zone(s) %s" % ', '.join(reverse_zones)
 
     bind.setup(config.host_name, config.ip_address, config.realm_name,
-               config.domain_name, forwarders, options.conf_ntp, reverse_zone,
+               config.domain_name, forwarders, options.conf_ntp, reverse_zones,
                ca_configured=options.setup_ca)
     bind.create_instance()
 
@@ -326,12 +358,16 @@ def install_dns_records(config, options):
             config.master_host_name, config.dirman_password):
         try:
             bind = bindinstance.BindInstance(dm_password=config.dirman_password)
-            reverse_zone = bindinstance.find_reverse_zone(config.ip)
+            for ip, ip_address in zip(config.ips, config.ip_addresses):
+                reverse_zone = bindinstance.find_reverse_zone(ip)
 
-            bind.add_master_dns_records(config.host_name, config.ip_address,
-                                        config.realm_name, config.domain_name,
-                                        reverse_zone, options.conf_ntp,
-                                        options.setup_ca)
+                bind.add_master_dns_records(config.host_name,
+                                            ip_address,
+                                            config.realm_name,
+                                            config.domain_name,
+                                            reverse_zone,
+                                            options.conf_ntp,
+                                            options.setup_ca)
         except errors.NotFound, e:
             root_logger.debug('Replica DNS records could not be added '
                               'on master: %s', str(e))
@@ -534,8 +570,8 @@ def main():
 
 
     # check replica host IP resolution
-    config.ip = installutils.get_server_ip_address(config.host_name, fstore, True, options)
-    config.ip_address = str(config.ip)
+    config.ips = installutils.get_server_ip_address(config.host_name, fstore, True, options)
+    config.ip_addresses = [str(ip) for ip in config.ips]
 
     # Create the management framework config file
     # Note: We must do this before bootstraping and finalizing ipalib.api
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index c8191495121a98023566c07f2b1e6892344cc707..a161e4f9d3f853c2306b02f02808c23a936cfda5 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -175,8 +175,8 @@ def parse_options():
                            help="create home directories for users "
                                 "on their first login")
     basic_group.add_option("--hostname", dest="host_name", help="fully qualified name of server")
-    basic_group.add_option("--ip-address", dest="ip_address",
-                      type="ip", ip_local=True,
+    basic_group.add_option("--ip-address", dest="ip_addresses",
+                      type="ip", ip_local=True, action="append", default=[],
                       help="Master Server IP Address")
     basic_group.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false",
                       help="do not configure ntp", default=True)
@@ -236,7 +236,8 @@ def parse_options():
                       type="ip", help="Add a DNS forwarder")
     dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true",
                       default=False, help="Do not add any DNS forwarders, use root servers instead")
-    dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use")
+    dns_group.add_option("--reverse-zone", dest="reverse_zones", help="The reverse DNS zone to use",
+                      action="append", default=[])
     dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true",
                       default=False, help="Do not create reverse DNS zone")
     dns_group.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback,
@@ -280,13 +281,13 @@ def parse_options():
             parser.error("You cannot specify a --forwarder option without the --setup-dns option")
         if options.no_forwarders:
             parser.error("You cannot specify a --no-forwarders option without the --setup-dns option")
-        if options.reverse_zone:
+        if options.reverse_zones:
             parser.error("You cannot specify a --reverse-zone option without the --setup-dns option")
         if options.no_reverse:
             parser.error("You cannot specify a --no-reverse option without the --setup-dns option")
     elif options.forwarders and options.no_forwarders:
         parser.error("You cannot specify a --forwarder option together with --no-forwarders")
-    elif options.reverse_zone and options.no_reverse:
+    elif options.reverse_zones and options.no_reverse:
         parser.error("You cannot specify a --reverse-zone option together with --no-reverse")
 
     if options.uninstall:
@@ -828,11 +829,11 @@ def main():
     realm_name = ""
     host_name = ""
     domain_name = ""
-    ip_address = ""
+    ip_addresses = []
     master_password = ""
     dm_password = ""
     admin_password = ""
-    reverse_zone = None
+    reverse_zones = []
 
     if not options.setup_dns and not options.unattended:
         if ipautil.user_input("Do you want to configure integrated DNS (BIND)?", False):
@@ -891,11 +892,14 @@ def main():
 
     domain_name = domain_name.lower()
 
-    ip = get_server_ip_address(host_name, fstore, options.unattended, options)
-    ip_address = str(ip)
+    ip_addresses = get_server_ip_address(host_name, fstore, options.unattended, options)
 
-    if options.reverse_zone and not bindinstance.verify_reverse_zone(options.reverse_zone, ip):
-        sys.exit(1)
+    for ip in ip_addresses:
+        for rev_zone in reverse_zones:
+            if bindinstance.verify_reverse_zone(rev_zone, str(ip)):
+                break
+            else:
+                sys.exit(1)
 
     if not options.realm_name:
         realm_name = read_realm_name(domain_name, options.unattended)
@@ -972,27 +976,52 @@ def main():
         else:
             dns_forwarders = read_dns_forwarders()
 
-        if options.reverse_zone:
-            reverse_zone = bindinstance.normalize_zone(options.reverse_zone)
-        elif not options.no_reverse:
+        # check that there is IP address in every reverse zone
+        if options.reverse_zones:
+            for rz in options.reverse_zones:
+                for ip in ip_addresses:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        reverse_zones.append(bindinstance.normalize_zone(rz))
+                        break
+                else:
+                    sys.exit("There is no IP address matching reverze_zone %s." % rz)
+        if not options.no_reverse:
+            # check that there is reverse zone for every IP
             if options.unattended:
-                reverse_zone = util.get_reverse_zone_default(ip)
-            elif bindinstance.create_reverse():
-                reverse_zone = util.get_reverse_zone_default(ip)
-                reverse_zone = bindinstance.read_reverse_zone(reverse_zone, ip)
+                for ip in ip_addresses:
+                    for rz in reverse_zones:
+                        if bindinstance.verify_reverse_zone(rz, ip):
+                            # reverse zone is entered by user
+                            break
+                    else:
+                        rz = util.get_reverse_zone_default(str(ip))
+                        reverse_zones.append(rz)
+            elif options.reverse_zones or (not(options.no_reverse) and bindinstance.create_reverse()):
+                for ip in ip_addresses:
+                    for rz in reverse_zones:
+                        if bindinstance.verify_reverse_zone(rz, ip):
+                            # reverse zone is entered by user
+                            break
+                    else:
+                        rz = util.get_reverse_zone_default(str(ip))
+                        rz = bindinstance.read_reverse_zone(rz, str(ip))
+                        reverse_zones.append(rz)
+            else:
+                options.no_reverse = True
+                reverse_zones = []
 
-        if reverse_zone is not None:
-            print "Using reverse zone %s" % reverse_zone
+        if reverse_zones:
+            print "Using reverse zone(s) %s" % ", ".join(str(rz) for rz in reverse_zones)
     else:
         dns_forwarders = ()
     root_logger.debug("will use dns_forwarders: %s\n" % str(dns_forwarders))
 
     print
     print "The IPA Master Server will be configured with:"
-    print "Hostname:      %s" % host_name
-    print "IP address:    %s" % ip_address
-    print "Domain name:   %s" % domain_name
-    print "Realm name:    %s" % realm_name
+    print "Hostname:       %s" % host_name
+    print "IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses)
+    print "Domain name:    %s" % domain_name
+    print "Realm name:     %s" % realm_name
     print
 
     if options.setup_dns:
@@ -1000,7 +1029,7 @@ def main():
         print "Forwarders:    %s" % ("No forwarders" if not dns_forwarders \
                 else ", ".join([str(ip) for ip in dns_forwarders]))
         print "Reverse zone:  %s" % ("No reverse zone" if options.no_reverse \
-                or reverse_zone is None else reverse_zone)
+                or reverse_zones is None else ", ".join(str(rz) for rz in reverse_zones))
         print
 
     # If domain name and realm does not match, IPA server will not be able
@@ -1111,7 +1140,7 @@ def main():
             options.host_name = host_name
             options.unattended = True
             options.forwarders = dns_forwarders
-            options.reverse_zone = reverse_zone
+            options.reverse_zones = reverse_zones
             write_cache(vars(options))
             ca.configure_instance(host_name, domain_name, dm_password,
                                   dm_password, csr_file=paths.ROOT_IPA_CSR,
@@ -1205,8 +1234,8 @@ def main():
 
     # Create a BIND instance
     bind = bindinstance.BindInstance(fstore, dm_password)
-    bind.setup(host_name, ip_address, realm_name, domain_name, dns_forwarders,
-               options.conf_ntp, reverse_zone, zonemgr=options.zonemgr,
+    bind.setup(host_name, ip_addresses, realm_name, domain_name, dns_forwarders,
+               options.conf_ntp, reverse_zones, zonemgr=options.zonemgr,
                ca_configured=setup_ca)
     if options.setup_dns:
         api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 9a27c781764f3dc311d20cfcf9150fde31307b03..41a847cdb1d1b6a9293dca1ec1247b98291146ec 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -265,7 +265,7 @@ def verify_reverse_zone(zone, ip_address):
     try:
         get_reverse_record_name(zone, ip_address)
     except ValueError:
-        print "Invalid reverse zone %s" % zone
+        print "Invalid reverse zone %s for IP address %s" % (zone, ip_address)
         return False
 
     return True
@@ -467,11 +467,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:
@@ -481,19 +481,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:
@@ -539,8 +539,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)
@@ -552,7 +553,7 @@ class BindInstance(service.Service):
             self.step("adding NS record to the zone", self.__add_self_ns)
         else:
             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)
@@ -603,18 +604,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,
@@ -630,15 +630,13 @@ class BindInstance(service.Service):
         self._ldap_mod("dns.ldif", self.sub_dict)
 
     def __setup_zone(self):
-        nameserver_ip_address = self.ip_address
+        nameserver_ip_address = self.ip_addresses
         if not self.host_in_default_domain():
             # Nameserver is in self.host_domain, no forward record added to self.domain
             nameserver_ip_address = None
         # Always use force=True as named is not set up yet
         add_zone(self.domain, self.zonemgr, dns_backup=self.dns_backup,
-                ns_hostname=api.env.host, ns_ip_address=nameserver_ip_address,
-                force=True)
-
+                 ns_hostname=api.env.host, force=True)
         add_rr(self.domain, "_kerberos", "TXT", self.realm)
 
     def __add_self_ns(self):
@@ -646,7 +644,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):
@@ -682,7 +681,7 @@ class BindInstance(service.Service):
             root_logger.debug("Add DNS zone for host first.")
 
             if normalize_zone(zone) == normalize_zone(self.host_domain):
-                ns_ip_address = self.ip_address
+                ns_ip_address = self.ip_addresses
             else:
                 ns_ip_address = None
 
@@ -699,7 +698,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(
@@ -744,7 +743,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:
@@ -832,7 +831,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)
@@ -846,16 +855,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 e4cf5040f28d583576ee472be12ce31b8a451ab3..e6de5c1816121a23a7c57a694ced451e3f98b553 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -437,74 +437,74 @@ def get_server_ip_address(host_name, fstore, unattended, options):
 
     ip_add_to_hosts = False
 
+    ips = []
     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
-
-        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
-        else:
+        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 not ips:
             if unattended:
                 print >> sys.stderr, "Please use --ip-address option to specify the address"
                 sys.exit(1)
             else:
-                ip = read_ip_address(host_name, fstore)
+                ips.append(read_ip_address(host_name, fstore))
     elif len(hostaddr) == 1:
         try:
-            ip = ipautil.CheckedIPAddress(hostaddr[0], match_local=True)
+            ips.append(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:
+    elif options.ip_addresses:
         # hostname is not resolvable
-        ip = options.ip_address
+        ips = options.ip_addresses
         ip_add_to_hosts = True
 
-    if ip is None:
+    if not ips:
         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)
+    if options.ip_addresses:
+        if options.setup_dns:
+            ips = options.ip_addresses
+        else:
+            # all specified addresses was resolved for this host
+            if set(options.ip_addresses) <= set(ips):
+                ips = options.ip_addresses
+            else:
+                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(options.ip_addresses) - set(ips)))
+                sys.exit(1)
 
-        ip = options.ip_address
+    if not ips:
+        ips.append(read_ip_address(host_name, fstore))
+        root_logger.debug("read ip_address: %s\n" % ips[0])
 
-    if ip is None:
-        ip = read_ip_address(host_name, fstore)
-        root_logger.debug("read ip_address: %s\n" % str(ip))
+    for ip_address in ips:
+        # check /etc/hosts sanity, add a record when needed
+        hosts_record = record_in_hosts(str(ip_address))
 
-    ip_address = str(ip)
+        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)
 
-    # 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 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 2e91ddd92d9eb9ccd690daa1c78d9027f1b0b965..9619147aa537e5ceb52bda4bda98449099f36c25 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -51,9 +51,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,
@@ -89,14 +91,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")
 
@@ -186,7 +188,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,
@@ -200,7 +202,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):
@@ -209,9 +211,14 @@ 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")
+            for reverse_zone in options.reverse_zones:
+                for ip_address in options.ip_addresses:
+                    if bindinstance.verify_reverse_zone(reverse_zone,
+                            ip_address):
+                        break
+                    else:
+                        raise admintool.ScriptError("Invalid reverse zone %s"
+                                                    % reverse_zone)
 
         if options.http_pkcs12:
             if options.http_pin is None:
@@ -287,7 +294,7 @@ class ReplicaPrepare(admintool.AdminTool):
         finally:
             shutil.rmtree(self.top_dir)
 
-        if options.ip_address:
+        if options.ip_addresses:
             self.add_dns_records()
 
     def copy_ds_certificate(self):
@@ -417,40 +424,39 @@ class ReplicaPrepare(admintool.AdminTool):
 
         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)
-
         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)
-
-        if reverse_zone is not None:
+        for rz in options.reverse_zones:
+            reverse_zone = bindinstance.normalize_zone(rz)
             self.log.info("Using reverse zone %s", reverse_zone)
             try:
                 add_zone(reverse_zone)
             except errors.PublicError, e:
                 raise admintool.ScriptError(
                     "Could not create reverse DNS zone for replica: %s" % e)
+
+        for ip in options.ip_addresses:
+            ip_address = str(ip)
             try:
-                add_ptr_rr(reverse_zone, ip_address, self.replica_fqdn)
+                add_fwd_rr(domain, name, ip_address)
             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.get_reverse_zone(ip)
+                if reverse_zone not in options.reverse_zones:
+                    add_zone(reverse_zone)
+                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 copy_info_file(self, source, dest):
         """Copy a file into the info directory
-- 
1.9.3

From 691d0ba0234a3cd007d3edb14e67a762e0df5406 Mon Sep 17 00:00:00 2001
From: David Kupka <dku...@redhat.com>
Date: Wed, 27 Aug 2014 13:50:21 +0200
Subject: [PATCH] Detect and configure all usable IP addresses.

Find, verify and configure all IP addresses that can be used to reach the server
FreeIPA is being installed on. Ignore some IP address only if user specifies
subset of detected addresses using --ip-address option.
This change simplyfies FreeIPA installation on multihomed and dual-stacked servers.

https://fedorahosted.org/freeipa/ticket/3575
---
 install/tools/ipa-replica-install        | 88 ++++++++++++++++++++---------
 install/tools/ipa-server-install         | 85 ++++++++++++++++++----------
 ipaserver/install/bindinstance.py        | 73 +++++++++++++-----------
 ipaserver/install/installutils.py        | 96 ++++++++++++++++----------------
 ipaserver/install/ipa_replica_prepare.py | 66 ++++++++++++----------
 5 files changed, 245 insertions(+), 163 deletions(-)

diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index f7dfafc6b293afdd241aa0a49864f195efeee6c4..ad6a259492bc63b9452c90805d7e09668ea90893 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -65,8 +65,10 @@ def parse_options():
     basic_group = OptionGroup(parser, "basic options")
     basic_group.add_option("--setup-ca", dest="setup_ca", action="store_true",
                       default=False, help="configure a dogtag CA")
-    basic_group.add_option("--ip-address", dest="ip_address",
-                      type="ip", ip_local=True,
+    basic_group.add_option("--setup-kra", dest="setup_kra", action="store_true",
+                      default=False, help="configure a dogtag KRA")
+    basic_group.add_option("--ip-address", dest="ip_addresses",
+                      type="ip", ip_local=True, action="append", default=[],
                       help="Replica server IP Address")
     basic_group.add_option("-p", "--password", dest="password", sensitive=True,
                       help="Directory Manager (existing master) password")
@@ -110,7 +112,8 @@ def parse_options():
                       type="ip", help="Add a DNS forwarder")
     dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true",
                       default=False, help="Do not add any DNS forwarders, use root servers instead")
-    dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use")
+    dns_group.add_option("--reverse-zone", dest="reverse_zones", default=[],
+                         action="append", help="The reverse DNS zone to use")
     dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true",
                       default=False, help="Do not create new reverse DNS zone")
     dns_group.add_option("--no-host-dns", dest="no_host_dns", action="store_true",
@@ -131,7 +134,7 @@ def parse_options():
             parser.error("You cannot specify a --forwarder option without the --setup-dns option")
         if options.no_forwarders:
             parser.error("You cannot specify a --no-forwarders option without the --setup-dns option")
-        if options.reverse_zone:
+        if options.reverse_zones:
             parser.error("You cannot specify a --reverse-zone option without the --setup-dns option")
         if options.no_reverse:
             parser.error("You cannot specify a --no-reverse option without the --setup-dns option")
@@ -139,7 +142,7 @@ def parse_options():
         parser.error("You cannot specify a --forwarder option together with --no-forwarders")
     elif not options.forwarders and not options.no_forwarders:
         parser.error("You must specify at least one --forwarder option or --no-forwarders option")
-    elif options.reverse_zone and options.no_reverse:
+    elif options.reverse_zones and options.no_reverse:
         parser.error("You cannot specify a --reverse-zone option together with --no-reverse")
 
     return safe_options, options, args[0]
@@ -261,22 +264,53 @@ def install_bind(config, options):
         forwarders = ()
     bind = bindinstance.BindInstance(dm_password=config.dirman_password)
 
-    if options.reverse_zone:
-        if not bindinstance.verify_reverse_zone(options.reverse_zone, config.ip):
-            sys.exit(1)
-        reverse_zone = bindinstance.normalize_zone(options.reverse_zone)
-    else:
-        reverse_zone = bindinstance.find_reverse_zone(config.ip)
-        if reverse_zone is None and not options.no_reverse:
-            reverse_zone = util.get_reverse_zone_default(config.ip)
-            if not options.unattended and bindinstance.create_reverse():
-                reverse_zone = bindinstance.read_reverse_zone(reverse_zone, config.ip)
+    reverse_zones = []
 
-    if reverse_zone is not None:
-        print "Using reverse zone %s" % reverse_zone
+    # check that there is IP address in every reverse zone
+    if options.reverse_zones:
+        for rz in options.reverse_zones:
+            for ip in config.ip_addresses:
+                if bindinstance.verify_reverse_zone(rz, ip):
+                    reverse_zones.append(bindinstance.normalize_zone(rz))
+                    break
+            else:
+                sys.exit("There is no IP address matching reverze_zone %s." % rz)
+    if not options.no_reverse:
+        # check that there is reverse zone for every IP
+        if options.unattended:
+            for ip in config.ip_addresses:
+                if bindinstance.find_reverse_zone(str(ip)):
+                    # reverse zone is already in LDAP
+                    continue
+                for rz in reverse_zones:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        # reverse zone is entered by user
+                        break
+                else:
+                    rz = util.get_reverse_zone_default(str(ip))
+                    reverse_zones.append(rz)
+        elif options.reverse_zones or (not(options.no_reverse) and bindinstance.create_reverse()):
+            for ip in config.ip_addresses:
+                if bindinstance.find_reverse_zone(str(ip)):
+                    # reverse zone is already in LDAP
+                    continue
+                for rz in reverse_zones:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        # reverse zone is entered by user
+                        break
+                else:
+                    rz = util.get_reverse_zone_default(str(ip))
+                    rz = bindinstance.read_reverse_zone(rz, str(ip))
+                    reverse_zones.append(rz)
+        else:
+            options.no_reverse = True
+            reverse_zones = []
+
+    if reverse_zones is not None:
+        print "Using reverse zone(s) %s" % ', '.join(reverse_zones)
 
     bind.setup(config.host_name, config.ip_address, config.realm_name,
-               config.domain_name, forwarders, options.conf_ntp, reverse_zone,
+               config.domain_name, forwarders, options.conf_ntp, reverse_zones,
                ca_configured=options.setup_ca)
     bind.create_instance()
 
@@ -323,12 +357,16 @@ def install_dns_records(config, options):
             config.master_host_name, config.dirman_password):
         try:
             bind = bindinstance.BindInstance(dm_password=config.dirman_password)
-            reverse_zone = bindinstance.find_reverse_zone(config.ip)
+            for ip, ip_address in zip(config.ips, config.ip_addresses):
+                reverse_zone = bindinstance.find_reverse_zone(ip)
 
-            bind.add_master_dns_records(config.host_name, config.ip_address,
-                                        config.realm_name, config.domain_name,
-                                        reverse_zone, options.conf_ntp,
-                                        options.setup_ca)
+                bind.add_master_dns_records(config.host_name,
+                                            ip_address,
+                                            config.realm_name,
+                                            config.domain_name,
+                                            reverse_zone,
+                                            options.conf_ntp,
+                                            options.setup_ca)
         except errors.NotFound, e:
             root_logger.debug('Replica DNS records could not be added '
                               'on master: %s', str(e))
@@ -551,8 +589,8 @@ def main():
 
 
     # check replica host IP resolution
-    config.ip = installutils.get_server_ip_address(config.host_name, fstore, True, options)
-    config.ip_address = str(config.ip)
+    config.ips = installutils.get_server_ip_address(config.host_name, fstore, True, options)
+    config.ip_addresses = [str(ip) for ip in config.ips]
 
     # Create the management framework config file
     # Note: We must do this before bootstraping and finalizing ipalib.api
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 207dabde9faf1cbb1cc401482ccdbefdae29d726..25a65faf4e86c4dfee6f9c6eeab005f8832cc1b0 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -174,8 +174,8 @@ def parse_options():
                            help="create home directories for users "
                                 "on their first login")
     basic_group.add_option("--hostname", dest="host_name", help="fully qualified name of server")
-    basic_group.add_option("--ip-address", dest="ip_address",
-                      type="ip", ip_local=True,
+    basic_group.add_option("--ip-address", dest="ip_addresses",
+                      type="ip", ip_local=True, action="append", default=[],
                       help="Master Server IP Address")
     basic_group.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false",
                       help="do not configure ntp", default=True)
@@ -235,7 +235,8 @@ def parse_options():
                       type="ip", help="Add a DNS forwarder")
     dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true",
                       default=False, help="Do not add any DNS forwarders, use root servers instead")
-    dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use")
+    dns_group.add_option("--reverse-zone", dest="reverse_zones", help="The reverse DNS zone to use",
+                      action="append", default=[])
     dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true",
                       default=False, help="Do not create reverse DNS zone")
     dns_group.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback,
@@ -279,13 +280,13 @@ def parse_options():
             parser.error("You cannot specify a --forwarder option without the --setup-dns option")
         if options.no_forwarders:
             parser.error("You cannot specify a --no-forwarders option without the --setup-dns option")
-        if options.reverse_zone:
+        if options.reverse_zones:
             parser.error("You cannot specify a --reverse-zone option without the --setup-dns option")
         if options.no_reverse:
             parser.error("You cannot specify a --no-reverse option without the --setup-dns option")
     elif options.forwarders and options.no_forwarders:
         parser.error("You cannot specify a --forwarder option together with --no-forwarders")
-    elif options.reverse_zone and options.no_reverse:
+    elif options.reverse_zones and options.no_reverse:
         parser.error("You cannot specify a --reverse-zone option together with --no-reverse")
 
     if options.uninstall:
@@ -811,11 +812,11 @@ def main():
     realm_name = ""
     host_name = ""
     domain_name = ""
-    ip_address = ""
+    ip_addresses = []
     master_password = ""
     dm_password = ""
     admin_password = ""
-    reverse_zone = None
+    reverse_zones = []
 
     if not options.setup_dns and not options.unattended:
         if ipautil.user_input("Do you want to configure integrated DNS (BIND)?", False):
@@ -874,11 +875,14 @@ def main():
 
     domain_name = domain_name.lower()
 
-    ip = get_server_ip_address(host_name, fstore, options.unattended, options)
-    ip_address = str(ip)
+    ip_addresses = get_server_ip_address(host_name, fstore, options.unattended, options)
 
-    if options.reverse_zone and not bindinstance.verify_reverse_zone(options.reverse_zone, ip):
-        sys.exit(1)
+    for ip in ip_addresses:
+        for rev_zone in reverse_zones:
+            if bindinstance.verify_reverse_zone(rev_zone, str(ip)):
+                break
+            else:
+                sys.exit(1)
 
     if not options.realm_name:
         realm_name = read_realm_name(domain_name, options.unattended)
@@ -955,27 +959,52 @@ def main():
         else:
             dns_forwarders = read_dns_forwarders()
 
-        if options.reverse_zone:
-            reverse_zone = bindinstance.normalize_zone(options.reverse_zone)
-        elif not options.no_reverse:
+        # check that there is IP address in every reverse zone
+        if options.reverse_zones:
+            for rz in options.reverse_zones:
+                for ip in ip_addresses:
+                    if bindinstance.verify_reverse_zone(rz, ip):
+                        reverse_zones.append(bindinstance.normalize_zone(rz))
+                        break
+                else:
+                    sys.exit("There is no IP address matching reverze_zone %s." % rz)
+        if not options.no_reverse:
+            # check that there is reverse zone for every IP
             if options.unattended:
-                reverse_zone = util.get_reverse_zone_default(ip)
-            elif bindinstance.create_reverse():
-                reverse_zone = util.get_reverse_zone_default(ip)
-                reverse_zone = bindinstance.read_reverse_zone(reverse_zone, ip)
+                for ip in ip_addresses:
+                    for rz in reverse_zones:
+                        if bindinstance.verify_reverse_zone(rz, ip):
+                            # reverse zone is entered by user
+                            break
+                    else:
+                        rz = util.get_reverse_zone_default(str(ip))
+                        reverse_zones.append(rz)
+            elif options.reverse_zones or (not(options.no_reverse) and bindinstance.create_reverse()):
+                for ip in ip_addresses:
+                    for rz in reverse_zones:
+                        if bindinstance.verify_reverse_zone(rz, ip):
+                            # reverse zone is entered by user
+                            break
+                    else:
+                        rz = util.get_reverse_zone_default(str(ip))
+                        rz = bindinstance.read_reverse_zone(rz, str(ip))
+                        reverse_zones.append(rz)
+            else:
+                options.no_reverse = True
+                reverse_zones = []
 
-        if reverse_zone is not None:
-            print "Using reverse zone %s" % reverse_zone
+        if reverse_zones:
+            print "Using reverse zone(s) %s" % ", ".join(str(rz) for rz in reverse_zones)
     else:
         dns_forwarders = ()
     root_logger.debug("will use dns_forwarders: %s\n" % str(dns_forwarders))
 
     print
     print "The IPA Master Server will be configured with:"
-    print "Hostname:      %s" % host_name
-    print "IP address:    %s" % ip_address
-    print "Domain name:   %s" % domain_name
-    print "Realm name:    %s" % realm_name
+    print "Hostname:       %s" % host_name
+    print "IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses)
+    print "Domain name:    %s" % domain_name
+    print "Realm name:     %s" % realm_name
     print
 
     if options.setup_dns:
@@ -983,7 +1012,7 @@ def main():
         print "Forwarders:    %s" % ("No forwarders" if not dns_forwarders \
                 else ", ".join([str(ip) for ip in dns_forwarders]))
         print "Reverse zone:  %s" % ("No reverse zone" if options.no_reverse \
-                or reverse_zone is None else reverse_zone)
+                or reverse_zones is None else ", ".join(str(rz) for rz in reverse_zones))
         print
 
     # If domain name and realm does not match, IPA server will not be able
@@ -1093,7 +1122,7 @@ def main():
             options.host_name = host_name
             options.unattended = True
             options.forwarders = dns_forwarders
-            options.reverse_zone = reverse_zone
+            options.reverse_zones = reverse_zones
             write_cache(vars(options))
             ca.configure_instance(host_name, domain_name, dm_password,
                                   dm_password, csr_file=paths.ROOT_IPA_CSR,
@@ -1187,8 +1216,8 @@ def main():
 
     # Create a BIND instance
     bind = bindinstance.BindInstance(fstore, dm_password)
-    bind.setup(host_name, ip_address, realm_name, domain_name, dns_forwarders,
-               options.conf_ntp, reverse_zone, zonemgr=options.zonemgr,
+    bind.setup(host_name, ip_addresses, realm_name, domain_name, dns_forwarders,
+               options.conf_ntp, reverse_zones, zonemgr=options.zonemgr,
                ca_configured=setup_ca)
     if options.setup_dns:
         api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 9a27c781764f3dc311d20cfcf9150fde31307b03..41a847cdb1d1b6a9293dca1ec1247b98291146ec 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -265,7 +265,7 @@ def verify_reverse_zone(zone, ip_address):
     try:
         get_reverse_record_name(zone, ip_address)
     except ValueError:
-        print "Invalid reverse zone %s" % zone
+        print "Invalid reverse zone %s for IP address %s" % (zone, ip_address)
         return False
 
     return True
@@ -467,11 +467,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:
@@ -481,19 +481,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:
@@ -539,8 +539,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)
@@ -552,7 +553,7 @@ class BindInstance(service.Service):
             self.step("adding NS record to the zone", self.__add_self_ns)
         else:
             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)
@@ -603,18 +604,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,
@@ -630,15 +630,13 @@ class BindInstance(service.Service):
         self._ldap_mod("dns.ldif", self.sub_dict)
 
     def __setup_zone(self):
-        nameserver_ip_address = self.ip_address
+        nameserver_ip_address = self.ip_addresses
         if not self.host_in_default_domain():
             # Nameserver is in self.host_domain, no forward record added to self.domain
             nameserver_ip_address = None
         # Always use force=True as named is not set up yet
         add_zone(self.domain, self.zonemgr, dns_backup=self.dns_backup,
-                ns_hostname=api.env.host, ns_ip_address=nameserver_ip_address,
-                force=True)
-
+                 ns_hostname=api.env.host, force=True)
         add_rr(self.domain, "_kerberos", "TXT", self.realm)
 
     def __add_self_ns(self):
@@ -646,7 +644,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):
@@ -682,7 +681,7 @@ class BindInstance(service.Service):
             root_logger.debug("Add DNS zone for host first.")
 
             if normalize_zone(zone) == normalize_zone(self.host_domain):
-                ns_ip_address = self.ip_address
+                ns_ip_address = self.ip_addresses
             else:
                 ns_ip_address = None
 
@@ -699,7 +698,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(
@@ -744,7 +743,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:
@@ -832,7 +831,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)
@@ -846,16 +855,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 0f85c26cb1940b1cd6fcf8debe93ffed3a1d1184..45d4a36b34e3d200b8aba98b0c662eb1afe581b4 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -436,74 +436,74 @@ def get_server_ip_address(host_name, fstore, unattended, options):
 
     ip_add_to_hosts = False
 
+    ips = []
     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
-
-        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
-        else:
+        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 not ips:
             if unattended:
                 print >> sys.stderr, "Please use --ip-address option to specify the address"
                 sys.exit(1)
             else:
-                ip = read_ip_address(host_name, fstore)
+                ips.append(read_ip_address(host_name, fstore))
     elif len(hostaddr) == 1:
         try:
-            ip = ipautil.CheckedIPAddress(hostaddr[0], match_local=True)
+            ips.append(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:
+    elif options.ip_addresses:
         # hostname is not resolvable
-        ip = options.ip_address
+        ips = options.ip_addresses
         ip_add_to_hosts = True
 
-    if ip is None:
+    if not ips:
         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)
+    if options.ip_addresses:
+        if options.setup_dns:
+            ips = options.ip_addresses
+        else:
+            # all specified addresses was resolved for this host
+            if set(options.ip_addresses) <= set(ips):
+                ips = options.ip_addresses
+            else:
+                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(options.ip_addresses) - set(ips)))
+                sys.exit(1)
 
-        ip = options.ip_address
+    if not ips:
+        ips.append(read_ip_address(host_name, fstore))
+        root_logger.debug("read ip_address: %s\n" % ips[0])
 
-    if ip is None:
-        ip = read_ip_address(host_name, fstore)
-        root_logger.debug("read ip_address: %s\n" % str(ip))
+    for ip_address in ips:
+        # check /etc/hosts sanity, add a record when needed
+        hosts_record = record_in_hosts(str(ip_address))
 
-    ip_address = str(ip)
+        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)
 
-    # 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 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 7762614a1174208db0915d4e882212b3f578476e..274d5f4befeb41a409b294accaff0f3eb61f7270 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -51,9 +51,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,
@@ -89,14 +91,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")
 
@@ -186,7 +188,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,
@@ -200,7 +202,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):
@@ -209,9 +211,14 @@ 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")
+            for reverse_zone in options.reverse_zones:
+                for ip_address in options.ip_addresses:
+                    if bindinstance.verify_reverse_zone(reverse_zone,
+                            ip_address):
+                        break
+                    else:
+                        raise admintool.ScriptError("Invalid reverse zone %s"
+                                                    % reverse_zone)
 
         if options.http_pkcs12:
             if options.http_pin is None:
@@ -287,7 +294,7 @@ class ReplicaPrepare(admintool.AdminTool):
         finally:
             shutil.rmtree(self.top_dir)
 
-        if options.ip_address:
+        if options.ip_addresses:
             self.add_dns_records()
 
     def copy_ds_certificate(self):
@@ -416,40 +423,39 @@ class ReplicaPrepare(admintool.AdminTool):
 
         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)
-
         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)
-
-        if reverse_zone is not None:
+        for rz in options.reverse_zones:
+            reverse_zone = bindinstance.normalize_zone(rz)
             self.log.info("Using reverse zone %s", reverse_zone)
             try:
                 add_zone(reverse_zone)
             except errors.PublicError, e:
                 raise admintool.ScriptError(
                     "Could not create reverse DNS zone for replica: %s" % e)
+
+        for ip in options.ip_addresses:
+            ip_address = str(ip)
             try:
-                add_ptr_rr(reverse_zone, ip_address, self.replica_fqdn)
+                add_fwd_rr(domain, name, ip_address)
             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.get_reverse_zone(ip)
+                if reverse_zone not in options.reverse_zones:
+                    add_zone(reverse_zone)
+                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 copy_info_file(self, source, dest):
         """Copy a file into the info directory
-- 
1.9.3

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to