]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | |
2 | import ceph_state #noqa | |
3 | import json | |
4 | import logging | |
5 | import threading | |
6 | ||
7 | ||
8 | class CommandResult(object): | |
9 | """ | |
10 | Use with MgrModule.send_command | |
11 | """ | |
12 | def __init__(self, tag): | |
13 | self.ev = threading.Event() | |
14 | self.outs = "" | |
15 | self.outb = "" | |
16 | self.r = 0 | |
17 | ||
18 | # This is just a convenience for notifications from | |
19 | # C++ land, to avoid passing addresses around in messages. | |
20 | self.tag = tag | |
21 | ||
22 | def complete(self, r, outb, outs): | |
23 | self.r = r | |
24 | self.outb = outb | |
25 | self.outs = outs | |
26 | self.ev.set() | |
27 | ||
28 | def wait(self): | |
29 | self.ev.wait() | |
30 | return self.r, self.outb, self.outs | |
31 | ||
32 | ||
33 | class MgrModule(object): | |
34 | COMMANDS = [] | |
35 | ||
36 | def __init__(self, handle): | |
37 | self._handle = handle | |
38 | self._logger = logging.getLogger(handle) | |
39 | ||
40 | # Don't filter any logs at the python level, leave it to C++ | |
41 | self._logger.setLevel(logging.DEBUG) | |
42 | ||
43 | # FIXME: we should learn the log level from C++ land, and then | |
44 | # avoid calling ceph_state.log when we know a message is of | |
45 | # an insufficient level to be ultimately output | |
46 | ||
47 | class CPlusPlusHandler(logging.Handler): | |
48 | def emit(self, record): | |
49 | if record.levelno <= logging.DEBUG: | |
50 | ceph_level = 20 | |
51 | elif record.levelno <= logging.INFO: | |
52 | ceph_level = 4 | |
53 | elif record.levelno <= logging.WARNING: | |
54 | ceph_level = 1 | |
55 | else: | |
56 | ceph_level = 0 | |
57 | ||
58 | ceph_state.log(handle, ceph_level, self.format(record)) | |
59 | ||
60 | self._logger.addHandler(CPlusPlusHandler()) | |
61 | ||
62 | self._version = ceph_state.get_version() | |
63 | ||
64 | @property | |
65 | def log(self): | |
66 | return self._logger | |
67 | ||
68 | @property | |
69 | def version(self): | |
70 | return self._version | |
71 | ||
72 | def notify(self, notify_type, notify_id): | |
73 | """ | |
74 | Called by the ceph-mgr service to notify the Python plugin | |
75 | that new state is available. | |
76 | """ | |
77 | pass | |
78 | ||
79 | def serve(self): | |
80 | """ | |
81 | Called by the ceph-mgr service to start any server that | |
82 | is provided by this Python plugin. The implementation | |
83 | of this function should block until ``shutdown`` is called. | |
84 | ||
85 | You *must* implement ``shutdown`` if you implement ``serve`` | |
86 | """ | |
87 | pass | |
88 | ||
89 | def shutdown(self): | |
90 | """ | |
91 | Called by the ceph-mgr service to request that this | |
92 | module drop out of its serve() function. You do not | |
93 | need to implement this if you do not implement serve() | |
94 | ||
95 | :return: None | |
96 | """ | |
97 | pass | |
98 | ||
99 | def get(self, data_name): | |
100 | """ | |
101 | Called by the plugin to load some cluster state from ceph-mgr | |
102 | """ | |
103 | return ceph_state.get(self._handle, data_name) | |
104 | ||
105 | def get_server(self, hostname): | |
106 | """ | |
107 | Called by the plugin to load information about a particular | |
108 | node from ceph-mgr. | |
109 | ||
110 | :param hostname: a hostame | |
111 | """ | |
112 | return ceph_state.get_server(self._handle, hostname) | |
113 | ||
c07f9fc5 FG |
114 | def get_perf_schema(self, svc_type, svc_name): |
115 | """ | |
116 | Called by the plugin to fetch perf counter schema info. | |
117 | svc_name can be nullptr, as can svc_type, in which case | |
118 | they are wildcards | |
119 | ||
120 | :param svc_type: | |
121 | :param svc_name: | |
122 | :return: list of dicts describing the counters requested | |
123 | """ | |
124 | return ceph_state.get_perf_schema(self._handle, svc_type, svc_name) | |
125 | ||
7c673cae FG |
126 | def get_counter(self, svc_type, svc_name, path): |
127 | """ | |
128 | Called by the plugin to fetch data for a particular perf counter | |
129 | on a particular service. | |
130 | ||
131 | :param svc_type: | |
132 | :param svc_name: | |
133 | :param path: | |
134 | :return: A list of two-element lists containing time and value | |
135 | """ | |
136 | return ceph_state.get_counter(self._handle, svc_type, svc_name, path) | |
137 | ||
138 | def list_servers(self): | |
139 | """ | |
140 | Like ``get_server``, but instead of returning information | |
141 | about just one node, return all the nodes in an array. | |
142 | """ | |
143 | return ceph_state.get_server(self._handle, None) | |
144 | ||
145 | def get_metadata(self, svc_type, svc_id): | |
146 | """ | |
147 | Fetch the metadata for a particular service. | |
148 | ||
224ce89b | 149 | :param svc_type: string (e.g., 'mds', 'osd', 'mon') |
7c673cae FG |
150 | :param svc_id: string |
151 | :return: dict | |
152 | """ | |
153 | return ceph_state.get_metadata(self._handle, svc_type, svc_id) | |
154 | ||
224ce89b WB |
155 | def get_daemon_status(self, svc_type, svc_id): |
156 | """ | |
157 | Fetch the latest status for a particular service daemon. | |
158 | ||
159 | :param svc_type: string (e.g., 'rgw') | |
160 | :param svc_id: string | |
161 | :return: dict | |
162 | """ | |
163 | return ceph_state.get_daemon_status(self._handle, svc_type, svc_id) | |
164 | ||
7c673cae FG |
165 | def send_command(self, *args, **kwargs): |
166 | """ | |
167 | Called by the plugin to send a command to the mon | |
168 | cluster. | |
169 | """ | |
170 | ceph_state.send_command(self._handle, *args, **kwargs) | |
171 | ||
c07f9fc5 FG |
172 | def set_health_checks(self, checks): |
173 | """ | |
174 | Set module's health checks | |
175 | ||
176 | Set the module's current map of health checks. Argument is a | |
177 | dict of check names to info, in this form: | |
178 | ||
179 | { | |
180 | 'CHECK_FOO': { | |
181 | 'severity': 'warning', # or 'error' | |
182 | 'summary': 'summary string', | |
183 | 'detail': [ 'list', 'of', 'detail', 'strings' ], | |
184 | }, | |
185 | 'CHECK_BAR': { | |
186 | 'severity': 'error', | |
187 | 'summary': 'bars are bad', | |
188 | 'detail': [ 'too hard' ], | |
189 | }, | |
190 | } | |
191 | ||
192 | :param list: dict of health check dicts | |
193 | """ | |
194 | ceph_state.set_health_checks(self._handle, checks) | |
195 | ||
7c673cae FG |
196 | def handle_command(self, cmd): |
197 | """ | |
198 | Called by ceph-mgr to request the plugin to handle one | |
199 | of the commands that it declared in self.COMMANDS | |
200 | ||
201 | Return a status code, an output buffer, and an | |
202 | output string. The output buffer is for data results, | |
203 | the output string is for informative text. | |
204 | ||
205 | :param cmd: dict, from Ceph's cmdmap_t | |
206 | ||
207 | :return: 3-tuple of (int, str, str) | |
208 | """ | |
209 | ||
210 | # Should never get called if they didn't declare | |
211 | # any ``COMMANDS`` | |
212 | raise NotImplementedError() | |
213 | ||
31f18b77 FG |
214 | def get_mgr_id(self): |
215 | """ | |
216 | Retrieve the mgr id. | |
217 | ||
218 | :return: str | |
219 | """ | |
220 | return ceph_state.get_mgr_id() | |
221 | ||
7c673cae FG |
222 | def get_config(self, key): |
223 | """ | |
224 | Retrieve the value of a persistent configuration setting | |
225 | ||
226 | :param key: str | |
227 | :return: str | |
228 | """ | |
229 | return ceph_state.get_config(self._handle, key) | |
230 | ||
31f18b77 FG |
231 | def get_config_prefix(self, key_prefix): |
232 | """ | |
233 | Retrieve a dict of config values with the given prefix | |
234 | ||
235 | :param key_prefix: str | |
236 | :return: str | |
237 | """ | |
238 | return ceph_state.get_config_prefix(self._handle, key_prefix) | |
239 | ||
224ce89b WB |
240 | def get_localized_config(self, key, default=None): |
241 | """ | |
242 | Retrieve localized configuration for this ceph-mgr instance | |
243 | :param key: str | |
244 | :param default: str | |
245 | :return: str | |
246 | """ | |
247 | r = self.get_config(self.get_mgr_id() + '/' + key) | |
248 | if r is None: | |
249 | r = self.get_config(key) | |
250 | ||
251 | if r is None: | |
252 | r = default | |
253 | return r | |
254 | ||
7c673cae FG |
255 | def set_config(self, key, val): |
256 | """ | |
257 | Set the value of a persistent configuration setting | |
258 | ||
259 | :param key: str | |
260 | :param val: str | |
261 | """ | |
262 | ceph_state.set_config(self._handle, key, val) | |
263 | ||
224ce89b WB |
264 | def set_localized_config(self, key, val): |
265 | """ | |
266 | Set localized configuration for this ceph-mgr instance | |
267 | :param key: str | |
268 | :param default: str | |
269 | :return: str | |
270 | """ | |
271 | return self.set_config(self.get_mgr_id() + '/' + key, val) | |
272 | ||
7c673cae FG |
273 | def set_config_json(self, key, val): |
274 | """ | |
275 | Helper for setting json-serialized-config | |
276 | ||
277 | :param key: str | |
278 | :param val: json-serializable object | |
279 | """ | |
280 | self.set_config(key, json.dumps(val)) | |
281 | ||
282 | def get_config_json(self, key): | |
283 | """ | |
284 | Helper for getting json-serialized config | |
285 | ||
286 | :param key: str | |
287 | :return: object | |
288 | """ | |
289 | raw = self.get_config(key) | |
290 | if raw is None: | |
291 | return None | |
292 | else: | |
293 | return json.loads(raw) | |
224ce89b WB |
294 | |
295 | def self_test(self): | |
296 | """ | |
297 | Run a self-test on the module. Override this function and implement | |
298 | a best as possible self-test for (automated) testing of the module | |
299 | :return: bool | |
300 | """ | |
301 | pass |