def _set_agents_summary(self): results = env.dataprovider.query(["max(heartbeat.create_time)", "heartbeat.analyzer(-1).analyzerid/group_by"]) if not results: return c = Criterion() for create_time, analyzerid in results: c |= Criterion("heartbeat.create_time", "==", create_time) & Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid) agents = { "up": utils.AttrObj(count=0, title=_("Online"), label="label-success", status=["online"]), "down": utils.AttrObj(count=0, title=_("Offline"), label="label-danger", status=["offline", "missing", "unknown"]) } heartbeat_error_margin = env.config.general.get_int("heartbeat_error_margin", 3) for heartbeat in env.dataprovider.get(c): heartbeat = heartbeat["heartbeat"] analyzer = heartbeat["analyzer"][-1] analyzer.status = utils.get_analyzer_status_from_latest_heartbeat(heartbeat, heartbeat_error_margin)[0] for key, values in agents.items(): if analyzer.status in values.status: values.count += 1 parameters = env.request.menu_parameters val = agents["down"] if agents["down"].count else agents["up"] data = resource.HTMLNode("a", localization.format_number(val.count), title=val.title, _class="label " + val.label, href=url_for("Agents.agents", status=val.status, **parameters)) return utils.AttrObj( name="agents", title=resource.HTMLNode("a", _("Agents"), href=url_for("Agents.agents", **parameters)), data=[data] )
def _get_analyzers(self, reqstatus): # Do not take the control menu into account. # The expected behavior is yet to be determined. results = env.dataprovider.query(["max(heartbeat.create_time)", "heartbeat.analyzer(-1).analyzerid/group_by"]) if not results: return c = Criterion() for create_time, analyzerid in results: c |= Criterion("heartbeat.create_time", "==", create_time) & Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid) for heartbeat in env.dataprovider.get(c): heartbeat = heartbeat["heartbeat"] status, status_text = utils.get_analyzer_status_from_latest_heartbeat( heartbeat, self._heartbeat_error_margin ) if reqstatus and status not in reqstatus: continue delta = heartbeat.get("create_time") - utils.timeutil.now() analyzerid = heartbeat["analyzer(-1).analyzerid"] heartbeat_listing = url_for("HeartbeatDataSearch.forensic", criteria=Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid), _default=None) alert_listing = url_for("AlertDataSearch.forensic", criteria=Criterion("alert.analyzer.analyzerid", "==", analyzerid), _default=None) heartbeat_analyze = url_for(".analyze", analyzerid=analyzerid) analyzer = heartbeat["analyzer(-1)"] node_name = analyzer["node.name"] or _("Node name n/a") osversion = analyzer["osversion"] or _("OS version n/a") ostype = analyzer["ostype"] or _("OS type n/a") yield { "id": analyzerid, "label": "%s - %s %s" % (node_name, ostype, osversion), "location": analyzer["node.location"] or _("Node location n/a"), "node": node_name, "name": analyzer["name"], "model": analyzer["model"], "class": analyzer["class"], "version": analyzer["version"], "latest_heartbeat": localization.format_timedelta(delta, add_direction=True), "status": status, "status_text": status_text, "links": [ resource.HTMLNode("a", _("Alert listing"), href=alert_listing), resource.HTMLNode("a", _("Heartbeat listing"), href=heartbeat_listing), resource.HTMLNode("a", _("Heartbeat analysis"), href=heartbeat_analyze) ] }
def _get_analyzers(self): criteria = None if "filter_path" in self.parameters: criteria = "%s == '%s'" % (self.parameters["filter_path"], utils.escape_criteria(self.parameters["filter_value"])) for (analyzerid,) in env.idmef_db.getValues(["heartbeat.analyzer(-1).analyzerid/group_by"], criteria): analyzer, heartbeat = env.idmef_db.getAnalyzer(analyzerid) status, status_text = utils.get_analyzer_status_from_latest_heartbeat( heartbeat, self._heartbeat_error_margin ) if self.parameters["status"] and status not in self.parameters["status"]: continue delta = float(heartbeat.get("create_time")) - time.time() parameters = {"heartbeat.analyzer(-1).analyzerid": analyzerid} heartbeat_listing = utils.create_link(view.getViewPath("HeartbeatListing"), parameters) parameters = {"analyzer_object_0": "alert.analyzer.analyzerid", "analyzer_operator_0": "=", "analyzer_value_0": analyzerid} alert_listing = utils.create_link(view.getViewPath("AlertListing"), parameters) parameters = {"analyzerid": analyzerid} heartbeat_analyze = utils.create_link(self.view_path + "/HeartbeatAnalyze", parameters) node_name = analyzer["node.name"] or _("Node name n/a") osversion = analyzer["osversion"] or _("OS version n/a") ostype = analyzer["ostype"] or _("OS type n/a") yield {"id": analyzerid, "label": "%s - %s %s" % (node_name, ostype, osversion), "location": analyzer["node.location"] or _("Node location n/a"), "node": node_name, "name": analyzer["name"], "model": analyzer["model"], "class": analyzer["class"], "version": analyzer["version"], "latest_heartbeat": localization.format_timedelta(delta, add_direction=True), "status": status, "status_text": status_text, "links": [ {"text": _("Alert listing"), "link": alert_listing}, {"text": _("Heartbeat listing"), "link": heartbeat_listing}, {"text": _("Heartbeat analysis"), "link": heartbeat_analyze, "class": "widget-link", "title": _("Heartbeat analysis")}, ]}
def analyze(self, analyzerid): analyzer, heartbeat = self._get_analyzer(analyzerid) delta = heartbeat["create_time"] - utils.timeutil.now() analyzer.last_heartbeat_time = localization.format_timedelta(delta, add_direction=True) analyzer.status = None analyzer.events = [] res = env.dataprovider.get(Criterion("heartbeat.analyzer(-1).analyzerid", "=", analyzerid), limit=self._heartbeat_count) prev = None total_interval = 0 # Iterate from oldest heartbeat to newest for obj in reversed(res): cur = HeartbeatObject(obj["heartbeat"]) if not (prev and cur.status and cur.interval): prev = cur continue total_interval += cur.interval event = None if cur.status == "starting": if prev.status == "exiting": event = utils.AttrObj(time=cur.time_str, value=_("Normal sensor start"), type="start") else: event = utils.AttrObj(time=cur.time_str, value=_("Unexpected sensor restart"), type="unexpected_restart") elif cur.status == "running": delta = cur.time - prev.time if abs(delta.total_seconds() - cur.interval) > self._heartbeat_error_margin: delta = localization.format_timedelta(delta, granularity="second") event = utils.AttrObj(time=cur.time_str, value=_("Unexpected heartbeat interval: %(delta)s") % {'delta': delta}, type="abnormal_heartbeat_interval") elif cur.status == "exiting": event = utils.AttrObj(time=cur.time_str, value=_("Normal sensor stop"), type="normal_stop") if event: analyzer.events.append(event) prev = cur if prev: analyzer.status, analyzer.status_meaning = \ utils.get_analyzer_status_from_latest_heartbeat(obj["heartbeat"], self._heartbeat_error_margin) if analyzer.status == "missing": delta = utils.timeutil.now() - prev.time analyzer.events.append(utils.AttrObj(time=prev.time_str, value=_("Sensor is down since %s") % localization.format_timedelta(delta), type="down")) if not analyzer.status: analyzer.status, analyzer.status_meaning = "unknown", _("Unknown") if not analyzer.events: delta = localization.format_timedelta(total_interval / self._heartbeat_count) analyzer.events.append(utils.AttrObj( time="", value=_("No anomaly in the last %(count)d heartbeats (one heartbeat every %(delta)s average)") % {'count': self._heartbeat_count, 'delta': delta}, type="no_anomaly" )) return template.PrewikkaTemplate(__name__, "templates/heartbeatanalyze.mak").render(analyzer=analyzer)
def _get_analyzers(self, reqstatus): # Do not take the control menu into account. # The expected behavior is yet to be determined. for (analyzerid, ) in env.dataprovider.query( ["heartbeat.analyzer(-1).analyzerid/group_by"]): analyzer, heartbeat = self._get_analyzer(analyzerid) status, status_text = utils.get_analyzer_status_from_latest_heartbeat( heartbeat, self._heartbeat_error_margin) if reqstatus and status not in reqstatus: continue delta = float(heartbeat.get("create_time")) - time.time() heartbeat_listing = url_for( "HeartbeatListing.render", **{"heartbeat.analyzer(-1).analyzerid": analyzerid}) alert_listing = url_for( "AlertListing.render", **{ "analyzer_object_0": "alert.analyzer.analyzerid", "analyzer_operator_0": "=", "analyzer_value_0": analyzerid }) heartbeat_analyze = url_for(".analyze", analyzerid=analyzerid) node_name = analyzer["node.name"] or _("Node name n/a") osversion = analyzer["osversion"] or _("OS version n/a") ostype = analyzer["ostype"] or _("OS type n/a") yield { "id": analyzerid, "label": "%s - %s %s" % (node_name, ostype, osversion), "location": analyzer["node.location"] or _("Node location n/a"), "node": node_name, "name": analyzer["name"], "model": analyzer["model"], "class": analyzer["class"], "version": analyzer["version"], "latest_heartbeat": localization.format_timedelta(delta, add_direction=True), "status": status, "status_text": status_text, "links": [ { "text": _("Alert listing"), "link": alert_listing }, { "text": _("Heartbeat listing"), "link": heartbeat_listing }, { "text": _("Heartbeat analysis"), "link": heartbeat_analyze, "class": "widget-link", "title": _("Heartbeat analysis") }, ] }
def analyze(self, analyzerid): analyzer, heartbeat = self._get_analyzer(analyzerid) delta = float(heartbeat["create_time"]) - time.time() analyzer.last_heartbeat_time = localization.format_timedelta( delta, add_direction=True) analyzer.status = None analyzer.events = [] res = env.dataprovider.get(Criterion( "heartbeat.analyzer(-1).analyzerid", "=", analyzerid), limit=self._heartbeat_count) prev = None latest = True total_interval = 0 for idx, cur in enumerate(res): cur = cur["heartbeat"] cur_status, cur_interval, cur_time = cur.get( "additional_data('Analyzer status').data" )[0], cur["heartbeat_interval"], cur["create_time"] cur_time_str = localization.format_datetime(float(cur_time)) try: prev = res[idx + 1]["heartbeat"] prev_status, prev_time = prev.get( "additional_data('Analyzer status').data" )[0], prev["create_time"] except: break if not cur_status or not cur_interval: continue total_interval += int(cur_interval) if latest: latest = False analyzer.status, analyzer.status_meaning = \ utils.get_analyzer_status_from_latest_heartbeat(cur, self._heartbeat_error_margin) if analyzer.status == "missing": delta = time.time() - float(cur_time) analyzer.events.append( utils.AttrObj(time=cur_time_str, value=_("Sensor is down since %s") % localization.format_timedelta(delta), type="down")) event = None if cur_status == "starting": if prev_status == "exiting": event = utils.AttrObj(time=cur_time_str, value=_("Normal sensor start"), type="start") else: event = utils.AttrObj(time=cur_time_str, value=_("Unexpected sensor restart"), type="unexpected_restart") elif cur_status == "running": delta = abs(int(cur_time) - int(prev_time) - int(cur_interval)) if delta > self._heartbeat_error_margin: delta = localization.format_timedelta(delta, granularity="second") event = utils.AttrObj( time=cur_time_str, value=_("Unexpected heartbeat interval: %(delta)s") % {'delta': delta}, type="abnormal_heartbeat_interval") elif cur_status == "exiting": event = utils.AttrObj(time=cur_time_str, value=_("Normal sensor stop"), type="normal_stop") if event: analyzer.events.append(event) if not analyzer.status: analyzer.status, analyzer.status_meaning = "unknown", _("Unknown") if not analyzer.events: delta = localization.format_timedelta(total_interval / self._heartbeat_count) analyzer.events.append( utils.AttrObj( time="", value= _("No anomaly in the last %(count)d heartbeats (one heartbeat every %(delta)s average)" ) % { 'count': self._heartbeat_count, 'delta': delta }, type="no_anomaly")) return template.PrewikkaTemplate( __name__, "templates/heartbeatanalyze.mak").render(analyzer=analyzer)
def render(self): analyzerid = self.parameters["analyzerid"] analyzer, heartbeat = env.idmef_db.getAnalyzer(analyzerid) delta = float(heartbeat["create_time"]) - time.time() analyzer.last_heartbeat_time = localization.format_timedelta(delta, add_direction=True) analyzer.status = None analyzer.events = [ ] idents = env.idmef_db.getHeartbeatIdents(criteria="heartbeat.analyzer(-1).analyzerid == %s" % analyzerid, limit=self._heartbeat_count) prev = None latest = True total_interval = 0 for idx, ident in enumerate(idents): cur = env.idmef_db.getHeartbeat(ident)["heartbeat"] cur_status, cur_interval, cur_time = cur.get("additional_data('Analyzer status').data")[0], cur["heartbeat_interval"], cur["create_time"] cur_time_str = localization.format_datetime(float(cur_time)) try: prev = env.idmef_db.getHeartbeat(idents[idx + 1])["heartbeat"] prev_status, prev_time = prev.get("additional_data('Analyzer status').data")[0], prev["create_time"] except: break if not cur_status or not cur_interval: continue total_interval += int(cur_interval) if latest: latest = False analyzer.status, analyzer.status_meaning = \ utils.get_analyzer_status_from_latest_heartbeat(cur, self._heartbeat_error_margin) if analyzer.status == "missing": delta = time.time() - float(cur_time) analyzer.events.append({ "time": cur_time_str, "value": _("Sensor is down since %s") % localization.format_timedelta(delta), "type": "down"}) event = None if cur_status == "starting": if prev_status == "exiting": event = { "time": cur_time_str, "value": _("Normal sensor start"), "type": "start" } else: event = { "time": cur_time_str, "value": _("Unexpected sensor restart"), "type": "unexpected_restart" } elif cur_status == "running": delta = abs(int(cur_time) - int(prev_time) - int(cur_interval)) if delta > self._heartbeat_error_margin: delta = localization.format_timedelta(delta, granularity="second") event = { "time": cur_time_str, "value": _("Unexpected heartbeat interval: %(delta)s") % {'delta': delta}, "type": "abnormal_heartbeat_interval" } elif cur_status == "exiting": event = { "time": cur_time_str, "value": _("Normal sensor stop"), "type": "normal_stop" } if event: analyzer.events.append(event) if not analyzer.status: analyzer.status, analyzer.status_meaning = "unknown", _("Unknown") if not analyzer.events: delta = localization.format_timedelta(total_interval / self._heartbeat_count) analyzer.events.append({ "time": "", "value": _("No anomaly in the last %(count)d heartbeats (one heartbeat every %(delta)s average)") % {'count': self._heartbeat_count, 'delta':delta}, "type": "no_anomaly" }) self.dataset["analyzer"] = analyzer