1 /**
2 * collection4 - graph_instance.c
3 * Copyright (C) 2010 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
19 *
20 * Authors:
21 * Florian octo Forster <ff at octo.it>
22 **/
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <assert.h>
30 #include "graph_instance.h"
31 #include "graph.h"
32 #include "graph_def.h"
33 #include "graph_ident.h"
34 #include "graph_list.h"
35 #include "common.h"
36 #include "utils_cgi.h"
38 #include <fcgiapp.h>
39 #include <fcgi_stdio.h>
41 struct graph_instance_s /* {{{ */
42 {
43 graph_ident_t *select;
45 graph_ident_t **files;
46 size_t files_num;
47 }; /* }}} struct graph_instance_s */
49 struct def_callback_data_s
50 {
51 graph_instance_t *inst;
52 rrd_args_t *args;
53 };
54 typedef struct def_callback_data_s def_callback_data_t;
56 /*
57 * Private functions
58 */
59 /* Create one DEF for each data source in the file. Called by
60 * "inst_get_default_defs" for each file. */
61 static graph_def_t *ident_get_default_defs (graph_config_t *cfg, /* {{{ */
62 graph_ident_t *ident, graph_def_t *def_head)
63 {
64 graph_def_t *defs = NULL;
65 char *file;
66 char **dses = NULL;
67 size_t dses_num = 0;
68 int status;
69 size_t i;
71 if ((cfg == NULL) || (ident == NULL))
72 return (def_head);
74 file = ident_to_file (ident);
75 if (file == NULL)
76 {
77 fprintf (stderr, "ident_get_default_defs: ident_to_file failed\n");
78 return (def_head);
79 }
81 status = ds_list_from_rrd_file (file, &dses_num, &dses);
82 if (status != 0)
83 {
84 free (file);
85 return (def_head);
86 }
88 for (i = 0; i < dses_num; i++)
89 {
90 graph_def_t *def;
92 def = def_search (def_head, ident, dses[i]);
93 if (def != NULL)
94 continue;
96 def = def_create (cfg, ident, dses[i]);
97 if (def == NULL)
98 continue;
100 if (defs == NULL)
101 defs = def;
102 else
103 def_append (defs, def);
105 free (dses[i]);
106 }
108 free (dses);
109 free (file);
111 return (defs);
112 } /* }}} int ident_get_default_defs */
114 /* Create one or more DEFs for each file in the graph instance. The number
115 * depends on the number of data sources in each of the files. Called from
116 * "inst_get_rrdargs" if no DEFs are available from the configuration.
117 * */
118 static graph_def_t *inst_get_default_defs (graph_config_t *cfg, /* {{{ */
119 graph_instance_t *inst)
120 {
121 graph_def_t *defs = NULL;
122 size_t i;
124 if ((cfg == NULL) || (inst == NULL))
125 return (NULL);
127 for (i = 0; i < inst->files_num; i++)
128 {
129 graph_def_t *def;
131 def = ident_get_default_defs (cfg, inst->files[i], defs);
132 if (def == NULL)
133 continue;
135 if (defs == NULL)
136 defs = def;
137 else
138 def_append (defs, def);
139 }
141 return (defs);
142 } /* }}} graph_def_t *inst_get_default_defs */
144 /* Called with each DEF in turn. Calls "def_get_rrdargs" with every appropriate
145 * file / DEF pair. */
146 static int gl_instance_get_rrdargs_cb (graph_def_t *def, void *user_data) /* {{{ */
147 {
148 def_callback_data_t *data = user_data;
149 graph_instance_t *inst = data->inst;
150 rrd_args_t *args = data->args;
152 size_t i;
153 int status;
155 for (i = 0; i < inst->files_num; i++)
156 {
157 if (!def_matches (def, inst->files[i]))
158 continue;
160 status = def_get_rrdargs (def, inst->files[i], args);
161 if (status != 0)
162 {
163 fprintf (stderr, "gl_instance_get_rrdargs_cb: def_get_rrdargs failed with status %i\n",
164 status);
165 fflush (stderr);
166 }
167 }
169 return (0);
170 } /* }}} int gl_instance_get_rrdargs_cb */
172 static const char *get_part_from_param (const char *prim_key, /* {{{ */
173 const char *sec_key)
174 {
175 const char *val;
177 val = param (prim_key);
178 if (val != NULL)
179 return (val);
181 return (param (sec_key));
182 } /* }}} const char *get_part_from_param */
184 static graph_ident_t *inst_get_selector_from_params (void) /* {{{ */
185 {
186 const char *host = get_part_from_param ("inst_host", "host");
187 const char *plugin = get_part_from_param ("inst_plugin", "plugin");
188 const char *plugin_instance = get_part_from_param ("inst_plugin_instance",
189 "plugin_instance");
190 const char *type = get_part_from_param ("inst_type", "type");
191 const char *type_instance = get_part_from_param ("inst_type_instance",
192 "type_instance");
194 graph_ident_t *ident;
196 if ((host == NULL)
197 || (plugin == NULL) || (plugin_instance == NULL)
198 || (type == NULL) || (type_instance == NULL))
199 {
200 fprintf (stderr, "inst_get_selected: A parameter is NULL\n");
201 return (NULL);
202 }
204 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
205 if (ident == NULL)
206 {
207 fprintf (stderr, "inst_get_selected: ident_create failed\n");
208 return (NULL);
209 }
211 return (ident);
212 } /* }}} graph_ident_t *inst_get_selector_from_params */
214 /*
215 * Public functions
216 */
217 graph_instance_t *inst_create (graph_config_t *cfg, /* {{{ */
218 const graph_ident_t *ident)
219 {
220 graph_instance_t *i;
221 graph_ident_t *selector;
223 if ((cfg == NULL) || (ident == NULL))
224 return (NULL);
226 i = malloc (sizeof (*i));
227 if (i == NULL)
228 return (NULL);
229 memset (i, 0, sizeof (*i));
231 selector = graph_get_selector (cfg);
232 if (selector == NULL)
233 {
234 fprintf (stderr, "inst_create: graph_get_selector failed\n");
235 free (i);
236 return (NULL);
237 }
239 i->select = ident_copy_with_selector (selector, ident,
240 IDENT_FLAG_REPLACE_ANY);
241 if (i->select == NULL)
242 {
243 fprintf (stderr, "inst_create: ident_copy_with_selector failed\n");
244 ident_destroy (selector);
245 free (i);
246 return (NULL);
247 }
249 ident_destroy (selector);
251 i->files = NULL;
252 i->files_num = 0;
254 return (i);
255 } /* }}} graph_instance_t *inst_create */
257 void inst_destroy (graph_instance_t *inst) /* {{{ */
258 {
259 size_t i;
261 if (inst == NULL)
262 return;
264 ident_destroy (inst->select);
266 for (i = 0; i < inst->files_num; i++)
267 ident_destroy (inst->files[i]);
268 free (inst->files);
270 free (inst);
271 } /* }}} void inst_destroy */
273 int inst_add_file (graph_instance_t *inst, /* {{{ */
274 const graph_ident_t *file)
275 {
276 graph_ident_t **tmp;
278 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
279 if (tmp == NULL)
280 return (ENOMEM);
281 inst->files = tmp;
283 inst->files[inst->files_num] = ident_clone (file);
284 if (inst->files[inst->files_num] == NULL)
285 return (ENOMEM);
287 inst->files_num++;
289 return (0);
290 } /* }}} int inst_add_file */
292 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
293 {
294 graph_ident_t *ident;
295 graph_instance_t *inst;
297 if (cfg == NULL)
298 cfg = gl_graph_get_selected ();
300 if (cfg == NULL)
301 {
302 DEBUG ("inst_get_selected: cfg == NULL;\n");
303 return (NULL);
304 }
306 ident = inst_get_selector_from_params ();
307 if (ident == NULL)
308 {
309 fprintf (stderr, "inst_get_selected: ident_create failed\n");
310 return (NULL);
311 }
313 inst = graph_inst_find_exact (cfg, ident);
315 ident_destroy (ident);
316 return (inst);
317 } /* }}} graph_instance_t *inst_get_selected */
319 int inst_get_all_selected (graph_config_t *cfg, /* {{{ */
320 graph_inst_callback_t callback, void *user_data)
321 {
322 graph_ident_t *ident;
323 int status;
325 if ((cfg == NULL) || (callback == NULL))
326 return (EINVAL);
328 ident = inst_get_selector_from_params ();
329 if (ident == NULL)
330 {
331 fprintf (stderr, "inst_get_all_selected: "
332 "inst_get_selector_from_params failed\n");
333 return (EINVAL);
334 }
336 status = graph_inst_find_all_matching (cfg, ident, callback, user_data);
338 ident_destroy (ident);
339 return (status);
340 } /* }}} int inst_get_all_selected */
342 int inst_get_rrdargs (graph_config_t *cfg, /* {{{ */
343 graph_instance_t *inst,
344 rrd_args_t *args)
345 {
346 def_callback_data_t data = { inst, args };
347 graph_def_t *defs;
348 int status;
350 if ((cfg == NULL) || (inst == NULL) || (args == NULL))
351 return (EINVAL);
353 status = graph_get_rrdargs (cfg, inst, args);
354 if (status != 0)
355 return (status);
357 defs = graph_get_defs (cfg);
358 if (defs == NULL)
359 {
360 defs = inst_get_default_defs (cfg, inst);
362 if (defs == NULL)
363 return (-1);
365 status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
367 def_destroy (defs);
368 }
369 else
370 {
371 status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
372 }
374 return (status);
375 } /* }}} int inst_get_rrdargs */
377 graph_ident_t *inst_get_selector (graph_instance_t *inst) /* {{{ */
378 {
379 if (inst == NULL)
380 return (NULL);
382 return (ident_clone (inst->select));
383 } /* }}} graph_ident_t *inst_get_selector */
385 int inst_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
386 char *buffer, size_t buffer_size)
387 {
388 graph_ident_t *cfg_select;
390 if ((cfg == NULL) || (inst == NULL)
391 || (buffer == NULL) || (buffer_size < 1))
392 return (EINVAL);
394 cfg_select = graph_get_selector (cfg);
395 if (cfg_select == NULL)
396 {
397 fprintf (stderr, "inst_get_params: graph_get_selector failed");
398 return (-1);
399 }
401 buffer[0] = 0;
403 #define COPY_ESCAPE(str) do { \
404 char tmp[1024]; \
405 uri_escape_copy (tmp, (str), sizeof (tmp)); \
406 strlcat (buffer, tmp, buffer_size); \
407 } while (0) \
409 #define COPY_FIELD(field) do { \
410 const char *cfg_f = ident_get_##field (cfg_select); \
411 const char *inst_f = ident_get_##field (inst->select); \
412 if (strcmp (cfg_f, inst_f) == 0) \
413 { \
414 strlcat (buffer, #field, buffer_size); \
415 strlcat (buffer, "=", buffer_size); \
416 COPY_ESCAPE (cfg_f); \
417 } \
418 else \
419 { \
420 strlcat (buffer, "graph_", buffer_size); \
421 strlcat (buffer, #field, buffer_size); \
422 strlcat (buffer, "=", buffer_size); \
423 COPY_ESCAPE (cfg_f); \
424 strlcat (buffer, ";", buffer_size); \
425 strlcat (buffer, "inst_", buffer_size); \
426 strlcat (buffer, #field, buffer_size); \
427 strlcat (buffer, "=", buffer_size); \
428 COPY_ESCAPE (inst_f); \
429 } \
430 } while (0)
432 COPY_FIELD(host);
433 strlcat (buffer, ";", buffer_size);
434 COPY_FIELD(plugin);
435 strlcat (buffer, ";", buffer_size);
436 COPY_FIELD(plugin_instance);
437 strlcat (buffer, ";", buffer_size);
438 COPY_FIELD(type);
439 strlcat (buffer, ";", buffer_size);
440 COPY_FIELD(type_instance);
442 #undef COPY_FIELD
443 #undef COPY_ESCAPE
445 ident_destroy (cfg_select);
447 return (0);
448 } /* }}} int inst_get_params */
450 int inst_compare (const graph_instance_t *i0, /* {{{ */
451 const graph_instance_t *i1)
452 {
453 return (ident_compare (i0->select, i1->select));
454 } /* }}} int inst_compare */
456 int inst_compare_ident (graph_instance_t *inst, /* {{{ */
457 const graph_ident_t *ident)
458 {
459 if ((inst == NULL) || (ident == NULL))
460 return (0);
462 return (ident_compare (inst->select, ident));
463 } /* }}} int inst_compare_ident */
465 _Bool inst_ident_matches (graph_instance_t *inst, /* {{{ */
466 const graph_ident_t *ident)
467 {
468 #if C4_DEBUG
469 if ((inst == NULL) || (ident == NULL))
470 return (0);
471 #endif
473 return (ident_matches (inst->select, ident));
474 } /* }}} _Bool inst_ident_matches */
476 _Bool inst_matches_ident (graph_instance_t *inst, /* {{{ */
477 const graph_ident_t *ident)
478 {
479 if ((inst == NULL) || (ident == NULL))
480 return (0);
482 return (ident_matches (ident, inst->select));
483 } /* }}} _Bool inst_matches_ident */
485 _Bool inst_matches_string (graph_config_t *cfg, /* {{{ */
486 graph_instance_t *inst,
487 const char *term)
488 {
489 char buffer[1024];
490 int status;
492 if ((cfg == NULL) || (inst == NULL) || (term == NULL))
493 return (0);
495 status = inst_describe (cfg, inst, buffer, sizeof (buffer));
496 if (status != 0)
497 {
498 fprintf (stderr, "inst_matches_string: inst_describe failed\n");
499 return (status);
500 }
502 strtolower (buffer);
504 /* no match */
505 if (strstr (buffer, term) == NULL)
506 return (0);
508 return (1);
509 } /* }}} _Bool inst_matches_string */
511 _Bool inst_matches_field (graph_instance_t *inst, /* {{{ */
512 graph_ident_field_t field, const char *field_value)
513 {
514 const char *selector_field;
515 size_t i;
517 if ((inst == NULL) || (field_value == NULL))
518 return (0);
520 selector_field = ident_get_field (inst->select, field);
521 if (selector_field == NULL)
522 return (0);
524 assert (!IS_ANY (selector_field));
525 if (!IS_ALL (selector_field))
526 {
527 if (strcasecmp (selector_field, field_value) == 0)
528 return (1);
529 else
530 return (0);
531 }
533 /* The selector field is an ALL selector
534 * => we need to check the files to see if the instance matches. */
535 for (i = 0; i < inst->files_num; i++)
536 {
537 selector_field = ident_get_field (inst->files[i], field);
538 if (selector_field == NULL)
539 continue;
541 assert (!IS_ANY (selector_field));
542 assert (!IS_ALL (selector_field));
544 if (strcasecmp (selector_field, field_value) == 0)
545 return (1);
546 } /* for files */
548 return (0);
549 } /* }}} _Bool inst_matches_field */
551 int inst_to_json (const graph_instance_t *inst, /* {{{ */
552 yajl_gen handler)
553 {
554 size_t i;
556 if ((inst == NULL) || (handler == NULL))
557 return (EINVAL);
559 /* TODO: error handling */
560 yajl_gen_map_open (handler);
561 yajl_gen_string (handler,
562 (unsigned char *) "select",
563 (unsigned int) strlen ("select"));
564 ident_to_json (inst->select, handler);
565 yajl_gen_string (handler,
566 (unsigned char *) "files",
567 (unsigned int) strlen ("files"));
568 yajl_gen_array_open (handler);
569 for (i = 0; i < inst->files_num; i++)
570 ident_to_json (inst->files[i], handler);
571 yajl_gen_array_close (handler);
572 yajl_gen_map_close (handler);
574 return (0);
575 } /* }}} int inst_to_json */
577 int inst_data_to_json (const graph_instance_t *inst, /* {{{ */
578 dp_time_t begin, dp_time_t end,
579 yajl_gen handler)
580 {
581 size_t i;
583 yajl_gen_array_open (handler);
584 for (i = 0; i < inst->files_num; i++)
585 ident_data_to_json (inst->files[i], begin, end, handler);
586 yajl_gen_array_close (handler);
588 return (0);
589 } /* }}} int inst_data_to_json */
591 int inst_describe (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
592 char *buffer, size_t buffer_size)
593 {
594 graph_ident_t *cfg_select;
595 int status;
597 if ((cfg == NULL) || (inst == NULL)
598 || (buffer == NULL) || (buffer_size < 2))
599 return (EINVAL);
601 cfg_select = graph_get_selector (cfg);
602 if (cfg_select == NULL)
603 {
604 fprintf (stderr, "inst_describe: graph_get_selector failed\n");
605 return (-1);
606 }
608 status = ident_describe (inst->select, cfg_select,
609 buffer, buffer_size);
611 ident_destroy (cfg_select);
613 return (status);
614 } /* }}} int inst_describe */
616 time_t inst_get_mtime (graph_instance_t *inst) /* {{{ */
617 {
618 size_t i;
619 time_t mtime;
621 if (inst == NULL)
622 return (0);
624 mtime = 0;
625 for (i = 0; i < inst->files_num; i++)
626 {
627 time_t tmp;
629 tmp = ident_get_mtime (inst->files[i]);
630 if (mtime < tmp)
631 mtime = tmp;
632 }
634 return (mtime);
635 } /* }}} time_t inst_get_mtime */
637 /* vim: set sw=2 sts=2 et fdm=marker : */