File: ps.py

package info (click to toggle)
zeekctl 2.2.0%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,544 kB
  • sloc: python: 5,639; sh: 1,374; makefile: 71; awk: 24
file content (113 lines) | stat: -rw-r--r-- 3,524 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#
# A simple example plugin implementing a command "ps.zeek" that shows all Zeek
# processes currently running on any of the configured nodes, including  those
# not controlled by this zeekctl. The latter are marked with "(-)", while "our"
# processes get a "(+)".

import ZeekControl.plugin
import ZeekControl.cmdresult

class PsZeek(ZeekControl.plugin.Plugin):
    def __init__(self):
        super(PsZeek, self).__init__(apiversion=1)

    def name(self):
        return "ps"

    def pluginVersion(self):
        return 1

    def commands(self):
        return [
            ("zeek", "[<nodes>]", "Show Zeek processes on nodes' systems"),
        ]

    def cmd_custom(self, cmd, args, cmdout):
        results = ZeekControl.cmdresult.CmdResult()

        assert(cmd == "zeek") # Can't be anything else.

        # Get the nodes the user wants.
        if args:
            nodes, notnodes = self.parseNodes(args)
            for n in notnodes:
                cmdout.error("unknown node '%s'" % n)
        else:
            nodes = self.nodes()

        if not nodes:
            cmdout.error("No nodes given.")
            results.ok = False
            return results

        # Get one node for every host running at least one of the nodes. Also
        # records each hosts Zeek PIDs.
        host_nodes = {}
        pids = {}

        for n in nodes:
            pid = n.getPID()
            if pid:
                p = pids.setdefault(n.host, set())
                p.add(pid)

            host_nodes[n.host] = n

        # Build commands to execute.

        # The grep command grabs the header line and all lines ending in "zeek"
        # (and ignores "run-zeek" that may appear in the output of ps).
        cmd = "POSIXLY_CORRECT=1 ps axco user,pid,ppid,%cpu,%mem,vsz,rss,tt,state,start,time,command | grep -e PID -e '[^-]zeek$'"
        cmds = [(n, cmd) for n in host_nodes.values()]
        cmds.sort(key=lambda n: n[0].name)

        # Run them in parallel and print output.

        first_node = True

        for (n, success, output) in self.executeParallel(cmds):
            outlines = output.splitlines()
            # Remove stderr output (if any)
            while outlines and not outlines[0].startswith("USER"):
                outlines = outlines[1:]

            # Print the header line.
            if first_node and outlines:
                cmdout.info("        %s" % outlines[0])

            if success:
                cmdout.info(">>> %s" % n.host)
            else:
                cmdout.error(">>> %s failed" % n.host)
                results.ok = False

            if not outlines:
                continue

            for line in outlines[1:]:

                m = line.split()
                try:
                    pid, ppid = int(m[1]), int(m[2])
                except IndexError:
                    cmdout.error("unexpected output from ps command: %s" % line)
                    results.ok = False
                    continue
                except ValueError as err:
                    cmdout.error("%s" % err)
                    results.ok = False
                    continue
                try:
                    known = (pid in pids[n.host] or ppid in pids[n.host])
                except KeyError:
                    known = False

                if known:
                    cmdout.info("   (+) %s" % line.strip())
                else:
                    cmdout.info("   (-) %s" % line.strip())

            first_node = False

        return results