<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 01/21/2016 05:04 PM, Martin Babinsky
      wrote:<br>
    </div>
    <blockquote cite="mid:56A1018D.101@redhat.com" type="cite">On
      01/21/2016 01:37 PM, thierry bordaz wrote:
      <br>
      <blockquote type="cite">
        <br>
        <br>
        <br>
      </blockquote>
      Hi Thierry,
      <br>
      <br>
      I have couple of comments to your patch:
      <br>
      <br>
      1.)
      <br>
      there is a number of PEP8 errors in the patch
      (<a class="moz-txt-link-freetext" href="http://paste.fedoraproject.org/313246/33893701">http://paste.fedoraproject.org/313246/33893701</a>), please fix them.
      <br>
      <br>
      See <a class="moz-txt-link-freetext" href="http://www.freeipa.org/page/Python_Coding_Style">http://www.freeipa.org/page/Python_Coding_Style</a> for our
      conventions used in Python code.
      <br>
      <br>
      2.)
      <br>
      +        DNA_BIND_METHOD   = "dnaRemoteBindMethod"
      <br>
      +        DNA_CONN_PROTOCOL = "dnaRemoteConnProtocol"
      <br>
      +        DNA_PLUGIN_DN     = 'cn=Distributed Numeric Assignment
      Plugin,cn=plugins,cn=config'
      <br>
      +        dna_config_base   = 'cn=Posix IDs,%s' % DNA_PLUGIN_DN
      <br>
      <br>
      Uppercase names are usually reserved for module-level constants.
      OTOH, local variables should be lowercase. Also you can
      instantiate dna_config_base directly as DN, using 2-member tuples,
      i. e:
      <br>
      <br>
      """
      <br>
      dna_config_base = DN(('cn', 'posix IDs'), ('cn', 'Distributed
      Numeric Assignment Plugin'), ('cn', 'plugins'), ('cn', 'config'))
      <br>
      """
      <br>
      <br>
      When passing DN object to the formatting functions/operators, it
      is automatically converted to string so no need to hold string and
      DN object separately. This is done in other places (see
      function/methods in replication.py).
      <br>
      <br>
      3.)
      <br>
      <br>
      +        for i in range(len(entries)) :
      <br>
      +
      <br>
      +            mod = []
      <br>
      +            if entries[i].single_value.get(DNA_BIND_METHOD) !=
      method:
      <br>
      +                mod.append((ldap.MOD_REPLACE, DNA_BIND_METHOD,
      method))
      <br>
      +
      <br>
      +            if entries[i].single_value.get(DNA_CONN_PROTOCOL) !=
      protocol:
      <br>
      +                mod.append((ldap.MOD_REPLACE, DNA_CONN_PROTOCOL,
      protocol))
      <br>
      <br>
      <br>
      please use idiomatic Python when handling list of entries, e.g.:
      <br>
      <br>
      """
      <br>
      for entry in entries:
      <br>
         mod = []
      <br>
         if entry.single_value.get(DNA_BIND_METHOD) != method:
      <br>
         ...
      <br>
      """
      <br>
      <br>
      4.) I think that this method should in DSInstance class since it
      deals with directory server configuration. Service is a parent
      object of all other service installers/configurators and should
      contain only methods common to more children.
      <br>
      <br>
      5.) Since the method is called from every installer, it could be
      beneficial to call it in DSInstance.__common_post_setup() as a
      part of Directory server installation. Is there any reason why
      this is not the case?
      <br>
      <br>
      6.)
      <br>
      <br>
      +        while attempt != MAX_WAIT:
      <br>
      +            try:
      <br>
      +                entries = conn.get_entries(sharedcfgdn,
      scope=ldap.SCOPE_ONELEVEL, filter='dnaHostname=%s' % self.fqdn)
      <br>
      +                break
      <br>
      +            except errors.NotFound:
      <br>
      +                root_logger.debug("So far enable not find DNA
      shared config entry for dnaHostname=%s under %s. Retry in 2sec" %
      (self.fqdn, sharedcfgdn))
      <br>
      +                attempt = attempt + 1
      <br>
      +                time.sleep(2)
      <br>
      +                continue
      <br>
      +
      <br>
      +        # safety checking
      <br>
      +        # there is no return, if there are several entries, as a
      workaround of #5510
      <br>
      +        if len(entries) != 1:
      <br>
      <br>
      I am quite afraid what would happen if the server does not return
      any entries until 30 s timeout. The code will then continue to the
      condition which can potentially test an uninitialized variable and
      blow up with 'NameError'. This should be handled more robustly, e.
      g. raise an exception when a timeout is reached and no entries
      were returned.
      <br>
      <br>
      7.)
      <br>
      <br>
      +            if len(mod) > 0:
      <br>
      <br>
      A Pythonic way to test for non-empty container is
      <br>
      <br>
      """
      <br>
      if mods:
      <br>
         # do stuff
      <br>
      """
      <br>
      <br>
      since an empty list/dict/set evaluates to False and non-empty
      containers are True.
      <br>
      <br>
      <br>
      8.)
      <br>
      <br>
      +                entry = conn.get_entry(entries[i].dn)
      <br>
      +                if entry.single_value.get(DNA_BIND_METHOD) !=
      method:
      <br>
      +                    root_logger.error("Fail to set SASL/GSSAPI
      bind method to %s" % (entries[i].dn))
      <br>
      +                if entry.single_value.get(DNA_CONN_PROTOCOL) !=
      protocol:
      <br>
      +                    root_logger.error("Fail to set LDAP protocol
      to %s" % (entries[i].dn))
      <br>
      <br>
      rather than re-fetching the modified entry and testing what
      happened, you can just catch an exception raised by unsuccessfull
      mod and log an error like this:
      <br>
      <br>
      """
      <br>
      try:
      <br>
         conn.modify_s(entry.dn, mod)
      <br>
      except Exception as e:
      <br>
         root_logger.error("Failed to modify entry {}: {}".format(entry,
      e))
      <br>
      """
      <br>
      <br>
      as a matter of fact, if the modify_s operation would fail for some
      reason, an ldap exception would be raised and you checks would not
      even be executed.
      <br>
      <br>
      9.)
      <br>
      The debug message on line 219 should read "Unable to find DNA
      shared config entry for dnaHostname=%s so far. Retry in 2 sec.".
      The errors at the end of the method should have "Failed" instead
      of "Fail".
      <br>
      <br>
    </blockquote>
    <font face="Times New Roman, Times, serif">Hi Martin,<br>
      <br>
      Finally tested... here is the updated patch. Thanks for you
      patience<br>
      <br>
      <br>
      thanks<br>
      thierry<br>
    </font>
  </body>
</html>