def register_report_searches(self): """Register all sequence search definitions that we will execute against rabbitmqctl report. """ self._sequences = { "queues": { "searchdef": SequenceSearchDef( start=SearchDef(r"^Queues on ([^:]+):"), body=SearchDef(r"^<([^.\s]+)[.0-9]+>\s+(\S+)\s+.+"), end=SearchDef(r"^$"), tag="queues"), "callbacks": [self.get_queues] }, "connections": { "searchdef": SequenceSearchDef( start=SearchDef(r"^Connections:$"), body=SearchDef(r"^<(rabbit[^>.]*)(?:[.][0-9]+)+>.*$"), end=SearchDef(r"^$"), tag="connections"), "callbacks": [self.get_queue_connection_distribution] }, "memory": { "searchdef": SequenceSearchDef( start=SearchDef(r"^Status of node '([^']*)'$"), body=SearchDef(r"^\s+\[{total,([0-9]+)}.+"), end=SearchDef(r"^$"), tag="memory"), "callbacks": [self.get_memory_used] } } for s in self._sequences.values(): self.searcher.add_search_term(s["searchdef"], self.report_path)
def register_report_searches(self): """Register all sequence search definitions that we will execute against rabbitmqctl report. NOTE: the rabbitmqctl report output differs between versions 3.6.x and 3.8.x and we try to account for either by providing optional regex expressions to match either. """ self._sequences = { "queues": { "searchdef": SequenceSearchDef( start=SearchDef([r"^Queues on ([^:]+):", (r"^Listing queues for vhost ([^:]+) " r"...")]), # NOTE: we don't use a list for the body here because # we need to know which expression matched so that we # can know in which order to retrieve the columns since # their order is inverted between 3.6.x and 3.8.x body=SearchDef(r"^(?:<([^.\s]+)[.0-9]+>\s+(\S+)|" r"(\S+)\s+(?:\S+\s+){4}<([^.\s]+)[.0-9]" r"+>)\s+.+"), end=SearchDef(r"^$"), tag="queues"), "callbacks": [self.get_queue_info] }, "connections": { "searchdef": SequenceSearchDef( start=SearchDef([r"^Connections:$", r"^Listing connections ...$"]), body=SearchDef(r"^<(rabbit[^>.]*)(?:[.][0-9]+)+>.*$"), end=SearchDef(r"^$"), tag="connections"), "callbacks": [self.get_queue_connection_distribution] }, "memory": { "searchdef": SequenceSearchDef( start=SearchDef([r"^Status of node '([^']*)'$", r"^Status of node ([^']*) ...$"]), body=SearchDef(r"^\s+\[{total,([0-9]+)}.+"), end=SearchDef(r"^$"), tag="memory"), "callbacks": [self.get_memory_used] }, "partitioning": { "searchdef": SearchDef(r"^\s*{cluster_partition_handling,([^}]*)}", tag="cluster_partition_handling"), "callbacks": [self.get_partition_handling] } } for s in self._sequences.values(): self.searcher.add_search_term(s["searchdef"], self.f_report)
def get_osd_lvm_info(self): if not self.ceph_volume_lvm_list: return ceph_osds = self.services.get("ceph-osd") if not ceph_osds: return 0 f_ceph_volume_lvm_list = mktemp_dump('\n'.join( self.ceph_volume_lvm_list)) s = FileSearcher() sd = SequenceSearchDef(start=SearchDef(r"^=+\s+osd\.(\d+)\s+=+.*"), body=SearchDef([ r"\s+osd\s+(fsid)\s+(\S+)\s*", r"\s+(devices)\s+([\S]+)\s*" ]), tag="ceph-lvm") s.add_search_term(sd, path=f_ceph_volume_lvm_list) info = {} for results in s.search().find_sequence_sections(sd).values(): _osd_id = None _info = {} for result in results: if result.tag == sd.start_tag: _osd_id = int(result.get(1)) elif result.tag == sd.body_tag: if result.get(1) == "fsid": _info["fsid"] = result.get(2) elif result.get(1) == "devices": _info["dev"] = result.get(2) info[_osd_id] = _info os.unlink(f_ceph_volume_lvm_list) return info
def test_sequence_searcher_section_start_end_same(self): """ Test scenario: * multiple sections that end with start of the next * start def matches unique start * end def matches any start """ with tempfile.NamedTemporaryFile(mode='w', delete=False) as ftmp: ftmp.write(SEQ_TEST_7) ftmp.close() s = FileSearcher() sd = SequenceSearchDef(start=SearchDef(r"^section (2)"), body=SearchDef(r"\d_\d"), end=SearchDef( r"^section (\d+)"), tag="seq-search-test7") s.add_search_term(sd, path=ftmp.name) results = s.search() sections = results.find_sequence_sections(sd) self.assertEqual(len(sections), 1) for id in sections: for r in sections[id]: if r.tag == sd.start_tag: self.assertEqual(r.get(1), "2") elif r.tag == sd.body_tag: self.assertTrue(r.get(0) in ["2_1"]) os.remove(ftmp.name)
def register_search_terms(self): self.sequence_defs.append( SequenceSearchDef(start=SearchDef(r"\s+port \d+: (\S+) .+"), body=SearchDef( r"\s+([RT]X) \S+:(\d+) \S+:(\d+) \S+:(\d+) " r"\S+:(\d+) \S+:(\d+)"), tag="port-stats")) for sd in self.sequence_defs: self.search_obj.add_search_term(sd, self.f_dpctl)
def test_sequence_searcher_overlapping_incomplete(self): with tempfile.NamedTemporaryFile(mode='w', delete=False) as ftmp: ftmp.write(SEQ_TEST_3) ftmp.close() s = FileSearcher() sd = SequenceSearchDef(start=SearchDef( r"^(a\S*) (start\S*) point\S*"), body=SearchDef(r"leads to"), end=SearchDef(r"^an (ending)$"), tag="seq-search-test3") s.add_search_term(sd, path=ftmp.name) results = s.search() sections = results.find_sequence_sections(sd) self.assertEqual(len(sections), 1) for id in sections: for r in sections[id]: if r.tag == sd.start_tag: self.assertEqual(r.get(1), "another") elif r.tag == sd.end_tag: self.assertEqual(r.get(1), "ending") os.remove(ftmp.name)
def test_sequence_searcher_multiple_sections(self): with tempfile.NamedTemporaryFile(mode='w', delete=False) as ftmp: ftmp.write(SEQ_TEST_5) ftmp.close() s = FileSearcher() sd = SequenceSearchDef(start=SearchDef( r"^(a\S*) (start\S*) point\S*"), body=SearchDef(r"value is (\S+)"), end=SearchDef(r"^$"), tag="seq-search-test5") s.add_search_term(sd, path=ftmp.name) results = s.search() sections = results.find_sequence_sections(sd) self.assertEqual(len(sections), 2) for id in sections: for r in sections[id]: if r.tag == sd.start_tag: self.assertEqual(r.get(1), "another") elif r.tag == sd.body_tag: self.assertTrue(r.get(1) in ["3", "4"]) elif r.tag == sd.end_tag: self.assertEqual(r.get(0), "") os.remove(ftmp.name)
def _get_port_stats(self, name=None, mac=None): """Get ip link stats for the given port.""" ip_link_show = cli_helpers.get_ip_link_show() stats_raw = [] if mac: libvirt_mac = "fe" + mac[2:] exprs = [] if mac: for _mac in [mac, libvirt_mac]: exprs.append(r"\s+link/ether\s+({})\s+.+".format(_mac)) else: exprs.append(r"\d+:\s+({}):\s+.+".format(name)) with tempfile.NamedTemporaryFile(mode='w', delete=False) as ftmp: ftmp.write(''.join(ip_link_show)) ftmp.close() s = FileSearcher() sd = SequenceSearchDef( # match start if interface start=SearchDef(r"^(?:{})".format('|'.join(exprs))), # match body of interface body=SearchDef(r".+"), # match next interface or EOF end=SearchDef(r"(?:^\d+:\s+\S+:.+|^$)"), tag="ifaces") s.add_search_term(sd, path=ftmp.name) results = s.search() for results in results.find_sequence_sections(sd).values(): for result in results: if result.tag == sd.body_tag: stats_raw.append(result.get(0)) # stop at first match - if matching by mac address it is # possible for multiple interfaces to have the same mac e.g. # bonds and its interfaces but we dont support that so just use # first. break os.unlink(ftmp.name) stats = {} total_packets = float(0) if stats_raw: for i, line in enumerate(stats_raw): ret = re.compile(r"\s+[RT]X:\s+.+").findall(line) if ret: ret = re.compile(r"\s*([a-z]+)\s*").findall(line) if ret: for j, column in enumerate(ret): value = int(stats_raw[i + 1].split()[j]) if column == "packets": total_packets = float(value) continue for key in ["dropped", "errors"]: if column == key: if not value: continue percentage = int( (100 / total_packets) * value) # only report if > 0% drops/errors if percentage > 0: stats[key] = ("{} ({}%)".format( value, percentage)) return stats