def execute_cmd(self, nodes, cmd): results = cmdresult.CmdResult() for node, success, out in self.executor.run_shell_cmds([(n, cmd) for n in nodes]): results.set_node_output(node, success, out) return results
def deploy(self): if not self.plugins.cmdPre("deploy"): results = cmdresult.CmdResult(ok=False) return results if self.config.is_cfg_changed(): self.ui.info("Reloading zeekctl configuration ...") self.reload_cfg() self.ui.info("checking configurations ...") results = self.check(check_node_types=True) if not results.ok: for (node, success, output) in results.get_node_output(): if not success: self.ui.info("%s scripts failed." % node) self.ui.info(output) return results self.ui.info("installing ...") results = self.install() if not results.ok: return results self.ui.info("stopping ...") results = self.stop() if not results.ok: return results self.ui.info("starting ...") results = self.start() self.plugins.cmdPost("deploy") return results
def cmd_custom(self, cmd, args, cmdout): args = args.split() results = cmdresult.CmdResult() results.ok = True if args == ['help']: self.message("Available checks:") #self.message("Using log directory {}".format(self.log_directory)) funcs = [f for f in dir(self) if f.startswith("check_")] for func in funcs: f = getattr(self, func) short_msg, long_msg = split_doc(f.__doc__) if args == ['help']: self.message(" * {}: {}".format( func, short_msg.replace("Checking", "Checks"))) continue if args and func not in args: continue self.message("#" * (len(short_msg) + 4)) self.message("# {} #".format(short_msg)) self.message("#" * (len(short_msg) + 4)) try: results.ok = f() and results.ok except Exception as e: results.ok = False self.error(traceback.format_exc()) self.message('') self.message('') return results
def install(self, local=False): if self.plugins.cmdPre("install"): results = self.controller.install(local) else: results = cmdresult.CmdResult(ok=False) self.plugins.cmdPost("install") return results
def _check_config(self, nodes, installed, list_scripts): results = cmdresult.CmdResult() nodetmpdirs = [(node, os.path.join(self.config.tmpdir, "check-config-%s" % node.name)) for node in nodes] nodes = [] for (node, cwd) in nodetmpdirs: if os.path.isdir(cwd): try: shutil.rmtree(cwd) except OSError as err: self.ui.error("cannot remove directory %s: %s" % (cwd, err)) results.ok = False return results try: os.makedirs(cwd) except OSError as err: self.ui.error("cannot create temporary directory: %s" % err) results.ok = False return results nodes += [(node, cwd)] cmds = [] for (node, cwd) in nodes: env = _make_env_params(node) installed_policies = "1" if installed else "0" print_scripts = "1" if list_scripts else "0" if not install.make_layout(cwd, self.ui, True): results.ok = False return results if not install.make_local_networks(cwd, self.ui): results.ok = False return results if not install.make_zeekctl_config_policy(cwd, self.ui, self.pluginregistry): results.ok = False return results cmd = os.path.join(self.config.scriptsdir, "check-config") + " %s %s %s %s" % (installed_policies, print_scripts, cwd, " ".join(_make_zeek_params(node, False))) cmd += " zeekctl/check" cmds += [((node, cwd), cmd, env, None)] for ((node, cwd), success, output) in execute.run_localcmds(cmds): results.set_node_output(node, success, output) try: shutil.rmtree(cwd) except OSError as err: # Don't bother reporting an error now. pass return results
def process(self, trace, options, scripts): if self.plugins.cmdPre("process", trace, options, scripts): results = self.controller.process(trace, options, scripts) else: results = cmdresult.CmdResult(ok=False) self.plugins.cmdPost("process", trace, options, scripts, results.ok) return results
def df(self, nodes): results = cmdresult.CmdResult() DiskInfo = namedtuple("DiskInfo", ("fs", "total", "used", "available", "percent")) dirs = ("logdir", "bindir", "helperdir", "cfgdir", "spooldir", "policydir", "libdir", "libdir64", "tmpdir", "staticdir", "scriptsdir") df = {} for node in nodes: df[node.name] = {} cmds = [] for node in nodes: for key in dirs: if key == "logdir" and not (node_mod.is_logger(node) or node_mod.is_manager(node) or node_mod.is_standalone(node)): # Don't need to check this on nodes that don't write logs. continue path = self.config.config[key] if key == "libdir" or key == "libdir64": if not os.path.exists(path): continue cmds += [(node, "df", [path])] for (node, success, output) in self.executor.run_helper(cmds): if success: fields = output.split() if len(fields) != 4: df[node.name]["FAIL"] = "wrong number of fields from df helper" continue fs = fields[0] # Ignore NFS mounted volumes. if not fs.startswith("/") and ":" in fs: continue try: total = float(fields[1]) used = float(fields[2]) avail = float(fields[3]) except ValueError as err: df[node.name]["FAIL"] = "bad output from df helper: %s" % err continue perc = used * 100.0 / (used + avail) df[node.name][fs] = DiskInfo(fs, total, used, avail, perc) else: df[node.name]["FAIL"] = output if output else "no output" for node in nodes: success = "FAIL" not in df[node.name] results.set_node_data(node, success, df[node.name]) return results
def get_config(self): results = cmdresult.CmdResult() if self.plugins.cmdPre("config"): results.keyval = self.config.options() else: results.ok = False self.plugins.cmdPost("config") return results
def execute(self, cmd): nodes = self.node_args(get_hosts=True) if self.plugins.cmdPre("exec", cmd): results = self.controller.execute_cmd(nodes, cmd) else: results = cmdresult.CmdResult(ok=False) self.plugins.cmdPost("exec", cmd) return results
def nodes(self): results = cmdresult.CmdResult() if self.plugins.cmdPre("nodes"): for n in self.config.nodes(): results.set_node_data(n, True, n.to_dict()) else: results.ok = False self.plugins.cmdPost("nodes") return results
def process(self, trace, zeek_options, zeek_scripts): results = cmdresult.CmdResult() if not os.path.isfile(trace): self.ui.error("trace file not found: %s" % trace) results.ok = False return results if self.config.standalone: node = self.config.nodes()[0] else: node = self.config.workers()[0] cwd = os.path.join(self.config.tmpdir, "testing") if os.path.isdir(cwd): try: shutil.rmtree(cwd) except OSError as err: self.ui.error("cannot remove directory: %s" % err) results.ok = False return results try: os.makedirs(cwd) except OSError as err: self.ui.error("cannot create directory: %s" % err) results.ok = False return results env = _make_env_params(node) zeek_args = " ".join(zeek_options + _make_zeek_params(node, False)) zeek_args += " zeekctl/process-trace" if zeek_scripts: zeek_args += " " + " ".join(zeek_scripts) cmd = os.path.join(self.config.scriptsdir, "run-zeek-on-trace") + " %s %s %s %s" % (0, cwd, trace, zeek_args) self.ui.info(cmd) success, output = execute.run_localcmd(cmd, env=env) if not success: results.ok = False self.ui.info(output) self.ui.info("### Zeek output in %s" % cwd) return results
def runCustomCommand(self, cmd, args, cmdout): """Runs a custom command *cmd* with string *args* as argument. Returns a CmdResult object which contains the command results.""" try: myplugin, usage, descr = self._cmds[cmd] except LookupError: return cmdresult.CmdResult(ok=False, unknowncmd=True) prefix = myplugin.prefix() if cmd.startswith("%s." % prefix): cmd = cmd[len(prefix) + 1:] return myplugin.cmd_custom(cmd, args, cmdout)
def diag(self, nodes): results = cmdresult.CmdResult() crashdiag = os.path.join(self.config.scriptsdir, "crash-diag") cmds = [(node, crashdiag, [node.cwd()]) for node in nodes] for (node, success, output) in self.executor.run_cmds(cmds): if not success: errmsgs = "error running crash-diag for %s\n" % node.name errmsgs += output results.set_node_output(node, False, errmsgs) continue results.set_node_output(node, True, output) return results
def netstats(self, nodes): results = cmdresult.CmdResult() for (node, success, args) in self._query_netstats(nodes): if success: if args: out = args[0].strip() else: out = "" else: out = args results.set_node_output(node, success, out) if not results.nodes: results.set_node_output(nodes[0], False, "no running instances of Zeek") return results
def capstats(self, nodes, interval): results = cmdresult.CmdResult() if not self.config.capstatspath: results.set_node_data(nodes[0], False, {"output": 'Error: cannot run capstats because zeekctl option "capstatspath" is not defined'}) return results for (node, netif, success, vals) in self.get_capstats_output(nodes, interval): if not success: vals = {"output": vals} results.set_node_data(node, success, vals) if not results.nodes: results.ok = False return results
def cleanup(self, nodes, cleantmp=False): # Given a set of node names "orig" and command results "res", add # all node names to "orig" that have a failed result in "res". def addfailed(orig, res): for (node, status, output) in res: # if status is Fail, then add the node name if not status: orig.add(node.name) return orig results = cmdresult.CmdResult() result = self._isrunning(nodes) running = [node for (node, on) in result if on] notrunning = [node for (node, on) in result if not on] for node in running: self.ui.info(" %s is still running, not cleaning work directory" % node) results1 = self.executor.rmdirs([(n, n.cwd()) for n in notrunning]) results2 = self.executor.mkdirs([(n, n.cwd()) for n in notrunning]) failed = set() failed = addfailed(failed, results1) failed = addfailed(failed, results2) for node in notrunning: node.clearCrashed() if cleantmp: self.ui.info("cleaning %s ..." % self.config.tmpdir) results3 = self.executor.rmdirs([(n, self.config.tmpdir) for n in running + notrunning]) results4 = self.executor.mkdirs([(n, self.config.tmpdir) for n in running + notrunning]) failed = addfailed(failed, results3) failed = addfailed(failed, results4) for node in nodes: if node.name in failed: results.set_node_fail(node) else: results.set_node_success(node) return results
def top(self, nodes): results = cmdresult.CmdResult() for (node, error, vals) in self.get_top_output(nodes): top_info = {"name": node.name, "type": node.type, "host": node.host, "pid": None, "vsize": None, "rss": None, "cpu": None, "cmd": None, "error": None} if error: top_info["error"] = error results.set_node_data(node, False, {"procs": top_info}) continue top_info2 = top_info.copy() top_info2.update(vals) results.set_node_data(node, True, {"procs": top_info2}) return results
def print_id(self, nodes, id): results = cmdresult.CmdResult() running = self._isrunning(nodes) eventlist = [] for (node, isrunning) in running: if isrunning: eventlist += [(node, "Control::id_value_request", [id], "Control::id_value_response")] if not eventlist: results.set_node_output(nodes[0], False, "no running instances of Zeek") return results for (node, success, args) in events.send_events_parallel(eventlist, config.Config.controltopic): if success: out = "\n".join(args) else: out = args results.set_node_output(node, success, out) return results
def stop(self, nodes): results = cmdresult.CmdResult() loggers, manager, proxies, workers = node_mod.separate_types(nodes) for n in nodes: n.setExpectRunning(False) # Stop nodes. Do it in the order workers, proxies, manager, loggers # (the reverse of "start"). if workers: self._stop_nodes(workers, results) if not results.ok: for n in (proxies + manager + loggers): results.set_node_fail(n) return results if proxies: self._stop_nodes(proxies, results) if not results.ok: for n in (manager + loggers): results.set_node_fail(n) return results if manager: self._stop_nodes(manager, results) if not results.ok: for n in loggers: results.set_node_fail(n) return results if loggers: self._stop_nodes(loggers, results) return results
def start(self, nodes): results = cmdresult.CmdResult() loggers, manager, proxies, workers = node_mod.separate_types(nodes) for n in nodes: n.setExpectRunning(True) # Start nodes. Do it in the order loggers, manager, proxies, workers. if loggers: self._start_nodes(loggers, results) if not results.ok: for n in (manager + proxies + workers): results.set_node_fail(n) return results if manager: self._start_nodes(manager, results) if not results.ok: for n in (proxies + workers): results.set_node_fail(n) return results if proxies: self._start_nodes(proxies, results) if not results.ok: for n in workers: results.set_node_fail(n) return results if workers: self._start_nodes(workers, results) return results
def cmd_custom_process(self): results = cmdresult.CmdResult() results.ok = True return results
def cmd_custom_check(self): enabled = JE.is_profiling_enalbed() self.message("jemalloc profiling enabled: {}".format(enabled)) results = cmdresult.CmdResult() results.ok = enabled return results
def install(self, local_only): results = cmdresult.CmdResult() try: self.config.record_zeek_version() except config.ConfigurationError as err: self.ui.error("%s" % err) results.ok = False return results manager = self.config.manager() # Delete previously installed policy files to not mix things up. policies = [self.config.policydirsiteinstall, self.config.policydirsiteinstallauto] for dirpath in policies: if os.path.isdir(dirpath): self.ui.info("removing old policies in %s ..." % dirpath) try: shutil.rmtree(dirpath) except OSError as err: self.ui.error("failed to remove directory %s: %s" % (dirpath, err)) results.ok = False return results self.ui.info("creating policy directories ...") for dirpath in policies: try: os.makedirs(dirpath) except OSError as err: self.ui.error("failed to create directory: %s" % err) results.ok = False return results # Install local site policy. if self.config.sitepolicypath: self.ui.info("installing site policies ...") dst = self.config.policydirsiteinstall for dir in self.config.sitepolicypath.split(":"): dirpath = self.config.subst(dir) for pathname in glob.glob(os.path.join(dirpath, "*")): if not execute.install(pathname, dst, self.ui): results.ok = False return results if not install.make_layout(self.config.policydirsiteinstallauto, self.ui): results.ok = False return results self.ui.info("generating local-networks.zeek ...") if not install.make_local_networks(self.config.policydirsiteinstallauto, self.ui): results.ok = False return results self.ui.info("generating zeekctl-config.zeek ...") if not install.make_zeekctl_config_policy(self.config.policydirsiteinstallauto, self.ui, self.pluginregistry): results.ok = False return results loggers = self.config.loggers() if loggers: # Just use the first logger that is defined. node_cwd = loggers[0].cwd() else: node_cwd = manager.cwd() current = self.config.subst(os.path.join(self.config.logdir, "current")) try: util.force_symlink(node_cwd, current) except (IOError, OSError) as err: results.ok = False self.ui.error("failed to update symlink '%s': %s" % (current, err)) return results self.ui.info("generating zeekctl-config.sh ...") if not install.make_zeekctl_config_sh(self.ui): results.ok = False return results if local_only: return results # Make sure we install each remote host only once. nodes = self.config.hosts(exclude_local=True) # If there are no remote hosts, then we're done. if not nodes: # Save current configuration state. self.config.update_cfg_hash() return results # Sync to clients. self.ui.info("updating nodes ...") dirs = [] if not self.config.havenfs: # Non-NFS, need to explicitly synchronize. syncs = install.get_syncs() else: # NFS. We only need to take care of the spool/log directories. # We need this only on the manager. dirs.append((manager, self.config.logdir)) syncs = install.get_nfssyncs() syncs = [(dir, mirror) for (dir, mirror, optional) in syncs if not optional or os.path.exists(self.config.subst(dir))] createdirs = [self.config.subst(dir) for (dir, mirror) in syncs if not mirror] for n in nodes: for dir in createdirs: dirs.append((n, dir)) for (node, success, output) in self.executor.mkdirs(dirs): if not success: self.ui.error("cannot create a directory on node %s" % node.name) if output: self.ui.error(output) results.ok = False return results paths = [self.config.subst(dir) for (dir, mirror) in syncs if mirror] if not execute.sync(nodes, paths, self.ui): results.ok = False return results # Save current configuration state. self.config.update_cfg_hash() return results
def status(self, nodes): results = cmdresult.CmdResult() showall = self.config.statuscmdshowall if showall: self.ui.info("Getting process status ...") nodestatus = self._isrunning(nodes) running = [] cmds = [] for (node, isrunning) in nodestatus: if isrunning: running += [node] cmds += [(node, "first-line", ["%s/.status" % node.cwd(), "%s/.startup" % node.cwd()])] statuses = {} startups = {} for (n, success, output) in self.executor.run_helper(cmds): out = output.splitlines() try: val = out[0].split()[0].lower() if (success and out[0]) else "???" except IndexError: val = "???" statuses[n.name] = val try: val = fmttime(out[1]) if (success and out[1]) else "???" except (IndexError, ValueError): val = "???" startups[n.name] = val if showall: self.ui.info("Getting peer status ...") peers = {} nodes = [n for n in running if statuses[n.name] == "running"] for (node, success, args) in self._query_peerstatus(nodes): if success and args: peers[node.name] = [] for f in args[0].split(): if not f.startswith("peer="): continue # Get everything after the '=' character. val = f[5:] if val: peers[node.name] += [val] for (node, isrunning) in nodestatus: node_info = { "name": node.name, "type": node.type, "host": node.host, "status": "stopped", "pid": None, "started": None, } if showall: node_info["peers"] = None if isrunning: node_info["status"] = statuses[node.name] elif node.hasCrashed(): node_info["status"] = "crashed" if isrunning: node_info["pid"] = node.getPID() if showall: if node.name in peers: node_info["peers"] = len(peers[node.name]) else: node_info["peers"] = "???" node_info["started"] = startups[node.name] results.set_node_data(node, True, node_info) return results