1 #include <dotconf.h>
2 #include <string.h>
3 #include <gmetad.h>
4 #include <ganglia.h>
5 #include "conf.h"
6 
7 /* Variables that get filled in by configuration file */
8 extern Source_t root;
9 extern hash_t *sources;
10 
11 gmetad_config_t gmetad_config;
12 
13 #define GANGLIA_HOSTNAME_LEN  128
14 
DOTCONF_CB(cb_gridname)15 static DOTCONF_CB(cb_gridname)
16 {
17     gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
18     debug_msg("Grid name %s", cmd->data.str);
19     c->gridname = strdup(cmd->data.str);
20     return NULL;
21 }
22 
DOTCONF_CB(cb_authority)23 static DOTCONF_CB(cb_authority)
24 {
25    /* See gmetad.h for why we record strings this way. */
26     debug_msg("Grid authority %s", cmd->data.str);
27     root.authority_ptr = 0;
28     strcpy(root.strings, cmd->data.str);
29     root.stringslen += strlen(root.strings) + 1;
30     return NULL;
31 }
32 
DOTCONF_CB(cb_all_trusted)33 static DOTCONF_CB(cb_all_trusted)
34 {
35    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
36    debug_msg("All hosts are trusted!");
37    c->all_trusted = 1;
38    return NULL;
39 }
40 
DOTCONF_CB(cb_trusted_hosts)41 static DOTCONF_CB(cb_trusted_hosts)
42 {
43    int i,rv;
44    llist_entry *le;
45    struct sockaddr_in sa;
46    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
47 
48    for (i = 0; i < cmd->arg_count; i++)
49       {
50          le = (llist_entry *)malloc(sizeof(llist_entry));
51          rv = g_gethostbyname( cmd->data.list[i], &sa, NULL);
52          if (!rv) {
53             err_msg("Warning: we failed to resolve trusted host name %s", cmd->data.list[i]);
54             continue;
55          }
56          le->val = (char*) malloc(GANGLIA_HOSTNAME_LEN);
57          my_inet_ntop(AF_INET, &sa.sin_addr, le->val, GANGLIA_HOSTNAME_LEN);
58          llist_add(&(c->trusted_hosts), le);
59       }
60    return NULL;
61 }
62 
DOTCONF_CB(cb_RRAs)63 static DOTCONF_CB(cb_RRAs)
64 {
65   int i;
66   gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
67   c->num_RRAs = cmd->arg_count;
68   for(i = 0; i < c->num_RRAs; i++)
69     {
70       c->RRAs[i] = strdup(cmd->data.list[i]);
71     }
72   return NULL;
73 }
74 
DOTCONF_CB(cb_data_source)75 static DOTCONF_CB(cb_data_source)
76 {
77    unsigned int i;
78    data_source_list_t *dslist;
79    datum_t key, val, *find;
80    int port, rv=0;
81    unsigned long step;
82    unsigned int source_index=0;
83    char *p, *str;
84    char *endptr;
85    struct sockaddr_in sa;
86    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
87 
88    source_index++;
89 
90    debug_msg("Datasource = [%s]", cmd->data.list[0]);
91 
92    dslist = (data_source_list_t *) malloc ( sizeof(data_source_list_t) );
93    if(!dslist)
94       {
95          err_quit("Unable to malloc data source list");
96       }
97 
98    dslist->name = strdup( cmd->data.list[0] );
99 
100   /* Set data source step (avg polling interval). Default is 15s.
101    * Be careful of the case where the source is an ip address,
102    * in which case endptr = '.'
103    */
104   i=1;
105   step=strtoul(cmd->data.list[i], &endptr, 10);
106    if (step && *endptr == '\0')
107       {
108          dslist->step = step;
109          i++;
110       }
111    else
112       dslist->step = 15;
113 
114    debug_msg("Polling interval for %s is %u sec.", dslist->name, dslist->step);
115    c->shortest_step = dslist->step;
116 
117    dslist->sources = (g_inet_addr **) malloc( (cmd->arg_count-i) * sizeof(g_inet_addr *) );
118    if (! dslist->sources )
119       err_quit("Unable to malloc sources array");
120 
121    dslist->num_sources = 0;
122    dslist->last_good_index = -1;
123 
124    for ( ; i< cmd->arg_count; i++)
125       {
126          str = cmd->data.list[i];
127 
128          p = strchr( str, ':' );
129          if( p )
130             {
131                /* Port is specified */
132                *p = '\0';
133                port = atoi ( p+1 );
134             }
135          else
136             port = 8649;
137 
138          rv = g_gethostbyname( cmd->data.list[i], &sa, NULL);
139          if (!rv) {
140             err_msg("Warning: we failed to resolve data source name %s", cmd->data.list[i]);
141             continue;
142          }
143          str = (char*) malloc(GANGLIA_HOSTNAME_LEN);
144          my_inet_ntop(AF_INET, &sa.sin_addr, str, GANGLIA_HOSTNAME_LEN);
145 
146          debug_msg("Trying to connect to %s:%d for [%s]", str, port, dslist->name);
147          dslist->sources[dslist->num_sources] = (g_inet_addr *) g_inetaddr_new ( str, port );
148          if(! dslist->sources[dslist->num_sources])
149                err_quit("Unable to create inetaddr [%s:%d] and save it to [%s]", str, port, dslist->name);
150          else
151                dslist->num_sources++;
152          free(str);
153       }
154 
155    key.data = cmd->data.list[0];
156    key.size = strlen(key.data) + 1;
157 
158    val.data = &dslist;
159    val.size = sizeof(dslist);
160 
161    find  = hash_insert( &key, &val, sources );
162    if(!find)
163          err_quit("Unable to insert list pointer into source hash\n");
164 
165    debug_msg("Data inserted for [%s] into sources hash", (const char *) key.data);
166    return NULL;
167 }
168 
DOTCONF_CB(cb_debug_level)169 static DOTCONF_CB(cb_debug_level)
170 {
171    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
172    c->debug_level = cmd->data.value;
173    debug_msg("Setting the debug level to %ld", cmd->data.value);
174    return NULL;
175 }
176 
DOTCONF_CB(cb_xml_port)177 static DOTCONF_CB(cb_xml_port)
178 {
179    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
180    debug_msg("Setting xml port to %ld", cmd->data.value);
181    c->xml_port = cmd->data.value;
182    return NULL;
183 }
184 
DOTCONF_CB(cb_interactive_port)185 static DOTCONF_CB(cb_interactive_port)
186 {
187    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
188    debug_msg("Setting interactive port to %ld", cmd->data.value);
189    c->interactive_port = cmd->data.value;
190    return NULL;
191 }
192 
DOTCONF_CB(cb_server_threads)193 static DOTCONF_CB(cb_server_threads)
194 {
195    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
196    debug_msg("Setting number of xml server threads to %ld", cmd->data.value);
197    c->server_threads = cmd->data.value;
198    return NULL;
199 }
200 
DOTCONF_CB(cb_umask)201 static DOTCONF_CB(cb_umask)
202 {
203    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
204    debug_msg("Setting umask to %.5lo & 07077", cmd->data.value);
205    c->umask = cmd->data.value & 07077; /* protect owner permissions */
206    return NULL;
207 }
208 
DOTCONF_CB(cb_rrd_rootdir)209 static DOTCONF_CB(cb_rrd_rootdir)
210 {
211    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
212    debug_msg("Setting the RRD Rootdir to %s", cmd->data.str);
213    c->rrd_rootdir = strdup (cmd->data.str);
214    return NULL;
215 }
216 
DOTCONF_CB(cb_setuid_username)217 static DOTCONF_CB(cb_setuid_username)
218 {
219    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
220    debug_msg("Setting setuid username to %s", cmd->data.str);
221    c->setuid_username = strdup(cmd->data.str);
222    return NULL;
223 }
224 
DOTCONF_CB(cb_setuid)225 static DOTCONF_CB(cb_setuid)
226 {
227    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
228    c->should_setuid = cmd->data.value;
229    return NULL;
230 }
231 
DOTCONF_CB(cb_scalable)232 static DOTCONF_CB(cb_scalable)
233 {
234    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
235    debug_msg("Setting scalable = %s", cmd->data.str);
236    if (!strcmp(cmd->data.str, "off"))
237       c->scalable_mode = 0;
238    return NULL;
239 }
240 
DOTCONF_CB(cb_write_rrds)241 static DOTCONF_CB(cb_write_rrds)
242 {
243    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
244    debug_msg("Setting write_rrds = %s", cmd->data.str);
245    if (!strcmp(cmd->data.str, "off"))
246        c->write_rrds = cmd->data.value;
247    return NULL;
248 }
249 
DOTCONF_CB(cb_case_sensitive_hostnames)250 static DOTCONF_CB(cb_case_sensitive_hostnames)
251 {
252    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
253    c->case_sensitive_hostnames = cmd->data.value;
254    return NULL;
255 }
256 
DOTCONF_CB(cb_carbon_server)257 static DOTCONF_CB(cb_carbon_server)
258 {
259    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
260    debug_msg("Enabling Graphite proxy to %s", cmd->data.str);
261    c->carbon_server = strdup (cmd->data.str);
262    return NULL;
263 }
264 
DOTCONF_CB(cb_carbon_port)265 static DOTCONF_CB(cb_carbon_port)
266 {
267    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
268    debug_msg("Setting carbon port to %ld", cmd->data.value);
269    c->carbon_port = cmd->data.value;
270    return NULL;
271 }
272 
DOTCONF_CB(cb_carbon_protocol)273 static DOTCONF_CB(cb_carbon_protocol)
274 {
275    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
276    debug_msg("Setting carbon protocol to %s", cmd->data.str);
277    c->carbon_protocol = strdup (cmd->data.str);
278    return NULL;
279 }
280 
DOTCONF_CB(cb_carbon_timeout)281 static DOTCONF_CB(cb_carbon_timeout)
282 {
283    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
284    debug_msg("Setting carbon timeout to %ld", cmd->data.value);
285    c->carbon_timeout = cmd->data.value;
286    return NULL;
287 }
288 
DOTCONF_CB(cb_memcached_parameters)289 static DOTCONF_CB(cb_memcached_parameters)
290 {
291    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
292    debug_msg("Enabling memcached parameters to %s", cmd->data.str);
293    c->memcached_parameters = strdup (cmd->data.str);
294    return NULL;
295 }
296 
DOTCONF_CB(cb_memcached_include_cluster_in_key)297 static DOTCONF_CB(cb_memcached_include_cluster_in_key)
298 {
299    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
300    debug_msg("Setting memcached_include_cluster_in_key to %ld", cmd->data.value);
301    c->memcached_include_cluster_in_key = cmd->data.value;
302    return NULL;
303 }
304 
DOTCONF_CB(cb_graphite_prefix)305 static DOTCONF_CB(cb_graphite_prefix)
306 {
307    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
308    debug_msg("Enabling Graphite proxy to %s", cmd->data.str);
309    c->graphite_prefix = strdup (cmd->data.str);
310    return NULL;
311 }
312 
DOTCONF_CB(cb_graphite_path)313 static DOTCONF_CB(cb_graphite_path)
314 {
315 	gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
316 	debug_msg("Setting Graphite path to %s", cmd->data.str);
317 	c->graphite_path = strdup (cmd->data.str);
318 	return NULL;
319 }
320 
DOTCONF_CB(cb_riemann_server)321 static DOTCONF_CB(cb_riemann_server)
322 {
323    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
324    debug_msg("Enabling Riemann forwarding to %s", cmd->data.str);
325    c->riemann_server = strdup (cmd->data.str);
326    return NULL;
327 }
328 
DOTCONF_CB(cb_riemann_port)329 static DOTCONF_CB(cb_riemann_port)
330 {
331    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
332    debug_msg("Setting Riemann port to %ld", cmd->data.value);
333    c->riemann_port = cmd->data.value;
334    return NULL;
335 }
336 
DOTCONF_CB(cb_riemann_protocol)337 static DOTCONF_CB(cb_riemann_protocol)
338 {
339    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
340    debug_msg("Setting Riemann protocol to %s", cmd->data.str);
341    c->riemann_protocol = strdup (cmd->data.str);
342    return NULL;
343 }
344 
DOTCONF_CB(cb_riemann_attributes)345 static DOTCONF_CB(cb_riemann_attributes)
346 {
347    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
348    debug_msg("Riemann key-value attributes %s", cmd->data.str);
349    c->riemann_attributes = strdup (cmd->data.str);
350    return NULL;
351 }
352 
DOTCONF_CB(cb_unsummarized_metrics)353 static DOTCONF_CB(cb_unsummarized_metrics)
354 {
355    int i;
356    llist_entry *le;
357    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
358 
359    for (i = 0; i < cmd->arg_count; i++)
360       {
361          le = (llist_entry *)malloc(sizeof(llist_entry));
362          le->val = strdup(cmd->data.list[i]);
363          llist_add(&(c->unsummarized_metrics), le);
364          debug_msg("Adding %s to unsummarized_metrics", (const char *) le->val);
365       }
366    return NULL;
367 }
368 
DOTCONF_CB(cb_unsummarized_sflow_vm_metrics)369 static DOTCONF_CB(cb_unsummarized_sflow_vm_metrics)
370 {
371    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
372    debug_msg("Setting unsummarized_sflow_vm_metrics = %ld", cmd->data.value);
373    c->unsummarized_sflow_vm_metrics = cmd->data.value;
374    return NULL;
375 }
376 
DOTCONF_CB(cb_summarized_metrics)377 static DOTCONF_CB(cb_summarized_metrics)
378 {
379    int i;
380    llist_entry *le;
381    gmetad_config_t *c = cmd->option->info;
382 
383    for (i = 0; i < cmd->arg_count; i++)
384       {
385          le = malloc(sizeof(*le));
386          le->val = strdup(cmd->data.list[i]);
387          llist_add(&(c->summarized_metrics), le);
388          debug_msg("Adding %s to summarized_metrics", (const char *)le->val);
389       }
390    return NULL;
391 }
392 
DOTCONF_CB(cb_rrdcached_address)393 static DOTCONF_CB(cb_rrdcached_address)
394 {
395    gmetad_config_t *c = (gmetad_config_t*) cmd->option->info;
396    char *ip, *tmp, *f;
397    long port;
398 
399    f = tmp = strdup(cmd->data.str);
400    if ((ip = strsep(&tmp, ":")) == NULL ||
401        inet_pton(AF_INET, ip, &c->rrdcached_address.sin_addr) != 1)
402       {
403          err_quit("Expected IPv4 address in form a.b.c.d:port for "
404                   "rrdcached_address, got %s\n", cmd->data.str);
405       }
406    port = strtol(tmp, NULL, 10);
407    if ((port == 0 && errno == EINVAL) ||
408        ((port == LONG_MIN || port == LONG_MAX) && errno == ERANGE) ||
409        port < 0 || port > 65535)
410       {
411          err_quit("Expected IPv4 port within range; got %s\n", tmp);
412       }
413 
414    c->rrdcached_address.sin_family = AF_INET;
415    c->rrdcached_address.sin_port = htons(port);
416    c->rrdcached_addrstr = strdup(cmd->data.str);
417    free(f);
418 
419    return NULL;
420 }
421 
FUNC_ERRORHANDLER(errorhandler)422 static FUNC_ERRORHANDLER(errorhandler)
423 {
424    err_quit("gmetad config file error: %s\n", msg);
425    return 0;
426 }
427 
428 static configoption_t gmetad_options[] =
429    {
430       {"data_source", ARG_LIST, cb_data_source, &gmetad_config, 0},
431       {"gridname", ARG_STR, cb_gridname, &gmetad_config, 0},
432       {"authority", ARG_STR, cb_authority, &gmetad_config, 0},
433       {"trusted_hosts", ARG_LIST, cb_trusted_hosts, &gmetad_config, 0},
434       {"all_trusted", ARG_INT, cb_all_trusted, &gmetad_config, 0},
435       {"debug_level",  ARG_INT,  cb_debug_level, &gmetad_config, 0},
436       {"xml_port",  ARG_INT, cb_xml_port, &gmetad_config, 0},
437       {"interactive_port", ARG_INT, cb_interactive_port, &gmetad_config, 0},
438       {"server_threads", ARG_INT, cb_server_threads, &gmetad_config, 0},
439       {"umask", ARG_INT, cb_umask, &gmetad_config, 0},
440       {"rrd_rootdir", ARG_STR, cb_rrd_rootdir, &gmetad_config, 0},
441       {"rrdcached_address", ARG_STR, cb_rrdcached_address, &gmetad_config, 0},
442       {"setuid", ARG_TOGGLE, cb_setuid, &gmetad_config, 0},
443       {"setuid_username", ARG_STR, cb_setuid_username, &gmetad_config, 0},
444       {"scalable", ARG_STR, cb_scalable, &gmetad_config, 0},
445       {"write_rrds", ARG_STR, cb_write_rrds, &gmetad_config, 0},
446       {"RRAs", ARG_LIST, cb_RRAs, &gmetad_config, 0},
447       {"case_sensitive_hostnames", ARG_INT, cb_case_sensitive_hostnames, &gmetad_config, 0},
448       {"carbon_server", ARG_STR, cb_carbon_server, &gmetad_config, 0},
449       {"carbon_port", ARG_INT, cb_carbon_port, &gmetad_config, 0},
450       {"carbon_protocol", ARG_STR, cb_carbon_protocol, &gmetad_config, 0},
451       {"carbon_timeout", ARG_INT, cb_carbon_timeout, &gmetad_config, 0},
452       {"memcached_parameters", ARG_STR, cb_memcached_parameters, &gmetad_config, 0},
453       {"memcached_include_cluster_in_key", ARG_INT, cb_memcached_include_cluster_in_key, &gmetad_config, 0},
454       {"graphite_prefix", ARG_STR, cb_graphite_prefix, &gmetad_config, 0},
455       {"graphite_path", ARG_STR, cb_graphite_path, &gmetad_config, 0},
456       {"riemann_server", ARG_STR, cb_riemann_server, &gmetad_config, 0},
457       {"riemann_port", ARG_INT, cb_riemann_port, &gmetad_config, 0},
458       {"riemann_protocol", ARG_STR, cb_riemann_protocol, &gmetad_config, 0},
459       {"riemann_attributes", ARG_STR, cb_riemann_attributes, &gmetad_config, 0},
460       {"unsummarized_metrics", ARG_LIST, cb_unsummarized_metrics, &gmetad_config, 0},
461       {"unsummarized_sflow_vm_metrics", ARG_TOGGLE, cb_unsummarized_sflow_vm_metrics, &gmetad_config, 0},
462       {"summarized_metrics", ARG_LIST, cb_summarized_metrics, &gmetad_config, 0},
463       LAST_OPTION
464    };
465 
466 static void
set_defaults(gmetad_config_t * config)467 set_defaults (gmetad_config_t *config)
468 {
469    /* Gmetad defaults */
470    config->gridname = "unspecified";
471    config->xml_port = 8651;
472    config->interactive_port = 8652;
473    config->server_threads = 4;
474    config->umask = 0;
475    config->trusted_hosts = NULL;
476    config->debug_level = 0;
477    config->should_setuid = 1;
478    config->setuid_username = "nobody";
479    config->rrd_rootdir = "/var/lib/ganglia/rrds";
480    config->rrdcached_addrstr = NULL;
481    memset(&config->rrdcached_address, 0, sizeof (config->rrdcached_address));
482    config->write_rrds = 1;
483    config->scalable_mode = 1;
484    config->all_trusted = 0;
485    config->num_RRAs = 3;
486    config->RRAs[0] = "RRA:AVERAGE:0.5:1:5856";
487    config->RRAs[1] = "RRA:AVERAGE:0.5:4:20160";
488    config->RRAs[2] = "RRA:AVERAGE:0.5:40:52704";
489    config->case_sensitive_hostnames = 1;
490    config->carbon_port = 2003;
491    config->carbon_protocol = "tcp";
492    config->carbon_timeout = 500;
493    config->memcached_include_cluster_in_key = 0;
494    config->riemann_port = 5555;
495    config->riemann_protocol = "udp";
496    config->riemann_attributes = NULL;
497    config->unsummarized_metrics = NULL;
498    config->unsummarized_sflow_vm_metrics = 0;
499    config->summarized_metrics = NULL;
500 }
501 
502 int
parse_config_file(char * config_file)503 parse_config_file ( char *config_file )
504 {
505    configfile_t *configfile;
506 
507    set_defaults(&gmetad_config);
508 
509    configfile = dotconf_create( config_file, gmetad_options, 0, CASE_INSENSITIVE );
510    if (!configfile)
511       {
512          err_quit("Unable to open config file: %s\n", config_file);
513       }
514 
515    configfile->errorhandler = (dotconf_errorhandler_t) errorhandler;
516 
517    if (dotconf_command_loop(configfile) == 0)
518       {
519          dotconf_cleanup(configfile);
520          err_quit("dotconf_command_loop error");
521       }
522    return 0;
523 }
524 
525 int
number_of_datasources(char * config_file)526 number_of_datasources ( char *config_file )
527 {
528    int number_of_sources = 0;
529    char buf[1024];
530    configfile_t *configfile;
531 
532    configfile = dotconf_create( config_file, gmetad_options, 0, CASE_INSENSITIVE );
533    if (!configfile) {
534       err_quit("Unable to open config file: %s\n", config_file);
535    }
536 
537    while (! dotconf_get_next_line( buf, 1024, configfile ))
538       {
539          if( strstr( buf, "data_source" ) && (buf[0] != '#') )
540             {
541                number_of_sources++;
542             }
543       }
544    dotconf_cleanup(configfile);
545    return number_of_sources;
546 }
547 
548