diff --git a/src/damon-backend-app.c b/src/damon-backend-app.c index ba287c4..e47c9a0 100644 --- a/src/damon-backend-app.c +++ b/src/damon-backend-app.c @@ -15,6 +15,42 @@ +#include +#include +#include +#include +#include "rrd.h" +#include "damon.h" + +/* constants */ +#ifndef PROGNAME +# define PROGNAME "DaMon" +#endif + +#define DAMON_SEP '/' + + +/* types */ +/* XXX duplicated from damon.c */ +typedef struct _Host +{ + DaMon * damon; + AppClient * appclient; + char * hostname; + char ** ifaces; + char ** vols; +} Host; + +struct _DaMon +{ + char const * prefix; + unsigned int refresh; + Host * hosts; + unsigned int hosts_cnt; + Event * event; +}; + + /* damon_refresh */ static AppClient * _refresh_connect(Host * host, Event * event); static int _refresh_uptime(AppClient * ac, Host * host, char * rrd); @@ -89,7 +125,7 @@ static int _refresh_uptime(AppClient * ac, Host * host, char * rrd) if(appclient_call(ac, (void **)&ret, "uptime") != 0) return error_print(PROGNAME); sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "uptime.rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, ret); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, ret); return 0; } @@ -104,7 +140,7 @@ static int _refresh_load(AppClient * ac, Host * host, char * rrd) if(res != 0) return 0; sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "load.rrd"); - _damon_update(host->damon, RRDTYPE_LOAD, rrd, 3, + damon_update(host->damon, RRDTYPE_LOAD, rrd, 3, load[0], load[1], load[2]); return 0; } @@ -116,7 +152,7 @@ static int _refresh_procs(AppClient * ac, Host * host, char * rrd) if(appclient_call(ac, (void **)&res, "procs") != 0) return 1; sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "procs.rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, res); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, res); return 0; } @@ -129,7 +165,7 @@ static int _refresh_ram(AppClient * ac, Host * host, char * rrd) &ram[3]) != 0) return 1; sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "ram.rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 4, + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 4, ram[0], ram[1], ram[2], ram[3]); return 0; } @@ -142,7 +178,7 @@ static int _refresh_swap(AppClient * ac, Host * host, char * rrd) if(appclient_call(ac, (void **)&res, "swap", &swap[0], &swap[1]) != 0) return 1; sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "swap.rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, swap[0], swap[1]); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, swap[0], swap[1]); return 0; } @@ -153,7 +189,7 @@ static int _refresh_users(AppClient * ac, Host * host, char * rrd) if(appclient_call(ac, (void **)&res, "users") != 0) return 1; sprintf(rrd, "%s%c%s", host->hostname, DAMON_SEP, "users.rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, res); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 1, res); return 0; } @@ -179,7 +215,7 @@ static int _refresh_ifaces_if(AppClient * ac, Host * host, char * rrd, iface) != 0) return 1; sprintf(rrd, "%s%c%s%s", host->hostname, DAMON_SEP, iface, ".rrd"); - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, res[0], res[1]); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, res[0], res[1]); return 0; } @@ -205,6 +241,6 @@ static int _refresh_vols_vol(AppClient * ac, Host * host, char * rrd, != 0) return 1; sprintf(rrd, "%s%s%s", host->hostname, vol, ".rrd"); /* FIXME */ - _damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, res[0], res[1]); + damon_update(host->damon, RRDTYPE_UNKNOWN, rrd, 2, res[0], res[1]); return 0; } diff --git a/src/damon-backend-salt.c b/src/damon-backend-salt.c new file mode 100644 index 0000000..84c88b5 --- /dev/null +++ b/src/damon-backend-salt.c @@ -0,0 +1,222 @@ +/* $Id$ */ +/* Copyright (c) 2016 Pierre Pronchery */ +/* This file is part of DeforaOS Network Probe */ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + + + +#include +#include +#include +#include +#include +#include +#include "damon.h" + +/* constants */ +#ifndef SALT +# define SALT "salt" +#endif + + +/* damon_refresh */ +typedef enum _SaltFunction +{ + SF_STATUS_ALL_STATUS = 0 +} SaltFunction; +#define SF_LAST SF_STATUS_ALL_STATUS +#define SF_COUNT (SF_LAST + 1) + +static int _refresh_salt(DaMon * damon, + int (*callback)(DaMon * damon, json_t * json), + SaltFunction function, ...); +static int _refresh_status(DaMon * damon); +static int _refresh_status_parse(DaMon * damon, json_t * json); +static int _refresh_status_parse_diskusage(DaMon * damon, char const * hostname, + json_t * json); +static int _refresh_status_parse_diskusage_volume(DaMon * damon, + char const * hostname, char const * volume, json_t * json); +static int _refresh_status_parse_loadavg(DaMon * damon, char const * hostname, + json_t * json); + +int damon_refresh(DaMon * damon) +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + _refresh_status(damon); + return 0; +} + +static int _refresh_salt(DaMon * damon, + int (*callback)(DaMon * damon, json_t * json), + SaltFunction function, ...) +{ + char * functions[SF_COUNT] = { + SALT " --out=json '*' status.all_status" }; + FILE * fp; + const size_t flags = JSON_DISABLE_EOF_CHECK; + json_t * json; + json_error_t error; + int res; + + if((fp = popen(functions[function], "rb")) == NULL) + return damon_perror("popen", -errno); + while(!feof(fp) && (json = json_loadf(fp, flags, &error)) != NULL) + { +#if 0 + json_dump_file(json, "/dev/stdout", 0); + fprintf(stderr, "DEBUG: %d\n", json_typeof(json)); +#else + callback(damon, json); + json_decref(json); +#endif + } +#ifdef DEBUG + if(json == NULL) + fprintf(stderr, "DEBUG: %s\n", error.text); +#endif + if((res = pclose(fp)) == 127) + return damon_error(SALT ": Could not execute", res); + else if(res != 0) + return damon_error(SALT ": An error occured", res); + return 0; +} + +static int _refresh_status(DaMon * damon) +{ + _refresh_salt(damon, _refresh_status_parse, SF_STATUS_ALL_STATUS); + return 0; +} + +static int _refresh_status_parse(DaMon * damon, json_t * json) +{ + char const * hostname; + json_t * what; + char const * status; + json_t * value; + + if(!json_is_object(json)) + return -1; + json_object_foreach(json, hostname, what) + { +#ifdef DEBUG + fprintf(stderr, "DEBUG: hostname: %s\n", hostname); +#endif + /* XXX report errors */ + if(string_find(hostname, "/") != NULL) + return -1; + if(!json_is_object(what)) + return -1; + json_object_foreach(what, status, value) + if(strcmp("diskusage", status) == 0) + _refresh_status_parse_diskusage(damon, hostname, + value); + else if(strcmp("loadavg", status) == 0) + _refresh_status_parse_loadavg(damon, hostname, + value); + } + return 0; +} + +static int _refresh_status_parse_diskusage(DaMon * damon, char const * hostname, + json_t * json) +{ + int ret = 0; + char const * volume; + json_t * value; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\", %d)\n", __func__, hostname, + json_typeof(json)); +#endif + if(!json_is_object(json)) + return -1; + json_object_foreach(json, volume, value) + { + if(string_find(volume, "/..") != NULL) + /* XXX report */ + continue; + ret |= _refresh_status_parse_diskusage_volume(damon, hostname, + volume, value); + } + return ret; +} + +static int _refresh_status_parse_diskusage_volume(DaMon * damon, + char const * hostname, char const * volume, json_t * json) +{ + int ret; + uint64_t usage[2] = { 0, 0 }; + char const * key; + json_t * value; + char * rrd; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\", %d)\n", __func__, hostname, + volume, json_typeof(json)); +#endif + if(!json_is_object(json)) + return -1; + json_object_foreach(json, key, value) + if(strcmp(key, "available") == 0) + usage[0] = json_integer_value(value); + else if(strcmp(key, "total") == 0) + usage[1] = json_integer_value(value); + if(usage[0] == 0 && usage[1] == 0) + /* ignore empty volumes */ + return 0; + if(usage[0] > usage[1]) + /* invalid or partial input */ + return -1; + /* graph the volume used instead */ + usage[0] = usage[1] - usage[0]; + if((rrd = string_new_append(hostname, "/", "volume", + (strcmp(volume, "/") == 0) + ? "" : volume, + ".rrd", NULL)) == NULL) + return -1; + ret = damon_update(damon, RRDTYPE_VOLUME, rrd, 2, usage[0], usage[1]); + string_delete(rrd); + return ret; +} + +static int _refresh_status_parse_loadavg(DaMon * damon, char const * hostname, + json_t * json) +{ + int ret; + uint64_t load[3] = { 0, 0, 0 }; + char const * key; + json_t * value; + char * rrd; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\", %d)\n", __func__, hostname, + json_typeof(json)); +#endif + if(!json_is_object(json)) + return -1; + json_object_foreach(json, key, value) + if(strcmp(key, "1-min") == 0) + load[0] = json_real_value(value) * 1000; + else if(strcmp(key, "5-min") == 0) + load[1] = json_real_value(value) * 1000; + else if(strcmp(key, "15-min") == 0) + load[2] = json_real_value(value) * 1000; + if((rrd = string_new_append(hostname, "/", "load.rrd", NULL)) == NULL) + return -1; + ret = damon_update(damon, RRDTYPE_LOAD, rrd, + 3, load[0], load[1], load[2]); + string_delete(rrd); + return ret; +} diff --git a/src/damon.c b/src/damon.c index 6729240..deaa6eb 100644 --- a/src/damon.c +++ b/src/damon.c @@ -25,7 +25,6 @@ #include #include #include -#include "rrd.h" #include "damon.h" #include "../config.h" @@ -69,18 +68,12 @@ struct _DaMon #else # define DAMON_DEFAULT_REFRESH 300 #endif -#define DAMON_SEP '/' /* prototypes */ static int _damon_init(DaMon * damon, char const * config, Event * event); static void _damon_destroy(DaMon * damon); -static int _damon_perror(char const * message, int error); - -static int _damon_update(DaMon * damon, RRDType type, char const * filename, - int args_cnt, ...); - /* functions */ /* public */ @@ -136,8 +129,43 @@ Event * damon_get_event(DaMon * damon) /* useful */ -/* damon_refresh */ -#include "damon-backend.c" +/* damon_error */ +int damon_error(char const * message, int ret) +{ + return error_set_print(PROGNAME, ret, "%s", message); +} + + +/* damon_perror */ +int damon_perror(char const * message, int ret) +{ + return error_set_print(PROGNAME, ret, "%s%s%s", + (message != NULL) ? message : "", + (message != NULL) ? ": " : "", strerror(errno)); +} + + +/* damon_update */ +int damon_update(DaMon * damon, RRDType type, char const * filename, + int args_cnt, ...) +{ + int ret; + char * path; + va_list args; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%u, \"%s\", %d, ...) \"%s\"\n", __func__, + type, filename, args_cnt, damon->prefix); +#endif + if((path = string_new_append(damon->prefix, "/", filename, NULL)) + == NULL) + return -1; + va_start(args, args_cnt); + ret = rrd_updatev(type, path, args_cnt, args); + va_end(args); + string_delete(path); + return ret; +} /* private */ @@ -230,7 +258,7 @@ static int _init_config_hosts(DaMon * damon, Config * config, } if((p = realloc(damon->hosts, sizeof(*p) * (damon->hosts_cnt + 1))) == NULL) - return _damon_perror(NULL, -errno); + return damon_perror(NULL, -errno); damon->hosts = p; p = &damon->hosts[damon->hosts_cnt++]; if(_init_config_hosts_host(damon, config, p, h, pos) != 0) @@ -251,7 +279,7 @@ static int _init_config_hosts_host(DaMon * damon, Config * config, Host * host, host->ifaces = NULL; host->vols = NULL; if((host->hostname = malloc(pos + 1)) == NULL) - return _damon_perror(NULL, -errno); + return damon_perror(NULL, -errno); strncpy(host->hostname, h, pos); host->hostname[pos] = '\0'; #ifdef DEBUG @@ -326,36 +354,3 @@ static void _damon_destroy(DaMon * damon) event_delete(damon->event); free(damon->hosts); } - - -/* useful */ -/* damon_perror */ -static int _damon_perror(char const * message, int ret) -{ - return error_set_print(PROGNAME, ret, "%s%s%s", - (message != NULL) ? message : "", - (message != NULL) ? ": " : "", strerror(errno)); -} - - -/* damon_update */ -static int _damon_update(DaMon * damon, RRDType type, char const * filename, - int args_cnt, ...) -{ - int ret; - char * path; - va_list args; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%u, \"%s\", %d, ...) \"%s\"\n", __func__, - type, filename, args_cnt, damon->prefix); -#endif - if((path = string_new_append(damon->prefix, "/", filename, NULL)) - == NULL) - return -1; - va_start(args, args_cnt); - ret = rrd_updatev(type, path, args_cnt, args); - va_end(args); - string_delete(path); - return ret; -} diff --git a/src/damon.h b/src/damon.h index 58fb906..a6e4cd2 100644 --- a/src/damon.h +++ b/src/damon.h @@ -19,6 +19,7 @@ # define DAMON_DAMON_H # include +# include "rrd.h" /* DaMon */ @@ -35,6 +36,11 @@ void damon_delete(DaMon * damon); Event * damon_get_event(DaMon * damon); /* useful */ +int damon_error(char const * message, int error); +int damon_perror(char const * message, int error); + int damon_refresh(DaMon * damon); +int damon_update(DaMon * damon, RRDType type, char const * filename, + int args_cnt, ...); #endif /* !DAMON_DAMON_H */ diff --git a/src/project.conf b/src/project.conf index 7805f1e..c5bea74 100644 --- a/src/project.conf +++ b/src/project.conf @@ -1,9 +1,13 @@ targets=../data/Probe.h,Probe,DaMon -cflags_force=`pkg-config --cflags libApp` cflags=-W -Wall -g -O2 -pedantic -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all -ldflags_force=`pkg-config --libs libApp` ldflags=-Wl,-pie -Wl,-z,relro -Wl,-z,now -dist=Makefile,appbroker.sh,damon.h,damon-backend.c,damon-backend-app.c,rrd.h +#for App +cflags_force=`pkg-config --cflags libApp` +ldflags_force=`pkg-config --libs libApp` +#for Salt +#cflags_force=`pkg-config --cflags libApp jansson` +#ldflags_force=`pkg-config --libs libApp jansson` +dist=Makefile,appbroker.sh,damon.h,damon-backend-app.c,damon-backend-salt.c,rrd.h [../data/Probe.h] type=script @@ -18,11 +22,14 @@ install=$(BINDIR) [DaMon] type=binary -sources=damon.c,damon-main.c,rrd.c +sources=damon.c,damon-backend.c,damon-main.c,rrd.c install=$(BINDIR) [damon.c] -depends=damon.h,damon-backend.c,damon-backend-app.c,rrd.h,../config.h +depends=damon.h,rrd.h,../config.h + +[damon-backend.c] +depends=damon.h,rrd.h,damon-backend-app.c,damon-backend-salt.c [damon-main.c] depends=damon.h