summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kosek <mkosek@redhat.com>2012-05-31 17:02:44 +0200
committerRob Crittenden <rcritten@redhat.com>2012-06-10 21:23:19 -0400
commit1d44aba89b225aa9e131ac8ca596df7b0faaa964 (patch)
treedd85c4dd1361e2e4fd6895f256de0dbb9286f703
parentce97d6f8e7cb47927fccc27c258d32caf895a88c (diff)
downloadfreeipa-1d44aba89b225aa9e131ac8ca596df7b0faaa964.zip
freeipa-1d44aba89b225aa9e131ac8ca596df7b0faaa964.tar.gz
freeipa-1d44aba89b225aa9e131ac8ca596df7b0faaa964.tar.xz
Enable psearch on upgrades
From IPA 3.0, persistent search is a preferred mechanism for new DNS zone detection and is also needed for other features (DNSSEC, SOA serial updates). Enable psearch and make sure connections attribute is right. This step is done just once for a case when user switched the persistent search back to disabled on purpose. ipa-upgradeconfig was updated to accept --debug option in case somebody would want to see debug messages.
-rw-r--r--install/tools/ipa-upgradeconfig88
-rw-r--r--ipaserver/install/bindinstance.py94
2 files changed, 174 insertions, 8 deletions
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index 0cf59f2..07c8466 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -25,14 +25,18 @@ Upgrade configuration files to a newer template.
import sys
try:
- from ipapython import ipautil, sysrestore
+ from ipapython import ipautil, sysrestore, version
+ from ipapython.config import IPAOptionParser
+ from ipapython.ipa_log_manager import *
from ipaserver.install import installutils
from ipaserver.install import dsinstance
from ipaserver.install import httpinstance
from ipaserver.install import memcacheinstance
+ from ipaserver.install import bindinstance
from ipaserver.install import service
from ipaserver.install import cainstance
from ipaserver.install import certs
+ from ipaserver.install import sysupgrade
import ldap
import krbV
import re
@@ -49,6 +53,16 @@ error was:
""" % sys.exc_value
sys.exit(1)
+def parse_options():
+ parser = IPAOptionParser(version=version.VERSION)
+ parser.add_option("-d", "--debug", dest="debug", action="store_true",
+ default=False, help="print debugging information")
+
+ options, args = parser.parse_args()
+ safe_options = parser.get_safe_opts(options)
+
+ return safe_options, options
+
class KpasswdInstance(service.SimpleServiceInstance):
def __init__(self):
service.SimpleServiceInstance.__init__(self, "ipa_kpasswd")
@@ -249,6 +263,70 @@ def upgrade_httpd_selinux(fstore):
http = httpinstance.HTTPInstance(fstore)
http.configure_selinux_for_httpd()
+def enable_psearch_for_named():
+ """
+ From IPA 3.0, persistent search is a preferred mechanism for new DNS zone
+ detection and is also needed for other features (DNSSEC, SOA serial
+ updates). Enable psearch and make sure connections attribute is right.
+ This step is done just once for a case when user switched the persistent
+ search back to disabled.
+
+ When some change in named.conf is done, this functions returns True
+ """
+ changed = False
+
+ if not bindinstance.named_conf_exists():
+ # DNS service may not be configured
+ return
+
+ try:
+ psearch = bindinstance.named_conf_get_directive('psearch').lower()
+ except IOError, e:
+ root_logger.debug('Cannot retrieve psearch option from %s: %s',
+ bindinstance.NAMED_CONF, e)
+ return
+ if not sysupgrade.get_upgrade_state('named.conf', 'psearch_enabled'):
+ if psearch != "yes":
+ try:
+ bindinstance.named_conf_set_directive('zone_refresh', 0)
+ bindinstance.named_conf_set_directive('psearch', 'yes')
+ except IOError, e:
+ root_logger.error('Cannot enable psearch in %s: %s',
+ bindinstance.NAMED_CONF, e)
+ else:
+ changed = True
+ sysupgrade.set_upgrade_state('named.conf', 'psearch_enabled', True)
+
+ # make sure number of connections is right
+ minimum_connections = 2
+ if psearch == 'yes':
+ minimum_connections = 3
+ try:
+ connections = bindinstance.named_conf_get_directive('connections')
+ except IOError, e:
+ root_logger.debug('Cannot retrieve connections option from %s: %s',
+ bindinstance.NAMED_CONF, e)
+ return
+ if connections is not None:
+ try:
+ connections = int(connections)
+ except ValueError:
+ # this should not happend, but there is some bad value in
+ # "connections" option, bail out
+ pass
+ else:
+ if connections < minimum_connections:
+ try:
+ bindinstance.named_conf_set_directive('connections',
+ minimum_connections)
+ except IOError, e:
+ root_logger.error('Cannot update connections in %s: %s',
+ bindinstance.NAMED_CONF, e)
+ else:
+ changed = True
+
+ return changed
+
def main():
"""
Get some basics about the system. If getting those basics fail then
@@ -259,6 +337,10 @@ def main():
if not os.geteuid()==0:
sys.exit("\nYou must be root to run this script.\n")
+ safe_options, options = parse_options()
+
+ standard_logging_setup(None, debug=options.debug)
+
fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
try:
@@ -304,6 +386,10 @@ def main():
cleanup_kdc(fstore)
upgrade_ipa_profile(krbctx.default_realm)
+ changed = enable_psearch_for_named()
+ if changed:
+ # configuration has changed, restart the name server
+ bindinstance.BindInstance(fstore).restart()
if __name__ == '__main__':
installutils.run_script(main, operation_name='ipa-upgradeconfig')
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 623e397..3ff5932 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -21,6 +21,7 @@ import tempfile
import os
import pwd
import netaddr
+import re
import installutils
import ldap
@@ -38,6 +39,12 @@ from ipapython.ipa_log_manager import *
import ipalib
from ipalib import api, util, errors
+NAMED_CONF = '/etc/named.conf'
+RESOLV_CONF = '/etc/resolv.conf'
+
+named_conf_ipa_re = re.compile(r'(?P<indent>\s*)arg\s+"(?P<name>\S+)\s(?P<value>[^"]+)";')
+named_conf_ipa_template = "%(indent)sarg \"%(name)s %(value)s\";\n"
+
def check_inst(unattended):
has_bind = True
# So far this file is always present in both RHEL5 and Fedora if all the necessary
@@ -57,7 +64,7 @@ def check_inst(unattended):
if not has_bind:
return False
- if not unattended and os.path.exists('/etc/named.conf'):
+ if not unattended and os.path.exists(NAMED_CONF):
msg = "Existing BIND configuration detected, overwrite?"
return ipautil.user_input(msg, False)
@@ -73,7 +80,10 @@ def create_reverse():
return ipautil.user_input("Do you want to configure the reverse zone?", True)
def named_conf_exists():
- named_fd = open('/etc/named.conf', 'r')
+ try:
+ named_fd = open(NAMED_CONF, 'r')
+ except IOError:
+ return False
lines = named_fd.readlines()
named_fd.close()
for line in lines:
@@ -81,6 +91,76 @@ def named_conf_exists():
return True
return False
+def named_conf_get_directive(name):
+ """Get a configuration option in bind-dyndb-ldap section of named.conf"""
+
+ with open(NAMED_CONF, 'r') as f:
+ ipa_section = False
+ for line in f:
+ if line.startswith('dynamic-db "ipa"'):
+ ipa_section = True
+ continue
+ if line.startswith('};'):
+ if ipa_section:
+ break
+
+ if ipa_section:
+ match = named_conf_ipa_re.match(line)
+
+ if match and name == match.group('name'):
+ return match.group('value')
+
+def named_conf_set_directive(name, value):
+ """
+ Set configuration option in bind-dyndb-ldap section of named.conf.
+
+ When the configuration option with given name does not exist, it
+ is added at the end of ipa section in named.conf.
+
+ If the value is set to None, the configuration option is removed
+ from named.conf.
+ """
+ new_lines = []
+
+ with open(NAMED_CONF, 'r') as f:
+ ipa_section = False
+ matched = False
+ last_indent = "\t"
+ for line in f:
+ if line.startswith('dynamic-db "ipa"'):
+ ipa_section = True
+ if line.startswith('};'):
+ if ipa_section and not matched:
+ # create a new conf
+ new_conf = named_conf_ipa_template \
+ % dict(indent=last_indent,
+ name=name,
+ value=value)
+ new_lines.append(new_conf)
+ ipa_section = False
+
+ if ipa_section and not matched:
+ match = named_conf_ipa_re.match(line)
+
+ if match:
+ last_indent = match.group('indent')
+ if name == match.group('name'):
+ matched = True
+ if value is not None:
+ if not isinstance(value, basestring):
+ value = str(value)
+ new_conf = named_conf_ipa_template \
+ % dict(indent=last_indent,
+ name=name,
+ value=value)
+ new_lines.append(new_conf)
+ continue
+ new_lines.append(line)
+
+ # write new configuration
+ with open(NAMED_CONF, 'w') as f:
+ f.write("".join(new_lines))
+
def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None):
"""
Test whether the dns container exists.
@@ -610,18 +690,18 @@ class BindInstance(service.Service):
raise
def __setup_named_conf(self):
- self.fstore.backup_file('/etc/named.conf')
+ self.fstore.backup_file(NAMED_CONF)
named_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.named.conf.template", self.sub_dict)
- named_fd = open('/etc/named.conf', 'w')
+ named_fd = open(NAMED_CONF, 'w')
named_fd.seek(0)
named_fd.truncate(0)
named_fd.write(named_txt)
named_fd.close()
def __setup_resolv_conf(self):
- self.fstore.backup_file('/etc/resolv.conf')
+ self.fstore.backup_file(RESOLV_CONF)
resolv_txt = "search "+self.domain+"\nnameserver "+self.ip_address+"\n"
- resolv_fd = open('/etc/resolv.conf', 'w')
+ resolv_fd = open(RESOLV_CONF, 'w')
resolv_fd.seek(0)
resolv_fd.truncate(0)
resolv_fd.write(resolv_txt)
@@ -704,7 +784,7 @@ class BindInstance(service.Service):
if not running is None:
self.stop()
- for f in ["/etc/named.conf", "/etc/resolv.conf"]:
+ for f in [NAMED_CONF, RESOLV_CONF]:
try:
self.fstore.restore_file(f)
except ValueError, error: