From 234270dc753ef39cd5c0ada17e88ef7f512a8cd0 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Thu, 28 Apr 2016 10:32:00 +0200 Subject: [PATCH] dns: do not rely on custom param fields in record attributes Obtain the information provided by the `hint` kwarg and `dnsrecord_part` and `dnsrecord_extra` flags by other means. https://fedorahosted.org/freeipa/ticket/4739 Reviewed-By: David Kupka --- ipaclient/plugins/dns.py | 7 ++++--- ipalib/dns.py | 32 +++++++++++++++++++++++++------- ipaserver/plugins/dns.py | 36 +++++++++++++++++------------------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/ipaclient/plugins/dns.py b/ipaclient/plugins/dns.py index 06cd2c281..d04f686dd 100644 --- a/ipaclient/plugins/dns.py +++ b/ipaclient/plugins/dns.py @@ -25,7 +25,8 @@ import copy from ipaclient.frontend import MethodOverride, CommandOverride from ipalib import errors -from ipalib.dns import (get_record_rrtype, +from ipalib.dns import (get_part_rrtype, + get_record_rrtype, has_cli_options, iterate_rrparams_by_parts, record_name_format) @@ -63,7 +64,7 @@ def prompt_parts(rrtype, cmd, mod_dnsvalue=None): name, mod_dnsvalue)['result'] user_options = {} - parts = [p for p in cmd.params() if 'dnsrecord_part' in p.flags] + parts = [p for p in cmd.params() if get_part_rrtype(p.name) == rrtype] if not parts: return user_options @@ -80,7 +81,7 @@ def prompt_parts(rrtype, cmd, mod_dnsvalue=None): def prompt_missing_parts(rrtype, cmd, kw, prompt_optional=False): user_options = {} - parts = [p for p in cmd.params() if 'dnsrecord_part' in p.flags] + parts = [p for p in cmd.params() if get_part_rrtype(p.name) == rrtype] if not parts: return user_options diff --git a/ipalib/dns.py b/ipalib/dns.py index 55e45a094..95c7989b6 100644 --- a/ipalib/dns.py +++ b/ipalib/dns.py @@ -26,6 +26,8 @@ from ipalib import errors # dnsrecord param name formats record_name_format = '%srecord' +part_name_format = "%s_part_%s" +extra_name_format = "%s_extra_%s" def get_record_rrtype(name): @@ -36,6 +38,22 @@ def get_record_rrtype(name): return match.group(1).upper() +def get_part_rrtype(name): + match = re.match('([^_]+)_part_.*$', name) + if match is None: + return None + + return match.group(1).upper() + + +def get_extra_rrtype(name): + match = re.match('([^_]+)_extra_.*$', name) + if match is None: + return None + + return match.group(1).upper() + + def has_cli_options(cmd, options, no_option_msg, allow_empty_attrs=False): sufficient = ('setattr', 'addattr', 'delattr', 'rename') if any(k in options for k in sufficient): @@ -43,9 +61,8 @@ def has_cli_options(cmd, options, no_option_msg, allow_empty_attrs=False): has_options = False for attr in options.keys(): - obj_params = [ - p.name for p in cmd.params() - if get_record_rrtype(p.name) or 'dnsrecord_part' in p.flags] + obj_params = [n for n in cmd.params + if get_record_rrtype(n) or get_part_rrtype(n)] if attr in obj_params: if options[attr] or allow_empty_attrs: has_options = True @@ -65,13 +82,14 @@ def get_rrparam_from_part(cmd, part_name): try: param = cmd.params[part_name] - if not any(flag in param.flags for flag in - ('dnsrecord_part', 'dnsrecord_extra')): + rrtype = (get_part_rrtype(param.name) or + get_extra_rrtype(param.name)) + if not rrtype: return None # All DNS record part or extra parameters contain a name of its # parent RR parameter in its hint attribute - rrparam = cmd.params[param.hint] + rrparam = cmd.params[record_name_format % rrtype.lower()] except (KeyError, AttributeError): return None @@ -94,7 +112,7 @@ def iterate_rrparams_by_parts(cmd, kw, skip_extra=False): if rrparam is None: continue - if skip_extra and 'dnsrecord_extra' in cmd.params[opt].flags: + if skip_extra and get_extra_rrtype(opt): continue if rrparam.name not in processed: diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py index 86da01ac5..14607b3fe 100644 --- a/ipaserver/plugins/dns.py +++ b/ipaserver/plugins/dns.py @@ -32,10 +32,14 @@ import dns.rdatatype import dns.resolver import six -from ipalib.dns import (get_record_rrtype, +from ipalib.dns import (extra_name_format, + get_extra_rrtype, + get_part_rrtype, + get_record_rrtype, get_rrparam_from_part, has_cli_options, iterate_rrparams_by_parts, + part_name_format, record_name_format) from ipalib.request import context from ipalib import api, errors, output @@ -657,8 +661,6 @@ class DNSRecord(Str): doc_format = _('Raw %s records') option_group_format = _('%s Record') see_rfc_msg = _("(see RFC %s for details)") - part_name_format = "%s_part_%s" - extra_name_format = "%s_extra_%s" cli_name_format = "%s_%s" format_error_msg = None @@ -708,8 +710,8 @@ class DNSRecord(Str): return u" ".join(parts) def get_parts_from_kw(self, kw, raise_on_none=True): - part_names = tuple(self.part_name_format % (self.rrtype.lower(), part.name) \ - for part in self.parts) + part_names = tuple(part_name_format % (self.rrtype.lower(), part.name) + for part in self.parts) vals = tuple(kw.get(part_name) for part_name in part_names) if all(val is None for val in vals): @@ -813,11 +815,11 @@ class DNSRecord(Str): can be added to global DNS API. For example a prefix need to be added before part name so that the name is unique in the global namespace. """ - name = self.part_name_format % (self.rrtype.lower(), part.name) + name = part_name_format % (self.rrtype.lower(), part.name) cli_name = self.cli_name_format % (self.rrtype.lower(), part.name) label = self.part_label_format % (self.rrtype, unicode(part.label)) option_group = self.option_group_format % self.rrtype - flags = list(part.flags) + ['dnsrecord_part', 'virtual_attribute',] + flags = list(part.flags) + ['virtual_attribute'] if not part.required: flags.append('dnsrecord_optional') if not self.supported: @@ -828,27 +830,25 @@ class DNSRecord(Str): label=label, required=False, option_group=option_group, - flags=flags, - hint=self.name,) # name of parent RR param + flags=flags) def _convert_dnsrecord_extra(self, extra): """ Parameters for special per-type behavior need to be processed in the same way as record parts in _convert_dnsrecord_part(). """ - name = self.extra_name_format % (self.rrtype.lower(), extra.name) + name = extra_name_format % (self.rrtype.lower(), extra.name) cli_name = self.cli_name_format % (self.rrtype.lower(), extra.name) label = self.part_label_format % (self.rrtype, unicode(extra.label)) option_group = self.option_group_format % self.rrtype - flags = list(extra.flags) + ['dnsrecord_extra', 'virtual_attribute',] + flags = list(extra.flags) + ['virtual_attribute'] return extra.clone_rename(name, cli_name=cli_name, label=label, required=False, option_group=option_group, - flags=flags, - hint=self.name,) # name of parent RR param + flags=flags) def get_parts(self): if self.parts is None: @@ -3509,7 +3509,7 @@ class dnsrecord_add(LDAPCreate): if rrparam is None: continue - if 'dnsrecord_part' in param.flags: + if get_part_rrtype(param.name): if rrparam.name in processed_attrs: # this record was already entered continue @@ -3525,7 +3525,7 @@ class dnsrecord_add(LDAPCreate): processed_attrs.append(rrparam.name) continue - if 'dnsrecord_extra' in param.flags: + if get_extra_rrtype(param.name): # do not run precallback for unset flags if isinstance(param, Flag) and not options[option]: continue @@ -3779,8 +3779,7 @@ class dnsrecord_del(LDAPUpdate): def get_options(self): for option in super(dnsrecord_del, self).get_options(): - if any(flag in option.flags for flag in \ - ('dnsrecord_part', 'dnsrecord_extra',)): + if get_part_rrtype(option.name) or get_extra_rrtype(option.name): continue elif option.name in ('rename', ): # options only valid for dnsrecord-mod @@ -3910,8 +3909,7 @@ class dnsrecord_find(LDAPSearch): def get_options(self): for option in super(dnsrecord_find, self).get_options(): - if any(flag in option.flags for flag in \ - ('dnsrecord_part', 'dnsrecord_extra',)): + if get_part_rrtype(option.name) or get_extra_rrtype(option.name): continue elif isinstance(option, DNSRecord): yield option.clone(option_group=None)