summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--API.txt6
-rw-r--r--VERSION4
-rw-r--r--ipalib/plugins/dns.py126
3 files changed, 86 insertions, 50 deletions
diff --git a/API.txt b/API.txt
index 3c584cba0..2d02ecd8c 100644
--- a/API.txt
+++ b/API.txt
@@ -1366,6 +1366,12 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
+command: dnsrecord_split_parts
+args: 2,1,1
+arg: Str('name')
+arg: Str('value')
+option: Str('version?')
+output: Output('result')
command: dnszone_add
args: 1,28,3
arg: DNSNameParam('idnsname', cli_name='name')
diff --git a/VERSION b/VERSION
index 36d3fe267..17b335280 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=166
-# Last change: tbabej - idviews: Add user certificate attribute to user ID overrides
+IPA_API_VERSION_MINOR=167
+# Last change: dns: do not rely on server data structures in code called on client
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 2ea803025..a613a7399 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -295,6 +295,9 @@ server:
register = Registry()
+# dnsrecord param name formats
+record_name_format = '%srecord'
+
# supported resource record types
_record_types = (
u'A', u'AAAA', u'A6', u'AFSDB', u'APL', u'CERT', u'CNAME', u'DHCID', u'DLV',
@@ -312,7 +315,8 @@ _rev_top_record_types = ('PTR', )
_zone_top_record_types = ('NS', 'MX', 'LOC', )
# attributes derived from record types
-_record_attributes = [str('%srecord' % t.lower()) for t in _record_types]
+_record_attributes = [str(record_name_format % t.lower())
+ for t in _record_types]
# Deprecated
# supported DNS classes, IN = internet, rest is almost never used
@@ -331,6 +335,14 @@ _output_permissions = (
)
+def get_record_rrtype(name):
+ match = re.match('([^_]+)record$', name)
+ if match is None:
+ return None
+
+ return match.group(1).upper()
+
+
def _rname_validator(ugettext, zonemgr):
try:
DNSName(zonemgr) # test only if it is valid domain name
@@ -665,9 +677,9 @@ def _check_DN_objectclass(ldap, dn, objectclasses):
return _check_entry_objectclass(entry, objectclasses)
-def __get_part_param(param, cmd, part, output_kw, default=None):
- name = param.part_name_format % (param.rrtype.lower(), part.name)
- label = param.part_label_format % (param.rrtype, unicode(part.label))
+def __get_part_param(cmd, part, output_kw, default=None):
+ name = part.name
+ label = unicode(part.label)
optional = not part.required
output_kw[name] = cmd.prompt_param(part,
@@ -675,33 +687,37 @@ def __get_part_param(param, cmd, part, output_kw, default=None):
label=label)
-def prompt_parts(param, cmd, mod_dnsvalue=None):
+def prompt_parts(rrtype, cmd, mod_dnsvalue=None):
mod_parts = None
if mod_dnsvalue is not None:
- mod_parts = param._get_part_values(mod_dnsvalue)
+ name = record_name_format % rrtype.lower()
+ mod_parts = cmd.api.Command.dnsrecord_split_parts(
+ name, mod_dnsvalue)['result']
user_options = {}
- if param.parts is None:
+ parts = [p for p in cmd.params if 'dnsrecord_part' in p.flags]
+ if not parts:
return user_options
- for part_id, part in enumerate(param.parts):
+ for part_id, part in enumerate(parts):
if mod_parts:
default = mod_parts[part_id]
else:
default = None
- __get_part_param(param, cmd, part, user_options, default)
+ __get_part_param(cmd, part, user_options, default)
return user_options
-def prompt_missing_parts(param, cmd, kw, prompt_optional=False):
+def prompt_missing_parts(rrtype, cmd, kw, prompt_optional=False):
user_options = {}
- if param.parts is None:
+ parts = [p for p in cmd.params if 'dnsrecord_part' in p.flags]
+ if not parts:
return user_options
- for part in param.parts:
- name = param.part_name_format % (param.rrtype.lower(), part.name)
+ for part in parts:
+ name = part.name
if name in kw:
continue
@@ -711,7 +727,7 @@ def prompt_missing_parts(param, cmd, kw, prompt_optional=False):
continue
default = part.get_default(**kw)
- __get_part_param(param, cmd, part, user_options, default)
+ __get_part_param(cmd, part, user_options, default)
return user_options
@@ -723,8 +739,10 @@ def has_cli_options(cmd, options, no_option_msg, allow_empty_attrs=False):
has_options = False
for attr in options.keys():
- if (attr in cmd.obj.params and
- not cmd.obj.params[attr].primary_key):
+ obj_params = [
+ p.name for p in cmd.params()
+ if get_record_rrtype(p.name) or 'dnsrecord_part' in p.flags]
+ if attr in obj_params:
if options[attr] or allow_empty_attrs:
has_options = True
break
@@ -741,7 +759,7 @@ def get_rrparam_from_part(cmd, part_name):
:param part_name Part parameter name
"""
try:
- param = cmd.obj.params[part_name]
+ param = cmd.params[part_name]
if not any(flag in param.flags for flag in
('dnsrecord_part', 'dnsrecord_extra')):
@@ -749,7 +767,7 @@ def get_rrparam_from_part(cmd, part_name):
# All DNS record part or extra parameters contain a name of its
# parent RR parameter in its hint attribute
- rrparam = cmd.obj.params[param.hint]
+ rrparam = cmd.params[param.hint]
except (KeyError, AttributeError):
return None
@@ -772,7 +790,7 @@ def iterate_rrparams_by_parts(cmd, kw, skip_extra=False):
if rrparam is None:
continue
- if skip_extra and 'dnsrecord_extra' in cmd.obj.params[opt].flags:
+ if skip_extra and 'dnsrecord_extra' in cmd.params[opt].flags:
continue
if rrparam.name not in processed:
@@ -812,7 +830,7 @@ class DNSRecord(Str):
raise ValueError("Unknown RR type: %s. Must be one of %s" % \
(str(self.rrtype), ", ".join(_record_types)))
if not name:
- name = "%srecord*" % self.rrtype.lower()
+ name = "%s*" % (record_name_format % self.rrtype.lower())
kw.setdefault('cli_name', '%s_rec' % self.rrtype.lower())
kw.setdefault('label', self.label_format % self.rrtype)
kw.setdefault('doc', self.doc_format % self.rrtype)
@@ -1625,8 +1643,7 @@ def __dns_record_options_iter():
yield extra
_dns_record_options = tuple(__dns_record_options_iter())
-_dns_supported_record_types = tuple(record.rrtype for record in _dns_records \
- if record.supported)
+
def check_ns_rec_resolvable(zone, name, log):
assert isinstance(zone, DNSName)
@@ -1787,8 +1804,8 @@ def _create_idn_filter(cmd, ldap, term=None, **options):
return filter
-map_names_to_records = {"%srecord" % record.rrtype.lower(): record for record
- in _dns_records if record.supported}
+map_names_to_records = {record_name_format % record.rrtype.lower(): record
+ for record in _dns_records if record.supported}
def _records_idn_postprocess(record, **options):
for attr in record.keys():
@@ -3118,7 +3135,7 @@ class dnsrecord(LDAPObject):
# dissallowed wildcard (RFC 4592 section 4)
no_wildcard_rtypes = ['DNAME', 'DS', 'NS']
if (keys[-1].is_wild() and
- any(entry_attrs.get('%srecord' % r.lower())
+ any(entry_attrs.get(record_name_format % r.lower())
for r in no_wildcard_rtypes)
):
raise errors.ValidationError(
@@ -3228,9 +3245,8 @@ class dnsrecord(LDAPObject):
return super(dnsrecord, self).get_dn(*keys, **options)
def attr_to_cli(self, attr):
- try:
- cliname = attr[:-len('record')].upper()
- except IndexError:
+ cliname = get_record_rrtype(attr)
+ if not cliname:
cliname = attr
return cliname
@@ -3348,7 +3364,7 @@ class dnsrecord(LDAPObject):
if nsrecords and not self.is_pkey_zone_record(*keys):
for r_type in _record_types:
if (r_type not in allowed_records
- and rrattrs.get('%srecord' % r_type.lower())
+ and rrattrs.get(record_name_format % r_type.lower())
):
raise errors.ValidationError(
name='nsrecord',
@@ -3379,7 +3395,6 @@ class dnsrecord(LDAPObject):
{rdtype: None} if RRset of given type is empty
{rdtype: RRset} if RRset of given type is non-empty
'''
- record_attr_suf = 'record'
ldap_rrsets = {}
if not entry_attrs:
@@ -3387,10 +3402,11 @@ class dnsrecord(LDAPObject):
return None
for attr, value in entry_attrs.items():
- if not attr.endswith(record_attr_suf):
+ rrtype = get_record_rrtype(attr)
+ if not rrtype:
continue
- rdtype = dns.rdatatype.from_text(attr[0:-len(record_attr_suf)])
+ rdtype = dns.rdatatype.from_text(rrtype)
if not value:
ldap_rrsets[rdtype] = None # RRset is empty
continue
@@ -3583,6 +3599,20 @@ class dnsrecord(LDAPObject):
@register()
+class dnsrecord_split_parts(Command):
+ NO_CLI = True
+
+ takes_args = (
+ Str('name'),
+ Str('value'),
+ )
+
+ def execute(self, name, value, *args, **options):
+ result = self.api.Object.dnsrecord.params[name]._get_part_values(value)
+ return dict(result=result)
+
+
+@register()
class dnsrecord_add(LDAPCreate):
__doc__ = _('Add new DNS resource record.')
@@ -3614,7 +3644,8 @@ class dnsrecord_add(LDAPCreate):
new_kw = {}
for rrparam in iterate_rrparams_by_parts(self, kw,
skip_extra=True):
- user_options = prompt_missing_parts(rrparam, self, kw,
+ rrtype = get_record_rrtype(rrparam.name)
+ user_options = prompt_missing_parts(rrtype, self, kw,
prompt_optional=False)
new_kw.update(user_options)
kw.update(new_kw)
@@ -3652,21 +3683,21 @@ class dnsrecord_add(LDAPCreate):
return
try:
- name = '%srecord' % rrtype.lower()
+ name = record_name_format % rrtype.lower()
param = self.params[name]
- if not isinstance(param, DNSRecord):
- raise ValueError()
-
- if not param.supported:
+ if 'no_option' in param.flags:
raise ValueError()
except (KeyError, ValueError):
- all_types = u', '.join(_dns_supported_record_types)
+ all_types = u', '.join(get_record_rrtype(p.name)
+ for p in self.params()
+ if (get_record_rrtype(p.name) and
+ 'no_option' not in p.flags))
self.Backend.textui.print_plain(_(u'Invalid or unsupported type. Allowed values are: %s') % all_types)
continue
ok = True
- user_options = prompt_parts(param, self)
+ user_options = prompt_parts(rrtype, self)
kw.update(user_options)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
@@ -3935,7 +3966,6 @@ class dnsrecord_mod(LDAPUpdate):
# get DNS record first so that the NotFound exception is raised
# before the helper would start
dns_record = self.api.Command['dnsrecord_show'](kw['dnszoneidnsname'], kw['idnsname'])['result']
- rec_types = [rec_type for rec_type in dns_record if rec_type in _record_attributes]
self.Backend.textui.print_plain(_("No option to modify specific record provided."))
@@ -3948,23 +3978,24 @@ class dnsrecord_mod(LDAPUpdate):
param = self.params[attr]
except KeyError:
continue
- if not isinstance(param, DNSRecord):
+ rrtype = get_record_rrtype(param.name)
+ if not rrtype:
continue
- record_params.append(param)
+ record_params.append((param, rrtype))
rec_type_content = u', '.join(dns_record[param.name])
self.Backend.textui.print_plain(u'%s: %s' % (param.label, rec_type_content))
self.Backend.textui.print_plain(u'')
# ask what records to remove
- for param in record_params:
+ for param, rrtype in record_params:
rec_values = list(dns_record[param.name])
for rec_value in dns_record[param.name]:
rec_values.remove(rec_value)
mod_value = self.Backend.textui.prompt_yesno(
_("Modify %(name)s '%(value)s'?") % dict(name=param.label, value=rec_value), default=False)
if mod_value is True:
- user_options = prompt_parts(param, self,
+ user_options = prompt_parts(rrtype, self,
mod_dnsvalue=rec_value)
kw[param.name] = [rec_value]
kw.update(user_options)
@@ -3973,7 +4004,7 @@ class dnsrecord_mod(LDAPUpdate):
self.Backend.textui.print_plain(ngettext(
u'%(count)d %(type)s record skipped. Only one value per DNS record type can be modified at one time.',
u'%(count)d %(type)s records skipped. Only one value per DNS record type can be modified at one time.',
- 0) % dict(count=len(rec_values), type=param.rrtype))
+ 0) % dict(count=len(rec_values), type=rrtype))
break
@@ -4124,7 +4155,6 @@ class dnsrecord_del(LDAPUpdate):
# get DNS record first so that the NotFound exception is raised
# before the helper would start
dns_record = self.api.Command['dnsrecord_show'](kw['dnszoneidnsname'], kw['idnsname'])['result']
- rec_types = [rec_type for rec_type in dns_record if rec_type in _record_attributes]
self.Backend.textui.print_plain(_("No option to delete specific record provided."))
user_del_all = self.Backend.textui.prompt_yesno(_("Delete all?"), default=False)
@@ -4142,7 +4172,7 @@ class dnsrecord_del(LDAPUpdate):
param = self.params[attr]
except KeyError:
continue
- if not isinstance(param, DNSRecord):
+ if not get_record_rrtype(param.name):
continue
present_params.append(param)