9d732772d9c77167fde1297df2886ef87e0d1ab5
1 /**
2 * collectd - src/python.c
3 * Copyright (C) 2009 Sven Trenkel
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Sven Trenkel <collectd at semidefinite.de>
25 **/
27 #include <Python.h>
28 #include <structmember.h>
30 #include <signal.h>
31 #if HAVE_PTHREAD_H
32 # include <pthread.h>
33 #endif
35 #include "collectd.h"
36 #include "common.h"
38 #include "cpython.h"
40 typedef struct cpy_callback_s {
41 char *name;
42 PyObject *callback;
43 PyObject *data;
44 struct cpy_callback_s *next;
45 } cpy_callback_t;
47 static char log_doc[] = "This function sends a string to all logging plugins.";
49 static char get_ds_doc[] = "get_dataset(name) -> definition\n"
50 "\n"
51 "Returns the definition of a dataset specified by name.\n"
52 "\n"
53 "'name' is a string specifying the dataset to query.\n"
54 "'definition' is a list of 4-tuples. Every tuple represents a \n"
55 " data source within the data set and its 4 values are the \n"
56 " name, type, min and max value.\n"
57 " 'name' is a string.\n"
58 " 'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
59 " DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
60 " 'min' and 'max' are either a float or None.";
62 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
63 "\n"
64 "Flushes the cache of another plugin.";
66 static char unregister_doc[] = "Unregisters a callback. This function needs exactly one parameter either\n"
67 "the function to unregister or the callback identifier to unregister.";
69 static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifier\n"
70 "\n"
71 "Register a callback function for log messages.\n"
72 "\n"
73 "'callback' is a callable object that will be called every time something\n"
74 " is logged.\n"
75 "'data' is an optional object that will be passed back to the callback\n"
76 " function every time it is called.\n"
77 "'name' is an optional identifier for this callback. The default name\n"
78 " is 'python.<module>'.\n"
79 " Every callback needs a unique identifier, so if you want to\n"
80 " register this callback multiple time from the same module you need\n"
81 " to specify a name here.\n"
82 "'identifier' is the full identifier assigned to this callback.\n"
83 "\n"
84 "The callback function will be called with two or three parameters:\n"
85 "severity: An integer that should be compared to the LOG_ constants.\n"
86 "message: The text to be logged.\n"
87 "data: The optional data parameter passed to the register function.\n"
88 " If the parameter was omitted it will be omitted here, too.";
90 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
91 "\n"
92 "Register a callback function that will be executed once after the config.\n"
93 "file has been read, all plugins heve been loaded and the collectd has\n"
94 "forked into the background.\n"
95 "\n"
96 "'callback' is a callable object that will be executed.\n"
97 "'data' is an optional object that will be passed back to the callback\n"
98 " function when it is called.\n"
99 "'name' is an optional identifier for this callback. The default name\n"
100 " is 'python.<module>'.\n"
101 " Every callback needs a unique identifier, so if you want to\n"
102 " register this callback multiple time from the same module you need\n"
103 " to specify a name here.\n"
104 "'identifier' is the full identifier assigned to this callback.\n"
105 "\n"
106 "The callback function will be called without parameters, except for\n"
107 "data if it was supplied.";
109 static char reg_config_doc[] = "register_config(callback[, data][, name]) -> identifier\n"
110 "\n"
111 "Register a callback function for config file entries.\n"
112 "'callback' is a callable object that will be called for every config block.\n"
113 "'data' is an optional object that will be passed back to the callback\n"
114 " function every time it is called.\n"
115 "'name' is an optional identifier for this callback. The default name\n"
116 " is 'python.<module>'.\n"
117 " Every callback needs a unique identifier, so if you want to\n"
118 " register this callback multiple time from the same module you need\n"
119 " to specify a name here.\n"
120 "'identifier' is the full identifier assigned to this callback.\n"
121 "\n"
122 "The callback function will be called with one or two parameters:\n"
123 "config: A Config object.\n"
124 "data: The optional data parameter passed to the register function.\n"
125 " If the parameter was omitted it will be omitted here, too.";
127 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
128 "\n"
129 "Register a callback function for reading data. It will just be called\n"
130 "in a fixed interval to signal that it's time to dispatch new values.\n"
131 "'callback' is a callable object that will be called every time something\n"
132 " is logged.\n"
133 "'interval' is the number of seconds between between calls to the callback\n"
134 " function. Full float precision is supported here.\n"
135 "'data' is an optional object that will be passed back to the callback\n"
136 " function every time it is called.\n"
137 "'name' is an optional identifier for this callback. The default name\n"
138 " is 'python.<module>'.\n"
139 " Every callback needs a unique identifier, so if you want to\n"
140 " register this callback multiple time from the same module you need\n"
141 " to specify a name here.\n"
142 "'identifier' is the full identifier assigned to this callback.\n"
143 "\n"
144 "The callback function will be called without parameters, except for\n"
145 "data if it was supplied.";
147 static char reg_write_doc[] = "register_write(callback[, data][, name]) -> identifier\n"
148 "\n"
149 "Register a callback function to receive values dispatched by other plugins.\n"
150 "'callback' is a callable object that will be called every time a value\n"
151 " is dispatched.\n"
152 "'data' is an optional object that will be passed back to the callback\n"
153 " function every time it is called.\n"
154 "'name' is an optional identifier for this callback. The default name\n"
155 " is 'python.<module>'.\n"
156 " Every callback needs a unique identifier, so if you want to\n"
157 " register this callback multiple time from the same module you need\n"
158 " to specify a name here.\n"
159 "'identifier' is the full identifier assigned to this callback.\n"
160 "\n"
161 "The callback function will be called with one or two parameters:\n"
162 "values: A Values object which is a copy of the dispatched values.\n"
163 "data: The optional data parameter passed to the register function.\n"
164 " If the parameter was omitted it will be omitted here, too.";
166 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
167 "\n"
168 "Register a callback function for notifications.\n"
169 "'callback' is a callable object that will be called every time a notification\n"
170 " is dispatched.\n"
171 "'data' is an optional object that will be passed back to the callback\n"
172 " function every time it is called.\n"
173 "'name' is an optional identifier for this callback. The default name\n"
174 " is 'python.<module>'.\n"
175 " Every callback needs a unique identifier, so if you want to\n"
176 " register this callback multiple time from the same module you need\n"
177 " to specify a name here.\n"
178 "'identifier' is the full identifier assigned to this callback.\n"
179 "\n"
180 "The callback function will be called with one or two parameters:\n"
181 "notification: A copy of the notification that was dispatched.\n"
182 "data: The optional data parameter passed to the register function.\n"
183 " If the parameter was omitted it will be omitted here, too.";
185 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
186 "\n"
187 "Register a callback function for flush messages.\n"
188 "'callback' is a callable object that will be called every time a plugin\n"
189 " requests a flush for either this or all plugins.\n"
190 "'data' is an optional object that will be passed back to the callback\n"
191 " function every time it is called.\n"
192 "'name' is an optional identifier for this callback. The default name\n"
193 " is 'python.<module>'.\n"
194 " Every callback needs a unique identifier, so if you want to\n"
195 " register this callback multiple time from the same module you need\n"
196 " to specify a name here.\n"
197 "'identifier' is the full identifier assigned to this callback.\n"
198 "\n"
199 "The callback function will be called with two or three parameters:\n"
200 "timeout: Indicates that only data older than 'timeout' seconds is to\n"
201 " be flushed.\n"
202 "id: Specifies which values are to be flushed.\n"
203 "data: The optional data parameter passed to the register function.\n"
204 " If the parameter was omitted it will be omitted here, too.";
206 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
207 "\n"
208 "Register a callback function for collectd shutdown.\n"
209 "'callback' is a callable object that will be called once collectd is\n"
210 " shutting down.\n"
211 "'data' is an optional object that will be passed back to the callback\n"
212 " function if it is called.\n"
213 "'name' is an optional identifier for this callback. The default name\n"
214 " is 'python.<module>'.\n"
215 " Every callback needs a unique identifier, so if you want to\n"
216 " register this callback multiple time from the same module you need\n"
217 " to specify a name here.\n"
218 "'identifier' is the full identifier assigned to this callback.\n"
219 "\n"
220 "The callback function will be called with no parameters except for\n"
221 " data if it was supplied.";
224 static int do_interactive = 0;
226 /* This is our global thread state. Python saves some stuff in thread-local
227 * storage. So if we allow the interpreter to run in the background
228 * (the scriptwriters might have created some threads from python), we have
229 * to save the state so we can resume it later after shutdown. */
231 static PyThreadState *state;
233 static PyObject *sys_path, *cpy_format_exception;
235 static cpy_callback_t *cpy_config_callbacks;
236 static cpy_callback_t *cpy_init_callbacks;
237 static cpy_callback_t *cpy_shutdown_callbacks;
239 static void cpy_destroy_user_data(void *data) {
240 cpy_callback_t *c = data;
241 free(c->name);
242 Py_DECREF(c->callback);
243 Py_XDECREF(c->data);
244 free(c);
245 }
247 /* You must hold the GIL to call this function!
248 * But if you managed to extract the callback parameter then you probably already do. */
250 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
251 const char *module = NULL;
252 PyObject *mod = NULL;
254 if (name != NULL) {
255 snprintf(buf, size, "python.%s", name);
256 return;
257 }
259 mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
260 if (mod != NULL)
261 module = cpy_unicode_or_bytes_to_string(&mod);
263 if (module != NULL) {
264 snprintf(buf, size, "python.%s", module);
265 Py_XDECREF(mod);
266 PyErr_Clear();
267 return;
268 }
269 Py_XDECREF(mod);
271 snprintf(buf, size, "python.%p", callback);
272 PyErr_Clear();
273 }
275 void cpy_log_exception(const char *context) {
276 int l = 0, i;
277 const char *typename = NULL, *message = NULL;
278 PyObject *type, *value, *traceback, *tn, *m, *list;
280 PyErr_Fetch(&type, &value, &traceback);
281 PyErr_NormalizeException(&type, &value, &traceback);
282 if (type == NULL) return;
283 tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
284 m = PyObject_Str(value); /* New reference. */
285 if (tn != NULL)
286 typename = cpy_unicode_or_bytes_to_string(&tn);
287 if (m != NULL)
288 message = cpy_unicode_or_bytes_to_string(&m);
289 if (typename == NULL)
290 typename = "NamelessException";
291 if (message == NULL)
292 message = "N/A";
293 Py_BEGIN_ALLOW_THREADS
294 ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
295 Py_END_ALLOW_THREADS
296 Py_XDECREF(tn);
297 Py_XDECREF(m);
298 if (!cpy_format_exception || !traceback) {
299 PyErr_Clear();
300 Py_DECREF(type);
301 Py_XDECREF(value);
302 Py_XDECREF(traceback);
303 return;
304 }
305 list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. Steals references from "type", "value" and "traceback". */
306 if (list)
307 l = PyObject_Length(list);
309 for (i = 0; i < l; ++i) {
310 PyObject *line;
311 char const *msg;
312 char *cpy;
314 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
315 Py_INCREF(line);
317 msg = cpy_unicode_or_bytes_to_string(&line);
318 Py_DECREF(line);
319 if (msg == NULL)
320 continue;
322 cpy = strdup(msg);
323 if (cpy == NULL)
324 continue;
326 if (cpy[strlen(cpy) - 1] == '\n')
327 cpy[strlen(cpy) - 1] = 0;
329 Py_BEGIN_ALLOW_THREADS
330 ERROR("%s", cpy);
331 Py_END_ALLOW_THREADS
333 free(cpy);
334 }
336 Py_XDECREF(list);
337 PyErr_Clear();
338 }
340 static int cpy_read_callback(user_data_t *data) {
341 cpy_callback_t *c = data->data;
342 PyObject *ret;
344 CPY_LOCK_THREADS
345 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
346 if (ret == NULL) {
347 cpy_log_exception("read callback");
348 } else {
349 Py_DECREF(ret);
350 }
351 CPY_RELEASE_THREADS
352 if (ret == NULL)
353 return 1;
354 return 0;
355 }
357 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
358 int i;
359 cpy_callback_t *c = data->data;
360 PyObject *ret, *list, *temp, *dict = NULL;
361 Values *v;
363 CPY_LOCK_THREADS
364 list = PyList_New(value_list->values_len); /* New reference. */
365 if (list == NULL) {
366 cpy_log_exception("write callback");
367 CPY_RETURN_FROM_THREADS 0;
368 }
369 for (i = 0; i < value_list->values_len; ++i) {
370 if (ds->ds[i].type == DS_TYPE_COUNTER) {
371 if ((long) value_list->values[i].counter == value_list->values[i].counter)
372 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
373 else
374 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
375 } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
376 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
377 } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
378 if ((long) value_list->values[i].derive == value_list->values[i].derive)
379 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
380 else
381 PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
382 } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
383 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
384 PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
385 else
386 PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
387 } else {
388 Py_BEGIN_ALLOW_THREADS
389 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
390 Py_END_ALLOW_THREADS
391 Py_DECREF(list);
392 CPY_RETURN_FROM_THREADS 0;
393 }
394 if (PyErr_Occurred() != NULL) {
395 cpy_log_exception("value building for write callback");
396 Py_DECREF(list);
397 CPY_RETURN_FROM_THREADS 0;
398 }
399 }
400 dict = PyDict_New(); /* New reference. */
401 if (value_list->meta) {
402 int num;
403 char **table;
404 meta_data_t *meta = value_list->meta;
406 num = meta_data_toc(meta, &table);
407 for (i = 0; i < num; ++i) {
408 int type;
409 char *string;
410 int64_t si;
411 uint64_t ui;
412 double d;
413 _Bool b;
415 type = meta_data_type(meta, table[i]);
416 if (type == MD_TYPE_STRING) {
417 if (meta_data_get_string(meta, table[i], &string))
418 continue;
419 temp = cpy_string_to_unicode_or_bytes(string); /* New reference. */
420 free(string);
421 PyDict_SetItemString(dict, table[i], temp);
422 Py_XDECREF(temp);
423 } else if (type == MD_TYPE_SIGNED_INT) {
424 if (meta_data_get_signed_int(meta, table[i], &si))
425 continue;
426 temp = PyObject_CallFunctionObjArgs((void *) &SignedType, PyLong_FromLongLong(si), (void *) 0); /* New reference. */
427 PyDict_SetItemString(dict, table[i], temp);
428 Py_XDECREF(temp);
429 } else if (type == MD_TYPE_UNSIGNED_INT) {
430 if (meta_data_get_unsigned_int(meta, table[i], &ui))
431 continue;
432 temp = PyObject_CallFunctionObjArgs((void *) &UnsignedType, PyLong_FromUnsignedLongLong(ui), (void *) 0); /* New reference. */
433 PyDict_SetItemString(dict, table[i], temp);
434 Py_XDECREF(temp);
435 } else if (type == MD_TYPE_DOUBLE) {
436 if (meta_data_get_double(meta, table[i], &d))
437 continue;
438 temp = PyFloat_FromDouble(d); /* New reference. */
439 PyDict_SetItemString(dict, table[i], temp);
440 Py_XDECREF(temp);
441 } else if (type == MD_TYPE_BOOLEAN) {
442 if (meta_data_get_boolean(meta, table[i], &b))
443 continue;
444 if (b)
445 PyDict_SetItemString(dict, table[i], Py_True);
446 else
447 PyDict_SetItemString(dict, table[i], Py_False);
448 }
449 free(table[i]);
450 }
451 free(table);
452 }
453 v = (Values *) Values_New(); /* New reference. */
454 sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
455 sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
456 sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance));
457 sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
458 sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance));
459 v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
460 v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
461 Py_CLEAR(v->values);
462 v->values = list;
463 Py_CLEAR(v->meta);
464 v->meta = dict; /* Steals a reference. */
465 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
466 Py_XDECREF(v);
467 if (ret == NULL) {
468 cpy_log_exception("write callback");
469 } else {
470 Py_DECREF(ret);
471 }
472 CPY_RELEASE_THREADS
473 return 0;
474 }
476 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
477 cpy_callback_t *c = data->data;
478 PyObject *ret, *notify;
479 Notification *n;
481 CPY_LOCK_THREADS
482 notify = Notification_New(); /* New reference. */
483 n = (Notification *) notify;
484 sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
485 sstrncpy(n->data.type, notification->type, sizeof(n->data.type));
486 sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance));
487 sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
488 sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance));
489 n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
490 sstrncpy(n->message, notification->message, sizeof(n->message));
491 n->severity = notification->severity;
492 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
493 Py_XDECREF(notify);
494 if (ret == NULL) {
495 cpy_log_exception("notification callback");
496 } else {
497 Py_DECREF(ret);
498 }
499 CPY_RELEASE_THREADS
500 return 0;
501 }
503 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
504 cpy_callback_t * c = data->data;
505 PyObject *ret, *text;
507 CPY_LOCK_THREADS
508 text = cpy_string_to_unicode_or_bytes(message); /* New reference. */
509 if (c->data == NULL)
510 ret = PyObject_CallFunction(c->callback, "iN", severity, text); /* New reference. Steals a reference from "text". */
511 else
512 ret = PyObject_CallFunction(c->callback, "iNO", severity, text, c->data); /* New reference. Steals a reference from "text". */
514 if (ret == NULL) {
515 /* FIXME */
516 /* Do we really want to trigger a log callback because a log callback failed?
517 * Probably not. */
518 PyErr_Print();
519 /* In case someone wanted to be clever, replaced stderr and failed at that. */
520 PyErr_Clear();
521 } else {
522 Py_DECREF(ret);
523 }
524 CPY_RELEASE_THREADS
525 }
527 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
528 cpy_callback_t * c = data->data;
529 PyObject *ret, *text;
531 CPY_LOCK_THREADS
532 text = cpy_string_to_unicode_or_bytes(id);
533 if (c->data == NULL)
534 ret = PyObject_CallFunction(c->callback, "iN", timeout, text); /* New reference. */
535 else
536 ret = PyObject_CallFunction(c->callback, "iNO", timeout, text, c->data); /* New reference. */
538 if (ret == NULL) {
539 cpy_log_exception("flush callback");
540 } else {
541 Py_DECREF(ret);
542 }
543 CPY_RELEASE_THREADS
544 }
546 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
547 char buf[512];
548 cpy_callback_t *c;
549 char *name = NULL;
550 PyObject *callback = NULL, *data = NULL, *mod = NULL;
551 static char *kwlist[] = {"callback", "data", "name", NULL};
553 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
554 if (PyCallable_Check(callback) == 0) {
555 PyMem_Free(name);
556 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
557 return NULL;
558 }
559 cpy_build_name(buf, sizeof(buf), callback, name);
561 Py_INCREF(callback);
562 Py_XINCREF(data);
564 c = malloc(sizeof(*c));
565 if (c == NULL)
566 return NULL;
567 memset (c, 0, sizeof (*c));
569 c->name = strdup(buf);
570 c->callback = callback;
571 c->data = data;
572 c->next = *list_head;
573 *list_head = c;
574 Py_XDECREF(mod);
575 PyMem_Free(name);
576 return cpy_string_to_unicode_or_bytes(buf);
577 }
579 static PyObject *float_or_none(float number) {
580 if (isnan(number)) {
581 Py_RETURN_NONE;
582 }
583 return PyFloat_FromDouble(number);
584 }
586 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
587 int i;
588 char *name;
589 const data_set_t *ds;
590 PyObject *list, *tuple;
592 if (PyArg_ParseTuple(args, "et", NULL, &name) == 0) return NULL;
593 ds = plugin_get_ds(name);
594 PyMem_Free(name);
595 if (ds == NULL) {
596 PyErr_Format(PyExc_TypeError, "Dataset %s not found", name);
597 return NULL;
598 }
599 list = PyList_New(ds->ds_num); /* New reference. */
600 for (i = 0; i < ds->ds_num; ++i) {
601 tuple = PyTuple_New(4);
602 PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name));
603 PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes(DS_TYPE_TO_STRING(ds->ds[i].type)));
604 PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
605 PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
606 PyList_SET_ITEM(list, i, tuple);
607 }
608 return list;
609 }
611 static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
612 int timeout = -1;
613 char *plugin = NULL, *identifier = NULL;
614 static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
616 if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin, &timeout, NULL, &identifier) == 0) return NULL;
617 Py_BEGIN_ALLOW_THREADS
618 plugin_flush(plugin, timeout, identifier);
619 Py_END_ALLOW_THREADS
620 PyMem_Free(plugin);
621 PyMem_Free(identifier);
622 Py_RETURN_NONE;
623 }
625 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
626 return cpy_register_generic(&cpy_config_callbacks, args, kwds);
627 }
629 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
630 return cpy_register_generic(&cpy_init_callbacks, args, kwds);
631 }
633 typedef int reg_function_t(const char *name, void *callback, void *data);
635 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
636 char buf[512];
637 reg_function_t *register_function = (reg_function_t *) reg;
638 cpy_callback_t *c = NULL;
639 user_data_t user_data;
640 char *name = NULL;
641 PyObject *callback = NULL, *data = NULL;
642 static char *kwlist[] = {"callback", "data", "name", NULL};
644 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
645 if (PyCallable_Check(callback) == 0) {
646 PyMem_Free(name);
647 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
648 return NULL;
649 }
650 cpy_build_name(buf, sizeof(buf), callback, name);
651 PyMem_Free(name);
653 Py_INCREF(callback);
654 Py_XINCREF(data);
656 c = malloc(sizeof(*c));
657 if (c == NULL)
658 return NULL;
659 memset (c, 0, sizeof (*c));
661 c->name = strdup(buf);
662 c->callback = callback;
663 c->data = data;
664 c->next = NULL;
666 memset (&user_data, 0, sizeof (user_data));
667 user_data.free_func = cpy_destroy_user_data;
668 user_data.data = c;
670 register_function(buf, handler, &user_data);
671 return cpy_string_to_unicode_or_bytes(buf);
672 }
674 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
675 char buf[512];
676 cpy_callback_t *c = NULL;
677 user_data_t user_data;
678 double interval = 0;
679 char *name = NULL;
680 PyObject *callback = NULL, *data = NULL;
681 struct timespec ts;
682 static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
684 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
685 if (PyCallable_Check(callback) == 0) {
686 PyMem_Free(name);
687 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
688 return NULL;
689 }
690 cpy_build_name(buf, sizeof(buf), callback, name);
691 PyMem_Free(name);
693 Py_INCREF(callback);
694 Py_XINCREF(data);
696 c = malloc(sizeof(*c));
697 if (c == NULL)
698 return NULL;
699 memset (c, 0, sizeof (*c));
701 c->name = strdup(buf);
702 c->callback = callback;
703 c->data = data;
704 c->next = NULL;
706 memset (&user_data, 0, sizeof (user_data));
707 user_data.free_func = cpy_destroy_user_data;
708 user_data.data = c;
710 ts.tv_sec = interval;
711 ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
712 plugin_register_complex_read(/* group = */ "python", buf,
713 cpy_read_callback, &ts, &user_data);
715 return cpy_string_to_unicode_or_bytes(buf);
716 }
718 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
719 return cpy_register_generic_userdata((void *) plugin_register_log,
720 (void *) cpy_log_callback, args, kwds);
721 }
723 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
724 return cpy_register_generic_userdata((void *) plugin_register_write,
725 (void *) cpy_write_callback, args, kwds);
726 }
728 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
729 return cpy_register_generic_userdata((void *) plugin_register_notification,
730 (void *) cpy_notification_callback, args, kwds);
731 }
733 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
734 return cpy_register_generic_userdata((void *) plugin_register_flush,
735 (void *) cpy_flush_callback, args, kwds);
736 }
738 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
739 return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
740 }
742 static PyObject *cpy_error(PyObject *self, PyObject *args) {
743 char *text;
744 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
745 Py_BEGIN_ALLOW_THREADS
746 plugin_log(LOG_ERR, "%s", text);
747 Py_END_ALLOW_THREADS
748 PyMem_Free(text);
749 Py_RETURN_NONE;
750 }
752 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
753 char *text;
754 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
755 Py_BEGIN_ALLOW_THREADS
756 plugin_log(LOG_WARNING, "%s", text);
757 Py_END_ALLOW_THREADS
758 PyMem_Free(text);
759 Py_RETURN_NONE;
760 }
762 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
763 char *text;
764 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
765 Py_BEGIN_ALLOW_THREADS
766 plugin_log(LOG_NOTICE, "%s", text);
767 Py_END_ALLOW_THREADS
768 PyMem_Free(text);
769 Py_RETURN_NONE;
770 }
772 static PyObject *cpy_info(PyObject *self, PyObject *args) {
773 char *text;
774 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
775 Py_BEGIN_ALLOW_THREADS
776 plugin_log(LOG_INFO, "%s", text);
777 Py_END_ALLOW_THREADS
778 PyMem_Free(text);
779 Py_RETURN_NONE;
780 }
782 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
783 #ifdef COLLECT_DEBUG
784 char *text;
785 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
786 Py_BEGIN_ALLOW_THREADS
787 plugin_log(LOG_DEBUG, "%s", text);
788 Py_END_ALLOW_THREADS
789 PyMem_Free(text);
790 #endif
791 Py_RETURN_NONE;
792 }
794 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
795 char buf[512];
796 const char *name;
797 cpy_callback_t *prev = NULL, *tmp;
799 Py_INCREF(arg);
800 name = cpy_unicode_or_bytes_to_string(&arg);
801 if (name == NULL) {
802 PyErr_Clear();
803 if (!PyCallable_Check(arg)) {
804 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
805 Py_DECREF(arg);
806 return NULL;
807 }
808 cpy_build_name(buf, sizeof(buf), arg, NULL);
809 name = buf;
810 }
811 for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
812 if (strcmp(name, tmp->name) == 0)
813 break;
815 Py_DECREF(arg);
816 if (tmp == NULL) {
817 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
818 return NULL;
819 }
820 /* Yes, this is actually save. To call this function the caller has to
821 * hold the GIL. Well, save as long as there is only one GIL anyway ... */
822 if (prev == NULL)
823 *list_head = tmp->next;
824 else
825 prev->next = tmp->next;
826 cpy_destroy_user_data(tmp);
827 Py_RETURN_NONE;
828 }
830 typedef int cpy_unregister_function_t(const char *name);
832 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
833 char buf[512];
834 const char *name;
836 Py_INCREF(arg);
837 name = cpy_unicode_or_bytes_to_string(&arg);
838 if (name == NULL) {
839 PyErr_Clear();
840 if (!PyCallable_Check(arg)) {
841 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
842 Py_DECREF(arg);
843 return NULL;
844 }
845 cpy_build_name(buf, sizeof(buf), arg, NULL);
846 name = buf;
847 }
848 if (unreg(name) == 0) {
849 Py_DECREF(arg);
850 Py_RETURN_NONE;
851 }
852 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
853 Py_DECREF(arg);
854 return NULL;
855 }
857 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
858 return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
859 }
861 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
862 return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
863 }
865 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
866 return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
867 }
869 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
870 return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
871 }
873 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
874 return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
875 }
877 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
878 return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
879 }
881 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
882 return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
883 }
885 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
886 return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
887 }
889 static PyMethodDef cpy_methods[] = {
890 {"debug", cpy_debug, METH_VARARGS, log_doc},
891 {"info", cpy_info, METH_VARARGS, log_doc},
892 {"notice", cpy_notice, METH_VARARGS, log_doc},
893 {"warning", cpy_warning, METH_VARARGS, log_doc},
894 {"error", cpy_error, METH_VARARGS, log_doc},
895 {"get_dataset", (PyCFunction) cpy_get_dataset, METH_VARARGS, get_ds_doc},
896 {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
897 {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
898 {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
899 {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
900 {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
901 {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
902 {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
903 {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
904 {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
905 {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
906 {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
907 {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
908 {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
909 {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
910 {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
911 {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
912 {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
913 {0, 0, 0, 0}
914 };
916 static int cpy_shutdown(void) {
917 cpy_callback_t *c;
918 PyObject *ret;
920 /* This can happen if the module was loaded but not configured. */
921 if (state != NULL)
922 PyEval_RestoreThread(state);
924 for (c = cpy_shutdown_callbacks; c; c = c->next) {
925 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
926 if (ret == NULL)
927 cpy_log_exception("shutdown callback");
928 else
929 Py_DECREF(ret);
930 }
931 PyErr_Print();
932 Py_Finalize();
933 return 0;
934 }
936 static void cpy_int_handler(int sig) {
937 return;
938 }
940 static void *cpy_interactive(void *data) {
941 sigset_t sigset;
942 struct sigaction sig_int_action, old;
944 /* Signal handler in a plugin? Bad stuff, but the best way to
945 * handle it I guess. In an interactive session people will
946 * press Ctrl+C at some time, which will generate a SIGINT.
947 * This will cause collectd to shutdown, thus killing the
948 * interactive interpreter, and leaving the terminal in a
949 * mess. Chances are, this isn't what the user wanted to do.
950 *
951 * So this is the plan:
952 * 1. Block SIGINT in the main thread.
953 * 2. Install our own signal handler that does nothing.
954 * 3. Unblock SIGINT in the interactive thread.
955 *
956 * This will make sure that SIGINT won't kill collectd but
957 * still interrupt syscalls like sleep and pause.
958 * It does not raise a KeyboardInterrupt exception because so
959 * far nobody managed to figure out how to do that. */
960 memset (&sig_int_action, '\0', sizeof (sig_int_action));
961 sig_int_action.sa_handler = cpy_int_handler;
962 sigaction (SIGINT, &sig_int_action, &old);
964 sigemptyset(&sigset);
965 sigaddset(&sigset, SIGINT);
966 pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
967 PyEval_AcquireThread(state);
968 if (PyImport_ImportModule("readline") == NULL) {
969 /* This interactive session will suck. */
970 cpy_log_exception("interactive session init");
971 }
972 PyRun_InteractiveLoop(stdin, "<stdin>");
973 PyErr_Print();
974 PyEval_ReleaseThread(state);
975 NOTICE("python: Interactive interpreter exited, stopping collectd ...");
976 /* Restore the original collectd SIGINT handler and raise SIGINT.
977 * The main thread still has SIGINT blocked and there's nothing we
978 * can do about that so this thread will handle it. But that's not
979 * important, except that it won't interrupt the main loop and so
980 * it might take a few seconds before collectd really shuts down. */
981 sigaction (SIGINT, &old, NULL);
982 raise(SIGINT);
983 pause();
984 return NULL;
985 }
987 static int cpy_init(void) {
988 cpy_callback_t *c;
989 PyObject *ret;
990 static pthread_t thread;
991 sigset_t sigset;
993 if (!Py_IsInitialized()) {
994 WARNING("python: Plugin loaded but not configured.");
995 plugin_unregister_shutdown("python");
996 return 0;
997 }
998 PyEval_InitThreads();
999 /* Now it's finally OK to use python threads. */
1000 for (c = cpy_init_callbacks; c; c = c->next) {
1001 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
1002 if (ret == NULL)
1003 cpy_log_exception("init callback");
1004 else
1005 Py_DECREF(ret);
1006 }
1007 sigemptyset(&sigset);
1008 sigaddset(&sigset, SIGINT);
1009 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1010 state = PyEval_SaveThread();
1011 if (do_interactive) {
1012 if (plugin_thread_create(&thread, NULL, cpy_interactive, NULL)) {
1013 ERROR("python: Error creating thread for interactive interpreter.");
1014 }
1015 }
1017 return 0;
1018 }
1020 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
1021 int i;
1022 PyObject *item, *values, *children, *tmp;
1024 if (parent == NULL)
1025 parent = Py_None;
1027 values = PyTuple_New(ci->values_num); /* New reference. */
1028 for (i = 0; i < ci->values_num; ++i) {
1029 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
1030 PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
1031 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
1032 PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
1033 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
1034 PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
1035 }
1036 }
1038 tmp = cpy_string_to_unicode_or_bytes(ci->key);
1039 item = PyObject_CallFunction((void *) &ConfigType, "NONO", tmp, parent, values, Py_None);
1040 if (item == NULL)
1041 return NULL;
1042 children = PyTuple_New(ci->children_num); /* New reference. */
1043 for (i = 0; i < ci->children_num; ++i) {
1044 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
1045 }
1046 tmp = ((Config *) item)->children;
1047 ((Config *) item)->children = children;
1048 Py_XDECREF(tmp);
1049 return item;
1050 }
1052 #ifdef IS_PY3K
1053 static struct PyModuleDef collectdmodule = {
1054 PyModuleDef_HEAD_INIT,
1055 "collectd", /* name of module */
1056 "The python interface to collectd", /* module documentation, may be NULL */
1057 -1,
1058 cpy_methods
1059 };
1061 PyMODINIT_FUNC PyInit_collectd(void) {
1062 return PyModule_Create(&collectdmodule);
1063 }
1064 #endif
1066 static int cpy_init_python() {
1067 PyObject *sys;
1068 PyObject *module;
1070 #ifdef IS_PY3K
1071 wchar_t *argv = L"";
1072 /* Add a builtin module, before Py_Initialize */
1073 PyImport_AppendInittab("collectd", PyInit_collectd);
1074 #else
1075 char *argv = "";
1076 #endif
1078 Py_Initialize();
1080 PyType_Ready(&ConfigType);
1081 PyType_Ready(&PluginDataType);
1082 ValuesType.tp_base = &PluginDataType;
1083 PyType_Ready(&ValuesType);
1084 NotificationType.tp_base = &PluginDataType;
1085 PyType_Ready(&NotificationType);
1086 SignedType.tp_base = &PyLong_Type;
1087 PyType_Ready(&SignedType);
1088 UnsignedType.tp_base = &PyLong_Type;
1089 PyType_Ready(&UnsignedType);
1090 sys = PyImport_ImportModule("sys"); /* New reference. */
1091 if (sys == NULL) {
1092 cpy_log_exception("python initialization");
1093 return 1;
1094 }
1095 sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1096 Py_DECREF(sys);
1097 if (sys_path == NULL) {
1098 cpy_log_exception("python initialization");
1099 return 1;
1100 }
1101 PySys_SetArgv(1, &argv);
1102 PyList_SetSlice(sys_path, 0, 1, NULL);
1104 #ifdef IS_PY3K
1105 module = PyImport_ImportModule("collectd");
1106 #else
1107 module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1108 #endif
1109 PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
1110 PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
1111 PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
1112 PyModule_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */
1113 PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */
1114 PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1115 PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1116 PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1117 PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1118 PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1119 PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1120 PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1121 PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1122 PyModule_AddStringConstant(module, "DS_TYPE_COUNTER", DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1123 PyModule_AddStringConstant(module, "DS_TYPE_GAUGE", DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1124 PyModule_AddStringConstant(module, "DS_TYPE_DERIVE", DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1125 PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE", DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1126 return 0;
1127 }
1129 static int cpy_config(oconfig_item_t *ci) {
1130 int i;
1131 PyObject *tb;
1133 /* Ok in theory we shouldn't do initialization at this point
1134 * but we have to. In order to give python scripts a chance
1135 * to register a config callback we need to be able to execute
1136 * python code during the config callback so we have to start
1137 * the interpreter here. */
1138 /* Do *not* use the python "thread" module at this point! */
1140 if (!Py_IsInitialized() && cpy_init_python()) return 1;
1142 for (i = 0; i < ci->children_num; ++i) {
1143 oconfig_item_t *item = ci->children + i;
1145 if (strcasecmp(item->key, "Interactive") == 0) {
1146 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1147 continue;
1148 do_interactive = item->values[0].value.boolean;
1149 } else if (strcasecmp(item->key, "Encoding") == 0) {
1150 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
1151 continue;
1152 #ifdef IS_PY3K
1153 NOTICE("python: \"Encoding\" was used in the config file but Python3 was used, which does not support changing encodings. Ignoring this.");
1154 #else
1155 /* Why is this even necessary? And undocumented? */
1156 if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
1157 cpy_log_exception("setting default encoding");
1158 #endif
1159 } else if (strcasecmp(item->key, "LogTraces") == 0) {
1160 if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1161 continue;
1162 if (!item->values[0].value.boolean) {
1163 Py_XDECREF(cpy_format_exception);
1164 cpy_format_exception = NULL;
1165 continue;
1166 }
1167 if (cpy_format_exception)
1168 continue;
1169 tb = PyImport_ImportModule("traceback"); /* New reference. */
1170 if (tb == NULL) {
1171 cpy_log_exception("python initialization");
1172 continue;
1173 }
1174 cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1175 Py_DECREF(tb);
1176 if (cpy_format_exception == NULL)
1177 cpy_log_exception("python initialization");
1178 } else if (strcasecmp(item->key, "ModulePath") == 0) {
1179 char *dir = NULL;
1180 PyObject *dir_object;
1182 if (cf_util_get_string(item, &dir) != 0)
1183 continue;
1184 dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1185 if (dir_object == NULL) {
1186 ERROR("python plugin: Unable to convert \"%s\" to "
1187 "a python object.", dir);
1188 free(dir);
1189 cpy_log_exception("python initialization");
1190 continue;
1191 }
1192 if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1193 ERROR("python plugin: Unable to prepend \"%s\" to "
1194 "python module path.", dir);
1195 cpy_log_exception("python initialization");
1196 }
1197 Py_DECREF(dir_object);
1198 free(dir);
1199 } else if (strcasecmp(item->key, "Import") == 0) {
1200 char *module_name = NULL;
1201 PyObject *module;
1203 if (cf_util_get_string(item, &module_name) != 0)
1204 continue;
1205 module = PyImport_ImportModule(module_name); /* New reference. */
1206 if (module == NULL) {
1207 ERROR("python plugin: Error importing module \"%s\".", module_name);
1208 cpy_log_exception("importing module");
1209 }
1210 free(module_name);
1211 Py_XDECREF(module);
1212 } else if (strcasecmp(item->key, "Module") == 0) {
1213 char *name = NULL;
1214 cpy_callback_t *c;
1215 PyObject *ret;
1217 if (cf_util_get_string(item, &name) != 0)
1218 continue;
1219 for (c = cpy_config_callbacks; c; c = c->next) {
1220 if (strcasecmp(c->name + 7, name) == 0)
1221 break;
1222 }
1223 if (c == NULL) {
1224 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1225 "but the plugin isn't loaded or didn't register "
1226 "a configuration callback.", name);
1227 free(name);
1228 continue;
1229 }
1230 free(name);
1231 if (c->data == NULL)
1232 ret = PyObject_CallFunction(c->callback, "N",
1233 cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1234 else
1235 ret = PyObject_CallFunction(c->callback, "NO",
1236 cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
1237 if (ret == NULL)
1238 cpy_log_exception("loading module");
1239 else
1240 Py_DECREF(ret);
1241 } else {
1242 WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
1243 }
1244 }
1245 return 0;
1246 }
1248 void module_register(void) {
1249 plugin_register_complex_config("python", cpy_config);
1250 plugin_register_init("python", cpy_init);
1251 plugin_register_shutdown("python", cpy_shutdown);
1252 }