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.
This commit is contained in:
Martin Kosek 2012-05-31 17:02:44 +02:00 committed by Rob Crittenden
parent ce97d6f8e7
commit 1d44aba89b
2 changed files with 174 additions and 8 deletions

View File

@ -25,14 +25,18 @@ Upgrade configuration files to a newer template.
import sys import sys
try: 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 installutils
from ipaserver.install import dsinstance from ipaserver.install import dsinstance
from ipaserver.install import httpinstance from ipaserver.install import httpinstance
from ipaserver.install import memcacheinstance from ipaserver.install import memcacheinstance
from ipaserver.install import bindinstance
from ipaserver.install import service from ipaserver.install import service
from ipaserver.install import cainstance from ipaserver.install import cainstance
from ipaserver.install import certs from ipaserver.install import certs
from ipaserver.install import sysupgrade
import ldap import ldap
import krbV import krbV
import re import re
@ -49,6 +53,16 @@ error was:
""" % sys.exc_value """ % sys.exc_value
sys.exit(1) 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): class KpasswdInstance(service.SimpleServiceInstance):
def __init__(self): def __init__(self):
service.SimpleServiceInstance.__init__(self, "ipa_kpasswd") service.SimpleServiceInstance.__init__(self, "ipa_kpasswd")
@ -249,6 +263,70 @@ def upgrade_httpd_selinux(fstore):
http = httpinstance.HTTPInstance(fstore) http = httpinstance.HTTPInstance(fstore)
http.configure_selinux_for_httpd() 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(): def main():
""" """
Get some basics about the system. If getting those basics fail then Get some basics about the system. If getting those basics fail then
@ -259,6 +337,10 @@ def main():
if not os.geteuid()==0: if not os.geteuid()==0:
sys.exit("\nYou must be root to run this script.\n") 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') fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
try: try:
@ -304,6 +386,10 @@ def main():
cleanup_kdc(fstore) cleanup_kdc(fstore)
upgrade_ipa_profile(krbctx.default_realm) 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__': if __name__ == '__main__':
installutils.run_script(main, operation_name='ipa-upgradeconfig') installutils.run_script(main, operation_name='ipa-upgradeconfig')

View File

@ -21,6 +21,7 @@ import tempfile
import os import os
import pwd import pwd
import netaddr import netaddr
import re
import installutils import installutils
import ldap import ldap
@ -38,6 +39,12 @@ from ipapython.ipa_log_manager import *
import ipalib import ipalib
from ipalib import api, util, errors 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): def check_inst(unattended):
has_bind = True has_bind = True
# So far this file is always present in both RHEL5 and Fedora if all the necessary # 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: if not has_bind:
return False 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?" msg = "Existing BIND configuration detected, overwrite?"
return ipautil.user_input(msg, False) 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) return ipautil.user_input("Do you want to configure the reverse zone?", True)
def named_conf_exists(): 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() lines = named_fd.readlines()
named_fd.close() named_fd.close()
for line in lines: for line in lines:
@ -81,6 +91,76 @@ def named_conf_exists():
return True return True
return False 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): def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None):
""" """
Test whether the dns container exists. Test whether the dns container exists.
@ -610,18 +690,18 @@ class BindInstance(service.Service):
raise raise
def __setup_named_conf(self): 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_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.seek(0)
named_fd.truncate(0) named_fd.truncate(0)
named_fd.write(named_txt) named_fd.write(named_txt)
named_fd.close() named_fd.close()
def __setup_resolv_conf(self): 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_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.seek(0)
resolv_fd.truncate(0) resolv_fd.truncate(0)
resolv_fd.write(resolv_txt) resolv_fd.write(resolv_txt)
@ -704,7 +784,7 @@ class BindInstance(service.Service):
if not running is None: if not running is None:
self.stop() self.stop()
for f in ["/etc/named.conf", "/etc/resolv.conf"]: for f in [NAMED_CONF, RESOLV_CONF]:
try: try:
self.fstore.restore_file(f) self.fstore.restore_file(f)
except ValueError, error: except ValueError, error: