]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/types.py
update sources to v12.1.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / types.py
CommitLineData
7c673cae 1from collections import namedtuple
7c673cae
FG
2
3
4CRUSH_RULE_TYPE_REPLICATED = 1
5CRUSH_RULE_TYPE_ERASURE = 3
6
7
8ServiceId = namedtuple('ServiceId', ['fsid', 'service_type', 'service_id'])
9
10
11MON = 'mon'
12OSD = 'osd'
13MDS = 'mds'
14POOL = 'pool'
15OSD_MAP = 'osd_map'
16CRUSH_RULE = 'crush_rule'
17CLUSTER = 'cluster'
18SERVER = 'server'
19
20
31f18b77
FG
21def memoize(function):
22 def wrapper(*args):
23 self = args[0]
24 if not hasattr(self, "_memo"):
25 self._memo = {}
7c673cae 26
31f18b77
FG
27 if args in self._memo:
28 return self._memo[args]
29 else:
30 rv = function(*args)
31 self._memo[args] = rv
32 return rv
33 return wrapper
7c673cae 34
7c673cae 35
31f18b77
FG
36OSD_FLAGS = ('pause', 'noup', 'nodown', 'noout', 'noin', 'nobackfill',
37 'norecover', 'noscrub', 'nodeep-scrub')
7c673cae 38
31f18b77
FG
39class DataWrapper(object):
40 def __init__(self, data):
41 self.data = data
7c673cae
FG
42
43
31f18b77 44class OsdMap(DataWrapper):
7c673cae
FG
45 str = OSD_MAP
46
31f18b77
FG
47 def __init__(self, data):
48 super(OsdMap, self).__init__(data)
7c673cae
FG
49 if data is not None:
50 self.osds_by_id = dict([(o['osd'], o) for o in data['osds']])
51 self.pools_by_id = dict([(p['pool'], p) for p in data['pools']])
52 self.osd_tree_node_by_id = dict([(o['id'], o) for o in data['tree']['nodes'] if o['id'] >= 0])
53
54 # Special case Yuck
55 flags = data.get('flags', '').replace('pauserd,pausewr', 'pause')
56 tokenized_flags = flags.split(',')
57
58 self.flags = dict([(x, x in tokenized_flags) for x in OSD_FLAGS])
59 else:
60 self.osds_by_id = {}
61 self.pools_by_id = {}
62 self.osd_tree_node_by_id = {}
63 self.flags = dict([(x, False) for x in OSD_FLAGS])
64
65 @property
66 def osd_metadata(self):
67 return self.data['osd_metadata']
68
69 @memoize
70 def get_tree_nodes_by_id(self):
71 return dict((n["id"], n) for n in self.data['tree']["nodes"])
72
73 def _get_crush_rule_osds(self, rule):
74 nodes_by_id = self.get_tree_nodes_by_id()
75
76 def _gather_leaf_ids(node):
77 if node['id'] >= 0:
78 return set([node['id']])
79
80 result = set()
81 for child_id in node['children']:
82 if child_id >= 0:
83 result.add(child_id)
84 else:
85 result |= _gather_leaf_ids(nodes_by_id[child_id])
86
87 return result
88
89 def _gather_descendent_ids(node, typ):
90 result = set()
91 for child_id in node['children']:
92 child_node = nodes_by_id[child_id]
93 if child_node['type'] == typ:
94 result.add(child_node['id'])
95 elif 'children' in child_node:
96 result |= _gather_descendent_ids(child_node, typ)
97
98 return result
99
100 def _gather_osds(root, steps):
101 if root['id'] >= 0:
102 return set([root['id']])
103
104 osds = set()
105 step = steps[0]
106 if step['op'] == 'choose_firstn':
107 # Choose all descendents of the current node of type 'type'
108 d = _gather_descendent_ids(root, step['type'])
109 for desc_node in [nodes_by_id[i] for i in d]:
110 osds |= _gather_osds(desc_node, steps[1:])
111 elif step['op'] == 'chooseleaf_firstn':
112 # Choose all descendents of the current node of type 'type',
113 # and select all leaves beneath those
114 for desc_node in [nodes_by_id[i] for i in _gather_descendent_ids(root, step['type'])]:
115 # Short circuit another iteration to find the emit
116 # and assume anything we've done a chooseleaf on
117 # is going to be part of the selected set of osds
118 osds |= _gather_leaf_ids(desc_node)
119 elif step['op'] == 'emit':
120 if root['id'] >= 0:
121 osds |= root['id']
122
123 return osds
124
125 osds = set()
126 for i, step in enumerate(rule['steps']):
127 if step['op'] == 'take':
128 osds |= _gather_osds(nodes_by_id[step['item']], rule['steps'][i + 1:])
129 return osds
130
131 @property
132 @memoize
133 def osds_by_rule_id(self):
134 result = {}
135 for rule in self.data['crush']['rules']:
136 result[rule['rule_id']] = list(self._get_crush_rule_osds(rule))
137
138 return result
139
140 @property
141 @memoize
142 def osds_by_pool(self):
143 """
144 Get the OSDS which may be used in this pool
145
146 :return dict of pool ID to OSD IDs in the pool
147 """
148
149 result = {}
150 for pool_id, pool in self.pools_by_id.items():
151 osds = None
152 for rule in [r for r in self.data['crush']['rules'] if r['ruleset'] == pool['crush_ruleset']]:
153 if rule['min_size'] <= pool['size'] <= rule['max_size']:
154 osds = self.osds_by_rule_id[rule['rule_id']]
155
156 if osds is None:
157 # Fallthrough, the pool size didn't fall within any of the rules in its ruleset, Calamari
158 # doesn't understand. Just report all OSDs instead of failing horribly.
7c673cae
FG
159 osds = self.osds_by_id.keys()
160
161 result[pool_id] = osds
162
163 return result
164
165 @property
166 @memoize
167 def osd_pools(self):
168 """
169 A dict of OSD ID to list of pool IDs
170 """
171 osds = dict([(osd_id, []) for osd_id in self.osds_by_id.keys()])
172 for pool_id in self.pools_by_id.keys():
173 for in_pool_id in self.osds_by_pool[pool_id]:
174 osds[in_pool_id].append(pool_id)
175
176 return osds
177
178
31f18b77 179class FsMap(DataWrapper):
7c673cae
FG
180 str = 'fs_map'
181
224ce89b
WB
182 def get_filesystem(self, fscid):
183 for fs in self.data['filesystems']:
184 if fs['id'] == fscid:
185 return fs
186
187 raise NotFound("filesystem", fscid)
188
7c673cae 189
31f18b77 190class MonMap(DataWrapper):
7c673cae
FG
191 str = 'mon_map'
192
193
31f18b77 194class MonStatus(DataWrapper):
7c673cae
FG
195 str = 'mon_status'
196
31f18b77
FG
197 def __init__(self, data):
198 super(MonStatus, self).__init__(data)
7c673cae
FG
199 if data is not None:
200 self.mons_by_rank = dict([(m['rank'], m) for m in data['monmap']['mons']])
201 else:
202 self.mons_by_rank = {}
203
204
31f18b77 205class PgSummary(DataWrapper):
7c673cae
FG
206 """
207 A summary of the state of PGs in the cluster, reported by pool and by OSD.
208 """
209 str = 'pg_summary'
210
211
31f18b77 212class Health(DataWrapper):
7c673cae
FG
213 str = 'health'
214
215
31f18b77 216class Config(DataWrapper):
7c673cae
FG
217 str = 'config'
218
219
220class NotFound(Exception):
221 def __init__(self, object_type, object_id):
222 self.object_type = object_type
223 self.object_id = object_id
224
225 def __str__(self):
226 return "Object of type %s with id %s not found" % (self.object_type, self.object_id)
227