#49776 Ticket 49712 - lib389 CLI tools should return a result code on failures
Closed 3 years ago by spichugi. Opened 5 years ago by mreynolds.
mreynolds/389-ds-base ticket49775  into  master

@@ -366,6 +366,7 @@ 

              slapi_task_log_notice(task, "mkdir(%s) failed; errno %i (%s)",

                                    directory, errno, msg ? msg : "unknown");

          }

+         return_value = -1;

If I understand correctly, by documentation, return_value = PR_Rename(directory, dir_bak); returns either PR_SUCCESS (0), either PR_FAILURE (-1). So the line you've added seems redundant to me... Or do I miss something?

Its MKDIR not PR_RENAME, and yes it is needed or else it silently fails.

          goto err;

      }

  

file modified
+16 -16
@@ -82,7 +82,7 @@ 

      cli_whoami.create_parser(subparsers)

      cli_referint.create_parser(subparsers)

      cli_automember.create_parser(subparsers)

-     

+ 

      args = parser.parse_args()

  

      log = reset_get_logger('dsconf', args.verbose)
@@ -111,26 +111,26 @@ 

      # Connect

      # We don't need a basedn, because the config objects derive it properly

      inst = None

-     if args.verbose:

+     result = False

+     try:

          inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose)

-         args.func(inst, None, log, args)

-         if not args.json:

+         result = args.func(inst, None, log, args)

+         if args.verbose:

              log.info("Command successful.")

-     else:

-         try:

-             inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose)

-             args.func(inst, None, log, args)

-             if not args.json:

-                 log.info("Command successful.")

-         except ldap.LDAPError as e:

-             #log.debug(e, exc_info=True)

-             if args and args.json:

-                 print(e)

-             else:

-                 log.error("Error!: %s" % str(e))

+     except Exception as e:

+         log.debug(e, exc_info=True)

+         if args and args.json:

+             print(e)

+         else:

+             log.error("Error!: %s" % str(e))

+         result = False

+ 

      disconnect_instance(inst)

  

      # Done!

      log.debug("dsconf is brought to you by the letter H and the number 25.")

  

+     if result is False:

+         sys.exit(1)

+ 

  

file modified
+11 -16
@@ -29,13 +29,15 @@ 

  

      fromfile_parser = subparsers.add_parser('fromfile', help="Create an instance of Directory Server from an inf answer file")

      fromfile_parser.add_argument('file', help="Inf file to use with prepared answers. You can generate an example of this with 'dscreate example'")

-     fromfile_parser.add_argument('-n', '--dryrun', help="Validate system and configurations only. Do not alter the system.", action='store_true', default=False)

