summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ACI.txt4
-rw-r--r--API.txt65
-rw-r--r--VERSION4
-rw-r--r--install/share/dns.ldif6
-rw-r--r--install/updates/40-dns.update6
-rw-r--r--ipalib/constants.py1
-rw-r--r--ipalib/util.py53
-rw-r--r--ipaserver/plugins/dns.py41
-rw-r--r--ipaserver/plugins/dnsserver.py183
-rw-r--r--ipaserver/plugins/host.py30
-rw-r--r--ipaserver/plugins/server.py1
11 files changed, 336 insertions, 58 deletions
diff --git a/ACI.txt b/ACI.txt
index d8d2b3955..717fa7a1d 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -63,6 +63,10 @@ aci: (targetattr = "createtimestamp || entryusn || idnsallowsyncptr || idnsforwa
dn: dc=ipa,dc=example
aci: (targetattr = "idnsallowsyncptr || idnsforwarders || idnsforwardpolicy || idnspersistentsearch || idnszonerefresh")(target = "ldap:///cn=dns,dc=ipa,dc=example")(targetfilter = "(objectclass=idnsConfigObject)")(version 3.0;acl "permission:System: Write DNS Configuration";allow (write) groupdn = "ldap:///cn=System: Write DNS Configuration,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: dc=ipa,dc=example
+aci: (targetattr = "idnsforwarders || idnsforwardpolicy || idnssoamname || idnssubstitutionvariable")(targetfilter = "(objectclass=idnsServerConfigObject)")(version 3.0;acl "permission:System: Modify DNS Servers Configuration";allow (write) groupdn = "ldap:///cn=System: Modify DNS Servers Configuration,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: dc=ipa,dc=example
+aci: (targetattr = "createtimestamp || entryusn || idnsforwarders || idnsforwardpolicy || idnsserverid || idnssoamname || idnssubstitutionvariable || modifytimestamp || objectclass")(targetfilter = "(objectclass=idnsServerConfigObject)")(version 3.0;acl "permission:System: Read DNS Servers Configuration";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNS Servers Configuration,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: dc=ipa,dc=example
aci: (target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Add DNS Entries";allow (add) groupdn = "ldap:///cn=System: Add DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: dc=ipa,dc=example
aci: (targetattr = "ipaprivatekey || ipapublickey || ipasecretkey || ipasecretkeyref || ipawrappingkey || ipawrappingmech || ipk11allowedmechanisms || ipk11alwaysauthenticate || ipk11alwayssensitive || ipk11checkvalue || ipk11copyable || ipk11decrypt || ipk11derive || ipk11destroyable || ipk11distrusted || ipk11encrypt || ipk11enddate || ipk11extractable || ipk11id || ipk11keygenmechanism || ipk11keytype || ipk11label || ipk11local || ipk11modifiable || ipk11neverextractable || ipk11private || ipk11publickeyinfo || ipk11sensitive || ipk11sign || ipk11signrecover || ipk11startdate || ipk11subject || ipk11trusted || ipk11uniqueid || ipk11unwrap || ipk11unwraptemplate || ipk11verify || ipk11verifyrecover || ipk11wrap || ipk11wraptemplate || ipk11wrapwithtrusted || objectclass")(target = "ldap:///cn=keys,cn=sec,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Manage DNSSEC keys";allow (all) groupdn = "ldap:///cn=System: Manage DNSSEC keys,cn=permissions,cn=pbac,dc=ipa,dc=example";)
diff --git a/API.txt b/API.txt
index 5d63ba84a..8dde37142 100644
--- a/API.txt
+++ b/API.txt
@@ -1499,6 +1499,71 @@ arg: Str('name')
arg: Str('value')
option: Str('version?')
output: Output('result')
+command: dnsserver_add
+args: 1,8,3
+arg: Str('idnsserverid', cli_name='hostname')
+option: Str('addattr*', cli_name='addattr')
+option: Flag('all', autofill=True, cli_name='all', default=False)
+option: Str('idnsforwarders*', cli_name='forwarder')
+option: StrEnum('idnsforwardpolicy?', cli_name='forward_policy', values=[u'only', u'first', u'none'])
+option: DNSNameParam('idnssoamname?', cli_name='soa_mname_override')
+option: Flag('raw', autofill=True, cli_name='raw', default=False)
+option: Str('setattr*', cli_name='setattr')
+option: Str('version?')
+output: Entry('result')
+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
+output: PrimaryKey('value')
+command: dnsserver_del
+args: 1,2,3
+arg: Str('idnsserverid+', cli_name='hostname')
+option: Flag('continue', autofill=True, cli_name='continue', default=False)
+option: Str('version?')
+output: Output('result', type=[<type 'dict'>])
+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
+output: ListOfPrimaryKeys('value')
+command: dnsserver_find
+args: 1,10,4
+arg: Str('criteria?')
+option: Flag('all', autofill=True, cli_name='all', default=False)
+option: Str('idnsforwarders*', autofill=False, cli_name='forwarder')
+option: StrEnum('idnsforwardpolicy?', autofill=False, cli_name='forward_policy', values=[u'only', u'first', u'none'])
+option: Str('idnsserverid?', autofill=False, cli_name='hostname')
+option: DNSNameParam('idnssoamname?', autofill=False, cli_name='soa_mname_override')
+option: Flag('pkey_only?', autofill=True, default=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False)
+option: Int('sizelimit?', autofill=False)
+option: Int('timelimit?', autofill=False)
+option: Str('version?')
+output: Output('count', type=[<type 'int'>])
+output: ListOfEntries('result')
+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
+output: Output('truncated', type=[<type 'bool'>])
+command: dnsserver_mod
+args: 1,10,3
+arg: Str('idnsserverid', cli_name='hostname')
+option: Str('addattr*', cli_name='addattr')
+option: Flag('all', autofill=True, cli_name='all', default=False)
+option: Str('delattr*', cli_name='delattr')
+option: Str('idnsforwarders*', autofill=False, cli_name='forwarder')
+option: StrEnum('idnsforwardpolicy?', autofill=False, cli_name='forward_policy', values=[u'only', u'first', u'none'])
+option: DNSNameParam('idnssoamname?', autofill=False, cli_name='soa_mname_override')
+option: Flag('raw', autofill=True, cli_name='raw', default=False)
+option: Flag('rights', autofill=True, default=False)
+option: Str('setattr*', cli_name='setattr')
+option: Str('version?')
+output: Entry('result')
+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
+output: PrimaryKey('value')
+command: dnsserver_show
+args: 1,4,3
+arg: Str('idnsserverid', cli_name='hostname')
+option: Flag('all', autofill=True, cli_name='all', default=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False)
+option: Flag('rights', autofill=True, default=False)
+option: Str('version?')
+output: Entry('result')
+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
+output: PrimaryKey('value')
command: dnszone_add
args: 1,28,3
arg: DNSNameParam('idnsname', cli_name='name')
diff --git a/VERSION b/VERSION
index 3341cf5fb..8ea9602f0 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=185
-# Last change: mbasti - added command dns-update-system-records
+IPA_API_VERSION_MINOR=186
+# Last change: mbasti - added dnsserver-* commands
diff --git a/install/share/dns.ldif b/install/share/dns.ldif
index 6cee47867..6a8524b51 100644
--- a/install/share/dns.ldif
+++ b/install/share/dns.ldif
@@ -12,3 +12,9 @@ aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)
aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)
aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
+
+dn: cn=servers,cn=dns,$SUFFIX
+changetype: add
+objectClass: nsContainer
+objectClass: top
+cn: servers
diff --git a/install/updates/40-dns.update b/install/updates/40-dns.update
index 4c0824b83..50f8b79ec 100644
--- a/install/updates/40-dns.update
+++ b/install/updates/40-dns.update
@@ -33,3 +33,9 @@ default: nsslapd-plugintype: preoperation
default: nsslapd-pluginvendor: Red Hat, Inc.
default: nsslapd-pluginversion: 1.0
default: nsslapd-plugin-depends-on-type: database
+
+# add dns servers container
+dn: cn=servers,cn=dns,$SUFFIX
+default: objectClass: nsContainer
+default: objectClass: top
+default: cn: servers
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 05ba1adbb..bcddb5b97 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -123,6 +123,7 @@ DEFAULT_CONFIG = (
('container_caacl', DN(('cn', 'caacls'), ('cn', 'ca'))),
('container_locations', DN(('cn', 'locations'), ('cn', 'etc'))),
('container_ca', DN(('cn', 'cas'), ('cn', 'ca'))),
+ ('container_dnsservers', DN(('cn', 'servers'), ('cn', 'dns'))),
# Ports, hosts, and URIs:
('xmlrpc_uri', 'http://localhost:8888/ipa/xml'),
diff --git a/ipalib/util.py b/ipalib/util.py
index 4b5f11509..68d11fc6c 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -898,3 +898,56 @@ class classproperty(object):
def getter(self, fget):
self.fget = fget
return self
+
+
+def normalize_hostname(hostname):
+ """Use common fqdn form without the trailing dot"""
+ if hostname.endswith(u'.'):
+ hostname = hostname[:-1]
+ hostname = hostname.lower()
+ return hostname
+
+
+def hostname_validator(ugettext, value):
+ try:
+ validate_hostname(value)
+ except ValueError as e:
+ return _('invalid domain-name: %s') % unicode(e)
+
+ return None
+
+
+def ipaddr_validator(ugettext, ipaddr, ip_version=None):
+ try:
+ ip = netaddr.IPAddress(str(ipaddr), flags=netaddr.INET_PTON)
+
+ if ip_version is not None:
+ if ip.version != ip_version:
+ return _(
+ 'invalid IP address version (is %(value)d, must be '
+ '%(required_value)d)!') % dict(
+ value=ip.version,
+ required_value=ip_version
+ )
+ except (netaddr.AddrFormatError, ValueError):
+ return _('invalid IP address format')
+ return None
+
+
+def validate_bind_forwarder(ugettext, forwarder):
+ ip_address, sep, port = forwarder.partition(u' port ')
+
+ ip_address_validation = ipaddr_validator(ugettext, ip_address)
+
+ if ip_address_validation is not None:
+ return ip_address_validation
+
+ if sep:
+ try:
+ port = int(port)
+ if port < 0 or port > 65535:
+ raise ValueError()
+ except ValueError:
+ return _('%(port)s is not a valid port' % dict(port=port))
+
+ return None
diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index e9eb1f98f..094f8eb57 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -66,7 +66,9 @@ from ipalib.util import (normalize_zonemgr,
EDNS0UnsupportedError, DNSSECValidationError,
validate_dnssec_zone_forwarder_step1,
validate_dnssec_zone_forwarder_step2,
- verify_host_resolvable)
+ verify_host_resolvable,
+ validate_bind_forwarder,
+ ipaddr_validator)
from ipapython.dn import DN
from ipapython.ipautil import CheckedIPAddress
from ipapython.dnsutil import check_zone_overlap
@@ -373,23 +375,12 @@ def _reverse_zone_name(netstr):
else:
return None
-def _validate_ipaddr(ugettext, ipaddr, ip_version=None):
- try:
- ip = netaddr.IPAddress(str(ipaddr), flags=netaddr.INET_PTON)
-
- if ip_version is not None:
- if ip.version != ip_version:
- return _('invalid IP address version (is %(value)d, must be %(required_value)d)!') \
- % dict(value=ip.version, required_value=ip_version)
- except (netaddr.AddrFormatError, ValueError):
- return _('invalid IP address format')
- return None
def _validate_ip4addr(ugettext, ipaddr):
- return _validate_ipaddr(ugettext, ipaddr, 4)
+ return ipaddr_validator(ugettext, ipaddr, 4)
def _validate_ip6addr(ugettext, ipaddr):
- return _validate_ipaddr(ugettext, ipaddr, 6)
+ return ipaddr_validator(ugettext, ipaddr, 6)
def _validate_ipnet(ugettext, ipnet):
try:
@@ -457,24 +448,6 @@ def _normalize_bind_aci(bind_acis):
acis += u';'
return acis
-def _validate_bind_forwarder(ugettext, forwarder):
- ip_address, sep, port = forwarder.partition(u' port ')
-
- ip_address_validation = _validate_ipaddr(ugettext, ip_address)
-
- if ip_address_validation is not None:
- return ip_address_validation
-
- if sep:
- try:
- port = int(port)
- if port < 0 or port > 65535:
- raise ValueError()
- except ValueError:
- return _('%(port)s is not a valid port' % dict(port=port))
-
- return None
-
def _validate_nsec3param_record(ugettext, value):
_nsec3param_pattern = (r'^(?P<alg>\d+) (?P<flags>\d+) (?P<iter>\d+) '
r'(?P<salt>([0-9a-fA-F]{2})+|-)$')
@@ -2001,7 +1974,7 @@ class DNSZoneBase(LDAPObject):
attribute=True,
),
Str('idnsforwarders*',
- _validate_bind_forwarder,
+ validate_bind_forwarder,
cli_name='forwarder',
label=_('Zone forwarders'),
doc=_('Per-zone forwarders. A custom port can be specified '
@@ -4043,7 +4016,7 @@ class dnsconfig(LDAPObject):
takes_params = (
Str('idnsforwarders*',
- _validate_bind_forwarder,
+ validate_bind_forwarder,
cli_name='forwarder',
label=_('Global forwarders'),
doc=_('Global forwarders. A custom port can be specified for each '
diff --git a/ipaserver/plugins/dnsserver.py b/ipaserver/plugins/dnsserver.py
new file mode 100644
index 000000000..f22d6943e
--- /dev/null
+++ b/ipaserver/plugins/dnsserver.py
@@ -0,0 +1,183 @@
+#
+# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
+#
+
+from __future__ import absolute_import
+
+from ipalib import (
+ _,
+ ngettext,
+ api,
+ DNSNameParam,
+ Str,
+ StrEnum,
+)
+from ipalib.frontend import Local
+from ipalib.plugable import Registry
+from ipalib.util import (
+ normalize_hostname,
+ hostname_validator,
+ validate_bind_forwarder,
+)
+from ipaserver.plugins.baseldap import (
+ LDAPObject,
+ LDAPRetrieve,
+ LDAPUpdate,
+ LDAPSearch,
+ LDAPCreate,
+ LDAPDelete,
+)
+
+
+__doc__ = _("""
+DNS server configuration
+""") + _("""
+Manipulate DNS server configuration
+""") + _("""
+EXAMPLES:
+""") + _("""
+ Show configuration of a specific DNS server:
+ ipa dnsserver-show
+""") + _("""
+ Update configuration of a specific DNS server:
+ ipa dnsserver-mod
+""")
+
+
+register = Registry()
+
+dnsserver_object_class = ['top', 'idnsServerConfigObject']
+
+@register()
+class dnsserver(LDAPObject):
+ """
+ DNS Servers
+ """
+ container_dn = api.env.container_dnsservers
+ object_name = _('DNS server')
+ object_name_plural = _('DNS servers')
+ object_class = dnsserver_object_class
+ default_attributes = [
+ 'idnsServerId',
+ 'idnsSOAmName',
+ 'idnsForwarders',
+ 'idnsForwardPolicy',
+ ]
+ label = _('DNS Servers')
+ label_singular = _('DNS Server')
+
+ permission_filter_objectclasses = ['idnsServerConfigObject']
+
+ managed_permissions = {
+ 'System: Read DNS Servers Configuration': {
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'objectclass',
+ 'idnsServerId',
+ 'idnsSOAmName',
+ 'idnsForwarders',
+ 'idnsForwardPolicy',
+ 'idnsSubstitutionVariable',
+ },
+ 'ipapermlocation': api.env.basedn,
+ 'default_privileges': {
+ 'DNS Servers',
+ 'DNS Administrators'
+ },
+ },
+ 'System: Modify DNS Servers Configuration': {
+ 'ipapermright': {'write'},
+ 'ipapermdefaultattr': {
+ 'idnsSOAmName',
+ 'idnsForwarders',
+ 'idnsForwardPolicy',
+ 'idnsSubstitutionVariable',
+ },
+ 'ipapermlocation': api.env.basedn,
+ 'default_privileges': {'DNS Administrators'},
+ },
+ }
+
+ takes_params = (
+ Str(
+ 'idnsserverid',
+ hostname_validator,
+ cli_name='hostname',
+ primary_key=True,
+ label=_('Server name'),
+ doc=_('DNS Server name'),
+ normalizer=normalize_hostname,
+ ),
+ DNSNameParam(
+ 'idnssoamname?',
+ cli_name='soa_mname_override',
+ label=_('SOA mname override'),
+ doc=_('SOA mname (authoritative server) override'),
+ ),
+ Str(
+ 'idnsforwarders*',
+ validate_bind_forwarder,
+ cli_name='forwarder',
+ label=_('Forwarders'),
+ doc=_(
+ 'Per-server forwarders. A custom port can be specified '
+ 'for each forwarder using a standard format '
+ '"IP_ADDRESS port PORT"'
+ ),
+ ),
+ StrEnum(
+ 'idnsforwardpolicy?',
+ cli_name='forward_policy',
+ label=_('Forward policy'),
+ doc=_(
+ 'Per-server conditional forwarding policy. Set to "none" to '
+ 'disable forwarding to global forwarder for this zone. In '
+ 'that case, conditional zone forwarders are disregarded.'
+ ),
+ values=(u'only', u'first', u'none'),
+ ),
+ )
+
+
+@register()
+class dnsserver_mod(LDAPUpdate):
+ __doc__ = _('Modify DNS server configuration')
+
+ msg_summary = _('Modified DNS server "%(value)s"')
+
+
+@register()
+class dnsserver_find(LDAPSearch):
+ __doc__ = _('Search for DNS servers.')
+
+ msg_summary = ngettext(
+ '%(count)d DNS server matched',
+ '%(count)d DNS servers matched', 0
+ )
+
+
+@register()
+class dnsserver_show(LDAPRetrieve):
+ __doc__=_('Display configuration of a DNS server.')
+
+
+@register()
+class dnsserver_add(LDAPCreate, Local):
+ """
+ Only for internal use, this is not part of public API on purpose.
+ Be careful in future this will be transformed to public API call
+ """
+ __doc__ = _('Add a new DNS server.')
+
+ msg_summary = _('Added new DNS server "%(value)s"')
+
+
+@register()
+class dnsserver_del(LDAPDelete, Local):
+ """
+ Only for internal use, this is not part of public API on purpose.
+ Be careful in future this will be transformed to public API call
+ """
+ __doc__ = _('Delete a DNS server')
+
+ msg_summary = _('Deleted DNS server "%(value)s"')
diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py
index e59e0fa93..15805a3d2 100644
--- a/ipaserver/plugins/host.py
+++ b/ipaserver/plugins/host.py
@@ -44,10 +44,13 @@ from ipalib import x509
from ipalib import output
from ipalib.request import context
from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options,
- convert_sshpubkey_post, validate_hostname,
+ convert_sshpubkey_post,
add_sshpubkey_to_attrs_pre,
remove_sshpubkey_from_output_post,
- remove_sshpubkey_from_output_list_post)
+ remove_sshpubkey_from_output_list_post,
+ normalize_hostname,
+ hostname_validator,
+)
from ipapython.ipautil import ipa_generate_password, CheckedIPAddress
from ipapython.dnsutil import DNSName
from ipapython.ssh import SSHPublicKey
@@ -271,23 +274,6 @@ def validate_ipaddr(ugettext, ipaddr):
return None
-def normalize_hostname(hostname):
- """Use common fqdn form without the trailing dot"""
- if hostname.endswith(u'.'):
- hostname = hostname[:-1]
- hostname = hostname.lower()
- return hostname
-
-
-def _hostname_validator(ugettext, value):
- try:
- validate_hostname(value)
- except ValueError as e:
- return _('invalid domain-name: %s') % unicode(e)
-
- return None
-
-
@register()
class host(LDAPObject):
"""
@@ -465,7 +451,7 @@ class host(LDAPObject):
label_singular = _('Host')
takes_params = (
- Str('fqdn', _hostname_validator,
+ Str('fqdn', hostname_validator,
cli_name='hostname',
label=_('Host name'),
primary_key=True,
@@ -734,7 +720,7 @@ class host_del(LDAPDelete):
def pre_callback(self, ldap, dn, *keys, **options):
assert isinstance(dn, DN)
# If we aren't given a fqdn, find it
- if _hostname_validator(None, keys[-1]) is not None:
+ if hostname_validator(None, keys[-1]) is not None:
hostentry = api.Command['host_show'](keys[-1])['result']
fqdn = hostentry['fqdn'][0]
else:
@@ -1093,7 +1079,7 @@ class host_disable(LDAPQuery):
ldap = self.obj.backend
# If we aren't given a fqdn, find it
- if _hostname_validator(None, keys[-1]) is not None:
+ if hostname_validator(None, keys[-1]) is not None:
hostentry = api.Command['host_show'](keys[-1])['result']
fqdn = hostentry['fqdn'][0]
else:
diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py
index 3b58c6b2f..344756f00 100644
--- a/ipaserver/plugins/server.py
+++ b/ipaserver/plugins/server.py
@@ -237,6 +237,7 @@ class server_mod(LDAPUpdate):
if not result.get('value'):
self.add_message(messages.AutomaticDNSRecordsUpdateFailed())
self.obj.convert_location(entry_attrs, **options)
+
return dn