"""
CephOsdTreeText - command ``ceph osd tree``
===========================================
"""
from insights.core import CommandParser, LegacyItemAccess
from insights.core.exceptions import ParseException, SkipComponent
from insights.core.plugins import parser
from insights.specs import Specs
text_to_json_header_map = {
"ID": "id",
"CLASS": "device_class",
"WEIGHT": "crush_weight",
"TYPE NAME": "type_name",
"TYPE_NAME": "type_name",
"STATUS": "status",
"UP/DOWN": "status",
"REWEIGHT": "reweight",
"PRI-AFF": "primary_affinity",
"PRIMARY-AFFINITY": "primary_affinity"
}
[docs]
@parser(Specs.ceph_osd_tree_text)
class CephOsdTreeText(CommandParser, LegacyItemAccess):
"""
Class to parse the output of command ``ceph osd tree``.
The typical content is::
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08752 root default
-9 0.02917 host ceph1
2 hdd 0.01459 osd.2 up 1.00000 1.00000
5 hdd 0.01459 osd.5 up 1.00000 1.00000
-5 0.02917 host ceph2
1 hdd 0.01459 osd.1 up 1.00000 1.00000
4 hdd 0.01459 osd.4 up 1.00000 1.00000
-3 0.02917 host ceph3
0 hdd 0.01459 osd.0 up 1.00000 1.00000
3 hdd 0.01459 osd.3 up 1.00000 1.00000
-7 0 host ceph_1
Examples:
>>> ceph_osd_tree_text['nodes'][0]['id']
'-1'
>>> ceph_osd_tree_text['nodes'][0]['name']
'default'
>>> ceph_osd_tree_text['nodes'][0]['type']
'root'
>>> ceph_osd_tree_text['nodes'][3]['type']
'osd'
"""
[docs]
def parse_content(self, content):
def calc_column_indices(line, headers):
idx = []
for h in headers:
i = idx[-1] + 1 if idx else 0
idx.append(line.index(h, i))
return idx
if not content:
raise SkipComponent("Empty content.")
if len(content) == 1 or "TYPE NAME" not in content[0]:
raise ParseException("Wrong content in table: '{0}'.".format(content))
header = content[0].replace('TYPE NAME', 'TYPE_NAME')
col_headers = header.strip().split()
json_headers = [text_to_json_header_map[h] for h in col_headers]
col_index = calc_column_indices(header, col_headers)
name_header_index = header.index("TYPE_NAME")
parents = []
nodes = []
for row_num, line in enumerate(content[1:]):
node = dict(
(json_headers[c], line[col_index[c]:col_index[c + 1]].strip())
for c in range(len(col_index) - 1)
)
node[json_headers[-1]] = line[col_index[-1]:].strip()
# update parent's children list
name_index = line.index(node['type_name'])
shift = (name_index - name_header_index) / 4
if shift == 0:
pass
elif shift > len(parents):
prev_line = row_num - 1
parents.append(prev_line)
nodes[parents[-1]]['children'].insert(0, int(node['id']))
elif shift == len(parents):
nodes[parents[-1]]['children'].insert(0, int(node['id']))
elif shift < len(parents):
parents.pop()
nodes[parents[-1]]['children'].insert(0, int(node['id']))
# update type name
type_name = node.pop('type_name').split()
node['type'] = type_name[0] if len(type_name) > 1 else type_name[0].split('.')[0]
node['name'] = type_name[-1]
nodes.append(node)
# update children list for the none leave node
if len(type_name) > 1:
node['children'] = []
self.data = {'nodes': nodes}