+     fromfile_parser.add_argument('-n', '--dryrun', help="Validate system and configurations only. Do not alter the system.",

+                                  action='store_true', default=False)

      fromfile_parser.add_argument('--IsolemnlyswearthatIamuptonogood', dest="ack",

-                         help="""You are here likely here by mistake! You want setup-ds.pl!

+                                  help="""You are here likely here by mistake! You want setup-ds.pl!

  By setting this value you acknowledge and take responsibility for the fact this command is UNTESTED and NOT READY. You are ON YOUR OWN!

  """,

-                         action='store_true', default=False)

-     fromfile_parser.add_argument('-c', '--containerised', help="Indicate to the installer that this is running in a container. Used to disable systemd native components, even if they are installed.", action='store_true', default=False)

+                                  action='store_true', default=False)

+     fromfile_parser.add_argument('-c', '--containerised', help="Indicate to the installer that this is running in a container. Used to disable systemd native components, even if they are installed.",

+                                  action='store_true', default=False)

      fromfile_parser.set_defaults(func=cli_instance.instance_create)

  

      example_parser = subparsers.add_parser('example', help="Display an example ini answer file, with comments")
@@ -62,19 +64,12 @@ 

  

      result = False

  

-     if args.verbose:

+     try:

          result = args.func(inst, log, args)

-     else:

-         try:

-             result = args.func(inst, log, args)

-         except Exception as e:

-             log.debug(e, exc_info=True)

-             log.error("Error: %s" % str(e))

- 

-     if result is True:

-         log.info('FINISH: Command succeeded')

-     elif result is False:

-         log.info('FAIL: Command failed. See output for details.')

+     except Exception as e:

+         log.debug(e, exc_info=True)

+         log.error("Error: %s" % str(e))

+         result = False

  

      # Done!

      log.debug("dscreate is brought to you by the letter S and the number 22.")

file modified
+5 -14
@@ -86,23 +86,14 @@ 

      inst.allocate(insts[0])

      log.debug('Instance allocated')

  

-     if args.verbose:

+     try:

          result = args.func(inst, log, args)

-         log.info("Command successful.")

-     else:

-         try:

-             result = args.func(inst, log, args)

-             log.info("Command successful.")

-         except Exception as e:

-             log.debug(e, exc_info=True)

-             log.error("Error: %s" % str(e))

+     except Exception as e:

+         log.debug(e, exc_info=True)

+         log.error("Error: %s" % str(e))

+         result = False

      disconnect_instance(inst)

  

-     if result is True:

-         log.info('FINISH: Command succeeded')

-     elif result is False:

-         log.info('FAIL: Command failed. See output for details.')

- 

      # Done!

      log.debug("dsctl is brought to you by the letter R and the number 27.")

  

file modified
+11 -12
@@ -104,21 +104,20 @@ 

  

      # Connect

      inst = None

-     if args.verbose:

+     result = False

+     try:

          inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose)

-         args.func(inst, dsrc_inst['basedn'], log, args)

-         log.info("Command successful.")

-     else:

-         try:

-             inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose)

-             args.func(inst, dsrc_inst['basedn'], log, args)

+         result = args.func(inst, dsrc_inst['basedn'], log, args)

+         if args.verbose:

              log.info("Command successful.")

-         except Exception as e:

-             log.debug(e, exc_info=True)

-             log.error("Error: %s" % str(e))

-     disconnect_instance(inst)

+     except Exception as e:

+         log.debug(e, exc_info=True)

+         log.error("Error: %s" % str(e))

+         result = False

  

+     disconnect_instance(inst)

  

      log.debug("dsidm is brought to you by the letter E and the number 26.")

  

- 

+     if result is False:

+         sys.exit(1)

file modified
+62 -29
@@ -1663,7 +1663,7 @@ 

  

      def get_ldaps_uri(self):

          """Return what our ldaps (TLS) uri would be for this instance

-         

+ 

          :returns: The string of the servers ldaps (TLS) uri.

          """

          return 'ldaps://%s:%s' % (self.host, self.sslport)
@@ -1674,7 +1674,7 @@ 

  

      def get_ldap_uri(self):

          """Return what our ldap uri would be for this instance

-         

+ 

          :returns: The string of the servers ldap uri.

          """

          return 'ldap://%s:%s' % (self.host, self.port)
@@ -2777,8 +2777,13 @@ 

          if encrypt:

              cmd.append('-E')

  

-         result = subprocess.check_output(cmd)

-         u_result = ensure_str(result)

+         try:

+             result = subprocess.check_output(cmd, stderr=subprocess.STDOUT, encoding='utf-8')

+             u_result = ensure_str(result)

+         except subprocess.CalledProcessError as e:

+             self.log.debug("Command: {} failed with the return code {} and the error {}".format(

+                            format_cmd_list(cmd), e.returncode, e.output))

+             return False

  

          self.log.debug("ldif2db output: BEGIN")

          for line in u_result.split("\n"):
@@ -2830,12 +2835,24 @@ 

              cmd.append('-E')

          if repl_data:

              cmd.append('-r')

-         if outputfile:

+         if outputfile is not None:

              cmd.append('-a')

              cmd.append(outputfile)

- 

-         result = subprocess.check_output(cmd)

-         u_result = ensure_str(result)

+         else:

+             # No output file specified.  Use the default ldif location/name

+             cmd.append('-a')

+             if bename:

+                 ldifname = "/" + self.serverid + "-" + bename + "-" + datetime.now().strftime("%Y_%m_%d_%H_%M_%S")

+             else:

+                 ldifname = "/" + self.serverid + "-" + datetime.now().strftime("%Y_%m_%d_%H_%M_%S")

+             cmd.append(self.get_ldif_dir() + ldifname)

+         try:

+             result = subprocess.check_output(cmd, stderr=subprocess.STDOUT, encoding='utf-8')

+             u_result = ensure_str(result)

+         except subprocess.CalledProcessError as e:

+             self.log.debug("Command: {} failed with the return code {} and the error {}".format(

+                            format_cmd_list(cmd), e.returncode, e.output))

+             return False

  

          self.log.debug("db2ldif output: BEGIN")

          for line in u_result.split("\n"):
@@ -2861,13 +2878,18 @@ 

              self.log.error("bak2db: backup directory missing")

              return False

  

-         result = subprocess.check_output([

-             prog,

-             'archive2db',

-             '-a', archive_dir,

-             '-D', self.get_config_dir()

-         ])

-         u_result = ensure_str(result)

+         try:

+             result = subprocess.check_output([

+                 prog,

+                 'archive2db',

+                 '-a', archive_dir,

+                 '-D', self.get_config_dir()

+             ], stderr=subprocess.STDOUT, encoding='utf-8')

+             u_result = ensure_str(result)

+         except subprocess.CalledProcessError as e:

+             self.log.debug("Command: {} failed with the return code {} and the error {}".format(

+                            format_cmd_list(cmd), e.returncode, e.output))

+             return False

  

          self.log.debug("bak2db output: BEGIN")

          for line in u_result.split("\n"):
@@ -2888,17 +2910,24 @@ 

              self.log.error("db2bak: Can not operate while directory server is running")

              return False

  

-         if not archive_dir:

-             self.log.error("db2bak: archive directory missing")

-             return False

+         if archive_dir is None:

+             # Use the instance name and date/time as the default backup name

+             archive_dir = self.get_bak_dir() + "/" + self.serverid + "-" + datetime.now().strftime("%Y_%m_%d_%H_%M_%S")

+         elif archive_dir[0] != "/":

+             # Relative path, append it to the bak directory

+             archive_dir = self.get_bak_dir() + "/" + archive_dir

  

-         result = subprocess.check_output([

-             prog,

-             'db2archive',

-             '-a', archive_dir,

-             '-D', self.get_config_dir()

-         ])

-         u_result = ensure_str(result)

+         try:

+             result = subprocess.check_output([

+                 prog,

+                 'db2archive',

+                 '-a', archive_dir,

+                 '-D', self.get_config_dir()

+             ], stderr=subprocess.STDOUT, encoding='utf-8')

+             u_result = ensure_str(result)

+         except subprocess.CalledProcessError as e:

+             self.log.debug("Command: {} failed with the return code {} and the error {}".format(

+                         format_cmd_list(cmd), e.returncode, e.output))

  

          self.log.debug("db2bak output: BEGIN")

          for line in u_result.split("\n"):
@@ -2937,7 +2966,6 @@ 

          cmd.append('-D')

          cmd.append(self.get_config_dir())

  

- 

          if bename:

              cmd.append('-n')

              cmd.append(bename)
@@ -2957,15 +2985,20 @@ 

              cmd.append('-T')

              cmd.append(vlvTag)

  

-         result = subprocess.check_output(cmd)

-         u_result = ensure_str(result)

+         try:

+             result = subprocess.check_output(cmd, stderr=subprocess.STDOUT, encoding='utf-8')

+             u_result = ensure_str(result)

+         except subprocess.CalledProcessError as e:

+             self.log.debug("Command: {} failed with the return code {} and the error {}".format(

+                            format_cmd_list(cmd), e.returncode, e.output))

+             return False

  

          self.log.debug("db2index output: BEGIN")

          for line in u_result.split("\n"):

              self.log.debug(line)

          self.log.debug("db2index output: END")

  

-         return result

+         return True

  

      def dbscan(self, bename=None, index=None, key=None, width=None, isRaw=False):

          """Wrapper around dbscan tool that analyzes and extracts information

@@ -17,6 +17,7 @@ 

  

  MAJOR, MINOR, _, _, _ = sys.version_info

  

+ 

  # REALLY PYTHON 3? REALLY???

  def _input(msg):

      if MAJOR >= 3:
@@ -43,6 +44,7 @@ 

          else:

              return _input("%s : " % msg)

  

+ 

  def _get_args(args, kws):

      kwargs = {}

      while len(kws) > 0:
@@ -57,6 +59,7 @@ 

                  kwargs[kw] = _input("%s : " % msg)

      return kwargs

  

+ 

  # This is really similar to get_args, but generates from an array

  def _get_attributes(args, attrs):

      kwargs = {}
@@ -81,6 +84,7 @@ 

          raise Exception("Not sure if want")

      return data

  

+ 

  # We'll need another of these that does a "connect via instance name?"

  def connect_instance(dsrc_inst, verbose):

      dsargs = dsrc_inst['args']
@@ -99,14 +103,17 @@ 

              starttls=dsrc_inst['starttls'], connOnly=True)

      return ds

  

