[Freeipa-devel] PATCH: setup bind as part of server configuration

Pete Rowley prowley at redhat.com
Thu Sep 20 20:17:05 UTC 2007


Simo Sorce wrote:
> This patch will help QA, you have to explicitly pass --setup-bind and no
> question about it is asked if you don't.
>   
Ack
> ------------------------------------------------------------------------
>
> # HG changeset patch
> # User Simo Sorce <ssorce at redhat.com>
> # Date 1190315421 14400
> # Node ID 9353b33672ee1bf8afabee1615d2cd4aebcce019
> # Parent  578d26927d915e3c85bded0c2206cf9679a58977
> Initial support for confiuguring a DNS Server during installation.
> It's not perfect yet but good enough to include it.
>
> diff -r 578d26927d91 -r 9353b33672ee ipa-client/ipa-install/ipa-client-install
> --- a/ipa-client/ipa-install/ipa-client-install	Thu Sep 13 12:10:55 2007 -0400
> +++ b/ipa-client/ipa-install/ipa-client-install	Thu Sep 20 15:10:21 2007 -0400
> @@ -31,7 +31,6 @@ import ipaclient.ipadiscovery
>  import ipaclient.ipadiscovery
>  import ipaclient.ipachangeconf
>  from ipa.ipautil import run
> -import shutil
>  
>  def parse_options():
>      parser = OptionParser(version=VERSION)
> diff -r 578d26927d91 -r 9353b33672ee ipa-server/ipa-install/ipa-server-install
> --- a/ipa-server/ipa-install/ipa-server-install	Thu Sep 13 12:10:55 2007 -0400
> +++ b/ipa-server/ipa-install/ipa-server-install	Thu Sep 20 15:10:21 2007 -0400
> @@ -36,6 +36,7 @@ from optparse import OptionParser
>  from optparse import OptionParser
>  import ipaserver.dsinstance
>  import ipaserver.krbinstance
> +import ipaserver.bindinstance
>  from ipa.ipautil import run
>  
>  def parse_options():
> @@ -51,10 +52,13 @@ def parse_options():
>      parser.add_option("-a", "--admin-password", dest="admin_password",
>                        help="admin user kerberos password")
>      parser.add_option("-d", "--debug", dest="debug", action="store_true",
> -                     dest="debug", default=False, help="print debugging information")
> +                      default=False, help="print debugging information")
>      parser.add_option("--hostname", dest="host_name", help="fully qualified name of server")
> -    parser.add_option("-U", "--unattended", dest="unattended",
> -                     help="unattended installation never prompts the user")
> +    parser.add_option("--ip-address", dest="ip_address", help="Master Server IP Address")
> +    parser.add_option("--setup-bind", dest="setup_bind", action="store_true",
> +                      default=False, help="configure bind with our zone file")
> +    parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
> +                      default=False, help="unattended installation never prompts the user")
>  
>      options, args = parser.parse_args()
>  
> @@ -63,7 +67,7 @@ def parse_options():
>                                 not options.dm_password or
>                                 not options.admin_password or
>                                 not options.master_password):
> -        parser.error("error: In unattended mode you need to provide -u, -r, -p and -P options")
> +        parser.error("error: In unattended mode you need to provide iat least -u, -r, -p and -P options")
>  
>      return options
>  
> @@ -93,34 +97,140 @@ def main():
>      ds_user = ""
>      realm_name = ""
>      host_name = ""
> +    domain_name = ""
> +    ip_address = ""
>      master_password = ""
>      dm_password = ""
>      admin_password = ""
>  
> +    # check bind packages are installed
> +    bind = ipaserver.bindinstance.BindInstance()
> +    if options.setup_bind:
> +        if not bind.check_inst():
> +            print "--setup-bind was specified but bind is not installed on the system"
> +            print "Please install bind (you also need the package 'caching-nameserver') and restart the setup program"
> +            return "-Fatal Error-"
> +
>      # check the hostname is correctly configured, it must be as the kldap
>      # utilities just use the hostname as returned by gethostbyname to set
>      # up some of the standard entries
>  
> +    host_name = ""
>      if options.host_name:
>          host_name = options.host_name
>      else:
> -        host_name = socket.gethostname()
> -    if len(host_name.split(".")) < 2:
> -        print "Invalid hostname <"+host_name+">"
> -        print "Check the /etc/hosts file and make sure to have a valid FQDN"
> -        return "-Fatal Error-"
> -
> -    ip = socket.gethostbyname(host_name)
> -    if ip == "127.0.0.1":
> -        print "The hostname resolves to the localhost address (127.0.0.1)"
> -        print "Please change your /etc/hosts file or your DNS so that the"
> -        print "hostname resolves to the ip address of your network interface."
> -        print "The KDC service does not listen on 127.0.0.1"
> -        print ""
> -        print "Please fix your /etc/hosts file and restart the setup program"
> -        return "-Fatal Error-"
> -     
> -    print "The Final KDC Host Name will be: " + host_name + ". With IP address: " + ip
> +        try:
> +            host_name = socket.gethostname()
> +        except:
> +            pass
> +        if options.unattended:
> +           if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain":
> +               print "Invalid hostname: "+host_name
> +               print "This host name can't be used as a hostname for an IPA Server"
> +               return "-Fatal Error-"
> +        else:
> +            host_ok = False
> +            while not host_ok:
> +               if host_name == "":
> +                   print ""
> +                   host_name = raw_input("Please provide a Fully Qualified name to use for your system [master.example.com]: ")
> +                   if host_name != "":
> +                       host_name = "master.example.com"
> +    
> +               if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain":
> +                   print "Invalid hostname: "+host_name
> +                   print "This host name can't be used as a hostname for an IPA Server"
> +                   host_name = ""
> +                   continue
> +               else:
> +                   host_ok = True
> +    
> +               yesno = raw_input("Please confirm this ["+host_name+"] is the server hostname you want to use [Y/n]: ")
> +               if yesno != "" and yesno.lower() != 'y':
> +                   host_name = ""
> +                   host_ok = False
> +
> +    domain_name = host_name[host_name.find(".")+1:]
> +
> +    # Check we have a public IP that is associated with the hostname
> +    ip = ""
> +    askip = False
> +    try:
> +        ip = socket.gethostbyname(host_name)
> +
> +        if ip == "127.0.0.1" or ip == "::1":
> +            print "The hostname resolves to the localhost address (127.0.0.1/::1)"
> +            print "Please change your /etc/hosts file so that the hostname"
> +            print "resolves to the ip address of your network interface."
> +            print "The KDC service does not listen on localhost"
> +            print ""
> +            print "Please fix your /etc/hosts file and restart the setup program"
> +            return "-Fatal Error-"
> +
> +    except:
> +        print "The provided hostname can't actually be use to resolve the IP address"
> +        if options.ip_address:
> +            ip = options.ip_address
> +        else:
> +            askip = True
> +
> +    if ip != "":
> +        try:
> +            socket.inet_pton(socket.AF_INET, ip)
> +        except:
> +            try:
> +                socket.inet_pton(socket.AF_INET6, ip)
> +            except:
> +                print "Invalid IP format"
> +                if options.unattended:
> +                    return "-Fatal Error-"
> +                else:
> +                    ip = ""
> +                    askip = True
> +
> +        if options.ip_address and options.ip_address != ip:
> +            if options.setup_bind:
> +                ip = options.ip_address
> +            else:
> +                print "Error: the hostname resolves to an IP that is different from the one provided on the command line"
> +                print "Please fix your DNS or /etc/hosts file to provide consistent information and restart the setup program"
> +                return "-Fatal Error-"
> + 
> +    if options.unattended:
> +        if askip or ip == "":
> +            print "Unable to resolve IP address"
> +            return "-Fatal Error-"
> +
> +    while askip:
> +        ip = raw_input("Please provide the IP address to be used for this host name: ")
> +
> +        if ip == "":
> +            print "An empty IP is not acceptable"
> +            continue
> +        if ip == "127.0.0.1" or ip == "::1":
> +            print "The IPA Server can't use localhost as a valid IP"
> +            continue
> +
> +        try:
> +            socket.inet_pton(socket.AF_INET, ip)
> +        except:
> +            try:
> +                socket.inet_pton(socket.AF_INET6, ip)
> +            except:
> +                print "Invalid IP format"
> +                continue
> +
> +        print "Adding ["+ip+" "+host_name+"] to your /etc/hosts file"
> +        hosts_fd = open('/etc/hosts', 'r+')
> +        hosts_fd.seek(0, 2)
> +        hosts_fd.write(ip+'\t'+host_name+' '+host_name[:host_name.find('.')]+'\n')
> +        hosts_fd.close()
> +        askip = False
> +
> +    ip_address = ip
> +
> +    print "The IPA Master Server Name will be: " + host_name + ". With IP address: " + ip_address
> +    print "The IPA Domain Name will be: " + domain_name
>      print ""
>  
>      if not options.ds_user:
> @@ -152,7 +262,7 @@ def main():
>          print "The kerberos protocol requires a Realm name to be defined."
>          print "Usually the domain name all in uppercase is used as realm name."
>          print ""
> -        upper_dom = (host_name[host_name.find(".")+1:]).upper()
> +        upper_dom = domain_name.upper()
>          realm_name = raw_input("Please provide a realm name ["+upper_dom+"]: ")
>          print ""
>          if realm_name == "":
> @@ -227,6 +337,11 @@ def main():
>      else:
>          admin_password = options.admin_password
>  
> +    if not options.unattended:
> +        print ""
> +        print "The following operations may take some minutes to complete."
> +        print "Please wait until the prompt is returned."
> +
>      # Create a directory server instance
>      ds = ipaserver.dsinstance.DsInstance()
>      ds.create_instance(ds_user, realm_name, host_name, dm_password)
> @@ -235,8 +350,24 @@ def main():
>      krb = ipaserver.krbinstance.KrbInstance()
>      krb.create_instance(ds_user, realm_name, host_name, dm_password, master_password)
>  
> -    # Restart ds after the krb instance has changed ds configurations
> +    bind.setup(host_name, ip_address, realm_name)
> +    if options.setup_bind:
> +        skipbind = False
> +        if not options.unattended:
> +            print "This program is about to replace the DNS Server configuration,"
> +            print "with an automatically generated one, based on the data gathered so far."
> +            print "This will REPLACE any existing configuration."
> +            yesno = raw_input("Are you sure you want to configure the DNS Server ? [y/N]: ")
> +            if yesno.lower() != 'y':
> +                skipbind = True
> +        if not skipbind:
> +            bind.create_instance()
> +    else:
> +        bind.create_sample_bind_zone()
> +
> +    # Restart ds and krb after configurations have been changed
>      ds.restart()
> +    krb.restart()
>  
>      # Restart apache
>      run(["/sbin/service", "httpd", "restart"])
> diff -r 578d26927d91 -r 9353b33672ee ipa-server/ipa-install/share/bind.named.conf.template
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/ipa-server/ipa-install/share/bind.named.conf.template	Thu Sep 20 15:10:21 2007 -0400
> @@ -0,0 +1,41 @@
> +options {
> +	/* make named use port 53 for the source of all queries, to allow
> +	 * firewalls to block all ports except 53:
> +	 */
> +	query-source    port 53;
> +	query-source-v6 port 53;
> +
> +	// Put files that named is allowed to write in the data/ directory:
> +	directory "/var/named"; // the default
> +	dump-file               "data/cache_dump.db";
> +	statistics-file         "data/named_stats.txt";
> +	memstatistics-file      "data/named_mem_stats.txt";
> +
> +        /* Not used yet, support only on very recent bind versions */
> +#       tkey-gssapi-credential "DNS/$FQDN";
> +#       tkey-domain "$REALM";
> +};
> +
> +logging {
> +/*      If you want to enable debugging, eg. using the 'rndc trace' command,
> + *      By default, SELinux policy does not allow named to modify the /var/named directory,
> + *      so put the default debug log file in data/ :
> + */
> +        channel default_debug {
> +                file "data/named.run";
> +                severity dynamic;
> +        };
> +};
> +
> +zone "." IN {
> +	type hint;
> +	file "named.ca";
> +};
> +
> +include "/etc/named.rfc1912.zones";
> +
> +zone "$DOMAIN" {
> +	type master;
> +	file "$DOMAIN.zone.db";
> +};
> +
> diff -r 578d26927d91 -r 9353b33672ee ipa-server/ipaserver/bindinstance.py
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/ipa-server/ipaserver/bindinstance.py	Thu Sep 20 15:10:21 2007 -0400
> @@ -0,0 +1,113 @@
> +#! /usr/bin/python -E
> +# Authors: Simo Sorce <ssorce at redhat.com>
> +#
> +# Copyright (C) 2007  Red Hat
> +# see file 'COPYING' for use and warranty information
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation; version 2 or later
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +#
> +
> +import string
> +import tempfile
> +import shutil
> +import os
> +import socket
> +from ipa.ipautil import *
> +
> +class BindInstance:
> +    def __init__(self):
> +        self.fqdn = None
> +	self.domain = None
> +        self.host = None
> +        self.ip_address = None
> +        self.realm = None
> +        self.sub_dict = None
> +
> +    def setup(self, fqdn, ip_address, realm_name):
> +        self.fqdn = fqdn
> +        self.ip_address = ip_address
> +        self.realm = realm_name
> +        self.domain = fqdn[fqdn.find(".")+1:]
> +        self.host = fqdn[:fqdn.find(".")]
> +
> +        self.__setup_sub_dict()
> +
> +    def check_inst(self):
> +        # So far this file is always present in both RHEL5 and Fedora if all the necessary
> +        # bind packages are installed (RHEL5 requires also the pkg: caching-nameserver)
> +        if not os.path.exists('/etc/named.rfc1912.zones'):
> +             return False
> +
> +        return True
> +
> +    def create_sample_bind_zone(self):
> +        bind_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
> +        [bind_fd, bind_name] = tempfile.mkstemp(".db","sample.zone.")
> +        os.write(bind_fd, bind_txt)
> +        os.close(bind_fd)
> +        print "Sample zone file for bind has been created in "+bind_name
> +
> +    def create_instance(self):
> +
> +        try:
> +            self.stop()
> +        except:
> +            pass
> +
> +        self.__setup_zone()
> +        self.__setup_named_conf()
> +
> +        self.start()
> +
> +    def stop(self):
> +        run(["/sbin/service", "named", "stop"])
> +
> +    def start(self):
> +        run(["/sbin/service", "named", "start"])
> +
> +    def restart(self):
> +        run(["/sbin/service", "named", "restart"])
> +
> +    def __setup_sub_dict(self):
> +        self.sub_dict = dict(FQDN=self.fqdn,
> +                             IP=self.ip_address,
> +                             DOMAIN=self.domain,
> +                             HOST=self.host,
> +                             REALM=self.realm)
> +
> +    def __setup_zone(self):
> +        zone_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
> +        zone_fd = open('/var/named/'+self.domain+'.zone.db', 'w')
> +        zone_fd.write(zone_txt)
> +        zone_fd.close()
> +
> +    def __setup_named_conf(self):
> +        if os.path.exists('/etc/named.conf'):
> +            shutil.copy2('/etc/named.conf', '/etc/named.conf.ipabkp')
> +        named_txt = template_file(SHARE_DIR + "bind.named.conf.template", self.sub_dict)
> +        named_fd = open('/etc/named.conf', 'w')
> +        named_fd.seek(0)
> +        named_fd.truncate(0)
> +        named_fd.write(named_txt)
> +        named_fd.close()
> +
> +        if os.path.exists('/etc/resolve.conf'):
> +            shutil.copy2('/etc/resolve.conf', '/etc/resolv.conf.ipabkp')
> +        resolve_txt = "search "+self.domain+"\nnameserver "+self.ip_address+"\n"
> +        resolve_fd = open('/etc/resolve.conf', 'w')
> +        resolve_fd.seek(0)
> +        resolve_fd.truncate(0)
> +        resolve_fd.write(resolve_txt)
> +        resolve_fd.close()
> +
> diff -r 578d26927d91 -r 9353b33672ee ipa-server/ipaserver/krbinstance.py
> --- a/ipa-server/ipaserver/krbinstance.py	Thu Sep 13 12:10:55 2007 -0400
> +++ b/ipa-server/ipaserver/krbinstance.py	Thu Sep 20 15:10:21 2007 -0400
> @@ -73,6 +73,9 @@ class KrbInstance:
>          
>  	self.suffix = realm_to_suffix(self.realm)
>          self.kdc_password = generate_kdc_password()
> +
> +        self.stop()
> +
>  	self.__configure_kdc_account_password()
>  
>          self.__setup_sub_dict()
> @@ -88,8 +91,6 @@ class KrbInstance:
>          self.__create_http_keytab()
>  
>          self.__export_kadmin_changepw_keytab()
> -
> -        self.__create_sample_bind_zone()
>  
>          self.__add_pwd_extop_module()
>  
> @@ -161,13 +162,6 @@ class KrbInstance:
>          args = ["/usr/bin/setfacl", "-m", "u:"+self.ds_user+":r", "/var/kerberos/krb5kdc/.k5."+self.realm]
>          run(args)
>  
> -    def __create_sample_bind_zone(self):
> -        bind_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
> -        [bind_fd, bind_name] = tempfile.mkstemp(".db","sample.zone.")
> -        os.write(bind_fd, bind_txt)
> -        os.close(bind_fd)
> -        print "Sample zone file for bind has been created in "+bind_name
> -
>      def __create_ds_keytab(self):
>          (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local")
>          kwrite.write("addprinc -randkey ldap/"+self.fqdn+"@"+self.realm+"\n")
>   
> ------------------------------------------------------------------------
>
> _______________________________________________
> Freeipa-devel mailing list
> Freeipa-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/freeipa-devel


-- 
Pete

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 3241 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20070920/5e82d13f/attachment.bin>


More information about the Freeipa-devel mailing list