samba-tool processes: display pre-fork masters and workers
authorGary Lockyer <gary@catalyst.net.nz>
Thu, 13 Sep 2018 21:38:56 +0000 (09:38 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 23 Nov 2018 07:25:20 +0000 (08:25 +0100)
Tag prefork work processes with "(worker 0)", and sort the process list
on server name to get a consistent order.

 Service:                          PID
 --------------------------------------
 cldap_server                     15588
 ...
 ldap_server                      15584
 ldap_server(worker 0)            15627
 ldap_server(worker 1)            15630
 ldap_server(worker 2)            15632
 ldap_server(worker 3)            15634
 nbt_server                       15576
 notify-daemon                    15638
 ...
 samba                                0
 ...
 wrepl_server                     15580

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/netcmd/processes.py

index d04a548abd78268913ca6c4cf0913df70034a712..0406b1859ca2f5f36a661de93b33b433f393115d 100644 (file)
@@ -49,6 +49,42 @@ class cmd_processes(Command):
 
     takes_args = []
 
+    #
+    # Get details of the samba services currently registered in irpc
+    # The prefork process model registers names in the form:
+    #     prefork-master-<service> and prefork-worker-<service>-<instance>
+    #
+    # To allow this routine to identify pre-fork master and worker process
+    #
+    # returns a tuple (filtered, masters, workers)
+    #
+    #  filtered - is a list of services with the prefork-* removed
+    #  masters  - dictionary keyed on service name of prefork master processes
+    #  workers  - dictionary keyed on service name containing an ordered list
+    #             of worker processes.
+    def get_service_data(self, msg_ctx):
+        services = msg_ctx.irpc_all_servers()
+        filtered = []
+        masters = {}
+        workers = {}
+        for service in services:
+            for id in service.ids:
+                if service.name.startswith("prefork-master"):
+                    ns = service.name.split("-")
+                    name = ns[2] + "_server"
+                    masters[name] = service.ids[0].pid
+                elif service.name.startswith("prefork-worker"):
+                    ns = service.name.split("-")
+                    name = ns[2] + "_server"
+                    instance = int(ns[3])
+                    pid = service.ids[0].pid
+                    if name not in workers:
+                        workers[name] = {}
+                    workers[name][instance] = (instance, pid)
+                else:
+                    filtered.append(service)
+        return (filtered, masters, workers)
+
     def run(self, sambaopts, versionopts, section_name=None,
             name=None, pid=None):
 
@@ -72,9 +108,36 @@ class cmd_processes(Command):
                     if server_id.pid == int(pid):
                         self.outf.write("%s\n" % name.name)
         else:
-            names = msg_ctx.irpc_all_servers()
-            self.outf.write(" Service:                PID \n")
-            self.outf.write("-----------------------------\n")
-            for name in names:
-                for server_id in name.ids:
-                    self.outf.write("%-16s      %6d\n" % (name.name, server_id.pid))
+            seen = {}     # Service entries already printed, service names can
+            #               be registered multiple times against a process
+            #               but we should only display them once.
+            prefork = {}  # Services running in the prefork process model
+            #               want to ensure that the master process and workers
+            #               are grouped to together.
+            (services, masters, workers) = self.get_service_data(msg_ctx)
+            self.outf.write(" Service:                          PID\n")
+            self.outf.write("--------------------------------------\n")
+
+            for service in sorted(services, key=lambda x: x.name):
+                if service.name in masters:
+                    # If this service is running in a pre-forked process we
+                    # want to print the master process followed by all the
+                    # worker processes
+                    pid = masters[service.name]
+                    if pid not in prefork:
+                        prefork[pid] = True
+                        self.outf.write("%-26s      %6d\n" %
+                            (service.name, pid))
+                        if service.name in workers:
+                            ws = workers[service.name]
+                            for w in ws:
+                                (instance, pid) = ws[w]
+                                sn = "{0}(worker {1})".format(
+                                    service.name, instance)
+                                self.outf.write("%-26s      %6d\n" % (sn, pid))
+                else:
+                    for server_id in service.ids:
+                        if (service.name, server_id.pid) not in seen:
+                            self.outf.write("%-26s      %6d\n"
+                                % (service.name, server_id.pid))
+                            seen[(service.name, server_id.pid)] = True