+ 

  def disconnect_instance(inst):

      if inst is not None:

          inst.close()

  

+ 

  def populate_attr_arguments(parser, attributes):

      for attr in attributes:

          parser.add_argument('--%s' % attr, nargs='?', help="Value of %s" % attr)

  

+ 

  def _generic_list(inst, basedn, log, manager_class, args=None):

      mc = manager_class(inst, basedn)

      ol = mc.list()
@@ -128,30 +135,33 @@ 

          if args and args.json:

              print(json.dumps(json_result))

  

+ 

  # Display these entries better!

  def _generic_get(inst, basedn, log, manager_class, selector, args=None):

      mc = manager_class(inst, basedn)

      if args and args.json:

           o = mc.get(selector, json=True)

-          print(o);

+          print(o)

      else:

          o = mc.get(selector)

          o_str = o.display()

          log.info(o_str)

  

+ 

  def _generic_get_dn(inst, basedn, log, manager_class, dn, args=None):

      mc = manager_class(inst, basedn)

      o = mc.get(dn=dn)

      o_str = o.display()

      log.info(o_str)

  

+ 

  def _generic_create(inst, basedn, log, manager_class, kwargs, args=None):

      mc = manager_class(inst, basedn)

      o = mc.create(properties=kwargs)

      o_str = o.__unicode__()

