diff options
| author | sasha <sasha@97f52cf1-0a1b-0410-bd0e-c28be96e8082> | 2008-01-18 10:52:08 +0000 |
|---|---|---|
| committer | sasha <sasha@97f52cf1-0a1b-0410-bd0e-c28be96e8082> | 2008-01-18 10:52:08 +0000 |
| commit | 83c43012c9fd777e6a8d095c58f534d7de2963ad (patch) | |
| tree | cb09146399616b584a71f57b7d3b54e214497548 /src/zabbix_proxy | |
| parent | aac7703069141a27b1279189c4a94bffb0a76c85 (diff) | |
| download | zabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.tar.gz zabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.tar.xz zabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.zip | |
- [DEV-99] New application: zabbix_proxy
git-svn-id: svn://svn.zabbix.com/trunk@5265 97f52cf1-0a1b-0410-bd0e-c28be96e8082
Diffstat (limited to 'src/zabbix_proxy')
69 files changed, 14606 insertions, 0 deletions
diff --git a/src/zabbix_proxy/Makefile.am b/src/zabbix_proxy/Makefile.am new file mode 100644 index 00000000..c2bc8cb9 --- /dev/null +++ b/src/zabbix_proxy/Makefile.am @@ -0,0 +1,52 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = \ + dbsyncer \ + discoverer \ + housekeeper \ + httppoller \ + nodewatcher \ + pinger \ + poller \ + trapper + +sbin_PROGRAMS = zabbix_proxy + +zabbix_proxy_SOURCES = \ + evalfunc.c evalfunc.h \ + expression.c expression.h \ + operations.c operations.h \ + events.c events.h \ + zlog.c \ + functions.c functions.h \ + proxy.c + +zabbix_proxy_LDADD = \ + dbsyncer/libzbxdbsyncer.a \ + discoverer/libzbxdiscoverer.a \ + housekeeper/libzbxhousekeeper.a \ + httppoller/libzbxhttppoller.a \ + nodewatcher/libzbxnodewatcher.a \ + pinger/libzbxpinger.a \ + poller/libzbxpoller.a \ + trapper/libzbxtrapper.a \ + $(top_srcdir)/src/libs/zbxsysinfo/libzbxserversysinfo.a \ + $(top_srcdir)/src/libs/zbxsysinfo/$(ARCH)/libspecsysinfo.a \ + $(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo.a \ + $(top_srcdir)/src/libs/zbxsysinfo/simple/libsimplesysinfo.a \ + $(top_srcdir)/src/libs/zbxlog/libzbxlog.a \ + $(top_srcdir)/src/libs/zbxnix/libzbxnix.a \ + $(top_srcdir)/src/libs/zbxsys/libzbxsys.a \ + $(top_srcdir)/src/libs/zbxconf/libzbxconf.a \ + $(top_srcdir)/src/libs/zbxdbhigh/libzbxdbhigh.a \ + $(top_srcdir)/src/libs/zbxdb/libzbxdb.a \ + $(top_srcdir)/src/libs/zbxdbcache/libzbxdbcache.a \ + $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \ + $(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \ + $(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \ + @PROXY_LIBS@ + +zabbix_proxy_LDFLAGS = \ + @PROXY_LDFLAGS@ + +zabbix_proxy_CFLAGS = -DZABBIX_DAEMON diff --git a/src/zabbix_proxy/dbsyncer/Makefile.am b/src/zabbix_proxy/dbsyncer/Makefile.am new file mode 100644 index 00000000..c81bdc5e --- /dev/null +++ b/src/zabbix_proxy/dbsyncer/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxdbsyncer.a + +libzbxdbsyncer_a_SOURCES = dbsyncer.c dbsyncer.h diff --git a/src/zabbix_proxy/dbsyncer/dbsyncer.c b/src/zabbix_proxy/dbsyncer/dbsyncer.c new file mode 100644 index 00000000..644418da --- /dev/null +++ b/src/zabbix_proxy/dbsyncer/dbsyncer.c @@ -0,0 +1,75 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "dbcache.h" +#include "dbsyncer.h" + +/****************************************************************************** + * * + * Function: main_dbsyncer_loop * + * * + * Purpose: periodically syncronises data in memory cache with database * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +int main_dbsyncer_loop() +{ + int now; + struct timeval from; + struct timeval to; + + zbx_setproctitle("connecting to the database"); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + for(;;) + { + now = time(NULL); + + zabbix_log( LOG_LEVEL_WARNING, "Syncing ..."); + + + gettimeofday(&from, NULL); + + DCsync(); + + gettimeofday(&to, NULL); + zabbix_log( LOG_LEVEL_WARNING, "Spent " ZBX_FS_DBL " sec", + time_diff(&from,&to)); + + zbx_setproctitle("sender [sleeping for %d seconds]", + CONFIG_DBSYNCER_FREQUENCY); + + sleep(CONFIG_DBSYNCER_FREQUENCY); + } + DBclose(); +} diff --git a/src/zabbix_proxy/dbsyncer/dbsyncer.h b/src/zabbix_proxy/dbsyncer/dbsyncer.h new file mode 100644 index 00000000..753ea08b --- /dev/null +++ b/src/zabbix_proxy/dbsyncer/dbsyncer.h @@ -0,0 +1,29 @@ +/* +** ZABBIX +** Copyright (C) 2000-2007 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_DBSYNCER_H +#define ZABBIX_DBSYNCER_H + +#include "db.h" + +extern int CONFIG_DBSYNCER_FREQUENCY; + +int main_dbsyncer_loop(); + +#endif diff --git a/src/zabbix_proxy/discoverer/Makefile.am b/src/zabbix_proxy/discoverer/Makefile.am new file mode 100644 index 00000000..aae20ad6 --- /dev/null +++ b/src/zabbix_proxy/discoverer/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxdiscoverer.a + +libzbxdiscoverer_a_SOURCES = discoverer.c discoverer.h diff --git a/src/zabbix_proxy/discoverer/discoverer.c b/src/zabbix_proxy/discoverer/discoverer.c new file mode 100644 index 00000000..101117c4 --- /dev/null +++ b/src/zabbix_proxy/discoverer/discoverer.c @@ -0,0 +1,907 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "pid.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" +#include "zlog.h" + +#include "daemon.h" +#include "discoverer.h" +#include "../events.h" +#include "../poller/checks_agent.h" +#include "../poller/checks_snmp.h" + +int discoverer_num; + +/****************************************************************************** + * * + * Function: add_host_event * + * * + * Purpose: generate host UP/DOWN event if required * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void add_host_event(char *ip) +{ + DB_RESULT result; + DB_ROW row; + DB_EVENT event; + int now; + int status; + zbx_uint64_t dhostid; + + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In add_host_event(ip:%s)", + ip); + + result = DBselect("select status,dhostid from dhosts where ip='%s'", + ip); + row=DBfetch(result); + if(row && DBis_null(row[0])!=SUCCEED) + { + now = time(NULL); + status = atoi(row[0]); + ZBX_STR2UINT64(dhostid, row[1]); + + memset(&event,0,sizeof(DB_EVENT)); + + event.eventid = 0; + event.source = EVENT_SOURCE_DISCOVERY; + event.object = EVENT_OBJECT_DHOST; + event.objectid = dhostid; + event.clock = now; + event.value = status; + event.acknowledged = 0; + + process_event(&event); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End add_host_event()"); +} + +/****************************************************************************** + * * + * Function: add_service_event * + * * + * Purpose: generate service UP/DOWN event if required * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void add_service_event(DB_DSERVICE *service) +{ + DB_EVENT event; + int now; + + assert(service); + + zabbix_log(LOG_LEVEL_DEBUG, "In add_service_event()"); + + now = time(NULL); + + memset(&event,0,sizeof(DB_EVENT)); + + event.eventid = 0; + event.source = EVENT_SOURCE_DISCOVERY; + event.object = EVENT_OBJECT_DSERVICE; + event.objectid = service->dserviceid; + event.clock = now; + event.value = service->status; + event.acknowledged = 0; + + process_event(&event); + + zabbix_log(LOG_LEVEL_DEBUG, "End add_service_event()"); +} + +/****************************************************************************** + * * + * Function: update_dservice * + * * + * Purpose: update descovered service details * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void update_dservice(DB_DSERVICE *service) +{ + char key_esc[MAX_STRING_LEN]; + + assert(service); + + DBescape_string(service->key_, key_esc, sizeof(key_esc)-1); + + DBexecute("update dservices set dhostid=" ZBX_FS_UI64 ",type=%d,port=%d,status=%d,lastup=%d,lastdown=%d,key_='%s' where dserviceid=" ZBX_FS_UI64, + service->dhostid, + service->type, + service->port, + service->status, + service->lastup, + service->lastdown, + key_esc, + service->dserviceid); +} + +/****************************************************************************** + * * + * Function: update_host * + * * + * Purpose: update descovered host details * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void update_dhost(DB_DHOST *host) +{ + assert(host); + + DBexecute("update dhosts set druleid=" ZBX_FS_UI64 ",ip='%s',status=%d,lastup=%d,lastdown=%d where dhostid=" ZBX_FS_UI64, + host->druleid, + host->ip, + host->status, + host->lastup, + host->lastdown, + host->dhostid); +} + +/****************************************************************************** + * * + * Function: register_service * + * * + * Purpose: register service if one does not exist * + * * + * Parameters: host ip address * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void register_service(DB_DSERVICE *service,DB_DRULE *rule,DB_DCHECK *check,zbx_uint64_t dhostid,char *ip,int port) +{ + DB_RESULT result; + DB_ROW row; + char value_esc[MAX_STRING_LEN]; + char key_esc[MAX_STRING_LEN]; + + assert(service); + assert(rule); + assert(check); + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In register_service(ip:%s,port:%d)", + ip, + port); + + DBescape_string(check->key_, key_esc, sizeof(key_esc)-1); + + result = DBselect("select dserviceid,dhostid,type,port,status,lastup,lastdown,value,key_ from dservices where dhostid=" ZBX_FS_UI64 " and type=%d and port=%d and key_='%s'", + dhostid, + check->type, + port, + key_esc); + row=DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + /* Add host only if service is up */ + if(check->status == DOBJECT_STATUS_UP) + { + zabbix_log(LOG_LEVEL_DEBUG, "New service discovered on port %d", port); + + service->dserviceid = DBget_maxid("dservices","dserviceid"); + service->dhostid = dhostid; + service->type = check->type; + service->port = port; + service->status = DOBJECT_STATUS_UP; + service->lastup = 0; + service->lastdown = 0; + strscpy(service->value, check->value); + strscpy(service->key_, check->key_); + + DBescape_string(service->value, value_esc, sizeof(value_esc)-1); + DBescape_string(service->key_, key_esc, sizeof(key_esc)-1); + + DBexecute("insert into dservices (dhostid,dserviceid,type,port,status,value,key_) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d,%d,%d,'%s','%s')", + service->dhostid, + service->dserviceid, + check->type, + service->port, + service->status, + value_esc, + key_esc); + } + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "Service is already in database"); + + ZBX_STR2UINT64(service->dserviceid, row[0]); + ZBX_STR2UINT64(service->dhostid, row[1]); + service->type = atoi(row[2]); + service->port = atoi(row[3]); + service->status = atoi(row[4]); + service->lastup = atoi(row[5]); + service->lastdown = atoi(row[6]); + strscpy(service->value,row[7]); + strscpy(service->key_,row[8]); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End register_service()"); +} + +/****************************************************************************** + * * + * Function: register_host * + * * + * Purpose: register host if one does not exist * + * * + * Parameters: host ip address * + * * + * Return value: dhostid or 0 if we didn't add host * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void register_host(DB_DHOST *host,DB_DCHECK *check, zbx_uint64_t druleid, char *ip) +{ + DB_RESULT result; + DB_ROW row; + + assert(host); + assert(check); + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In register_host(ip:%s)", + ip); + + host->dhostid=0; + result = DBselect("select dhostid,druleid,ip,status,lastup,lastdown from dhosts where ip='%s' and " ZBX_COND_NODEID, + ip, + LOCAL_NODE("dhostid")); + row=DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + /* Add host only if service is up */ + if(check->status == DOBJECT_STATUS_UP) + { + zabbix_log(LOG_LEVEL_DEBUG, "New host discovered at %s", + ip); + host->dhostid = DBget_maxid("dhosts","dhostid"); + DBexecute("insert into dhosts (dhostid,druleid,ip) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",'%s')", + host->dhostid, + druleid, + ip); + host->druleid = druleid; + strscpy(host->ip,ip); + host->status = 0; + host->lastup = 0; + host->lastdown = 0; + } + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "Host is already in database"); + ZBX_STR2UINT64(host->dhostid,row[0]); + ZBX_STR2UINT64(host->druleid,row[1]); + strscpy(host->ip, row[2]); + host->status = atoi(row[3]); + host->lastup = atoi(row[4]); + host->lastdown = atoi(row[5]); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End register_host()"); +} + +/****************************************************************************** + * * + * Function: update_service * + * * + * Purpose: process new service status * + * * + * Parameters: service - service info * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void update_service(DB_DRULE *rule, DB_DCHECK *check, char *ip, int port) +{ + int now; + DB_DHOST host; + DB_DSERVICE service; + + assert(rule); + assert(check); + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In update_service(ip:%s, port:%d, status:%s)", + ip, + port, + (check->status==DOBJECT_STATUS_UP?"up":"down")); + + service.dserviceid=0; + + /* Register host if is not registered yet */ + register_host(&host,check,rule->druleid,ip); + + if(host.dhostid>0) + { + /* Register service if is not registered yet */ +/* dserviceid = register_service(rule,check,host.dhostid,ip,port);*/ + register_service(&service,rule,check,host.dhostid,ip,port); + } + + if(service.dserviceid == 0) + { + /* Service wasn't registered because we do not add down service */ + return; + } + + now = time(NULL); + if(check->status == DOBJECT_STATUS_UP) + { + /* Update host status */ + if(host.status == DOBJECT_STATUS_DOWN || host.lastup==0) + { + host.status=DOBJECT_STATUS_UP; + host.lastdown=0; + host.lastup=now; + update_dhost(&host); + } + /* Update service status */ + if(service.status == DOBJECT_STATUS_DOWN || service.lastup==0) + { + service.status=DOBJECT_STATUS_UP; + service.lastdown=0; + service.lastup=now; + update_dservice(&service); + } + } + /* DOBJECT_STATUS_DOWN */ + else + { + if(host.status == DOBJECT_STATUS_UP || host.lastdown==0) + { + host.status=DOBJECT_STATUS_DOWN; + host.lastdown=now; + host.lastup=0; + update_dhost(&host); + } + /* Update service status */ + if(service.status == DOBJECT_STATUS_UP || service.lastdown==0) + { + service.status=DOBJECT_STATUS_DOWN; + service.lastdown=now; + service.lastup=0; + update_dservice(&service); + } + } + + add_service_event(&service); +} + +/****************************************************************************** + * * + * Function: discover_service * + * * + * Purpose: check if service is avaiable and update database * + * * + * Parameters: service typ,e ip address, port number * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int discover_service(DB_DCHECK *check, char *ip, int port) +{ + int ret = SUCCEED; + char key[MAX_STRING_LEN]; + AGENT_RESULT value; + DB_ITEM item; + struct sigaction phan; + + assert(check); + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In discover_service(ip:%s, port:%d, type:%d)", + ip, + port, + check->type); + + init_result(&value); + + switch(check->type) { + case SVC_SSH: + zbx_snprintf(key,sizeof(key),"net.tcp.service[ssh,%s,%d]", + ip, + port); + break; + case SVC_LDAP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[ldap,%s,%d]", + ip, + port); + break; + case SVC_SMTP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[smtp,%s,%d]", + ip, + port); + break; + case SVC_FTP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[ftp,%s,%d]", + ip, + port); + break; + case SVC_HTTP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[http,%s,%d]", + ip, + port); + break; + case SVC_POP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[pop,%s,%d]", + ip, + port); + break; + case SVC_NNTP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[nntp,%s,%d]", + ip, + port); + break; + case SVC_IMAP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[imap,%s,%d]", + ip, + port); + break; + case SVC_TCP: + zbx_snprintf(key,sizeof(key),"net.tcp.service[tcp,%s,%d]", + ip, + port); + break; + case SVC_AGENT: + case SVC_SNMPv1: + case SVC_SNMPv2c: + break; + default: + ret = FAIL; + break; + } + + if(ret == SUCCEED) + { + phan.sa_handler = &child_signal_handler; + sigemptyset(&phan.sa_mask); + phan.sa_flags = 0; + sigaction(SIGALRM, &phan, NULL); + alarm(10); + + switch(check->type) { + /* Agent and SNMP checks */ + case SVC_AGENT: + case SVC_SNMPv1: + case SVC_SNMPv2c: + memset(&item,0,sizeof(DB_ITEM)); + strscpy(item.key,check->key_); + item.host_name = ip; + item.host_ip = ip; + item.host_dns = ip; + item.useip = 1; + item.port = port; + + item.value_type = ITEM_VALUE_TYPE_STR; + + if(check->type == SVC_SNMPv1) + { + item.type = ITEM_TYPE_SNMPv1; + } + else + { + item.type = ITEM_TYPE_SNMPv2c; + } + + item.snmp_oid = check->key_; + item.snmp_community = check->snmp_community; + item.snmp_port = port; + + if(check->type==SVC_AGENT) + { + if(SUCCEED == get_value_agent(&item, &value)) + { + if(GET_STR_RESULT(&value)) + { + strscpy(check->value, value.str); + } + else ret = FAIL; + } + else + { + ret = FAIL; + } + } + else +#ifdef HAVE_SNMP + { + if(SUCCEED == get_value_snmp(&item, &value)) + { + if(GET_STR_RESULT(&value)) + { + strscpy(check->value, value.str); + } + else ret = FAIL; + } + else + { + ret = FAIL; + } + } +#else + { + ret = FAIL; + } +#endif + break; + /* Simple checks */ + default: + if(process(key, 0, &value) == SUCCEED) + { + if(GET_UI64_RESULT(&value)) + { + if(value.ui64 == 0) ret = FAIL; + } + else ret = FAIL; + } + else ret = FAIL; + break; + } + alarm(0); + } + free_result(&value); + + zabbix_log(LOG_LEVEL_DEBUG, "End discover_service()"); + + return ret; +} + +/****************************************************************************** + * * + * Function: process_check * + * * + * Purpose: check if service is avaiable and update database * + * * + * Parameters: service - service info * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +static void process_check(DB_DRULE *rule, DB_DCHECK *check, char *ip) +{ + int port, + first, + last; + + char *curr_range = NULL, + *next_range = NULL, + *last_port = NULL; + + assert(rule); + assert(check); + assert(ip); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_check(ip:%s, ports:%s, type:%d)", + ip, + check->ports, + check->type); + + for ( curr_range = check->ports; curr_range; curr_range = next_range ) + { /* split by ',' */ + if ( (next_range = strchr(curr_range, ',')) ) + { + *next_range = '\0'; + } + + if ( (last_port = strchr(curr_range, '-')) ) + { /* split by '-' */ + *last_port = '\0'; + first = atoi(curr_range); + last = atoi(last_port); + *last_port = '-'; + } + else + { + first = last = atoi(curr_range); + } + + if ( next_range ) + { + *next_range = ','; + next_range++; + } + + for ( port = first; port <= last; port++) + { + check->status = discover_service(check,ip,port); + update_service(rule, check, ip, port); + } + } + + zabbix_log(LOG_LEVEL_DEBUG, "End process_check()"); +} + +/****************************************************************************** + * * + * Function: process_rule * + * * + * Purpose: process single discovery rule * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +static void process_rule(DB_DRULE *rule) +{ + DB_RESULT result; + DB_ROW row; + DB_DCHECK check; + + char ip[MAX_STRING_LEN], prefix[MAX_STRING_LEN]; + unsigned int j[9], i; + int first, last, ipv6; + + char *curr_range = NULL, + *next_range = NULL, + *dash = NULL; +#if defined(HAVE_IPV6) + char *colon; +#endif + + assert(rule); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_rule() [name:%s] [range:%s]", + rule->name, + rule->iprange); + + for ( curr_range = rule->iprange; curr_range; curr_range = next_range ) + { /* split by ',' */ + if ( NULL != (next_range = strchr(curr_range, ',')) ) + { + next_range[0] = '\0'; + } + + if ( NULL != (dash = strchr(curr_range, '-')) ) + { + dash[0] = '\0'; + } + + first = last = -1; +#if defined(HAVE_IPV6) + if ( SUCCEED == expand_ipv6(curr_range, ip, sizeof(ip)) ) + { + ipv6 = 1; + if( sscanf(ip, "%x:%x:%x:%x:%x:%x:%x:%x", &j[0], &j[1], &j[2], &j[3], &j[4], &j[5], &j[6], &j[7]) == 8 ) + { + first = j[7]; + + zbx_strlcpy( prefix, curr_range, sizeof(prefix) ); + if( NULL != (colon = strrchr(prefix, ':')) ) + { + ( colon + 1 )[0] = '\0'; + } + } + + if( dash != NULL ) + { + if( sscanf(dash + 1, "%x", &j[8]) == 1 ) + { + last = j[8]; + } + } + else + { + last = first; + } + } + else + { +#endif /* HAVE_IPV6 */ + ipv6 = 0; + if( sscanf(curr_range, "%d.%d.%d.%d", &j[0], &j[1], &j[2], &j[3]) == 4 ) + { + first = j[3]; + } + + if( dash != NULL ) + { + if( sscanf(dash + 1, "%d", &j[4]) == 1 ) + { + last = j[4]; + } + } + else + { + last = first; + } +#if defined(HAVE_IPV6) + } +#endif /* HAVE_IPV6 */ + + if( dash ) + { + dash[0] = '-'; + dash = NULL; + } + + if ( next_range ) + { + next_range[0] = ','; + next_range ++; + } + + if( first < 0 || last < 0 ) + { + zabbix_log(LOG_LEVEL_WARNING, "Discovery: Wrong format of IP range [%s]", + rule->iprange); + continue; + } + + for ( i = first; i <= last; i++ ) + { + switch( ipv6 ) + { + case 0 : zbx_snprintf(ip, sizeof(ip), "%d.%d.%d.%d", j[0], j[1], j[2], i); break; + case 1 : zbx_snprintf(ip, sizeof(ip), "%s%x", prefix, i); break; + } + + zabbix_log(LOG_LEVEL_DEBUG, "Discovery: process_rule() [IP:%s]", ip); + + result = DBselect("select dcheckid,druleid,type,key_,snmp_community,ports from dchecks where druleid=" ZBX_FS_UI64, + rule->druleid); + while((row=DBfetch(result))) + { + memset(&check, 0, sizeof(DB_RESULT)); + + ZBX_STR2UINT64(check.dcheckid,row[0]); + ZBX_STR2UINT64(check.druleid,row[1]); + check.type = atoi(row[2]); + check.key_ = row[3]; + check.snmp_community = row[4]; + check.ports = row[5]; + + process_check(rule, &check, ip); + } + DBfree_result(result); + + add_host_event(ip); + } + } + + zabbix_log( LOG_LEVEL_DEBUG, "End process_rule()"); +} + +/****************************************************************************** + * * + * Function: main_discoverer_loop * + * * + * Purpose: periodically try to find new hosts and services * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: executes once per 30 seconds (hardcoded) * + * * + ******************************************************************************/ +void main_discoverer_loop(int num) +{ + int now; + + DB_RESULT result; + DB_ROW row; + DB_DRULE rule; + + zabbix_log( LOG_LEVEL_DEBUG, "In main_discoverer_loop(num:%d)", + num); + + discoverer_num = num; + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + for(;;) + { + now=time(NULL); + + result = DBselect("select druleid,iprange,delay,nextcheck,name,status from drules where status=%d and nextcheck<=%d and " ZBX_SQL_MOD(druleid,%d) "=%d and" ZBX_COND_NODEID, + DRULE_STATUS_MONITORED, + now, + CONFIG_DISCOVERER_FORKS, + discoverer_num-1, + LOCAL_NODE("druleid")); + while((row=DBfetch(result))) + { + memset(&rule, 0, sizeof(DB_DRULE)); + + ZBX_STR2UINT64(rule.druleid,row[0]); + rule.iprange = row[1]; + rule.delay = atoi(row[2]); + rule.nextcheck = atoi(row[3]); + rule.name = row[4]; + rule.status = atoi(row[5]); + + process_rule(&rule); + } + DBfree_result(result); + + zbx_setproctitle("sleeping for 30 sec"); + + sleep(30); + } + DBclose(); +} diff --git a/src/zabbix_proxy/discoverer/discoverer.h b/src/zabbix_proxy/discoverer/discoverer.h new file mode 100644 index 00000000..12f30728 --- /dev/null +++ b/src/zabbix_proxy/discoverer/discoverer.h @@ -0,0 +1,27 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_DISCOVERER_H +#define ZABBIX_DISCOVERER_H + +extern int CONFIG_DISCOVERER_FORKS; + +void main_discoverer_loop(int num); + +#endif diff --git a/src/zabbix_proxy/evalfunc.c b/src/zabbix_proxy/evalfunc.c new file mode 100644 index 00000000..642913f0 --- /dev/null +++ b/src/zabbix_proxy/evalfunc.c @@ -0,0 +1,1826 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "evalfunc.h" + +/****************************************************************************** + * * + * Function: evaluate_LOGSOURCE * + * * + * Purpose: evaluate function 'logsource' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - ignored * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_LOGSOURCE(char *value, DB_ITEM *item, char *parameter) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + + if(item->value_type != ITEM_VALUE_TYPE_LOG) + { + return FAIL; + } + + now=time(NULL); + + zbx_snprintf(sql,sizeof(sql),"select source from history_log where itemid=" ZBX_FS_UI64 " order by clock desc", + item->itemid); + + result = DBselectN(sql,1); + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for LOGSOURCE is empty" ); + res = FAIL; + } + else + { + if(strcmp(row[0], parameter) == 0) + { + strcpy(value,"1"); + } + else + { + strcpy(value,"0"); + } + } + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_LOGSEVERITY * + * * + * Purpose: evaluate function 'logseverity' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - ignored * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_LOGSEVERITY(char *value, DB_ITEM *item, char *parameter) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + + if(item->value_type != ITEM_VALUE_TYPE_LOG) + { + return FAIL; + } + + now=time(NULL); + + zbx_snprintf(sql,sizeof(sql),"select severity from history_log where itemid=" ZBX_FS_UI64 " order by clock desc", + item->itemid); + + result = DBselectN(sql,1); + row = DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for LOGSEVERITY is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + } + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_COUNT * + * * + * Purpose: evaluate function 'count' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_COUNT(char *value, DB_ITEM *item, char *parameter) +{ + DB_RESULT result; + DB_ROW row; + + char period[MAX_STRING_LEN+1]; + char op[MAX_STRING_LEN+1]; + char cmp[MAX_STRING_LEN+1]; + char cmp_esc[MAX_STRING_LEN+1]; + + int now; + int res = SUCCEED; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + char table_log[] = "history_log"; + char table_str[] = "history_str"; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_COUNT(param:%s)", + parameter); + + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + case ITEM_VALUE_TYPE_LOG: table = table_log; break; + case ITEM_VALUE_TYPE_STR: table = table_str; break; + default: + return FAIL; + } + + now=time(NULL); + + if(get_param(parameter, 1, period, MAX_STRING_LEN) != 0) + { + return FAIL; + } + if(get_param(parameter, 2, cmp, MAX_STRING_LEN) != 0) + { + result = DBselect("select count(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-atoi(period), + item->itemid); + + } + else + { + if(get_param(parameter, 3, op, MAX_STRING_LEN) != 0) + { + strscpy(op,"eq"); + } + DBescape_string(cmp, cmp_esc, sizeof(cmp_esc)); + /* ITEM_VALUE_TYPE_UINT64 */ + if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"eq") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"ne") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value<>" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"gt") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value>" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"lt") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value<" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"ge") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value>=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"le") == 0)) + { + result = DBselect("select count(value) from history_uint where clock>%d and value<=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64, + now-atoi(period), + zbx_atoui64(cmp_esc), + item->itemid); + } + /* ITEM_VALUE_TYPE_FLOAT */ + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"eq") == 0)) + { + result = DBselect("select count(value) from history where clock>%d and value+0.00001>" ZBX_FS_DBL " and value-0.0001<" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + atof(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"ne") == 0)) + { + result = DBselect("select count(value) from history where clock>%d and ((value+0.00001<" ZBX_FS_DBL ") or (value-0.0001>" ZBX_FS_DBL ")) and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + atof(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"gt") == 0)) + { + result = DBselect("select count(value) from history where clock>%d and value>" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"ge") == 0)) + { + result = DBselect("select count(value) from history where clock>=%d and value>" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"lt") == 0)) + { + result = DBselect("select count(value) from history where clock>%d and value<" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + item->itemid); + } + else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"le") == 0)) + { + result = DBselect("select count(value) from history where clock>%d and value<=" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64, + now-atoi(period), + atof(cmp_esc), + item->itemid); + } + else if(item->value_type == ITEM_VALUE_TYPE_LOG) + { + result = DBselect("select count(value) from history_log where clock>%d and value like '%s' and itemid=" ZBX_FS_UI64, + now-atoi(period), + cmp_esc, + item->itemid); + } + else + { + result = DBselect("select count(value) from history_str where clock>%d and value like '%s' and itemid=" ZBX_FS_UI64, + now-atoi(period), + cmp_esc, + item->itemid); + } + } + + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for COUNT is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + } + DBfree_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "End evaluate_COUNT"); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_SUM * + * * + * Purpose: evaluate function 'sum' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_SUM(char *value, DB_ITEM *item, int parameter, int flag) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + int rows = 0; + double sum=0; + zbx_uint64_t sum_uint64=0; + zbx_uint64_t value_uint64; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + default: + return FAIL; + } + + now=time(NULL); + + if(flag == ZBX_FLAG_SEC) + { + result = DBselect("select sum(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-parameter, + item->itemid); + + row = DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for SUM is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + } + } + else if(flag == ZBX_FLAG_VALUES) + { + zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc", + table, + item->itemid); + result = DBselectN(sql, parameter); + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(value_uint64,row[0]); + sum_uint64+=value_uint64; + rows++; + } + if(rows>0) zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, sum_uint64); + } + else + { + while((row=DBfetch(result))) + { + sum+=atof(row[0]); + rows++; + } + if(rows>0) zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, sum); + } + if(0 == rows) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for SUM is empty" ); + res = FAIL; + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]", + flag, + ZBX_FLAG_SEC, + ZBX_FLAG_VALUES); + return FAIL; + } + + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_AVG * + * * + * Purpose: evaluate function 'avg' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_AVG(char *value,DB_ITEM *item,int parameter,int flag) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + int rows; + double sum=0; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + default: + return FAIL; + } + + now=time(NULL); + + if(flag == ZBX_FLAG_SEC) + { + result = DBselect("select avg(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-parameter, + item->itemid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for AVG is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + del_zeroes(value); + } + } + else if(flag == ZBX_FLAG_VALUES) + { + zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc", + table, + item->itemid); + result = DBselectN(sql, parameter); + rows=0; + while((row=DBfetch(result))) + { + sum+=atof(row[0]); + rows++; + } + if(rows == 0) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for AVG is empty" ); + res = FAIL; + } + else + { + zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, sum/(double)rows); + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]", + flag, + ZBX_FLAG_SEC, + ZBX_FLAG_VALUES); + return FAIL; + } + + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_MIN * + * * + * Purpose: evaluate function 'min' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_MIN(char *value,DB_ITEM *item,int parameter, int flag) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int rows; + int res = SUCCEED; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + + zbx_uint64_t min_uint64=0; + zbx_uint64_t l; + + double min=0; + double f; + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + default: + return FAIL; + } + + now=time(NULL); + + + if(flag == ZBX_FLAG_SEC) + { + result = DBselect("select min(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-parameter, + item->itemid); + row = DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for MIN is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + del_zeroes(value); + } + } + else if(flag == ZBX_FLAG_VALUES) + { + zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc", + table, + item->itemid); + result = DBselectN(sql,parameter); + + rows=0; + while((row=DBfetch(result))) + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + ZBX_STR2UINT64(l,row[0]); + + if(rows==0) min_uint64 = l; + else if(l<min_uint64) min_uint64 = l; + } + else + { + f=atof(row[0]); + if(rows==0) min = f; + else if(f<min) min = f; + } + rows++; + } + + if(rows==0) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for MIN is empty" ); + res = FAIL; + } + else + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, min_uint64); + } + else + { + zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, min); + } + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]", + flag, + ZBX_FLAG_SEC, + ZBX_FLAG_VALUES); + return FAIL; + } + + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_MAX * + * * + * Purpose: evaluate function 'max' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_MAX(char *value,DB_ITEM *item,int parameter,int flag) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + int rows; + double f; + double max = 0; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + + zbx_uint64_t max_uint64=0; + zbx_uint64_t l; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_MAX()"); + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + default: + return FAIL; + } + + now=time(NULL); + + if(flag == ZBX_FLAG_SEC) + { + result = DBselect("select max(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-parameter, + item->itemid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for MAX is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + del_zeroes(value); + } + } + else if(flag == ZBX_FLAG_VALUES) + { + zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc", + table, + item->itemid); + result = DBselectN(sql,parameter); + rows=0; + while((row=DBfetch(result))) + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + ZBX_STR2UINT64(l,row[0]); + + if(rows==0) max_uint64 = l; + else if(l>max_uint64) max_uint64 = l; + } + else + { + f=atof(row[0]); + if(rows==0) max=f; + else if(f>max) max=f; + } + rows++; + } + if(rows == 0) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for MAX is empty" ); + res = FAIL; + } + else + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, max_uint64); + } + else + { + zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, max); + } + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]", + flag, + ZBX_FLAG_SEC, + ZBX_FLAG_VALUES); + return FAIL; + } + + DBfree_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_MAX()"); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_DELTA * + * * + * Purpose: evaluate function 'delat' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_DELTA(char *value,DB_ITEM *item,int parameter, int flag) +{ + DB_RESULT result; + DB_ROW row; + + char sql[MAX_STRING_LEN]; + int now; + int res = SUCCEED; + int rows; + double f; + double min = 0,max = 0; + + zbx_uint64_t max_uint64=0,min_uint64=0; + zbx_uint64_t l; + + char *table = NULL; + char table_ui64[] = "history_uint"; + char table_float[] = "history"; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_DELTA()"); + + switch(item->value_type) + { + case ITEM_VALUE_TYPE_FLOAT: table = table_float; break; + case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break; + default: + return FAIL; + } + + now=time(NULL); + + if(flag == ZBX_FLAG_SEC) + { + result = DBselect("select max(value)-min(value) from %s where clock>%d and itemid=" ZBX_FS_UI64, + table, + now-parameter, + item->itemid); + + row = DBfetch(result); + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for DELTA is empty" ); + res = FAIL; + } + else + { + strcpy(value,row[0]); + del_zeroes(value); + } + } + else if(flag == ZBX_FLAG_VALUES) + { + zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc", + table, + item->itemid); + result = DBselectN(sql,parameter); + rows=0; + while((row=DBfetch(result))) + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + ZBX_STR2UINT64(l,row[0]); + + if(rows==0) + { + max_uint64 = l; + min_uint64 = l; + } + else + { + if(l>max_uint64) max_uint64 = l; + if(l<min_uint64) min_uint64 = l; + } + } + else + { + f=atof(row[0]); + if(rows==0) + { + min=f; + max=f; + } + else + { + if(f>max) max=f; + if(f<min) min=f; + } + } + rows++; + } + if(rows==0) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result for DELTA is empty" ); + res = FAIL; + } + else + { + if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, max_uint64-min_uint64); + } + else + { + zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, max-min); + } + } + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]", + flag, + ZBX_FLAG_SEC, + ZBX_FLAG_VALUES); + return FAIL; + } + + DBfree_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_DELTA()"); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_NODATA * + * * + * Purpose: evaluate function 'nodata' for the item * + * * + * Parameters: item - item (performance metric) * + * parameter - number of seconds * + * * + * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' * + * FAIL - failed to evaluate function * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int evaluate_NODATA(char *value,DB_ITEM *item,int parameter) +{ + int now; + int res = SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_NODATA()"); + + now = time(NULL); + + if((CONFIG_SERVER_STARTUP_TIME + parameter > now) || (item->lastclock + parameter > now)) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + + zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_NODATA()"); + + return res; +} + +/****************************************************************************** + * * + * Function: evaluate_function * + * * + * Purpose: evaluate function * + * * + * Parameters: item - item to calculate function for * + * function - function (for example, 'max') * + * parameter - parameter of the function) * + * flag - if EVALUATE_FUNCTION_SUFFIX, then include units and * + * suffix (K,M,G) into result value (for example, 15GB) * + * * + * Return value: SUCCEED - evaluated succesfully, value contains its value * + * FAIL - evaluation failed * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int evaluate_function(char *value,DB_ITEM *item,char *function,char *parameter) +{ + int ret = SUCCEED; + time_t now; + struct tm *tm; + + int fuzlow, fuzhig; + + int day; + int len; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_function(%s)", + function); + + if(strcmp(function,"last")==0) + { + if(item->lastvalue_null==1) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,item->lastvalue_dbl); + del_zeroes(value); + break; + case ITEM_VALUE_TYPE_UINT64: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,item->lastvalue_uint64); + break; + default: + strcpy(value,item->lastvalue_str); + break; + } + } + } + else if(strcmp(function,"prev")==0) + { + if(item->prevvalue_null==1) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,item->prevvalue_dbl); + del_zeroes(value); + break; + case ITEM_VALUE_TYPE_UINT64: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,item->prevvalue_uint64); + break; + default: + strcpy(value,item->prevvalue_str); + break; + } + } + } + else if(strcmp(function,"min")==0) + { + if(parameter[0]=='#') + ret = evaluate_MIN(value,item,atoi(parameter+1),ZBX_FLAG_VALUES); + else + ret = evaluate_MIN(value,item,atoi(parameter),ZBX_FLAG_SEC); + } + else if(strcmp(function,"max")==0) + { + if(parameter[0]=='#') + ret = evaluate_MAX(value,item,atoi(parameter+1),ZBX_FLAG_VALUES); + else + ret = evaluate_MAX(value,item,atoi(parameter),ZBX_FLAG_SEC); + } + else if(strcmp(function,"avg")==0) + { + if(parameter[0]=='#') + ret = evaluate_AVG(value,item,atoi(parameter+1),ZBX_FLAG_VALUES); + else + ret = evaluate_AVG(value,item,atoi(parameter),ZBX_FLAG_SEC); + } + else if(strcmp(function,"sum")==0) + { + if(parameter[0]=='#') + ret = evaluate_SUM(value,item,atoi(parameter+1),ZBX_FLAG_VALUES); + else + ret = evaluate_SUM(value,item,atoi(parameter),ZBX_FLAG_SEC); + } + else if(strcmp(function,"count")==0) + { + ret = evaluate_COUNT(value,item,parameter); + } + else if(strcmp(function,"delta")==0) + { + if(parameter[0]=='#') + ret = evaluate_DELTA(value,item,atoi(parameter+1),ZBX_FLAG_VALUES); + else + ret = evaluate_DELTA(value,item,atoi(parameter),ZBX_FLAG_SEC); + } + else if(strcmp(function,"nodata")==0) + { + ret = evaluate_NODATA(value,item,atoi(parameter)); + } + else if(strcmp(function,"date")==0) + { + now=time(NULL); + tm=localtime(&now); + zbx_snprintf(value,MAX_STRING_LEN,"%.4d%.2d%.2d", + tm->tm_year+1900, + tm->tm_mon+1, + tm->tm_mday); + } + else if(strcmp(function,"dayofweek")==0) + { + now=time(NULL); + tm=localtime(&now); + /* The number of days since Sunday, in the range 0 to 6. */ + day=tm->tm_wday; + if(0 == day) day=7; + zbx_snprintf(value,MAX_STRING_LEN,"%d", + day); + } + else if(strcmp(function,"time")==0) + { + now=time(NULL); + tm=localtime(&now); + zbx_snprintf(value,MAX_STRING_LEN,"%.2d%.2d%.2d", + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + } + else if(strcmp(function,"abschange")==0) + { + if((item->lastvalue_null==1)||(item->prevvalue_null==1)) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL, + (double)abs(item->lastvalue_dbl-item->prevvalue_dbl)); + del_zeroes(value); + break; + case ITEM_VALUE_TYPE_UINT64: + /* To avoid overflow */ + if(item->lastvalue_uint64>=item->prevvalue_uint64) + { + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, + labs(item->lastvalue_uint64-item->prevvalue_uint64)); + } + else + { + zbx_snprintf(value,MAX_STRING_LEN,"-" ZBX_FS_UI64, + labs(item->prevvalue_uint64 - item->lastvalue_uint64)); + } + break; + default: + if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + break; + } + } + } + else if(strcmp(function,"change")==0) + { + if((item->lastvalue_null==1)||(item->prevvalue_null==1)) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL, + item->lastvalue_dbl-item->prevvalue_dbl); + del_zeroes(value); + break; + case ITEM_VALUE_TYPE_UINT64: + /* To avoid overflow */ + if(item->lastvalue_uint64>=item->prevvalue_uint64) + { + zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, + item->lastvalue_uint64-item->prevvalue_uint64); + } + else + { + zbx_snprintf(value,MAX_STRING_LEN,"-" ZBX_FS_UI64, + item->prevvalue_uint64 - item->lastvalue_uint64); + } + break; + default: + if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + break; + } + } + } + else if(strcmp(function,"diff")==0) + { + if((item->lastvalue_null==1)||(item->prevvalue_null==1)) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + if(cmp_double(item->lastvalue_dbl, item->prevvalue_dbl) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + break; + case ITEM_VALUE_TYPE_UINT64: + if(item->lastvalue_uint64 == item->prevvalue_uint64) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + break; + default: + if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + break; + } +/* if( (item->value_type==ITEM_VALUE_TYPE_FLOAT) || (item->value_type==ITEM_VALUE_TYPE_UINT64)) + { + if(cmp_double(item->lastvalue, item->prevvalue) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + } + else + { + if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + }*/ + } + } + else if(strcmp(function,"str")==0) + { + if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG)) + { + if(strstr(item->lastvalue_str, parameter) == NULL) + { + strcpy(value,"0"); + } + else + { + strcpy(value,"1"); + } + + } + else + { + ret = FAIL; + } + } + else if(strcmp(function,"regexp")==0) + { + if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG)) + { + if(zbx_regexp_match(item->lastvalue_str, parameter, &len) != NULL) + { + strcpy(value,"1"); + } + else + { + strcpy(value,"0"); + } + } + else + { + ret = FAIL; + } + } + else if(strcmp(function,"iregexp")==0) + { + if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG)) + { + if(zbx_iregexp_match(item->lastvalue_str, parameter, &len) != NULL) + { + strcpy(value,"1"); + } + else + { + strcpy(value,"0"); + } + } + else + { + ret = FAIL; + } + } + else if(strcmp(function,"now")==0) + { + now=time(NULL); + zbx_snprintf(value,MAX_STRING_LEN,"%d",(int)now); + } + else if(strcmp(function,"fuzzytime")==0) + { + now=time(NULL); + fuzlow=(int)(now-atoi(parameter)); + fuzhig=(int)(now+atoi(parameter)); + + if(item->lastvalue_null==1) + { + ret = FAIL; + } + else + { + switch (item->value_type) { + case ITEM_VALUE_TYPE_FLOAT: + if((item->lastvalue_dbl>=fuzlow)&&(item->lastvalue_dbl<=fuzhig)) + { + strcpy(value,"1"); + } + else + { + strcpy(value,"0"); + } + break; + case ITEM_VALUE_TYPE_UINT64: + if((item->lastvalue_uint64>=fuzlow)&&(item->lastvalue_uint64<=fuzhig)) + { + strcpy(value,"1"); + } + else + { + strcpy(value,"0"); + } + break; + default: + ret = FAIL; + break; + } + } + } + else if(strcmp(function,"logseverity")==0) + { + ret = evaluate_LOGSEVERITY(value,item,parameter); + } + else if(strcmp(function,"logsource")==0) + { + ret = evaluate_LOGSOURCE(value,item,parameter); + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "Unsupported function:%s", + function); + zabbix_syslog("Unsupported function:%s", + function); + ret = FAIL; + } + + zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_function(result:%s)", + value); + return ret; +} + +/****************************************************************************** + * * + * Function: add_value_suffix_uptime * + * * + * Purpose: Peocess suffix 'uptime' * + * * + * Parameters: value - value for adjusting * + * max_len - max len of the value * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void add_value_suffix_uptime(char *value, int max_len) +{ + double value_double; + double days, hours, min; + + zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix_uptime(%s)", + value); + + value_double = atof(value); + + if(value_double <0) return; + + days=floor(value_double/(24*3600)); + if(cmp_double(days,0) != 0) + { + value_double=value_double-days*(24*3600); + } + hours=floor(value_double/(3600)); + if(cmp_double(hours,0) != 0) + { + value_double=value_double-hours*3600; + } + min=floor(value_double/(60)); + if( cmp_double(min,0) !=0) + { + value_double=value_double-min*(60); + } + if(cmp_double(days,0) == 0) + { + zbx_snprintf(value, max_len, "%02d:%02d:%02d", + (int)hours, + (int)min, + (int)value_double); + } + else + { + zbx_snprintf(value, max_len, "%d days, %02d:%02d:%02d", + (int)days, + (int)hours, + (int)min, + (int)value_double); + } + zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_suffix_uptime(%s)", + value); +} + +/****************************************************************************** + * * + * Function: add_value_suffix_s * + * * + * Purpose: Peocess suffix 's' * + * * + * Parameters: value - value for adjusting * + * max_len - max len of the value * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void add_value_suffix_s(char *value, int max_len) +{ + double value_double; + double t; + char tmp[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix_s(%s)", + value); + + value_double = atof(value); + if(value_double <0) return; + + value[0]='\0'; + + t=floor(value_double/(365*24*3600)); + if(cmp_double(t,0) != 0) + { + zbx_snprintf(tmp, sizeof(tmp), "%dy", (int)t); + zbx_strlcat(value, tmp, max_len); + value_double = value_double-t*(365*24*3600); + } + + t=floor(value_double/(30*24*3600)); + if(cmp_double(t,0) != 0) + { + zbx_snprintf(tmp, sizeof(tmp), "%dm", (int)t); + zbx_strlcat(value, tmp, max_len); + value_double = value_double-t*(30*24*3600); + } + + t=floor(value_double/(24*3600)); + if(cmp_double(t,0) != 0) + { + zbx_snprintf(tmp, sizeof(tmp), "%dd", (int)t); + zbx_strlcat(value, tmp, max_len); + value_double = value_double-t*(24*3600); + } + + t=floor(value_double/(3600)); + if(cmp_double(t,0) != 0) + { + zbx_snprintf(tmp, sizeof(tmp), "%dh", (int)t); + zbx_strlcat(value, tmp, max_len); + value_double = value_double-t*(3600); + } + + t=floor(value_double/(60)); + if(cmp_double(t,0) != 0) + { + zbx_snprintf(tmp, sizeof(tmp), "%dm", (int)t); + zbx_strlcat(value, tmp, max_len); + value_double = value_double-t*(60); + } + + zbx_snprintf(tmp, sizeof(tmp), "%02.2f", value_double); + zbx_rtrim(tmp,"0"); + zbx_rtrim(tmp,"."); + zbx_strlcat(tmp, "s", sizeof(tmp)); + zbx_strlcat(value, tmp, max_len); + + zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_suffix_s(%s)", + value); +} + +/****************************************************************************** + * * + * Function: add_value_suffix_normsl * + * * + * Purpose: Peocess normal values and add K,M,G,T * + * * + * Parameters: value - value for adjusting * + * max_len - max len of the value * + * units - units (bps, b,B, etc) * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void add_value_suffix_normal(char *value, int max_len, char *units) +{ + double base = 1024; + char kmgt[MAX_STRING_LEN]; + + zbx_uint64_t value_uint64; + double value_double; + + zabbix_log( LOG_LEVEL_DEBUG, "In add_value_normal(value:%s,units:%s)", + value, + units); + + value_uint64 = labs(zbx_atoui64(value)); + + /* SPecial processing for bits */ + if(strcmp(units,"b") == 0 || strcmp(units,"bps") == 0) + { + base = 1000; + } + + if(value_uint64 < base) + { + strscpy(kmgt,""); + value_double = (double)value_uint64; + } + else if(value_uint64 < base*base) + { + strscpy(kmgt,"K"); + value_double = (double)value_uint64/base; + } + else if(value_uint64 < base*base*base) + { + strscpy(kmgt,"M"); + value_double = (double)(value_uint64/(base*base)); + } + else if(value_uint64 < base*base*base*base) + { + strscpy(kmgt,"G"); + value_double = (double)value_uint64/(base*base*base); + } + else + { + strscpy(kmgt,"T"); + value_double = (double)value_uint64/(base*base*base*base); + } + + if(cmp_double((int)(value_double+0.5), value_double) == 0) + { + zbx_snprintf(value, MAX_STRING_LEN, ZBX_FS_DBL_EXT(0) " %s%s", + value_double, + kmgt, + units); + } + else + { + zbx_snprintf(value, MAX_STRING_LEN, ZBX_FS_DBL_EXT(2) " %s%s", + value_double, + kmgt, + units); + } + + zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_normal(value:%s)", + value); +} + +/****************************************************************************** + * * + * Function: add_value_suffix * + * * + * Purpose: Add suffix for value * + * * + * Parameters: value - value to replacing * + * valuemapid - index of value map * + * * + * Return value: SUCCEED - suffix added succesfully, value contains new value * + * FAIL - adding failed, value contains old value * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ + +/* Do not forget to keep it in sync wiht convert_units in config.inc.php */ +int add_value_suffix(char *value, int max_len, char *units, int value_type) +{ + int ret = FAIL; + + struct tm *local_time = NULL; + time_t time; + + char tmp[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix(value:%s,units:%s)", + value, + units); + + switch(value_type) + { + case ITEM_VALUE_TYPE_FLOAT: + if(strcmp(units,"s") == 0) + { + add_value_suffix_s(value, max_len); + ret = SUCCEED; + } + else if(strcmp(units,"uptime") == 0) + { + add_value_suffix_uptime(value, max_len); + ret = SUCCEED; + } + else if(strlen(units) != 0) + { + add_value_suffix_normal(value, max_len, units); + ret = SUCCEED; + } + else + { + /* Do nothing if units not set */ + } + break; + + case ITEM_VALUE_TYPE_UINT64: + if(strcmp(units,"s") == 0) + { + add_value_suffix_s(value, max_len); + ret = SUCCEED; + } + else if(strcmp(units,"unixtime") == 0) + { + time = (time_t)zbx_atoui64(value); + local_time = localtime(&time); + strftime(tmp, MAX_STRING_LEN, "%Y.%m.%d %H:%M:%S", + local_time); + zbx_strlcpy(value, tmp, max_len); + ret = SUCCEED; + } + else if(strcmp(units,"uptime") == 0) + { + add_value_suffix_uptime(value, max_len); + ret = SUCCEED; + } + else if(strlen(units) != 0) + { + add_value_suffix_normal(value, max_len, units); + ret = SUCCEED; + } + else + { + /* Do nothing if units not set */ + } + break; + default: + ret = FAIL; + break; + } + + zabbix_log(LOG_LEVEL_DEBUG, "End of add_value_suffix(%s)", + value); + + return ret; +} + +/****************************************************************************** + * * + * Function: replace_value_by_map * + * * + * Purpose: replace value by mapping value * + * * + * Parameters: value - value to replacing * + * valuemapid - index of value map * + * * + * Return value: SUCCEED - evaluated succesfully, value contains new value * + * FAIL - evaluation failed, value contains old value * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +int replace_value_by_map(char *value, zbx_uint64_t valuemapid) +{ + DB_RESULT result; + DB_ROW row; + + char new_value[MAX_STRING_LEN]; + char sql[MAX_STRING_LEN]; + char *or_value; + + zabbix_log(LOG_LEVEL_DEBUG, "In replace_value_by_map()" ); + + if(valuemapid == 0) return FAIL; + + result = DBselect("select newvalue from mappings where valuemapid=" ZBX_FS_UI64 " and value='%s'", + valuemapid, + value); + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) return FAIL; + + strcpy(new_value,row[0]); + DBfree_result(result); + + del_zeroes(new_value); + or_value = sql; /* sql variarbvle used as tmp - original value */ + zbx_strlcpy(sql,value,MAX_STRING_LEN); + + zbx_snprintf(value, MAX_STRING_LEN, "%s (%s)", + new_value, + or_value); + + zabbix_log(LOG_LEVEL_DEBUG, "End replace_value_by_map(result:%s)", + value); + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: evaluate_function2 * + * * + * Purpose: evaluate function * + * * + * Parameters: host - host the key belongs to * + * key - item's key (for example, 'max') * + * function - function (for example, 'max') * + * parameter - parameter of the function) * + * * + * Return value: SUCCEED - evaluated succesfully, value contains its value * + * FAIL - evaluation failed * + * * + * Author: Alexei Vladishev * + * * + * Comments: Used for evaluation of notification macros * + * * + ******************************************************************************/ +int evaluate_function2(char *value,char *host,char *key,char *function,char *parameter) +{ + DB_ITEM item; + DB_RESULT result; + DB_ROW row; + + char host_esc[MAX_STRING_LEN]; + char key_esc[MAX_STRING_LEN]; + + int res; + + zabbix_log(LOG_LEVEL_DEBUG, "In evaluate_function2(%s,%s,%s,%s)", + host, + key, + function, + parameter); + + DBescape_string(host, host_esc, MAX_STRING_LEN); + DBescape_string(key, key_esc, MAX_STRING_LEN); + + result = DBselect("select %s where h.host='%s' and h.hostid=i.hostid and i.key_='%s' and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + host_esc, + key_esc, + LOCAL_NODE("h.hostid")); + + row = DBfetch(result); + + if(!row) + { + DBfree_result(result); + zabbix_log(LOG_LEVEL_WARNING, "Query returned empty result"); + zabbix_syslog("Query returned empty result"); + return FAIL; + } + + DBget_item_from_db(&item,row); + + res = evaluate_function(value,&item,function,parameter); + + if(replace_value_by_map(value, item.valuemapid) != SUCCEED) + { + add_value_suffix(value, MAX_STRING_LEN, item.units, item.value_type); + } + +/* Cannot call DBfree_result until evaluate_FUNC */ + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_function2(result:%s)", + value); + return res; +} diff --git a/src/zabbix_proxy/evalfunc.h b/src/zabbix_proxy/evalfunc.h new file mode 100644 index 00000000..5da6b67d --- /dev/null +++ b/src/zabbix_proxy/evalfunc.h @@ -0,0 +1,39 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_EVALFUNC_H +#define ZABBIX_EVALFUNC_H + +#include "common.h" +#include "db.h" + +#define EVALUATE_FUNCTION_NORMAL 0 +#define EVALUATE_FUNCTION_SUFFIX 1 + +#define ZBX_FLAG_SEC 0 +#define ZBX_FLAG_VALUES 1 + +extern int CONFIG_SERVER_STARTUP_TIME; + +int evaluate_function(char *value,DB_ITEM *item,char *function,char *parameter); +int evaluate_function2(char *value,char *host,char *key,char *function,char *parameter); +int add_value_suffix(char *value, int max_len, char *units, int value_type); + +#endif diff --git a/src/zabbix_proxy/events.c b/src/zabbix_proxy/events.c new file mode 100644 index 00000000..3f514030 --- /dev/null +++ b/src/zabbix_proxy/events.c @@ -0,0 +1,211 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <signal.h> + +#include <string.h> + +#include <time.h> + +#include <sys/socket.h> +#include <errno.h> + +/* Functions: pow(), round() */ +#include <math.h> + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +/*#include "actions.h"*/ +#include "functions.h" +#include "events.h" + +/****************************************************************************** + * * + * Function: add_trigger_info * + * * + * Purpose: add trigger info to event if required * + * * + * Parameters: event - event data (event.triggerid) * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: use 'free_trigger_info' function to clear allocated memory * + * * + ******************************************************************************/ +static void add_trigger_info(DB_EVENT *event) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t triggerid; + + int event_prev_status, event_last_status; + + if(event->object==EVENT_OBJECT_TRIGGER && event->objectid != 0) + { + triggerid = event->objectid; + + result = DBselect("select description,priority,comments,url,type from triggers where triggerid=" ZBX_FS_UI64, + triggerid); + row = DBfetch(result); + event->trigger_description[0]=0; + zbx_free(event->trigger_comments); + zbx_free(event->trigger_url); + + if(row) + { + strscpy(event->trigger_description, row[0]); + event->trigger_priority = atoi(row[1]); + event->trigger_comments = strdup(row[2]); + event->trigger_url = strdup(row[3]); + event->trigger_type = atoi(row[4]); + } + DBfree_result(result); + + get_latest_event_status(triggerid, &event_prev_status, &event_last_status); + zabbix_log(LOG_LEVEL_DEBUG,"event_prev_status %d event_last_status %d event->value %d", + event_prev_status, + event_last_status, + event->value); + + event->skip_actions = 0; + + switch(event->trigger_type) + { + case TRIGGER_TYPE_NORMAL: + if( (event->value == TRIGGER_VALUE_UNKNOWN) || + (event_prev_status == TRIGGER_VALUE_TRUE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_TRUE) || + (event_prev_status == TRIGGER_VALUE_FALSE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) || + (event_prev_status == TRIGGER_VALUE_UNKNOWN && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) + ) + { + zabbix_log(LOG_LEVEL_DEBUG,"Skip actions"); + event->skip_actions = 1; + } + case TRIGGER_TYPE_MULTIPLE_TRUE: + if( (event->value == TRIGGER_VALUE_UNKNOWN) || +/* (event_prev_status == TRIGGER_VALUE_TRUE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_TRUE) ||*/ + (event_prev_status == TRIGGER_VALUE_FALSE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) || + (event_prev_status == TRIGGER_VALUE_UNKNOWN && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) + ) + { + zabbix_log(LOG_LEVEL_DEBUG,"Skip actions"); + event->skip_actions = 1; + } + } + } +} + +/****************************************************************************** + * * + * Function: free_trigger_info * + * * + * Purpose: clean allocated memory by function 'add_trigger_info' * + * * + * Parameters: event - event data (event.triggerid) * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +static void free_trigger_info(DB_EVENT *event) +{ + zbx_free(event->trigger_url); + zbx_free(event->trigger_comments); +} + +/****************************************************************************** + * * + * Function: process_event * + * * + * Purpose: process new event * + * * + * Parameters: event - event data (event.eventid - new event) * + * * + * Return value: SUCCESS - event added * + * * + * Author: Alexei Vladishev * + * * + * Comments: Cannot use action->userid as it may also be groupid * + * * + ******************************************************************************/ +int process_event(DB_EVENT *event) +{ + zabbix_log(LOG_LEVEL_DEBUG,"In process_event(eventid:" ZBX_FS_UI64 ",object:%d,objectid:" ZBX_FS_UI64 ")", + event->eventid, + event->object, + event->objectid); + + add_trigger_info(event); + + if(event->eventid == 0) + { + event->eventid = DBget_maxid("events","eventid"); + } + DBexecute("insert into events(eventid,source,object,objectid,clock,value) values(" ZBX_FS_UI64 ",%d,%d," ZBX_FS_UI64 ",%d,%d)", + event->eventid, + event->source, + event->object, + event->objectid, + event->clock, + event->value); + + /* Cancel currently active alerts */ +/* if(event->value == TRIGGER_VALUE_FALSE || event->value == TRIGGER_VALUE_TRUE) + { + DBexecute("update alerts set retries=3,error='Trigger changed its status. Will not send repeats.' where triggerid=" ZBX_FS_UI64 " and repeats>0 and status=%d", + event->triggerid, ALERT_STATUS_NOT_SENT); + }*/ +/* + if(event->skip_actions == 0) + { + process_actions(event); + } +*/ + if(event->value == TRIGGER_VALUE_TRUE) + { + DBupdate_services(event->objectid, event->trigger_priority); + } + else + { + DBupdate_services(event->objectid, 0); + } + + free_trigger_info(event); + + zabbix_log(LOG_LEVEL_DEBUG,"End of process_event()"); + + return SUCCEED; +} diff --git a/src/zabbix_proxy/events.h b/src/zabbix_proxy/events.h new file mode 100644 index 00000000..b56d9f77 --- /dev/null +++ b/src/zabbix_proxy/events.h @@ -0,0 +1,29 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_EVENTS_H +#define ZABBIX_EVENTS_H + +#include "common.h" +#include "db.h" + +int process_event(DB_EVENT *event); + +#endif diff --git a/src/zabbix_proxy/expression.c b/src/zabbix_proxy/expression.c new file mode 100644 index 00000000..f288f754 --- /dev/null +++ b/src/zabbix_proxy/expression.c @@ -0,0 +1,1631 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "expression.h" +#include "functions.h" +#include "evalfunc.h" +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + + + +/****************************************************************************** + * * + * Function: str2double * + * * + * Purpose: convert string to double * + * * + * Parameters: str - string to convert * + * * + * Return value: converted double value * + * * + * Author: Alexei Vladishev * + * * + * Comments: the function automatically processes prefixes 'K','M','G' * + * * + ******************************************************************************/ +double str2double(char *str) +{ + if(str[strlen(str)-1] == 'K') + { + str[strlen(str)-1] = 0; + return (double)1024*atof(str); + } + else if(str[strlen(str)-1] == 'M') + { + str[strlen(str)-1] = 0; + return (double)1024*1024*atof(str); + } + else if(str[strlen(str)-1] == 'G') + { + str[strlen(str)-1] = 0; + return (double)1024*1024*1024*atof(str); + } + return atof(str); +} + + +/****************************************************************************** + * * + * Function: delete_spaces * + * * + * Purpose: delete all spaces * + * * + * Parameters: c - string to delete spaces * + * * + * Return value: the string wtihout spaces * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void delete_spaces(char *c) +{ + int i,j; + + j=0; + for(i=0;c[i]!=0;i++) + { + if( c[i] != ' ') + { + c[j]=c[i]; + j++; + } + } + c[j]=0; +} + +/****************************************************************************** + * * + * Function: evaluate_simple * + * * + * Purpose: evaluate simple expression * + * * + * Parameters: exp - expression string * + * * + * Return value: SUCCEED - evaluated succesfully, result - value of the exp * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: format: <double> or <double> <operator> <double> * + * * + * It is recursive function! * + * * + ******************************************************************************/ +int evaluate_simple(double *result,char *exp,char *error,int maxerrlen) +{ + double value1,value2; + char first[MAX_STRING_LEN],second[MAX_STRING_LEN]; + char *p; + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_simple(%s)", + exp); + +/* Remove left and right spaces */ + lrtrim_spaces(exp); + +/* Compress repeating - and +. Add prefix N to negative numebrs. */ + compress_signs(exp); + + /* We should process negative prefix, i.e. N123 == -123 */ + if( exp[0]=='N' && is_double_prefix(exp+1) == SUCCEED ) + { +/* str2double support prefixes */ + *result=-str2double(exp+1); + return SUCCEED; + } + else if( exp[0]!='N' && is_double_prefix(exp) == SUCCEED ) + { +/* str2double support prefixes */ + *result=str2double(exp); + return SUCCEED; + } + + /* Operators with lowest priority come first */ + /* HIGHEST / * - + < > # = & | LOWEST */ + if( (p = strchr(exp,'|')) != NULL ) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( value1 == 1) + { + *result=value1; + return SUCCEED; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( value2 == 1) + { + *result=value2; + return SUCCEED; + } + *result=0; + return SUCCEED; + } + if( (p = strchr(exp,'&')) != NULL ) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( (value1 == 1) && (value2 == 1) ) + { + *result=1; + } + else + { + *result=0; + } + return SUCCEED; + } + if((p = strchr(exp,'=')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( cmp_double(value1,value2) ==0 ) + { + *result=1; + } + else + { + *result=0; + } + return SUCCEED; + } + if((p = strchr(exp,'#')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( cmp_double(value1,value2) != 0 ) + { + *result=1; + } + else + { + *result=0; + } + return SUCCEED; + } + if((p = strchr(exp,'>')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", error); + zabbix_syslog("%s", error); + return FAIL; + } + if( value1 > value2 ) + { + *result=1; + } + else + { + *result=0; + } + return SUCCEED; + } + if((p = strchr(exp,'<')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( value1 < value2 ) + { + *result=1; + } + else + { + *result=0; + } + zabbix_log(LOG_LEVEL_DEBUG, "Result [" ZBX_FS_DBL "]",*result ); + return SUCCEED; + } + if((p = strchr(exp,'+')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + *result=value1+value2; + return SUCCEED; + } + if((p = strchr(exp,'-')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + *result=value1-value2; + return SUCCEED; + } + if((p = strchr(exp,'*')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + *result=value1*value2; + return SUCCEED; + } + if((p = strchr(exp,'/')) != NULL) + { + *p=0; + strscpy( first, exp); + *p='|'; + p++; + strscpy( second, p); + if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) + { + zabbix_log(LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if(cmp_double(value2,0) == 0) + { + zbx_snprintf(error,maxerrlen,"Division by zero. Cannot evaluate expression [%s/%s]", + first, + second); + zabbix_log(LOG_LEVEL_WARNING, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + else + { + *result=value1/value2; + } + return SUCCEED; + } + else + { + zbx_snprintf(error,maxerrlen,"Format error or unsupported operator. Exp: [%s]", + exp); + zabbix_log(LOG_LEVEL_WARNING, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: evaluate * + * * + * Purpose: evaluate simplified expression * + * * + * Parameters: exp - expression string * + * * + * Return value: SUCCEED - evaluated succesfully, result - value of the exp * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: example: ({15}>10)|({123}=1) * + * * + ******************************************************************************/ +int evaluate(int *result, char *exp, char *error, int maxerrlen) +{ + double value; + char *res; + char simple[MAX_STRING_LEN]; + char tmp[MAX_STRING_LEN]; + char value_str[MAX_STRING_LEN]; + int i,l,r; + char c; + int t; + + zabbix_log(LOG_LEVEL_DEBUG, "In evaluate(%s)", + exp); + + res = NULL; + + strscpy(tmp, exp); + t=0; + while( find_char( tmp, ')' ) != FAIL ) + { + l=-1; + r=find_char(tmp,')'); + for(i=r;i>=0;i--) + { + if( tmp[i] == '(' ) + { + l=i; + break; + } + } + if( l == -1 ) + { + zbx_snprintf(error, maxerrlen, "Cannot find left bracket [(]. Expression:[%s]", + tmp); + zabbix_log(LOG_LEVEL_WARNING, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + for(i=l+1;i<r;i++) + { + simple[i-l-1]=tmp[i]; + } + simple[r-l-1]=0; + + if( evaluate_simple( &value, simple, error, maxerrlen ) != SUCCEED ) + { + /* Changed to LOG_LEVEL_DEBUG */ + zabbix_log( LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + + /* res = first+simple+second */ + c=tmp[l]; tmp[l]='\0'; + res = zbx_strdcat(res, tmp); + tmp[l]=c; + + zbx_snprintf(value_str,MAX_STRING_LEN-1,"%lf", + value); + res = zbx_strdcat(res, value_str); + res = zbx_strdcat(res, tmp+r+1); + + delete_spaces(res); + strscpy(tmp,res); + + zbx_free(res); res = NULL; + } + if( evaluate_simple( &value, tmp, error, maxerrlen ) != SUCCEED ) + { + zabbix_log(LOG_LEVEL_WARNING, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + if(cmp_double(value,0) == 0) + { + *result = TRIGGER_VALUE_FALSE; + } + else + { + *result = TRIGGER_VALUE_TRUE; + } + + zabbix_log(LOG_LEVEL_DEBUG, "End evaluate(result:%lf)", + value); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: extract_numbers * + * * + * Purpose: Extract from string numbers with prefixes (A-Z) * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: !!! Don't forget sync code with PHP !!! * + * Use zbx_free_numbers to free allocated memory * + * * + ******************************************************************************/ +static char** extract_numbers(char *str, int *count) +{ + char *s = NULL; + char *e = NULL; + + char **result = NULL; + + int dot_founded = 0; + int len = 0; + + assert(count); + + *count = 0; + + /* find start of number */ + for ( s = str; *s; s++) + { + if ( !isdigit(*s) ) { + continue; /* for s */ + } + + if ( s != str && '{' == *(s-1) ) { + /* skip functions '{65432}' */ + s = strchr(s, '}'); + continue; /* for s */ + } + + dot_founded = 0; + /* find end of number */ + for ( e = s; *e; e++ ) + { + if ( isdigit(*e) ) { + continue; /* for e */ + } + else if ( '.' == *e && !dot_founded ) { + dot_founded = 1; + continue; /* for e */ + } + else if ( *e >= 'A' && *e <= 'Z' ) + { + e++; + } + break; /* for e */ + } + + /* number founded */ + len = e - s; + (*count)++; + result = zbx_realloc(result, sizeof(char*) * (*count)); + result[(*count)-1] = zbx_malloc(NULL, len + 1); + memcpy(result[(*count)-1], s, len); + result[(*count)-1][len] = '\0'; + + s = e; + } + + return result; +} + +static void zbx_free_numbers(char ***numbers, int count) +{ + register int i = 0; + + if ( !numbers ) return; + if ( !*numbers ) return; + + for ( i = 0; i < count; i++ ) + { + zbx_free((*numbers)[i]); + } + + zbx_free(*numbers); +} + +/****************************************************************************** + * * + * Function: expand_trigger_description_constants * + * * + * Purpose: substitute simple macros in data string with real values * + * * + * Parameters: data - trigger description * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: !!! Don't forget sync code with PHP !!! * + * replcae ONLY $1-9 macros NOT {HOSTNAME} * + * * + ******************************************************************************/ +static void expand_trigger_description_constants( + char **data, + zbx_uint64_t triggerid + ) +{ + DB_RESULT db_trigger; + DB_ROW db_trigger_data; + + char **numbers = NULL; + int numbers_cnt = 0; + + int i = 0; + + char *new_str = NULL; + + char replace[3] = "$0"; + + db_trigger = DBselect("select expression from triggers where triggerid=" ZBX_FS_UI64, triggerid); + + if ( (db_trigger_data = DBfetch(db_trigger)) ) { + + numbers = extract_numbers(db_trigger_data[0], &numbers_cnt); + + for ( i = 0; i < 9; i++ ) + { + replace[1] = '0' + i + 1; + new_str = string_replace( + *data, + replace, + i < numbers_cnt ? + numbers[i] : + "" + ); + zbx_free(*data); + *data = new_str; + } + + zbx_free_numbers(&numbers, numbers_cnt); + } + + DBfree_result(db_trigger); +} + +/****************************************************************************** + * * + * Function: substitute_simple_macros * + * * + * Purpose: substitute simple macros in data string with real values * + * * + * Parameters: trigger - trigger structure * + * action - action structure (NULL if unknown) * + * data - data string * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: {DATE},{TIME},{HOSTNAME},{IPADDRESS},{STATUS}, * + * {TRIGGER.NAME}, {TRIGGER.KEY}, {TRIGGER.SEVERITY} * + * * + ******************************************************************************/ +/* definition of macros variables */ +#define MVAR_DATE "{DATE}" +#define MVAR_EVENT_ID "{EVENT.ID}" +#define MVAR_HOST_NAME "{HOSTNAME}" +#define MVAR_IPADDRESS "{IPADDRESS}" +#define MVAR_TIME "{TIME}" +#define MVAR_ITEM_LASTVALUE "{ITEM.LASTVALUE}" +#define MVAR_ITEM_NAME "{ITEM.NAME}" +#define MVAR_TRIGGER_COMMENT "{TRIGGER.COMMENT}" +#define MVAR_TRIGGER_ID "{TRIGGER.ID}" +#define MVAR_TRIGGER_KEY "{TRIGGER.KEY}" +#define MVAR_TRIGGER_NAME "{TRIGGER.NAME}" +#define MVAR_TRIGGER_SEVERITY "{TRIGGER.SEVERITY}" +#define MVAR_TRIGGER_STATUS "{TRIGGER.STATUS}" +#define MVAR_TRIGGER_STATUS_OLD "{STATUS}" +#define MVAR_TRIGGER_VALUE "{TRIGGER.VALUE}" +#define MVAR_TRIGGER_URL "{TRIGGER.URL}" +#define MVAR_PROFILE_DEVICETYPE "{PROFILE.DEVICETYPE}" +#define MVAR_PROFILE_NAME "{PROFILE.NAME}" +#define MVAR_PROFILE_OS "{PROFILE.OS}" +#define MVAR_PROFILE_SERIALNO "{PROFILE.SERIALNO}" +#define MVAR_PROFILE_TAG "{PROFILE.TAG}" +#define MVAR_PROFILE_MACADDRESS "{PROFILE.MACADDRESS}" +#define MVAR_PROFILE_HARDWARE "{PROFILE.HARDWARE}" +#define MVAR_PROFILE_SOFTWARE "{PROFILE.SOFTWARE}" +#define MVAR_PROFILE_CONTACT "{PROFILE.CONTACT}" +#define MVAR_PROFILE_LOCATION "{PROFILE.LOCATION}" +#define MVAR_PROFILE_NOTES "{PROFILE.NOTES}" + +#define STR_UNKNOWN_VARIABLE "*UNKNOWN*" + +void substitute_simple_macros(DB_EVENT *event, DB_ACTION *action, char **data, int macro_type) +{ + + char + *pl = NULL, + *pr = NULL, + *str_out = NULL, + *replace_to = NULL; + + char tmp[MAX_STRING_LEN]; + + int var_len; + + time_t now; + struct tm *tm; + + DB_RESULT result; + DB_ROW row; + + zabbix_log(LOG_LEVEL_DEBUG, "In substitute_simple_macros()"); + + if(!data || !*data) return; + + zabbix_log(LOG_LEVEL_DEBUG, "In substitute_simple_macros (data:%s)", + *data); + + if('\0' == *data[0]) return; + + if ( macro_type & MACRO_TYPE_TRIGGER_DESCRIPTION ) { + expand_trigger_description_constants(data, event->objectid); + } + + pl = *data; + while((pr = strchr(pl, '{'))) + { + pr[0] = '\0'; +zabbix_log(LOG_LEVEL_DEBUG, "str_out1 [%s] pl [%s]", str_out, pl); + str_out = zbx_strdcat(str_out, pl); +zabbix_log(LOG_LEVEL_DEBUG, "str_out1 [%s] pl [%s]", str_out, pl); + pr[0] = '{'; + + replace_to = zbx_dsprintf(replace_to, "{"); + var_len = 1; + + if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_NAME, strlen(MVAR_TRIGGER_NAME)) == 0) + { + var_len = strlen(MVAR_TRIGGER_NAME); + + zabbix_log(LOG_LEVEL_DEBUG, "Before replace_to [%s]", replace_to); + + replace_to = zbx_dsprintf(replace_to, "%s", event->trigger_description); + /* Why it was here? *//* For substituting macros in trigger description :) */ + substitute_simple_macros(event, action, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION); + + zabbix_log(LOG_LEVEL_DEBUG, "After replace_to [%s]", replace_to); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_COMMENT, strlen(MVAR_TRIGGER_COMMENT)) == 0) + { + var_len = strlen(MVAR_TRIGGER_COMMENT); + + replace_to = zbx_dsprintf(replace_to, "%s", event->trigger_comments); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_DEVICETYPE, strlen(MVAR_PROFILE_DEVICETYPE)) == 0) + { + var_len = strlen(MVAR_PROFILE_DEVICETYPE); + + result = DBselect("select distinct p.devicetype from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.DEVECETYPE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_NAME, strlen(MVAR_PROFILE_NAME)) == 0) + { + var_len = strlen(MVAR_PROFILE_NAME); + + result = DBselect("select distinct p.name from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.NAME in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_OS, strlen(MVAR_PROFILE_OS)) == 0) + { + var_len = strlen(MVAR_PROFILE_OS); + + result = DBselect("select distinct p.os from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.OS in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_SERIALNO, strlen(MVAR_PROFILE_SERIALNO)) == 0) + { + var_len = strlen(MVAR_PROFILE_SERIALNO); + + result = DBselect("select distinct p.serialno from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.SERIALNO in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_TAG, strlen(MVAR_PROFILE_TAG)) == 0) + { + var_len = strlen(MVAR_PROFILE_TAG); + + result = DBselect("select distinct p.tag from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.TAG in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_MACADDRESS, strlen(MVAR_PROFILE_MACADDRESS)) == 0) + { + var_len = strlen(MVAR_PROFILE_MACADDRESS); + + result = DBselect("select distinct p.macaddress from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.MACADDRESS in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_HARDWARE, strlen(MVAR_PROFILE_HARDWARE)) == 0) + { + var_len = strlen(MVAR_PROFILE_HARDWARE); + + result = DBselect("select distinct p.hardware from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.HARDWARE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_SOFTWARE, strlen(MVAR_PROFILE_SOFTWARE)) == 0) + { + var_len = strlen(MVAR_PROFILE_SOFTWARE); + + result = DBselect("select distinct p.software from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.SOFTWARE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_CONTACT, strlen(MVAR_PROFILE_CONTACT)) == 0) + { + var_len = strlen(MVAR_PROFILE_CONTACT); + + result = DBselect("select distinct p.contact from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.CONTACT in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_LOCATION, strlen(MVAR_PROFILE_LOCATION)) == 0) + { + var_len = strlen(MVAR_PROFILE_LOCATION); + + result = DBselect("select distinct p.location from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.LOCATION in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_PROFILE_NOTES, strlen(MVAR_PROFILE_NOTES)) == 0) + { + var_len = strlen(MVAR_PROFILE_NOTES); + + result = DBselect("select distinct p.notes from triggers t, functions f,items i, hosts h, hosts_profiles p" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.NOTES in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_DESCRIPTION) && + strncmp(pr, MVAR_HOST_NAME, strlen(MVAR_HOST_NAME)) == 0) + { + var_len = strlen(MVAR_HOST_NAME); + + result = DBselect("select distinct h.host from triggers t, functions f,items i, hosts h " + "where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No hostname in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_ITEM_NAME, strlen(MVAR_ITEM_NAME)) == 0) + { + var_len = strlen(MVAR_ITEM_NAME); + + result = DBselect("select distinct i.description from triggers t, functions f,items i, hosts h" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid" + " order by i.description", + event->objectid); + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No ITEM.NAME in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_DESCRIPTION) && + strncmp(pr, MVAR_ITEM_LASTVALUE, strlen(MVAR_ITEM_LASTVALUE)) == 0) + { + var_len = strlen(MVAR_ITEM_LASTVALUE); + + result = DBselect("select distinct i.lastvalue,i.units,i.value_type" + " from triggers t, functions f,items i, hosts h" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid", + event->objectid); + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No ITEM.LASTVALUE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + strscpy(tmp, row[0]); + + add_value_suffix(tmp, sizeof(tmp), row[1], atoi(row[2])); + + replace_to = zbx_dsprintf(replace_to, "%s", + tmp); + } + + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_KEY, strlen(MVAR_TRIGGER_KEY)) == 0) + { + var_len = strlen(MVAR_TRIGGER_KEY); + + result = DBselect("select distinct i.key_ from triggers t, functions f,items i, hosts h" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid" + " order by i.key_", + event->objectid); + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No TRIGGER.KEY in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_IPADDRESS, strlen(MVAR_IPADDRESS)) == 0) + { + var_len = strlen(MVAR_IPADDRESS); + + result = DBselect("select distinct h.ip from triggers t, functions f,items i, hosts h" + " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid", + event->objectid); + + row = DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "No hostname in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]", + event->objectid); + + replace_to = zbx_dsprintf(replace_to, "%s", + STR_UNKNOWN_VARIABLE); + } + else + { + replace_to = zbx_dsprintf(replace_to, "%s", + row[0]); + } + DBfree_result(result); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_DATE, strlen(MVAR_DATE)) == 0) + { + var_len = strlen(MVAR_TIME); + + now = time(NULL); + tm = localtime(&now); + replace_to = zbx_dsprintf(replace_to, "%.4d.%.2d.%.2d", + tm->tm_year+1900, + tm->tm_mon+1, + tm->tm_mday); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY)&& + strncmp(pr, MVAR_TIME, strlen(MVAR_TIME)) == 0) + { + var_len = strlen(MVAR_TIME); + + now = time(NULL); + tm = localtime(&now); + replace_to = zbx_dsprintf(replace_to, "%.2d:%.2d:%.2d", + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_STATUS, strlen(MVAR_TRIGGER_STATUS)) == 0) + { + /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS_OLD block */ + var_len = strlen(MVAR_TRIGGER_STATUS); + + replace_to = zbx_dsprintf(replace_to, "%s", + event->value == TRIGGER_VALUE_TRUE ? "ON" : "OFF"); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_STATUS_OLD, strlen(MVAR_TRIGGER_STATUS_OLD)) == 0) + { + /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */ + var_len = strlen(MVAR_TRIGGER_STATUS_OLD); + + replace_to = zbx_dsprintf(replace_to, "%s", + event->value == TRIGGER_VALUE_TRUE ? "ON" : "OFF"); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_ID, strlen(MVAR_TRIGGER_ID)) == 0) + { + /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */ + var_len = strlen(MVAR_TRIGGER_ID); + + replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, + event->objectid); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_EXPRESSION) && + strncmp(pr, MVAR_TRIGGER_VALUE, strlen(MVAR_TRIGGER_VALUE)) == 0) + { + var_len = strlen(MVAR_TRIGGER_VALUE); + + replace_to = zbx_dsprintf(replace_to, "%d", + event->value); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_URL, strlen(MVAR_TRIGGER_URL)) == 0) + { + /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */ + var_len = strlen(MVAR_TRIGGER_URL); + + replace_to = zbx_dsprintf(replace_to, "%s", + event->trigger_url); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_EVENT_ID, strlen(MVAR_EVENT_ID)) == 0) + { + /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */ + var_len = strlen(MVAR_EVENT_ID); + + replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, + event->eventid); + } + else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) && + strncmp(pr, MVAR_TRIGGER_SEVERITY, strlen(MVAR_TRIGGER_SEVERITY)) == 0) + { + var_len = strlen(MVAR_TRIGGER_SEVERITY); + + if(event->trigger_priority == 0) replace_to = zbx_dsprintf(replace_to, "Not classified"); + else if(event->trigger_priority == 1) replace_to = zbx_dsprintf(replace_to, "Information"); + else if(event->trigger_priority == 2) replace_to = zbx_dsprintf(replace_to, "Warning"); + else if(event->trigger_priority == 3) replace_to = zbx_dsprintf(replace_to, "Average"); + else if(event->trigger_priority == 4) replace_to = zbx_dsprintf(replace_to, "High"); + else if(event->trigger_priority == 5) replace_to = zbx_dsprintf(replace_to, "Disaster"); + else replace_to = zbx_dsprintf(replace_to, "Unknown"); + } + +zabbix_log(LOG_LEVEL_DEBUG, "str_out2 [%s] replace_to [%s]", str_out, replace_to); + str_out = zbx_strdcat(str_out, replace_to); +zabbix_log(LOG_LEVEL_DEBUG, "str_out2 [%s] replace_to [%s]", str_out, replace_to); + pl = pr + var_len; + + zbx_free(replace_to); + } +zabbix_log(LOG_LEVEL_DEBUG, "str_out3 [%s] pl [%s]", str_out, pl); + str_out = zbx_strdcat(str_out, pl); +zabbix_log(LOG_LEVEL_DEBUG, "str_out3 [%s] pl [%s]", str_out, pl); + + zbx_free(*data); + + *data = str_out; + + zabbix_log(LOG_LEVEL_DEBUG, "End substitute_simple_macros ()"); + zabbix_log(LOG_LEVEL_DEBUG, "End substitute_simple_macros (result:%s)", + *data); +} + +/****************************************************************************** + * * + * Function: substitute_macros * + * * + * Purpose: substitute macros in data string with real values * + * * + * Parameters: trigger - trigger structure * + * action - action structure * + * data - data string * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: example: "{127.0.0.1:system[procload].last(0)}" to "1.34" * + * * + ******************************************************************************/ +void substitute_macros(DB_EVENT *event, DB_ACTION *action, char **data) +{ + char + *str_out = NULL, + *replace_to = NULL, + *pl = NULL, + *pr = NULL, + *pms = NULL, + *pme = NULL, + *p = NULL; + char + host[MAX_STRING_LEN], + key[MAX_STRING_LEN], + function[MAX_STRING_LEN], + parameter[MAX_STRING_LEN]; + + if(!data || !*data) return; + + zabbix_log(LOG_LEVEL_DEBUG, "In substitute_macros(data:%s)", + *data); + + if('\0' == *data[0]) return; + + zabbix_log(LOG_LEVEL_DEBUG, "Before substitute_simple_macros(%s)", *data); + substitute_simple_macros(event, action, data, MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY); + zabbix_log(LOG_LEVEL_DEBUG, "After substitute_simple_macros(%s)", *data); + + pl = *data; + while((pr = strchr(pl, '{'))) + { + if((pme = strchr(pr, '}')) == NULL) + break; + + pme[0] = '\0'; + + pr = strrchr(pr, '{'); /* find '{' near '}' */ + + /* copy left side */ + pr[0] = '\0'; + str_out = zbx_strdcat(str_out, pl); + pr[0] = '{'; + + + /* copy original name of variable */ + replace_to = zbx_dsprintf(replace_to, "%s}", pr); /* in format used '}' */ + /* cose in 'pr' string symbol '}' is changed to '\0' by 'pme'*/ + pl = pr + strlen(replace_to); + + pms = pr + 1; + + if(NULL != (p = strchr(pms, ':'))) + { + *p = '\0'; + zbx_snprintf(host, sizeof(host), "%s", pms); + *p = ':'; + pms = p + 1; + if(NULL != (p = strrchr(pms, '.'))) + { + *p = '\0'; + zbx_snprintf(key, sizeof(key), "%s", pms); + *p = '.'; + pms = p + 1; + if(NULL != (p = strchr(pms, '('))) + { + *p = '\0'; + zbx_snprintf(function, sizeof(function), "%s", pms); + *p = '('; + pms = p + 1; + if(NULL != (p = strchr(pms, ')'))) + { + *p = '\0'; + zbx_snprintf(parameter, sizeof(parameter), "%s", pms); + *p = ')'; + pms = p + 1; + + /* function 'evaluate_function2' require 'replace_to' with size 'MAX_STRING_LEN' */ + zbx_free(replace_to); + replace_to = zbx_malloc(replace_to, MAX_STRING_LEN); + + if(evaluate_function2(replace_to,host,key,function,parameter) != SUCCEED) + zbx_snprintf(replace_to, MAX_STRING_LEN, "%s", STR_UNKNOWN_VARIABLE); + } + } + } + + } + pme[0] = '}'; + + str_out = zbx_strdcat(str_out, replace_to); + zbx_free(replace_to); + } + str_out = zbx_strdcat(str_out, pl); + + zbx_free(*data); + + *data = str_out; + + zabbix_log( LOG_LEVEL_DEBUG, "End substitute_macros(result:%s)", + *data ); +} + +/****************************************************************************** + * * + * Function: substitute_functions * + * * + * Purpose: substitute expression functions with theirs values * + * * + * Parameters: exp - expression string * + * error - place error message here if any * + * maxerrlen - max length of error msg * + * * + * Return value: SUCCEED - evaluated succesfully, exp - updated expression * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: example: "({15}>10)|({123}=0)" => "(6.456>10)|(0=0) * + * * + ******************************************************************************/ +int substitute_functions(char **exp, char *error, int maxerrlen) +{ + char *value; + char functionid[MAX_STRING_LEN]; + int i,j; + int len; + char *out = NULL; + char c; + + zabbix_log(LOG_LEVEL_DEBUG, "In substitute_functions(%s)", + *exp); + + i = 0; + len = strlen(*exp); + while(i<len) + { + if((*exp)[i] == '{') + { + for(j=i+1;((*exp)[j]!='}')&&((*exp)[j]!='\0');j++) + { + functionid[j-i-1]=(*exp)[j]; + } + functionid[j-i-1]='\0'; + if( DBget_function_result( &value, functionid ) != SUCCEED ) + { +/* It may happen because of functions.lastvalue is NULL, so this is not warning */ + zbx_snprintf(error,maxerrlen, "Unable to get value for functionid [%s]", + functionid); + zabbix_log( LOG_LEVEL_DEBUG, "%s", + error); + zabbix_syslog("%s", + error); + return FAIL; + } + out = zbx_strdcat(out,value); + zbx_free(value); + i=j+1; + } + else + { + c=(*exp)[i+1]; (*exp)[i+1]='\0'; + out = zbx_strdcat(out, (*exp+i)); + (*exp)[i+1]=c; + i++; + } + } + zbx_free(*exp); + + *exp = out; + zabbix_log( LOG_LEVEL_DEBUG, "End substitute_functions [%s]", + *exp); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: evaluate_expression * + * * + * Purpose: evaluate expression * + * * + * Parameters: exp - expression string * + * error - place rrror message if any * + * maxerrlen - max length of error message * + * * + * Return value: SUCCEED - evaluated succesfully, result - value of the exp * + * FAIL - otherwise * + * error - error message * + * * + * Author: Alexei Vladishev * + * * + * Comments: example: ({a0:system[procload].last(0)}>1)| * + * ({a0:system[procload].max(300)}>3) * + * * + ******************************************************************************/ +int evaluate_expression(int *result,char **expression, int trigger_value, char *error, int maxerrlen) +{ + /* Required for substitution of macros */ + DB_EVENT event; + DB_ACTION action; + + zabbix_log(LOG_LEVEL_DEBUG, "In evaluate_expression(%s)", + *expression); + + /* Substitute macros first */ + memset(&event,0,sizeof(DB_EVENT)); + memset(&action,0,sizeof(DB_ACTION)); + event.value = trigger_value; + + substitute_simple_macros(&event, &action, expression, MACRO_TYPE_TRIGGER_EXPRESSION); + + /* Evaluate expression */ + delete_spaces(*expression); + if( substitute_functions(expression, error, maxerrlen) == SUCCEED) + { + if( evaluate(result, *expression, error, maxerrlen) == SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_expression(result:%d)", + *result); + return SUCCEED; + } + } + zabbix_log(LOG_LEVEL_DEBUG, "Evaluation of expression [%s] failed [%s]", + *expression, + error); + zabbix_syslog("Evaluation of expression [%s] failed [%s]", + *expression, + error); + + zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_expression(result:FAIL)"); + return FAIL; +} diff --git a/src/zabbix_proxy/expression.h b/src/zabbix_proxy/expression.h new file mode 100644 index 00000000..d3808fcc --- /dev/null +++ b/src/zabbix_proxy/expression.h @@ -0,0 +1,40 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_EXPRESSION_H +#define ZABBIX_EXPRESSION_H + +#include "common.h" +#include "db.h" + +int cmp_double(double a,double b); +int find_char(char *str,char c); +int evaluate_expression(int *result,char **expression, int triggger_value, char *error, int maxerrlen); +void substitute_macros(DB_EVENT *event, DB_ACTION *action, char **data); +void delete_reol(char *c); + +#define MACRO_TYPE_TRIGGER_DESCRIPTION 1 +#define MACRO_TYPE_MESSAGE_SUBJECT 2 +#define MACRO_TYPE_MESSAGE_BODY 4 +#define MACRO_TYPE_TRIGGER_EXPRESSION 5 + +void substitute_simple_macros(DB_EVENT *event, DB_ACTION *action, char **data, int macro_type); + +#endif diff --git a/src/zabbix_proxy/functions.c b/src/zabbix_proxy/functions.c new file mode 100644 index 00000000..53d3a2f4 --- /dev/null +++ b/src/zabbix_proxy/functions.c @@ -0,0 +1,815 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include "common.h" + +#include "comms.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "evalfunc.h" +#include "functions.h" +#include "expression.h" + +/****************************************************************************** + * * + * Function: update_functions * + * * + * Purpose: re-calculate and updates values of functions related to the item * + * * + * Parameters: item - item to update functions for * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void update_functions(DB_ITEM *item) +{ + DB_FUNCTION function; + DB_RESULT result; + DB_ROW row; + char value[MAX_STRING_LEN]; + char value_esc[MAX_STRING_LEN]; + char *lastvalue; + int ret=SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In update_functions(" ZBX_FS_UI64 ")", + item->itemid); + +/* Oracle does'n support this */ +/* zbx_snprintf(sql,sizeof(sql),"select function,parameter,itemid,lastvalue from functions where itemid=%d group by function,parameter,itemid order by function,parameter,itemid",item->itemid);*/ + result = DBselect("select distinct function,parameter,itemid,lastvalue from functions where itemid=" ZBX_FS_UI64, + item->itemid); + + while((row=DBfetch(result))) + { + function.function=row[0]; + function.parameter=row[1]; + ZBX_STR2UINT64(function.itemid,row[2]); +/* function.itemid=atoi(row[2]); */ + lastvalue=row[3]; + + zabbix_log( LOG_LEVEL_DEBUG, "ItemId:" ZBX_FS_UI64 " Evaluating %s(%s)", + function.itemid, + function.function, + function.parameter); + + ret = evaluate_function(value,item,function.function,function.parameter); + if( FAIL == ret) + { + zabbix_log( LOG_LEVEL_DEBUG, "Evaluation failed for function:%s", + function.function); + continue; + } + if (ret == SUCCEED) + { + /* Update only if lastvalue differs from new one */ + if( (lastvalue == NULL) || (strcmp(lastvalue,value) != 0)) + { + DBescape_string(value,value_esc,MAX_STRING_LEN); + DBexecute("update functions set lastvalue='%s' where itemid=" ZBX_FS_UI64 " and function='%s' and parameter='%s'", + value_esc, + function.itemid, + function.function, + function.parameter ); + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "Do not update functions, same value"); + } + } + } + + DBfree_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "End update_functions()"); +} + +/****************************************************************************** + * * + * Function: update_triggers * + * * + * Purpose: re-calculate and updates values of triggers related to the item * + * * + * Parameters: itemid - item to update trigger values for * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void update_triggers(zbx_uint64_t itemid) +{ + char *exp; + char error[MAX_STRING_LEN]; + int exp_value; + DB_TRIGGER trigger; + DB_RESULT result; + DB_ROW row; + + zabbix_log( LOG_LEVEL_DEBUG, "In update_triggers [itemid:" ZBX_FS_UI64 "]", + itemid); + + result = DBselect("select distinct t.triggerid,t.expression,t.description,t.url,t.comments,t.status,t.value,t.priority,t.type from triggers t,functions f,items i where i.status<>%d and i.itemid=f.itemid and t.status=%d and f.triggerid=t.triggerid and f.itemid=" ZBX_FS_UI64, + ITEM_STATUS_NOTSUPPORTED, + TRIGGER_STATUS_ENABLED, + itemid); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(trigger.triggerid,row[0]); + strscpy(trigger.expression,row[1]); + strscpy(trigger.description,row[2]); + trigger.url = row[3]; + trigger.comments = row[4]; + trigger.status = atoi(row[5]); + trigger.value = atoi(row[6]); + trigger.priority = atoi(row[7]); + trigger.type = atoi(row[8]); + + exp = strdup(trigger.expression); + if( evaluate_expression(&exp_value, &exp, trigger.value, error, sizeof(error)) != 0 ) + { + zabbix_log( LOG_LEVEL_WARNING, "Expression [%s] cannot be evaluated [%s]", + trigger.expression, + error); + zabbix_syslog("Expression [%s] cannot be evaluated [%s]", + trigger.expression, + error); +/* DBupdate_trigger_value(&trigger, exp_value, time(NULL), error);*//* We shouldn't update triggervalue if expressions failed */ + } + else + { + DBupdate_trigger_value(&trigger, exp_value, time(NULL), NULL); + } + zbx_free(exp); + } + DBfree_result(result); + zabbix_log( LOG_LEVEL_DEBUG, "End update_triggers [" ZBX_FS_UI64 "]", + itemid); +} + +void calc_timestamp(char *line,int *timestamp, char *format) +{ + int hh=0,mm=0,ss=0,yyyy=0,dd=0,MM=0; + int hhc=0,mmc=0,ssc=0,yyyyc=0,ddc=0,MMc=0; + int i,num; + struct tm tm; + time_t t; + + zabbix_log( LOG_LEVEL_DEBUG, "In calc_timestamp()"); + + hh=mm=ss=yyyy=dd=MM=0; + + for(i=0;(format[i]!=0)&&(line[i]!=0);i++) + { + if(isdigit(line[i])==0) continue; + num=(int)line[i]-48; + + switch ((char) format[i]) { + case 'h': + hh=10*hh+num; + hhc++; + break; + case 'm': + mm=10*mm+num; + mmc++; + break; + case 's': + ss=10*ss+num; + ssc++; + break; + case 'y': + yyyy=10*yyyy+num; + yyyyc++; + break; + case 'd': + dd=10*dd+num; + ddc++; + break; + case 'M': + MM=10*MM+num; + MMc++; + break; + } + } + + zabbix_log( LOG_LEVEL_DEBUG, "hh [%d] mm [%d] ss [%d] yyyy [%d] dd [%d] MM [%d]", + hh, + mm, + ss, + yyyy, + dd, + MM); + + /* Seconds can be ignored. No ssc here. */ + if(hhc!=0&&mmc!=0&&yyyyc!=0&&ddc!=0&&MMc!=0) + { + tm.tm_sec=ss; + tm.tm_min=mm; + tm.tm_hour=hh; + tm.tm_mday=dd; + tm.tm_mon=MM-1; + tm.tm_year=yyyy-1900; + + t=mktime(&tm); + if(t>0) + { + *timestamp=t; + } + } + + zabbix_log( LOG_LEVEL_DEBUG, "End timestamp [%d]", + *timestamp); +} + +/****************************************************************************** + * * + * Function: process_data * + * * + * Purpose: process new item value * + * * + * Parameters: sockfd - descriptor of agent-server socket connection * + * server - server name * + * key - item's key * + * value - new value of server:key * + * lastlogsize - if key=log[*], last size of log file * + * * + * Return value: SUCCEED - new value processed sucesfully * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: for trapper server process * + * * + ******************************************************************************/ +int process_data(zbx_sock_t *sock,char *server,char *key,char *value,char *lastlogsize, char *timestamp, + char *source, char *severity) +{ + AGENT_RESULT agent; + + DB_RESULT result; + DB_ROW row; + DB_ITEM item; + + char server_esc[MAX_STRING_LEN]; + char key_esc[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In process_data([%s],[%s],[%s],[%s])", + server, + key, + value, + lastlogsize); + + init_result(&agent); + + DBescape_string(server, server_esc, MAX_STRING_LEN); + DBescape_string(key, key_esc, MAX_STRING_LEN); + + result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.host='%s' and i.key_='%s' and i.status in (%d,%d) and i.type in (%d,%d) and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + HOST_STATUS_MONITORED, + server_esc, + key_esc, + ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, + ITEM_TYPE_TRAPPER, + ITEM_TYPE_ZABBIX_ACTIVE, + LOCAL_NODE("h.hostid")); + + row=DBfetch(result); + + if(!row) + { + DBfree_result(result); + return FAIL; +/* + zabbix_log( LOG_LEVEL_DEBUG, "Before checking autoregistration for [%s]", + server); + + if(autoregister(server) == SUCCEED) + { + DBfree_result(result); + + result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.host='%s' and i.key_='%s' and i.status=%d and i.type in (%d,%d) and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + HOST_STATUS_MONITORED, + server_esc, + key_esc, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_TRAPPER, + ITEM_TYPE_ZABBIX_ACTIVE, + LOCAL_NODE("h.hostid")); + row = DBfetch(result); + if(!row) + { + DBfree_result(result); + return FAIL; + } + } + else + { + DBfree_result(result); + return FAIL; + } +*/ + } + + DBget_item_from_db(&item,row); + + if( (item.type==ITEM_TYPE_ZABBIX_ACTIVE) && (zbx_tcp_check_security(sock,item.trapper_hosts,1) == FAIL)) + { + DBfree_result(result); + return FAIL; + } + + zabbix_log( LOG_LEVEL_DEBUG, "Processing [%s]", + value); + + if(strcmp(value,"ZBX_NOTSUPPORTED") ==0) + { + zabbix_log( LOG_LEVEL_WARNING, "Active parameter [%s] is not supported by agent on host [%s]", + item.key, + item.host_name); + zabbix_syslog("Active parameter [%s] is not supported by agent on host [%s]", + item.key, + item.host_name); + DBupdate_item_status_to_notsupported(item.itemid, "Not supported by ZABBIX agent"); + } + else + { + if( (strncmp(item.key,"log[",4)==0) || + (strncmp(item.key,"eventlog[",9)==0) + ) + { + item.lastlogsize=atoi(lastlogsize); + item.timestamp=atoi(timestamp); + + calc_timestamp(value,&item.timestamp,item.logtimefmt); + + item.eventlog_severity=atoi(severity); + item.eventlog_source=source; + zabbix_log(LOG_LEVEL_DEBUG, "Value [%s] Lastlogsize [%s] Timestamp [%s]", + value, + lastlogsize, + timestamp); + } + + if(set_result_type(&agent, item.value_type, value) == SUCCEED) + { + process_new_value(&item,&agent); + update_triggers(item.itemid); + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "Type of received value [%s] is not suitable for [%s@%s]", + value, + item.key, + item.host_name); + zabbix_syslog("Type of received value [%s] is not suitable for [%s@%s]", + value, + item.key, + item.host_name); + } + } + + DBfree_result(result); + + free_result(&agent); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: add_history * + * * + * Purpose: add new value to history * + * * + * Parameters: item - item data * + * value - new value of the item * + * now - new value of the item * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int add_history(DB_ITEM *item, AGENT_RESULT *value, int now) +{ + int ret = SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In add_history(key:%s,value_type:%X,type:%X)", + item->key, + item->value_type, + value->type); + + if (value->type & AR_UINT64) + zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",UINT64:"ZBX_FS_UI64")", + item->itemid, + value->ui64); + if (value->type & AR_STRING) + zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",STRING:%s)", + item->itemid, + value->str); + if (value->type & AR_DOUBLE) + zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",DOUBLE:"ZBX_FS_DBL")", + item->itemid, + value->dbl); + if (value->type & AR_TEXT) + zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",TEXT:[%s])", + item->itemid, + value->text); + + if(item->history>0) + { + if( (item->value_type==ITEM_VALUE_TYPE_FLOAT) || (item->value_type==ITEM_VALUE_TYPE_UINT64)) + { + /* Should we store delta or original value? */ + if(item->delta == ITEM_STORE_AS_IS) + { + if(item->value_type==ITEM_VALUE_TYPE_UINT64) + { + if(GET_UI64_RESULT(value)) + DBadd_history_uint(item->itemid,value->ui64,now); + } + else if(item->value_type==ITEM_VALUE_TYPE_FLOAT) + { + if(GET_DBL_RESULT(value)) + DBadd_history(item->itemid,value->dbl,now); + } + } + /* Delta as speed of change */ + else if(item->delta == ITEM_STORE_SPEED_PER_SECOND) + { + /* Save delta */ + if( ITEM_VALUE_TYPE_FLOAT == item->value_type ) + { + if(GET_DBL_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) && (now != item->lastclock)) + { + DBadd_history( + item->itemid, + (value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock), + now); + } + } + else if( ITEM_VALUE_TYPE_UINT64 == item->value_type ) + { + if(GET_UI64_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) && (now != item->lastclock)) + { + DBadd_history_uint( + item->itemid, + (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)/(now-item->lastclock), + now); + } + } + } + /* Real delta: simple difference between values */ + else if(item->delta == ITEM_STORE_SIMPLE_CHANGE) + { + /* Save delta */ + if( ITEM_VALUE_TYPE_FLOAT == item->value_type ) + { + if(GET_DBL_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) ) + { + DBadd_history(item->itemid, (value->dbl - item->prevorgvalue_dbl), now); + } + } + else if(item->value_type==ITEM_VALUE_TYPE_UINT64) + { + if(GET_UI64_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) ) + { + DBadd_history_uint(item->itemid, value->ui64 - item->prevorgvalue_uint64, now); + } + } + } + else + { + zabbix_log(LOG_LEVEL_ERR, "Value not stored for itemid [%d]. Unknown delta [%d]", + item->itemid, + item->delta); + zabbix_syslog("Value not stored for itemid [%d]. Unknown delta [%d]", + item->itemid, + item->delta); + ret = FAIL; + } + } + else if(item->value_type==ITEM_VALUE_TYPE_STR) + { + if(GET_STR_RESULT(value)) + DBadd_history_str(item->itemid,value->str,now); + } + else if(item->value_type==ITEM_VALUE_TYPE_LOG) + { + if(GET_STR_RESULT(value)) + DBadd_history_log(0, item->itemid,value->str,now,item->timestamp,item->eventlog_source,item->eventlog_severity); + } + else if(item->value_type==ITEM_VALUE_TYPE_TEXT) + { + if(GET_TEXT_RESULT(value)) + DBadd_history_text(item->itemid,value->text,now); + } + else + { + zabbix_log(LOG_LEVEL_ERR, "Unknown value type [%d] for itemid [" ZBX_FS_UI64 "]", + item->value_type, + item->itemid); + } + } + + zabbix_log( LOG_LEVEL_DEBUG, "End of add_history"); + + return ret; +} + +/****************************************************************************** + * * + * Function: update_item * + * * + * Purpose: update item info after new value is received * + * * + * Parameters: item - item data * + * value - new value of the item * + * now - current timestamp * + * * + * Author: Alexei Vladishev, Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +static void update_item(DB_ITEM *item, AGENT_RESULT *value, time_t now) +{ + char value_esc[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In update_item()"); + + value_esc[0] = '\0'; + + if(item->delta == ITEM_STORE_AS_IS) + { + if(GET_STR_RESULT(value)) + { + DBescape_string(value->str, value_esc, sizeof(value_esc)); + } + + if (item->value_type == ITEM_VALUE_TYPE_LOG) { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,lastvalue='%s',lastclock=%d,lastlogsize=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay, item->delay_flex, now), + value_esc, + (int)now, + item->lastlogsize, + item->itemid); + } else { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,lastvalue='%s',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay, item->delay_flex, now), + value_esc, + (int)now, + item->itemid); + } + } + /* Logic for delta as speed of change */ + else if(item->delta == ITEM_STORE_SPEED_PER_SECOND) + { + if(item->value_type == ITEM_VALUE_TYPE_FLOAT) + { + if(GET_DBL_RESULT(value)) + { + if((item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) ) + { + /* In order to continue normal processing, we assume difference 1 second + Otherwise function update_functions and update_triggers won't work correctly*/ + if(now != item->lastclock) + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "'," + "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->dbl, + (value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock), + (int)now, + item->itemid); + SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock)); + } + else + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "'," + "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->dbl, + value->dbl - item->prevorgvalue_dbl, + (int)now, + item->itemid); + SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl)); + } + } + else + { + DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->dbl, + (int)now, + item->itemid); + } + } + } + else if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + if(GET_UI64_RESULT(value)) + { + if((item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) ) + { + if(now != item->lastclock) + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "'," + "lastvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->ui64, + ((zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64))/(now-item->lastclock), + (int)now, + item->itemid); + SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)/(now-item->lastclock)); + } + else + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "'," + "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->ui64, + (double)(value->ui64 - item->prevorgvalue_uint64), + (int)now, + item->itemid); + SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)); + } + } + else + { + DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->ui64, + (int)now, + item->itemid); + } + } + } + } + /* Real delta: simple difference between values */ + else if(item->delta == ITEM_STORE_SIMPLE_CHANGE) + { + if(item->value_type == ITEM_VALUE_TYPE_FLOAT) + { + if(GET_DBL_RESULT(value)) + { + if((item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl)) + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "'," + "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->dbl, + (value->dbl - item->prevorgvalue_dbl), + (int)now, + item->itemid); + SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl)); + } + else + { + DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex, now), + value->dbl, + (int)now, + item->itemid); + } + } + } + else if(item->value_type == ITEM_VALUE_TYPE_UINT64) + { + if(GET_UI64_RESULT(value)) + { + if((item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64)) + { + DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "'," + "lastvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now), + value->ui64, + (value->ui64 - item->prevorgvalue_uint64), + (int)now, + item->itemid); + SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)); + } + else + { + DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64, + calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex, now), + value->ui64, + (int)now, + item->itemid); + } + } + } + } + + item->prevvalue_str = item->lastvalue_str; + item->prevvalue_dbl = item->lastvalue_dbl; + item->prevvalue_uint64 = item->lastvalue_uint64; + item->prevvalue_null = item->lastvalue_null; + + item->lastvalue_uint64 = value->ui64; + item->lastvalue_dbl = value->dbl; + item->lastvalue_str = value->str; + item->lastvalue_null = 0; + +/* Update item status if required */ + if(item->status == ITEM_STATUS_NOTSUPPORTED) + { + zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] became supported by agent on host [%s]", + item->key, + item->host_name); + zabbix_syslog("Parameter [%s] became supported by agent on host [%s]", + item->key, + item->host_name); + item->status = ITEM_STATUS_ACTIVE; + DBexecute("update items set status=%d where itemid=" ZBX_FS_UI64, + ITEM_STATUS_ACTIVE, + item->itemid); + } + + /* Required for nodata() */ + item->lastclock = now; + + zabbix_log( LOG_LEVEL_DEBUG, "End update_item()"); +} + +/****************************************************************************** + * * + * Function: process_new_value * + * * + * Purpose: process new item value * + * * + * Parameters: item - item data * + * value - new value of the item * + * * + * Author: Alexei Vladishev * + * * + * Comments: for trapper poller process * + * * + ******************************************************************************/ +void process_new_value(DB_ITEM *item, AGENT_RESULT *value) +{ + time_t now; + + zabbix_log( LOG_LEVEL_DEBUG, "In process_new_value(%s)", + item->key); + + now = time(NULL); + + if( ITEM_MULTIPLIER_USE == item->multiplier ) + { + if( ITEM_VALUE_TYPE_FLOAT == item->value_type ) + { + if(GET_DBL_RESULT(value)) + { + UNSET_RESULT_EXCLUDING(value, AR_DOUBLE); + SET_DBL_RESULT(value, value->dbl * strtod(item->formula, NULL)); + } + } + else if( ITEM_VALUE_TYPE_UINT64 == item->value_type ) + { + if(GET_UI64_RESULT(value)) + { + UNSET_RESULT_EXCLUDING(value, AR_UINT64); + if(is_uint(item->formula) == SUCCEED) + { + SET_UI64_RESULT(value, value->ui64 * zbx_atoui64((item->formula))); + } + else + { + SET_UI64_RESULT(value, (zbx_uint64_t)((double)value->ui64 * strtod(item->formula, NULL))); + } + } + } + } + + add_history(item, value, now); + update_item(item, value, now); + update_functions( item ); +} diff --git a/src/zabbix_proxy/functions.h b/src/zabbix_proxy/functions.h new file mode 100644 index 00000000..79d64bbd --- /dev/null +++ b/src/zabbix_proxy/functions.h @@ -0,0 +1,34 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_FUNCTIONS_H +#define ZABBIX_FUNCTIONS_H + +#include "common.h" +#include "comms.h" +#include "db.h" +#include "sysinfo.h" + +void update_triggers (zbx_uint64_t itemid); +void update_functions(DB_ITEM *item); +int process_data(zbx_sock_t *sock,char *server,char *key, char *value,char *lastlogsize,char *timestamp, + char *source, char *severity); +void process_new_value(DB_ITEM *item, AGENT_RESULT *value); + +#endif diff --git a/src/zabbix_proxy/housekeeper/Makefile.am b/src/zabbix_proxy/housekeeper/Makefile.am new file mode 100644 index 00000000..315f0d24 --- /dev/null +++ b/src/zabbix_proxy/housekeeper/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxhousekeeper.a + +libzbxhousekeeper_a_SOURCES = housekeeper.c housekeeper.h diff --git a/src/zabbix_proxy/housekeeper/housekeeper.c b/src/zabbix_proxy/housekeeper/housekeeper.c new file mode 100644 index 00000000..048ac76e --- /dev/null +++ b/src/zabbix_proxy/housekeeper/housekeeper.c @@ -0,0 +1,375 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "cfg.h" +#include "db.h" +#include "log.h" + +#include "housekeeper.h" + +/****************************************************************************** + * * + * Function: housekeeping_process_log * + * * + * Purpose: process table 'housekeeper' and remove data if required * + * * + * Parameters: * + * * + * Return value: SUCCEED - information removed succesfully * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int housekeeping_process_log() +{ + DB_HOUSEKEEPER housekeeper; + + DB_RESULT result; + DB_ROW row; + int res = SUCCEED; + + long deleted; + + zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_process_log()"); + + /* order by tablename to effectively use DB cache */ + result = DBselect("select housekeeperid, tablename, field, value from housekeeper order by tablename"); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(housekeeper.housekeeperid,row[0]); + housekeeper.tablename=row[1]; + housekeeper.field=row[2]; + ZBX_STR2UINT64(housekeeper.value,row[3]); + +#ifdef HAVE_ORACLE + deleted = DBexecute("delete from %s where %s=" ZBX_FS_UI64 " and rownum<500", + housekeeper.tablename, + housekeeper.field, + housekeeper.value); +#elif defined(HAVE_POSTGRESQL) + deleted = DBexecute("delete from %s where oid in (select oid from %s where %s=" ZBX_FS_UI64 " limit 500)", + housekeeper.tablename, + housekeeper.tablename, + housekeeper.field, + housekeeper.value); +#else + deleted = DBexecute("delete from %s where %s=" ZBX_FS_UI64 " limit 500", + housekeeper.tablename, + housekeeper.field, + housekeeper.value); +#endif + if(deleted == 0) + { + DBexecute("delete from housekeeper where housekeeperid=" ZBX_FS_UI64, + housekeeper.housekeeperid); + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [%s]", + deleted, + housekeeper.tablename); + } + } + DBfree_result(result); + + return res; +} + + +static int housekeeping_sessions(int now) +{ + int deleted; + + zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_sessions(%d)", + now); + + deleted = DBexecute("delete from sessions where lastaccess<%d", + now-24*3600); + + zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [sessions]", + deleted); + + return SUCCEED; +} + +static int housekeeping_alerts(int now) +{ + int alert_history; + DB_RESULT result; + DB_ROW row; + int res = SUCCEED; + int deleted; + + zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_alerts(%d)", + now); + + result = DBselect("select alert_history from config"); + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_ERR, "No records in table 'config'."); + res = FAIL; + } + else + { + alert_history=atoi(row[0]); + + deleted = DBexecute("delete from alerts where clock<%d", + now-24*3600*alert_history); + zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [alerts]", + deleted); + } + + DBfree_result(result); + return res; +} + +static int housekeeping_events(int now) +{ + int event_history; + DB_RESULT result; + DB_RESULT result2; + DB_ROW row1; + DB_ROW row2; + zbx_uint64_t eventid; + int res = SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_events(%d)", + now); + + result = DBselect("select event_history from config"); + + row1=DBfetch(result); + + if(!row1 || DBis_null(row1[0])==SUCCEED) + { + zabbix_log( LOG_LEVEL_ERR, "No records in table 'config'."); + res = FAIL; + } + else + { + event_history=atoi(row1[0]); + + result2 = DBselect("select eventid from events where clock<%d", + now-24*3600*event_history); + while((row2=DBfetch(result2))) + { + ZBX_STR2UINT64(eventid,row2[0]); + + DBexecute("delete from acknowledges where eventid=" ZBX_FS_UI64, + eventid); + + DBexecute("delete from events where eventid=" ZBX_FS_UI64, + eventid); + } + DBfree_result(result2); + + } + + DBfree_result(result); + return res; +} + +/****************************************************************************** + * * + * Function: delete_history * + * * + * Purpose: remove outdated information from historical table * + * * + * Parameters: now - current timestamp * + * * + * Return value: number of rows deleted * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int delete_history(char *table, zbx_uint64_t itemid, int keep_history, int now) +{ + DB_RESULT result; + DB_ROW row; + int min_clock; + + zabbix_log( LOG_LEVEL_DEBUG, "In delete_history(%s," ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d)", + table, + itemid, + keep_history, + now); + + result = DBselect("select min(clock) from %s where itemid=" ZBX_FS_UI64, + table, + itemid); + + row=DBfetch(result); + + if(!row || DBis_null(row[0]) == SUCCEED) + { + DBfree_result(result); + return 0; + } + + min_clock = atoi(row[0]); + DBfree_result(result); + +/* zabbix_log( LOG_LEVEL_DEBUG, "Now %d keep_history %d Itemid " ZBX_FS_UI64 " min %d new min %d", + now, + keep_history, + itemid, + min_clock, + MIN(now-24*3600*keep_history, min_clock+4*3600*CONFIG_HOUSEKEEPING_FREQUENCY));*/ + + return DBexecute("delete from %s where itemid=" ZBX_FS_UI64 " and clock<%d", + table, + itemid, + MIN(now-24*3600*keep_history, min_clock+4*3600*CONFIG_HOUSEKEEPING_FREQUENCY) + ); +} + +/****************************************************************************** + * * + * Function: housekeeping_history_and_trends * + * * + * Purpose: remove outdated information from history and trends * + * * + * Parameters: now - current timestamp * + * * + * Return value: SUCCEED - information removed succesfully * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int housekeeping_history_and_trends(int now) +{ + DB_ITEM item; + + DB_RESULT result; + DB_ROW row; + + int deleted = 0; + + zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_history_and_trends(%d)", + now); + + result = DBselect("select itemid,history,trends from items"); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(item.itemid,row[0]); + item.history=atoi(row[1]); + item.trends=atoi(row[2]); + + deleted += delete_history("history", item.itemid, item.history, now); + deleted += delete_history("history_uint", item.itemid, item.history, now); + deleted += delete_history("history_str", item.itemid, item.history, now); + deleted += delete_history("history_text", item.itemid, item.history, now); + deleted += delete_history("history_log", item.itemid, item.history, now); + deleted += delete_history("trends", item.itemid, item.trends, now); + } + DBfree_result(result); + return deleted; +} + +int main_housekeeper_loop() +{ + int now; + int d; + + if(CONFIG_DISABLE_HOUSEKEEPING == 1) + { + for(;;) + { +/* Do nothing */ + zbx_setproctitle("do nothing"); + + sleep(3600); + } + } + + for(;;) + { + zabbix_log( LOG_LEVEL_WARNING, "Executing housekeeper"); + now = time(NULL); + + zbx_setproctitle("connecting to the database"); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + +/* Transaction is not required here. It causes timeouts under MySQL */ +/* DBbegin();*/ + +/* zbx_setproctitle("housekeeper [removing deleted hosts]");*/ + +/* housekeeping_hosts();*/ + +/* zbx_setproctitle("housekeeper [removing deleted items]");*/ + +/* housekeeping_items();*/ + +/* zbx_setproctitle("housekeeper [removing old history]");*/ + + d = housekeeping_history_and_trends(now); + zabbix_log( LOG_LEVEL_WARNING, "Deleted %d records from history and trends", + d); + + zbx_setproctitle("housekeeper [removing old history]"); + + housekeeping_process_log(now); + + zbx_setproctitle("housekeeper [removing old events]"); + + housekeeping_events(now); + + zbx_setproctitle("housekeeper [removing old alerts]"); + + housekeeping_alerts(now); + + zbx_setproctitle("housekeeper [removing old sessions]"); + + housekeeping_sessions(now); + + zbx_setproctitle("housekeeper [vacuuming database]"); + +/* Transaction is not required here. It causes timeouts under MySQL */ +/* DBcommit();*/ + + DBvacuum(); + + zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d hours", + CONFIG_HOUSEKEEPING_FREQUENCY); + + zbx_setproctitle("housekeeper [sleeping for %d hour(s)]", + CONFIG_HOUSEKEEPING_FREQUENCY); + + DBclose(); + zabbix_log( LOG_LEVEL_DEBUG, "Next housekeeper run is after %dh", + CONFIG_HOUSEKEEPING_FREQUENCY); + sleep(3660*CONFIG_HOUSEKEEPING_FREQUENCY); + } +} diff --git a/src/zabbix_proxy/housekeeper/housekeeper.h b/src/zabbix_proxy/housekeeper/housekeeper.h new file mode 100644 index 00000000..ecb9bb52 --- /dev/null +++ b/src/zabbix_proxy/housekeeper/housekeeper.h @@ -0,0 +1,29 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_HOUSEKEEPER_H +#define ZABBIX_HOUSEKEEPER_H + +extern int CONFIG_DISABLE_HOUSEKEEPING; +extern int CONFIG_HOUSEKEEPING_FREQUENCY; +extern char *CONFIG_FPING_LOCATION; + +int main_housekeeper_loop(); + +#endif diff --git a/src/zabbix_proxy/httppoller/Makefile.am b/src/zabbix_proxy/httppoller/Makefile.am new file mode 100644 index 00000000..07706687 --- /dev/null +++ b/src/zabbix_proxy/httppoller/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxhttppoller.a + +libzbxhttppoller_a_SOURCES = \ + httpmacro.c httpmacro.h \ + httptest.c httptest.h \ + httppoller.c httppoller.h diff --git a/src/zabbix_proxy/httppoller/httpmacro.c b/src/zabbix_proxy/httppoller/httpmacro.c new file mode 100644 index 00000000..4e14fe9b --- /dev/null +++ b/src/zabbix_proxy/httppoller/httpmacro.c @@ -0,0 +1,133 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "pid.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "httpmacro.h" + +/****************************************************************************** + * * + * Function: http_substitute_macros * + * * + * Purpose: substitute macros in input string by value from http test config * + * * + * Parameters: httptest - http test data, data - string to substitute macros * + * * + * Return value: - * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void http_substitute_macros(DB_HTTPTEST *httptest, char *data, int data_max_len) +{ + char + *pl = NULL, + *pr = NULL, + str_out[MAX_STRING_LEN], + replace_to[MAX_STRING_LEN], + *c,*c2, save,*replacement,save2; + int + outlen, + var_len; + + zabbix_log(LOG_LEVEL_DEBUG, "In http_substitute_macros(httptestid:" ZBX_FS_UI64 ", data:%s)", + httptest->httptestid, + data); + + assert(data); + + *str_out = '\0'; + outlen = sizeof(str_out) - 1; + pl = data; + while((pr = strchr(pl, '{')) && outlen > 0) + { + pr[0] = '\0'; + zbx_strlcat(str_out, pl, outlen); + outlen -= MIN(strlen(pl), outlen); + pr[0] = '{'; + + zbx_snprintf(replace_to, sizeof(replace_to), "{"); + var_len = 1; + + + if(NULL!=(c=strchr(pr,'}'))) + { + /* Macro in pr */ + save = c[1]; c[1]=0; + + if(NULL != (c2 = strstr(httptest->macros,pr))) + { + if(NULL != (replacement = strchr(c2,'='))) + { + replacement++; + if(NULL != (c2 = strchr(replacement,'\r'))) + { + save2 = c2[0]; c2[0]=0; + var_len = strlen(pr); + zbx_snprintf(replace_to, sizeof(replace_to), "%s", replacement); + c2[0] = save2; + } + else + { + var_len = strlen(pr); + zbx_snprintf(replace_to, sizeof(replace_to), "%s", replacement); + } + } + + } +/* result = DBselect("select value from httpmacro where macro='%s' and httptestid=" ZBX_FS_UI64, + pr, httptest->httptestid); + row = DBfetch(result); + if(row) + { + var_len = strlen(pr); + zbx_snprintf(replace_to, sizeof(replace_to), "%s", row[0]); + } + DBfree_result(result);*/ + /* Restore pr */ + c[1]=save; + } + +/* if(strncmp(pr, "TRIGGER.NAME", strlen("TRIGGER.NAME")) == 0) + { + var_len = strlen("TRIGGER.NAME"); + + zbx_snprintf(replace_to, sizeof(replace_to), "%s", event->trigger_description); + substitute_simple_macros(event, action, replace_to, sizeof(replace_to), MACRO_TYPE_TRIGGER_DESCRIPTION); + }*/ + zbx_strlcat(str_out, replace_to, outlen); + outlen -= MIN(strlen(replace_to), outlen); + pl = pr + var_len; + } + zbx_strlcat(str_out, pl, outlen); + outlen -= MIN(strlen(pl), outlen); + + zbx_snprintf(data, data_max_len, "%s", str_out); + + zabbix_log( LOG_LEVEL_DEBUG, "Result expression [%s]", + data); +} diff --git a/src/zabbix_proxy/httppoller/httpmacro.h b/src/zabbix_proxy/httppoller/httpmacro.h new file mode 100644 index 00000000..3a3a2abf --- /dev/null +++ b/src/zabbix_proxy/httppoller/httpmacro.h @@ -0,0 +1,25 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_HTTPMACRO_H +#define ZABBIX_HTTPMACRO_H + +void http_substitute_macros(DB_HTTPTEST *httptest, char *data, int data_max_len); + +#endif diff --git a/src/zabbix_proxy/httppoller/httppoller.c b/src/zabbix_proxy/httppoller/httppoller.c new file mode 100644 index 00000000..ef07fa05 --- /dev/null +++ b/src/zabbix_proxy/httppoller/httppoller.c @@ -0,0 +1,165 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "pid.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "../functions.h" +#include "../expression.h" +#include "httptest.h" +#include "httppoller.h" + +#include "daemon.h" + +int httppoller_num; + +/****************************************************************************** + * * + * Function: get_minnextcheck * + * * + * Purpose: calculate when we have to process earliest httptest * + * * + * Parameters: now - current timestamp * + * * + * Return value: timestamp of earliest check or -1 if not found * + * * + * Author: Alexei Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +static int get_minnextcheck(int now) +{ + DB_RESULT result; + DB_ROW row; + + int res; + + result = DBselect("select count(*),min(nextcheck) from httptest t where t.status=%d and " ZBX_SQL_MOD(t.httptestid,%d) "=%d and " ZBX_COND_NODEID, + HTTPTEST_STATUS_MONITORED, + CONFIG_HTTPPOLLER_FORKS, + httppoller_num-1, + LOCAL_NODE("t.httptestid")); + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED || DBis_null(row[1])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "No httptests to process in get_minnextcheck."); + res = FAIL; + } + else + { + if( atoi(row[0]) == 0) + { + res = FAIL; + } + else + { + res = atoi(row[1]); + } + } + DBfree_result(result); + + return res; +} + +/****************************************************************************** + * * + * Function: main_httppoller_loop * + * * + * Purpose: main loop of processing of httptests * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +void main_httppoller_loop(int num) +{ + int now; + int nextcheck,sleeptime; + + zabbix_log( LOG_LEVEL_DEBUG, "In main_httppoller_loop(num:%d)", + num); + + httppoller_num = num; + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + for(;;) + { + zbx_setproctitle("http poller [getting values]"); + + now=time(NULL); + process_httptests(now); + + zabbix_log( LOG_LEVEL_DEBUG, "Spent %d seconds while processing HTTP tests", + (int)time(NULL)-now); + + nextcheck=get_minnextcheck(now); + zabbix_log( LOG_LEVEL_DEBUG, "Nextcheck:%d Time:%d", + nextcheck, + (int)time(NULL)); + + if( FAIL == nextcheck) + { + sleeptime=POLLER_DELAY; + } + else + { + sleeptime=nextcheck-time(NULL); + if(sleeptime<0) + { + sleeptime=0; + } + } + if(sleeptime>0) + { + if(sleeptime > POLLER_DELAY) + { + sleeptime = POLLER_DELAY; + } + zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d seconds", + sleeptime ); + + zbx_setproctitle("http poller [sleeping for %d seconds]", + sleeptime); + + sleep( sleeptime ); + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "No sleeping" ); + } + +#ifdef ZABBIX_TEST + break; +#endif /* ZABBIX_TEST */ + } +} diff --git a/src/zabbix_proxy/httppoller/httppoller.h b/src/zabbix_proxy/httppoller/httppoller.h new file mode 100644 index 00000000..eb0d63e0 --- /dev/null +++ b/src/zabbix_proxy/httppoller/httppoller.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_HTTPPOLLER_H +#define ZABBIX_HTTPPOLLER_H + +extern void signal_handler(int); +extern int server_num; + +extern int CONFIG_HTTPPOLLER_FORKS; + +void main_httppoller_loop(int num); + +#endif diff --git a/src/zabbix_proxy/httppoller/httptest.c b/src/zabbix_proxy/httppoller/httptest.c new file mode 100644 index 00000000..cc7fefc4 --- /dev/null +++ b/src/zabbix_proxy/httppoller/httptest.c @@ -0,0 +1,544 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "pid.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "../functions.h" +#include "httpmacro.h" +#include "httptest.h" + +#ifdef HAVE_LIBCURL + +static S_ZBX_HTTPPAGE page; + +/****************************************************************************** + * * + * Function: process_value * + * * + * Purpose: process new item value * + * * + * Parameters: key - item key * + * host - host name * + * value - new value of the item * + * * + * Return value: SUCCEED - new value sucesfully processed * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: can be done in process_data() * + * * + ******************************************************************************/ +static int process_value(zbx_uint64_t itemid, AGENT_RESULT *value) +{ + DB_RESULT result; + DB_ROW row; + DB_ITEM item; + + INIT_CHECK_MEMORY(); + + zabbix_log( LOG_LEVEL_DEBUG, "In process_value(itemid:" ZBX_FS_UI64 ")", + itemid); + + result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and i.status=%d and i.type=%d and i.itemid=" ZBX_FS_UI64 " and " ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + HOST_STATUS_MONITORED, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_HTTPTEST, + itemid, + LOCAL_NODE("h.hostid")); + row=DBfetch(result); + + if(!row) + { + DBfree_result(result); + zabbix_log( LOG_LEVEL_DEBUG, "End process_value(result:FAIL)"); + return FAIL; + } + + DBget_item_from_db(&item,row); + + DBbegin(); + process_new_value(&item,value); + update_triggers(item.itemid); + DBcommit(); + + DBfree_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "End process_value()"); + + CHECK_MEMORY("process_value", "end"); + + return SUCCEED; +} + +static size_t WRITEFUNCTION2( void *ptr, size_t size, size_t nmemb, void *stream) +{ + size_t r_size = size*nmemb; + + /* First piece of data */ + if(page.data == NULL) + { + page.allocated=MAX(8096, r_size); + page.offset=0; + page.data=malloc(page.allocated); + } + + zbx_snprintf_alloc(&page.data, &page.allocated, &page.offset, MAX(8096, r_size), "%s", ptr); + + return r_size; +} + +static size_t HEADERFUNCTION2( void *ptr, size_t size, size_t nmemb, void *stream) +{ +/* + ZBX_LIM_PRINT("HEADERFUNCTION", size*nmemb, ptr, 300); + zabbix_log(LOG_LEVEL_WARNING, "In HEADERFUNCTION"); +*/ + + return size*nmemb; +} + +static void process_test_data(DB_HTTPTEST *httptest, S_ZBX_HTTPSTAT *stat) +{ + DB_RESULT result; + DB_ROW row; + DB_HTTPTESTITEM httptestitem; + + AGENT_RESULT value; + + INIT_CHECK_MEMORY(); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_test_data(test:%s,time:" ZBX_FS_DBL ",last step:%d)", + httptest->name, + stat->test_total_time, + stat->test_last_step); + + result = DBselect("select httptestitemid,httptestid,itemid,type from httptestitem where httptestid=" ZBX_FS_UI64, + httptest->httptestid); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(httptestitem.httptestitemid, row[0]); + ZBX_STR2UINT64(httptestitem.httptestid, row[1]); + ZBX_STR2UINT64(httptestitem.itemid, row[2]); + httptestitem.type=atoi(row[3]); + + init_result(&value); + + switch (httptestitem.type) { + case ZBX_HTTPITEM_TYPE_TIME: + SET_DBL_RESULT(&value, stat->test_total_time); + process_value(httptestitem.itemid,&value); + break; + case ZBX_HTTPITEM_TYPE_LASTSTEP: + SET_UI64_RESULT(&value, stat->test_last_step); + process_value(httptestitem.itemid,&value); + break; + default: + break; + } + + free_result(&value); + } + + DBfree_result(result); + zabbix_log(LOG_LEVEL_DEBUG, "End process_test_data()"); + + CHECK_MEMORY("process_test_data", "end"); +} + + +static void process_step_data(DB_HTTPTEST *httptest, DB_HTTPSTEP *httpstep, S_ZBX_HTTPSTAT *stat) +{ + DB_RESULT result; + DB_ROW row; + DB_HTTPSTEPITEM httpstepitem; + + AGENT_RESULT value; + + INIT_CHECK_MEMORY(); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_step_data(step:%s,url:%s,rsp:%d,time:" ZBX_FS_DBL ",speed:" ZBX_FS_DBL ")", + httpstep->name, + httpstep->url, + stat->rspcode, + stat->total_time, + stat->speed_download); + + result = DBselect("select httpstepitemid,httpstepid,itemid,type from httpstepitem where httpstepid=" ZBX_FS_UI64, + httpstep->httpstepid); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(httpstepitem.httpstepitemid, row[0]); + ZBX_STR2UINT64(httpstepitem.httpstepid, row[1]); + ZBX_STR2UINT64(httpstepitem.itemid, row[2]); + httpstepitem.type=atoi(row[3]); + + init_result(&value); + + switch (httpstepitem.type) { + case ZBX_HTTPITEM_TYPE_RSPCODE: + SET_UI64_RESULT(&value, stat->rspcode); + process_value(httpstepitem.itemid,&value); + break; + case ZBX_HTTPITEM_TYPE_TIME: + SET_DBL_RESULT(&value, stat->total_time); + process_value(httpstepitem.itemid,&value); + break; + case ZBX_HTTPITEM_TYPE_SPEED: + SET_DBL_RESULT(&value, stat->speed_download); + process_value(httpstepitem.itemid,&value); + break; + default: + break; + } + + free_result(&value); + } + + DBfree_result(result); + zabbix_log(LOG_LEVEL_DEBUG, "End process_step_data()"); + + CHECK_MEMORY("process_step_data", "end"); +} + +/****************************************************************************** + * * + * Function: process_httptest * + * * + * Purpose: process single scenario of http test * + * * + * Parameters: httptestid - ID of http test * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: SUCCEED or FAIL * + * * + ******************************************************************************/ +static void process_httptest(DB_HTTPTEST *httptest) +{ + DB_RESULT result; + DB_ROW row; + DB_HTTPSTEP httpstep; + int err; + char *err_str = NULL, *esc_err_str = NULL; + int now; + int lastfailedstep; + + S_ZBX_HTTPSTAT stat; + + CURL *easyhandle = NULL; + + INIT_CHECK_MEMORY(); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_httptest(httptestid:" ZBX_FS_UI64 ",name:%s)", + httptest->httptestid, + httptest->name); + + now = time(NULL); + + DBexecute("update httptest set lastcheck=%d where httptestid=" ZBX_FS_UI64, + now, + httptest->httptestid); + + easyhandle = curl_easy_init(); + if(easyhandle == NULL) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot init CURL"); + + return; + } + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_COOKIEFILE, ""))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_COOKIEFILE [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, httptest->agent))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_USERAGENT [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_FOLLOWLOCATION [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_WRITEFUNCTION ,WRITEFUNCTION2))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_WRITEFUNCTION [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_HEADERFUNCTION ,HEADERFUNCTION2))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_WRITEFUNCTION [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + /* Process self-signed certificates. Do not verify certificate. */ + if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_SSL_VERIFYPEER , 0))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_SSL_VERIFYPEER [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + + /* Process certs whose hostnames do not match the queried hostname. */ + if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_SSL_VERIFYHOST , 0))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_SSL_VERIFYHOST [%s]", + curl_easy_strerror(err)); + (void)curl_easy_cleanup(easyhandle); + return; + } + + lastfailedstep=0; + httptest->time = 0; + result = DBselect("select httpstepid,httptestid,no,name,url,timeout,posts,required,status_codes from httpstep where httptestid=" ZBX_FS_UI64 " order by no", + httptest->httptestid); + now=time(NULL); + while((row=DBfetch(result)) && !err_str) + { + /* NOTE: do not use break or return for this block! + * process_step_data calling required! + */ + ZBX_STR2UINT64(httpstep.httpstepid, row[0]); + ZBX_STR2UINT64(httpstep.httptestid, row[1]); + httpstep.no=atoi(row[2]); + httpstep.name=row[3]; + strscpy(httpstep.url,row[4]); + httpstep.timeout=atoi(row[5]); + strscpy(httpstep.posts,row[6]); + strscpy(httpstep.required,row[7]); + strscpy(httpstep.status_codes,row[8]); + + DBexecute("update httptest set curstep=%d,curstate=%d where httptestid=" ZBX_FS_UI64, + httpstep.no, + HTTPTEST_STATE_BUSY, + httptest->httptestid); + + memset(&stat,0,sizeof(stat)); + + /* Substitute macros */ + http_substitute_macros(httptest,httpstep.url, sizeof(httpstep.url)); + + http_substitute_macros(httptest,httpstep.posts, sizeof(httpstep.posts)); + /* zabbix_log(LOG_LEVEL_WARNING, "POSTS [%s]", httpstep.posts); */ + if(httpstep.posts[0] != 0) + { + zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: use post [%s]", httpstep.posts); + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, httpstep.posts))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set POST vars [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + } + if( !err_str ) + { + zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: Go to URL [%s]", httpstep.url); + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_URL, httpstep.url))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set URL [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + } + if( !err_str ) + { + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, httpstep.timeout))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set TIMEOUT [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + } + if( !err_str ) + { + if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_CONNECTTIMEOUT, httpstep.timeout))) + { + zabbix_log(LOG_LEVEL_ERR, "Cannot set CONNECTTIMEOUT [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + } + + if( !err_str ) + { + memset(&page, 0, sizeof(page)); + if(CURLE_OK != (err = curl_easy_perform(easyhandle))) + { + zabbix_log(LOG_LEVEL_ERR, "Error doing curl_easy_perform [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + else + { + if(httpstep.required[0]!='\0' && zbx_regexp_match(page.data,httpstep.required,NULL) == NULL) + { + zabbix_log(LOG_LEVEL_DEBUG, "Page didn't match [%s]", httpstep.required); + err_str = strdup("Page didn't match"); + lastfailedstep = httpstep.no; + } + } + free(page.data); + + if( !err_str ) + { + if(CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_RESPONSE_CODE ,&stat.rspcode))) + { + zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_RESPONSE_CODE [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + else if(httpstep.status_codes[0]!='\0' && (int_in_list(httpstep.status_codes,stat.rspcode) == FAIL)) + { + zabbix_log(LOG_LEVEL_DEBUG, "Status code didn't match [%s]", httpstep.status_codes); + err_str = strdup("Status code didn't match"); + lastfailedstep = httpstep.no; + } + } + + if( !err_str && CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_TOTAL_TIME ,&stat.total_time))) + { + zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_TOTAL_TIME [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + + if( !err_str && CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_SPEED_DOWNLOAD ,&stat.speed_download))) + { + zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_SPEED_DOWNLOAD [%s]", + curl_easy_strerror(err)); + err_str = strdup(curl_easy_strerror(err)); + lastfailedstep = httpstep.no; + } + } + + httptest->time+=stat.total_time; + process_step_data(httptest, &httpstep, &stat); + } + DBfree_result(result); + + esc_err_str = DBdyn_escape_string(err_str); + zbx_free(err_str); + + (void)curl_easy_cleanup(easyhandle); + + DBexecute("update httptest set curstep=0,curstate=%d,lastcheck=%d,nextcheck=%d+delay,lastfailedstep=%d," + "time=" ZBX_FS_DBL ",error='%s' where httptestid=" ZBX_FS_UI64, + HTTPTEST_STATE_IDLE, + now, + now, + lastfailedstep, + httptest->time, + esc_err_str, + httptest->httptestid); + + zbx_free(esc_err_str); + + stat.test_total_time = httptest->time; + stat.test_last_step = lastfailedstep; + + process_test_data(httptest, &stat); + + zabbix_log(LOG_LEVEL_DEBUG, "End process_httptest(total time:" ZBX_FS_DBL ")", + httptest->time); + + CHECK_MEMORY("process_httptest", "end"); +} + +/****************************************************************************** + * * + * Function: process_httptests * + * * + * Purpose: process httptests * + * * + * Parameters: now - current timestamp * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: always SUCCEED * + * * + ******************************************************************************/ +void process_httptests(int now) +{ + DB_RESULT result; + DB_ROW row; + + DB_HTTPTEST httptest; + + INIT_CHECK_MEMORY(); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_httptests()"); + + result = DBselect("select httptestid,name,applicationid,nextcheck,status,delay,macros,agent from httptest where status=%d and nextcheck<=%d and " ZBX_SQL_MOD(httptestid,%d) "=%d and " ZBX_COND_NODEID, + HTTPTEST_STATUS_MONITORED, + now, + CONFIG_HTTPPOLLER_FORKS, + httppoller_num-1, + LOCAL_NODE("httptestid")); + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(httptest.httptestid, row[0]); + httptest.name=row[1]; + ZBX_STR2UINT64(httptest.applicationid, row[2]); + httptest.nextcheck=atoi(row[3]); + httptest.status=atoi(row[4]); + httptest.delay=atoi(row[5]); + httptest.macros=row[6]; + httptest.agent=row[7]; + + process_httptest(&httptest); + } + DBfree_result(result); + zabbix_log(LOG_LEVEL_DEBUG, "End process_httptests()"); + + CHECK_MEMORY("process_httptests", "end"); +} + +#endif /* HAVE_LIBCURL */ diff --git a/src/zabbix_proxy/httppoller/httptest.h b/src/zabbix_proxy/httppoller/httptest.h new file mode 100644 index 00000000..fef92849 --- /dev/null +++ b/src/zabbix_proxy/httppoller/httptest.h @@ -0,0 +1,51 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_HTTPTEST_H +#define ZABBIX_HTTPTEST_H + +#define S_ZBX_HTTPPAGE struct s_zbx_httppage_t +S_ZBX_HTTPPAGE +{ + char *data; + int allocated; + int offset; +}; + +#define S_ZBX_HTTPSTAT struct s_zbx_httpstat_t +S_ZBX_HTTPSTAT +{ + long rspcode; + double total_time; + double speed_download; + double test_total_time; + int test_last_step; +}; + +#ifdef HAVE_LIBCURL + void process_httptests(int now); +#else +# define process_httptests(now) +#endif /* HAVE_LIBCURL */ + +extern int httppoller_num; + +extern int CONFIG_HTTPPOLLER_FORKS; + +#endif diff --git a/src/zabbix_proxy/nodewatcher/Makefile.am b/src/zabbix_proxy/nodewatcher/Makefile.am new file mode 100644 index 00000000..5d7387a7 --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxnodewatcher.a + +libzbxnodewatcher_a_SOURCES = \ + nodewatcher.c nodewatcher.h \ + nodesender.c nodesender.h \ + nodecomms.c nodecomms.h \ + history.c history.h diff --git a/src/zabbix_proxy/nodewatcher/history.c b/src/zabbix_proxy/nodewatcher/history.c new file mode 100644 index 00000000..edcdd69c --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/history.c @@ -0,0 +1,347 @@ +/* +** ZABBIX +** Copyright (C) 2000-2006 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "history.h" +#include "nodewatcher.h" +#include "nodecomms.h" + +/****************************************************************************** + * * + * Function: get_history_lastid: * + * * + * Purpose: get last history id from master node * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int get_history_lastid(int master_nodeid, int nodeid, ZBX_TABLE *table, zbx_uint64_t *lastid) +{ + zbx_sock_t sock; + char data[MAX_STRING_LEN], *answer; + int res = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In get_history_lastid()"); + + if (SUCCEED == connect_to_node(master_nodeid, &sock)) { + zbx_snprintf(data, sizeof(data), "ZBX_GET_HISTORY_LAST_ID%c%d%c%d\n%s%c%s", + ZBX_DM_DELIMITER, CONFIG_NODEID, + ZBX_DM_DELIMITER, nodeid, + table->table, ZBX_DM_DELIMITER, table->recid); + + if (FAIL == send_data_to_node(master_nodeid, &sock, data)) + goto disconnect; + + if (FAIL == recv_data_from_node(master_nodeid, &sock, &answer)) + goto disconnect; + + if (0 == strncmp(answer, "FAIL", 4)) { + zabbix_log( LOG_LEVEL_ERR, "NODE %d: get_history_lastid() FAIL from node %d for node %d", + CONFIG_NODEID, + master_nodeid, + nodeid); + goto disconnect; + } + + ZBX_STR2UINT64(*lastid, answer); + res = SUCCEED; +disconnect: + disconnect_node(&sock); + } + return res; +} + +/****************************************************************************** + * * + * Function: get_trends_lastid: * + * * + * Purpose: get last history lastid and lastclock from master node * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int get_trends_lastid(int master_nodeid, int nodeid, ZBX_TABLE *table, zbx_uint64_t *lastid, int *lastclock) +{ + zbx_sock_t sock; + char data[MAX_STRING_LEN], *answer, *ptr; + int res = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In get_trends_lastclock()"); + + if (SUCCEED == connect_to_node(master_nodeid, &sock)) { + zbx_snprintf(data, sizeof(data), "ZBX_GET_TRENDS_LAST_ID%c%d%c%d\n%s", + ZBX_DM_DELIMITER, CONFIG_NODEID, + ZBX_DM_DELIMITER, nodeid, + table->table); + + if (FAIL == send_data_to_node(master_nodeid, &sock, data)) + goto disconnect; + + if (FAIL == recv_data_from_node(master_nodeid, &sock, &answer)) + goto disconnect; + + if (0 == strncmp(answer, "FAIL", 4)) { + zabbix_log( LOG_LEVEL_ERR, "NODE %d: get_trends_lastid() FAIL from node %d for node %d", + CONFIG_NODEID, + master_nodeid, + nodeid); + goto disconnect; + } + + if (NULL != (ptr = strchr(answer, ZBX_DM_DELIMITER))) { + *ptr++ = '\0'; + + ZBX_STR2UINT64(*lastid, answer); + *lastclock = atoi(ptr); + + res = SUCCEED; + } +disconnect: + disconnect_node(&sock); + } + return res; +} + +/****************************************************************************** + * * + * Function : process_hstory_table_data: * + * * + * Purpose: process new history data * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void process_history_table_data(ZBX_TABLE *table, int master_nodeid, int nodeid) +{ + DB_RESULT result; + DB_ROW row; + char *data = NULL, *tmp = NULL; + int data_allocated = 1024*1024, tmp_allocated = 4096, tmp_offset, data_offset, f, fld, len; + int data_found = 0; + zbx_uint64_t lastid; + int lastclock = 0, clock; + + zabbix_log( LOG_LEVEL_DEBUG, "In process_history_table_data()"); + + DBbegin(); + + if ((table->flags & ZBX_HISTORY) && FAIL == get_history_lastid(master_nodeid, nodeid, table, &lastid)) + return; + if ((table->flags & ZBX_HISTORY_TRENDS) && FAIL == get_trends_lastid(master_nodeid, nodeid, table, &lastid, &lastclock)) + return; + + data = zbx_malloc(data, data_allocated); + tmp = zbx_malloc(tmp, tmp_allocated); + + data_offset = 0; + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "History%c%d%c%d%c%s", + ZBX_DM_DELIMITER, CONFIG_NODEID, + ZBX_DM_DELIMITER, nodeid, + ZBX_DM_DELIMITER, table->table); + + /* Do not send history for current node if CONFIG_NODE_NOHISTORY is set */ +/* if ((CONFIG_NODE_NOHISTORY != 0) && (CONFIG_NODEID == nodeid)) + goto exit;*/ + + tmp_offset = 0; + if (table->flags & ZBX_HISTORY_SYNC) { + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "select %s,", + table->recid); + } else { /* ZBX_HISTORY, ZBX_HISTORY_TRENDS */ + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16, "select "); + } + + for (f = 0; table->fields[f].name != 0; f++) { + if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) + continue; + + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s,", + table->fields[f].name); + } + tmp_offset--; + + if (table->flags & ZBX_HISTORY_SYNC) { + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where nodeid=%d order by %s", + table->table, + nodeid, + table->recid); + } else if (table->flags & ZBX_HISTORY_TRENDS) { + clock = time(NULL) - 600; /* -10min */ + clock -= clock % 3600; + + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where" + " (itemid>"ZBX_FS_UI64" or (itemid="ZBX_FS_UI64" and clock>%d)) and clock<%d" + " and"ZBX_COND_NODEID"order by itemid,clock", + table->table, + lastid, lastid, lastclock, clock, + ZBX_NODE("itemid", nodeid)); + } else { /* ZBX_HISTORY */ + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where %s>"ZBX_FS_UI64 + " and"ZBX_COND_NODEID"order by %2$s", + table->table, + table->recid, + lastid, + ZBX_NODE(table->recid, nodeid)); + } + + result = DBselectN(tmp, 10000); + while (NULL != (row = DBfetch(result))) { + if (table->flags & ZBX_HISTORY_SYNC) { + ZBX_STR2UINT64(lastid, row[0]); + fld = 1; + } else + fld = 0; + + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n"); + + for (f = 0; table->fields[f].name != 0; f++) { + if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) + continue; + + if (table->fields[f].type == ZBX_TYPE_INT || + table->fields[f].type == ZBX_TYPE_UINT || + table->fields[f].type == ZBX_TYPE_ID || + table->fields[f].type == ZBX_TYPE_FLOAT) + { + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c", + row[fld], ZBX_DM_DELIMITER); + } else { /* ZBX_TYPE_CHAR ZBX_TYPE_BLOB ZBX_TYPE_TEXT */ + len = (int)strlen(row[fld]); + len = zbx_binary2hex((u_char *)row[fld], len, &tmp, &tmp_allocated); + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, len + 8, "%s%c", + tmp, ZBX_DM_DELIMITER); + } + fld++; + } + data_offset--; + data_found = 1; + } + DBfree_result(result); + + data[data_offset] = '\0'; + + if (1 == data_found && SUCCEED == send_to_node(table->table, master_nodeid, nodeid, data)) { + if (table->flags & ZBX_HISTORY_SYNC) { + DBexecute("delete from %s where nodeid=%d and %s<="ZBX_FS_UI64, + table->table, + nodeid, + table->recid, + lastid); + } + } + + DBcommit(); + + zbx_free(tmp); + zbx_free(data); +} + +/****************************************************************************** + * * + * Function: process_history_tables * + * * + * Purpose: process new history data from tables with ZBX_HISTORY* flags * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static void process_history_tables(int master_nodeid, int nodeid) +{ + int t; + int start = time(NULL); + + zabbix_log(LOG_LEVEL_DEBUG, "In process_history_tables()"); + + for (t = 0; tables[t].table != 0; t++) { + if (tables[t].flags & (ZBX_HISTORY | ZBX_HISTORY_SYNC | ZBX_HISTORY_TRENDS)) + process_history_table_data(&tables[t], master_nodeid, nodeid); + } + + zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Spent %d seconds for node %d in process_history_tables", + CONFIG_NODEID, + time(NULL) - start, + nodeid); +} +/****************************************************************************** + * * + * Function: main_historysender * + * * + * Purpose: periodically sends historical data to master node * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void main_historysender() +{ + DB_RESULT result; + DB_ROW row; + int master_nodeid, nodeid; + + zabbix_log(LOG_LEVEL_DEBUG, "In main_historysender()"); + + master_nodeid = CONFIG_MASTER_NODEID; + if (0 == master_nodeid) + return; + + result = DBselect("select nodeid from nodes"); + while ((row = DBfetch(result))) { + nodeid = atoi(row[0]); + if (SUCCEED == is_master_node(CONFIG_NODEID, nodeid)) + continue; + + process_history_tables(master_nodeid, nodeid); + } + DBfree_result(result); +} diff --git a/src/zabbix_proxy/nodewatcher/history.h b/src/zabbix_proxy/nodewatcher/history.h new file mode 100644 index 00000000..cf064cc3 --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/history.h @@ -0,0 +1,25 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_NODEWATCHER_HISTORY_H +#define ZABBIX_NODEWATCHER_HISTORY_H + +void main_historysender(); + +#endif diff --git a/src/zabbix_proxy/nodewatcher/nodecomms.c b/src/zabbix_proxy/nodewatcher/nodecomms.c new file mode 100644 index 00000000..7f87befc --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodecomms.c @@ -0,0 +1,153 @@ +/* +** ZABBIX +** Copyright (C) 2000-2006 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "comms.h" +#include "nodecomms.h" + +int connect_to_node(int nodeid, zbx_sock_t *sock) +{ + DB_RESULT result; + DB_ROW row; + unsigned short port; + int res = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In connect_to_node(nodeid:%d)", nodeid); + + result = DBselect("select ip,port from nodes where nodeid=%d", + nodeid); + + if (NULL != (row = DBfetch(result))) { + port = (unsigned short)atoi(row[1]); + + if (SUCCEED == zbx_tcp_connect(sock, row[0], port, 0)) + res = SUCCEED; + else + zabbix_log(LOG_LEVEL_ERR, "NODE %d: Unable to connect to Node [%d] error: %s", + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + } else + zabbix_log(LOG_LEVEL_ERR, "NODE %d: Node [%d] is unknown", + CONFIG_NODEID, + nodeid); + DBfree_result(result); + + return res; +} + +int send_data_to_node(int nodeid, zbx_sock_t *sock, const char *data) +{ + int res; + + if (FAIL == (res = zbx_tcp_send_ext(sock, data, ZBX_TCP_NEW_PROTOCOL))) { + zabbix_log(LOG_LEVEL_ERR, "NODE %d: Error while sending data to Node [%d] error: %s", + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + } else + zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Sending [%s] to Node [%d]", + CONFIG_NODEID, + data, + nodeid); + + return res; +} + +int recv_data_from_node(int nodeid, zbx_sock_t *sock, char **data) +{ + int res; + + if (FAIL == (res = zbx_tcp_recv_ext(sock, data, 0))) { + zabbix_log(LOG_LEVEL_ERR, "NODE %d: Error while receiving answer from Node [%d] error: %s", + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + } else + zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Receiving [%s] from Node [%d]", + CONFIG_NODEID, + *data, + nodeid); + + return res; +} + +void disconnect_node(zbx_sock_t *sock) +{ + zbx_tcp_close(sock); +} + +/****************************************************************************** + * * + * Function: send_to_node * + * * + * Purpose: send configuration changes to required node * + * * + * Parameters: * + * * + * Return value: SUCCESS - processed succesfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int send_to_node(const char *name, int dest_nodeid, int nodeid, char *data) +{ + int ret = FAIL; + zbx_sock_t sock; + char *answer; + + zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Sending %s of node %d to node %d datalen %zd", + CONFIG_NODEID, + name, + nodeid, + dest_nodeid, + strlen(data)); + + if (FAIL == connect_to_node(dest_nodeid, &sock)) + return FAIL; + + if (FAIL == send_data_to_node(dest_nodeid, &sock, data)) + goto disconnect; + + if (FAIL == recv_data_from_node(dest_nodeid, &sock, &answer)) + goto disconnect; + + if (0 == strcmp(answer, "OK")) + { + zabbix_log( LOG_LEVEL_DEBUG, "OK"); + ret = SUCCEED; + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "NOT OK"); + } +disconnect: + disconnect_node(&sock); + + return ret; +} diff --git a/src/zabbix_proxy/nodewatcher/nodecomms.h b/src/zabbix_proxy/nodewatcher/nodecomms.h new file mode 100644 index 00000000..88303cf1 --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodecomms.h @@ -0,0 +1,32 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_NODECOMMS_H +#define ZABBIX_NODECOMMS_H + +#include "comms.h" + +int connect_to_node(int nodeid, zbx_sock_t *sock); +int send_data_to_node(int nodeid, zbx_sock_t *sock, const char *data); +int recv_data_from_node(int nodeid, zbx_sock_t *sock, char **data); +void disconnect_node(zbx_sock_t *sock); + +int send_to_node(const char *name, int dest_nodeid, int nodeid, char *data); + +#endif diff --git a/src/zabbix_proxy/nodewatcher/nodesender.c b/src/zabbix_proxy/nodewatcher/nodesender.c new file mode 100644 index 00000000..0e49e60b --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodesender.c @@ -0,0 +1,673 @@ +/* +** ZABBIX +** Copyright (C) 2000-2006 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "nodesender.h" +#include "nodewatcher.h" +#include "nodecomms.h" +#include "../trapper/nodesync.h" + + +/****************************************************************************** + * * + * Function: calculate_checksums * + * * + * Purpose: calculate check sums of configuration data * + * * + * Parameters: * + * * + * Return value: SUCCESS - calculated succesfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t id) +{ + char *sql = NULL; + int sql_allocated = 16*1024, sql_offset = 0; + int t, f, res = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In calculate_checksums"); + + sql = zbx_malloc(sql, sql_allocated); + + for (t = 0; tables[t].table != 0; t++) { + /* Do not sync some of tables */ + if ((tables[t].flags & ZBX_SYNC) == 0) + continue; + + if (NULL != tablename && 0 != strcmp(tablename, tables[t].table)) + continue; + +#ifdef HAVE_MYSQL + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512, + "%s select %d,'%s',%s,%d,concat_ws(',',", + sql_offset > 0 ? "union all" : "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)", + nodeid, + tables[t].table, + tables[t].recid, + NODE_CKSUM_TYPE_NEW); +#else + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512, + "%s select %d,'%s',%s,%d,", + sql_offset > 0 ? "union all" : "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)", + nodeid, + tables[t].table, + tables[t].recid, + NODE_CKSUM_TYPE_NEW); +#endif + + for (f = 0; tables[t].fields[f].name != 0; f ++) { + if ((tables[t].fields[f].flags & ZBX_SYNC) == 0) + continue; + + if (tables[t].fields[f].flags & ZBX_NOTNULL) { + switch ( tables[t].fields[f].type ) { + case ZBX_TYPE_ID : + case ZBX_TYPE_INT : + case ZBX_TYPE_UINT : + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, + "%s", + tables[t].fields[f].name); + break; + default : + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, + "md5(%s)", + tables[t].fields[f].name); + break; + } + } else { + switch ( tables[t].fields[f].type ) { + case ZBX_TYPE_ID : + case ZBX_TYPE_INT : + case ZBX_TYPE_UINT : + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, + "case when %s is null then 'NULL' else %1$s end", + tables[t].fields[f].name); + break; + default : + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, + "case when %s is null then 'NULL' else md5(%1$s) end", + tables[t].fields[f].name); + break; + } + } +#ifdef HAVE_MYSQL + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16, + "," + ); +#else + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16, + "||','||" + ); +#endif + } + + /* remove last delimiter */ + if (f > 0) { +#ifdef HAVE_MYSQL + sql_offset --; + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16, ")"); +#else + sql_offset -= 7; +#endif + } + + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512, + " from %s where"ZBX_COND_NODEID, + tables[t].table, + ZBX_NODE(tables[t].recid,nodeid)); + + if (0 != id) { + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, + "and %s="ZBX_FS_UI64, + tables[t].recid, + id); + } + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "\n"); + } + if (SUCCEED == res && DBexecute("delete from node_cksum where nodeid=%d and cksumtype=%d", + nodeid, + NODE_CKSUM_TYPE_NEW) < ZBX_DB_OK) + res = FAIL; + if (SUCCEED == res && DBexecute("%s", sql) < ZBX_DB_OK) + res = FAIL; + + return res; +} + +/****************************************************************************** + * * + * Function: send_config_data * + * * + * Purpose: send configuration changes to required node * + * * + * Parameters: * + * * + * Return value: SUCCESS - processed succesfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +char *get_config_data(int nodeid, int dest_nodetype) +{ + DB_RESULT result; + DB_RESULT result2; + DB_ROW row; + DB_ROW row2; + + char *data = NULL, *hex = NULL, *sql = NULL, c, sync[129], *s, *r[2], *d[2]; + int data_offset=0, sql_offset = 0; + int data_allocated=1024, hex_allocated=1024, sql_allocated=8*1024; + int t, f, j, rowlen; + + zabbix_log( LOG_LEVEL_DEBUG, "In get_config_data(node:%d,dest_nodetype:%s)", + nodeid, + dest_nodetype == ZBX_NODE_MASTER ? "MASTER" : "SLAVE"); + + data = zbx_malloc(data, data_allocated); + hex = zbx_malloc(hex, hex_allocated); + sql = zbx_malloc(sql, sql_allocated); + c = '1'; + + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "Data%c%d%c%d\n", + ZBX_DM_DELIMITER, + CONFIG_NODEID, + ZBX_DM_DELIMITER, + nodeid); + + /* Find updated records */ + result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync " + "from node_cksum curr, node_cksum prev " + "where curr.nodeid=%1$d and prev.nodeid=%1$d and " + "curr.tablename=prev.tablename and curr.recordid=prev.recordid and " + "curr.cksumtype=%3$d and prev.cksumtype=%2$d " + /*" and curr.tablename='hosts' "*/ + "union all " + /* Find new records */ + "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,curr.sync " + "from node_cksum curr left join node_cksum prev " + "on prev.nodeid=%1$d and prev.tablename=curr.tablename and " + "prev.recordid=curr.recordid and prev.cksumtype=%2$d " + "where curr.nodeid=%1$d and curr.cksumtype=%3$d and prev.tablename is null " + /*" and curr.tablename='hosts' "*/ + "union all " + /* Find deleted records */ + "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync " + "from node_cksum prev left join node_cksum curr " + "on prev.nodeid=curr.nodeid and curr.nodeid=%1$d and curr.tablename=prev.tablename and " + "curr.recordid=prev.recordid and curr.cksumtype=%3$d " + "where prev.nodeid=%1$d and prev.cksumtype=%2$d and curr.tablename is null" + /*" and prev.tablename='hosts' "*/, + nodeid, + NODE_CKSUM_TYPE_OLD, /* prev */ + NODE_CKSUM_TYPE_NEW); /* curr */ + + while (NULL != (row = DBfetch(result))) { + for (t = 0; tables[t].table != 0 && strcmp(tables[t].table, row[0]) != 0; t++) + ; + + /* Found table */ + if (tables[t].table == 0) { + zabbix_log( LOG_LEVEL_WARNING, "Cannot find table [%s]", + row[0]); + continue; + } + + if (DBis_null(row[4]) == FAIL) + strcpy(sync, row[4]); + else + memset(sync, ' ', sizeof(sync)); + s = sync; + + /* Special (simpler) processing for operation DELETE */ + if (DBis_null(row[2]) == FAIL && DBis_null(row[3]) == SUCCEED && + ((dest_nodetype == ZBX_NODE_SLAVE && *s != c) || + (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c))) { + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c%s%c%d\n", + row[0], + ZBX_DM_DELIMITER, + row[1], + ZBX_DM_DELIMITER, + NODE_CONFIGLOG_OP_DELETE); + continue; + } + + r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; + r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3]; + f = 0; + sql_offset = 0; + + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "select "); + do { + while ((tables[t].fields[f].flags & ZBX_SYNC) == 0) + f++; + + d[0] = NULL; + d[1] = NULL; + if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) + *d[0] = '\0'; + if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) + *d[1] = '\0'; + + if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c) || + (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c) || strcmp(r[0], r[1]) != 0) { + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "%s,length(%1$s),", + tables[t].fields[f].name); + } + s += 2; + f++; + + if (d[0] != NULL) { + *d[0] = ','; + r[0] = d[0] + 1; + } else + r[0] = NULL; + if (d[1] != NULL) { + *d[1] = ','; + r[1] = d[1] + 1; + } else + r[1] = NULL; + } while (d[0] != NULL || d[1] != NULL); + + if (sql[sql_offset-1] != ',') + continue; + + sql_offset--; + zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, " from %s where %s=%s", + row[0], + tables[t].recid, + row[1]); + + result2 = DBselect("%s", sql); + if (NULL == (row2=DBfetch(result2))) + goto out; + + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c%s%c%d", + row[0], + ZBX_DM_DELIMITER, + row[1], + ZBX_DM_DELIMITER, + NODE_CONFIGLOG_OP_UPDATE); + + r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; + r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3]; + s = sync; + f = 0; + j = 0; + + do { + while ((tables[t].fields[f].flags & ZBX_SYNC) == 0) + f++; + + d[0] = NULL; + d[1] = NULL; + if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) + *d[0] = '\0'; + if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) + *d[1] = '\0'; + + if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c) || + (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c) || strcmp(r[0], r[1]) != 0) { + + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%c%s%c%d%c", + ZBX_DM_DELIMITER, + tables[t].fields[f].name, + ZBX_DM_DELIMITER, + tables[t].fields[f].type, + ZBX_DM_DELIMITER); + + /* Fieldname, type, value */ + if (DBis_null(row2[j*2]) == SUCCEED) { + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "NULL"); + } else if(tables[t].fields[f].type == ZBX_TYPE_INT || + tables[t].fields[f].type == ZBX_TYPE_UINT || + tables[t].fields[f].type == ZBX_TYPE_ID || + tables[t].fields[f].type == ZBX_TYPE_FLOAT) { + + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s", row2[j*2]); + } else { + rowlen = atoi(row2[j*2+1]); + zbx_binary2hex((u_char *)row2[j*2], rowlen, &hex, &hex_allocated); + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, strlen(hex)+128, "%s", hex); +/*zabbix_log(LOG_LEVEL_CRIT, "----- [field:%s][type:%d][row:%s][hex:%s]",tables[t].fields[f].name,tables[t].fields[f].type,row2[j*2],hex);*/ + } + j++; + } + s += 2; + f++; + + if (d[0] != NULL) { + *d[0] = ','; + r[0] = d[0] + 1; + } else + r[0] = NULL; + if (d[1] != NULL) { + *d[1] = ','; + r[1] = d[1] + 1; + } else + r[1] = NULL; + } while (d[0] != NULL || d[1] != NULL); + zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n"); +out: + DBfree_result(result2); + } + DBfree_result(result); + + zbx_free(hex); + zbx_free(sql); + + return data; +} + +/****************************************************************************** + * * + * Function: update_checksums * + * * + * Purpose: overwrite old checksums with new ones * + * * + * Parameters: * + * * + * Return value: SUCCESS - calculated succesfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, char *fields) +{ + char *r[2], *d[2], sync[129], *s; + char c, sql[2][256]; + char cksum[32*64+32], *ck; + DB_RESULT result; + DB_ROW row; + int t, f; + + zabbix_log(LOG_LEVEL_DEBUG, "In update_checksums"); + + c = synked == SUCCEED ? '1' : ' '; + + if (NULL != tablename) { + zbx_snprintf(sql[0], sizeof(sql[0]), " and curr.tablename='%s' and curr.recordid="ZBX_FS_UI64, + tablename, id); + zbx_snprintf(sql[1], sizeof(sql[1]), " and prev.tablename='%s' and prev.recordid="ZBX_FS_UI64, + tablename, id); + } else { + *sql[0] = '\0'; + *sql[1] = '\0'; + } + + /* Find updated records */ + result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync " + "from node_cksum curr, node_cksum prev " + "where curr.nodeid=%1$d and prev.nodeid=%1$d and " + "curr.tablename=prev.tablename and curr.recordid=prev.recordid and " + "curr.cksumtype=%3$d and prev.cksumtype=%2$d%4$s " + "union all " + /* Find new records */ + "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,NULL " + "from node_cksum curr left join node_cksum prev " + "on prev.nodeid=%1$d and prev.tablename=curr.tablename and " + "prev.recordid=curr.recordid and prev.cksumtype=%2$d " + "where curr.nodeid=%1$d and curr.cksumtype=%3$d and prev.tablename is null%4$s " + "union all " + /* Find deleted records */ + "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync " + "from node_cksum prev left join node_cksum curr " + "on prev.nodeid=curr.nodeid and curr.nodeid=%1$d and curr.tablename=prev.tablename and " + "curr.recordid=prev.recordid and curr.cksumtype=%3$d " + "where prev.nodeid=%1$d and prev.cksumtype=%2$d and curr.tablename is null%5$s", + nodeid, + NODE_CKSUM_TYPE_OLD, /* prev */ + NODE_CKSUM_TYPE_NEW, /* curr */ + sql[0], + sql[1]); + + while (NULL != (row = DBfetch(result))) { + for (t = 0; tables[t].table != 0 && strcmp(tables[t].table, row[0]) != 0; t++) + ; + + /* Found table */ + if (tables[t].table == 0) { + zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", + row[0]); + continue; + } + + if (DBis_null(row[4]) == FAIL) + strcpy(sync, row[4]); + else + memset(sync, ' ', sizeof(sync)); + s = sync; + ck = cksum; + *ck = '\0'; + + /* Special (simpler) processing for operation DELETE */ + if (DBis_null(row[3]) == SUCCEED) { + if (*(s+2) != '\0') { + *s = ' '; + *(s+1) = ' '; + } + if (synked == SUCCEED) { + if (synked_nodetype == ZBX_NODE_SLAVE) + *s = c; + else if (synked_nodetype == ZBX_NODE_MASTER) + *(s+1) = c; + } + s += 2; + } else { + r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; + r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3]; + f = 0; + + do { + while ((tables[t].fields[f].flags & ZBX_SYNC) == 0) + f++; + + d[0] = NULL; + d[1] = NULL; + if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) + *d[0] = '\0'; + if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) + *d[1] = '\0'; + + if (NULL == tablename || SUCCEED == str_in_list(fields, tables[t].fields[f].name, ',')) { + ck += zbx_snprintf(ck, 64, "%s,", NULL != r[1] ? r[1] : r[0]); + + if (r[0] == NULL || r[1] == NULL || strcmp(r[0], r[1]) != 0) { + if (synked_nodetype == ZBX_NODE_SLAVE) { + *s = c; + *(s+1) = ' '; + } else if (synked_nodetype == ZBX_NODE_MASTER) { + *s = ' '; + *(s+1) = c; + } + } else { + if (synked == SUCCEED) { + if (synked_nodetype == ZBX_NODE_SLAVE) + *s = c; + else if (synked_nodetype == ZBX_NODE_MASTER) + *(s+1) = c; + } + } + } else + ck += zbx_snprintf(ck, 64, "%s,", NULL != r[0] ? r[0] : ""); + s += 2; + f++; + + if (d[0] != NULL) { + *d[0] = ','; + r[0] = d[0] + 1; + } else + r[0] = NULL; + if (d[1] != NULL) { + *d[1] = ','; + r[1] = d[1] + 1; + } else + r[1] = NULL; + } while (d[0] != NULL || d[1] != NULL); + } + *s = '\0'; + *--ck = '\0'; + + if (DBis_null(row[2]) == SUCCEED || DBis_null(row[3]) == SUCCEED || + strcmp(row[4], sync) != 0 || strcmp(row[2], row[3]) != 0) + { + DBexecute("update node_cksum set cksumtype=%d,cksum=\'%s\',sync=\'%s\' " + "where nodeid=%d and tablename=\'%s\' and recordid=%s and cksumtype=%d", + NODE_CKSUM_TYPE_OLD, + cksum, + sync, + nodeid, + row[0], + row[1], + DBis_null(row[2]) == SUCCEED ? NODE_CKSUM_TYPE_NEW : NODE_CKSUM_TYPE_OLD); + } + } + DBfree_result(result); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: node_sync_lock * + * * + * Purpose: * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void node_sync_lock(int nodeid) +{ + zbx_mutex_lock(&node_sync_access); +} + +/****************************************************************************** + * * + * Function: node_sync_unlock * + * * + * Purpose: * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void node_sync_unlock(int nodeid) +{ + zbx_mutex_unlock(&node_sync_access); +} + +/****************************************************************************** + * * + * Function: process_nodes * + * * + * Purpose: calculates checks sum of config data * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Aleksander Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +void process_nodes() +{ + DB_RESULT result; + DB_ROW row; + int nodeid; + int master_nodeid; + char *data, *answer; + zbx_sock_t sock; + int res; +/* int now = time(NULL);*/ + int sender_nodeid; + + master_nodeid = CONFIG_MASTER_NODEID; + if (0 == master_nodeid) + return; + + result = DBselect("select nodeid from nodes"); + while (NULL != (row=DBfetch(result))) { + nodeid = atoi(row[0]); + if (SUCCEED == is_master_node(CONFIG_NODEID, nodeid)) + continue; + + node_sync_lock(nodeid); + +/* DBbegin();*/ + + res = calculate_checksums(nodeid, NULL, 0); + if (SUCCEED == res && NULL != (data = get_config_data(nodeid, ZBX_NODE_MASTER))) { + zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Sending configuration changes to master node %d for node %d datalen %d", + CONFIG_NODEID, + master_nodeid, + nodeid, + strlen(data)); + if (SUCCEED == (res = connect_to_node(master_nodeid, &sock))) { + if (SUCCEED == res) + res = send_data_to_node(master_nodeid, &sock, data); + if (SUCCEED == res) + res = recv_data_from_node(master_nodeid, &sock, &answer); + if (SUCCEED == res && 0 == strncmp(answer, "Data", 4)) { + res = update_checksums(nodeid, ZBX_NODE_MASTER, SUCCEED, NULL, 0, NULL); + if (SUCCEED == res) + res = node_sync(answer, &sender_nodeid, &nodeid); + send_data_to_node(master_nodeid, &sock, SUCCEED == res ? "OK" : "FAIL"); + } + disconnect_node(&sock); + } + zbx_free(data); + } + +/* DBcommit();*/ + + node_sync_unlock(nodeid); + } + DBfree_result(result); + +/* zabbix_log(LOG_LEVEL_CRIT, "<-----> process_nodes [Selected records in %d seconds]", time(NULL)-now);*/ +} diff --git a/src/zabbix_proxy/nodewatcher/nodesender.h b/src/zabbix_proxy/nodewatcher/nodesender.h new file mode 100644 index 00000000..7f64e5da --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodesender.h @@ -0,0 +1,37 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_NODESENDER_H +#define ZABBIX_NODESENDER_H + +#include "mutexs.h" + +#define ZBX_NODE_MASTER 0 +#define ZBX_NODE_SLAVE 1 + +extern ZBX_MUTEX node_sync_access; + +int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t id); +char *get_config_data(int nodeid, int dest_nodetype); +int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, char *fields); +void node_sync_lock(int nodeid); +void node_sync_unlock(int nodeid); +void process_nodes(); + +#endif diff --git a/src/zabbix_proxy/nodewatcher/nodewatcher.c b/src/zabbix_proxy/nodewatcher/nodewatcher.c new file mode 100644 index 00000000..951bc871 --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodewatcher.c @@ -0,0 +1,120 @@ +/* +** ZABBIX +** Copyright (C) 2000-2006 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "cfg.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "nodewatcher.h" +#include "nodesender.h" +#include "history.h" + +/****************************************************************************** + * * + * Function: is_master_node * + * * + * Purpose: * + * * + * Parameters: * + * * + * Return value: SUCCEED - nodeid is master node * + * FAIL - nodeid is slave node * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int is_master_node(int current_nodeid, int nodeid) +{ + DB_RESULT dbresult; + DB_ROW dbrow; + int res = FAIL; + + dbresult = DBselect("select masterid from nodes where nodeid=%d", + current_nodeid); + + if (NULL != (dbrow = DBfetch(dbresult))) { + current_nodeid = atoi(dbrow[0]); + if (current_nodeid == nodeid) + res = SUCCEED; + else if (0 != current_nodeid) + res = is_master_node(current_nodeid, nodeid); + } + DBfree_result(dbresult); + + return res; +} + +/****************************************************************************** + * * + * Function: main_nodewatcher_loop * + * * + * Purpose: periodically calculates checks sum of config data * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +int main_nodewatcher_loop() +{ + int start, end; + int lastrun = 0; + + zabbix_log( LOG_LEVEL_DEBUG, "In main_nodeupdater_loop()"); + for(;;) + { + start = time(NULL); + + zbx_setproctitle("connecting to the database"); + zabbix_log( LOG_LEVEL_DEBUG, "Starting sync with nodes"); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + if(lastrun + 120 < start) + { + process_nodes(); + + lastrun = start; + } + + /* Send new history data to master node */ + main_historysender(); + + DBclose(); + + end = time(NULL); + + if(end-start<10) + { + zbx_setproctitle("sender [sleeping for %d seconds]", + 10-(end-start)); + zabbix_log( LOG_LEVEL_DEBUG, "Sleeping %d seconds", + 10-(end-start)); + sleep(10-(end-start)); + } + } +} diff --git a/src/zabbix_proxy/nodewatcher/nodewatcher.h b/src/zabbix_proxy/nodewatcher/nodewatcher.h new file mode 100644 index 00000000..60285d0f --- /dev/null +++ b/src/zabbix_proxy/nodewatcher/nodewatcher.h @@ -0,0 +1,26 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_NODEWATCHER_H +#define ZABBIX_NODEWATCHER_H + +int main_nodewatcher_loop(); +int is_master_node(int current_nodeid, int nodeid); + +#endif diff --git a/src/zabbix_proxy/operations.c b/src/zabbix_proxy/operations.c new file mode 100644 index 00000000..e2f11a78 --- /dev/null +++ b/src/zabbix_proxy/operations.c @@ -0,0 +1,833 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <signal.h> + +#include <string.h> + +#include <time.h> + +#include "common.h" +#include "comms.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "poller/poller.h" +#include "poller/checks_agent.h" + +/****************************************************************************** + * * + * Function: send_to_user_medias * + * * + * Purpose: send notifications to user's medias (email, sms, whatever) * + * * + * Parameters: trigger - trigger data * + * action - action data * + * userid - user id * + * * + * Return value: nothing * + * * + * Author: Alexei Vladishev * + * * + * Comments: Cannot use action->userid as it may also be groupid * + * * + ******************************************************************************/ +static void send_to_user_medias(DB_EVENT *event,DB_OPERATION *operation, zbx_uint64_t userid) +{ + DB_MEDIA media; + DB_RESULT result; + DB_ROW row; + + zabbix_log( LOG_LEVEL_DEBUG, "In send_to_user_medias(objectid:" ZBX_FS_UI64 ")", + event->objectid); + + result = DBselect("select mediatypeid,sendto,active,severity,period from media where active=%d and userid=" ZBX_FS_UI64, + MEDIA_STATUS_ACTIVE, + userid); + + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(media.mediatypeid, row[0]); + + media.sendto = row[1]; + media.active = atoi(row[2]); + media.severity = atoi(row[3]); + media.period = row[4]; + + zabbix_log( LOG_LEVEL_DEBUG, "Trigger severity [%d] Media severity [%d] Period [%s]", + event->trigger_priority, + media.severity, + media.period); + if(((1<<event->trigger_priority)&media.severity)==0) + { + zabbix_log( LOG_LEVEL_DEBUG, "Won't send message (severity)"); + continue; + } + if(check_time_period(media.period, (time_t)NULL) == 0) + { + zabbix_log( LOG_LEVEL_DEBUG, "Won't send message (period)"); + continue; + } + + DBadd_alert(operation->actionid, userid, event->objectid, media.mediatypeid,media.sendto,operation->shortdata,operation->longdata); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End send_to_user_medias()"); +} + +/****************************************************************************** + * * + * Function: op_notify_user * + * * + * Purpose: send notifications to user or user groupd * + * * + * Parameters: trigger - trigger data * + * action - action data * + * * + * Return value: nothing * + * * + * Author: Alexei Vladishev * + * * + * Comments: action->recipient specifies user or group * + * * + ******************************************************************************/ +void op_notify_user(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t userid; + + zabbix_log(LOG_LEVEL_DEBUG, "In send_to_user()"); + + if(operation->object == OPERATION_OBJECT_USER) + { + result = DBselect("SELECT count(u.userid) as user_cnt FROM users u WHERE u.userid= " ZBX_FS_UI64 " and u.status=%d", + operation->objectid, USER_STATUS_ACTIVE); + row = DBfetch(result); + if(row && (DBis_null(row[0])!=SUCCEED) && (atoi(row[0])>0)) + { + send_to_user_medias(event, operation, operation->objectid); + } + DBfree_result(result); + } + else if(operation->object == OPERATION_OBJECT_GROUP) + { + result = DBselect("select u.userid from users u, users_groups ug where ug.usrgrpid=" ZBX_FS_UI64 " and ug.userid=u.userid and u.status=%d", + operation->objectid,USER_STATUS_ACTIVE); + while((row=DBfetch(result))) + { + ZBX_STR2UINT64(userid, row[0]); + send_to_user_medias(event, operation, userid); + } + DBfree_result(result); + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "Unknown object type [%d] for operationid [" ZBX_FS_UI64 "]", + operation->object, + operation->operationid); + zabbix_syslog("Unknown object type [%d] for operationid [" ZBX_FS_UI64 "]", + operation->object, + operation->operationid); + } + zabbix_log(LOG_LEVEL_DEBUG, "End send_to_user()"); +} + + +/****************************************************************************** + * * + * Function: run_remote_commands * + * * + * Purpose: run remote command on specific host * + * * + * Parameters: host_name - host name * + * command - remote command * + * * + * Return value: nothing * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ + +static void run_remote_command(char* host_name, char* command) +{ + int ret = 9; + + AGENT_RESULT agent_result; + DB_ITEM item; + DB_RESULT result; + DB_ROW row; + + assert(host_name); + assert(command); + + zabbix_log(LOG_LEVEL_DEBUG, "In run_remote_command(hostname:%s,command:%s)", + host_name, + command); + + result = DBselect("select distinct host,ip,useip,port,dns from hosts where host='%s' and " ZBX_COND_NODEID, + host_name, + LOCAL_NODE("hostid")); + row = DBfetch(result); + if(row) + { + item.host_name = row[0]; + item.host_ip=row[1]; + item.useip=atoi(row[2]); + item.port=atoi(row[3]); + item.host_dns=row[4]; + + zbx_snprintf(item.key,ITEM_KEY_LEN_MAX,"system.run[%s,nowait]",command); + + alarm(CONFIG_TIMEOUT); + + ret = get_value_agent(&item, &agent_result); + + alarm(0); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End run_remote_command(result:%d)", + ret); +} + +/****************************************************************************** + * * + * Function: get_next_command * + * * + * Purpose: parse action script on remote commands * + * * + * Parameters: command_list - command list * + * alias - (output) of host name or group name * + * is_group - (output) 0 if alias is a host name * + * 1 if alias is a group name * + * command - (output) remote command * + * * + * Return value: 0 - correct comand is readed * + * 1 - EOL * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ + +#define CMD_ALIAS 0 +#define CMD_REM_COMMAND 1 + +static int get_next_command(char** command_list, char** alias, int* is_group, char** command) +{ + int state = CMD_ALIAS; + int len = 0; + int i = 0; + + assert(alias); + assert(is_group); + assert(command); + + zabbix_log(LOG_LEVEL_DEBUG, "In get_next_command(command_list:%s)", + *command_list); + + *alias = NULL; + *is_group = 0; + *command = NULL; + + + if((*command_list)[0] == '\0' || (*command_list)==NULL) { + zabbix_log(LOG_LEVEL_DEBUG, "Result get_next_command [EOL]"); + return 1; + } + + *alias = *command_list; + len = strlen(*command_list); + + for(i=0; i < len; i++) + { + if(state == CMD_ALIAS) + { + if((*command_list)[i] == '#'){ + *is_group = 1; + (*command_list)[i] = '\0'; + state = CMD_REM_COMMAND; + *command = &(*command_list)[i+1]; + }else if((*command_list)[i] == ':'){ + *is_group = 0; + (*command_list)[i] = '\0'; + state = CMD_REM_COMMAND; + *command = &(*command_list)[i+1]; + } + } else if(state == CMD_REM_COMMAND) { + if((*command_list)[i] == '\r') + { + (*command_list)[i] = '\0'; + } else if((*command_list)[i] == '\n') + { + (*command_list)[i] = '\0'; + (*command_list) = &(*command_list)[i+1]; + break; + } + } + if((*command_list)[i+1] == '\0') + { + (*command_list) = &(*command_list)[i+1]; + break; + } + } + + zabbix_log(LOG_LEVEL_DEBUG, "End get_next_command(alias:%s,is_group:%i,command:%s)", + *alias, + *is_group, + *command); + + return 0; +} + +/****************************************************************************** + * * + * Function: run_commands * + * * + * Purpose: run remote commandlist for specific action * + * * + * Parameters: trigger - trigger data * + * action - action data * + * * + * Return value: nothing * + * * + * Author: Eugene Grigorjev * + * * + * Comments: commands devided with newline * + * * + ******************************************************************************/ +void op_run_commands(DB_EVENT *event, DB_OPERATION *operation) +{ + DB_RESULT result; + DB_ROW row; + + char *cmd_list = NULL; + char *alias = NULL; + char *command = NULL; + int is_group = 0; + + assert(event); + assert(operation); + + zabbix_log( LOG_LEVEL_DEBUG, "In run_commands(operationid:" ZBX_FS_UI64 ")", + operation->operationid); + + cmd_list = operation->longdata; + while(get_next_command(&cmd_list,&alias,&is_group,&command)!=1) + { + if(!alias || !command) continue; + if(alias == '\0' || command == '\0') continue; + if(is_group) + { + result = DBselect("select distinct h.host from hosts_groups hg,hosts h, groups g where hg.hostid=h.hostid and hg.groupid=g.groupid and g.name='%s' and" ZBX_COND_NODEID, + alias, + LOCAL_NODE("h.hostid")); + while((row=DBfetch(result))) + { + run_remote_command(row[0], command); + } + + DBfree_result(result); + } + else + { + run_remote_command(alias, command); + } +/* DBadd_alert(action->actionid,trigger->triggerid, userid, media.mediatypeid,media.sendto,action->subject,action->scripts); */ /* TODO !!! Add alert for remote commands !!! */ + } + zabbix_log( LOG_LEVEL_DEBUG, "End run_commands()"); +} + +/****************************************************************************** + * * + * Function: select dhostid by dserviceid * + * * + * Purpose: select discovered host id * + * * + * Parameters: dserviceid - servce id * + * * + * Return value: dhostid - existing dhostid, 0 - if not found * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static zbx_uint64_t select_dhostid_by_dserviceid(zbx_uint64_t dserviceid) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t dhostid = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In select_dhostid_by_dserviceid(dserviceid:" ZBX_FS_UI64 ")", + dserviceid); + + result = DBselect("select dhostid from dservices where dserviceid=" ZBX_FS_UI64, + dserviceid); + row = DBfetch(result); + if(row && DBis_null(row[0]) != SUCCEED) + { + ZBX_STR2UINT64(dhostid, row[0]); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End select_dhostid_by_dserviceid()"); + + return dhostid; +} + +/****************************************************************************** + * * + * Function: select hostid of discovered host * + * * + * Purpose: select discovered host * + * * + * Parameters: dhostid - discovered host id * + * * + * Return value: hostid - existing hostid, o - if not found * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static zbx_uint64_t select_discovered_host(zbx_uint64_t dhostid) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t hostid = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In select_discovered_host(dhostid:" ZBX_FS_UI64 ")", + dhostid); + + result = DBselect("select h.hostid from dhosts d,hosts h where h.ip=d.ip and d.dhostid=" ZBX_FS_UI64, + dhostid); + row = DBfetch(result); + if(row && DBis_null(row[0]) != SUCCEED) + { + ZBX_STR2UINT64(hostid, row[0]); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End select_discovered_host()"); + + return hostid; +} + +/****************************************************************************** + * * + * Function: add host if not added already * + * * + * Purpose: add discovered host * + * * + * Parameters: dhostid - discovered host id * + * * + * Return value: hostid - new/existing hostid * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static zbx_uint64_t add_discovered_host(zbx_uint64_t dhostid) +{ + DB_RESULT result; + DB_RESULT result2; + DB_ROW row; + DB_ROW row2; + zbx_uint64_t hostid = 0; + char *ip; + char host[MAX_STRING_LEN], host_esc[MAX_STRING_LEN]; + + zabbix_log(LOG_LEVEL_DEBUG, "In add_discovered_host(dhostid:" ZBX_FS_UI64 ")", + dhostid); + + result = DBselect("select ip from dhosts where dhostid=" ZBX_FS_UI64, + dhostid); + row = DBfetch(result); + if(row && DBis_null(row[0]) != SUCCEED) + { + ip=row[0]; + + alarm(CONFIG_TIMEOUT); + zbx_gethost_by_ip(ip, host, sizeof(host)); + alarm(0); + + DBescape_string(host, host_esc, sizeof(host_esc)); + + result2 = DBselect("select hostid from hosts where ip='%s' and " ZBX_COND_NODEID, + ip, + LOCAL_NODE("hostid")); + row2 = DBfetch(result2); + if(!row2 || DBis_null(row2[0]) == SUCCEED) + { + hostid = DBget_maxid("hosts","hostid"); + DBexecute("insert into hosts (hostid,host,useip,ip,dns) values (" ZBX_FS_UI64 ",'%s',1,'%s','%s')", + hostid, + (host[0] != '\0' ? host_esc : ip), /* Use host name if exists, IP otherwise */ + ip, + host_esc); + } + else + { + ZBX_STR2UINT64(hostid, row2[0]); + if(host_esc[0] != '\0') + { + DBexecute("update hosts set dns='%s' where hostid=" ZBX_FS_UI64, + host_esc, + hostid); + } + } + DBfree_result(result2); + } + DBfree_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End add_discovered_host()"); + + return hostid; +} + +/****************************************************************************** + * * + * Function: op_host_add * + * * + * Purpose: add discovered host * + * * + * Parameters: trigger - trigger data * + * action - action data * + * * + * Return value: nothing * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_host_add(DB_EVENT *event) +{ + zbx_uint64_t hostid; + zbx_uint64_t dhostid = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_host_add()"); + + if(event->object == EVENT_OBJECT_DHOST) + { + dhostid = event->objectid; + } + else if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + + hostid = add_discovered_host(dhostid); + + zabbix_log(LOG_LEVEL_DEBUG, "End op_host_add()"); +} + +/****************************************************************************** + * * + * Function: op_host_del * + * * + * Purpose: delete host * + * * + * Parameters: * + * * + * Return value: nothing * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_host_del(DB_EVENT *event) +{ + zbx_uint64_t hostid, dhostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_host_del()"); + + if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + else + { + dhostid = event->objectid; + } + + hostid = select_discovered_host(dhostid); + if(hostid != 0) + { + DBdelete_host(hostid); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End op_host_del()"); +} + +/****************************************************************************** + * * + * Function: op_group_add * + * * + * Purpose: add group to discovered host * + * * + * Parameters: trigger - trigger data * + * action - action data * + * * + * Return value: nothing * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_group_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t hostgroupid, groupid, hostid, dhostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_group_add(object:%d)", + event->object); + + if(operation->operationtype != OPERATION_TYPE_GROUP_ADD) return; + if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return; + + + if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + else + { + dhostid = event->objectid; + } + + hostid = add_discovered_host(dhostid); + if(hostid != 0) + { + groupid = operation->objectid; + result = DBselect("select hostgroupid from hosts_groups where groupid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64, + groupid, + hostid); + row = DBfetch(result); + if(!row || DBis_null(row[0]) == SUCCEED) + { + hostgroupid = DBget_maxid("hosts_groups","hostgroupid"); + DBexecute("insert into hosts_groups (hostgroupid,hostid,groupid) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ")", + hostgroupid, + hostid, + groupid); + } + DBfree_result(result); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End op_group_add()"); +} + +/****************************************************************************** + * * + * Function: op_group_del * + * * + * Purpose: delete group from discovered host * + * * + * Parameters: trigger - trigger data * + * action - action data * + * * + * Return value: nothing * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_group_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation) +{ + zbx_uint64_t groupid, hostid, dhostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_group_del()"); + + if(operation->operationtype != OPERATION_TYPE_GROUP_REMOVE) return; + if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return; + + if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + else + { + dhostid = event->objectid; + } + + hostid = select_discovered_host(dhostid); + if(hostid != 0) + { + groupid = operation->objectid; + DBexecute("delete from hosts_groups where hostid=" ZBX_FS_UI64 " and groupid=" ZBX_FS_UI64, + hostid, + groupid); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End op_group_del()"); +} + +/****************************************************************************** + * * + * Function: op_template_add * + * * + * Purpose: link host with template * + * * + * Parameters: * + * * + * Return value: nothing * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_template_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t hosttemplateid, templateid, hostid, dhostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_template_add(object:%d)", + event->object); + + if(operation->operationtype != OPERATION_TYPE_TEMPLATE_ADD) return; + if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return; + + + if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + else + { + dhostid = event->objectid; + } + + hostid = add_discovered_host(dhostid); + if(hostid != 0) + { + templateid = operation->objectid; + + result = DBselect("select hosttemplateid from hosts_templates where templateid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64, + templateid, + hostid); + row = DBfetch(result); + if(!row || DBis_null(row[0]) == SUCCEED) + { + hosttemplateid = DBget_maxid("hosts_templates","hosttemplateid"); + DBexecute("begin;"); + + DBexecute("insert into hosts_templates (hosttemplateid,hostid,templateid) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ")", + hosttemplateid, + hostid, + templateid); + + DBsync_host_with_template(hostid, templateid); + + DBexecute("commit;"); + } + DBfree_result(result); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End op_template_add()"); +} + +/****************************************************************************** + * * + * Function: op_template_del * + * * + * Purpose: unlink and clear host from template * + * * + * Parameters: * + * * + * Return value: nothing * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +void op_template_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation) +{ + DB_RESULT result; + DB_ROW row; + zbx_uint64_t templateid, hostid, dhostid; + + zabbix_log(LOG_LEVEL_DEBUG, "In op_template_del(object:%d)", + event->object); + + if(operation->operationtype != OPERATION_TYPE_TEMPLATE_REMOVE) return; + if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return; + + + if(event->object == EVENT_OBJECT_DSERVICE) + { + dhostid = select_dhostid_by_dserviceid(event->objectid); + } + else + { + dhostid = event->objectid; + } + + hostid = select_discovered_host(dhostid); + if(hostid != 0) + { + templateid = operation->objectid; + + result = DBselect("select hosttemplateid from hosts_templates where templateid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64, + templateid, + hostid); + + if( (row = DBfetch(result)) ) + { + DBexecute("begin;"); + + DBdelete_template_elements(hostid, templateid, 0 /* not a unlink mode */); + + DBexecute("delete from hosts_templates where " + "hostid=" ZBX_FS_UI64 " and templateid=" ZBX_FS_UI64, + hostid, + templateid); + + DBexecute("commit;"); + } + DBfree_result(result); + } + + zabbix_log(LOG_LEVEL_DEBUG, "End op_template_del()"); +} + diff --git a/src/zabbix_proxy/operations.h b/src/zabbix_proxy/operations.h new file mode 100644 index 00000000..523f03c3 --- /dev/null +++ b/src/zabbix_proxy/operations.h @@ -0,0 +1,36 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_OPERATIONS_H +#define ZABBIX_OPERATIONS_H + +#include "common.h" +#include "db.h" + +void op_template_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation); +void op_template_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation); +void op_group_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation); +void op_group_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation); +void op_host_add(DB_EVENT *event); +void op_host_del(DB_EVENT *event); +void op_run_commands(DB_EVENT *event, DB_OPERATION *operation); +void op_notify_user(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation); + +#endif diff --git a/src/zabbix_proxy/pinger/Makefile.am b/src/zabbix_proxy/pinger/Makefile.am new file mode 100644 index 00000000..589d6d19 --- /dev/null +++ b/src/zabbix_proxy/pinger/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxpinger.a + +libzbxpinger_a_SOURCES = pinger.c pinger.h diff --git a/src/zabbix_proxy/pinger/pinger.c b/src/zabbix_proxy/pinger/pinger.c new file mode 100644 index 00000000..01620be1 --- /dev/null +++ b/src/zabbix_proxy/pinger/pinger.c @@ -0,0 +1,415 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "db.h" +#include "../functions.h" +#include "log.h" +#include "zlog.h" +#include "threads.h" + +#include "pinger.h" + +int pinger_num; + +/****************************************************************************** + * * + * Function: is_ip * + * * + * Purpose: is string IP address * + * * + * Parameters: ip - string * + * * + * Return value: SUCCEED - is IP address * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: could be improved * + * * + ******************************************************************************/ +static int is_ip(char *ip) +{ + int i; + char c; + int dots=0; + int res = SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In process_ip([%s])", + ip); + + for(i=0;ip[i]!=0;i++) + { + c=ip[i]; + if( (c>='0') && (c<='9')) + { + continue; + } + else if(c=='.') + { + dots++; + } + else + { + res = FAIL; + break; + } + } + if( dots!=3) + { + res = FAIL; + } + zabbix_log( LOG_LEVEL_DEBUG, "End of process_ip(result:%d)", + res); + return res; +} + +/****************************************************************************** + * * + * Function: process_new_value * + * * + * Purpose: process new item value * + * * + * Parameters: key - item key * + * host - host name * + * value - new value of the item * + * * + * Return value: SUCCEED - new value sucesfully processed * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: can be done in process_data() * + * * + ******************************************************************************/ +static int process_value(char *key, char *host, AGENT_RESULT *value) +{ + DB_RESULT result; + DB_ROW row; + DB_ITEM item; + + zabbix_log( LOG_LEVEL_DEBUG, "In process_value(%s@%s)", + key, + host); + + /* IP address? */ + if(is_ip(host) == SUCCEED) + { + result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.ip='%s' and i.key_='%s' and i.status=%d and i.type=%d and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + HOST_STATUS_MONITORED, + host, + key, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_SIMPLE, + LOCAL_NODE("h.hostid")); + } + else + { + result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.dns='%s' and i.key_='%s' and i.status=%d and i.type=%d and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + HOST_STATUS_MONITORED, + host, + key, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_SIMPLE, + LOCAL_NODE("h.hostid")); + } + row=DBfetch(result); + + if(!row) + { + DBfree_result(result); + return FAIL; + } + + DBget_item_from_db(&item,row); + + DBbegin(); + process_new_value(&item,value); + update_triggers(item.itemid); + DBcommit(); + + DBfree_result(result); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: create_host_file * + * * + * Purpose: creates file which contains list of hosts to ping * + * * + * Parameters: * + * * + * Return value: SUCCEED - the file was created succesfully * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int create_host_file(void) +{ + FILE *f; + int now; + + DB_HOST host; + DB_RESULT result; + DB_ROW row; + char str[MAX_STRING_LEN]; + + + zabbix_log( LOG_LEVEL_DEBUG, "In create_host_file()"); + + zbx_snprintf(str,sizeof(str),"/tmp/zabbix_server_%li.pinger", + zbx_get_thread_id()); + + if(NULL == (f = fopen(str, "w") )) + { + zabbix_log( LOG_LEVEL_ERR, "Cannot open file [%s] [%s]", + str, + strerror(errno)); + zabbix_syslog("Cannot open file [%s] [%s]", + str, + strerror(errno)); + return FAIL; + } + + now=time(NULL); + /* Select hosts monitored by IP */ + result = DBselect("select distinct h.ip from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.hostid=h.hostid and h.status=%d and (i.key_='%s' or i.key_='%s') and i.type=%d and i.status=%d and h.useip=1 and" ZBX_COND_NODEID, + CONFIG_PINGER_FORKS, + pinger_num-1, + HOST_STATUS_MONITORED, + SERVER_ICMPPING_KEY, + SERVER_ICMPPINGSEC_KEY, + ITEM_TYPE_SIMPLE, + ITEM_STATUS_ACTIVE, + LOCAL_NODE("h.hostid")); + + while((row=DBfetch(result))) + { + strscpy(host.ip,row[0]); +/* host.host=DBget_field(result,i,2);*/ + + fprintf(f,"%s\n",host.ip); + + zabbix_log( LOG_LEVEL_DEBUG, "IP [%s]", host.ip); + } + DBfree_result(result); + + /* Select hosts monitored by hostname */ + result = DBselect("select distinct h.dns from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.hostid=h.hostid and h.status=%d and (i.key_='%s' or i.key_='%s') and i.type=%d and i.status=%d and h.useip=0 and" ZBX_COND_NODEID, + CONFIG_PINGER_FORKS, + pinger_num-1, + HOST_STATUS_MONITORED, + SERVER_ICMPPING_KEY, + SERVER_ICMPPINGSEC_KEY, + ITEM_TYPE_SIMPLE, + ITEM_STATUS_ACTIVE, + LOCAL_NODE("h.hostid")); + + while((row=DBfetch(result))) + { + strscpy(host.dns,row[0]); + + fprintf(f,"%s\n", + host.dns); + + zabbix_log( LOG_LEVEL_DEBUG, "DNS name [%s]", + host.dns); + } + DBfree_result(result); + + zbx_fclose(f); + + return SUCCEED; +} + + +/****************************************************************************** + * * + * Function: do_ping * + * * + * Purpose: ping hosts listed in the host files * + * * + * Parameters: * + * * + * Return value: SUCCEED - successfully processed * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: use external binary 'fping' to avoid superuser priviledges * + * * + ******************************************************************************/ +static int do_ping(void) +{ + FILE *f; + char ip[MAX_STRING_LEN]; + char str[MAX_STRING_LEN]; + char tmp[MAX_STRING_LEN]; + double mseconds; + char *c; + int alive; + AGENT_RESULT value; + + zabbix_log( LOG_LEVEL_DEBUG, "In do_ping()"); + + zbx_snprintf(str,sizeof(str),"cat /tmp/zabbix_server_%li.pinger | %s -e 2>/dev/null", + zbx_get_thread_id(), + CONFIG_FPING_LOCATION); + + f=popen(str,"r"); + if(f==0) + { + zabbix_log( LOG_LEVEL_ERR, "Cannot execute [%s] [%s]", + CONFIG_FPING_LOCATION, + strerror(errno)); + zabbix_syslog("Cannot execute [%s] [%s]", + CONFIG_FPING_LOCATION, + strerror(errno)); + return FAIL; + } + + while(NULL!=fgets(ip,MAX_STRING_LEN,f)) + { +/* zabbix_log( LOG_LEVEL_WARNING, "PING: [%s]", ip);*/ + + ip[strlen(ip)-1]=0; + zabbix_log( LOG_LEVEL_DEBUG, "Update IP [%s]", + ip); + + if(strstr(ip,"alive") != NULL) + { + alive=1; + sscanf(ip,"%s is alive (%lf ms)", + tmp, + &mseconds); + zabbix_log( LOG_LEVEL_DEBUG, "Mseconds [%lf]", + mseconds); + } + else + { + alive=0; + } + c=strstr(ip," "); + if(c != NULL) + { + *c=0; + zabbix_log( LOG_LEVEL_DEBUG, "IP [%s] alive [%d]", + ip, + alive); + + if(0 == alive) + { + init_result(&value); + SET_UI64_RESULT(&value, 0); + process_value(SERVER_ICMPPING_KEY,ip,&value); + free_result(&value); + + init_result(&value); + SET_DBL_RESULT(&value, 0); + process_value(SERVER_ICMPPINGSEC_KEY,ip,&value); + free_result(&value); + } + else + { + init_result(&value); + SET_UI64_RESULT(&value, 1); + process_value(SERVER_ICMPPING_KEY,ip,&value); + free_result(&value); + + init_result(&value); + SET_DBL_RESULT(&value, mseconds/1000); + process_value(SERVER_ICMPPINGSEC_KEY,ip,&value); + free_result(&value); + } + } + } + + pclose(f); + + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: main_pinger_loop * + * * + * Purpose: periodically perform ICMP pings * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: never returns * + * * + ******************************************************************************/ +void main_pinger_loop(int num) +{ + int ret = SUCCEED; + + char str[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In main_pinger_loop(num:%d)", + num); + + pinger_num = num; + + for(;;) + { + zbx_setproctitle("connecting to the database"); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + +/* zabbix_set_log_level(LOG_LEVEL_DEBUG);*/ + + ret = create_host_file(); + + if( SUCCEED == ret) + { + zbx_setproctitle("pinging hosts"); + + ret = do_ping(); + } + zbx_snprintf(str,sizeof(str),"/tmp/zabbix_server_%li.pinger", + zbx_get_thread_id()); + unlink(str); + +/* zabbix_set_log_level(LOG_LEVEL_WARNING); */ + + DBclose(); + + zbx_setproctitle("pinger [sleeping for %d seconds]", + CONFIG_PINGER_FREQUENCY); + + sleep(CONFIG_PINGER_FREQUENCY); + } + + /* Never reached */ +} diff --git a/src/zabbix_proxy/pinger/pinger.h b/src/zabbix_proxy/pinger/pinger.h new file mode 100644 index 00000000..bf52b8d7 --- /dev/null +++ b/src/zabbix_proxy/pinger/pinger.h @@ -0,0 +1,31 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_PINGER_H +#define ZABBIX_PINGER_H + +extern int CONFIG_PINGER_FORKS; +extern int CONFIG_PINGER_FREQUENCY; +extern char *CONFIG_FPING_LOCATION; + +extern void signal_handler( int sig ); + +void main_pinger_loop(int num); + +#endif diff --git a/src/zabbix_proxy/poller/Makefile.am b/src/zabbix_proxy/poller/Makefile.am new file mode 100644 index 00000000..5d6ebe0a --- /dev/null +++ b/src/zabbix_proxy/poller/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxpoller.a + +libzbxpoller_a_SOURCES = \ + checks_agent.c checks_agent.h \ + checks_internal.c checks_internal.h \ + checks_simple.c checks_simple.h \ + checks_snmp.c checks_snmp.h \ + checks_db.c checks_db.h \ + checks_aggregate.c checks_aggregate.h \ + checks_external.c checks_external.h \ + poller.c poller.h diff --git a/src/zabbix_proxy/poller/checks_agent.c b/src/zabbix_proxy/poller/checks_agent.c new file mode 100644 index 00000000..a9a5fe80 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_agent.c @@ -0,0 +1,133 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ +#include "common.h" +#include "comms.h" + +#include "checks_agent.h" + +/****************************************************************************** + * * + * Function: get_value_agent * + * * + * Purpose: retrieve data from ZABBIX agent * + * * + * Parameters: item - item we are interested in * + * * + * Return value: SUCCEED - data succesfully retrieved and stored in result * + * and result_str (as string) * + * NETWORK_ERROR - network related error occured * + * NOTSUPPORTED - item not supported by the agent * + * AGENT_ERROR - uncritical error on agent side occured * + * FAIL - otherwise * + * * + * Author: Alexei Vladishev * + * * + * Comments: error will contain error message * + * * + ******************************************************************************/ +int get_value_agent(DB_ITEM *item, AGENT_RESULT *result) +{ + zbx_sock_t s; + + char + *buf, + packet[MAX_STRING_LEN], + error[MAX_STRING_LEN]; + + int ret = SUCCEED; + + init_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_agent(host:%s,ip:%s,key:%s", + item->host_name, + item->host_ip, + item->key ); + + if (SUCCEED == (ret = zbx_tcp_connect(&s, item->useip==1 ? item->host_ip : item->host_dns, item->port, 0))) { + zbx_snprintf(packet, sizeof(packet), "%s\n",item->key); + zabbix_log(LOG_LEVEL_DEBUG, "Sending [%s]", packet); + + /* Send requests using old protocol */ + if( SUCCEED == (ret = zbx_tcp_send_raw(&s, packet)) ) + { + zabbix_log(LOG_LEVEL_DEBUG, "Before read"); + + ret = zbx_tcp_recv_ext(&s, &buf, ZBX_TCP_READ_UNTIL_CLOSE); + } + } + + if( SUCCEED == ret ) + { + zbx_rtrim(buf, " \r\n\0"); + zbx_ltrim(buf, " "); + + if( strcmp(buf,"ZBX_NOTSUPPORTED") == 0) + { + zbx_snprintf(error,sizeof(error),"Not supported by ZABBIX agent"); + SET_MSG_RESULT(result, strdup(error)); + ret = NOTSUPPORTED; + } + else if( strcmp(buf,"ZBX_ERROR") == 0) + { + zbx_snprintf(error,sizeof(error),"ZABBIX agent non-critical error"); + SET_MSG_RESULT(result, strdup(error)); + ret = AGENT_ERROR; + } + /* The section should be improved */ + else if(buf[0]==0) + { + zbx_snprintf(error,sizeof(error),"Got empty string from [%s] IP [%s] Parameter [%s]", + item->host_name, + item->host_ip, + item->key); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + zabbix_log( LOG_LEVEL_WARNING, "Assuming that agent dropped connection because of access permissions"); + SET_MSG_RESULT(result, strdup(error)); + ret = NETWORK_ERROR; + } + else if(set_result_type(result, item->value_type, buf) == FAIL) + { + zbx_snprintf(error,sizeof(error), "Type of received value [%s] is not sutable for [%s@%s] having type [%d]", + buf, + item->key, + item->host_name, + item->value_type); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + zabbix_log( LOG_LEVEL_WARNING, "Returning NOTSUPPORTED"); + result->msg=strdup(error); + ret = NOTSUPPORTED; + } + + zabbix_log( LOG_LEVEL_DEBUG, "End get_value_agent(result:%s)", + buf); + + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Get value from agent failed. Error: %s", zbx_tcp_strerror()); + SET_MSG_RESULT(result, strdup(zbx_tcp_strerror())); + ret = NETWORK_ERROR; + + } + zbx_tcp_close(&s); + + return ret; +} diff --git a/src/zabbix_proxy/poller/checks_agent.h b/src/zabbix_proxy/poller/checks_agent.h new file mode 100644 index 00000000..f890eee7 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_agent.h @@ -0,0 +1,32 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_AGENT_H +#define ZABBIX_CHECKS_AGENT_H + +#include "common.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" + +extern int CONFIG_NOTIMEWAIT; + +extern int get_value_agent(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/poller/checks_aggregate.c b/src/zabbix_proxy/poller/checks_aggregate.c new file mode 100644 index 00000000..29e56cb7 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_aggregate.c @@ -0,0 +1,369 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "checks_aggregate.h" + +static int evaluate_one(double *result, int *num, char *grpfunc, char const *value_str, int valuetype) +{ + int ret = SUCCEED; + double value = 0; + + if(valuetype == ITEM_VALUE_TYPE_FLOAT) + { + value = zbx_atod(value_str); + } + else if(valuetype == ITEM_VALUE_TYPE_UINT64) + { + value = (double)zbx_atoui64(value_str); + } + + if(strcmp(grpfunc,"grpsum") == 0) + { + *result+=value; + *num+=1; + } + else if(strcmp(grpfunc,"grpavg") == 0) + { + *result+=value; + *num+=1; + } + else if(strcmp(grpfunc,"grpmin") == 0) + { + if(*num==0) + { + *result=value; + } + else if(value<*result) + { + *result=value; + } + *num+=1; + } + else if(strcmp(grpfunc,"grpmax") == 0) + { + if(*num==0) + { + *result=value; + } + else if(value>*result) + { + *result=value; + } + *num+=1; + } + else + { + ret = FAIL; + } + + return ret; +} + +/* + * grpfunc: grpmax, grpmin, grpsum, grpavg + * itemfunc: last, min, max, avg, sum,count + */ +static int evaluate_aggregate(AGENT_RESULT *res,char *grpfunc, char *hostgroup, char *itemkey, char *itemfunc, char *param) +{ + char sql[MAX_STRING_LEN]; + char sql2[MAX_STRING_LEN]; + char hostgroup_esc[MAX_STRING_LEN],itemkey_esc[MAX_STRING_LEN]; + + DB_RESULT result; + DB_ROW row; + + int valuetype; + double d = 0; + const char *value; + int num = 0; + int now; + char items[MAX_STRING_LEN],items2[MAX_STRING_LEN]; + + now=time(NULL); + + zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_aggregate('%s','%s','%s','%s','%s')", + grpfunc, + hostgroup, + itemkey, + itemfunc, + param); + + init_result(res); + + DBescape_string(itemkey,itemkey_esc,MAX_STRING_LEN); + DBescape_string(hostgroup,hostgroup_esc,MAX_STRING_LEN); +/* Get list of affected item IDs */ + strscpy(items,"0"); + result = DBselect("select itemid from items i,hosts_groups hg,hosts h,groups g where hg.groupid=g.groupid and i.hostid=h.hostid and hg.hostid=h.hostid and g.name='%s' and i.key_='%s' and i.status=%d and h.status=%d and" ZBX_COND_NODEID, + hostgroup_esc, + itemkey_esc, + ITEM_STATUS_ACTIVE, + HOST_STATUS_MONITORED, + LOCAL_NODE("h.hostid")); + + while((row=DBfetch(result))) + { + zbx_snprintf(items2,sizeof(items2),"%s,%s", + items, + row[0]); +/* zabbix_log( LOG_LEVEL_WARNING, "ItemIDs items2[%s])",items2);*/ + strscpy(items,items2); +/* zabbix_log( LOG_LEVEL_WARNING, "ItemIDs items[%s])",items2);*/ + } + DBfree_result(result); + + if(strcmp(itemfunc,"last") == 0) + { + zbx_snprintf(sql,sizeof(sql),"select itemid,value_type,lastvalue from items where lastvalue is not NULL and items.itemid in (%s)", + items); + zbx_snprintf(sql2,sizeof(sql2),"select itemid,value_type,lastvalue from items where 0=1"); + } + /* The SQL works very very slow on MySQL 4.0. That's why it has been split into two. */ +/* zbx_snprintf(sql,sizeof(sql),"select items.itemid,items.value_type,min(history.value) from items,hosts_groups,hosts,groups,history where history.itemid=items.itemid and hosts_groups.groupid=groups.groupid and items.hostid=hosts.hostid and hosts_groups.hostid=hosts.hostid and groups.name='%s' and items.key_='%s' and history.clock>%d group by 1,2",hostgroup_esc, itemkey_esc, now - atoi(param));*/ + else if( (strcmp(itemfunc,"min") == 0) || + (strcmp(itemfunc,"max") == 0) || + (strcmp(itemfunc,"avg") == 0) || + (strcmp(itemfunc,"count") == 0) || + (strcmp(itemfunc,"sum") == 0) + ) + { + zbx_snprintf(sql,sizeof(sql),"select h.itemid,i.value_type,%s(h.value) from items i,history h where h.itemid=i.itemid and h.itemid in (%s) and h.clock>%d group by h.itemid,i.value_type", + itemfunc, + items, + now - atoi(param)); + zbx_snprintf(sql2,sizeof(sql),"select h.itemid,i.value_type,%s(h.value) from items i,history_uint h where h.itemid=i.itemid and h.itemid in (%s) and h.clock>%d group by h.itemid,i.value_type", + itemfunc, + items, + now - atoi(param)); + } + else + { + SET_MSG_RESULT(res, strdup("Unsupported item function")); + zabbix_log( LOG_LEVEL_WARNING, "Unsupported item function [%s])", + itemfunc); + return FAIL; + } + zabbix_log( LOG_LEVEL_DEBUG, "SQL [%s]",sql); + zabbix_log( LOG_LEVEL_DEBUG, "SQL2 [%s]",sql2); + + result = DBselect("%s",sql); + while((row=DBfetch(result))) + { + valuetype = atoi(row[1]); + value = row[2]; + if(FAIL == evaluate_one(&d, &num, grpfunc, value, valuetype)) + { + SET_MSG_RESULT(res, strdup("Unsupported group function")); + zabbix_log( LOG_LEVEL_WARNING, "Unsupported group function [%s])", + grpfunc); + DBfree_result(result); + return FAIL; + } + } + DBfree_result(result); + + result = DBselect("%s",sql2); + while((row=DBfetch(result))) + { + valuetype = atoi(row[1]); + value = row[2]; + if(FAIL == evaluate_one(&d, &num, grpfunc, value, valuetype)) + { + SET_MSG_RESULT(res, strdup("Unsupported group function")); + zabbix_log( LOG_LEVEL_WARNING, "Unsupported group function [%s])", + grpfunc); + DBfree_result(result); + return FAIL; + } + } + DBfree_result(result); + + if(num==0) + { + SET_MSG_RESULT(res, strdup("No values")); + zabbix_log( LOG_LEVEL_WARNING, "No values for group[%s] key[%s])", + hostgroup, + itemkey); + return FAIL; + } + + if(strcmp(grpfunc,"grpavg") == 0) + { + SET_DBL_RESULT(res, d/num); + } + else + { + SET_DBL_RESULT(res, d); + } + + zabbix_log( LOG_LEVEL_DEBUG, "End evaluate_aggregate(result:" ZBX_FS_DBL ")", + d); + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: get_value_aggregate * + * * + * Purpose: retrieve data from ZABBIX server (aggregate items) * + * * + * Parameters: item - item we are interested in * + * * + * Return value: SUCCEED - data succesfully retrieved and stored in result * + * and result_str (as string) * + * NOTSUPPORTED - requested item is not supported * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int get_value_aggregate(DB_ITEM *item, AGENT_RESULT *result) +{ + char function_grp[MAX_STRING_LEN]; + char key[MAX_STRING_LEN]; + char group[MAX_STRING_LEN]; + char itemkey[MAX_STRING_LEN]; + char function_item[MAX_STRING_LEN]; + char parameter[MAX_STRING_LEN]; + char *p,*p2; + + int ret = SUCCEED; + + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_aggregate([%s])", + item->key); + + init_result(result); + + strscpy(key, item->key); + if((p=strchr(key,'[')) != NULL) + { + *p=0; + strscpy(function_grp,key); + *p='['; + p++; + } + else ret = NOTSUPPORTED; + + if(ret == SUCCEED) + { + if((p2=strchr(p,'"')) != NULL) + { + p2++; + } + else ret = NOTSUPPORTED; + + if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL) + { + *p=0; + strscpy(group,p2); + *p='"'; + p++; + } + else ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if(*p != ',') ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if((p2=strchr(p,'"')) != NULL) + { + p2++; + } + else ret = NOTSUPPORTED; + + if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL) + { + *p=0; + strscpy(itemkey,p2); + *p='"'; + p++; + } + else ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if(*p != ',') ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if((p2=strchr(p,'"')) != NULL) + { + p2++; + } + else ret = NOTSUPPORTED; + + if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL) + { + *p=0; + strscpy(function_item,p2); + *p='"'; + p++; + } + else ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if(*p != ',') ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if((p2=strchr(p,'"')) != NULL) + { + p2++; + } + else ret = NOTSUPPORTED; + + if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL) + { + *p=0; + strscpy(parameter,p2); + *p='"'; + p++; + } + else ret = NOTSUPPORTED; + } + + zabbix_log( LOG_LEVEL_DEBUG, "Evaluating aggregate[%s] grpfunc[%s] group[%s] itemkey[%s] itemfunc [%s] parameter [%s]", + item->key, + function_grp, + group, + itemkey, + function_item, + parameter); + + if( (ret == SUCCEED) && + (evaluate_aggregate(result,function_grp, group, itemkey, function_item, parameter) != SUCCEED) + ) + { + ret = NOTSUPPORTED; + } + + return ret; +} diff --git a/src/zabbix_proxy/poller/checks_aggregate.h b/src/zabbix_proxy/poller/checks_aggregate.h new file mode 100644 index 00000000..0d42b2bd --- /dev/null +++ b/src/zabbix_proxy/poller/checks_aggregate.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_AGGREGATE_H +#define ZABBIX_CHECKS_AGGREGATE_H + +#include "common.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" + +extern int get_value_aggregate(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/poller/checks_db.c b/src/zabbix_proxy/poller/checks_db.c new file mode 100644 index 00000000..bd3b9cf7 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_db.c @@ -0,0 +1,201 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#ifdef HAVE_ODBC +# include "zbxodbc.h" +#endif /* HAVE_ODBC */ + +#include "checks_db.h" +#include "log.h" + +#ifdef HAVE_ODBC +/****************************************************************************** + * * + * Function: get_param_value * + * * + * Purpose: retrieve parameter value by name * + * * + * Parameters: params - list of params * + * param_name - name of requested parameter * + * * + * Return value: NULL - if parameter missedparam_name, * + * else return value in new allocated memory * + * * + * Author: Eugene Grigorjev * + * * + * Comments: this function allocate memory, required zbx_free for result!!! * + * one parameter format: param1_name=param1_value * + * parameters splited by '\n' * + * * + ******************************************************************************/ +static char* get_param_value(char* params, const char* param_name) +{ + char + *p = NULL, + *l = NULL, + *n = NULL, + *r = NULL, + *buf = NULL; + + for(p = params; p && *p; p++) + { + r = NULL; + + /* trim left spaces */ + for(; *p == ' '; p++); + + /* find '=' symbol */ + for(n = p; *n && *n != '\n'; n++) + { + if(*n == '=') + { + /* trim right spaces */ + for(l = n - 1; *l == ' '; l--); + l++; + + /* compare parameter name */ + if(l - p != strlen(param_name)) break; + if(strncmp(p, param_name, l - p)) break; + + r = n+1; + break; + } + } + + /* find EOL */ + for(p = n; *p && *p != '\n'; p++); + + /* allocate result */ + if(r) + { + /* trim right EOL symbols */ + while(*p == '\r' || *p == '\n' || *p == '\0') p--; + p++; + + /* allocate result */ + buf = zbx_malloc(buf, p - r + 1); + memmove(buf, r, p - r); + buf[p - r] = '\0'; + + break; + } + } + + if(buf == NULL) + { + /* allocate result */ + buf = zbx_malloc(buf, 1); + *buf = '\0'; + } + return buf; +} +#endif /* HAVE_ODBC */ + +/****************************************************************************** + * * + * Function: get_value_db * + * * + * Purpose: retrieve data from database * + * * + * Parameters: item - item we are interested in * + * * + * Return value: SUCCEED - data succesfully retrieved and stored in result * + * NOTSUPPORTED - requested item is not supported * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +int get_value_db(DB_ITEM *item, AGENT_RESULT *result) +{ +#ifdef HAVE_ODBC + ZBX_ODBC_DBH dbh; + ZBX_ODBC_ROW row; + + char + *db_dsn = NULL, + *db_user = NULL, + *db_pass = NULL, + *db_sql = NULL; +#endif /* HAVE_ODBC */ + + int ret = NOTSUPPORTED; + + init_result(result); + + zabbix_log(LOG_LEVEL_DEBUG, "In database monitor: %s", item->key); + +#ifdef HAVE_ODBC + + #define DB_ODBC_SELECT_KEY "db.odbc.select[" + + if(strncmp(item->key, DB_ODBC_SELECT_KEY, strlen(DB_ODBC_SELECT_KEY)) == 0) + { + db_dsn = get_param_value(item->params,"DSN"); + db_user = get_param_value(item->params,"user"); + db_pass = get_param_value(item->params,"password"); + db_sql = get_param_value(item->params,"sql"); + + if( SUCCEED == odbc_DBconnect(&dbh, db_dsn, db_user, db_pass) ) + { + if( NULL != (row = odbc_DBfetch(odbc_DBselect(&dbh, db_sql))) ) + { + if( SUCCEED == set_result_type(result, item->value_type, row[0]) ) + { + zabbix_log(LOG_LEVEL_DEBUG, "Result accepted with type 0x%02X [%s]", item->value_type, row[0]); + ret = SUCCEED; + } + else + { + zabbix_log(LOG_LEVEL_DEBUG, "Cant determine result type [%s]", row[0]); + } + } + else + { + SET_MSG_RESULT(result, strdup(get_last_odbc_strerror())); + } + odbc_DBclose(&dbh); + } + else + { + SET_MSG_RESULT(result, strdup(get_last_odbc_strerror())); + } + + zbx_free(db_dsn); + zbx_free(db_user); + zbx_free(db_pass); + zbx_free(db_sql); + } + +#endif /* HAVE_ODBC */ + + /* + * TODO: + * + * db.*.select[] + * db.*.ping + * ... + * + */ + + return ret; +} diff --git a/src/zabbix_proxy/poller/checks_db.h b/src/zabbix_proxy/poller/checks_db.h new file mode 100644 index 00000000..e3b07d21 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_db.h @@ -0,0 +1,28 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_DB_H +#define ZABBIX_CHECKS_DB_H + +#include "db.h" +#include "sysinfo.h" + +int get_value_db(DB_ITEM *item, AGENT_RESULT *result); + +#endif /* ZABBIX_CHECKS_DB_H */ diff --git a/src/zabbix_proxy/poller/checks_external.c b/src/zabbix_proxy/poller/checks_external.c new file mode 100644 index 00000000..a4a164b7 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_external.c @@ -0,0 +1,134 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "checks_external.h" + +/****************************************************************************** + * * + * Function: get_value_external * + * * + * Purpose: retrieve data from script executed on ZABBIX server * + * * + * Parameters: item - item we are interested in * + * * + * Return value: SUCCEED - data succesfully retrieved and stored in result * + * and result_str (as string) * + * NOTSUPPORTED - requested item is not supported * + * * + * Author: Mike Nestor * + * * + * Comments: * + * * + ************************************************** ****************************/ +int get_value_external(DB_ITEM *item, AGENT_RESULT *result) +{ + FILE* fp; + char scriptname[MAX_STRING_LEN]; + char key[MAX_STRING_LEN]; + char params[MAX_STRING_LEN]; + char error[MAX_STRING_LEN]; + char cmd[MAX_STRING_LEN]; + char msg[MAX_STRING_LEN]; + char *p,*p2; + int i; + + int ret = SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_external([%s])",item->key); + + init_result(result); + + strscpy(key, item->key); + if((p2=strchr(key,'[')) != NULL) + { + *p2=0; + strscpy(scriptname,key); + zabbix_log( LOG_LEVEL_DEBUG, "scriptname [%s]",scriptname); + *p2='['; + p2++; + } + else ret = NOTSUPPORTED; + + if(ret == SUCCEED) + { + if((ret == SUCCEED) && (p=strchr(p2,']')) != NULL) + { + *p=0; + strscpy(params,p2); + zabbix_log( LOG_LEVEL_DEBUG, "params [%s]",params); + *p=']'; + p++; + } + else ret = NOTSUPPORTED; + } + else + { + zbx_snprintf(error,MAX_STRING_LEN-1,"External check [%s] is not supported", item->key); + zabbix_log( LOG_LEVEL_DEBUG, "%s", error); + SET_STR_RESULT(result, strdup(error)); + return NOTSUPPORTED; + } + + zbx_snprintf(cmd, MAX_STRING_LEN-1, "%s/%s %s %s", + CONFIG_EXTERNALSCRIPTS, + scriptname, +/* item->host_name,*/ + item->useip == 1 ? item->host_ip : item->host_dns, + params); + zabbix_log( LOG_LEVEL_DEBUG, "%s", cmd ); + if (NULL == (fp = popen(cmd, "r"))) + { + zbx_snprintf(error,MAX_STRING_LEN-1,"External check [%s] is not supported, failed execution", item->key); + zabbix_log( LOG_LEVEL_DEBUG, "%s", error); + SET_STR_RESULT(result, strdup(error)); + return NOTSUPPORTED; + } + + /* we only care about the first line */ + memset(msg,0,sizeof(msg)); + if(NULL != fgets(msg, sizeof(msg)-1, fp)) + { + for (i = 0; i < MAX_STRING_LEN && msg[i] != 0; ++i) + { + if (msg[i] == '\n') + { + msg[i] = 0; + break; + } + } + zabbix_log( LOG_LEVEL_DEBUG, "Result [%s]", msg); + + set_result_type(result,item->value_type,strdup(msg)); + } + else + { + zbx_snprintf(error,MAX_STRING_LEN-1,"Script %s/%s returned nothing.", + CONFIG_EXTERNALSCRIPTS, + scriptname); + zabbix_log( LOG_LEVEL_WARNING, "%s", error); + SET_STR_RESULT(result, strdup(error)); + ret = NOTSUPPORTED; + } + + /* cleanup */ + pclose(fp); + + return ret; +} diff --git a/src/zabbix_proxy/poller/checks_external.h b/src/zabbix_proxy/poller/checks_external.h new file mode 100644 index 00000000..cdabbaab --- /dev/null +++ b/src/zabbix_proxy/poller/checks_external.h @@ -0,0 +1,36 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_EXTERNAL_H +#define ZABBIX_CHECKS_EXTERNAL_H + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "common.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" + +extern char *CONFIG_EXTERNALSCRIPTS; + +extern int get_value_external(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/poller/checks_internal.c b/src/zabbix_proxy/poller/checks_internal.c new file mode 100644 index 00000000..ed53c36e --- /dev/null +++ b/src/zabbix_proxy/poller/checks_internal.c @@ -0,0 +1,93 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" +#include "checks_internal.h" + +/****************************************************************************** + * * + * Function: get_value_internal * + * * + * Purpose: retrieve data from ZABBIX server (internally supported intems) * + * * + * Parameters: item - item we are interested in * + * * + * Return value: SUCCEED - data succesfully retrieved and stored in result * + * and result_str (as string) * + * NOTSUPPORTED - requested item is not supported * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int get_value_internal(DB_ITEM *item, AGENT_RESULT *result) +{ + zbx_uint64_t i; + char error[MAX_STRING_LEN]; + + init_result(result); + + if(strcmp(item->key,"zabbix[triggers]")==0) + { + i = (zbx_uint64_t)DBget_triggers_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[items]")==0) + { + i = (zbx_uint64_t)DBget_items_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[items_unsupported]")==0) + { + i=DBget_items_unsupported_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[history]")==0) + { + i=DBget_history_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[history_str]")==0) + { + i=DBget_history_str_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[trends]")==0) + { + i=DBget_trends_count(); + SET_UI64_RESULT(result, i); + } + else if(strcmp(item->key,"zabbix[queue]")==0) + { + i=DBget_queue_count(); + SET_UI64_RESULT(result, i); + } + else + { + zbx_snprintf(error,sizeof(error),"Internal check [%s] is not supported", + item->key); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + SET_STR_RESULT(result, strdup(error)); + return NOTSUPPORTED; + } + + return SUCCEED; +} diff --git a/src/zabbix_proxy/poller/checks_internal.h b/src/zabbix_proxy/poller/checks_internal.h new file mode 100644 index 00000000..da2bdf75 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_internal.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_INTERNAL_H +#define ZABBIX_CHECKS_INTERNAL_H + +#include "common.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" + +extern int get_value_internal(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/poller/checks_simple.c b/src/zabbix_proxy/poller/checks_simple.c new file mode 100644 index 00000000..bce26b2f --- /dev/null +++ b/src/zabbix_proxy/poller/checks_simple.c @@ -0,0 +1,221 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "checks_simple.h" + +int get_value_simple(DB_ITEM *item, AGENT_RESULT *result) +{ + char *t; + char c[MAX_STRING_LEN]; + char param[MAX_STRING_LEN]; + char error[MAX_STRING_LEN]; + char service[MAX_STRING_LEN]; + char service_sysinfo[MAX_STRING_LEN]; + char ip[MAX_STRING_LEN]; + char port[MAX_STRING_LEN]; + int port_int=0; + int ret = SUCCEED; + char *l,*r; + /* Assumption: host name does not contain '_perf' */ + + init_result(result); + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_simple([%s]", + item->key); + + if(0 == strncmp(item->key,"service.ntp",11)) + { + l=strchr(item->key,'['); + r=strrchr(item->key,']'); + if(l==NULL || r==NULL) + zbx_snprintf(c,sizeof(c),"net.tcp.service[%s]", + item->key); + else + { + zbx_strlcpy( param,l+1, r-l-1); + if(item->useip==1) + { + zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]", + item->key, + item->host_ip); + } + else + { + zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]", + item->key, + item->host_ip); + } + } + } + else if(0 == strncmp(item->key,"dns",3)) + { + if(item->useip==1) + { + l=strchr(item->key,'['); + r=strrchr(item->key,']'); + if(l==NULL || r==NULL) + zbx_snprintf(c,sizeof(c),"%s", + item->key); + else + { + zbx_strlcpy( param,l+1, r-l-1); +/* zbx_snprintf(c,sizeof(c),"dns[%s,%s]",item->ip,param);*/ + zbx_snprintf(c,sizeof(c),"dns[%s]", + param); + } + } + else + { + zbx_snprintf(error,sizeof(error),"You must use IP address in Host %s definition", + item->host_name); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + result->str=strdup(error); + return NOTSUPPORTED; + } + } + else + { + ip[0]=0; + port[0]=0; + service[0]=0; + if(num_param(item->key) == 1) + { + if(get_param(item->key, 1, service, MAX_STRING_LEN) != 0) + { + ret = NOTSUPPORTED; + } + } + else if(num_param(item->key) == 2) + { + if(get_param(item->key, 1, service, MAX_STRING_LEN) != 0) + { + ret = NOTSUPPORTED; + } + if(get_param(item->key, 2, port, MAX_STRING_LEN) != 0) + { + ret = NOTSUPPORTED; + } + else if(is_uint(port)==SUCCEED) + { + port_int=atoi(port); + } + else + { + zbx_snprintf(error,sizeof(error),"Port number must be numeric in [%s]", + item->key); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + result->str=strdup(error); + ret = NOTSUPPORTED; + } + } + else + { + zbx_snprintf(error,sizeof(error),"Too many parameters in [%s]", + item->key); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + result->str=strdup(error); + ret = NOTSUPPORTED; + } + + if(ret == SUCCEED) + { + if(item->useip==1) + { + strscpy(ip,item->host_ip); + } + else + { + strscpy(ip,item->host_dns); + } + + t = strstr(service,"_perf"); + if(t != NULL) + { + t[0]=0; + strscpy(service_sysinfo,"net.tcp.service.perf"); + } + else strscpy(service_sysinfo,"net.tcp.service"); + + if(port_int == 0) + { + zbx_snprintf(c,sizeof(c),"%s[%s,%s]", + service_sysinfo, + service, + ip); + } + else + { + zbx_snprintf(c,sizeof(c),"%s[%s,%s,%d]", + service_sysinfo, + service, + ip, + port_int); + } + zabbix_log( LOG_LEVEL_DEBUG, "Sysinfo [%s]", + c); + } + else + { + return ret; + } + } +/* + else if(NULL == strstr(item->key,"_perf")) + { + if(item->useip==1) + { + zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",item->key,item->ip); + } + else + { + zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",item->key,item->host); + } + } + else + { + strscpy(s,item->key); + t=strstr(s,"_perf"); + t[0]=0; + + if(item->useip==1) + { + zbx_snprintf(c,sizeof(c),"net.tcp.service.perf[%s,%s]",s,item->ip); + } + else + { + zbx_snprintf(c,sizeof(c),"net.tcp.service.perf[%s,%s]",s,item->host); + } + } +*/ + + if(process(c, 0, result) == NOTSUPPORTED) + { + zbx_snprintf(error,sizeof(error),"Simple check [%s] is not supported", + c); + zabbix_log( LOG_LEVEL_WARNING, "%s", + error); + result->str=strdup(error); + ret = NOTSUPPORTED; + } + + return ret; +} diff --git a/src/zabbix_proxy/poller/checks_simple.h b/src/zabbix_proxy/poller/checks_simple.h new file mode 100644 index 00000000..3b327214 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_simple.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_SIMPLE_H +#define ZABBIX_CHECKS_SIMPLE_H + +#include "common.h" +#include "db.h" +#include "log.h" +#include "sysinfo.h" + +extern int get_value_simple(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/poller/checks_snmp.c b/src/zabbix_proxy/poller/checks_snmp.c new file mode 100644 index 00000000..b289a1bc --- /dev/null +++ b/src/zabbix_proxy/poller/checks_snmp.c @@ -0,0 +1,493 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "checks_snmp.h" + +#ifdef HAVE_SNMP +int get_value_snmp(DB_ITEM *item, AGENT_RESULT *value) +{ + + #define NEW_APPROACH + + struct snmp_session session, *ss; + struct snmp_pdu *pdu; + struct snmp_pdu *response; + +#ifdef NEW_APPROACH + char temp[MAX_STRING_LEN]; +#endif + + oid anOID[MAX_OID_LEN]; + size_t anOID_len = MAX_OID_LEN; + + struct variable_list *vars; + int status; + + char *p, *c; + + unsigned char *ip; + + char error[MAX_STRING_LEN]; + + int ret=SUCCEED; + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP()"); + + init_result(value); + +/* assert((item->type == ITEM_TYPE_SNMPv1)||(item->type == ITEM_TYPE_SNMPv2c)); */ + assert((item->type == ITEM_TYPE_SNMPv1)||(item->type == ITEM_TYPE_SNMPv2c)||(item->type == ITEM_TYPE_SNMPv3)); + + snmp_sess_init( &session ); +/* session.version = version;*/ + if(item->type == ITEM_TYPE_SNMPv1) + { + session.version = SNMP_VERSION_1; + } + else if(item->type == ITEM_TYPE_SNMPv2c) + { + session.version = SNMP_VERSION_2c; + } + else if(item->type == ITEM_TYPE_SNMPv3) + { + session.version = SNMP_VERSION_3; + } + else + { + zbx_snprintf(error,sizeof(error),"Error in get_value_SNMP. Wrong item type [%d]. Must be SNMP.", + item->type); + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + + + if(item->useip == 1) + { + #ifdef NEW_APPROACH + zbx_snprintf(temp,sizeof(temp),"%s:%d", + item->host_ip, + item->snmp_port); + session.peername = temp; + session.remote_port = item->snmp_port; + #else + session.peername = item->host_ip; + session.remote_port = item->snmp_port; + #endif + } + else + { + #ifdef NEW_APPROACH + zbx_snprintf(temp, sizeof(temp), "%s:%d", + item->host_dns, + item->snmp_port); + session.peername = temp; + session.remote_port = item->snmp_port; + #else + session.peername = item->host_dns; + session.remote_port = item->snmp_port; + #endif + } + + if( (session.version == SNMP_VERSION_1) || (item->type == ITEM_TYPE_SNMPv2c)) + { + session.community = (u_char *)item->snmp_community; + session.community_len = strlen((void *)session.community); + zabbix_log( LOG_LEVEL_DEBUG, "SNMP [%s@%s:%d]", + session.community, + session.peername, + session.remote_port); + } + else if(session.version == SNMP_VERSION_3) + { + /* set the SNMPv3 user name */ + session.securityName = item->snmpv3_securityname; + session.securityNameLen = strlen(session.securityName); + + /* set the security level to authenticated, but not encrypted */ + + if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV) + { + session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; + } + else if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV) + { + session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; + + /* set the authentication method to MD5 */ + session.securityAuthProto = usmHMACMD5AuthProtocol; + session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; + session.securityAuthKeyLen = USM_AUTH_KU_LEN; + + if (generate_Ku(session.securityAuthProto, + session.securityAuthProtoLen, + (u_char *) item->snmpv3_authpassphrase, strlen(item->snmpv3_authpassphrase), + session.securityAuthKey, + &session.securityAuthKeyLen) != SNMPERR_SUCCESS) + { + zbx_snprintf(error,sizeof(error),"Error generating Ku from authentication pass phrase."); + + zabbix_log( LOG_LEVEL_ERR, "%s", error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + } + else if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV) + { + session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; + + /* set the authentication method to MD5 */ + session.securityAuthProto = usmHMACMD5AuthProtocol; + session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; + session.securityAuthKeyLen = USM_AUTH_KU_LEN; + + if (generate_Ku(session.securityAuthProto, + session.securityAuthProtoLen, + (u_char *) item->snmpv3_authpassphrase, strlen(item->snmpv3_authpassphrase), + session.securityAuthKey, + &session.securityAuthKeyLen) != SNMPERR_SUCCESS) + { + zbx_snprintf(error,sizeof(error),"Error generating Ku from authentication pass phrase."); + + zabbix_log( LOG_LEVEL_ERR, "%s", error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + + /* set the private method to DES */ + session.securityPrivProto = usmDESPrivProtocol; + session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN; + session.securityPrivKeyLen = USM_PRIV_KU_LEN; + + if (generate_Ku(session.securityAuthProto, + session.securityAuthProtoLen, + (u_char *) item->snmpv3_privpassphrase, strlen(item->snmpv3_privpassphrase), + session.securityPrivKey, + &session.securityPrivKeyLen) != SNMPERR_SUCCESS) + { + zbx_snprintf(error,sizeof(error),"Error generating Ku from priv pass phrase."); + + zabbix_log( LOG_LEVEL_ERR, "%s", error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + } + zabbix_log( LOG_LEVEL_DEBUG, "SNMPv3 [%s@%s:%d]", + session.securityName, + session.peername, + session.remote_port); + } + else + { + zbx_snprintf(error,sizeof(error),"Error in get_value_SNMP. Unsupported session.version [%d]", + (int)session.version); + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + + zabbix_log( LOG_LEVEL_DEBUG, "OID [%s]", + item->snmp_oid); + + SOCK_STARTUP; + ss = snmp_open(&session); + + if(ss == NULL) + { + SOCK_CLEANUP; + + zbx_snprintf(error,sizeof(error),"Error doing snmp_open()"); + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + return NOTSUPPORTED; + } + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.2"); + + pdu = snmp_pdu_create(SNMP_MSG_GET); +/* Changed to snmp_parse_oid */ +/* read_objid(item->snmp_oid, anOID, &anOID_len);*/ + snmp_parse_oid(item->snmp_oid, anOID, &anOID_len); + +#if OTHER_METHODS + get_node("sysDescr.0", anOID, &anOID_len); + read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len); + read_objid("system.sysDescr.0", anOID, &anOID_len); +#endif + + snmp_add_null_var(pdu, anOID, anOID_len); + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.3"); + + status = snmp_synch_response(ss, pdu, &response); + zabbix_log( LOG_LEVEL_DEBUG, "Status send [%d]", status); + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.4"); + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 1"); + + if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) + { + + zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 2"); +/* for(vars = response->variables; vars; vars = vars->next_variable) + { + print_variable(vars->name, vars->name_length, vars); + }*/ + + for(vars = response->variables; vars; vars = vars->next_variable) + { + int count=1; + zabbix_log( LOG_LEVEL_DEBUG, "AV loop(%d)", vars->type); + +/* if( (vars->type == ASN_INTEGER) ||*/ + if( (vars->type == ASN_UINTEGER)|| + (vars->type == ASN_COUNTER) || +#ifdef OPAQUE_SPECIAL_TYPES + (vars->type == ASN_UNSIGNED64) || +#endif + (vars->type == ASN_TIMETICKS) || + (vars->type == ASN_GAUGE) + ) + { +/* *result=(long)*vars->val.integer;*/ + /* + * This solves situation when large numbers are stored as negative values + * http://sourceforge.net/tracker/index.php?func=detail&aid=700145&group_id=23494&atid=378683 + */ + /*zbx_snprintf(result_str,sizeof(result_str),"%ld",(long)*vars->val.integer);*/ +/* zbx_snprintf(result_str,sizeof(result_str),"%lu",(long)*vars->val.integer);*/ + + /* Not correct. Returns huge values. */ +/* SET_UI64_RESULT(value, (zbx_uint64_t)*vars->val.integer);*/ + SET_UI64_RESULT(value, (unsigned long)*vars->val.integer); + zabbix_log( LOG_LEVEL_DEBUG, "OID [%s] Type [%d] UI64[" ZBX_FS_UI64 "]", + item->snmp_oid, + vars->type, + (zbx_uint64_t)*vars->val.integer); + zabbix_log( LOG_LEVEL_DEBUG, "OID [%s] Type [%d] ULONG[%lu]", + item->snmp_oid, + vars->type, + (zbx_uint64_t)(unsigned long)*vars->val.integer); + } + else if(vars->type == ASN_COUNTER64) + { + /* Incorrect code for 32 bit platforms */ +/* SET_UI64_RESULT(value, ((vars->val.counter64->high)<<32)+(vars->val.counter64->low));*/ + SET_UI64_RESULT(value, (((zbx_uint64_t)vars->val.counter64->high)<<32)+((zbx_uint64_t)vars->val.counter64->low)); + } + else if(vars->type == ASN_INTEGER +#define ASN_FLOAT (ASN_APPLICATION | 8) +#define ASN_DOUBLE (ASN_APPLICATION | 9) + +#ifdef OPAQUE_SPECIAL_TYPES + || (vars->type == ASN_INTEGER64) +#endif + ) + { + /* Negative integer values are converted to double */ + if(*vars->val.integer<0) + { + SET_DBL_RESULT(value, (double)*vars->val.integer); + } + else + { + SET_UI64_RESULT(value, (zbx_uint64_t)*vars->val.integer); + } + } +#ifdef OPAQUE_SPECIAL_TYPES + else if(vars->type == ASN_FLOAT) + { + SET_DBL_RESULT(value, *vars->val.floatVal); + } + else if(vars->type == ASN_DOUBLE) + { + SET_DBL_RESULT(value, *vars->val.doubleVal); + } +#endif + else if(vars->type == ASN_OCTET_STR) + { + if(item->value_type == ITEM_VALUE_TYPE_FLOAT) + { + SET_DBL_RESULT(value, strtod((char*)vars->val.string,0)); + } + else if(item->value_type != ITEM_VALUE_TYPE_STR) + { + zbx_snprintf(error,sizeof(error),"Cannot store SNMP string value (ASN_OCTET_STR) in item having numeric type"); + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret = NOTSUPPORTED; + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%s]", vars->val.string); + zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%d]", vars->val_len); + + p = malloc(1024); + if(p) + { + memset(p,0,1024); + snprint_value(p, 1023, vars->name, vars->name_length, vars); + /* Skip STRING: and STRING_HEX: */ + c=strchr(p,':'); + if(c==NULL) + { + SET_STR_RESULT(value, strdup(p)); + } + else + { + SET_STR_RESULT(value, strdup(c+1)); + } + zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%s]", p); + free(p); + } + else + { + zbx_snprintf(error,MAX_STRING_LEN-1,"Cannot allocate required memory"); + zabbix_log( LOG_LEVEL_ERR, "%s", error); + SET_MSG_RESULT(value, strdup(error)); + } + +/* p = malloc(vars->val_len+1); + if(p) + { + zabbix_log( LOG_LEVEL_WARNING, "Result [%s] len [%d]",vars->val.string,vars->val_len); + memcpy(p, vars->val.string, vars->val_len); + p[vars->val_len] = '\0'; + + SET_STR_RESULT(value, p); + } + else + { + zbx_snprintf(error,sizeof(error),"Cannot allocate required memory"); + zabbix_log( LOG_LEVEL_ERR, "%s", error); + SET_MSG_RESULT(value, strdup(error)); + }*/ + } + } + else if(vars->type == ASN_IPADDRESS) + { + if(item->value_type != ITEM_VALUE_TYPE_STR) + { + zbx_snprintf(error,sizeof(error),"Cannot store SNMP string value (ASN_IPADDRESS) in item having numeric type"); + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + ret = NOTSUPPORTED; + } + else + { + ip = vars->val.string; + SET_STR_RESULT(value, zbx_dsprintf(NULL, "%d.%d.%d.%d", + ip[0], + ip[1], + ip[2], + ip[3])); + } + } + else + { +/* count is not really used. Has to be removed */ + count++; + + zbx_snprintf(error,sizeof(error),"OID [%s] value #%d has unknow type [%X]", + item->snmp_oid, + count, + vars->type); + + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret = NOTSUPPORTED; + } + } + } + else + { + if (status == STAT_SUCCESS) + { + zabbix_log( LOG_LEVEL_WARNING, "SNMP error in packet. Reason: %s\n", + snmp_errstring(response->errstat)); + if(response->errstat == SNMP_ERR_NOSUCHNAME) + { + zbx_snprintf(error,sizeof(error),"SNMP error [%s]", + snmp_errstring(response->errstat)); + + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret=NOTSUPPORTED; + } + else + { + zbx_snprintf(error,sizeof(error),"SNMP error [%s]", + snmp_errstring(response->errstat)); + + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret=NOTSUPPORTED; + } + } + else if(status == STAT_TIMEOUT) + { + zbx_snprintf(error,sizeof(error),"Timeout while connecting to [%s]", + session.peername); + +/* snmp_sess_perror("snmpget", ss);*/ + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret = NETWORK_ERROR; + } + else + { + zbx_snprintf(error,sizeof(error),"SNMP error [%d]", + status); + + zabbix_log( LOG_LEVEL_ERR, "%s", + error); + SET_MSG_RESULT(value, strdup(error)); + + ret=NOTSUPPORTED; + } + } + + if (response) + { + snmp_free_pdu(response); + } + snmp_close(ss); + + SOCK_CLEANUP; + return ret; +} +#endif diff --git a/src/zabbix_proxy/poller/checks_snmp.h b/src/zabbix_proxy/poller/checks_snmp.h new file mode 100644 index 00000000..c574c874 --- /dev/null +++ b/src/zabbix_proxy/poller/checks_snmp.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_CHECKS_SNMP_H +#define ZABBIX_CHECKS_SNMP_H + +#include "common.h" +#include "log.h" +#include "db.h" +#include "sysinfo.h" + +int get_value_snmp(DB_ITEM *item, AGENT_RESULT *value); + +#endif diff --git a/src/zabbix_proxy/poller/poller.c b/src/zabbix_proxy/poller/poller.c new file mode 100644 index 00000000..8435d15e --- /dev/null +++ b/src/zabbix_proxy/poller/poller.c @@ -0,0 +1,579 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "zlog.h" + +#include "../functions.h" +#include "../expression.h" +#include "poller.h" + +#include "db.h" +#include "sysinfo.h" + +#include "checks_agent.h" +#include "checks_aggregate.h" +#include "checks_external.h" +#include "checks_internal.h" +#include "checks_simple.h" +#include "checks_snmp.h" +#include "checks_db.h" + +#include "daemon.h" + +AGENT_RESULT result; + +int poller_type; +int poller_num; + +int get_value(DB_ITEM *item, AGENT_RESULT *result) +{ + int res=FAIL; + + struct sigaction phan; + + zabbix_log(LOG_LEVEL_DEBUG, "In get_value(key:%s)", + item->key); + + phan.sa_handler = &child_signal_handler; + sigemptyset(&phan.sa_mask); + phan.sa_flags = 0; + sigaction(SIGALRM, &phan, NULL); + + alarm(CONFIG_TIMEOUT); + + if(item->type == ITEM_TYPE_ZABBIX) + { + res=get_value_agent(item, result); + } + else if( (item->type == ITEM_TYPE_SNMPv1) || (item->type == ITEM_TYPE_SNMPv2c) || (item->type == ITEM_TYPE_SNMPv3)) + { +#ifdef HAVE_SNMP + res=get_value_snmp(item, result); +#else + zabbix_log(LOG_LEVEL_WARNING, "Support of SNMP parameters was not compiled in"); + zabbix_syslog("Support of SNMP parameters was not compiled in. Cannot process [%s:%s]", + item->host_name, + item->key); + res=NOTSUPPORTED; +#endif + } + else if(item->type == ITEM_TYPE_SIMPLE) + { + res=get_value_simple(item, result); + } + else if(item->type == ITEM_TYPE_INTERNAL) + { + res=get_value_internal(item, result); + } + else if(item->type == ITEM_TYPE_DB_MONITOR) + { + res=get_value_db(item, result); + } + else if(item->type == ITEM_TYPE_AGGREGATE) + { + res=get_value_aggregate(item, result); + } + else if(item->type == ITEM_TYPE_EXTERNAL) + { + res=get_value_external(item, result); + } + else + { + zabbix_log(LOG_LEVEL_WARNING, "Not supported item type:%d", + item->type); + zabbix_syslog("Not supported item type:%d", + item->type); + res=NOTSUPPORTED; + } + alarm(0); + + zabbix_log(LOG_LEVEL_DEBUG, "End get_value()"); + return res; +} + +static int get_minnextcheck(int now) +{ + DB_RESULT result; + DB_ROW row; + + int res; + +/* Host status 0 == MONITORED + 1 == NOT MONITORED + 2 == UNREACHABLE */ + if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE) + { + result = DBselect("select count(*),min(nextcheck) as nextcheck from items i,hosts h where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from!=0 and h.hostid=i.hostid and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID "order by nextcheck", + CONFIG_UNREACHABLE_POLLER_FORKS, + poller_num-1, + now, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + HOST_STATUS_MONITORED, + now, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + else + { + if(CONFIG_REFRESH_UNSUPPORTED != 0) + { + result = DBselect("select count(*),min(nextcheck) from items i,hosts h where h.status=%d and h.disable_until<%d and h.errors_from=0 and h.hostid=i.hostid and i.status in (%d,%d) and i.type not in (%d,%d,%d) and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and" ZBX_COND_NODEID, + HOST_STATUS_MONITORED, + now, + ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + CONFIG_POLLER_FORKS, + poller_num-1, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + else + { + result = DBselect("select count(*),min(nextcheck) from items i,hosts h where h.status=%d and h.disable_until<%d and h.errors_from=0 and h.hostid=i.hostid and i.status in (%d) and i.type not in (%d,%d,%d) and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and" ZBX_COND_NODEID, + HOST_STATUS_MONITORED, + now, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + CONFIG_POLLER_FORKS, + poller_num-1, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + } + + row=DBfetch(result); + + if(!row || DBis_null(row[0])==SUCCEED || DBis_null(row[1])==SUCCEED) + { + zabbix_log(LOG_LEVEL_DEBUG, "No items to update for minnextcheck."); + res = FAIL; + } + else + { + if( atoi(row[0]) == 0) + { + res = FAIL; + } + else + { + res = atoi(row[1]); + } + } + DBfree_result(result); + + return res; +} + +/* Update special host's item - "status" */ +static void update_key_status(zbx_uint64_t hostid,int host_status) +{ +/* char value_str[MAX_STRING_LEN];*/ + AGENT_RESULT agent; + + DB_ITEM item; + DB_RESULT result; + DB_ROW row; + + int update; + + zabbix_log(LOG_LEVEL_DEBUG, "In update_key_status(" ZBX_FS_UI64 ",%d)", + hostid, + host_status); + + result = DBselect("select %s where h.hostid=i.hostid and h.hostid=" ZBX_FS_UI64 " and i.key_='%s'", + ZBX_SQL_ITEM_SELECT, + hostid, + SERVER_STATUS_KEY); + + row = DBfetch(result); + + if(row) + { + DBget_item_from_db(&item,row); + +/* Do not process new value for status, if previous status is the same */ + update = (item.lastvalue_null==1); + update = update || ((item.value_type == ITEM_VALUE_TYPE_FLOAT) &&(cmp_double(item.lastvalue_dbl, (double)host_status) == 1)); + update = update || ((item.value_type == ITEM_VALUE_TYPE_UINT64) &&(item.lastvalue_uint64 != host_status)); + + if(update) + { + init_result(&agent); + SET_UI64_RESULT(&agent, host_status); + process_new_value(&item,&agent); + free_result(&agent); + + update_triggers(item.itemid); + } + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "No items to update."); + } + + DBfree_result(result); +} + +/****************************************************************************** + * * + * Function: get_values * + * * + * Purpose: retrieve values of metrics from monitored hosts * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: always SUCCEED * + * * + ******************************************************************************/ +int get_values(void) +{ + DB_RESULT result; + DB_RESULT result2; + DB_ROW row; + DB_ROW row2; + + int now; + int delay; + int res; + DB_ITEM item; + AGENT_RESULT agent; + int stop=0; + + char *unreachable_hosts = NULL; + char tmp[MAX_STRING_LEN]; + + zabbix_log( LOG_LEVEL_DEBUG, "In get_values()"); + + now = time(NULL); + + zbx_snprintf(tmp,sizeof(tmp)-1,ZBX_FS_UI64,0); + unreachable_hosts=zbx_strdcat(unreachable_hosts,tmp); + + /* Poller for unreachable hosts */ + if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE) + { + result = DBselect("select h.hostid,min(i.itemid) from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from!=0 and h.hostid=i.hostid and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " group by h.hostid", + CONFIG_UNREACHABLE_POLLER_FORKS, + poller_num-1, + now, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + HOST_STATUS_MONITORED, + now, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + else + { + if(CONFIG_REFRESH_UNSUPPORTED != 0) + { + result = DBselect("select %s where i.nextcheck<=%d and i.status in (%d,%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from=0 and h.hostid=i.hostid and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " order by i.nextcheck", + ZBX_SQL_ITEM_SELECT, + now, + ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + HOST_STATUS_MONITORED, + now, + CONFIG_POLLER_FORKS, + poller_num-1, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + else + { + result = DBselect("select %s where i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from=0 and h.hostid=i.hostid and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " order by i.nextcheck", + ZBX_SQL_ITEM_SELECT, + now, + ITEM_STATUS_ACTIVE, + ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST, + HOST_STATUS_MONITORED, + now, + CONFIG_POLLER_FORKS, + poller_num-1, + SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY, + LOCAL_NODE("h.hostid")); + } + } + + /* Do not stop when select is made by poller for unreachable hosts */ + while((row=DBfetch(result))&&(stop==0 || poller_type == ZBX_POLLER_TYPE_UNREACHABLE)) + { + /* This code is just to avoid compilation warining about use of uninitialized result2 */ + result2 = result; + /* */ + + /* Poller for unreachable hosts */ + if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE) + { + result2 = DBselect("select %s where h.hostid=i.hostid and i.itemid=%s and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + row[1], + LOCAL_NODE("h.hostid")); + + row2 = DBfetch(result2); + + if(!row2) + { + DBfree_result(result2); + continue; + } + DBget_item_from_db(&item,row2); + } + else + { + DBget_item_from_db(&item,row); + /* Skip unreachable hosts but do not break the loop. */ + if(uint64_in_list(unreachable_hosts,item.hostid) == SUCCEED) + { + zabbix_log( LOG_LEVEL_DEBUG, "Host " ZBX_FS_UI64 " is unreachable. Skipping [%s]", + item.hostid,item.key); + continue; + } + } + + init_result(&agent); + res = get_value(&item, &agent); + + DBbegin(); + + if(res == SUCCEED ) + { + + process_new_value(&item,&agent); + + if(HOST_AVAILABLE_TRUE != item.host_available) + { + zabbix_log( LOG_LEVEL_WARNING, "Enabling host [%s]", + item.host_name); + zabbix_syslog("Enabling host [%s]", + item.host_name); + + now = time(NULL); + DBupdate_host_availability(item.hostid,HOST_AVAILABLE_TRUE,now,agent.msg); + + update_key_status(item.hostid, HOST_STATUS_MONITORED); /* 0 */ + item.host_available=HOST_AVAILABLE_TRUE; + + stop=1; + } + if(item.host_errors_from!=0) + { + DBexecute("update hosts set errors_from=0 where hostid=" ZBX_FS_UI64, + item.hostid); + + stop=1; + } + update_triggers(item.itemid); + } + else if(res == NOTSUPPORTED || res == AGENT_ERROR) + { + now = time(NULL); + if(item.status == ITEM_STATUS_NOTSUPPORTED) + { + /* It is not correct */ +/* snprintf(sql,sizeof(sql)-1,"update items set nextcheck=%d, lastclock=%d where itemid=%d",calculate_item_nextcheck(item.itemid, CONFIG_REFRESH_UNSUPPORTED,now), now, item.itemid);*/ + DBexecute("update items set nextcheck=%d, lastclock=%d where itemid=" ZBX_FS_UI64, + CONFIG_REFRESH_UNSUPPORTED+now, + now, + item.itemid); + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] is not supported by agent on host [%s] Old status [%d]", + item.key, + item.host_name, + item.status); + zabbix_syslog("Parameter [%s] is not supported by agent on host [%s]", + item.key, + item.host_name); + DBupdate_item_status_to_notsupported(item.itemid, agent.msg); + /* if(HOST_STATUS_UNREACHABLE == item.host_status)*/ + if(HOST_AVAILABLE_TRUE != item.host_available) + { + zabbix_log( LOG_LEVEL_WARNING, "Enabling host [%s]", + item.host_name); + zabbix_syslog("Enabling host [%s]", + item.host_name); + DBupdate_host_availability(item.hostid,HOST_AVAILABLE_TRUE,now,agent.msg); + update_key_status(item.hostid, HOST_STATUS_MONITORED); /* 0 */ + item.host_available=HOST_AVAILABLE_TRUE; + + stop=1; + } + } + } + else if(res == NETWORK_ERROR) + { + now = time(NULL); + + /* First error */ + if(item.host_errors_from==0) + { + zabbix_log( LOG_LEVEL_WARNING, "Host [%s]: first network error, wait for %d seconds", + item.host_name, + CONFIG_UNREACHABLE_DELAY); + zabbix_syslog("Host [%s]: first network error, wait for %d seconds", + item.host_name, + CONFIG_UNREACHABLE_DELAY); + + item.host_errors_from=now; + DBexecute("update hosts set errors_from=%d,disable_until=%d where hostid=" ZBX_FS_UI64, + now, + now+CONFIG_UNREACHABLE_DELAY, + item.hostid); + + delay = MIN(4*item.delay, 300); + zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] will be checked after %d seconds on host [%s]", + item.key, + delay, + item.host_name); + DBexecute("update items set nextcheck=%d where itemid=" ZBX_FS_UI64, + now + delay, + item.itemid); + } + else + { + if(now-item.host_errors_from>CONFIG_UNREACHABLE_PERIOD) + { + zabbix_log( LOG_LEVEL_WARNING, "Host [%s] will be checked after %d seconds", + item.host_name, + CONFIG_UNAVAILABLE_DELAY); + zabbix_syslog("Host [%s] will be checked after %d seconds", + item.host_name, + CONFIG_UNAVAILABLE_DELAY); + + DBupdate_host_availability(item.hostid,HOST_AVAILABLE_FALSE,now,agent.msg); + update_key_status(item.hostid,HOST_AVAILABLE_FALSE); /* 2 */ + item.host_available=HOST_AVAILABLE_FALSE; + + DBexecute("update hosts set disable_until=%d where hostid=" ZBX_FS_UI64, + now+CONFIG_UNAVAILABLE_DELAY, + item.hostid); + } + /* Still unavailable, but won't change status to UNAVAILABLE yet */ + else + { + zabbix_log( LOG_LEVEL_WARNING, "Host [%s]: another network error, wait for %d seconds", + item.host_name, + CONFIG_UNREACHABLE_DELAY); + zabbix_syslog("Host [%s]: another network error, wait for %d seconds", + item.host_name, + CONFIG_UNREACHABLE_DELAY); + + DBexecute("update hosts set disable_until=%d where hostid=" ZBX_FS_UI64, + now+CONFIG_UNREACHABLE_DELAY, + item.hostid); + } + } + + zbx_snprintf(tmp,sizeof(tmp)-1,"," ZBX_FS_UI64,item.hostid); + unreachable_hosts=zbx_strdcat(unreachable_hosts,tmp); + +/* stop=1;*/ + } + else + { + zabbix_log( LOG_LEVEL_CRIT, "Unknown response code returned."); + assert(0==1); + } + /* Poller for unreachable hosts */ + if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE) + { + /* We cannot freeit earlier because items has references to the structure */ + DBfree_result(result2); + } + free_result(&agent); + DBcommit(); + } + + zbx_free(unreachable_hosts); + + DBfree_result(result); + zabbix_log( LOG_LEVEL_DEBUG, "End get_values()"); + return SUCCEED; +} + +void main_poller_loop(int type, int num) +{ + int now; + int nextcheck,sleeptime; + + zabbix_log( LOG_LEVEL_DEBUG, "In main_poller_loop(type:%d,num:%d)", + type, + num); + + poller_type = type; + poller_num = num; + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + for(;;) + { + zbx_setproctitle("poller [getting values]"); + + now=time(NULL); + get_values(); + + zabbix_log( LOG_LEVEL_DEBUG, "Spent %d seconds while updating values", + (int)time(NULL)-now ); + + nextcheck=get_minnextcheck(now); + zabbix_log( LOG_LEVEL_DEBUG, "Nextcheck:%d Time:%d", + nextcheck, + (int)time(NULL) ); + + if( FAIL == nextcheck) + { + sleeptime=POLLER_DELAY; + } + else + { + sleeptime=nextcheck-time(NULL); + if(sleeptime<0) + { + sleeptime=0; + } + } + if(sleeptime>0) + { + if(sleeptime > POLLER_DELAY) + { + sleeptime = POLLER_DELAY; + } + zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d seconds", + sleeptime ); + + zbx_setproctitle("poller [sleeping for %d seconds]", + sleeptime); + + sleep( sleeptime ); + } + else + { + zabbix_log( LOG_LEVEL_DEBUG, "No sleeping" ); + } + } +} diff --git a/src/zabbix_proxy/poller/poller.h b/src/zabbix_proxy/poller/poller.h new file mode 100644 index 00000000..6f08111c --- /dev/null +++ b/src/zabbix_proxy/poller/poller.h @@ -0,0 +1,40 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_POLLER_H +#define ZABBIX_POLLER_H + +extern void signal_handler(int); +extern int server_num; + +extern int CONFIG_TIMEOUT; +extern int CONFIG_POLLER_FORKS; +extern int CONFIG_UNREACHABLE_POLLER_FORKS; +extern int CONFIG_UNAVAILABLE_DELAY; +extern int CONFIG_UNREACHABLE_PERIOD; +extern int CONFIG_UNREACHABLE_DELAY; + +void main_poller_loop(int type, int num); + +#include "db.h" +#include "sysinfo.h" + +int get_value(DB_ITEM *item, AGENT_RESULT *result); + +#endif diff --git a/src/zabbix_proxy/proxy.c b/src/zabbix_proxy/proxy.c new file mode 100644 index 00000000..7c69860a --- /dev/null +++ b/src/zabbix_proxy/proxy.c @@ -0,0 +1,569 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "pid.h" +#include "db.h" +#include "dbcache.h" +#include "log.h" +#include "zlog.h" +#include "zbxgetopt.h" +#include "mutexs.h" + +#include "functions.h" +#include "expression.h" +#include "sysinfo.h" + +#include "daemon.h" + +#include "dbsyncer/dbsyncer.h" +#include "discoverer/discoverer.h" +#include "httppoller/httppoller.h" +#include "housekeeper/housekeeper.h" +#include "pinger/pinger.h" +#include "poller/poller.h" +#include "poller/checks_snmp.h" +#include "trapper/trapper.h" +#include "nodewatcher/nodewatcher.h" + +/* +#define LISTENQ 1024 +*/ +char *progname = NULL; +char title_message[] = "ZABBIX Proxy (daemon)"; +char usage_message[] = "[-hV] [-c <file>]"; + +#ifndef HAVE_GETOPT_LONG +char *help_message[] = { + "Options:", + " -c <file> Specify configuration file", + " -h give this help", + " -V display version number", + 0 /* end of text */ +}; +#else +char *help_message[] = { + "Options:", + " -c --config <file> Specify configuration file", + " -h --help give this help", + " -V --version display version number", + 0 /* end of text */ +}; +#endif + +/* COMMAND LINE OPTIONS */ + +/* long options */ + +static struct zbx_option longopts[] = +{ + {"config", 1, 0, 'c'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'V'}, + +#if defined (_WINDOWS) + + {"install", 0, 0, 'i'}, + {"uninstall", 0, 0, 'd'}, + + {"start", 0, 0, 's'}, + {"stop", 0, 0, 'x'}, + +#endif /* _WINDOWS */ + + {0,0,0,0} +}; + +/* short options */ + +static char shortopts[] = + "c:n:hV" +#if defined (_WINDOWS) + "idsx" +#endif /* _WINDOWS */ + ; + +/* end of COMMAND LINE OPTIONS*/ + +pid_t *threads=NULL; + +int CONFIG_DBSYNCER_FORKS = 0;//1; +int CONFIG_DISCOVERER_FORKS = 1; +int CONFIG_HOUSEKEEPER_FORKS = 1; +int CONFIG_NODEWATCHER_FORKS = 1; +int CONFIG_PINGER_FORKS = 1; +int CONFIG_POLLER_FORKS = 5; +int CONFIG_HTTPPOLLER_FORKS = 5; +int CONFIG_TRAPPERD_FORKS = 5; +int CONFIG_UNREACHABLE_POLLER_FORKS = 1; + +int CONFIG_LISTEN_PORT = 10051; +char *CONFIG_LISTEN_IP = NULL; +int CONFIG_TRAPPER_TIMEOUT = TRAPPER_TIMEOUT; +/**/ +/*int CONFIG_NOTIMEWAIT =0;*/ +int CONFIG_HOUSEKEEPING_FREQUENCY = 1; +int CONFIG_SENDER_FREQUENCY = 30; +int CONFIG_DBSYNCER_FREQUENCY = 5; +int CONFIG_PINGER_FREQUENCY = 60; +/*int CONFIG_DISABLE_PINGER = 0;*/ +int CONFIG_DISABLE_HOUSEKEEPING = 0; +int CONFIG_UNREACHABLE_PERIOD = 45; +int CONFIG_UNREACHABLE_DELAY = 15; +int CONFIG_UNAVAILABLE_DELAY = 60; +int CONFIG_LOG_LEVEL = LOG_LEVEL_WARNING; +char *CONFIG_ALERT_SCRIPTS_PATH = NULL; +char *CONFIG_EXTERNALSCRIPTS = NULL; +char *CONFIG_FPING_LOCATION = NULL; +char *CONFIG_DBHOST = NULL; +char *CONFIG_DBNAME = NULL; +char *CONFIG_DBUSER = NULL; +char *CONFIG_DBPASSWORD = NULL; +char *CONFIG_DBSOCKET = NULL; +int CONFIG_DBPORT = 0; +int CONFIG_ENABLE_REMOTE_COMMANDS = 0; + +int CONFIG_NODEID = 0; +int CONFIG_MASTER_NODEID = 0; +int CONFIG_NODE_NOEVENTS = 0; +int CONFIG_NODE_NOHISTORY = 0; + +/* Global variable to control if we should write warnings to log[] */ +int CONFIG_ENABLE_LOG = 1; + +/* From table config */ +int CONFIG_REFRESH_UNSUPPORTED = 0; + +/* Zabbix server sturtup time */ +int CONFIG_SERVER_STARTUP_TIME = 0; + +/* Mutex for node syncs */ +ZBX_MUTEX node_sync_access; + +/****************************************************************************** + * * + * Function: init_config * + * * + * Purpose: parse config file and update configuration parameters * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: will terminate process if parsing fails * + * * + ******************************************************************************/ +void init_config(void) +{ + static struct cfg_line cfg[]= + { +/* PARAMETER ,VAR ,FUNC, TYPE(0i,1s),MANDATORY,MIN,MAX */ +/* {"StartDBSyncers",&CONFIG_DBSYNCER_FORKS,0,TYPE_INT,PARM_OPT,0,1},*/ + {"StartDiscoverers",&CONFIG_DISCOVERER_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"StartHTTPPollers",&CONFIG_HTTPPOLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"StartPingers",&CONFIG_PINGER_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"StartPollers",&CONFIG_POLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"StartPollersUnreachable",&CONFIG_UNREACHABLE_POLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"StartTrappers",&CONFIG_TRAPPERD_FORKS,0,TYPE_INT,PARM_OPT,0,255}, + {"HousekeepingFrequency",&CONFIG_HOUSEKEEPING_FREQUENCY,0,TYPE_INT,PARM_OPT,1,24}, + {"SenderFrequency",&CONFIG_SENDER_FREQUENCY,0,TYPE_INT,PARM_OPT,5,3600}, + {"PingerFrequency",&CONFIG_PINGER_FREQUENCY,0,TYPE_INT,PARM_OPT,1,3600}, + {"FpingLocation",&CONFIG_FPING_LOCATION,0,TYPE_STRING,PARM_OPT,0,0}, + {"Timeout",&CONFIG_TIMEOUT,0,TYPE_INT,PARM_OPT,1,30}, + {"TrapperTimeout",&CONFIG_TRAPPER_TIMEOUT,0,TYPE_INT,PARM_OPT,1,30}, + {"UnreachablePeriod",&CONFIG_UNREACHABLE_PERIOD,0,TYPE_INT,PARM_OPT,1,3600}, + {"UnreachableDelay",&CONFIG_UNREACHABLE_DELAY,0,TYPE_INT,PARM_OPT,1,3600}, + {"UnavailableDelay",&CONFIG_UNAVAILABLE_DELAY,0,TYPE_INT,PARM_OPT,1,3600}, + {"ListenIP",&CONFIG_LISTEN_IP,0,TYPE_STRING,PARM_OPT,0,0}, + {"ListenPort",&CONFIG_LISTEN_PORT,0,TYPE_INT,PARM_OPT,1024,32768}, +/* {"NoTimeWait",&CONFIG_NOTIMEWAIT,0,TYPE_INT,PARM_OPT,0,1},*/ +/* {"DisablePinger",&CONFIG_DISABLE_PINGER,0,TYPE_INT,PARM_OPT,0,1},*/ + {"DisableHousekeeping",&CONFIG_DISABLE_HOUSEKEEPING,0,TYPE_INT,PARM_OPT,0,1}, + {"DebugLevel",&CONFIG_LOG_LEVEL,0,TYPE_INT,PARM_OPT,0,4}, + {"PidFile",&APP_PID_FILE,0,TYPE_STRING,PARM_OPT,0,0}, + {"LogFile",&CONFIG_LOG_FILE,0,TYPE_STRING,PARM_OPT,0,0}, + {"LogFileSize",&CONFIG_LOG_FILE_SIZE,0,TYPE_INT,PARM_OPT,0,1024}, + {"AlertScriptsPath",&CONFIG_ALERT_SCRIPTS_PATH,0,TYPE_STRING,PARM_OPT,0,0}, + {"ExternalScripts",&CONFIG_EXTERNALSCRIPTS,0,TYPE_STRING,PARM_OPT,0,0}, + {"DBHost",&CONFIG_DBHOST,0,TYPE_STRING,PARM_OPT,0,0}, + {"DBName",&CONFIG_DBNAME,0,TYPE_STRING,PARM_MAND,0,0}, + {"DBUser",&CONFIG_DBUSER,0,TYPE_STRING,PARM_OPT,0,0}, + {"DBPassword",&CONFIG_DBPASSWORD,0,TYPE_STRING,PARM_OPT,0,0}, + {"DBSocket",&CONFIG_DBSOCKET,0,TYPE_STRING,PARM_OPT,0,0}, + {"DBPort",&CONFIG_DBPORT,0,TYPE_INT,PARM_OPT,1024,65535}, + {"NodeID",&CONFIG_NODEID,0,TYPE_INT,PARM_OPT,0,65535}, + {"NodeNoEvents",&CONFIG_NODE_NOEVENTS,0,TYPE_INT,PARM_OPT,0,1}, + {"NodeNoHistory",&CONFIG_NODE_NOHISTORY,0,TYPE_INT,PARM_OPT,0,1}, + {0} + }; + + CONFIG_SERVER_STARTUP_TIME = time(NULL); + + + parse_cfg_file(CONFIG_FILE,cfg); + + if(CONFIG_DBNAME == NULL) + { + zabbix_log( LOG_LEVEL_CRIT, "DBName not in config file"); + exit(1); + } + if(APP_PID_FILE == NULL) + { + APP_PID_FILE=strdup("/tmp/zabbix_server.pid"); + } + if(CONFIG_ALERT_SCRIPTS_PATH == NULL) + { + CONFIG_ALERT_SCRIPTS_PATH=strdup("/home/zabbix/bin"); + } + if(CONFIG_FPING_LOCATION == NULL) + { + CONFIG_FPING_LOCATION=strdup("/usr/sbin/fping"); + } + if(CONFIG_EXTERNALSCRIPTS == NULL) + { + CONFIG_EXTERNALSCRIPTS=strdup("/etc/zabbix/externalscripts"); + } +#ifndef HAVE_LIBCURL + CONFIG_HTTPPOLLER_FORKS = 0; +#endif +} + +/****************************************************************************** + * * + * Function: main * + * * + * Purpose: executes server processes * + * * + * Parameters: * + * * + * Return value: * + * * + * Author: Eugene Grigorjev * + * * + * Comments: * + * * + ******************************************************************************/ +int main(int argc, char **argv) +{ + zbx_task_t task = ZBX_TASK_START; + char ch = '\0'; + + int nodeid; + + progname = argv[0]; + + /* Parse the command-line. */ + while ((ch = (char)zbx_getopt_long(argc, argv, shortopts, longopts,NULL)) != (char)EOF) + switch (ch) { + case 'c': + CONFIG_FILE = strdup(zbx_optarg); + break; + case 'h': + help(); + exit(-1); + break; + case 'V': + version(); + exit(-1); + break; + default: + usage(); + exit(-1); + break; + } + + if(CONFIG_FILE == NULL) + { + CONFIG_FILE=strdup("/etc/zabbix/zabbix_proxy.conf"); + } + + /* Required for simple checks */ + init_metrics(); + + init_config(); + + if(CONFIG_DBSYNCER_FORKS!=0) + { + init_database_cache(); + } + + return daemon_start(CONFIG_ALLOW_ROOT); +} + +int MAIN_ZABBIX_ENTRY(void) +{ + DB_RESULT result; + DB_ROW row; + + int i; + pid_t pid; + + zbx_sock_t listen_sock; + + int server_num = 0; + + if(CONFIG_LOG_FILE == NULL) + { + zabbix_open_log(LOG_TYPE_SYSLOG,CONFIG_LOG_LEVEL,NULL); + } + else + { + zabbix_open_log(LOG_TYPE_FILE,CONFIG_LOG_LEVEL,CONFIG_LOG_FILE); + } + +#ifdef HAVE_SNMP +# define SNMP_FEATURE_STATUS "YES" +#else +# define SNMP_FEATURE_STATUS " NO" +#endif +#ifdef HAVE_LIBCURL +# define LIBCURL_FEATURE_STATUS "YES" +#else +# define LIBCURL_FEATURE_STATUS " NO" +#endif +#ifdef HAVE_ODBC +# define ODBC_FEATURE_STATUS "YES" +#else +# define ODBC_FEATURE_STATUS " NO" +#endif +#ifdef HAVE_IPV6 +# define IPV6_FEATURE_STATUS "YES" +#else +# define IPV6_FEATURE_STATUS " NO" +#endif + +/* zabbix_log( LOG_LEVEL_WARNING, "INFO [%s]", ZBX_SQL_MOD(a,%d)); */ + zabbix_log( LOG_LEVEL_WARNING, "Starting zabbix_proxy. ZABBIX %s.", ZABBIX_VERSION); + + zabbix_log( LOG_LEVEL_WARNING, "**** Enabled features ****"); + zabbix_log( LOG_LEVEL_WARNING, "SNMP monitoring: " SNMP_FEATURE_STATUS ); + zabbix_log( LOG_LEVEL_WARNING, "WEB monitoring: " LIBCURL_FEATURE_STATUS ); + zabbix_log( LOG_LEVEL_WARNING, "ODBC: " ODBC_FEATURE_STATUS ); + zabbix_log( LOG_LEVEL_WARNING, "IPv6 support: " IPV6_FEATURE_STATUS ); + zabbix_log( LOG_LEVEL_WARNING, "**************************"); + + DBconnect(ZBX_DB_CONNECT_EXIT); + + result = DBselect("select refresh_unsupported from config where " ZBX_COND_NODEID, + LOCAL_NODE("configid")); + row = DBfetch(result); + + if( (row != NULL) && DBis_null(row[0]) != SUCCEED) + { + CONFIG_REFRESH_UNSUPPORTED = atoi(row[0]); + } + DBfree_result(result); + + result = DBselect("select masterid from nodes where nodeid=%d", + CONFIG_NODEID); + row = DBfetch(result); + + if( (row != NULL) && DBis_null(row[0]) != SUCCEED) + { + CONFIG_MASTER_NODEID = atoi(row[0]); + } + DBfree_result(result); + +/* Need to set trigger status to UNKNOWN since last run */ +/* DBconnect() already made in init_config() */ +/* DBconnect();*/ + DBupdate_triggers_status_after_restart(); + DBclose(); + +/* To make sure that we can connect to the database before forking new processes */ +/* DBconnect(ZBX_DB_CONNECT_EXIT);*/ +/* Do not close database. It is required for database cache */ +/* DBclose();*/ + + if (ZBX_MUTEX_ERROR == zbx_mutex_create_force(&node_sync_access, ZBX_MUTEX_NODE_SYNC)) { + zbx_error("Unable to create mutex for node syncs"); + exit(FAIL); + } + + threads = calloc(1+CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS + +CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS + +CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS, + sizeof(pid_t)); + + if(CONFIG_TRAPPERD_FORKS > 0) + { + if( FAIL == zbx_tcp_listen(&listen_sock, CONFIG_LISTEN_IP, (unsigned short)CONFIG_LISTEN_PORT) ) + { + zabbix_log(LOG_LEVEL_CRIT, "Listener failed with error: %s.", zbx_tcp_strerror()); + exit(1); + } + } + + for( i=1; + i<=CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS+CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS+CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS+CONFIG_DBSYNCER_FORKS; + i++) + { + if((pid = zbx_fork()) == 0) + { + server_num = i; + break; + } + else + { + threads[i]=pid; + } + } + +/* zabbix_log( LOG_LEVEL_WARNING, "zabbix_server #%d started",server_num); */ + /* Main process */ + if(server_num == 0) + { + init_main_process(); +/* zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Watchdog]", + server_num); + main_watchdog_loop();*/ +/* for(;;) zbx_sleep(3600);*/ + } + + + if (server_num <= CONFIG_POLLER_FORKS) { +#ifdef HAVE_SNMP + init_snmp("zabbix_server"); +#endif /* HAVE_SNMP */ + zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Poller. SNMP:%s]", + server_num, + SNMP_FEATURE_STATUS); + main_poller_loop(ZBX_POLLER_TYPE_NORMAL, server_num); + } else if (server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS) { +/* Run trapper processes then do housekeeping */ + child_trapper_main(server_num, &listen_sock); + +/* threads[i] = child_trapper_make(i, listenfd, addrlen); */ +/* child_trapper_make(server_num, listenfd, addrlen); */ + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS) + { + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [ICMP pinger]", + server_num); + main_pinger_loop(server_num-(CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS)); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + +CONFIG_HOUSEKEEPER_FORKS) + { + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Housekeeper]", + server_num); + main_housekeeper_loop(); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + +CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS) + { +#ifdef HAVE_SNMP + init_snmp("zabbix_server"); +#endif /* HAVE_SNMP */ + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Poller for unreachable hosts. SNMP:%s]", + server_num, + SNMP_FEATURE_STATUS); + main_poller_loop(ZBX_POLLER_TYPE_UNREACHABLE, + server_num - (CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS)); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + + CONFIG_NODEWATCHER_FORKS) + { + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Node watcher. Node ID:%d]", + server_num, + CONFIG_NODEID); + main_nodewatcher_loop(); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS) + { + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [HTTP Poller]", + server_num); + main_httppoller_loop(server_num - CONFIG_POLLER_FORKS - CONFIG_TRAPPERD_FORKS -CONFIG_PINGER_FORKS + - CONFIG_HOUSEKEEPER_FORKS + - CONFIG_UNREACHABLE_POLLER_FORKS - CONFIG_NODEWATCHER_FORKS); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS) + { +#ifdef HAVE_SNMP + init_snmp("zabbix_server"); +#endif /* HAVE_SNMP */ + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Discoverer. SNMP:%s]", + server_num, + SNMP_FEATURE_STATUS); + main_discoverer_loop(server_num - CONFIG_POLLER_FORKS - CONFIG_TRAPPERD_FORKS -CONFIG_PINGER_FORKS + - CONFIG_HOUSEKEEPER_FORKS + - CONFIG_UNREACHABLE_POLLER_FORKS - CONFIG_NODEWATCHER_FORKS - CONFIG_HTTPPOLLER_FORKS); + } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS + + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS) + { + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [DB Syncer]", + server_num); + main_dbsyncer_loop(); + } + + return SUCCEED; +} + +void zbx_on_exit() +{ +#if !defined(_WINDOWS) + + int i = 0; + + if(threads != NULL) + { + for(i = 1; i <= CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS+CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS+CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS+CONFIG_DBSYNCER_FORKS; i++) + { + if(threads[i]) { + kill(threads[i],SIGTERM); + threads[i] = (ZBX_THREAD_HANDLE)NULL; + } + } + } + +#endif /* not _WINDOWS */ + +#ifdef USE_PID_FILE + + daemon_stop(); + +#endif /* USE_PID_FILE */ + + free_metrics(); + + zbx_sleep(2); /* wait for all threads closing */ + + DBconnect(ZBX_DB_CONNECT_EXIT); + + if(CONFIG_DBSYNCER_FORKS!=0) + { + free_database_cache(); + } + DBclose(); + zbx_mutex_destroy(&node_sync_access); + zabbix_close_log(); + +#ifdef HAVE_SQLITE3 + php_sem_remove(&sqlite_access); +#endif /* HAVE_SQLITE3 */ + + zabbix_log(LOG_LEVEL_INFORMATION, "ZABBIX Server stopped"); + + exit(SUCCEED); +} + diff --git a/src/zabbix_proxy/trapper/Makefile.am b/src/zabbix_proxy/trapper/Makefile.am new file mode 100644 index 00000000..dc09025f --- /dev/null +++ b/src/zabbix_proxy/trapper/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libzbxtrapper.a + +libzbxtrapper_a_SOURCES = \ + active.c active.h \ + trapper.c trapper.h \ + nodesync.c nodesync.h \ + nodehistory.c nodehistory.h \ + nodecommand.c nodecommand.h diff --git a/src/zabbix_proxy/trapper/active.c b/src/zabbix_proxy/trapper/active.c new file mode 100644 index 00000000..0500e81d --- /dev/null +++ b/src/zabbix_proxy/trapper/active.c @@ -0,0 +1,120 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <string.h> + +#include <time.h> + +#include <sys/socket.h> +#include <errno.h> + +/* Functions: pow(), round() */ +#include <math.h> + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "active.h" + +/****************************************************************************** + * * + * Function: send_list_of_active_checks * + * * + * Purpose: send list of active checks to the host * + * * + * Parameters: sockfd - open socket of server-agent connection * + * host - hostname * + * * + * Return value: SUCCEED - list of active checks sent succesfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: format of the list: key:delay:last_log_size * + * * + ******************************************************************************/ +int send_list_of_active_checks(zbx_sock_t *sock, const char *host) +{ + char s[MAX_STRING_LEN]; + DB_RESULT result; + DB_ROW row; + + zabbix_log( LOG_LEVEL_DEBUG, "In send_list_of_active_checks()"); + + if (0 != CONFIG_REFRESH_UNSUPPORTED) { + result = DBselect("select i.key_,i.delay,i.lastlogsize from items i,hosts h " + "where i.hostid=h.hostid and h.status=%d and i.type=%d and h.host='%s' " + "and (i.status=%d or (i.status=%d and i.nextcheck<=%d)) and"ZBX_COND_NODEID, + HOST_STATUS_MONITORED, + ITEM_TYPE_ZABBIX_ACTIVE, + host, + ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, time(NULL), + LOCAL_NODE("h.hostid")); + } else { + result = DBselect("select i.key_,i.delay,i.lastlogsize from items i,hosts h " + "where i.hostid=h.hostid and h.status=%d and i.type=%d and h.host='%s' " + "and i.status=%d and"ZBX_COND_NODEID, + HOST_STATUS_MONITORED, + ITEM_TYPE_ZABBIX_ACTIVE, + host, + ITEM_STATUS_ACTIVE, + LOCAL_NODE("h.hostid")); + } + + while((row=DBfetch(result))) + { + zbx_snprintf(s,sizeof(s),"%s:%s:%s\n", + row[0], + row[1], + row[2]); + zabbix_log( LOG_LEVEL_DEBUG, "Sending [%s]", + s); + + if( zbx_tcp_send_raw(sock,s) != SUCCEED ) + { + zabbix_log( LOG_LEVEL_WARNING, "Error while sending list of active checks"); + return FAIL; + } + } + DBfree_result(result); + + zbx_snprintf(s,sizeof(s),"%s\n", + "ZBX_EOF"); + zabbix_log( LOG_LEVEL_DEBUG, "Sending [%s]", + s); + + if( zbx_tcp_send_raw(sock,s) != SUCCEED ) + { + zabbix_log( LOG_LEVEL_WARNING, "Error while sending list of active checks"); + return FAIL; + } + + return SUCCEED; +} diff --git a/src/zabbix_proxy/trapper/active.h b/src/zabbix_proxy/trapper/active.h new file mode 100644 index 00000000..3b31ea74 --- /dev/null +++ b/src/zabbix_proxy/trapper/active.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_TRAPPER_ACTIVE_H +#define ZABBIX_TRAPPER_ACTIVE_H + +#include "common.h" +#include "db.h" +#include "comms.h" + +int send_list_of_active_checks(zbx_sock_t *sock, const char *host); + +#endif diff --git a/src/zabbix_proxy/trapper/nodecommand.c b/src/zabbix_proxy/trapper/nodecommand.c new file mode 100644 index 00000000..7fbc645e --- /dev/null +++ b/src/zabbix_proxy/trapper/nodecommand.c @@ -0,0 +1,284 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <string.h> + +#include <time.h> + +#include <sys/socket.h> +#include <errno.h> + +#include "comms.h" +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#define MVAR_HOST_NAME "{HOSTNAME}" +#define MVAR_IPADDRESS "{IPADDRESS}" +#define MVAR_HOST_CONN "{HOST.CONN}" + + +/****************************************************************************** + * * + * Function: execute_script * + * * + * Purpose: executing command * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void execute_script(const char *command, char **result, int *result_allocated) +{ + int result_offset = 0; + char buffer[MAX_STRING_LEN]; + FILE *f; + + zabbix_log(LOG_LEVEL_DEBUG, "In execute_script(command:%s)", command); + + if(0 != (f = popen(command, "r"))) { + zbx_snprintf_alloc(result, result_allocated, &result_offset, 8, "%d%c", + SUCCEED, + ZBX_DM_DELIMITER); + + while (NULL != fgets(buffer, sizeof(buffer)-1, f)) { + zbx_snprintf_alloc(result, result_allocated, &result_offset, sizeof(buffer), + "%s", + buffer); + } + (*result)[result_offset] = '\0'; + + pclose(f); + } else { + zbx_snprintf_alloc(result, result_allocated, &result_offset, 128, + "%d%cNODE %d: Cannot execute [%s] error:%s", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + command, + strerror(errno)); + } +} + +/****************************************************************************** + * * + * Function: send_script * + * * + * Purpose: sending command to slave node * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +void send_script(int nodeid, const char *data, char **result, int *result_allocated) +{ + DB_RESULT dbresult; + DB_ROW dbrow; + int result_offset = 0; + zbx_sock_t sock; + char *answer; + + zabbix_log(LOG_LEVEL_DEBUG, "In send_script(nodeid:%d)", nodeid); + + dbresult = DBselect("select ip,port from nodes where nodeid=%d", + nodeid); + + if (NULL != (dbrow = DBfetch(dbresult))) { + if (SUCCEED == zbx_tcp_connect(&sock, dbrow[0], atoi(dbrow[1]), 0)) { + if (FAIL == zbx_tcp_send(&sock, data)) { + zbx_snprintf_alloc(result, result_allocated, &result_offset, 128, + "%d%cNODE %d: Error while sending data to Node [%d] error: %s", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + goto exit_sock; + } + + if (SUCCEED == zbx_tcp_recv(&sock, &answer/*, ZBX_TCP_READ_UNTIL_CLOSE*/)) { + zbx_snprintf_alloc(result, result_allocated, &result_offset, strlen(answer)+1, + "%s", + answer); + } else { + + zbx_snprintf_alloc(result, result_allocated, &result_offset, 128, + "%d%cNODE %d: Error while receiving answer from Node [%d] error: %s", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + goto exit_sock; + } +exit_sock: + zbx_tcp_close(&sock); + } else { + zbx_snprintf_alloc(result, result_allocated, &result_offset, 128, + "%d%cNODE %d: Unable to connect to Node [%d] error: %s", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + nodeid, + zbx_tcp_strerror()); + } + } else { + zbx_snprintf_alloc(result, result_allocated, &result_offset, 128, + "%d%cNODE %d: Node [%d] is unknown", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + nodeid); + } + DBfree_result(dbresult); +} + +/****************************************************************************** + * * + * Function: get_next_point_to_node * + * * + * Purpose: find next point to slave node * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int get_next_point_to_node(int current_nodeid, int slave_nodeid, int *nodeid) +{ + DB_RESULT dbresult; + DB_ROW dbrow; + int id, res = FAIL; + + dbresult = DBselect("select nodeid from nodes where masterid=%d", + current_nodeid); + + while (NULL != (dbrow = DBfetch(dbresult))) { + id = atoi(dbrow[0]); + if (id == slave_nodeid || SUCCEED == get_next_point_to_node(id, slave_nodeid, NULL)) { + if (NULL != nodeid) + *nodeid = id; + res = SUCCEED; + break; + } + } + DBfree_result(dbresult); + + return res; +} + +/****************************************************************************** + * * + * Function: node_process_command * + * * + * Purpose: process command received from a master node or php * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int node_process_command(zbx_sock_t *sock, const char *data) +{ + const char *r; + char *tmp = NULL, *result = NULL; + int tmp_allocated = 64, result_allocated = 1024; + int datalen; + int nodeid, next_nodeid; + int result_offset = 0; + + result = zbx_malloc(result, result_allocated); + tmp = zbx_malloc(tmp, tmp_allocated); + datalen = strlen(data); + + zabbix_log(LOG_LEVEL_DEBUG, "In node_process_command(datalen:%d)", + datalen); + + r = data; + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* Constant 'Command' */ + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* NodeID */ + nodeid = atoi(tmp); + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); + + if (nodeid == CONFIG_NODEID) { + zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received command \"%s\"", + CONFIG_NODEID, + tmp); + + execute_script(tmp, &result, &result_allocated); + } else if (SUCCEED == get_next_point_to_node(CONFIG_NODEID, nodeid, &next_nodeid)) { + zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Sending command \"%s\" for nodeid %d" + "to node %d", + CONFIG_NODEID, + tmp, + nodeid, + next_nodeid); + + send_script(next_nodeid, data, &result, &result_allocated); + } else { + zbx_snprintf_alloc(&result, &result_allocated, &result_offset, 128, + "%d%cNODE %d: Node [%d] is unknown", + FAIL, + ZBX_DM_DELIMITER, + CONFIG_NODEID, + nodeid); + } + + if (zbx_tcp_send_raw(sock, result) != SUCCEED) { + zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Error sending result of command to node %d", + CONFIG_NODEID, + nodeid); + } + zbx_free(tmp); + zbx_free(result); + + return SUCCEED; +} diff --git a/src/zabbix_proxy/trapper/nodecommand.h b/src/zabbix_proxy/trapper/nodecommand.h new file mode 100644 index 00000000..0c92e05b --- /dev/null +++ b/src/zabbix_proxy/trapper/nodecommand.h @@ -0,0 +1,26 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_NODECOMMAND_H +#define ZABBIX_NODECOMMAND_H + +int node_process_command(zbx_sock_t *sock, const char *data); + +#endif diff --git a/src/zabbix_proxy/trapper/nodehistory.c b/src/zabbix_proxy/trapper/nodehistory.c new file mode 100644 index 00000000..51fec678 --- /dev/null +++ b/src/zabbix_proxy/trapper/nodehistory.c @@ -0,0 +1,481 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "../events.h" +#include "../nodewatcher/nodecomms.h" + +/****************************************************************************** + * * + * Function: send_history_last_id * + * * + * Purpose: send list of last historical tables ids * + * * + * Parameters: sock - opened socket of node-node connection * + * record * + * * + * Return value: SUCCEED - sent succesfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int send_history_last_id(zbx_sock_t *sock, const char *data) +{ + DB_RESULT result; + DB_ROW row; + const char *r; + char *tmp = NULL, tablename[MAX_STRING_LEN], fieldname[MAX_STRING_LEN]; + int tmp_allocated = 256, tmp_offset; + int sender_nodeid, nodeid, res; + + zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_history_ids()"); + + tmp = zbx_malloc(tmp, tmp_allocated); + + r = data; + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'ZBX_GET_HISTORY_LAST_ID' */ + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */ + sender_nodeid=atoi(tmp); + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, '\n'); /* nodeid */ + nodeid=atoi(tmp); + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* table name */ + strcpy(tablename, tmp); + + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* field name */ + strcpy(fieldname, tmp); + + tmp_offset= 0; + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "select MAX(%s) " + "from %s where"ZBX_COND_NODEID, + fieldname, + tablename, + ZBX_NODE(fieldname, nodeid)); + + tmp_offset= 0; + result = DBselect("%s", tmp); + if (NULL != (row = DBfetch(result))) + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s", + SUCCEED == DBis_null(row[0]) ? "0" : row[0]); + DBfree_result(result); + + if (tmp_offset == 0) + goto error; + + res = send_data_to_node(sender_nodeid, sock, tmp); + + zbx_free(tmp); + + return res; +error: + tmp_offset= 0; + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "FAIL"); + + res = send_data_to_node(sender_nodeid, sock, tmp); + + zbx_free(tmp); + + zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", + CONFIG_NODEID, + sender_nodeid, + nodeid, + data); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: send_trends_last_id * + * * + * Purpose: send last historical tables ids * + * * + * Parameters: sock - opened socket of node-node connection * + * record * + * * + * Return value: SUCCEED - sent succesfully * + * FAIL - an error occured * + * * + * Author: Aleksander Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int send_trends_last_id(zbx_sock_t *sock, const char *data) +{ + DB_RESULT result; + DB_ROW row; + const char *r; + char *tmp = NULL, tablename[MAX_STRING_LEN]; + int tmp_allocated = 256, tmp_offset; + int sender_nodeid, nodeid, res; + + zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_history_ids()"); + + tmp = zbx_malloc(tmp, tmp_allocated); + + r = data; + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'ZBX_GET_HISTORY_LAST_ID' */ + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */ + sender_nodeid=atoi(tmp); + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, '\n'); /* nodeid */ + nodeid=atoi(tmp); + if (NULL == r) + goto error; + + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* table name */ + strcpy(tablename, tmp); + + tmp_offset= 0; + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "select itemid,clock " + "from %s where"ZBX_COND_NODEID"order by itemid desc,clock desc", + tablename, + ZBX_NODE("itemid", nodeid)); + + tmp_offset= 0; + result = DBselectN(tmp, 1); + if (NULL == (row = DBfetch(result))) + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 64, "0%c0", + ZBX_DM_DELIMITER); + else + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s%c%s", + SUCCEED == DBis_null(row[0]) ? "0" : row[0], + ZBX_DM_DELIMITER, + SUCCEED == DBis_null(row[1]) ? "0" : row[1]); + DBfree_result(result); + + res = send_data_to_node(sender_nodeid, sock, tmp); + + zbx_free(tmp); + + return res; +error: + tmp_offset= 0; + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "FAIL"); + + res = send_data_to_node(sender_nodeid, sock, tmp); + + zbx_free(tmp); + + zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", + CONFIG_NODEID, + sender_nodeid, + nodeid, + data); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: process_record_event * + * * + * Purpose: process record update * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int process_record_event(int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, char **tmp, int *tmp_allocated) +{ + const char *r; + int f, len; + DB_EVENT event; + + zabbix_log(LOG_LEVEL_DEBUG, "In process_record_event ()"); + + memset(&event, 0, sizeof(event)); + + r = record; + for (f = 0; table->fields[f].name != 0; f++) { + if (NULL == r) + goto error; + + len = zbx_get_next_field(&r, tmp, tmp_allocated, ZBX_DM_DELIMITER); + + if (0 == strcmp(table->fields[f].name, "eventid")) { + ZBX_STR2UINT64(event.eventid, *tmp); + } else if (0 == strcmp(table->fields[f].name, "source")) { + event.source = atoi(*tmp); + } else if (0 == strcmp(table->fields[f].name, "object")) { + event.object = atoi(*tmp); + } else if (0 == strcmp(table->fields[f].name, "objectid")) { + ZBX_STR2UINT64(event.objectid, *tmp); + } else if (0 == strcmp(table->fields[f].name, "clock")) { + event.clock=atoi(*tmp); + } else if (0 == strcmp(table->fields[f].name, "value")) { + event.value=atoi(*tmp); + } else if (0 == strcmp(table->fields[f].name, "acknowledged")) { + event.acknowledged=atoi(*tmp); + } + } + + return process_event(&event); +error: + zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", + CONFIG_NODEID, + sender_nodeid, + nodeid, + record); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: process_record * + * * + * Purpose: process record update * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int process_record(int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, char **tmp, int *tmp_allocated, char **sql, int *sql_allocated, int lastrecord) +{ + const char *r; + int f, len, sql_offset, lastvalue_type; + int res = FAIL; + char lastvalue[MAX_STRING_LEN], lastclock[MAX_STRING_LEN]; + + zabbix_log(LOG_LEVEL_DEBUG, "In process_record ()"); + + r = record; + + sql_offset = 0; + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "insert into %s (", + table->table); + + if (0 != (table->flags & ZBX_HISTORY_SYNC)) + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "nodeid,"); + + for (f = 0; table->fields[f].name != 0; f++) { + if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) + continue; + + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "%s,", + table->fields[f].name); + } + + sql_offset--; + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 64, ") values ("); + + if (0 != (table->flags & ZBX_HISTORY_SYNC)) + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "%d,", + nodeid); + + for (f = 0; table->fields[f].name != 0; f++) { + if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) + continue; + + if (NULL == r) + goto error; + + len = zbx_get_next_field(&r, tmp, tmp_allocated, ZBX_DM_DELIMITER); + + if (table->fields[f].type == ZBX_TYPE_INT || + table->fields[f].type == ZBX_TYPE_UINT || + table->fields[f].type == ZBX_TYPE_ID || + table->fields[f].type == ZBX_TYPE_FLOAT) + { + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, len + 8, "%s,", + *tmp); + } else { /* ZBX_TYPE_CHAR ZBX_TYPE_BLOB ZBX_TYPE_TEXT */ + if (0 == len) + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 8, "'',"); + else + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, len + 8, "0x%s,", + *tmp); + } + + if (lastrecord && 0 != (table->flags & ZBX_HISTORY_SYNC)) { + if (0 == strcmp(table->fields[f].name, "clock")) { + strcpy(lastclock, *tmp); + } else if (0 == strcmp(table->fields[f].name, "value")) { + strcpy(lastvalue, *tmp); + lastvalue_type = table->fields[f].type; + } + } + } + + sql_offset--; + zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 8, ")"); + + if (DBexecute("%s", *sql) >= ZBX_DB_OK) + res = SUCCEED; + + return res; +error: + zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", + CONFIG_NODEID, + sender_nodeid, + nodeid, + record); + + return FAIL; +} + +/****************************************************************************** + * * + * Function: node_history * + * * + * Purpose: process new history received from a salve node * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int node_history(char *data, size_t datalen) +{ + const char *r; + char *newline = NULL, *tmp = NULL, *sql = NULL; + char *pos; + int tmp_allocated = 4096, sql_allocated = 8192; + int sender_nodeid = 0, nodeid = 0, firstline = 1, events = 0; + const ZBX_TABLE *table_sync = NULL, *table = NULL; + int res = SUCCEED; + + assert(data); + + zabbix_log(LOG_LEVEL_DEBUG, "In node_history()"); + + tmp = zbx_malloc(tmp, tmp_allocated); + sql = zbx_malloc(sql, sql_allocated); + + DBbegin(); + + for (r = data; *r != '\0' && res == SUCCEED;) { + if (NULL != (newline = strchr(r, '\n'))) + *newline = '\0'; + + if (1 == firstline) { + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'History' */ + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */ + sender_nodeid=atoi(tmp); + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* nodeid */ + nodeid=atoi(tmp); + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* tablename */ + + table = DBget_table(tmp); + if (0 == (table->flags & (ZBX_HISTORY | ZBX_HISTORY_SYNC | ZBX_HISTORY_TRENDS))) + table = NULL; + + if (NULL != table && 0 != (table->flags & ZBX_HISTORY_SYNC)) { + table_sync = table; + if (NULL != (pos = strstr(tmp, "_sync"))) { + *pos = '\0'; + table = DBget_table(tmp); + } + } + + if (NULL != table && 0 == strcmp(table->table, "events")) + events = 1; + + if (NULL == table) { + zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Invalid received data: unknown tablename \"%s\"", + CONFIG_NODEID, + tmp); + } + if (NULL != newline) { + zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received %s from node %d for node %d datalen %zd", + CONFIG_NODEID, + tmp, + sender_nodeid, + nodeid, + datalen); + } + firstline = 0; + } else if (NULL != table) { + if (events) { + res = process_record_event(sender_nodeid, nodeid, table, r, &tmp, &tmp_allocated); + } else { + res = process_record(sender_nodeid, nodeid, table, r, &tmp, &tmp_allocated, &sql, &sql_allocated, NULL == newline); + if (SUCCEED == res && NULL != table_sync && 0 != CONFIG_MASTER_NODEID) + res = process_record(sender_nodeid, nodeid, table_sync, r, &tmp, &tmp_allocated, &sql, &sql_allocated, 0); + } + } + + if (newline != NULL) { + *newline = '\n'; + r = newline + 1; + } else + break; + } + if (res == SUCCEED) + DBcommit(); + else + DBrollback(); + + zbx_free(sql); + zbx_free(tmp); + + return res; +} diff --git a/src/zabbix_proxy/trapper/nodehistory.h b/src/zabbix_proxy/trapper/nodehistory.h new file mode 100644 index 00000000..bfcf3e01 --- /dev/null +++ b/src/zabbix_proxy/trapper/nodehistory.h @@ -0,0 +1,30 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_NODEHISTORY_H +#define ZABBIX_NODEHISTORY_H + +#include "comms.h" + +int send_history_last_id(zbx_sock_t *sock, const char *data); +int send_trends_last_id(zbx_sock_t *sock, const char *data); +int node_history(char *data, size_t datalen); + +#endif diff --git a/src/zabbix_proxy/trapper/nodesync.c b/src/zabbix_proxy/trapper/nodesync.c new file mode 100644 index 00000000..6535d2a3 --- /dev/null +++ b/src/zabbix_proxy/trapper/nodesync.c @@ -0,0 +1,338 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <string.h> + +#include <time.h> + +#include <sys/socket.h> +#include <errno.h> + +/* Functions: pow(), round() */ +#include <math.h> + +#include "common.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "nodesync.h" +#include "../nodewatcher/nodesender.h" + +/****************************************************************************** + * * + * Function: process_record * + * * + * Purpose: process record update * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +static int process_record(int nodeid, const char *record, int sender_nodetype) +{ + char tablename[MAX_STRING_LEN]; + char fieldname[MAX_STRING_LEN]; + zbx_uint64_t recid; + int op, res = SUCCEED; + int valuetype; + char value_esc[MAX_STRING_LEN]; + int i; + char *key=NULL; + DB_RESULT result; + DB_ROW row; + const char *r; + char *buffer = NULL, *tmp = NULL, *fields_update = NULL, *fields = NULL, *values = NULL; + int buffer_allocated = 16*1024; + int tmp_allocated = 16*1024, tmp_offset = 0; + int fields_update_allocated = 16*1024, fields_update_offset = 0; + int fields_allocated = 4*1024, fields_offset = 0; + int values_allocated = 16*1024, values_offset = 0; +#if defined(HAVE_POSTGRESQL) + int len; +#endif /* HAVE_POSTGRESQL */ + + zabbix_log( LOG_LEVEL_DEBUG, "In process_record [%s]", record); + + r = record; + buffer = zbx_malloc(buffer, buffer_allocated); + tmp = zbx_malloc(tmp, tmp_allocated); + + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + strcpy(tablename, buffer); + + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + ZBX_STR2UINT64(recid, buffer); + + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + op = atoi(buffer); + + for(i=0;tables[i].table!=0;i++) + { + if(strcmp(tables[i].table, tablename)==0) + { + key=tables[i].recid; + break; + } + } + + if(key == NULL) + { + zabbix_log( LOG_LEVEL_WARNING, "Cannot find key field for table [%s]", + tablename); + res = FAIL; + goto out; + } + if(op==NODE_CONFIGLOG_OP_DELETE) + { + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "delete from %s where %s="ZBX_FS_UI64, + tablename, + key, + recid); + DBexecute("%s", tmp); + goto out; + } + + fields_update = zbx_malloc(fields_update, fields_update_allocated); + fields = zbx_malloc(fields, fields_allocated); + values = zbx_malloc(values, values_allocated); + + zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", key); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, ZBX_FS_UI64",", recid); + + while(r != NULL) + { + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + strcpy(fieldname, buffer); + + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + valuetype=atoi(buffer); + + zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); + if(op==NODE_CONFIGLOG_OP_UPDATE) + { + if(strcmp(buffer, "NULL") == 0) + { + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 128, "%s=NULL,", + fieldname); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "NULL,"); + } + else + { + if(valuetype == ZBX_TYPE_INT || valuetype == ZBX_TYPE_UINT || valuetype == ZBX_TYPE_ID || valuetype == ZBX_TYPE_FLOAT) + { + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 256, "%s=%s,", + fieldname, + buffer); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "%s,", + buffer); + } + else if(valuetype == ZBX_TYPE_BLOB) + { + if(*buffer == '\0') + { + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 128, "%s='',", + fieldname); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "'',"); + } + else + { +#if defined(HAVE_POSTGRESQL) + len = zbx_hex2binary(buffer); + zbx_pg_escape_bytea((u_char *)buffer, len, &tmp, &tmp_allocated); + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, strlen(tmp)+256, "%s='%s',", + fieldname, + tmp); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, strlen(tmp)+256, "'%s',", + tmp); +#else + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, strlen(buffer)+256, "%s=0x%s,", + fieldname, + buffer); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, strlen(buffer)+256, "0x%s,", + buffer); +#endif + } + } + else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ + { + zbx_hex2binary(buffer); + DBescape_string(buffer, value_esc,MAX_STRING_LEN); + + zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 256, "%s='%s',", + fieldname, + value_esc); + zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 256, "'%s',", + value_esc); + } + } + + zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", fieldname); + } + else + { + zabbix_log( LOG_LEVEL_WARNING, "Unknown record operation [%d]", + op); + res = FAIL; + goto out; + } + } + if(fields_offset != 0) fields[fields_offset - 1]='\0'; + if(fields_update_offset != 0) fields_update[fields_update_offset - 1]='\0'; + if(values_offset != 0) values[values_offset - 1]='\0'; + + if(op==NODE_CONFIGLOG_OP_UPDATE) + { + result = DBselect("select 0 from %s where %s="ZBX_FS_UI64, + tablename, + key, + recid); + row = DBfetch(result); + if(row) + { + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16*1024, "update %s set %s where %s=" ZBX_FS_UI64, + tablename, + fields_update, + key, + recid); + } + else + { + zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16*1024, "insert into %s (%s) values(%s)", + tablename, + fields, + values); + } + DBfree_result(result); + } + DBexecute("%s",tmp); + + if (FAIL == calculate_checksums(nodeid, tablename, recid) || + FAIL == update_checksums(nodeid, sender_nodetype, SUCCEED, tablename, recid, fields) ) { + res = FAIL; + goto out; + } +/* zabbix_log( LOG_LEVEL_CRIT, "RECORD [%s]", record);*/ +/* zabbix_log( LOG_LEVEL_CRIT, "SQL [%s] %s", tmp, res == FAIL ? "FAIL" : "SUCCEED");*/ + +out: + if (NULL != buffer) + zbx_free(buffer); + if (NULL != tmp) + zbx_free(tmp); + if (NULL != fields_update) + zbx_free(fields_update); + if (NULL != fields) + zbx_free(fields); + if (NULL != values) + zbx_free(values); + + return res; +} +/****************************************************************************** + * * + * Function: node_sync * + * * + * Purpose: process configuration changes received from a node * + * * + * Parameters: * + * * + * Return value: SUCCEED - processed successfully * + * FAIL - an error occured * + * * + * Author: Alexei Vladishev * + * * + * Comments: * + * * + ******************************************************************************/ +int node_sync(char *data, int *sender_nodeid, int *nodeid) +{ + const char *r; + char *newline, *tmp = NULL; + int tmp_allocated = 128; + int firstline=1; + int sender_nodetype=0; + int datalen; + int res = SUCCEED; + + datalen=strlen(data); + + zabbix_log( LOG_LEVEL_DEBUG, "In node_sync(len:%d)", datalen); + + tmp = zbx_malloc(tmp, tmp_allocated); + +/*zabbix_log(LOG_LEVEL_CRIT, "<----- [%s]", data);*/ + + for (r = data; *r != '\0' && res == SUCCEED;) { + if (NULL != (newline = strchr(r, '\n'))) + *newline = '\0'; + + if (firstline == 1) { + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* Data */ + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); + *sender_nodeid=atoi(tmp); + sender_nodetype = *sender_nodeid == CONFIG_MASTER_NODEID ? ZBX_NODE_MASTER : ZBX_NODE_SLAVE; + zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); + *nodeid=atoi(tmp); + + if (0 != *sender_nodeid && 0 != *nodeid) { + zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Received data from %s node %d for node %d datalen %d", + CONFIG_NODEID, + sender_nodetype == ZBX_NODE_SLAVE ? "slave" : "master", + *sender_nodeid, + *nodeid, + datalen); + +/* DBbegin();*/ + + DBexecute("delete from node_cksum where nodeid=%d and cksumtype=%d", + *nodeid, + NODE_CKSUM_TYPE_NEW); + + firstline=0; + } else + res = FAIL; + } else + res = process_record(*nodeid, r, sender_nodetype); + + if (newline != NULL) { + *newline = '\n'; + r = newline + 1; + } else + break; + } + zbx_free(tmp); + + return res; +} diff --git a/src/zabbix_proxy/trapper/nodesync.h b/src/zabbix_proxy/trapper/nodesync.h new file mode 100644 index 00000000..94c3a594 --- /dev/null +++ b/src/zabbix_proxy/trapper/nodesync.h @@ -0,0 +1,26 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#ifndef ZABBIX_NODESYNC_H +#define ZABBIX_NODESYNC_H + +int node_sync(char *data, int *sender_nodeid, int *nodeid); + +#endif diff --git a/src/zabbix_proxy/trapper/trapper.c b/src/zabbix_proxy/trapper/trapper.c new file mode 100644 index 00000000..d6ee142b --- /dev/null +++ b/src/zabbix_proxy/trapper/trapper.c @@ -0,0 +1,245 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#include "common.h" + +#include "cfg.h" +#include "comms.h" +#include "pid.h" +#include "db.h" +#include "log.h" +#include "zlog.h" + +#include "../functions.h" +#include "../expression.h" + +#include "../nodewatcher/nodecomms.h" +#include "../nodewatcher/nodesender.h" +#include "nodesync.h" +#include "nodehistory.h" +#include "trapper.h" +#include "active.h" +#include "nodecommand.h" + +#include "daemon.h" + +static int process_trap(zbx_sock_t *sock,char *s, int max_len) +{ + char *line,*host; + char *server,*key,*value_string, *data; + char copy[MAX_STRING_LEN]; + char host_dec[MAX_STRING_LEN],key_dec[MAX_STRING_LEN],value_dec[MAX_STRING_LEN]; + char lastlogsize[MAX_STRING_LEN]; + char timestamp[MAX_STRING_LEN]; + char source[MAX_STRING_LEN]; + char severity[MAX_STRING_LEN]; + int sender_nodeid, nodeid; + char *answer; + + int ret=SUCCEED, res; + size_t datalen; + + zbx_rtrim(s, " \r\n\0"); + + datalen = strlen(s); + zabbix_log( LOG_LEVEL_DEBUG, "Trapper got [%s] len %zd", + s, + datalen); +/* Request for list of active checks */ + if (strncmp(s,"ZBX_GET_ACTIVE_CHECKS", 21) == 0) { + line=strtok(s,"\n"); + host=strtok(NULL,"\n"); + if(host == NULL) + { + zabbix_log( LOG_LEVEL_WARNING, "ZBX_GET_ACTIVE_CHECKS: host is null. Ignoring."); + } + else + { + ret = send_list_of_active_checks(sock, host); + } +/* Request for last ids */ + } else if (strncmp(s,"ZBX_GET_HISTORY_LAST_ID", 23) == 0) { + send_history_last_id(sock, s); + return ret; + } else if (strncmp(s,"ZBX_GET_TRENDS_LAST_ID", 22) == 0) { + send_trends_last_id(sock, s); + return ret; +/* Process information sent by zabbix_sender */ + } else { + /* Command? */ + if(strncmp(s,"Command",7) == 0) + { + node_process_command(sock, s); + return ret; + } + /* Node data exchange? */ + if(strncmp(s,"Data",4) == 0) + { + node_sync_lock(0); + +/* zabbix_log( LOG_LEVEL_WARNING, "Node data received [len:%d]", strlen(s)); */ + res = node_sync(s, &sender_nodeid, &nodeid); + if (FAIL == res) + send_data_to_node(sender_nodeid, sock, "FAIL"); + else { + res = calculate_checksums(nodeid, NULL, 0); + if (SUCCEED == res && NULL != (data = get_config_data(nodeid, ZBX_NODE_SLAVE))) { + res = send_data_to_node(sender_nodeid, sock, data); + zbx_free(data); + if (SUCCEED == res) + res = recv_data_from_node(sender_nodeid, sock, &answer); + if (SUCCEED == res && 0 == strcmp(answer, "OK")) + res = update_checksums(nodeid, ZBX_NODE_SLAVE, SUCCEED, NULL, 0, NULL); + } + } + + node_sync_unlock(0); + + return ret; + } + /* Slave node history ? */ + if(strncmp(s,"History",7) == 0) + { +/* zabbix_log( LOG_LEVEL_WARNING, "Slave node history received [len:%d]", strlen(s)); */ + if (node_history(s, datalen) == SUCCEED) { + if (zbx_tcp_send_raw(sock,"OK") != SUCCEED) { + zabbix_log( LOG_LEVEL_WARNING, "Error sending confirmation to node"); + zabbix_syslog("Trapper: error sending confirmation to node"); + } + } + return ret; + } + /* New XML protocol? */ + else if(s[0]=='<') + { + zabbix_log( LOG_LEVEL_DEBUG, "XML received [%s]", s); + + comms_parse_response(s,host_dec,key_dec,value_dec,lastlogsize,timestamp,source,severity,sizeof(host_dec)-1); + + server=host_dec; + value_string=value_dec; + key=key_dec; + } + else + { + strscpy(copy,s); + + server=(char *)strtok(s,":"); + if(NULL == server) + { + return FAIL; + } + + key=(char *)strtok(NULL,":"); + if(NULL == key) + { + return FAIL; + } + + value_string=strchr(copy,':'); + value_string=strchr(value_string+1,':'); + + if(NULL == value_string) + { + return FAIL; + } + /* It points to ':', so have to increment */ + value_string++; + lastlogsize[0]=0; + timestamp[0]=0; + source[0]=0; + severity[0]=0; + } + zabbix_log( LOG_LEVEL_DEBUG, "Value [%s]", value_string); + + DBbegin(); + ret=process_data(sock,server,key,value_string,lastlogsize,timestamp,source,severity); + DBcommit(); + + if( zbx_tcp_send_raw(sock, SUCCEED == ret ? "OK" : "NOT OK") != SUCCEED) + { + zabbix_log( LOG_LEVEL_WARNING, "Error sending result back"); + zabbix_syslog("Trapper: error sending result back"); + } + zabbix_log( LOG_LEVEL_DEBUG, "After write()"); + } + return ret; +} + +void process_trapper_child(zbx_sock_t *sock) +{ + char *data; + +/* suseconds_t is not defined under HP-UX */ +/* struct timeval tv; + suseconds_t msec; + gettimeofday(&tv, NULL); + msec = tv.tv_usec;*/ + +/* alarm(CONFIG_TIMEOUT);*/ + + if(zbx_tcp_recv(sock, &data) != SUCCEED) + { +/* alarm(0);*/ + return; + } + + process_trap(sock, data, sizeof(data)); +/* alarm(0);*/ + +/* gettimeofday(&tv, NULL); + zabbix_log( LOG_LEVEL_DEBUG, "Trap processed in " ZBX_FS_DBL " seconds", + (double)(tv.tv_usec-msec)/1000000 );*/ +} + +void child_trapper_main(int i, zbx_sock_t *s) +{ + zabbix_log( LOG_LEVEL_DEBUG, "In child_trapper_main()"); + + zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Trapper]", i); + + DBconnect(ZBX_DB_CONNECT_NORMAL); + + for(;;) + { + zbx_setproctitle("waiting for connection"); + zbx_tcp_accept(s); + + zbx_setproctitle("processing data"); + process_trapper_child(s); + + zbx_tcp_unaccept(s); + } + DBclose(); +} + +/* +pid_t child_trapper_make(int i,int listenfd, int addrlen) +{ + pid_t pid; + + if((pid = zbx_fork()) >0) + { + return (pid); + } + + child_trapper_main(i, listenfd, addrlen); + + return 0; +}*/ diff --git a/src/zabbix_proxy/trapper/trapper.h b/src/zabbix_proxy/trapper/trapper.h new file mode 100644 index 00000000..3e3b543d --- /dev/null +++ b/src/zabbix_proxy/trapper/trapper.h @@ -0,0 +1,31 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + +#ifndef ZABBIX_TRAPPER_H +#define ZABBIX_TRAPPER_H + +extern int server_num; + +extern int CONFIG_TIMEOUT; + +extern void signal_handler( int sig ); + +void child_trapper_main(int i, zbx_sock_t *s); + +#endif diff --git a/src/zabbix_proxy/zlog.c b/src/zabbix_proxy/zlog.c new file mode 100644 index 00000000..a3071662 --- /dev/null +++ b/src/zabbix_proxy/zlog.c @@ -0,0 +1,92 @@ +/* +** ZABBIX +** Copyright (C) 2000-2005 SIA Zabbix +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +**/ + + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <syslog.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <time.h> + +#include "common.h" +#include "functions.h" +#include "log.h" +#include "zlog.h" + +/****************************************************************************** + * * + * Function: zabbix_syslog * + * * + * Purpose: save internal warning or error message in item zabbix[log] * + * * + * Parameters: va_list arguments * + * * + * Return value: * + * * + * Author: Alexei Vladishev * + * * + * Comments: do nothing if no zabbix[log] items * + * * + ******************************************************************************/ +void __zbx_zabbix_syslog(const char *fmt, ...) +{ + va_list ap; + char value_str[MAX_STRING_LEN]; + + DB_ITEM item; + DB_RESULT result; + DB_ROW row; + + AGENT_RESULT agent; + + zabbix_log(LOG_LEVEL_DEBUG, "In zabbix_log()"); + + /* This is made to disable writing to database for watchdog */ + if(CONFIG_ENABLE_LOG == 0) return; + + result = DBselect("select %s where h.hostid=i.hostid and i.key_='%s' and i.value_type=%d and" ZBX_COND_NODEID, + ZBX_SQL_ITEM_SELECT, + SERVER_ZABBIXLOG_KEY, + ITEM_VALUE_TYPE_STR, + LOCAL_NODE("h.hostid")); + + while((row=DBfetch(result))) + { + DBget_item_from_db(&item,row); + + va_start(ap,fmt); + vsnprintf(value_str,sizeof(value_str),fmt,ap); + value_str[MAX_STRING_LEN-1]=0; + va_end(ap); + + init_result(&agent); + SET_STR_RESULT(&agent, strdup(value_str)); + process_new_value(&item,&agent); + free_result(&agent); + + update_triggers(item.itemid); + } + + DBfree_result(result); +} |
