Browse Source

Ticket 50022, 50012, 49956, and 49800: Various dsctl/dscreate fixes

Description:

Fix 50022 - Confusing command line switches for dscreate and dsctl
Fix 50012 - Add option to dsctl to remove all instances
Fix 49956 - dsctl: add an option to list all available instances
Fix 49800 - Debug messages "OK user/group dirsrv exists" are emitted when lib389 cli tools are used

https://pagure.io/389-ds-base/issue/50022
https://pagure.io/389-ds-base/issue/50012
https://pagure.io/389-ds-base/issue/49956
https://pagure.io/389-ds-base/issue/49800

Reviewed by: spichugi(Thanks!)
Mark Reynolds 7 years ago
parent
commit
4fd73c5d9a

+ 1 - 1
docker/389ds_poc/Dockerfile

@@ -33,7 +33,7 @@ RUN dnf install -y 389-ds-base/dist/rpms/*389*.rpm && \
 
 # Create the example setup inf. It's valid for containers!
 # Build the instance from the new installer tools.
-RUN /usr/sbin/dscreate create-template > /root/ds-setup.inf && /usr/sbin/dscreate -v fromfile /root/ds-setup.inf --containerised
+RUN /usr/sbin/dscreate create-template > /root/ds-setup.inf && /usr/sbin/dscreate -v from-file /root/ds-setup.inf --containerised
 
 # Finally add the volumes, they will inherit the contents of these directories.
 VOLUME /etc/dirsrv

+ 2 - 2
src/cockpit/389-console/src/servers.js

@@ -1405,7 +1405,7 @@ $(document).ready( function() {
     $("#remove-server-btn").on("click", function () {
       popup_confirm("Are you sure you want to this remove instance: <b>" + server_id + "</b>", "Confirmation", function (yes) {
         if (yes) {
-          var cmd = [DSCTL, server_id, "remove", "--doit"];
+          var cmd = [DSCTL, server_id, "remove", "--do-it"];
           $("#ds-remove-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Removing instance <b>" + server_id + "</b>...");
           $("#remove-instance-form").modal('toggle');
           log_cmd('#remove-server-btn (click)', 'Remove instance', cmd);
@@ -1581,7 +1581,7 @@ $(document).ready( function() {
               /*
                * Next, create the instance...
                */