- 

      log.info('Successfully created %s' % o_str)

  

+ 

  def _generic_delete(inst, basedn, log, object_class, dn, args=None):

      # Load the oc direct

      o = object_class(inst, dn)
@@ -190,6 +200,7 @@ 

      def flush(self):

          self.outputs = []

  

+ 

  class FakeArgs(object):

      def __init__(self):

          pass
@@ -207,6 +218,7 @@ 

      logging.Formatter('%(levelname)s: %(message)s')

  )

  

+ 

  def reset_get_logger(name, verbose=False):

      """Reset the python logging system for STDOUT, and attach a new

      console logger with cli expected formatting.

@@ -7,8 +7,6 @@ 

  # --- END COPYRIGHT BLOCK ---

  

  from lib389.backend import Backend, Backends

- import argparse

- 

  from lib389.cli_base import (

      populate_attr_arguments,

      _generic_list,
@@ -26,24 +24,28 @@ 

  MANY = Backends

  RDN = 'cn'

  

+ 

  def backend_list(inst, basedn, log, args):

      _generic_list(inst, basedn, log.getChild('backend_list'), MANY, args)

  

+ 

  def backend_get(inst, basedn, log, args):

-     rdn = _get_arg( args.selector, msg="Enter %s to retrieve" % RDN)

+     rdn = _get_arg(args.selector, msg="Enter %s to retrieve" % RDN)

      _generic_get(inst, basedn, log.getChild('backend_get'), MANY, rdn, args)

  

+ 

  def backend_get_dn(inst, basedn, log, args):

-     dn = _get_arg( args.dn, msg="Enter dn to retrieve")

+     dn = _get_arg(args.dn, msg="Enter dn to retrieve")

      _generic_get_dn(inst, basedn, log.getChild('backend_get_dn'), MANY, dn, args)

  

+ 

  def backend_create(inst, basedn, log, args):

-     args.json = True

      kwargs = _get_attributes(args, Backend._must_attributes)

      _generic_create(inst, basedn, log.getChild('backend_create'), MANY, kwargs, args)

  

+ 

  def backend_delete(inst, basedn, log, args, warn=True):

-     dn = _get_arg( args.dn, msg="Enter dn to delete")

+     dn = _get_arg(args.dn, msg="Enter dn to delete")

      if warn:

          _warn(dn, msg="Deleting %s %s" % (SINGULAR.__name__, dn))

      _generic_delete(inst, basedn, log.getChild('backend_delete'), SINGULAR, dn, args)

@@ -7,19 +7,17 @@ 

  # --- END COPYRIGHT BLOCK ---

  

  from lib389.idm.directorymanager import DirectoryManager

- 

  from lib389.cli_base import _get_arg

  

- import argparse

  

  def password_change(inst, basedn, log, args):

      # Due to an issue, we can't use extended op, so we have to

      # submit the password directly to the field.

- 

      password = _get_arg(args.password, msg="Enter new directory manager password", hidden=True, confirm=True)

      dm = DirectoryManager(inst)

      dm.change_password(password)

  

+ 

  def create_parsers(subparsers):

      directory_manager_parser = subparsers.add_parser('directory_manager', help="Manage the directory manager account")

  

@@ -6,8 +6,6 @@ 

  # See LICENSE for details.

  # --- END COPYRIGHT BLOCK ---

  

- import argparse

- 

  from lib389.backend import Backend, Backends

  from lib389.config import Encryption, Config

  from lib389 import plugins
@@ -24,6 +22,7 @@ 

      plugins.ReferentialIntegrityPlugin

  ]

  

+ 

  def _format_check_output(log, result):

      log.info("==== DS Lint Error: %s ====" % result['dsle'])

      log.info(" Severity: %s " % result['severity'])
@@ -35,6 +34,7 @@ 

      log.info(" Resolution:")

      log.info(result['fix'])

  

+ 

  def health_check_run(inst, basedn, log, args):

      log.info("Beginning lint report, this could take a while ...")

      report = []
@@ -55,6 +55,7 @@ 

      for item in report:

          _format_check_output(log, item)

  

+ 

  def create_parser(subparsers):

      run_healthcheck_parser = subparsers.add_parser('healthcheck', help="Run a healthcheck report on your Directory Server instance. This is a safe, read only operation.")

      run_healthcheck_parser.set_defaults(func=health_check_run)

@@ -7,8 +7,6 @@ 

  # --- END COPYRIGHT BLOCK ---

  

  from lib389.plugins import Plugin, Plugins

- import argparse

- 

  from lib389.cli_base import (

      _generic_list,

      _generic_get,
@@ -29,26 +27,30 @@ 

  def plugin_list(inst, basedn, log, args):

      _generic_list(inst, basedn, log.getChild('plugin_list'), MANY, args)

  

+ 

  def plugin_get(inst, basedn, log, args):

-     rdn = _get_arg( args.selector, msg="Enter %s to retrieve" % RDN)

+     rdn = _get_arg(args.selector, msg="Enter %s to retrieve" % RDN)

      _generic_get(inst, basedn, log.getChild('plugin_get'), MANY, rdn, args)

  

+ 

  def plugin_get_dn(inst, basedn, log, args):

-     dn = _get_arg( args.dn, msg="Enter dn to retrieve")

+     dn = _get_arg(args.dn, msg="Enter dn to retrieve")

      _generic_get_dn(inst, basedn, log.getChild('plugin_get_dn'), MANY, dn, args)

  

+ 

  # Plugin enable

  def plugin_enable(inst, basedn, log, args):

-     dn = _get_arg( args.dn, msg="Enter plugin dn to enable")

+     dn = _get_arg(args.dn, msg="Enter plugin dn to enable")

      mc = MANY(inst, basedn)

      o = mc.get(dn=dn)

      o.enable()

      o_str = o.display()

      log.info('Enabled %s', o_str)

  

+ 

  # Plugin disable

  def plugin_disable(inst, basedn, log, args, warn=True):

-     dn = _get_arg( args.dn, msg="Enter plugin dn to disable")

+     dn = _get_arg(args.dn, msg="Enter plugin dn to disable")

      if warn:

          _warn(dn, msg="Disabling %s %s" % (SINGULAR.__name__, dn))

      mc = MANY(inst, basedn)
@@ -57,32 +59,38 @@ 

      o_str = o.display()

      log.info('Disabled %s', o_str)

  

+ 

  # Plugin configure?

  def plugin_configure(inst, basedn, log, args):

      pass

  

+ 

  def generic_show(inst, basedn, log, args):

      """Display plugin configuration."""

      plugin = args.plugin_cls(inst)

      log.info(plugin.display())

  

+ 

  def generic_enable(inst, basedn, log, args):

      plugin = args.plugin_cls(inst)

      plugin.enable()

      log.info("Enabled %s", plugin.rdn)

  

+ 

  def generic_disable(inst, basedn, log, args):

      plugin = args.plugin_cls(inst)

      plugin.disable()

      log.info("Disabled %s", plugin.rdn)

  

+ 

  def generic_status(inst, basedn, log, args):

      plugin = args.plugin_cls(inst)

-     if plugin.status() == True:

+     if plugin.status() is True:

          log.info("%s is enabled", plugin.rdn)

      else:

          log.info("%s is disabled", plugin.rdn)

  

+ 

  def add_generic_plugin_parsers(subparser, plugin_cls):

      show_parser = subparser.add_parser('show', help='display plugin configuration')

      show_parser.set_defaults(func=generic_show, plugin_cls=plugin_cls)

@@ -6,26 +6,50 @@ 

  # See LICENSE for details.

  # --- END COPYRIGHT BLOCK ---

  

+ 

  def dbtasks_db2index(inst, log, args):

-     inst.db2index(bename=args.backend)

+     if not inst.db2index(bename=args.backend):

+         log.fatal("db2index failed")

+         return False

+     else:

+         log.info("db2index successful")

+ 

  

  def dbtasks_db2bak(inst, log, args):

      # Needs an output name?

-     inst.db2bak(args.archive)

-     log.info("db2bak successful")

+     if not inst.db2bak(args.archive):

+         log.fatal("db2bak failed")

+         return False

+     else:

+         log.info("db2bak successful")

+ 

  

  def dbtasks_bak2db(inst, log, args):

      # Needs the archive to restore.

-     inst.bak2db(args.archive)

-     log.info("bak2db successful")

+     if not inst.bak2db(args.archive):

+         log.fatal("bak2db failed")

+         return False

+     else:

+         log.info("bak2db successful")

+ 

  

  def dbtasks_db2ldif(inst, log, args):

-     inst.db2ldif(bename=args.backend, encrypt=args.encrypted, repl_data=args.replication, outputfile=args.ldif, suffixes=None, excludeSuffixes=None)

-     log.info("db2ldif successful")

+     if not inst.db2ldif(bename=args.backend, encrypt=args.encrypted, repl_data=args.replication,

+                         outputfile=args.ldif, suffixes=None, excludeSuffixes=None):

+         log.fatal("db2ldif failed")

+         return False

+     else:

+         log.info("db2ldif successful")

+ 

  

  def dbtasks_ldif2db(inst, log, args):

-     inst.ldif2db(bename=args.backend, encrypt=args.encrypted, import_file=args.ldif, suffixes=None, excludeSuffixes=None)

-     log.info("ldif2db successful")

+     if not inst.ldif2db(bename=args.backend, encrypt=args.encrypted, import_file=args.ldif,

+                         suffixes=None, excludeSuffixes=None):

+         log.fatal("ldif2db failed")

+         return False

+     else:

+         log.info("ldif2db successful")

+ 

  

  def create_parser(subcommands):

      db2index_parser = subcommands.add_parser('db2index', help="Initialise a reindex of the server database. The server must be stopped for this to proceed.")
@@ -34,13 +58,15 @@ 

      db2index_parser.set_defaults(func=dbtasks_db2index)

  

      db2bak_parser = subcommands.add_parser('db2bak', help="Initialise a BDB backup of the database. The server must be stopped for this to proceed.")

-     db2bak_parser.add_argument('archive', help="The destination for the archive. This will be created during the db2bak process.")

+     db2bak_parser.add_argument('archive', help="The destination for the archive. This will be created during the db2bak process.",

+                                nargs='?', default=None)

      db2bak_parser.set_defaults(func=dbtasks_db2bak)

  

      db2ldif_parser = subcommands.add_parser('db2ldif', help="Initialise an LDIF dump of the database. The server must be stopped for this to proceed.")

      db2ldif_parser.add_argument('backend', help="The backend to output as an LDIF. IE userRoot")

-     db2ldif_parser.add_argument('ldif', help="The path to the ldif output location.")

-     db2ldif_parser.add_argument('--replication', help="Export replication information, suitable for importing on a new consumer or backups.", default=False, action='store_true')

+     db2ldif_parser.add_argument('ldif', help="The path to the ldif output location.", nargs='?', default=None)

+     db2ldif_parser.add_argument('--replication', help="Export replication information, suitable for importing on a new consumer or backups.",

+                                 default=False, action='store_true')

      db2ldif_parser.add_argument('--encrypted', help="Export encrypted attributes", default=False, action='store_true')

      db2ldif_parser.set_defaults(func=dbtasks_db2ldif)

  

@@ -18,6 +18,7 @@ 

  

  from lib389.instance.options import General2Base, Slapd2Base

  

+ 

  def instance_list(inst, log, args):

      instances = inst.list(all=True)

  
@@ -31,26 +32,31 @@ 

          log.info(e)

          log.info("Perhaps you need to be a different user?")

  

+ 

  def instance_restart(inst, log, args):

      inst.restart(post_open=False)

  

+ 

  def instance_start(inst, log, args):

      inst.start(post_open=False)

  

+ 

  def instance_stop(inst, log, args):

      inst.stop()

  

+ 

  def instance_status(inst, log, args):

      if inst.status() is True:

          log.info("Instance is running")

      else:

          log.info("Instance is not running")

  

+ 

  def instance_create(inst, log, args):

      if args.containerised:

          log.debug("Containerised features requested.")

      sd = SetupDs(args.verbose, args.dryrun, log, args.containerised)

-     ### If args.file is not set, we need to interactively get answers!

+     ### TODO - If args.file is not set, we need to interactively get answers!

      if sd.create_from_inf(args.file):

          # print("Sucessfully created instance")

          return True
@@ -58,6 +64,7 @@ 

          # print("Failed to create instance")

          return False

  

+ 

  def instance_example(inst, log, args):

      print("""

  ; --- BEGIN COPYRIGHT BLOCK ---
