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 <dkupka@redhat.com>
This commit is contained in:
Jan Cholasta
2016-04-28 10:32:00 +02:00
parent ade8d42525
commit 234270dc75
3 changed files with 46 additions and 29 deletions

View File

@@ -25,7 +25,8 @@ import copy
from ipaclient.frontend import MethodOverride, CommandOverride from ipaclient.frontend import MethodOverride, CommandOverride
from ipalib import errors from ipalib import errors
from ipalib.dns import (get_record_rrtype, from ipalib.dns import (get_part_rrtype,
get_record_rrtype,
has_cli_options, has_cli_options,
iterate_rrparams_by_parts, iterate_rrparams_by_parts,
record_name_format) record_name_format)
@@ -63,7 +64,7 @@ def prompt_parts(rrtype, cmd, mod_dnsvalue=None):
name, mod_dnsvalue)['result'] name, mod_dnsvalue)['result']
user_options = {} 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: if not parts:
return user_options 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): def prompt_missing_parts(rrtype, cmd, kw, prompt_optional=False):
user_options = {} 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: if not parts:
return user_options return user_options

View File

@@ -26,6 +26,8 @@ from ipalib import errors
# dnsrecord param name formats # dnsrecord param name formats
record_name_format = '%srecord' record_name_format = '%srecord'
part_name_format = "%s_part_%s"
extra_name_format = "%s_extra_%s"
def get_record_rrtype(name): def get_record_rrtype(name):
@@ -36,6 +38,22 @@ def get_record_rrtype(name):
return match.group(1).upper() 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): def has_cli_options(cmd, options, no_option_msg, allow_empty_attrs=False):
sufficient = ('setattr', 'addattr', 'delattr', 'rename') sufficient = ('setattr', 'addattr', 'delattr', 'rename')
if any(k in options for k in sufficient): 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 has_options = False
for attr in options.keys(): for attr in options.keys():
obj_params = [ obj_params = [n for n in cmd.params
p.name for p in cmd.params() if get_record_rrtype(n) or get_part_rrtype(n)]
if get_record_rrtype(p.name) or 'dnsrecord_part' in p.flags]
if attr in obj_params: if attr in obj_params:
if options[attr] or allow_empty_attrs: if options[attr] or allow_empty_attrs:
has_options = True has_options = True
@@ -65,13 +82,14 @@ def get_rrparam_from_part(cmd, part_name):
try: try:
param = cmd.params[part_name] param = cmd.params[part_name]
if not any(flag in param.flags for flag in rrtype = (get_part_rrtype(param.name) or
('dnsrecord_part', 'dnsrecord_extra')): get_extra_rrtype(param.name))
if not rrtype:
return None return None
# All DNS record part or extra parameters contain a name of its # All DNS record part or extra parameters contain a name of its
# parent RR parameter in its hint attribute # parent RR parameter in its hint attribute
rrparam = cmd.params[param.hint] rrparam = cmd.params[record_name_format % rrtype.lower()]
except (KeyError, AttributeError): except (KeyError, AttributeError):
return None return None
@@ -94,7 +112,7 @@ def iterate_rrparams_by_parts(cmd, kw, skip_extra=False):
if rrparam is None: if rrparam is None:
continue continue
if skip_extra and 'dnsrecord_extra' in cmd.params[opt].flags: if skip_extra and get_extra_rrtype(opt):
continue continue
if rrparam.name not in processed: if rrparam.name not in processed:

View File