-              cmd = [DSCREATE, 'fromfile', setup_file];
+              cmd = [DSCREATE, 'from-file', setup_file];
               cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV] }).fail(function(ex) {
                 // Failed to create the new instance!
                 cockpit.spawn(rm_cmd, { superuser: true });  // Remove Inf file with clear text password

+ 1 - 1
src/lib389/cli/dscreate

@@ -24,7 +24,7 @@ parser.add_argument('-v', '--verbose',
                     action='store_true', default=False, dest='verbose')
 subparsers = parser.add_subparsers(help="action")
 
-fromfile_parser = subparsers.add_parser('fromfile', help="Create an instance of Directory Server from an inf answer file")
+fromfile_parser = subparsers.add_parser('from-file', 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 create-template'")
 fromfile_parser.add_argument('-n', '--dryrun', help="Validate system and configurations only. Do not alter the system.",
                              action='store_true', default=False)

+ 25 - 2
src/lib389/cli/dsctl

@@ -14,24 +14,35 @@ import argparse, argcomplete
 import logging
 import sys
 import signal
+from lib389.utils import get_instance_list
 from lib389.cli_base import _get_arg
 from lib389 import DirSrv
 from lib389.cli_ctl import instance as cli_instance
 from lib389.cli_ctl import dbtasks as cli_dbtasks
 from lib389.cli_base import disconnect_instance, setup_script_logger
+from lib389.cli_ctl.instance import instance_remove_all
 
 parser = argparse.ArgumentParser()
 parser.add_argument('-v', '--verbose',
         help="Display verbose operation tracing during command execution",
         action='store_true', default=False
     )
-parser.add_argument('instance',
+parser.add_argument('instance', nargs='?', default=False,
         help="The name of the instance to act upon",
     )
 parser.add_argument('-j', '--json',
         help="Return result in JSON object",
         default=False, action='store_true'
     )
+parser.add_argument('-l', '--list',
+        help="List available Directory Server instances",
+        default=False, action='store_true'
+    )
+
+parser.add_argument('--remove-all', nargs="?", default=False, const=None,
+        help="Remove all instances of Directory Server (you can also provide an optional directory prefix for this argument)",
+    )
+
 subparsers = parser.add_subparsers(help="action")
 cli_instance.create_parser(subparsers)
 cli_dbtasks.create_parser(subparsers)
@@ -56,6 +67,19 @@ if __name__ == '__main__':
 
     log.debug("Called with: %s", args)
 
+    if args.list:
+        insts = get_instance_list()
+        for inst in insts:
+            print(inst)
+        sys.exit(0)
+    elif args.remove_all is not False:
+        instance_remove_all(log, args)
+        sys.exit(0)
+    elif not args.instance:
+        log.error("error: the following arguments are required: instance")
+        parser.print_help()
+        sys.exit(1)
+
     # Assert we have a resources to work on.
     if not hasattr(args, 'func'):
         log.error("No action provided, here is some --help.")
@@ -63,7 +87,6 @@ if __name__ == '__main__':
         sys.exit(1)
 
     # Connect
-    # inst = None
     inst = DirSrv(verbose=args.verbose)
 
     result = True

+ 6 - 6
src/lib389/lib389/__init__.py

@@ -1192,7 +1192,7 @@ class DirSrv(SimpleLDAPObject, object):
 
             @return None
 
-            @raise None
+            @raise ValueError
         '''
 
         if self.status() is True:
@@ -1230,7 +1230,7 @@ class DirSrv(SimpleLDAPObject, object):
                 time.sleep(1)
                 pid = pid_from_file(self.ds_paths.pid_file)
             if pid == 0 or pid is None:
-                raise ValueError
+                raise ValueError('Failed to start DS')
             # Wait
             while not pid_exists(pid) and count > 0:
                 # It looks like DS changes the value in here at some point ...
@@ -1240,7 +1240,7 @@ class DirSrv(SimpleLDAPObject, object):
                 time.sleep(1)
                 count -= 1
             if not pid_exists(pid):
-                raise Exception("Failed to start DS")
+                raise ValueError("Failed to start DS")
         if post_open:
             self.open()
 
@@ -1254,7 +1254,7 @@ class DirSrv(SimpleLDAPObject, object):
 
             @return None
 
-            @raise None
+            @raise ValueError
         '''
         if self.status() is False:
             return
@@ -1270,7 +1270,7 @@ class DirSrv(SimpleLDAPObject, object):
             count = timeout
             pid = pid_from_file(self.ds_paths.pid_file)
             if pid == 0 or pid is None:
-                raise ValueError
+                raise ValueError("Failed to stop DS")
             os.kill(pid, signal.SIGTERM)
             # Wait
             while pid_exists(pid) and count > 0:
@@ -1328,7 +1328,7 @@ class DirSrv(SimpleLDAPObject, object):
 
             @return None
 
-            @raise None
+            @raise ValueError
         '''
         self.stop(timeout)
         time.sleep(1)

+ 51 - 16
src/lib389/lib389/cli_ctl/instance.py

@@ -8,8 +8,10 @@
 
 from lib389._constants import *
 
+from lib389 import DirSrv
 from lib389.tools import DirSrvTools
 from lib389.instance.setup import SetupDs
+from lib389.utils import get_instance_list
 from lib389.instance.remove import remove_ds_instance
 from getpass import getpass
 import os
@@ -35,21 +37,24 @@ def instance_list(inst, log, args):
 
 def instance_restart(inst, log, args):
     inst.restart(post_open=False)
+    log.info('Instance "{}" has been restarted'.format(inst.serverid))
 
 
 def instance_start(inst, log, args):
     inst.start(post_open=False)
+    log.info('Instance "{}" has been started'.format(inst.serverid))
 
 
 def instance_stop(inst, log, args):
     inst.stop()
+    log.info('Instance "{}" has been stopped'.format(inst.serverid))
 
 
 def instance_status(inst, log, args):
     if inst.status() is True:
-        log.info("Instance is running")
+        log.info('Instance "{}" is running'.format(inst.serverid))
     else:
-        log.info("Instance is not running")
+        log.info('Instance "{}" is not running'.format(inst.serverid))
 
 
 def instance_create_interactive(inst, log, args):
@@ -124,25 +129,54 @@ def instance_example(inst, log, args):
     return True
 
 
+def instance_remove_all(log, args):
+    """Remove all instances - clean sweep!
+    """
+
+    inst_names = get_instance_list(args.remove_all)
+    if len(inst_names) > 0:
+        answer = input("Are you sure you want to remove all the Directory Server instances? (Yes/no): ")
+        if answer != 'Yes':
+            print("Aborted removal of all instances")
+            return
+
+        # Do it!
+        list_inst = DirSrv(verbose=args.verbose)
+        insts = list_inst.list(all=True, serverid=inst_names[0])
+        for inst in insts:
+            remove_inst = DirSrv(verbose=args.verbose)
+            remove_inst.allocate(inst)
+            try:
+                log.info("Removing instance: slapd-" + str(remove_inst.serverid))
+                remove_ds_instance(remove_inst)
+            except Exception as e:
+                log.fatal('Failed to remove all instances: ' + str(e))
+                sys.exit(1)
+        log.info('All instances have been successfully removed')
+    else:
+        print("No instances to remove")
+
+
 def instance_remove(inst, log, args):
     if not args.ack:
-        log.info("""Not removing: if you are sure, add --doit""")
+        # Some day do some type of dry-run validation?
+        log.info("""Not removing: if you are sure, add --do-it""")
         return True
     else:
         log.info("""
-About to remove instance %s!
+About to remove instance (%s)!
 If this is not what you want, press ctrl-c now ...
         """ % inst.serverid)
-    for i in range(1, 6):
-        log.info('%s ...' % (5 - int(i)))
-        time.sleep(1)
-    log.info('Removing instance ...')
-    try:
-        remove_ds_instance(inst)
-        log.info('Completed instance removal')
-    except:
-        log.fatal('Instance removal failed')
-        return False
+        for i in range(1, 6):
+            log.info('%s ...' % (6 - int(i)))
+            time.sleep(1)
+        log.info('Removing instance ...')
+        try:
+            remove_ds_instance(inst)
+            log.info('Completed instance removal')
+        except:
+            log.fatal('Instance removal failed')
+            return False
 
 
 def create_parser(subcommands):
@@ -163,8 +197,9 @@ def create_parser(subcommands):
     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.set_defaults(func=instance_remove)
+    remove_parser.add_argument('--do-it', dest="ack", help="By default we do a dry run. This actually initiates the removal of the instance.",
+                               action='store_true', default=False)
+
 
 

+ 1 - 0
src/lib389/lib389/paths.py

@@ -86,6 +86,7 @@ CONFIG_MAP = {
 
 SECTION = 'slapd'
 
+
 class Paths(object):
     def __init__(self, serverid=None, instance=None):
         """

+ 4 - 4
src/lib389/lib389/tools.py

@@ -811,9 +811,9 @@ class DirSrvTools(object):
         """
         try:
             grp.getgrnam(group)
-            print("OK group %s exists" % group)
+            log.debug("OK group %s exists" % group)
         except KeyError:
-            print("Adding group %s" % group)
+            log.debug("Adding group %s" % group)
             cmd = [GROUPADD, '-r', group]
             subprocess.Popen(cmd)
 
@@ -824,9 +824,9 @@ class DirSrvTools(object):
         """
         try:
             pwd.getpwnam(user)
-            print("OK user %s exists" % user)
+            log.debug("OK user %s exists" % user)
         except KeyError:
-            print("Adding user %s" % user)
+            log.debug("Adding user %s" % user)
             cmd = [USERADD, '-g', group, '-c', DEFAULT_USER_COMMENT, '-r',
                    '-d', home, '-s', NOLOGIN, user]
             subprocess.Popen(cmd)

+ 16 - 0
src/lib389/lib389/utils.py

@@ -1110,3 +1110,19 @@ def get_ldapurl_from_serverid(instance):
     else:
         # Use LDAP
         return ("ldap://{}:{}".format(host, port), None)
+
+
+def get_instance_list(prefix=None):
+    # List all server instances
+    conf_dir = (prefix or "") + "/etc/dirsrv/"
+    insts = []
+    try:
+        for inst in os.listdir(conf_dir):
+            if inst.startswith('slapd-') and not inst.endswith('.removed'):
+                insts.append(inst)
+    except OSError as e:
+        log.error("Failed to check directory: {} - {}".format(conf_dir, str(e)))
+    insts.sort()
+    return insts
+
+