@@ -85,22 +92,28 @@ 

      s2b = Slapd2Base(log)

      print(g2b.collect_help())

      print(s2b.collect_help())

+     return True

+ 

  

  def instance_remove(inst, log, args):

      if not args.ack:

          log.info("""Not removing: if you are sure, add --doit""")

-         sys.exit(0)

+         return True

      else:

          log.info("""

  About to remove instance %s!

  If this is not what you want, press ctrl-c now ...

          """ % inst.serverid)

-     for i in range(1,6):

+     for i in range(1, 6):

          log.info('%s ...' % (5 - int(i)))

          time.sleep(1)

      log.info('Removing instance ...')

-     remove_ds_instance(inst)

-     log.info('Completed instance removal')

+     try:

+         remove_ds_instance(inst)

+         log.info('Completed instance removal')

+     except:

+         log.fatal('Instance removal failed')

+         return False

  

  

  def create_parser(subcommands):
@@ -121,7 +134,8 @@ 

      status_parser.set_defaults(func=instance_status)

  

      remove_parser = subcommands.add_parser('remove', help="Destroy an instance of Directory Server, and remove all data.")

-     remove_parser.add_argument('--doit', dest="ack", help="By default we do a dry run. This actually initiates the removal.", action='store_true', default=False)

+     remove_parser.add_argument('--doit', dest="ack", help="By default we do a dry run. This actually initiates the removal.",

+                                action='store_true', default=False)

      remove_parser.set_defaults(func=instance_remove)

  

  

