diff options
-rw-r--r-- | ipalib/cli.py | 6 | ||||
-rw-r--r-- | ipalib/plugins/dns.py | 123 |
2 files changed, 109 insertions, 20 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py index e232c3ed2..737ae0015 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -529,6 +529,9 @@ class textui(backend.Backend): print raise PromptFailed(name=label) + def print_prompt_attribute_error(self, attribute, error): + self.print_plain('>>> %s: %s' % (attribute, error)) + def prompt(self, label, default=None, get_values=None, optional=False): """ Prompt user for input. @@ -1160,7 +1163,8 @@ class cli(backend.Executioner): error = None while True: if error is not None: - print '>>> %s: %s' % (unicode(param.label), unicode(error)) + self.Backend.textui.print_prompt_attribute_error(unicode(param.label), + unicode(error)) raw = self.Backend.textui.prompt(param.label, default, optional=param.alwaysask or not param.required) try: value = param(raw, **kw) diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py index 27bf1091f..a10960a2c 100644 --- a/ipalib/plugins/dns.py +++ b/ipalib/plugins/dns.py @@ -699,6 +699,25 @@ class DNSRecord(Str): return tuple(self._convert_dnsrecord_extra(extra) for extra in self.extra) + def __get_part_param(self, backend, part, output_kw, default=None): + name = self.part_name_format % (self.rrtype.lower(), part.name) + label = self.part_label_format % (self.rrtype, unicode(part.label)) + optional = not part.required + + while True: + try: + raw = backend.textui.prompt(label, + optional=optional, + default=default) + if not raw.strip(): + raw = default + + output_kw[name] = part(raw) + break + except (errors.ValidationError, errors.ConversionError), e: + backend.textui.print_prompt_attribute_error( + unicode(label), unicode(e.error)) + def prompt_parts(self, backend, mod_dnsvalue=None): mod_parts = None if mod_dnsvalue is not None: @@ -709,21 +728,33 @@ class DNSRecord(Str): return user_options for part_id, part in enumerate(self.parts): - name = self.part_name_format % (self.rrtype.lower(), part.name) - label = self.part_label_format % (self.rrtype, unicode(part.label)) - optional = not part.required if mod_parts: default = mod_parts[part_id] else: default = None - raw = backend.textui.prompt(label, - optional=optional, - default=default) - if not raw.strip(): - raw = default + self.__get_part_param(backend, part, user_options, default) + + return user_options + + def prompt_missing_parts(self, backend, kw, prompt_optional=False): + user_options = {} + if self.parts is None: + return user_options - user_options[name] = part(raw) + for part in self.parts: + name = self.part_name_format % (self.rrtype.lower(), part.name) + label = self.part_label_format % (self.rrtype, unicode(part.label)) + + if name in kw: + continue + + optional = not part.required + if optional and not prompt_optional: + continue + + default = part.get_default(**kw) + self.__get_part_param(backend, part, user_options, default) return user_options @@ -1946,6 +1977,51 @@ class dnsrecord(LDAPObject): record.setdefault('dnsrecords', []).append(dnsentry) del record[attr] + def get_rrparam_from_part(self, part_name): + """ + Get an instance of DNSRecord parameter that has part_name as its part. + If such parameter is not found, None is returned + + :param part_name Part parameter name + """ + try: + param = self.params[part_name] + + if not any(flag in param.flags for flag in \ + ('dnsrecord_part', 'dnsrecord_extra')): + return None + + # All DNS record part or extra parameters contain a name of its + # parent RR parameter in its hint attribute + rrparam = self.params[param.hint] + except (KeyError, AttributeError): + return None + + return rrparam + + def iterate_rrparams_by_parts(self, kw, skip_extra=False): + """ + Iterates through all DNSRecord instances that has at least one of its + parts or extra options in given dictionary. It returns the DNSRecord + instance only for the first occurence of part/extra option. + + :param kw Dictionary with DNS record parts or extra options + :param skip_extra Skip DNS record extra options, yield only DNS records + with a real record part + """ + processed = [] + for opt in kw: + rrparam = self.get_rrparam_from_part(opt) + if rrparam is None: + continue + + if skip_extra and 'dnsrecord_extra' in self.params[opt].flags: + continue + + if rrparam.name not in processed: + processed.append(rrparam) + yield rrparam + api.register(dnsrecord) @@ -1970,11 +2046,22 @@ class dnsrecord_add(LDAPCreate): def interactive_prompt_callback(self, kw): try: self.obj.has_cli_options(kw, self.no_option_msg) + + # Some DNS records were entered, do not use full interactive help + # We should still ask user for required parts of DNS parts he is + # trying to add in the same way we do for standard LDAP parameters + # + # Do not ask for required parts when any "extra" option is used, + # it can be used to fill all required params by itself + new_kw = {} + for rrparam in self.obj.iterate_rrparams_by_parts(kw, skip_extra=True): + user_options = rrparam.prompt_missing_parts(self.Backend, kw, + prompt_optional=False) + new_kw.update(user_options) + kw.update(new_kw) + return except errors.OptionError: pass - else: - # some record type entered, skip this helper - return # check zone type if kw['idnsname'] == _dns_zone_record: @@ -2026,13 +2113,11 @@ class dnsrecord_add(LDAPCreate): except KeyError: continue - if 'dnsrecord_part' in param.flags: - # check if any record part was added - try: - rrparam = self.params[param.hint] - except (KeyError, AttributeError): - continue + rrparam = self.obj.get_rrparam_from_part(option) + if rrparam is None: + continue + if 'dnsrecord_part' in param.flags: if rrparam.name in entry_attrs: # this record was already entered continue @@ -2047,7 +2132,7 @@ class dnsrecord_add(LDAPCreate): if isinstance(param, Flag) and not options[option]: continue # extra option is passed, run per-type pre_callback for given RR type - precallback_attrs.append(param.hint) + precallback_attrs.append(rrparam.name) # run precallback also for all new RR type attributes in entry_attrs for attr in entry_attrs: |