@@ -32,10 +32,14 @@ import dns.rdatatype
import dns.resolver import dns.resolver
import six 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, get_rrparam_from_part,
has_cli_options, has_cli_options,
iterate_rrparams_by_parts, iterate_rrparams_by_parts,
part_name_format,
record_name_format) record_name_format)
from ipalib.request import context from ipalib.request import context
from ipalib import api, errors, output from ipalib import api, errors, output
@@ -657,8 +661,6 @@ class DNSRecord(Str):
doc_format = _('Raw %s records') doc_format = _('Raw %s records')
option_group_format = _('%s Record') option_group_format = _('%s Record')
see_rfc_msg = _("(see RFC %s for details)") 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" cli_name_format = "%s_%s"
format_error_msg = None format_error_msg = None
@@ -708,8 +710,8 @@ class DNSRecord(Str):
return u" ".join(parts) return u" ".join(parts)
def get_parts_from_kw(self, kw, raise_on_none=True): def get_parts_from_kw(self, kw, raise_on_none=True):
part_names = tuple(self.part_name_format % (self.rrtype.lower(), part.name) \ part_names = tuple(part_name_format % (self.rrtype.lower(), part.name)
for part in self.parts) for part in self.parts)
vals = tuple(kw.get(part_name) for part_name in part_names) vals = tuple(kw.get(part_name) for part_name in part_names)
if all(val is None for val in vals): 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 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. 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) cli_name = self.cli_name_format % (self.rrtype.lower(), part.name)
label = self.part_label_format % (self.rrtype, unicode(part.label)) label = self.part_label_format % (self.rrtype, unicode(part.label))
option_group = self.option_group_format % self.rrtype 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: if not part.required:
flags.append('dnsrecord_optional') flags.append('dnsrecord_optional')
if not self.supported: if not self.supported:
@@ -828,27 +830,25 @@ class DNSRecord(Str):
label=label, label=label,
required=False, required=False,
option_group=option_group, option_group=option_group,
flags=flags, flags=flags)
hint=self.name,) # name of parent RR param
def _convert_dnsrecord_extra(self, extra): def _convert_dnsrecord_extra(self, extra):
""" """
Parameters for special per-type behavior need to be processed in the Parameters for special per-type behavior need to be processed in the
same way as record parts in _convert_dnsrecord_part(). 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) cli_name = self.cli_name_format % (self.rrtype.lower(), extra.name)
label = self.part_label_format % (self.rrtype, unicode(extra.label)) label = self.part_label_format % (self.rrtype, unicode(extra.label))
option_group = self.option_group_format % self.rrtype 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, return extra.clone_rename(name,
cli_name=cli_name, cli_name=cli_name,
label=label, label=label,
required=False, required=False,
option_group=option_group, option_group=option_group,
flags=flags, flags=flags)
hint=self.name,) # name of parent RR param
def get_parts(self): def get_parts(self):
if self.parts is None: if self.parts is None:
@@ -3509,7 +3509,7 @@ class dnsrecord_add(LDAPCreate):
if rrparam is None: if rrparam is None:
continue continue
if 'dnsrecord_part' in param.flags: if get_part_rrtype(param.name):
if rrparam.name in processed_attrs: if rrparam.name in processed_attrs:
# this record was already entered # this record was already entered
continue continue
@@ -3525,7 +3525,7 @@ class dnsrecord_add(LDAPCreate):
processed_attrs.append(rrparam.name) processed_attrs.append(rrparam.name)
continue continue
if 'dnsrecord_extra' in param.flags: if get_extra_rrtype(param.name):
# do not run precallback for unset flags # do not run precallback for unset flags
if isinstance(param, Flag) and not options[option]: if isinstance(param, Flag) and not options[option]:
continue continue
@@ -3779,8 +3779,7 @@ class dnsrecord_del(LDAPUpdate):
def get_options(self): def get_options(self):
for option in super(dnsrecord_del, self).get_options(): for option in super(dnsrecord_del, self).get_options():
if any(flag in option.flags for flag in \ if get_part_rrtype(option.name) or get_extra_rrtype(option.name):
('dnsrecord_part', 'dnsrecord_extra',)):
continue continue
elif option.name in ('rename', ): elif option.name in ('rename', ):
# options only valid for dnsrecord-mod # options only valid for dnsrecord-mod
@@ -3910,8 +3909,7 @@ class dnsrecord_find(LDAPSearch):
def get_options(self): def get_options(self):
for option in super(dnsrecord_find, self).get_options(): for option in super(dnsrecord_find, self).get_options():
if any(flag in option.flags for flag in \ if get_part_rrtype(option.name) or get_extra_rrtype(option.name):
('dnsrecord_part', 'dnsrecord_extra',)):
continue continue
elif isinstance(option, DNSRecord): elif isinstance(option, DNSRecord):
yield option.clone(option_group=None) yield option.clone(option_group=None)