@@ -89,7 +89,7 @@ 

      mc = manager_class(inst, basedn)

      if args and args.json:

          o = mc.get(selector, json=True)

-         print(o);

+         print(o)

      else:

          o = mc.get(selector)

          o_str = o.display()

@@ -42,18 +42,20 @@ 

  

  ds_paths = Paths()

  

+ 

  class Options2(object):

      # This stores the base options in a self._options dict.

      # It provides a number of options for:

      # - dict overlay

      # - parsing the config parser types.

+ 

      def __init__(self, log):

          # 'key' : (default, helptext, valid_func )

-         self._options = {} # this takes the default

-         self._type = {} # Lists the type the item should be.

-         self._helptext = {} # help text for the option, MANDATORY.

-         self._example_comment = {} # If this is a commented value in the example.

-         self._valid_func = {} # options verification function.

+         self._options = {}  # this takes the default

+         self._type = {}  # Lists the type the item should be.

+         self._helptext = {}  # help text for the option, MANDATORY.

+         self._example_comment = {}  # If this is a commented value in the example.

+         self._valid_func = {}  # options verification function.

          self._section = None

          self.log = log

  
@@ -102,6 +104,7 @@ 

  # Base, example dicts of the general, backend (userRoot) options.

  #

  

+ 

  class General2Base(Options2):

      def __init__(self, log):

          super(General2Base, self).__init__(log)
@@ -139,9 +142,10 @@ 

  

  #

  # This module contains the base options and configs for Director Server

- # setup and install. This allows 

+ # setup and install. This allows

  #

  

+ 

  class Slapd2Base(Options2):

      def __init__(self, log):

          super(Slapd2Base, self).__init__(log)

@@ -10,6 +10,7 @@ 

  import shutil

  import subprocess

  

+ 

  def remove_ds_instance(dirsrv):

      """

      This will delete the instance as it is define. This must be a local instance.

Description: I've also included the work for 49775 in this patch since
there was a lot of overldap.

          For dsctl functions we need to check for True and False in
          order to detect an error.  For dsconf & dsidm we need to
          catch exceptions.  Once an error is detected we return error
          code (1).

          The changes for 49775 was to use the default archive directory
          if one was not specified to db2bak, and use the default ldif
          location for db2ldif.  This how the old tools worked, no
          reason not to carry over this convenience.  Also the format
          used for the file name (Instance name + Date/Time) is the same
          as the old cli tools.

          Also did some pep8 cleanup.

https://pagure.io/389-ds-base/issue/49712

rebased onto e407dc250aca10d91ab9e415eddb45cd4a5c1777

5 years ago

If I understand correctly, by documentation, return_value = PR_Rename(directory, dir_bak); returns either PR_SUCCESS (0), either PR_FAILURE (-1). So the line you've added seems redundant to me... Or do I miss something?

I think we should print the error to debug so we don't lose the information.
You can rewrite the thing like this:

try:
    result = subprocess.check_output(cmd, stderr=subprocess.STDOUT, encoding='utf-8')
except subprocess.CalledProcessError as e:
    self.log.debug("Command: {} failed with the return code {} and the error {}".format(format_cmd_list(cmd), e.returncode, e.output))
    return False

Its MKDIR not PR_RENAME, and yes it is needed or else it silently fails.

rebased onto e6a061e93b44c2f46aea28b21aefce5f17d712a5

5 years ago

I've tested the change and it works. Beside the small thing we discussed (debugging output for other subprocess.check_output changes - the same way as the first one), LGTM! Ack.

rebased onto 5226bf9

5 years ago

Pull-Request has been merged by mreynolds

5 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/2835

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago