diff options
author | Vladimirs Maksimovs <vladimirs.maksimovs@zabbix.com> | 2022-01-05 15:23:12 +0300 |
---|---|---|
committer | Vladimirs Maksimovs <vladimirs.maksimovs@zabbix.com> | 2022-01-05 15:23:12 +0300 |
commit | a893912ab552fc44521662e22974b8586e984385 (patch) | |
tree | 4941370c95a81fdd799cc543bf56740cb210e894 | |
parent | 583678511bd86c1e53df42b34d6525bb2cdeb971 (diff) | |
parent | 6ce43839b8c77e8789cb3ddf3416b48228dcba8a (diff) |
.......... [ZBXNEXT-6470,ZBXNEXT-6890] updated to latest from master; no conflicts
69 files changed, 2342 insertions, 1034 deletions
diff --git a/ChangeLog.d/bugfix/ZBX-20143 b/ChangeLog.d/bugfix/ZBX-20143 new file mode 100644 index 00000000000..81c37f8226f --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-20143 @@ -0,0 +1 @@ +...G...... [ZBX-20143] fixed tcp timeout not working in net.dns.record (dgoloscapov) diff --git a/ChangeLog.d/bugfix/ZBX-20236 b/ChangeLog.d/bugfix/ZBX-20236 new file mode 100644 index 00000000000..69a60141c67 --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-20236 @@ -0,0 +1 @@ +...G...PS. [ZBX-20236] improved memory consumption in Zabbix proxy trappers by moving configuration sync between database and cache to configuration syncer; improved trappers and listeners memory consumption by freeing received data after it was processed instead of after new data is received (vso) diff --git a/ChangeLog.d/bugfix/ZBX-20292 b/ChangeLog.d/bugfix/ZBX-20292 new file mode 100644 index 00000000000..47d61cfe09e --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-20292 @@ -0,0 +1 @@ +........S. [ZBX-20292] fixed LLD overrides for item for particular corner-case (ssimonenko) diff --git a/ChangeLog.d/feature/ZBXNEXT-7109 b/ChangeLog.d/feature/ZBXNEXT-7109 new file mode 100644 index 00000000000..ab5210bf129 --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-7109 @@ -0,0 +1 @@ +.......PS. [ZBXNEXT-7109] changed runtime control options to connecto to zabbix server/proxy using socket rather than sending signals (wiper) diff --git a/configure.ac b/configure.ac index cd3f5475c93..fddcf42116b 100644 --- a/configure.ac +++ b/configure.ac @@ -2112,6 +2112,7 @@ AC_OUTPUT([ src/libs/zbxservice/Makefile src/libs/zbxxml/Makefile src/libs/zbxha/Makefile + src/libs/zbxrtc/Makefile src/zabbix_agent/Makefile src/zabbix_agent/logfiles/Makefile src/zabbix_get/Makefile diff --git a/database/mysql/Makefile.am b/database/mysql/Makefile.am index 6f7a78934ce..417096c245d 100644 --- a/database/mysql/Makefile.am +++ b/database/mysql/Makefile.am @@ -12,4 +12,5 @@ EXTRA_DIST = \ data.sql \ images.sql \ schema.sql \ - double.sql + double.sql \ + history_pk_prepare.sql diff --git a/database/oracle/Makefile.am b/database/oracle/Makefile.am index 992167c47ec..11bc82ceab1 100644 --- a/database/oracle/Makefile.am +++ b/database/oracle/Makefile.am @@ -12,4 +12,5 @@ EXTRA_DIST = \ data.sql \ images.sql \ schema.sql \ - double.sql + double.sql \ + history_pk_prepare.sql diff --git a/database/postgresql/Makefile.am b/database/postgresql/Makefile.am index 1b3eabb8c23..7fd2b92d657 100644 --- a/database/postgresql/Makefile.am +++ b/database/postgresql/Makefile.am @@ -17,4 +17,5 @@ EXTRA_DIST = \ images.sql \ schema.sql \ double.sql \ - $(DB_EXTENSION).sql + $(DB_EXTENSION).sql \ + history_pk_prepare.sql diff --git a/include/common.h b/include/common.h index 82b2c93f254..f947effcc57 100644 --- a/include/common.h +++ b/include/common.h @@ -982,6 +982,8 @@ typedef enum } zbx_task_t; +/* runtime control commands */ +#define ZBX_RTC_UNKNOWN 0 #define ZBX_RTC_LOG_LEVEL_INCREASE 1 #define ZBX_RTC_LOG_LEVEL_DECREASE 2 #define ZBX_RTC_HOUSEKEEPER_EXECUTE 3 @@ -996,6 +998,11 @@ zbx_task_t; #define ZBX_RTC_HA_SET_FAILOVER_DELAY 16 #define ZBX_RTC_USER_PARAMETERS_RELOAD 17 +/* runtime control notifications, must be less than 10000 */ +#define ZBX_RTC_CONFIG_SYNC_NOTIFY 9999 + +#define ZBX_IPC_RTC_MAX 9999 + typedef enum { HTTPTEST_AUTH_NONE = 0, @@ -1014,6 +1021,7 @@ typedef struct zbx_task_t task; unsigned int flags; int data; + char *opts; } ZBX_TASK_EX; diff --git a/include/daemon.h b/include/daemon.h index a0b7477e086..68a9ca3db1f 100644 --- a/include/daemon.h +++ b/include/daemon.h @@ -45,4 +45,7 @@ void zbx_set_sigusr_handler(void (*handler)(int flags)); #define START_MAIN_ZABBIX_ENTRY(allow_root, user, flags) daemon_start(allow_root, user, flags) +void zbx_signal_process_by_type(int proc_type, int proc_num, int flags, char **out); +void zbx_signal_process_by_pid(int pid, int flags, char **out); + #endif /* ZABBIX_DAEMON_H */ diff --git a/include/dbcache.h b/include/dbcache.h index 075d82e52a9..3a21af9e393 100644 --- a/include/dbcache.h +++ b/include/dbcache.h @@ -52,6 +52,10 @@ #define ZBX_SNMPTRAP_LOGGING_ENABLED 1 +#define ZBX_IPC_SERVICE_CONFIG "config" +#define ZBX_IPC_CONFIG_RELOAD_REQUEST 1 +#define ZBX_IPC_CONFIG_RELOAD_RESPONSE 2 + extern int CONFIG_TIMEOUT; extern zbx_uint64_t CONFIG_CONF_CACHE_SIZE; @@ -666,7 +670,8 @@ zbx_uint64_t DCget_nextid(const char *table_name, int num); #define ZBX_ITEM_GET_PROCESS (ZBX_ITEM_GET_MAINTENANCE|ZBX_ITEM_GET_MISC|ZBX_ITEM_GET_LOGTIMEFMT) -void DCsync_configuration(unsigned char mode, const struct zbx_json_parse *jp_kvs_paths); +void DCsync_configuration(unsigned char mode); +void DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths); int init_configuration_cache(char **error); void free_configuration_cache(void); @@ -740,7 +745,6 @@ int DCget_host_inventory_value_by_hostid(zbx_uint64_t hostid, char **replace_to, void *DCconfig_get_stats(int request); int DCconfig_get_last_sync_time(void); -void DCconfig_wait_sync(void); int DCconfig_get_proxypoller_hosts(DC_PROXY *proxies, int max_hosts); int DCconfig_get_proxypoller_nextcheck(void); diff --git a/include/log.h b/include/log.h index 4f2acba3a31..a7e3b08d358 100644 --- a/include/log.h +++ b/include/log.h @@ -85,4 +85,8 @@ void zbx_handle_log(void); int zbx_get_log_type(const char *logtype); int zbx_validate_log_parameters(ZBX_TASK_EX *task); +void zbx_strlog_alloc(int level, char **out, size_t *out_alloc, size_t *out_offset, const char *format, + ...) __zbx_attr_format_printf(5, 6); + + #endif diff --git a/include/proxy.h b/include/proxy.h index 246e47c6f0c..c1029fde9ad 100644 --- a/include/proxy.h +++ b/include/proxy.h @@ -44,7 +44,7 @@ int check_access_passive_proxy(zbx_socket_t *sock, int send_response, const char void update_proxy_lastaccess(const zbx_uint64_t hostid, time_t last_access); int get_proxyconfig_data(zbx_uint64_t proxy_hostid, struct zbx_json *j, char **error); -void process_proxyconfig(struct zbx_json_parse *jp_data); +int process_proxyconfig(struct zbx_json_parse *jp_data, struct zbx_json_parse *jp_kvs_paths); int get_interface_availability_data(struct zbx_json *json, int *ts); diff --git a/include/zbxdiag.h b/include/zbxdiag.h index e185b8f05bb..7b64a5acd5e 100644 --- a/include/zbxdiag.h +++ b/include/zbxdiag.h @@ -45,6 +45,6 @@ zbx_diaginfo_section_t; #define ZBX_DIAG_LOCKS "locks" int zbx_diag_get_info(const struct zbx_json_parse *jp, char **info); -void zbx_diag_log_info(unsigned int flags); +void zbx_diag_log_info(unsigned int flags, char **result); #endif diff --git a/include/zbxha.h b/include/zbxha.h index a8f6bc4fdf6..c59c257f8a1 100644 --- a/include/zbxha.h +++ b/include/zbxha.h @@ -22,19 +22,36 @@ #define ZBX_IPC_SERVICE_HA "haservice" -#define ZBX_IPC_SERVICE_HA_REGISTER 0 #define ZBX_IPC_SERVICE_HA_PAUSE 1 #define ZBX_IPC_SERVICE_HA_STOP 2 -#define ZBX_IPC_SERVICE_HA_UPDATE 3 +#define ZBX_IPC_SERVICE_HA_STATUS 3 #define ZBX_IPC_SERVICE_HA_GET_NODES 4 #define ZBX_IPC_SERVICE_HA_REMOVE_NODE 5 #define ZBX_IPC_SERVICE_HA_SET_FAILOVER_DELAY 6 -#define ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE 7 -#define ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE 8 -#define ZBX_IPC_SERVICE_HA_HEARTBEAT 9 +#define ZBX_IPC_SERVICE_HA_GET_FAILOVER_DELAY 7 +#define ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE 8 +#define ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE 9 + +#define ZBX_IPC_SERVICE_HA_RTC_FIRST (ZBX_IPC_RTC_MAX + 1) + +#define ZBX_IPC_SERVICE_HA_REGISTER ZBX_IPC_SERVICE_HA_RTC_FIRST +#define ZBX_IPC_SERVICE_HA_HEARTBEAT (ZBX_IPC_SERVICE_HA_RTC_FIRST + 1) +#define ZBX_IPC_SERVICE_HA_STATUS_UPDATE (ZBX_IPC_SERVICE_HA_RTC_FIRST + 2) #define ZBX_HA_SERVICE_TIMEOUT 10 +#define ZBX_NODE_STATUS_ERROR -2 +#define ZBX_NODE_STATUS_UNKNOWN -1 +#define ZBX_NODE_STATUS_STANDBY 0 +#define ZBX_NODE_STATUS_STOPPED 1 +#define ZBX_NODE_STATUS_UNAVAILABLE 2 +#define ZBX_NODE_STATUS_ACTIVE 3 + int zbx_ha_get_nodes(char **nodes, char **error); +int zbx_ha_remove_node(const char *node, char **result, char **error); +int zbx_ha_set_failover_delay(int delay, char **error); +int zbx_ha_get_failover_delay(int *delay, char **error); +int zbx_ha_change_loglevel(int direction, char **error); +const char *zbx_ha_status_str(int ha_status); #endif diff --git a/include/zbxjson.h b/include/zbxjson.h index 7f3790afa71..e0d27e63580 100644 --- a/include/zbxjson.h +++ b/include/zbxjson.h @@ -180,6 +180,12 @@ #define ZBX_PROTO_TAG_LASTACCESS "lastaccess" #define ZBX_PROTO_TAG_LASTACCESS_AGE "lastaccess_age" #define ZBX_PROTO_TAG_DB_TIMESTAMP "db_timestamp" +#define ZBX_PROTO_TAG_NODE "node" +#define ZBX_PROTO_TAG_FAILOVER_DELAY "failover_delay" +#define ZBX_PROTO_TAG_SECTION "section" +#define ZBX_PROTO_TAG_PID "pid" +#define ZBX_PROTO_TAG_PROCESS_NAME "process_name" +#define ZBX_PROTO_TAG_PROCESS_NUM "process_num" #define ZBX_PROTO_VALUE_FAILED "failed" #define ZBX_PROTO_VALUE_SUCCESS "success" diff --git a/include/zbxrtc.h b/include/zbxrtc.h new file mode 100644 index 00000000000..fb21a40341c --- /dev/null +++ b/include/zbxrtc.h @@ -0,0 +1,41 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#ifndef ZABBIX_ZBXRTC_H +#define ZABBIX_ZBXRTC_H + +#include "zbxipcservice.h" + +typedef struct +{ + zbx_ipc_service_t service; +} +zbx_rtc_t; + +/* provider API */ +int zbx_rtc_init(zbx_rtc_t *rtc ,char **error); +void zbx_rtc_dispatch(zbx_ipc_client_t *client, zbx_ipc_message_t *message); +void zbx_rtc_wait_config_sync(zbx_rtc_t *rtc); + +/* client API */ +int zbx_rtc_process(const char *option, char **error); +int zbx_rtc_open(zbx_ipc_async_socket_t *asocket, int timeout, char **error); +int zbx_rtc_notify_config_sync(char **error); + +#endif diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am index 0f7fd73fbc5..f985f86701e 100644 --- a/src/libs/Makefile.am +++ b/src/libs/Makefile.am @@ -39,7 +39,8 @@ DIST_SUBDIRS = \ zbxaudit \ zbxeval \ zbxxml \ - zbxha + zbxha \ + zbxrtc if SERVER SERVER_SUBDIRS = \ @@ -66,7 +67,8 @@ SERVER_SUBDIRS = \ zbxservice \ zbxaudit \ zbxeval \ - zbxha + zbxha \ + zbxrtc else if PROXY PROXY_SUBDIRS = \ @@ -90,7 +92,8 @@ PROXY_SUBDIRS = \ zbxtrends \ zbxavailability \ zbxaudit \ - zbxeval + zbxeval \ + zbxrtc endif endif diff --git a/src/libs/zbxcomms/comms.c b/src/libs/zbxcomms/comms.c index e9d28061d6a..2a56b617c12 100644 --- a/src/libs/zbxcomms/comms.c +++ b/src/libs/zbxcomms/comms.c @@ -1551,6 +1551,7 @@ void zbx_tcp_unaccept(zbx_socket_t *s) shutdown(s->socket, 2); + zbx_socket_free(s); zbx_socket_close(s->socket); s->socket = s->socket_orig; /* restore main socket */ diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c index 82c8b0d2c0d..cbd0a907f06 100644 --- a/src/libs/zbxdbcache/dbconfig.c +++ b/src/libs/zbxdbcache/dbconfig.c @@ -2136,13 +2136,13 @@ static void DCsync_hmacros(zbx_dbsync_t *sync) zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } -static int DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths) +void DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths) { zbx_dc_kvs_path_t *dc_kvs_path; zbx_dc_kv_t *dc_kv; zbx_hashset_t kvs; zbx_hashset_iter_t iter; - int i, j, ret; + int i, j; zbx_vector_ptr_pair_t diff; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -2157,14 +2157,8 @@ static int DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths) dc_kvs_path = (zbx_dc_kvs_path_t *)config->kvs_paths.values[i]; - if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) + if (NULL != jp_kvs_paths) { - if (NULL == jp_kvs_paths) - { - ret = FAIL; - goto fail; - } - if (FAIL == zbx_vault_json_kvs_get(dc_kvs_path->path, jp_kvs_paths, &kvs, &error)) { zabbix_log(LOG_LEVEL_WARNING, "cannot get secrets for path \"%s\": %s", @@ -2228,13 +2222,10 @@ static int DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths) zbx_vector_ptr_pair_clear(&diff); zbx_hashset_clear(&kvs); } - ret = SUCCEED; -fail: + zbx_vector_ptr_pair_destroy(&diff); zbx_hashset_destroy(&kvs); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); - - return ret; } /****************************************************************************** @@ -5941,7 +5932,7 @@ static void dc_load_trigger_queue(zbx_hashset_t *trend_functions) * Author: Alexander Vladishev, Aleksandrs Saveljevs * * * ******************************************************************************/ -void DCsync_configuration(unsigned char mode, const struct zbx_json_parse *jp_kvs_paths) +void DCsync_configuration(unsigned char mode) { int i, flags; double sec, csec, hsec, hisec, htsec, gmsec, hmsec, ifsec, isec, tsec, dsec, fsec, expr_sec, csec2, @@ -5970,12 +5961,6 @@ void DCsync_configuration(unsigned char mode, const struct zbx_json_parse *jp_kv config->sync_start_ts = time(NULL); - if (ZBX_SYNC_SECRETS == mode) - { - DCsync_kvs_paths(NULL); - goto skip; - } - zbx_dbsync_init_env(config); if (ZBX_DBSYNC_INIT == mode) @@ -6084,14 +6069,16 @@ void DCsync_configuration(unsigned char mode, const struct zbx_json_parse *jp_kv sec = zbx_time(); DCsync_host_tags(&host_tag_sync); host_tag_sec2 = zbx_time() - sec; - FINISH_SYNC; - if (FAIL == DCsync_kvs_paths(jp_kvs_paths)) + /* postpone configuration sync until macro secrets are received from Zabbix server */ + if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != config->kvs_paths.values_num && + ZBX_DBSYNC_INIT == mode) { - START_SYNC; goto out; } + FINISH_SYNC; + /* sync host data to support host lookups when resolving macros during configuration sync */ sec = zbx_time(); @@ -6682,7 +6669,7 @@ out: zbx_hashset_destroy(&trend_queue); zbx_dbsync_free_env(); -skip: + if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_TRACE)) DCdump_configuration(); @@ -9986,7 +9973,7 @@ static void DCagent_set_availability(zbx_agent_availability_t *av, unsigned cha if (dst != src) \ dst = src; \ else \ - flags &= (~(mask)); \ + flags &= (unsigned char)(~(mask)); \ } #define AGENT_AVAILABILITY_ASSIGN_STR(flags, mask, dst, src) \ @@ -9995,7 +9982,7 @@ static void DCagent_set_availability(zbx_agent_availability_t *av, unsigned cha if (0 != strcmp(dst, src)) \ DCstrpool_replace(1, &dst, src); \ else \ - flags &= (~(mask)); \ + flags &= (unsigned char)(~(mask)); \ } AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_AVAILABLE, *available, av->available); @@ -10750,14 +10737,6 @@ int DCconfig_get_last_sync_time(void) return config->sync_ts; } -void DCconfig_wait_sync(void) -{ - struct timespec ts = {0, 1e8}; - - while (0 == config->sync_ts) - nanosleep(&ts, NULL); -} - /****************************************************************************** * * * Function: DCconfig_get_proxypoller_hosts * diff --git a/src/libs/zbxdbhigh/proxy.c b/src/libs/zbxdbhigh/proxy.c index c2b156b78ca..59588f5ab11 100644 --- a/src/libs/zbxdbhigh/proxy.c +++ b/src/libs/zbxdbhigh/proxy.c @@ -1986,7 +1986,7 @@ out: * Purpose: update configuration * * * ******************************************************************************/ -void process_proxyconfig(struct zbx_json_parse *jp_data) +int process_proxyconfig(struct zbx_json_parse *jp_data, struct zbx_json_parse *jp_kvs_paths) { typedef struct { @@ -1997,7 +1997,7 @@ void process_proxyconfig(struct zbx_json_parse *jp_data) char buf[ZBX_TABLENAME_LEN_MAX]; const char *p = NULL; - struct zbx_json_parse jp_obj, jp_kvs_paths, *jp_kvs_paths_ptr = NULL; + struct zbx_json_parse jp_obj; char *error = NULL; int i, ret = SUCCEED; @@ -2023,8 +2023,7 @@ void process_proxyconfig(struct zbx_json_parse *jp_data) if (0 == strcmp(buf, "macro.secrets")) { - jp_kvs_paths = jp_obj; - jp_kvs_paths_ptr = &jp_kvs_paths; + *jp_kvs_paths = jp_obj; continue; } @@ -2086,20 +2085,17 @@ void process_proxyconfig(struct zbx_json_parse *jp_data) } zbx_vector_ptr_destroy(&tables_proxy); - if (SUCCEED != DBend(ret)) + if (SUCCEED != (ret = DBend(ret))) { zabbix_log(LOG_LEVEL_ERR, "failed to update local proxy configuration copy: %s", (NULL == error ? "database error" : error)); } - else - { - DCsync_configuration(ZBX_DBSYNC_UPDATE, jp_kvs_paths_ptr); - DCupdate_interfaces_availability(); - } zbx_free(error); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); + + return ret; } /****************************************************************************** diff --git a/src/libs/zbxdiag/diag.c b/src/libs/zbxdiag/diag.c index 18e983d16e5..a3e4997e0eb 100644 --- a/src/libs/zbxdiag/diag.c +++ b/src/libs/zbxdiag/diag.c @@ -697,7 +697,8 @@ static void diag_get_simple_values(const struct zbx_json_parse *jp, char **msg) * path - [OUT] the json path to the memory data * * * ******************************************************************************/ -static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, const char *path) +static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, const char *path, char **out, + size_t *out_alloc, size_t *out_offset) { struct zbx_json_parse jp_memory, jp_size, jp_chunks; char *msg = NULL; @@ -705,11 +706,11 @@ static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, c if (FAIL == zbx_json_open_path(jp, path, &jp_memory)) return; - zabbix_log(LOG_LEVEL_INFORMATION, "%s:", field); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s:", field); if (SUCCEED == zbx_json_brackets_by_name(&jp_memory, "size", &jp_size)) { diag_get_simple_values(&jp_size, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, " size: %s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, " size: %s", msg); zbx_free(msg); } @@ -718,21 +719,22 @@ static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, c struct zbx_json_parse jp_buckets, jp_bucket; diag_get_simple_values(&jp_chunks, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, " chunks: %s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, " chunks: %s", msg); zbx_free(msg); if (SUCCEED == zbx_json_brackets_by_name(&jp_chunks, "buckets", &jp_buckets)) { const char *pnext; - zabbix_log(LOG_LEVEL_INFORMATION, " buckets:"); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, " buckets:"); for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp_buckets, pnext));) { if (SUCCEED == zbx_json_brackets_open(pnext, &jp_bucket)) { diag_get_simple_values(&jp_bucket, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, " %s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, " %s", + msg); zbx_free(msg); } } @@ -746,12 +748,16 @@ static void diag_log_memory_info(struct zbx_json_parse *jp, const char *field, c * * * Purpose: log top view * * * - * Parameters: jp - [IN] the section json * - * field - [OUT] the top field name * - * path - [OUT] the json path to the top view * + * Parameters: jp - [IN] the section json * + * field - [OUT] the top field name * + * path - [OUT] the json path to the top view * + * out - [OUT] the output buffer (optional) * + * out_alloc - [OUT] the output buffer size * + * out_offset - [OUT] the output buffer offset * * * ******************************************************************************/ -static void diag_log_top_view(struct zbx_json_parse *jp, const char *field, const char *path) +static void diag_log_top_view(struct zbx_json_parse *jp, const char *field, const char *path, + char **out, size_t *out_alloc, size_t *out_offset) { struct zbx_json_parse jp_top, jp_row; const char *pnext; @@ -764,14 +770,14 @@ static void diag_log_top_view(struct zbx_json_parse *jp, const char *field, cons else if (FAIL == zbx_json_open_path(jp, path, &jp_top)) return; - zabbix_log(LOG_LEVEL_INFORMATION, "%s:", field); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s:", field); for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp_top, pnext));) { if (SUCCEED == zbx_json_brackets_open(pnext, &jp_row)) { diag_get_simple_values(&jp_row, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, " %s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, " %s", msg); zbx_free(msg); } } @@ -784,22 +790,22 @@ static void diag_log_top_view(struct zbx_json_parse *jp, const char *field, cons * Purpose: log history cache diagnostic information * * * ******************************************************************************/ -static void diag_log_history_cache(struct zbx_json_parse *jp) +static void diag_log_history_cache(struct zbx_json_parse *jp, char **out, size_t *out_alloc, size_t *out_offset) { char *msg = NULL; - zabbix_log(LOG_LEVEL_INFORMATION, "== history cache diagnostic information =="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "== history cache diagnostic information =="); diag_get_simple_values(jp, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s", msg); zbx_free(msg); - diag_log_memory_info(jp, "memory.data", "$.memory.data"); - diag_log_memory_info(jp, "memory.index", "$.memory.index"); + diag_log_memory_info(jp, "memory.data", "$.memory.data", out, out_alloc, out_offset); + diag_log_memory_info(jp, "memory.index", "$.memory.index", out, out_alloc, out_offset); - diag_log_top_view(jp, "top.values", "$.top.values"); + diag_log_top_view(jp, "top.values", "$.top.values", out, out_alloc, out_offset); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "=="); } /****************************************************************************** @@ -809,22 +815,22 @@ static void diag_log_history_cache(struct zbx_json_parse *jp) * Purpose: log value cache diagnostic information * * * ******************************************************************************/ -static void diag_log_value_cache(struct zbx_json_parse *jp) +static void diag_log_value_cache(struct zbx_json_parse *jp, char **out, size_t *out_alloc, size_t *out_offset) { char *msg = NULL; - zabbix_log(LOG_LEVEL_INFORMATION, "== value cache diagnostic information =="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "== value cache diagnostic information =="); diag_get_simple_values(jp, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s", msg); zbx_free(msg); - diag_log_memory_info(jp, "memory", "$.memory"); + diag_log_memory_info(jp, "memory", "$.memory", out, out_alloc, out_offset); - diag_log_top_view(jp, "top.values", "$.top.values"); - diag_log_top_view(jp, "top.request.values", "$.top['request.values']"); + diag_log_top_view(jp, "top.values", "$.top.values", out, out_alloc, out_offset); + diag_log_top_view(jp, "top.request.values", "$.top['request.values']", out, out_alloc, out_offset); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "=="); } /****************************************************************************** @@ -834,20 +840,20 @@ static void diag_log_value_cache(struct zbx_json_parse *jp) * Purpose: log preprocessing diagnostic information * * * ******************************************************************************/ -static void diag_log_preprocessing(struct zbx_json_parse *jp) +static void diag_log_preprocessing(struct zbx_json_parse *jp, char **out, size_t *out_alloc, size_t *out_offset) { char *msg = NULL; - zabbix_log(LOG_LEVEL_INFORMATION, "== preprocessing diagnostic information =="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "== preprocessing diagnostic information =="); diag_get_simple_values(jp, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s", msg); zbx_free(msg); - diag_log_top_view(jp, "top.values", "$.top.values"); - diag_log_top_view(jp, "top.oldest.preproc.values", "$.top['oldest.preproc.values']"); + diag_log_top_view(jp, "top.values", "$.top.values", out, out_alloc, out_offset); + diag_log_top_view(jp, "top.oldest.preproc.values", "$.top['oldest.preproc.values']", out, out_alloc, out_offset); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "=="); } /****************************************************************************** @@ -858,19 +864,19 @@ static void diag_log_preprocessing(struct zbx_json_parse *jp) * * ******************************************************************************/ -static void diag_log_lld(struct zbx_json_parse *jp) +static void diag_log_lld(struct zbx_json_parse *jp, char **out, size_t *out_alloc, size_t *out_offset) { char *msg = NULL; - zabbix_log(LOG_LEVEL_INFORMATION, "== LLD diagnostic information =="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "== LLD diagnostic information =="); diag_get_simple_values(jp, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s", msg); zbx_free(msg); - diag_log_top_view(jp, "top.values", "$.top.values"); + diag_log_top_view(jp, "top.values", "$.top.values", out, out_alloc, out_offset); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "=="); } /****************************************************************************** @@ -880,20 +886,20 @@ static void diag_log_lld(struct zbx_json_parse *jp) * Purpose: log alerting diagnostic information * * * ******************************************************************************/ -static void diag_log_alerting(struct zbx_json_parse *jp) +static void diag_log_alerting(struct zbx_json_parse *jp, char **out, size_t *out_alloc, size_t *out_offset) { char *msg = NULL; - zabbix_log(LOG_LEVEL_INFORMATION, "== alerting diagnostic information =="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "== alerting diagnostic information =="); diag_get_simple_values(jp, &msg); - zabbix_log(LOG_LEVEL_INFORMATION, "%s", msg); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "%s", msg); zbx_free(msg); - diag_log_top_view(jp, "media.alerts", "$.top['media.alerts']"); - diag_log_top_view(jp, "source.alerts", "$.top['source.alerts']"); + diag_log_top_view(jp, "media.alerts", "$.top['media.alerts']", out, out_alloc, out_offset); + diag_log_top_view(jp, "source.alerts", "$.top['source.alerts']", out, out_alloc, out_offset); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "=="); } /****************************************************************************** @@ -905,11 +911,12 @@ static void diag_log_alerting(struct zbx_json_parse *jp) * Parameters: flags - [IN] flags describing section to log * * * ******************************************************************************/ -void zbx_diag_log_info(unsigned int flags) +void zbx_diag_log_info(unsigned int flags, char **result) { struct zbx_json j; struct zbx_json_parse jp; char *info = NULL; + size_t result_alloc = 0, result_offset = 0; zbx_json_init(&j, 1024); @@ -942,25 +949,30 @@ void zbx_diag_log_info(unsigned int flags) } if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) - diag_log_history_cache(&jp_section); + diag_log_history_cache(&jp_section, result, &result_alloc, &result_offset); else if (0 == strcmp(section, ZBX_DIAG_VALUECACHE)) - diag_log_value_cache(&jp_section); + diag_log_value_cache(&jp_section, result, &result_alloc, &result_offset); else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) - diag_log_preprocessing(&jp_section); + diag_log_preprocessing(&jp_section, result, &result_alloc, &result_offset); else if (0 == strcmp(section, ZBX_DIAG_LLD)) - diag_log_lld(&jp_section); + diag_log_lld(&jp_section, result, &result_alloc, &result_offset); else if (0 == strcmp(section, ZBX_DIAG_ALERTING)) - diag_log_alerting(&jp_section); + diag_log_alerting(&jp_section, result, &result_alloc, &result_offset); else if (0 == strcmp(section, ZBX_DIAG_LOCKS)) { - zabbix_log(LOG_LEVEL_INFORMATION, "== locks diagnostic information =="); - diag_log_top_view(&jp_section, ZBX_DIAG_LOCKS, NULL); - zabbix_log(LOG_LEVEL_INFORMATION, "=="); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, result, &result_alloc, &result_offset, + "== locks diagnostic information =="); + diag_log_top_view(&jp_section, ZBX_DIAG_LOCKS, NULL, result, &result_alloc, + &result_offset); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, result, &result_alloc, &result_offset, "=="); } } } else - zabbix_log(LOG_LEVEL_INFORMATION, "cannot obtain diagnostic information: %s", info); + { + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, result, &result_alloc, &result_offset, + "cannot obtain diagnostic information: %s", info); + } out: zbx_free(info); zbx_json_free(&j); diff --git a/src/libs/zbxha/ha.c b/src/libs/zbxha/ha.c index e118273146b..759b39fe3ce 100644 --- a/src/libs/zbxha/ha.c +++ b/src/libs/zbxha/ha.c @@ -21,6 +21,7 @@ #include "zbxipcservice.h" #include "zbxserialize.h" #include "zbxha.h" +#include "log.h" /****************************************************************************** * * @@ -36,6 +37,8 @@ int zbx_ha_get_nodes(char **nodes, char **error) int ret; char *str; + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_GET_NODES, ZBX_HA_SERVICE_TIMEOUT, NULL, 0, &data, error)) { @@ -52,5 +55,141 @@ int zbx_ha_get_nodes(char **nodes, char **error) else *error = str; + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + return ret; } + +/****************************************************************************** + * * + * Function: zbx_ha_remove_node * + * * + * Purpose: remove HA node * + * * + * Comments: A new socket is opened to avoid interfering with notification * + * channel * + * * + ******************************************************************************/ +int zbx_ha_remove_node(const char *node, char **result, char **error) +{ + unsigned char *data, *ptr; + zbx_uint32_t error_len, result_len; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_REMOVE_NODE, + ZBX_HA_SERVICE_TIMEOUT, (const unsigned char *)node, (zbx_uint32_t)strlen(node) + 1, &data, error)) + { + return FAIL; + } + + ptr = data; + ptr += zbx_deserialize_str(ptr, result, result_len); + (void)zbx_deserialize_str(ptr, error, error_len); + zbx_free(data); + + return (0 == error_len ? SUCCEED : FAIL); +} + +/****************************************************************************** + * * + * Function: zbx_ha_set_failover_delay * + * * + * Purpose: set HA failover delay * + * * + * Comments: A new socket is opened to avoid interfering with notification * + * channel * + * * + ******************************************************************************/ +int zbx_ha_set_failover_delay(int delay, char **error) +{ + unsigned char *data; + zbx_uint32_t error_len; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_SET_FAILOVER_DELAY, + ZBX_HA_SERVICE_TIMEOUT, (unsigned char *)&delay, sizeof(delay), &data, error)) + { + return FAIL; + } + + (void)zbx_deserialize_str(data, error, error_len); + zbx_free(data); + + return (0 == error_len ? SUCCEED : FAIL); +} + +/****************************************************************************** + * * + * Function: zbx_ha_get_failover_delay * + * * + * Purpose: get HA failover delay * + * * + * Comments: A new socket is opened to avoid interfering with notification * + * channel * + * * + ******************************************************************************/ +int zbx_ha_get_failover_delay(int *delay, char **error) +{ + unsigned char *data; + + if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_GET_FAILOVER_DELAY, + ZBX_HA_SERVICE_TIMEOUT, NULL, 0, &data, error)) + { + return FAIL; + } + + memcpy(delay, data, sizeof(*delay)); + zbx_free(data); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_ha_change_loglevel * + * * + * Purpose: change HA manager log level * + * * + ******************************************************************************/ +int zbx_ha_change_loglevel(int direction, char **error) +{ + int ret = FAIL; + zbx_uint32_t cmd; + unsigned char *result = NULL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + cmd = 0 < direction ? ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE : ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE; + + ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, cmd, ZBX_HA_SERVICE_TIMEOUT, NULL, 0, &result, error); + zbx_free(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_ha_status_str * + * * + * Purpose: get HA status in text format * + * * + ******************************************************************************/ +const char *zbx_ha_status_str(int ha_status) +{ + switch (ha_status) + { + case ZBX_NODE_STATUS_STANDBY: + return "standby"; + case ZBX_NODE_STATUS_STOPPED: + return "stopped"; + case ZBX_NODE_STATUS_UNAVAILABLE: + return "unavailable"; + case ZBX_NODE_STATUS_ACTIVE: + return "active"; + case ZBX_NODE_STATUS_ERROR: + return "error"; + default: + return "unknown"; + } +} + diff --git a/src/libs/zbxlog/log.c b/src/libs/zbxlog/log.c index d6649f9093f..74508a22d2a 100644 --- a/src/libs/zbxlog/log.c +++ b/src/libs/zbxlog/log.c @@ -678,3 +678,53 @@ char *strerror_from_module(unsigned long error, const wchar_t *module) return utf8_string; } #endif /* _WINDOWS */ + +/****************************************************************************** + * * + * Function: zbx_strlog_alloc * + * * + * Purpose: log the message optionally appending to a string buffer * + * * + * Parameters: lebel - [IN] the log level * + * out - [OUT] the output buffer (optional) * + * out_alloc - [OUT] the output buffer size * + * out_offset - [OUT] the output buffer offset * + * format - [IN] the format string * + * * + * Return value: SUCCEED - the socket was successfully opened * + * FAIL - otherwise * + * * + ******************************************************************************/ +void zbx_strlog_alloc(int level, char **out, size_t *out_alloc, size_t *out_offset, const char *format, ...) +{ + va_list args; + size_t len; + char *buf; + + if (SUCCEED != ZBX_CHECK_LOG_LEVEL(level) && NULL == out) + return; + + va_start(args, format); + len = (size_t)vsnprintf(NULL, 0, format, args) + 2; + va_end(args); + + buf = (char *)zbx_malloc(NULL, len); + + va_start(args, format); + len = (size_t)vsnprintf(buf, len, format, args); + va_end(args); + + if (SUCCEED == ZBX_CHECK_LOG_LEVEL(level)) + zabbix_log(level, "%s", buf); + + if (NULL != out) + { + buf[0] = (char)toupper((unsigned char)buf[0]); + buf[len++] = '\n'; + buf[len] = '\0'; + + zbx_strcpy_alloc(out, out_alloc, out_offset, buf); + } + + zbx_free(buf); +} diff --git a/src/libs/zbxnix/control.c b/src/libs/zbxnix/control.c index ffd25a7c024..248103c1216 100644 --- a/src/libs/zbxnix/control.c +++ b/src/libs/zbxnix/control.c @@ -115,7 +115,6 @@ static int parse_log_level_options(const char *opt, size_t len, unsigned int *sc * message * * * * Parameters: opt - [IN] the command line argument * - * program_type - [IN] the program type * * message - [OUT] the message containing options for log * * level change or cache reload * * * @@ -123,7 +122,7 @@ static int parse_log_level_options(const char *opt, size_t len, unsigned int *sc * FAIL - an error occurred * * * ******************************************************************************/ -int parse_rtc_options(const char *opt, unsigned char program_type, int *message) +int parse_rtc_options(const char *opt, int *message) { unsigned int scope, data, command; @@ -141,145 +140,12 @@ int parse_rtc_options(const char *opt, unsigned char program_type, int *message) if (SUCCEED != parse_log_level_options(opt, ZBX_CONST_STRLEN(ZBX_LOG_LEVEL_DECREASE), &scope, &data)) return FAIL; } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER | ZBX_PROGRAM_TYPE_PROXY)) && - 0 == strcmp(opt, ZBX_CONFIG_CACHE_RELOAD)) - { - command = ZBX_RTC_CONFIG_CACHE_RELOAD; - scope = 0; - data = 0; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER | ZBX_PROGRAM_TYPE_PROXY)) && - 0 == strcmp(opt, ZBX_HOUSEKEEPER_EXECUTE)) - { - command = ZBX_RTC_HOUSEKEEPER_EXECUTE; - scope = 0; - data = 0; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER | ZBX_PROGRAM_TYPE_PROXY)) && - 0 == strcmp(opt, ZBX_SNMP_CACHE_RELOAD)) - { -#ifdef HAVE_NETSNMP - command = ZBX_RTC_SNMP_CACHE_RELOAD; - /* Scope is ignored for SNMP. R/U pollers, trapper, discoverer and taskmanager always get targeted. */ - scope = 0; - data = 0; -#else - zbx_error("invalid runtime control option: no SNMP support enabled"); - return FAIL; -#endif - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER | ZBX_PROGRAM_TYPE_PROXY)) && - 0 == strncmp(opt, ZBX_DIAGINFO, ZBX_CONST_STRLEN(ZBX_DIAGINFO))) - { - command = ZBX_RTC_DIAGINFO; - data = 0; - scope = ZBX_DIAGINFO_ALL; - - if ('=' == opt[ZBX_CONST_STRLEN(ZBX_DIAGINFO)]) - { - const char *section = opt + ZBX_CONST_STRLEN(ZBX_DIAGINFO) + 1; - - if (0 == strcmp(section, ZBX_DIAG_HISTORYCACHE)) - { - scope = ZBX_DIAGINFO_HISTORYCACHE; - } - else if (0 == strcmp(section, ZBX_DIAG_PREPROCESSING)) - { - scope = ZBX_DIAGINFO_PREPROCESSING; - } - else if (0 == strcmp(section, ZBX_DIAG_LOCKS)) - { - scope = ZBX_DIAGINFO_LOCKS; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER))) - { - if (0 == strcmp(section, ZBX_DIAG_VALUECACHE)) - scope = ZBX_DIAGINFO_VALUECACHE; - else if (0 == strcmp(section, ZBX_DIAG_LLD)) - scope = ZBX_DIAGINFO_LLD; - else if (0 == strcmp(section, ZBX_DIAG_ALERTING)) - scope = ZBX_DIAGINFO_ALERTING; - } - - if (0 == scope) - { - zbx_error("invalid diaginfo section: %s", section); - return FAIL; - } - } - else if ('\0' != opt[ZBX_CONST_STRLEN(ZBX_DIAGINFO)]) - { - zbx_error("invalid runtime control option: %s", opt); - return FAIL; - } - } - else if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 == strcmp(opt, ZBX_SECRETS_RELOAD)) - { - command = ZBX_RTC_SECRETS_RELOAD; - scope = 0; - data = 0; - } - else if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 == strcmp(opt, ZBX_SERVICE_CACHE_RELOAD)) - { - command = ZBX_RTC_SERVICE_CACHE_RELOAD; - scope = 0; - data = 0; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER)) && 0 == strcmp(opt, ZBX_TRIGGER_HOUSEKEEPER_EXECUTE)) - { - command = ZBX_RTC_TRIGGER_HOUSEKEEPER_EXECUTE; - scope = 0; - data = 0; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_AGENTD)) && 0 == strcmp(opt, ZBX_USER_PARAMETERS_RELOAD)) + else if (0 == strcmp(opt, ZBX_USER_PARAMETERS_RELOAD)) { command = ZBX_RTC_USER_PARAMETERS_RELOAD; scope = 0; data = 0; } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER)) && 0 == strcmp(opt, ZBX_HA_STATUS)) - { - command = ZBX_RTC_HA_STATUS; - scope = 0; - data = 0; - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER)) && - 0 == strncmp(opt, ZBX_HA_REMOVE_NODE, ZBX_CONST_STRLEN(ZBX_HA_REMOVE_NODE))) - { - command = ZBX_RTC_HA_REMOVE_NODE; - scope = 0; - if ('=' != opt[ZBX_CONST_STRLEN(ZBX_HA_REMOVE_NODE)] || - SUCCEED != is_uint32(opt + ZBX_CONST_STRLEN(ZBX_HA_REMOVE_NODE) + 1, &data)) - { - zbx_error("invalid HA node number: %s\n", opt); - return FAIL; - } - } - else if (0 != (program_type & (ZBX_PROGRAM_TYPE_SERVER)) && - 0 == strncmp(opt, ZBX_HA_SET_FAILOVER_DELAY, ZBX_CONST_STRLEN(ZBX_HA_SET_FAILOVER_DELAY))) - { - int delay; - - if ('=' == opt[ZBX_CONST_STRLEN(ZBX_HA_SET_FAILOVER_DELAY)] && - SUCCEED == is_time_suffix(opt + ZBX_CONST_STRLEN(ZBX_HA_SET_FAILOVER_DELAY) + 1, &delay, - ZBX_LENGTH_UNLIMITED)) - { - if (delay < 10 || delay > 15 * SEC_PER_MIN) - { - zbx_error("failover delay must be in range from 10s to 15m"); - return FAIL; - } - - command = ZBX_RTC_HA_SET_FAILOVER_DELAY; - scope = 0; - data = (unsigned int)delay; - } - else - { - zbx_error("invalid HA failover delay value: %s\n", opt); - return FAIL; - } - } else { zbx_error("invalid runtime control option: %s", opt); diff --git a/src/libs/zbxnix/control.h b/src/libs/zbxnix/control.h index 79e641a9fdd..8e851c9de3c 100644 --- a/src/libs/zbxnix/control.h +++ b/src/libs/zbxnix/control.h @@ -26,6 +26,6 @@ #define ZBX_RTC_LOG_SCOPE_PROC 0 #define ZBX_RTC_LOG_SCOPE_PID 1 -int parse_rtc_options(const char *opt, unsigned char program_type, int *message); +int parse_rtc_options(const char *opt, int *message); #endif diff --git a/src/libs/zbxnix/daemon.c b/src/libs/zbxnix/daemon.c index 0b89460b190..44f781aa646 100644 --- a/src/libs/zbxnix/daemon.c +++ b/src/libs/zbxnix/daemon.c @@ -87,11 +87,12 @@ static void common_sigusr_handler(int flags) } } -static void zbx_signal_process_by_type(int proc_type, int proc_num, int flags) +void zbx_signal_process_by_type(int proc_type, int proc_num, int flags, char **out) { - int process_num, found = 0, i; + int process_num, found = 0, i, failed_num = 0; union sigval s; unsigned char process_type; + size_t out_alloc = 0, out_offset = 0; s.sival_ptr = NULL; s.ZBX_SIVAL_INT = flags; @@ -121,53 +122,70 @@ static void zbx_signal_process_by_type(int proc_type, int proc_num, int flags) " pid:%d", get_process_type_string(process_type), threads[i]); } else + { zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: %s", zbx_strerror(errno)); + failed_num++; + } } if (0 == found) { if (0 == proc_num) { - zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal:" + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot redirect signal:" " \"%s\" process does not exist", get_process_type_string(proc_type)); } else { - zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal:" + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot redirect signal:" " \"%s #%d\" process does not exist", get_process_type_string(proc_type), proc_num); } } + else + { + if (0 != failed_num) + *out = zbx_strdup(*out, "failed to redirect remote control signal(s)"); + } } -static void zbx_signal_process_by_pid(int pid, int flags) +void zbx_signal_process_by_pid(int pid, int flags, char **out) { union sigval s; - int i, found = 0; + int i, found = 0, failed_num = 0; + size_t out_alloc = 0, out_offset = 0; + s.sival_ptr = NULL; s.ZBX_SIVAL_INT = flags; for (i = 0; i < threads_num; i++) { - if (0 != pid && threads[i] != ZBX_RTC_GET_DATA(flags)) + if ((0 != pid && threads[i] != pid) || 0 == threads[i]) continue; found = 1; if (-1 != sigqueue(threads[i], SIGUSR1, s)) { - zabbix_log(LOG_LEVEL_DEBUG, "the signal was redirected to process pid:%d", - threads[i]); + zabbix_log(LOG_LEVEL_DEBUG, "the signal was redirected to process pid:%d", threads[i]); } else + { zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: %s", zbx_strerror(errno)); + failed_num++; + } } - if (0 != ZBX_RTC_GET_DATA(flags) && 0 == found) + if (0 != pid && 0 == found) + { + zbx_strlog_alloc(LOG_LEVEL_DEBUG, out, &out_alloc, &out_offset, + "cannot redirect signal: process pid:%d is not a Zabbix child process", pid); + } + else { - zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: process pid:%d is not a Zabbix child" - " process", ZBX_RTC_GET_DATA(flags)); + if (0 != failed_num) + *out = zbx_strdup(*out, "failed to redirect remote control signal(s)"); } } @@ -215,42 +233,28 @@ static void user1_signal_handler(int sig, siginfo_t *siginfo, void *context) return; } - switch (ZBX_RTC_GET_MSG(flags)) + if (0 == (program_type & ZBX_PROGRAM_TYPE_AGENTD)) { - case ZBX_RTC_CONFIG_CACHE_RELOAD: - if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY_PASSIVE)) - { - zabbix_log(LOG_LEVEL_WARNING, "forced reloading of the configuration cache" - " cannot be performed for a passive proxy"); - return; - } + zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: runtime control signals are supported only by agent"); + return; + } - if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER)) - { - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_SERVICEMAN, 1, - ZBX_RTC_MAKE_MESSAGE(ZBX_RTC_SERVICE_CACHE_RELOAD, 0, 0)); - } - ZBX_FALLTHROUGH; - case ZBX_RTC_SECRETS_RELOAD: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_CONFSYNCER, 1, flags); - break; - case ZBX_RTC_HOUSEKEEPER_EXECUTE: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_HOUSEKEEPER, 1, flags); - break; + switch (ZBX_RTC_GET_MSG(flags)) + { case ZBX_RTC_LOG_LEVEL_INCREASE: case ZBX_RTC_LOG_LEVEL_DECREASE: scope = ZBX_RTC_GET_SCOPE(flags); if ((ZBX_RTC_LOG_SCOPE_FLAG | ZBX_RTC_LOG_SCOPE_PID) == scope) { - zbx_signal_process_by_pid(ZBX_RTC_GET_DATA(flags), flags); + zbx_signal_process_by_pid(ZBX_RTC_GET_DATA(flags), flags, NULL); } else { if (scope < ZBX_PROCESS_TYPE_EXT_FIRST) { zbx_signal_process_by_type(ZBX_RTC_GET_SCOPE(flags), ZBX_RTC_GET_DATA(flags), - flags); + flags, NULL); } } @@ -259,22 +263,9 @@ static void user1_signal_handler(int sig, siginfo_t *siginfo, void *context) zbx_sigusr_handler(flags); break; - case ZBX_RTC_SNMP_CACHE_RELOAD: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_UNREACHABLE, ZBX_RTC_GET_DATA(flags), flags); - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_POLLER, ZBX_RTC_GET_DATA(flags), flags); - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_TRAPPER, ZBX_RTC_GET_DATA(flags), flags); - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_DISCOVERER, ZBX_RTC_GET_DATA(flags), flags); - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_TASKMANAGER, ZBX_RTC_GET_DATA(flags), flags); - break; - case ZBX_RTC_TRIGGER_HOUSEKEEPER_EXECUTE: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_PROBLEMHOUSEKEEPER, 1, flags); - break; - case ZBX_RTC_SERVICE_CACHE_RELOAD: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_SERVICEMAN, ZBX_RTC_GET_DATA(flags), flags); - break; case ZBX_RTC_USER_PARAMETERS_RELOAD: - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_ACTIVE_CHECKS, ZBX_RTC_GET_DATA(flags), flags); - zbx_signal_process_by_type(ZBX_PROCESS_TYPE_LISTENER, ZBX_RTC_GET_DATA(flags), flags); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_ACTIVE_CHECKS, ZBX_RTC_GET_DATA(flags), flags, NULL); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_LISTENER, ZBX_RTC_GET_DATA(flags), flags, NULL); break; default: if (NULL != zbx_sigusr_handler) @@ -453,6 +444,7 @@ int zbx_sigusr_send(int flags) { union sigval s; + s.sival_ptr = NULL; s.ZBX_SIVAL_INT = flags; if (-1 != sigqueue(pid, SIGUSR1, s)) diff --git a/src/libs/zbxrtc/Makefile.am b/src/libs/zbxrtc/Makefile.am new file mode 100644 index 00000000000..a739d3868f6 --- /dev/null +++ b/src/libs/zbxrtc/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = \ + libzbxrtc.a \ + libzbxrtc_service.a \ + libzbxrtc_server.a \ + libzbxrtc_proxy.a + +# common rtc functionality + +libzbxrtc_a_SOURCES = \ + rtc.c \ + rtc.h + +# common rtc service functionality + +libzbxrtc_service_a_SOURCES = \ + rtc_service.c \ + rtc_client.c \ + rtc.h + +# server specific functionality + +libzbxrtc_server_a_SOURCES = \ + rtc_server.c \ + rtc.h + +# proxy specific functionality + +libzbxrtc_proxy_a_SOURCES = \ + rtc_proxy.c \ + rtc.h + diff --git a/src/libs/zbxrtc/rtc.c b/src/libs/zbxrtc/rtc.c new file mode 100644 index 00000000000..f333fd8d192 --- /dev/null +++ b/src/libs/zbxrtc/rtc.c @@ -0,0 +1,120 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "zbxipcservice.h" +#include "zbxjson.h" +#include "daemon.h" +#include "zbxrtc.h" +#include "rtc.h" +#include "log.h" +#include "zbxdiag.h" + +/****************************************************************************** + * * + * Function: zbx_rtc_parse_loglevel_option * + * * + * Purpose: parse loglevel runtime control option * + * * + * Parameters: opt - [IN] the runtime control option * + * len - [IN] the runtime control option length without * + * parameter * + * pid - [OUT] the target pid (if specified) * + * proc_type - [OUT] the target process type (if specified) * + * proc_num - [OUT] the target process num (if specified) * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - the runtime control option was processed * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_rtc_parse_loglevel_option(const char *opt, size_t len, pid_t *pid, int *proc_type, int *proc_num, + char **error) +{ + const char *rtc_options; + + rtc_options = opt + len; + + if ('\0' == *rtc_options) + return SUCCEED; + + if ('=' != *rtc_options) + { + *error = zbx_dsprintf(NULL, "invalid runtime control option \"%s\"", opt); + return FAIL; + } + else if (0 != isdigit(*(++rtc_options))) + { + /* convert PID */ + if (FAIL == is_uint32(rtc_options, pid) || 0 == *pid) + { + *error = zbx_dsprintf(NULL, "invalid log level control target -" + " invalid or unsupported process identifier"); + return FAIL; + } + } + else + { + char proc_name[MAX_STRING_LEN], *proc_num_ptr; + + if ('\0' == *rtc_options) + { + *error = zbx_dsprintf(NULL, "invalid log level control target -" + " unspecified process identifier or type"); + return FAIL; + } + + zbx_strlcpy(proc_name, rtc_options, sizeof(proc_name)); + + if (NULL != (proc_num_ptr = strchr(proc_name, ','))) + *proc_num_ptr++ = '\0'; + + if ('\0' == *proc_name) + { + *error = zbx_dsprintf(NULL, "invalid log level control target - unspecified process type"); + return FAIL; + } + + if (ZBX_PROCESS_TYPE_UNKNOWN == (*proc_type = get_process_type_by_name(proc_name))) + { + *error = zbx_dsprintf(NULL, "invalid log level control target - unknown process type \"%s\"", + proc_name); + return FAIL; + } + + if (NULL != proc_num_ptr) + { + if ('\0' == *proc_num_ptr) + { + *error = zbx_dsprintf(NULL, "invalid log level control target -" + " unspecified process number"); + return FAIL; + } + + /* convert Zabbix process number (e.g. "2" in "poller,2") */ + if (FAIL == is_uint32(proc_num_ptr, proc_num) || 0 == *proc_num) + { + *error = zbx_dsprintf(NULL, "invalid log level control target -" + " invalid or unsupported process number \"%s\"", proc_num_ptr); + return FAIL; + } + } + } + + return SUCCEED; +} diff --git a/src/zabbix_server/rtc.h b/src/libs/zbxrtc/rtc.h index 6926f627c74..57d67b55e4e 100644 --- a/src/zabbix_server/rtc.h +++ b/src/libs/zbxrtc/rtc.h @@ -20,6 +20,12 @@ #ifndef ZABBIX_RTC_H #define ZABBIX_RTC_H -void zbx_rtc_process_command(unsigned int command); +#define ZBX_IPC_SERVICE_RTC "rtc" + +int zbx_rtc_parse_loglevel_option(const char *opt, size_t len, pid_t *pid, int *proc_type, int *proc_num, + char **error); + +int rtc_parse_options_ex(const char *opt, zbx_uint32_t *code, char **data, char **error); +int rtc_process_request_ex(int code, const unsigned char *data, char **result); #endif diff --git a/src/libs/zbxrtc/rtc_client.c b/src/libs/zbxrtc/rtc_client.c new file mode 100644 index 00000000000..f5c6a698539 --- /dev/null +++ b/src/libs/zbxrtc/rtc_client.c @@ -0,0 +1,251 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "zbxipcservice.h" +#include "zbxjson.h" +#include "zbxrtc.h" +#include "rtc.h" + +extern int CONFIG_TIMEOUT; + +/****************************************************************************** + * * + * Function: rtc_parse_log_level_parameter * + * * + * Purpose: parse loglevel runtime control option * + * * + * Parameters: opt - [IN] the runtime control option * + * len - [IN] the runtime control option length without * + * parameter * + * data - [OUT] the runtime control option result * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the runtime control option was processed * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int rtc_parse_log_level_parameter(const char *opt, size_t len, char **data, char **error) +{ + struct zbx_json j; + const char *proc_name; + int pid = 0, proc_num = 0, proc_type = ZBX_PROCESS_TYPE_UNKNOWN; + + if (SUCCEED != zbx_rtc_parse_loglevel_option(opt, len, &pid, &proc_type, &proc_num, error)) + return FAIL; + + if (0 != pid) + { + zbx_json_init(&j, 1024); + zbx_json_addint64(&j, ZBX_PROTO_TAG_PID, pid); + goto finish; + } + + if (ZBX_PROCESS_TYPE_UNKNOWN == proc_type) + return SUCCEED; + + proc_name = get_process_type_string((unsigned char)proc_type); + + zbx_json_init(&j, 1024); + zbx_json_addstring(&j, ZBX_PROTO_TAG_PROCESS_NAME, proc_name, ZBX_JSON_TYPE_STRING); + + if (0 != proc_num) + zbx_json_addint64(&j, ZBX_PROTO_TAG_PROCESS_NUM, proc_num); + +finish: + *data = zbx_strdup(NULL, j.buffer); + zbx_json_clean(&j); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: rtc_parse_options * + * * + * Purpose: parse runtime control options and create a runtime control * + * message * + * * + * Parameters: opt - [IN] the command line argument * + * program_type - [IN] the program type * + * message - [OUT] the message containing options for log * + * level change or cache reload * + * * + * Return value: SUCCEED - the message was created successfully * + * FAIL - an error occurred * + * * + ******************************************************************************/ +static int rtc_parse_options(const char *opt, zbx_uint32_t *code, char **data, char **error) +{ + if (0 == strncmp(opt, ZBX_LOG_LEVEL_INCREASE, ZBX_CONST_STRLEN(ZBX_LOG_LEVEL_INCREASE))) + { + *code = ZBX_RTC_LOG_LEVEL_INCREASE; + + return rtc_parse_log_level_parameter(opt, ZBX_CONST_STRLEN(ZBX_LOG_LEVEL_INCREASE), data, error); + } + + if (0 == strncmp(opt, ZBX_LOG_LEVEL_DECREASE, ZBX_CONST_STRLEN(ZBX_LOG_LEVEL_DECREASE))) + { + *code = ZBX_RTC_LOG_LEVEL_DECREASE; + + return rtc_parse_log_level_parameter(opt, ZBX_CONST_STRLEN(ZBX_LOG_LEVEL_DECREASE), data, error); + } + + if (0 == strcmp(opt, ZBX_CONFIG_CACHE_RELOAD)) + { + *code = ZBX_RTC_CONFIG_CACHE_RELOAD; + return SUCCEED; + } + + if (0 == strcmp(opt, ZBX_HOUSEKEEPER_EXECUTE)) + { + *code = ZBX_RTC_HOUSEKEEPER_EXECUTE; + return SUCCEED; + } + + if (0 == strcmp(opt, ZBX_SNMP_CACHE_RELOAD)) + { +#ifdef HAVE_NETSNMP + *code = ZBX_RTC_SNMP_CACHE_RELOAD; + return SUCCEED; +#else + *error = zbx_strdup(NULL, "invalid runtime control option - no SNMP support enabled"); + return FAIL; +#endif + } + + if (0 == strncmp(opt, ZBX_DIAGINFO, ZBX_CONST_STRLEN(ZBX_DIAGINFO))) + { + const char *param = opt + ZBX_CONST_STRLEN(ZBX_DIAGINFO); + + if ('=' == *param) + param++; + else if ('\0' == *param) + param = "all"; + else + param = NULL; + + if (NULL != param) + { + struct zbx_json j; + + *code = ZBX_RTC_DIAGINFO; + + zbx_json_init(&j, 1024); + zbx_json_addstring(&j, ZBX_PROTO_TAG_SECTION, param, ZBX_JSON_TYPE_STRING); + *data = zbx_strdup(NULL, j.buffer); + zbx_json_clean(&j); + + return SUCCEED; + } + } + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_rtc_process * + * * + * Purpose: process runtime control option and print result * + * * + * Parameters: opt - [IN] the runtime control option * + * error - [OUT] error message * + * * + * Return value: SUCCEED - the runtime control option was processed * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_rtc_process(const char *option, char **error) +{ + zbx_uint32_t code = ZBX_RTC_UNKNOWN, size = 0; + char *data = NULL; + unsigned char *result = NULL; + int ret; + + if (SUCCEED != rtc_parse_options(option, &code, &data, error)) + return FAIL; + + if (ZBX_RTC_UNKNOWN == code) + { + if (SUCCEED != rtc_parse_options_ex(option, &code, &data, error)) + return FAIL; + + if (ZBX_RTC_UNKNOWN == code) + { + *error = zbx_dsprintf(NULL, "unknown option \"%s\"", option); + return FAIL; + } + } + + if (NULL != data) + size = (zbx_uint32_t)strlen(data) + 1; + + if (SUCCEED == (ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_RTC, code, CONFIG_TIMEOUT, (unsigned char *)data, + size, &result, error))) + { + if (NULL != result) + { + printf("%s", result); + zbx_free(result); + } + else + printf("No response\n"); + + } + + zbx_free(data); + + return ret; +} + +int zbx_rtc_open(zbx_ipc_async_socket_t *asocket, int timeout, char **error) +{ + if (FAIL == zbx_ipc_async_socket_open(asocket, ZBX_IPC_SERVICE_RTC, timeout, error)) + return FAIL; + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_rtc_notify_config_sync * + * * + * Purpose: notify RTC service about finishing initial configuration sync * + * * + * Parameters: error - [OUT] error message * + * * + * Return value: SUCCEED - the notification was sent successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_rtc_notify_config_sync(char **error) +{ + zbx_ipc_socket_t sock; + int ret; + + if (FAIL == zbx_ipc_socket_open(&sock, ZBX_IPC_SERVICE_RTC, CONFIG_TIMEOUT, error)) + return FAIL; + + if (FAIL == (ret = zbx_ipc_socket_write(&sock, ZBX_RTC_CONFIG_SYNC_NOTIFY, NULL, 0))) + *error = zbx_strdup(NULL, "failed to send message"); + + zbx_ipc_socket_close(&sock); + + return ret; +} diff --git a/src/libs/zbxrtc/rtc_proxy.c b/src/libs/zbxrtc/rtc_proxy.c new file mode 100644 index 00000000000..6a9b3096476 --- /dev/null +++ b/src/libs/zbxrtc/rtc_proxy.c @@ -0,0 +1,54 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "zbxipcservice.h" +#include "zbxrtc.h" +#include "rtc.h" +#include "proxy.h" + +extern int CONFIG_PROXYMODE; + +int rtc_parse_options_ex(const char *opt, zbx_uint32_t *code, char **data, char **error) +{ + ZBX_UNUSED(opt); + ZBX_UNUSED(code); + ZBX_UNUSED(data); + ZBX_UNUSED(error); + + return SUCCEED; +} + +int rtc_process_request_ex(int code, const unsigned char *data, char **result) +{ + ZBX_UNUSED(data); + + switch (code) + { + case ZBX_RTC_CONFIG_CACHE_RELOAD: + if (ZBX_PROXYMODE_PASSIVE == CONFIG_PROXYMODE) + { + *result = zbx_strdup(NULL, "Cannot perform configuration cache reloading on passive" + " proxy\n"); + return SUCCEED; + } + return FAIL; + } + + return FAIL; +} diff --git a/src/libs/zbxrtc/rtc_server.c b/src/libs/zbxrtc/rtc_server.c new file mode 100644 index 00000000000..76a638b4901 --- /dev/null +++ b/src/libs/zbxrtc/rtc_server.c @@ -0,0 +1,473 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "zbxipcservice.h" +#include "daemon.h" +#include "log.h" +#include "zbxdiag.h" +#include "zbxjson.h" +#include "zbxha.h" +#include "zbxrtc.h" +#include "rtc.h" + +int rtc_parse_options_ex(const char *opt, zbx_uint32_t *code, char **data, char **error) +{ + const char *param; + + if (0 == strcmp(opt, ZBX_SECRETS_RELOAD)) + { + *code = ZBX_RTC_SECRETS_RELOAD; + return SUCCEED; + } + + if (0 == strcmp(opt, ZBX_SERVICE_CACHE_RELOAD)) + { + *code = ZBX_RTC_SERVICE_CACHE_RELOAD; + return SUCCEED; + } + + if (0 == strcmp(opt, ZBX_TRIGGER_HOUSEKEEPER_EXECUTE)) + { + *code = ZBX_RTC_TRIGGER_HOUSEKEEPER_EXECUTE; + return SUCCEED; + } + + if (0 == strcmp(opt, ZBX_HA_STATUS)) + { + *code = ZBX_RTC_HA_STATUS; + return SUCCEED; + } + + if (0 == strncmp(opt, ZBX_HA_REMOVE_NODE, ZBX_CONST_STRLEN(ZBX_HA_REMOVE_NODE))) + { + param = opt + ZBX_CONST_STRLEN(ZBX_HA_REMOVE_NODE); + + if ('=' == *param) + { + struct zbx_json j; + + *code = ZBX_RTC_HA_REMOVE_NODE; + + zbx_json_init(&j, 1024); + zbx_json_addstring(&j, ZBX_PROTO_TAG_NODE, param + 1, ZBX_JSON_TYPE_STRING); + *data = zbx_strdup(NULL, j.buffer); + zbx_json_clean(&j); + + return SUCCEED; + } + + if ('\0' == *param) + { + *error = zbx_strdup(NULL, "missing node cuid or name parameter"); + return FAIL; + } + + /* not ha_remove_node runtime control option */ + } + + if (0 == strncmp(opt, ZBX_HA_SET_FAILOVER_DELAY, ZBX_CONST_STRLEN(ZBX_HA_SET_FAILOVER_DELAY))) + { + int delay; + + param = opt + ZBX_CONST_STRLEN(ZBX_HA_SET_FAILOVER_DELAY); + + if ('=' == *param) + { + if (SUCCEED == is_time_suffix(param + 1, &delay, ZBX_LENGTH_UNLIMITED)) + { + struct zbx_json j; + + if (delay < 10 || delay > 15 * SEC_PER_MIN) + { + *error = zbx_strdup(NULL, "failover delay must be in range from 10s to 15m"); + return FAIL; + } + + *code = ZBX_RTC_HA_SET_FAILOVER_DELAY; + + zbx_json_init(&j, 1024); + zbx_json_addint64(&j, ZBX_PROTO_TAG_FAILOVER_DELAY, delay); + *data = zbx_strdup(NULL, j.buffer); + zbx_json_clean(&j); + + return SUCCEED; + } + else + { + *error = zbx_dsprintf(NULL, "invalid HA failover delay parameter: %s\n", param + 1); + return FAIL; + } + } + + if ('\0' == *param) + { + *error = zbx_strdup(NULL, "missing failover delay parameter"); + return FAIL; + } + } + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: rtc_process_loglevel * + * * + * Purpose: process loglevel runtime control option * + * * + * Parameters: direction - [IN] the loglevel change direction: * + * (1) - increase, (-1) - decrease * + * data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + * Return value: SUCCEED - the loglevel command was processed * + * FAIL - the loglevel command must be processed by the * + * default loglevel command handler * + * * + ******************************************************************************/ +static int rtc_process_loglevel(int direction, const char *data, char **result) +{ + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + int process_num = 0; + + if (NULL == data) + { + (void)zbx_ha_change_loglevel(direction, result); + return FAIL; + } + + if (FAIL == zbx_json_open(data, &jp)) + { + *result = zbx_dsprintf(NULL, "Invalid parameters \"%s\"\n", data); + return SUCCEED; + } + + if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_PROCESS_NUM, buf, sizeof(buf), NULL)) + process_num = atoi(buf); + + if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_PROCESS_NAME, buf, sizeof(buf), NULL)) + { + return FAIL; + } + + if (0 == strcmp(buf, "ha manager")) + { + if (0 != process_num && 1 != process_num) + { + *result = zbx_dsprintf(NULL, "Invalid option parameter \"%d\"\n", process_num); + } + else + { + (void)zbx_ha_change_loglevel(direction, result); + *result = zbx_strdup(NULL, "Changed HA manager log level\n"); + + } + return SUCCEED; + } + + return FAIL; +} + + +/****************************************************************************** + * * + * Function: rtc_process_diaginfo * + * * + * Purpose: process diaginfo runtime control option * + * * + * Parameters: data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + ******************************************************************************/ +static void rtc_process_diaginfo(const char *data, char **result) +{ + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + unsigned int scope; + + if (FAIL == zbx_json_open(data, &jp) || + SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_SECTION, buf, sizeof(buf), NULL)) + { + *result = zbx_dsprintf(NULL, "Invalid parameter \"%s\"\n", data); + return; + } + + if (0 == strcmp(buf, "all")) + { + scope = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_PREPROCESSING) | + (1 << ZBX_DIAGINFO_LOCKS) | (1 << ZBX_DIAGINFO_VALUECACHE) | + (1 << ZBX_DIAGINFO_LLD) | (1 << ZBX_DIAGINFO_ALERTING); + } + else if (0 == strcmp(buf, ZBX_DIAG_HISTORYCACHE)) + scope = 1 << ZBX_DIAGINFO_HISTORYCACHE; + else if (0 == strcmp(buf, ZBX_DIAG_PREPROCESSING)) + scope = 1 << ZBX_DIAGINFO_PREPROCESSING; + else if (0 == strcmp(buf, ZBX_DIAG_LOCKS)) + scope = 1 << ZBX_DIAGINFO_LOCKS; + else if (0 == strcmp(buf, ZBX_DIAG_VALUECACHE)) + scope = 1 << ZBX_DIAGINFO_VALUECACHE; + else if (0 == strcmp(buf, ZBX_DIAG_LLD)) + scope = 1 << ZBX_DIAGINFO_LLD; + else if (0 == strcmp(buf, ZBX_DIAG_ALERTING)) + scope = 1 << ZBX_DIAGINFO_ALERTING; + else + return; + + zbx_diag_log_info(scope, result); +} + +/****************************************************************************** + * * + * Function: rtc_ha_status * + * * + * Purpose: process ha_status runtime command * + * * + ******************************************************************************/ +static void rtc_ha_status(char **out) +{ + char *nodes = NULL, *error = NULL; + struct zbx_json_parse jp, jp_node; + size_t out_alloc = 0, out_offset = 0; + int failover_delay; + + if (SUCCEED != zbx_ha_get_failover_delay(&failover_delay, &error)) + { + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot get failover delay: %s", + error); + zbx_free(error); + return; + } + + if (SUCCEED != zbx_ha_get_nodes(&nodes, &error)) + { + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot get HA node information: %s", + error); + zbx_free(error); + return; + } + +#define ZBX_HA_REPORT_FMT "%-25s %-25s %-30s %-11s %s" + + if (SUCCEED == zbx_json_open(nodes, &jp)) + { + const char *pnext; + char name[256], address[261], id[26], buffer[256]; + int status, lastaccess_age, index = 1; + + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, &out_alloc, &out_offset, "failover delay: %d seconds", + failover_delay); + + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, &out_alloc, &out_offset, "cluster status:"); + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, &out_alloc, &out_offset, " %2s " ZBX_HA_REPORT_FMT, "#", + "ID", "Name", "Address", "Status", "Last Access"); + + for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));) + { + if (FAIL == zbx_json_brackets_open(pnext, &jp_node)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_ID, id, sizeof(id), NULL)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_NAME, name, sizeof(name), + NULL)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_STATUS, buffer, + sizeof(buffer), NULL)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + status = atoi(buffer); + + if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_LASTACCESS_AGE, buffer, + sizeof(buffer), NULL)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + lastaccess_age = atoi(buffer); + + if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_ADDRESS, address, + sizeof(address), NULL)) + { + THIS_SHOULD_NEVER_HAPPEN; + continue; + } + + zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, &out_alloc, &out_offset, " %2d. " + ZBX_HA_REPORT_FMT, index++, id, '\0' != *name ? name : "<standalone server>", + address, zbx_ha_status_str(status), zbx_age2str(lastaccess_age)); + } + } + else + { + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "invalid response: %s", + nodes); + } + zbx_free(nodes); + +#undef ZBX_HA_REPORT_FMT +} + +/****************************************************************************** + * * + * Function: rtc_ha_remove_node * + * * + * Purpose: process ha_remove_node runtime command * + * * + ******************************************************************************/ +static void rtc_ha_remove_node(const char *data, char **out) +{ + char *error = NULL; + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + size_t out_alloc = 0, out_offset = 0; + + if (FAIL == zbx_json_open(data, &jp)) + { + *out = zbx_dsprintf(NULL, "Invalid parameter format \"%s\"\n", data); + return; + } + + if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_NODE, buf, sizeof(buf), NULL)) + { + *out = zbx_dsprintf(NULL, "Missing node parameter \"%s\"\n", data); + return; + } + + if (SUCCEED != zbx_ha_remove_node(buf, out, &error)) + { + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot remove HA node: %s", error); + zbx_free(error); + return; + } +} + +/****************************************************************************** + * * + * Function: rtc_ha_failover_delay * + * * + * Purpose: process ha_failover_delay runtime command * + * * + ******************************************************************************/ +static void rtc_ha_failover_delay(const char *data, char **out) +{ + char *error = NULL; + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + int failover_delay; + size_t out_alloc = 0, out_offset = 0; + + if (FAIL == zbx_json_open(data, &jp)) + { + *out = zbx_dsprintf(NULL, "Invalid parameter format \"%s\"\n", data); + return; + } + + if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_FAILOVER_DELAY, buf, sizeof(buf), NULL)) + { + *out = zbx_dsprintf(NULL, "Missing failover_delay parameter \"%s\"\n", data); + return; + } + + if (10 > (failover_delay = atoi(buf)) || 15 * SEC_PER_MIN < failover_delay) + { + *out = zbx_dsprintf(NULL, "Invalid failover delay value \"%s\"\n", buf); + return; + } + + if (SUCCEED != zbx_ha_set_failover_delay(failover_delay, &error)) + { + zbx_strlog_alloc(LOG_LEVEL_ERR, out, &out_alloc, &out_offset, "cannot set HA failover delay: %s", error); + zbx_free(error); + return; + } + + *out = zbx_dsprintf(NULL, "HA failover delay set to %d seconds\n", failover_delay); + +} +/****************************************************************************** + * * + * Function: rtc_process_request_ex * + * * + * Purpose: process runtime control option * + * * + * Parameters: code - [IN] the request code * + * data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + * Return value: SUCCEED - the rtc command was processed * + * FAIL - the rtc command must be processed by the default * + * rtc command handler * + * * + ******************************************************************************/ +int rtc_process_request_ex(int code, const unsigned char *data, char **result) +{ + ZBX_UNUSED(data); + + switch (code) + { + case ZBX_RTC_LOG_LEVEL_INCREASE: + return rtc_process_loglevel(1, (const char *)data, result); + case ZBX_RTC_LOG_LEVEL_DECREASE: + return rtc_process_loglevel(-1, (const char *)data, result); + case ZBX_RTC_CONFIG_CACHE_RELOAD: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_SERVICEMAN, 1, + ZBX_RTC_MAKE_MESSAGE(ZBX_RTC_SERVICE_CACHE_RELOAD, 0, 0), result); + return FAIL; + case ZBX_RTC_SERVICE_CACHE_RELOAD: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_SERVICEMAN, 1, + ZBX_RTC_MAKE_MESSAGE(ZBX_RTC_SERVICE_CACHE_RELOAD, 0, 0), result); + return SUCCEED; + case ZBX_RTC_SECRETS_RELOAD: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_CONFSYNCER, 1, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), + result); + return SUCCEED; + case ZBX_RTC_TRIGGER_HOUSEKEEPER_EXECUTE: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_PROBLEMHOUSEKEEPER, 1, + ZBX_RTC_MAKE_MESSAGE(code, 0, 0), result); + return SUCCEED; + case ZBX_RTC_DIAGINFO: + rtc_process_diaginfo((const char *)data, result); + return FAIL; + case ZBX_RTC_HA_STATUS: + rtc_ha_status(result); + return SUCCEED; + case ZBX_RTC_HA_SET_FAILOVER_DELAY: + rtc_ha_failover_delay((const char *)data, result); + return SUCCEED; + case ZBX_RTC_HA_REMOVE_NODE: + rtc_ha_remove_node((const char *)data, result); + return SUCCEED; + } + + return FAIL; +} diff --git a/src/libs/zbxrtc/rtc_service.c b/src/libs/zbxrtc/rtc_service.c new file mode 100644 index 00000000000..e7c61febecb --- /dev/null +++ b/src/libs/zbxrtc/rtc_service.c @@ -0,0 +1,342 @@ +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + +#include "zbxipcservice.h" +#include "zbxjson.h" +#include "daemon.h" +#include "zbxrtc.h" +#include "rtc.h" +#include "log.h" +#include "zbxdiag.h" + +/****************************************************************************** + * * + * Function: rtc_change_service_loglevel * + * * + * Purpose: change log level of service process * + * * + ******************************************************************************/ +static void rtc_change_service_loglevel(int code) +{ + if (ZBX_RTC_LOG_LEVEL_INCREASE == code) + { + if (SUCCEED != zabbix_increase_log_level()) + { + zabbix_log(LOG_LEVEL_INFORMATION, "cannot increase log level:" + " maximum level has been already set"); + } + else + { + zabbix_log(LOG_LEVEL_INFORMATION, "log level has been increased to %s", + zabbix_get_log_level_string()); + } + } + else + { + if (SUCCEED != zabbix_decrease_log_level()) + { + zabbix_log(LOG_LEVEL_INFORMATION, "cannot decrease log level:" + " minimum level has been already set"); + } + else + { + zabbix_log(LOG_LEVEL_INFORMATION, "log level has been decreased to %s", + zabbix_get_log_level_string()); + } + } +} + +/****************************************************************************** + * * + * Function: rtc_process_loglevel * + * * + * Purpose: process loglevel runtime control option * + * * + * Parameters: code - [IN] the runtime control request code * + * data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + ******************************************************************************/ +static void rtc_process_loglevel(int code, const char *data, char **result) +{ + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + int process_num = 0, process_type; + + if (NULL == data) + { + rtc_change_service_loglevel(code); + zbx_signal_process_by_pid(0, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), result); + return; + } + + if (FAIL == zbx_json_open(data, &jp)) + { + *result = zbx_dsprintf(NULL, "Invalid parameters \"%s\"\n", data); + return; + } + + if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_PID, buf, sizeof(buf), NULL)) + { + zbx_uint64_t pid; + + if (SUCCEED != is_uint64(buf, &pid) || 0 == pid) + { + *result = zbx_dsprintf(NULL, "Invalid pid value \"%s\"\n", buf); + return; + } + + if ((pid_t)pid == getpid()) + { + rtc_change_service_loglevel(code); + /* temporary message, the signal forwarding command output will be changed later */ + *result = zbx_strdup(NULL, "Changed log level for the main process\n"); + } + else + zbx_signal_process_by_pid((int)pid, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), result); + + return; + } + + if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_PROCESS_NUM, buf, sizeof(buf), NULL)) + process_num = atoi(buf); + + if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_PROCESS_NAME, buf, sizeof(buf), NULL)) + { + *result = zbx_dsprintf(NULL, "Invalid parameters \"%s\"\n", data); + return; + } + + if (ZBX_PROCESS_TYPE_UNKNOWN == (process_type = get_process_type_by_name(buf))) + { + *result = zbx_dsprintf(NULL, "Invalid parameters \"%s\"\n", data); + return; + } + + zbx_signal_process_by_type(process_type, process_num, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), result); +} + +/****************************************************************************** + * * + * Function: rtc_process_diaginfo * + * * + * Purpose: process diaginfo runtime control option * + * * + * Parameters: data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + ******************************************************************************/ +static void rtc_process_diaginfo(const char *data, char **result) +{ + struct zbx_json_parse jp; + char buf[MAX_STRING_LEN]; + unsigned int scope; + + if (FAIL == zbx_json_open(data, &jp) || + SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_SECTION, buf, sizeof(buf), NULL)) + { + *result = zbx_dsprintf(NULL, "Invalid parameters \"%s\"\n", data); + return; + } + + if (0 == strcmp(buf, "all")) + { + scope = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_PREPROCESSING) | (1 << ZBX_DIAGINFO_LOCKS); + } + else if (0 == strcmp(buf, ZBX_DIAG_HISTORYCACHE)) + { + scope = 1 << ZBX_DIAGINFO_HISTORYCACHE; + } + else if (0 == strcmp(buf, ZBX_DIAG_PREPROCESSING)) + { + scope = 1 << ZBX_DIAGINFO_PREPROCESSING; + } + else if (0 == strcmp(buf, ZBX_DIAG_LOCKS)) + { + scope = 1 << ZBX_DIAGINFO_LOCKS; + } + else + { + if (NULL == *result) + *result = zbx_dsprintf(NULL, "Unknown diaginfo section \"%s\"\n", buf); + return; + } + + zbx_diag_log_info(scope, result); +} + +/****************************************************************************** + * * + * Function: rtc_process_request * + * * + * Purpose: process runtime control option * + * * + * Parameters: code - [IN] the request code * + * data - [IN] the runtime control parameter (optional) * + * result - [OUT] the runtime control result * + * * + ******************************************************************************/ +static void rtc_process_request(int code, const unsigned char *data, char **result) +{ +#ifdef HAVE_NETSNMP + int cmd; + char *tmp = NULL; +#endif + + switch (code) + { + case ZBX_RTC_LOG_LEVEL_INCREASE: + case ZBX_RTC_LOG_LEVEL_DECREASE: + rtc_process_loglevel(code, (const char *)data, result); + return; + case ZBX_RTC_HOUSEKEEPER_EXECUTE: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_HOUSEKEEPER, 1, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), + result); + return; + case ZBX_RTC_CONFIG_CACHE_RELOAD: + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_CONFSYNCER, 1, ZBX_RTC_MAKE_MESSAGE(code, 0, 0), + result); + return; + case ZBX_RTC_SNMP_CACHE_RELOAD: +#ifdef HAVE_NETSNMP + cmd = ZBX_RTC_MAKE_MESSAGE(code, 0, 0); + + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_UNREACHABLE, 0, cmd, result); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_POLLER, 0, cmd, &tmp); + *result = zbx_strdcat(*result, tmp); + zbx_free(tmp); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_TRAPPER, 0, cmd, &tmp); + *result = zbx_strdcat(*result, tmp); + zbx_free(tmp); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_DISCOVERER, 0, cmd, &tmp); + *result = zbx_strdcat(*result, tmp); + zbx_free(tmp); + zbx_signal_process_by_type(ZBX_PROCESS_TYPE_TASKMANAGER, 0, cmd, &tmp); + *result = zbx_strdcat(*result, tmp); + zbx_free(tmp); +#else + *result = zbx_strdup(NULL, "Invalid runtime control option: no SNMP support enabled\n"); +#endif + return; + case ZBX_RTC_DIAGINFO: + rtc_process_diaginfo((const char *)data, result); + return; + default: + *result = zbx_strdup(*result, "Unknown runtime control option\n"); + } +} + +/****************************************************************************** + * * + * Function: zbx_rtc_init * + * * + * Purpose: initialize runtime control service * + * * + ******************************************************************************/ +int zbx_rtc_init(zbx_rtc_t *rtc ,char **error) +{ + return zbx_ipc_service_start(&rtc->service, ZBX_IPC_SERVICE_RTC, error); +} + +/****************************************************************************** + * * + * Function: zbx_rtc_dispatch * + * * + * Purpose: accept and process runtime control request * + * * + ******************************************************************************/ +void zbx_rtc_dispatch(zbx_ipc_client_t *client, zbx_ipc_message_t *message) +{ + char *result = NULL, *result_ex = NULL; + zbx_uint32_t size = 0; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() code:%u", __func__, message->code); + + if (FAIL == rtc_process_request_ex((int)message->code, message->data, &result_ex)) + rtc_process_request((int)message->code, message->data, &result); + + if (NULL != result_ex) + result = zbx_strdcat(result, result_ex); + + if (NULL == result) + { + /* generate default success message if no specific success or error messages were returned */ + result = zbx_strdup(NULL, "Runtime control command was forwarded successfully\n"); + } + + size = (zbx_uint32_t)strlen(result) + 1; + zbx_ipc_client_send(client, message->code, (unsigned char *)result, size); + zbx_free(result); + + zbx_free(result_ex); + zbx_free(result); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} + +/****************************************************************************** + * * + * Function: zbx_rtc_wait_config_sync * + * * + * Purpose: wait for configuration sync notification while optionally * + * dispatching runtime control commands * + * * + ******************************************************************************/ +void zbx_rtc_wait_config_sync(zbx_rtc_t *rtc) +{ + zbx_timespec_t rtc_timeout = {1, 0}; + int sync = 0; + + while (ZBX_IS_RUNNING() && 0 == sync) + { + zbx_ipc_client_t *client; + zbx_ipc_message_t *message; + + (void)zbx_ipc_service_recv(&rtc->service, &rtc_timeout, &client, &message); + + if (NULL != message) + { + switch (message->code) + { + case ZBX_RTC_CONFIG_SYNC_NOTIFY: + sync = 1; + break; + case ZBX_RTC_LOG_LEVEL_DECREASE: + case ZBX_RTC_LOG_LEVEL_INCREASE: + zbx_rtc_dispatch(client, message); + break; + default: + if (ZBX_IPC_RTC_MAX >= message->code) + { + const char *rtc_error = "Cannot perform specified runtime control" + " command during initial configuration cache sync\n"; + zbx_ipc_client_send(client, message->code, + (const unsigned char *)rtc_error, + (zbx_uint32_t)strlen(rtc_error) + 1); + } + } + zbx_ipc_message_free(message); + + } + + if (NULL != client) + zbx_ipc_client_release(client); + } +} + diff --git a/src/libs/zbxsysinfo/common/dns.c b/src/libs/zbxsysinfo/common/dns.c index 8b1281cd0d7..7e566cfb179 100644 --- a/src/libs/zbxsysinfo/common/dns.c +++ b/src/libs/zbxsysinfo/common/dns.c @@ -612,11 +612,11 @@ static int dns_query(AGENT_REQUEST *request, AGENT_RESULT *result, int short_ans if (1 == short_answer) { - SET_UI64_RESULT(result, NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res ? 0 : 1); + SET_UI64_RESULT(result, -1 == res || NOERROR != hp->rcode || 0 == ntohs(hp->ancount) ? 0 : 1); return SYSINFO_RET_OK; } - if (NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res) + if (-1 == res || NOERROR != hp->rcode || 0 == ntohs(hp->ancount)) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot perform DNS query.")); return SYSINFO_RET_FAIL; @@ -902,12 +902,40 @@ clean_dns: #endif /* defined(HAVE_RES_QUERY) || defined(_WINDOWS) || defined(__MINGW32__)*/ } -int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result) +static int dns_query_short(AGENT_REQUEST *request, AGENT_RESULT *result) { return dns_query(request, result, 1); } -int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result) +static int dns_query_long(AGENT_REQUEST *request, AGENT_RESULT *result) { return dns_query(request, result, 0); } + +static int dns_query_is_tcp(AGENT_REQUEST *request) +{ + char *param; + + if (NULL != (param = get_rparam(request, 5)) && 0 == strcmp(param, "tcp")) + return SUCCEED; + + return FAIL; +} + +int NET_DNS(AGENT_REQUEST *request, AGENT_RESULT *result) +{ +#if !defined(_WINDOWS) && !defined(__MINGW32__) + if (SUCCEED == dns_query_is_tcp(request)) + return zbx_execute_threaded_metric(dns_query_short, request, result); +#endif + return dns_query_short(request, result); +} + +int NET_DNS_RECORD(AGENT_REQUEST *request, AGENT_RESULT *result) +{ +#if !defined(_WINDOWS) && !defined(__MINGW32__) + if (SUCCEED == dns_query_is_tcp(request)) + return zbx_execute_threaded_metric(dns_query_long, request, result); +#endif + return dns_query_long(request, result); +} diff --git a/src/zabbix_agent/zabbix_agentd.c b/src/zabbix_agent/zabbix_agentd.c index 6583c540213..4163f66e049 100644 --- a/src/zabbix_agent/zabbix_agentd.c +++ b/src/zabbix_agent/zabbix_agentd.c @@ -365,7 +365,7 @@ static int parse_commandline(int argc, char **argv, ZBX_TASK_EX *t) break; #ifndef _WINDOWS case 'R': - if (SUCCEED != parse_rtc_options(zbx_optarg, program_type, &t->data)) + if (SUCCEED != parse_rtc_options(zbx_optarg, &t->data)) exit(EXIT_FAILURE); t->task = ZBX_TASK_RUNTIME_CONTROL; diff --git a/src/zabbix_proxy/Makefile.am b/src/zabbix_proxy/Makefile.am index e4320f7c2d4..5a6c77d98b9 100644 --- a/src/zabbix_proxy/Makefile.am +++ b/src/zabbix_proxy/Makefile.am @@ -77,6 +77,9 @@ zabbix_proxy_LDADD = \ $(top_builddir)/src/libs/zbxdb/libzbxdb.a \ $(top_builddir)/src/libs/zbxmodules/libzbxmodules.a \ $(top_builddir)/src/libs/zbxtasks/libzbxtasks.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc_service.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc_proxy.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc.a \ $(top_builddir)/src/libs/zbxdiag/libzbxdiag_proxy.a \ $(top_builddir)/src/libs/zbxcompress/libzbxcompress.a \ $(top_builddir)/src/libs/zbxtrends/libzbxtrends_baseline.a \ diff --git a/src/zabbix_proxy/proxy.c b/src/zabbix_proxy/proxy.c index 970d8840ecf..e0bfbf2f8ae 100644 --- a/src/zabbix_proxy/proxy.c +++ b/src/zabbix_proxy/proxy.c @@ -62,6 +62,7 @@ #include "zbxvault.h" #include "zbxdiag.h" #include "sighandler.h" +#include "zbxrtc.h" #ifdef HAVE_OPENIPMI #include "../zabbix_server/ipmi/ipmi_manager.h" @@ -155,7 +156,7 @@ ZBX_THREAD_LOCAL unsigned char process_type = ZBX_PROCESS_TYPE_UNKNOWN; ZBX_THREAD_LOCAL int process_num = 0; ZBX_THREAD_LOCAL int server_num = 0; -static int CONFIG_PROXYMODE = ZBX_PROXYMODE_ACTIVE; +int CONFIG_PROXYMODE = ZBX_PROXYMODE_ACTIVE; int CONFIG_DATASENDER_FORKS = 1; int CONFIG_DISCOVERER_FORKS = 1; int CONFIG_HOUSEKEEPER_FORKS = 1; @@ -316,8 +317,6 @@ int CONFIG_DOUBLE_PRECISION = ZBX_DB_DBL_PRECISION_ENABLED; zbx_vector_ptr_t zbx_addrs; -volatile sig_atomic_t zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; - int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num); int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num) @@ -529,7 +528,7 @@ static void zbx_set_defaults(void) if (ZBX_PROXYMODE_PASSIVE == CONFIG_PROXYMODE) { - CONFIG_CONFSYNCER_FORKS = CONFIG_DATASENDER_FORKS = 0; + CONFIG_DATASENDER_FORKS = 0; program_type = ZBX_PROGRAM_TYPE_PROXY_PASSIVE; } @@ -979,9 +978,7 @@ int main(int argc, char **argv) break; case 'R': opt_r++; - if (SUCCEED != parse_rtc_options(zbx_optarg, program_type, &t.data)) - exit(EXIT_FAILURE); - + t.opts = zbx_strdup(t.opts, zbx_optarg); t.task = ZBX_TASK_RUNTIME_CONTROL; break; case 'h': @@ -1034,23 +1031,27 @@ int main(int argc, char **argv) zbx_load_config(&t); if (ZBX_TASK_RUNTIME_CONTROL == t.task) - exit(SUCCEED == zbx_sigusr_send(t.data) ? EXIT_SUCCESS : EXIT_FAILURE); + { + int ret; + char *error = NULL; - return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); -} + if (FAIL == zbx_ipc_service_init_env(CONFIG_SOCKET_PATH, &error)) + { + zbx_error("cannot initialize IPC services: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } -static void zbx_main_sigusr_handler(int flags) -{ - if (ZBX_RTC_DIAGINFO == ZBX_RTC_GET_MSG(flags)) - { - int scope = ZBX_RTC_GET_SCOPE(flags); + if (SUCCEED != (ret = zbx_rtc_process(t.opts, &error))) + { + zbx_error("Cannot perform runtime control command: %s", error); + zbx_free(error); + } - if (ZBX_DIAGINFO_ALL == scope) - zbx_diaginfo_scope = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_PREPROCESSING) | - (1 << ZBX_DIAGINFO_LOCKS); - else - zbx_diaginfo_scope = 1 << scope; + exit(SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE); } + + return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); } static void zbx_check_db(void) @@ -1094,7 +1095,9 @@ int MAIN_ZABBIX_ENTRY(int flags) { zbx_socket_t listen_sock; char *error = NULL; - int i, db_type; + int i, db_type, ret; + zbx_rtc_t rtc; + zbx_timespec_t rtc_timeout = {1, 0}; if (0 != (flags & ZBX_TASK_FLAG_FOREGROUND)) { @@ -1197,6 +1200,13 @@ int MAIN_ZABBIX_ENTRY(int flags) zbx_free_config(); + if (SUCCEED != zbx_rtc_init(&rtc, &error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot initialize runtime control service: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } + if (SUCCEED != init_database_cache(&error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot initialize database cache: %s", error); @@ -1319,13 +1329,11 @@ int MAIN_ZABBIX_ENTRY(int flags) { case ZBX_PROCESS_TYPE_CONFSYNCER: zbx_thread_start(proxyconfig_thread, &thread_args, &threads[i]); - DCconfig_wait_sync(); + zbx_rtc_wait_config_sync(&rtc); break; case ZBX_PROCESS_TYPE_TRAPPER: thread_args.args = &listen_sock; zbx_thread_start(trapper_thread, &thread_args, &threads[i]); - if (0 == CONFIG_CONFSYNCER_FORKS) - DCconfig_wait_sync(); break; case ZBX_PROCESS_TYPE_HEARTBEAT: zbx_thread_start(heart_thread, &thread_args, &threads[i]); @@ -1402,23 +1410,36 @@ int MAIN_ZABBIX_ENTRY(int flags) } } - zbx_set_sigusr_handler(zbx_main_sigusr_handler); zbx_unset_exit_on_terminate(); - while (ZBX_IS_RUNNING() && -1 == wait(&i)) /* wait for any child to exit */ + while (ZBX_IS_RUNNING()) { - if (EINTR != errno) + zbx_ipc_client_t *client; + zbx_ipc_message_t *message; + + (void)zbx_ipc_service_recv(&rtc.service, &rtc_timeout, &client, &message); + + if (NULL != message) { - zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno)); + zbx_rtc_dispatch(client, message); + zbx_ipc_message_free(message); + } + + if (NULL != client) + zbx_ipc_client_release(client); + + if (0 < (ret = waitpid((pid_t)-1, &i, WNOHANG))) + { + zabbix_log(LOG_LEVEL_CRIT, "PROCESS EXIT: %d", ret); sig_exiting = ZBX_EXIT_FAILURE; break; } - /* check if the wait was interrupted because of diaginfo remote command */ - if (ZBX_DIAGINFO_UNDEFINED != zbx_diaginfo_scope) + if (-1 == ret && EINTR != errno) { - zbx_diag_log_info((unsigned int)zbx_diaginfo_scope); - zbx_diaginfo_scope = ZBX_DIAGINFO_UNDEFINED; + zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno)); + sig_exiting = ZBX_EXIT_FAILURE; + break; } } diff --git a/src/zabbix_proxy/proxyconfig/proxyconfig.c b/src/zabbix_proxy/proxyconfig/proxyconfig.c index 5a2c9061f50..5e209809681 100644 --- a/src/zabbix_proxy/proxyconfig/proxyconfig.c +++ b/src/zabbix_proxy/proxyconfig/proxyconfig.c @@ -27,6 +27,8 @@ #include "proxyconfig.h" #include "zbxcrypto.h" #include "zbxcompress.h" +#include "zbxrtc.h" +#include "zbxipcservice.h" #define CONFIG_PROXYCONFIG_RETRY 120 /* seconds */ @@ -61,7 +63,7 @@ static void zbx_proxyconfig_sigusr_handler(int flags) static void process_configuration_sync(size_t *data_size) { zbx_socket_t sock; - struct zbx_json_parse jp; + struct zbx_json_parse jp, jp_kvs_paths = {0}; char value[16], *error = NULL, *buffer = NULL; size_t buffer_size, reserved; struct zbx_json j; @@ -134,7 +136,15 @@ static void process_configuration_sync(size_t *data_size) zabbix_log(LOG_LEVEL_WARNING, "received configuration data from server at \"%s\", datalen " ZBX_FS_SIZE_T, sock.peer, (zbx_fs_size_t)*data_size); - process_proxyconfig(&jp); + if (SUCCEED == process_proxyconfig(&jp, &jp_kvs_paths)) + { + DCsync_configuration(ZBX_DBSYNC_UPDATE); + + if (NULL != jp_kvs_paths.start) + DCsync_kvs_paths(&jp_kvs_paths); + + DCupdate_interfaces_availability(); + } error: disconnect_server(&sock); out: @@ -162,8 +172,11 @@ out: ******************************************************************************/ ZBX_THREAD_ENTRY(proxyconfig_thread, args) { - size_t data_size; - double sec; + size_t data_size; + double sec; + zbx_ipc_service_t config_service; + char *error = NULL; + zbx_timespec_t timeout = {1, 0}; process_type = ((zbx_thread_args_t *)args)->process_type; server_num = ((zbx_thread_args_t *)args)->server_num; @@ -176,15 +189,62 @@ ZBX_THREAD_ENTRY(proxyconfig_thread, args) #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) zbx_tls_init_child(); #endif + + if (FAIL == zbx_ipc_service_start(&config_service, ZBX_IPC_SERVICE_CONFIG, &error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot start configuration syncer service: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } + zbx_setproctitle("%s [connecting to the database]", get_process_type_string(process_type)); DBconnect(ZBX_DB_CONNECT_NORMAL); zbx_setproctitle("%s [syncing configuration]", get_process_type_string(process_type)); - DCsync_configuration(ZBX_DBSYNC_INIT, NULL); + DCsync_configuration(ZBX_DBSYNC_INIT); + + if (SUCCEED != zbx_rtc_notify_config_sync(&error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot send configuration syncer notification: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } while (ZBX_IS_RUNNING()) { + if (ZBX_PROGRAM_TYPE_PROXY_PASSIVE == program_type) + { + zbx_ipc_client_t *client; + zbx_ipc_message_t *message; + + update_selfmon_counter(ZBX_PROCESS_STATE_IDLE); + zbx_ipc_service_recv(&config_service, &timeout, &client, &message); + update_selfmon_counter(ZBX_PROCESS_STATE_BUSY); + + sec = zbx_time(); + zbx_update_env(sec); + + if (NULL != message) + { + zbx_setproctitle("%s [loading configuration]", get_process_type_string(process_type)); + + DCsync_configuration(ZBX_DBSYNC_UPDATE); + DCupdate_interfaces_availability(); + + zbx_setproctitle("%s [synced config in " ZBX_FS_DBL " sec]", + get_process_type_string(process_type), zbx_time() - sec); + zbx_ipc_client_send(client, ZBX_IPC_CONFIG_RELOAD_RESPONSE, NULL, 0); + } + + zbx_ipc_message_free(message); + + if (NULL != client) + zbx_ipc_client_release(client); + + continue; + } + sec = zbx_time(); zbx_update_env(sec); diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am index f44884903d0..96e778f8b44 100644 --- a/src/zabbix_server/Makefile.am +++ b/src/zabbix_server/Makefile.am @@ -39,9 +39,7 @@ libzbxserver_a_SOURCES = \ operations.c \ operations.h \ postinit.c \ - postinit.h \ - rtc.c \ - rtc.h + postinit.h libzbxserver_a_CFLAGS = \ -DZABBIX_DAEMON \ @@ -120,6 +118,9 @@ zabbix_server_LDADD = \ $(top_builddir)/src/libs/zbxtrends/libzbxtrends.a \ $(top_builddir)/src/libs/zbxserver/libzbxserver_server.a \ $(top_builddir)/src/libs/zbxha/libzbxha.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc_service.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc_server.a \ + $(top_builddir)/src/libs/zbxrtc/libzbxrtc.a \ $(top_builddir)/src/libs/zbxvault/libzbxvault.a \ $(top_builddir)/src/libs/zbxavailability/libzbxavailability.a \ $(top_builddir)/src/libs/zbxaudit/libzbxaudit.a \ diff --git a/src/zabbix_server/dbconfig/dbconfig.c b/src/zabbix_server/dbconfig/dbconfig.c index 818a255dadb..e8c0f13761e 100644 --- a/src/zabbix_server/dbconfig/dbconfig.c +++ b/src/zabbix_server/dbconfig/dbconfig.c @@ -25,6 +25,7 @@ #include "log.h" #include "dbconfig.h" #include "dbcache.h" +#include "zbxrtc.h" extern int CONFIG_CONFSYNCER_FREQUENCY; extern ZBX_THREAD_LOCAL unsigned char process_type; @@ -80,6 +81,7 @@ ZBX_THREAD_ENTRY(dbconfig_thread, args) { double sec = 0.0; int nextcheck = 0; + char *error = NULL; process_type = ((zbx_thread_args_t *)args)->process_type; server_num = ((zbx_thread_args_t *)args)->server_num; @@ -98,9 +100,18 @@ ZBX_THREAD_ENTRY(dbconfig_thread, args) sec = zbx_time(); zbx_setproctitle("%s [syncing configuration]", get_process_type_string(process_type)); - DCsync_configuration(ZBX_DBSYNC_INIT, NULL); + DCsync_configuration(ZBX_DBSYNC_INIT); + DCsync_kvs_paths(NULL); zbx_setproctitle("%s [synced configuration in " ZBX_FS_DBL " sec, idle %d sec]", get_process_type_string(process_type), (sec = zbx_time() - sec), CONFIG_CONFSYNCER_FREQUENCY); + + if (SUCCEED != zbx_rtc_notify_config_sync(&error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot send configuration syncer notification: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } + zbx_sleep_loop(CONFIG_CONFSYNCER_FREQUENCY); while (ZBX_IS_RUNNING()) @@ -113,12 +124,13 @@ ZBX_THREAD_ENTRY(dbconfig_thread, args) if (1 == secrets_reload) { - DCsync_configuration(ZBX_SYNC_SECRETS, NULL); + DCsync_kvs_paths(NULL); secrets_reload = 0; } else { - DCsync_configuration(ZBX_DBSYNC_UPDATE, NULL); + DCsync_configuration(ZBX_DBSYNC_UPDATE); + DCsync_kvs_paths(NULL); DCupdate_interfaces_availability(); nextcheck = time(NULL) + CONFIG_CONFSYNCER_FREQUENCY; } diff --git a/src/zabbix_server/ha/ha.h b/src/zabbix_server/ha/ha.h index 277aa5c0981..c94ecf4c17f 100644 --- a/src/zabbix_server/ha/ha.h +++ b/src/zabbix_server/ha/ha.h @@ -21,14 +21,7 @@ #define ZABBIX_HA_H #include "common.h" - -#define ZBX_NODE_STATUS_UNINITIALIZED -3 -#define ZBX_NODE_STATUS_ERROR -2 -#define ZBX_NODE_STATUS_UNKNOWN -1 -#define ZBX_NODE_STATUS_STANDBY 0 -#define ZBX_NODE_STATUS_STOPPED 1 -#define ZBX_NODE_STATUS_UNAVAILABLE 2 -#define ZBX_NODE_STATUS_ACTIVE 3 +#include "zbxrtc.h" typedef struct { @@ -40,18 +33,13 @@ zbx_cuid_t; #define zbx_cuid_compare(a, b) (0 == memcmp((a).str, (b).str, CUID_LEN) ? SUCCEED : FAIL) #define zbx_cuid_clear(a) memset((a).str, 0, CUID_LEN) -int zbx_ha_start(char **error, int ha_status); +int zbx_ha_start(zbx_rtc_t *rtc, int ha_status, char **error); int zbx_ha_pause(char **error); int zbx_ha_stop(char **error); void zbx_ha_kill(void); -int zbx_ha_get_status(char **error); -int zbx_ha_recv_status(int timeout, int *ha_status, char **error); -int zbx_ha_get_nodes(char **nodes, char **error); -int zbx_ha_remove_node(int node_num, char **error); -int zbx_ha_set_failover_delay(int delay, char **error); -int zbx_ha_change_loglevel(int direction, char **error); +int zbx_ha_get_status(int *ha_status, char **error); +int zbx_ha_dispatch_message(zbx_ipc_message_t *message, int *ha_status, char **error); -const char *zbx_ha_status_str(int ha_status); int zbx_ha_check_pid(pid_t pid); #endif diff --git a/src/zabbix_server/ha/ha_manager.c b/src/zabbix_server/ha/ha_manager.c index ee6ef148d59..4b675f98f89 100644 --- a/src/zabbix_server/ha/ha_manager.c +++ b/src/zabbix_server/ha/ha_manager.c @@ -23,6 +23,7 @@ #include "zbxserialize.h" #include "threads.h" #include "zbxjson.h" +#include "mutexs.h" #include "../../libs/zbxalgo/vectorimpl.h" #include "../../libs/zbxaudit/audit.h" #include "../../libs/zbxaudit/audit_ha.h" @@ -37,7 +38,6 @@ #define ZBX_HA_NODE_LOCK 1 static pid_t ha_pid = ZBX_THREAD_ERROR; -static zbx_ipc_async_socket_t ha_socket; extern char *CONFIG_HA_NODE_NAME; extern char *CONFIG_NODE_ADDRESS; @@ -105,26 +105,67 @@ static int ha_db_execute(zbx_ha_info_t *info, const char *sql, ...) __zbx_attr_f /****************************************************************************** * * - * Function: ha_send_manager_message * + * Function: ha_manager_send_message * * * - * Purpose: send message to HA manager * + * Purpose: connect, send message and receive response in a given timeout * + * * + * Parameters: service_name - [IN] the IPC service name * + * code - [IN] the message code * + * timeout - [IN] time allowed to be spent on receive, note * + * that this does not include open, send and * + * flush that have their own timeouts * + * data - [IN] the data * + * size - [IN] the data size * + * out - [OUT] the received message or NULL on error * + * The message must be freed by zbx_free() * + * error - [OUT] the error message * + * * + * Return value: SUCCEED - successfully sent message and received response * + * or timeout occurred while waiting for response * + * FAIL - error occurred * * * ******************************************************************************/ -static int ha_send_manager_message(zbx_uint32_t code, char **error) +static int ha_manager_send_message(zbx_uint32_t code, int timeout, const unsigned char *data, zbx_uint32_t size, + unsigned char **out, char **error) { - if (FAIL == zbx_ipc_async_socket_send(&ha_socket, code, NULL, 0)) - { - *error = zbx_strdup(NULL, "cannot queue message to HA manager service"); + zbx_ipc_message_t *message; + zbx_ipc_async_socket_t asocket; + int ret = FAIL; + + if (FAIL == zbx_ipc_async_socket_open(&asocket, ZBX_IPC_SERVICE_HA, timeout, error)) return FAIL; + + if (FAIL == zbx_ipc_async_socket_send(&asocket, code, data, size)) + { + *error = zbx_strdup(NULL, "Cannot send request"); + goto out; } - if (FAIL == zbx_ipc_async_socket_flush(&ha_socket, ZBX_HA_SERVICE_TIMEOUT)) + if (FAIL == zbx_ipc_async_socket_flush(&asocket, timeout)) { - *error = zbx_strdup(NULL, "cannot send message to HA manager service"); - return FAIL; + *error = zbx_strdup(NULL, "Cannot flush request"); + goto out; } - return SUCCEED; + if (FAIL == zbx_ipc_async_socket_recv(&asocket, timeout, &message)) + { + *error = zbx_strdup(NULL, "Cannot receive response"); + goto out; + } + + if (NULL != message) + { + *out = message->data; + message->data = NULL; + zbx_ipc_message_free(message); + } + else + *out = NULL; + ret = SUCCEED; +out: + zbx_ipc_async_socket_close(&asocket); + + return ret; } /****************************************************************************** @@ -134,7 +175,7 @@ static int ha_send_manager_message(zbx_uint32_t code, char **error) * Purpose: update parent process with ha_status and failover delay * * * ******************************************************************************/ -static void ha_update_parent(zbx_ipc_client_t *client, zbx_ha_info_t *info) +static void ha_update_parent(zbx_ipc_async_socket_t *rtc_socket, zbx_ha_info_t *info) { zbx_uint32_t len = 0, error_len; unsigned char *ptr, *data; @@ -153,7 +194,9 @@ static void ha_update_parent(zbx_ipc_client_t *client, zbx_ha_info_t *info) ptr += zbx_serialize_value(ptr, info->failover_delay); (void)zbx_serialize_str(ptr, error, error_len); - ret = zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_UPDATE, data, len); + if (SUCCEED == (ret = zbx_ipc_async_socket_send(rtc_socket, ZBX_IPC_SERVICE_HA_STATUS_UPDATE, data, len))) + ret = zbx_ipc_async_socket_flush(rtc_socket, ZBX_HA_SERVICE_TIMEOUT); + zbx_free(data); if (SUCCEED != ret) @@ -172,9 +215,10 @@ static void ha_update_parent(zbx_ipc_client_t *client, zbx_ha_info_t *info) * Purpose: send heartbeat message to main process * * * ******************************************************************************/ -static void ha_send_heartbeat(zbx_ipc_client_t *client) +static void ha_send_heartbeat(zbx_ipc_async_socket_t *rtc_socket) { - if (SUCCEED != zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_HEARTBEAT, NULL, 0)) + if (SUCCEED != zbx_ipc_async_socket_send(rtc_socket, ZBX_IPC_SERVICE_HA_HEARTBEAT, NULL, 0) || + SUCCEED != zbx_ipc_async_socket_flush(rtc_socket, ZBX_HA_SERVICE_TIMEOUT)) { zabbix_log(LOG_LEVEL_CRIT, "cannot send HA heartbeat to main process"); exit(EXIT_FAILURE); @@ -942,7 +986,7 @@ static int ha_check_active_node(zbx_ha_info_t *info, zbx_vector_ha_node_t *nodes else info->offline_ticks_active++; - if (info->failover_delay / ZBX_HA_POLL_PERIOD + 1 < info->offline_ticks_active) + if (info->failover_delay / ZBX_HA_POLL_PERIOD < info->offline_ticks_active) { *unavailable_index = i; *ha_status = ZBX_NODE_STATUS_ACTIVE; @@ -1159,15 +1203,15 @@ out: /****************************************************************************** * * - * Function: ha_remove_node_by_index * + * Function: ha_remove_node_impl * * * - * Purpose: remove node by its index in node list * + * Purpose: remove node by its cuid or name * * * ******************************************************************************/ -static int ha_remove_node_by_index(zbx_ha_info_t *info, int index, char **error) +static int ha_remove_node_impl(zbx_ha_info_t *info, const char *node, char **result, char **error) { zbx_vector_ha_node_t nodes; - int ret = FAIL; + int i, ret = FAIL; if (ZBX_DB_OK > ha_db_begin(info)) { @@ -1183,22 +1227,35 @@ static int ha_remove_node_by_index(zbx_ha_info_t *info, int index, char **error) goto out; } - index--; + for (i = 0; i < nodes.values_num; i++) + { + if (0 == strcmp(node, nodes.values[i]->ha_nodeid.str)) + break; + } + + if (i == nodes.values_num) + { + for (i = 0; i < nodes.values_num; i++) + { + if (0 == strcmp(node, nodes.values[i]->name)) + break; + } + } - if (0 > index || index >= nodes.values_num) + if (i == nodes.values_num) { - *error = zbx_strdup(NULL, "node index out of range"); + *error = zbx_dsprintf(NULL, "unknown node \"%s\"", node); goto out; } - if (ZBX_NODE_STATUS_ACTIVE == nodes.values[index]->status || - ZBX_NODE_STATUS_STANDBY == nodes.values[index]->status) + if (ZBX_NODE_STATUS_ACTIVE == nodes.values[i]->status || ZBX_NODE_STATUS_STANDBY == nodes.values[i]->status) { - *error = zbx_dsprintf(NULL, "node is %s", zbx_ha_status_str(nodes.values[index]->status)); + *error = zbx_dsprintf(NULL, "node \"%s\" is %s", nodes.values[i]->name, + zbx_ha_status_str(nodes.values[i]->status)); goto out; } - if (SUCCEED != ha_db_execute(info, "delete from ha_node where ha_nodeid='%s'", nodes.values[index]->ha_nodeid.str)) + if (SUCCEED != ha_db_execute(info, "delete from ha_node where ha_nodeid='%s'", nodes.values[i]->ha_nodeid.str)) { *error = zbx_strdup(NULL, "database connection problem"); goto out; @@ -1206,8 +1263,8 @@ static int ha_remove_node_by_index(zbx_ha_info_t *info, int index, char **error) else { zbx_audit_init(info->auditlog); - zbx_audit_ha_create_entry(AUDIT_ACTION_DELETE, nodes.values[index]->ha_nodeid.str, - nodes.values[index]->name); + zbx_audit_ha_create_entry(AUDIT_ACTION_DELETE, nodes.values[i]->ha_nodeid.str, + nodes.values[i]->name); ha_flush_audit(info); } @@ -1217,8 +1274,11 @@ out: { if (ZBX_DB_OK <= ha_db_commit(info)) { - zabbix_log(LOG_LEVEL_WARNING, "removed node \"%s\" with ID \"%s\"", nodes.values[index]->name, - nodes.values[index]->ha_nodeid.str); + size_t result_alloc = 0, result_offset = 0; + + zbx_strlog_alloc(LOG_LEVEL_WARNING, result, &result_alloc, &result_offset, + "removed node \"%s\" with ID \"%s\"", nodes.values[i]->name, + nodes.values[i]->ha_nodeid.str); } } else @@ -1239,22 +1299,23 @@ out: ******************************************************************************/ static void ha_remove_node(zbx_ha_info_t *info, zbx_ipc_client_t *client, const zbx_ipc_message_t *message) { - int index; - char *error = NULL; - zbx_uint32_t len = 0, error_len; - unsigned char *data; + char *error = NULL, *result = NULL; + zbx_uint32_t len = 0, error_len, result_len; + unsigned char *data, *ptr; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - memcpy(&index, message->data, sizeof(index)); - - ha_remove_node_by_index(info, index, &error); + ha_remove_node_impl(info, (const char *)message->data, &result, &error); + zbx_serialize_prepare_str(len, result); zbx_serialize_prepare_str(len, error); - data = zbx_malloc(NULL, len); - zbx_serialize_str(data, error, error_len); + ptr = data = zbx_malloc(NULL, len); + ptr += zbx_serialize_str(ptr, result, result_len); + zbx_serialize_str(ptr, error, error_len); + zbx_free(error); + zbx_free(result); zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_REMOVE_NODE, data, len); zbx_free(data); @@ -1262,6 +1323,40 @@ static void ha_remove_node(zbx_ha_info_t *info, zbx_ipc_client_t *client, const zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } + +/****************************************************************************** + * * + * Function: ha_send_status * + * * + * Purpose: reply to ha_status request * + * * + ******************************************************************************/ +static void ha_send_status(zbx_ha_info_t *info, zbx_ipc_client_t *client) +{ + zbx_uint32_t len = 0, error_len; + unsigned char *ptr, *data; + const char *error = info->error; + int ret; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s() ha_status:%s info:%s", __func__, zbx_ha_status_str(info->ha_status), + ZBX_NULL2EMPTY_STR(info->error)); + + zbx_serialize_prepare_value(len, info->ha_status); + zbx_serialize_prepare_value(len, info->failover_delay); + zbx_serialize_prepare_str(len, error); + + ptr = data = (unsigned char *)zbx_malloc(NULL, len); + ptr += zbx_serialize_value(ptr, info->ha_status); + ptr += zbx_serialize_value(ptr, info->failover_delay); + (void)zbx_serialize_str(ptr, error, error_len); + + ret = zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_STATUS, data, len); + zbx_free(data); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_sysinfo_ret_string(ret)); +} + + /****************************************************************************** * * * Function: ha_set_failover_delay * @@ -1321,6 +1416,23 @@ out: /****************************************************************************** * * + * Function: ha_get_failover_delay * + * * + * Purpose: get failover delay * + * * + ******************************************************************************/ +static void ha_get_failover_delay(zbx_ha_info_t *info, zbx_ipc_client_t *client) +{ + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_GET_FAILOVER_DELAY, (const unsigned char *)&info->failover_delay, + (zbx_uint32_t)sizeof(info->failover_delay)); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); +} +/****************************************************************************** + * * * Function: ha_send_node_list * * * * Purpose: reply to get nodes request * @@ -1392,16 +1504,51 @@ out: * * * Function: zbx_ha_get_status * * * - * Purpose: requests HA manager to send status update * + * Purpose: get HA manager status * * * ******************************************************************************/ -int zbx_ha_get_status(char **error) +int zbx_ha_get_status(int *ha_status, char **error) { - int ret; + static time_t last_update; + static int ha_failover_delay = ZBX_HA_DEFAULT_FAILOVER_DELAY; + int ret; + unsigned char *result = NULL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - ret = ha_send_manager_message(ZBX_IPC_SERVICE_HA_UPDATE, error); + if (SUCCEED == (ret = ha_manager_send_message(ZBX_IPC_SERVICE_HA_STATUS, ZBX_HA_SERVICE_TIMEOUT, NULL, 0, + &result, error))) + { + if (NULL != result) + { + unsigned char *ptr = result; + zbx_uint32_t len; + + ptr += zbx_deserialize_value(ptr, ha_status); + ptr += zbx_deserialize_value(ptr, &ha_failover_delay); + (void)zbx_deserialize_str(ptr, error, len); + + zbx_free(result); + last_update = time(NULL); + + if (ZBX_NODE_STATUS_ERROR == *ha_status) + ret = FAIL; + } + else + { + time_t now; + + now = time(NULL); + + /* in the case of timeout switch status to standby if enough time has */ + /* passed since last successful update */ + if (ZBX_HA_IS_CLUSTER() && *ha_status == ZBX_NODE_STATUS_ACTIVE && 0 != last_update) + { + if (last_update + ha_failover_delay - ZBX_HA_POLL_PERIOD <= now || now < last_update) + *ha_status = ZBX_NODE_STATUS_STANDBY; + } + } + } zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -1410,7 +1557,7 @@ int zbx_ha_get_status(char **error) /****************************************************************************** * * - * Function: zbx_ha_recv_status * + * Function: zbx_ha_dispatch_message * * * * Purpose: handle HA manager notifications * * * @@ -1420,37 +1567,24 @@ int zbx_ha_get_status(char **error) * process to switch to standby mode and initiate teardown process * * * ******************************************************************************/ -int zbx_ha_recv_status(int timeout, int *ha_status, char **error) +int zbx_ha_dispatch_message(zbx_ipc_message_t *message, int *ha_status, char **error) { - zbx_ipc_message_t *message = NULL; - int ret = SUCCEED, ha_status_old; - time_t now; - static time_t last_hb; - static int ha_failover_delay = ZBX_HA_DEFAULT_FAILOVER_DELAY; + static time_t last_hb; + static int ha_failover_delay = ZBX_HA_DEFAULT_FAILOVER_DELAY; + int ret = SUCCEED, ha_status_old; + time_t now; + unsigned char *ptr; + zbx_uint32_t len; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - while (1) - { - unsigned char *ptr; - zbx_uint32_t len; - - if (SUCCEED != zbx_ipc_async_socket_recv(&ha_socket, timeout, &message)) - { - *ha_status = ZBX_NODE_STATUS_ERROR; - *error = zbx_strdup(NULL, "cannot receive message from HA manager service"); - ret = FAIL; - goto out; - } - - now = time(NULL); - - if (NULL == message) - break; + now = time(NULL); + if (NULL != message) + { switch (message->code) { - case ZBX_IPC_SERVICE_HA_UPDATE: + case ZBX_IPC_SERVICE_HA_STATUS_UPDATE: ha_status_old = *ha_status; ptr = message->data; @@ -1474,11 +1608,6 @@ int zbx_ha_recv_status(int timeout, int *ha_status, char **error) last_hb = now; break; } - - zbx_ipc_message_free(message); - - /* reset timeout for getting pending messages */ - timeout = 0; } if (ZBX_HA_IS_CLUSTER() && *ha_status == ZBX_NODE_STATUS_ACTIVE && 0 != last_hb) @@ -1487,77 +1616,25 @@ int zbx_ha_recv_status(int timeout, int *ha_status, char **error) *ha_status = ZBX_NODE_STATUS_STANDBY; } out: - zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); - return ret; } /****************************************************************************** * * - * Function: zbx_ha_remove_node * - * * - * Purpose: remove HA node * - * * - * Comments: A new socket is opened to avoid interfering with notification * - * channel * - * * - ******************************************************************************/ -int zbx_ha_remove_node(int node_num, char **error) -{ - unsigned char *data; - zbx_uint32_t error_len; - - if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_REMOVE_NODE, - ZBX_HA_SERVICE_TIMEOUT, (unsigned char *)&node_num, sizeof(node_num), &data, error)) - { - return FAIL; - } - - (void)zbx_deserialize_str(data, error, error_len); - zbx_free(data); - - return (0 == error_len ? SUCCEED : FAIL); -} - -/****************************************************************************** - * * - * Function: zbx_ha_set_failover_delay * - * * - * Purpose: set HA failover delay * - * * - * Comments: A new socket is opened to avoid interfering with notification * - * channel * - * * - ******************************************************************************/ -int zbx_ha_set_failover_delay(int delay, char **error) -{ - unsigned char *data; - zbx_uint32_t error_len; - - if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_SET_FAILOVER_DELAY, - ZBX_HA_SERVICE_TIMEOUT, (unsigned char *)&delay, sizeof(delay), &data, error)) - { - return FAIL; - } - - (void)zbx_deserialize_str(data, error, error_len); - zbx_free(data); - - return (0 == error_len ? SUCCEED : FAIL); -} - -/****************************************************************************** - * * * Function: zbx_ha_start * * * * Purpose: start HA manager * * * ******************************************************************************/ -int zbx_ha_start(char **error, int ha_status) +int zbx_ha_start(zbx_rtc_t *rtc, int ha_status, char **error) { - char *errmsg = NULL; int ret = FAIL; + zbx_uint32_t code = 0; zbx_thread_args_t args; + zbx_ipc_client_t *client; + zbx_ipc_message_t *message; + zbx_timespec_t rtc_timeout = {1, 0}; + time_t now, start; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -1570,29 +1647,42 @@ int zbx_ha_start(char **error, int ha_status) goto out; } - if (SUCCEED != zbx_ipc_async_socket_open(&ha_socket, ZBX_IPC_SERVICE_HA, ZBX_HA_SERVICE_TIMEOUT, &errmsg)) - { - *error = zbx_dsprintf(NULL, "cannot connect to HA manager process: %s", errmsg); - zbx_free(errmsg); - goto out; - } + start = now = time(NULL); - if (FAIL == zbx_ipc_async_socket_send(&ha_socket, ZBX_IPC_SERVICE_HA_REGISTER, NULL, 0)) + while (start + ZBX_HA_SERVICE_TIMEOUT > now) { - *error = zbx_dsprintf(NULL, "cannot queue message to HA manager service"); - goto out; + (void)zbx_ipc_service_recv(&rtc->service, &rtc_timeout, &client, &message); + + if (NULL != client) + zbx_ipc_client_release(client); + + if (NULL != message) + { + code = message->code; + zbx_ipc_message_free(message); + + if (ZBX_IPC_SERVICE_HA_REGISTER == code) + break; + } + + now = time(NULL); } - if (FAIL == zbx_ipc_async_socket_flush(&ha_socket, ZBX_HA_SERVICE_TIMEOUT)) + if (ZBX_IPC_SERVICE_HA_REGISTER != code) { - *error = zbx_dsprintf(NULL, "cannot send message to HA manager service"); + *error = zbx_strdup(NULL, "timeout while waiting for HA manager registration"); goto out; } ret = SUCCEED; out: if (SUCCEED != ret && ZBX_THREAD_ERROR != ha_pid) + { +#ifdef HAVE_PTHREAD_PROCESS_SHARED + zbx_locks_disable(); +#endif zbx_ha_kill(); + } zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -1610,11 +1700,14 @@ out: ******************************************************************************/ int zbx_ha_pause(char **error) { - int ret; + int ret; + unsigned char *result = NULL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - ret = ha_send_manager_message(ZBX_IPC_SERVICE_HA_PAUSE, error); + ret = zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_PAUSE, ZBX_HA_SERVICE_TIMEOUT, NULL, 0, + &result, error); + zbx_free(result); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -1632,7 +1725,8 @@ int zbx_ha_pause(char **error) ******************************************************************************/ int zbx_ha_stop(char **error) { - int ret = FAIL; + int ret = FAIL; + unsigned char *result = NULL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -1642,8 +1736,11 @@ int zbx_ha_stop(char **error) goto out; } - if (SUCCEED == ha_send_manager_message(ZBX_IPC_SERVICE_HA_STOP, error)) + if (SUCCEED == zbx_ipc_async_exchange(ZBX_IPC_SERVICE_HA, ZBX_IPC_SERVICE_HA_STOP, ZBX_HA_SERVICE_TIMEOUT, + NULL, 0, &result, error)) { + zbx_free(result); + if (ZBX_THREAD_ERROR == zbx_thread_wait(ha_pid)) { *error = zbx_dsprintf(NULL, "failed to wait for HA manager to exit: %s", zbx_strerror(errno)); @@ -1662,35 +1759,6 @@ out: /****************************************************************************** * * - * Function: zbx_ha_change_loglevel * - * * - * Purpose: change HA manager log level * - * * - ******************************************************************************/ -int zbx_ha_change_loglevel(int direction, char **error) -{ - int ret = FAIL; - zbx_uint32_t cmd; - - zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); - - if (ZBX_THREAD_ERROR == ha_pid) - { - *error = zbx_strdup(NULL, "HA manager has not been started"); - goto out; - } - - cmd = 0 < direction ? ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE : ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE; - - ret = ha_send_manager_message(cmd, error); -out: - zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); - - return ret; -} - -/****************************************************************************** - * * * Function: zbx_ha_kill * * * * Purpose: kill HA manager * @@ -1701,35 +1769,6 @@ void zbx_ha_kill(void) kill(ha_pid, SIGKILL); zbx_thread_wait(ha_pid); ha_pid = ZBX_THREAD_ERROR; - - if (SUCCEED == zbx_ipc_async_socket_connected(&ha_socket)) - zbx_ipc_async_socket_close(&ha_socket); -} - -/****************************************************************************** - * * - * Function: zbx_ha_status_str * - * * - * Purpose: get HA status in text format * - * * - ******************************************************************************/ -const char *zbx_ha_status_str(int ha_status) -{ - switch (ha_status) - { - case ZBX_NODE_STATUS_STANDBY: - return "standby"; - case ZBX_NODE_STATUS_STOPPED: - return "stopped"; - case ZBX_NODE_STATUS_UNAVAILABLE: - return "unavailable"; - case ZBX_NODE_STATUS_ACTIVE: - return "active"; - case ZBX_NODE_STATUS_ERROR: - return "error"; - default: - return "unknown"; - } } /****************************************************************************** @@ -1751,7 +1790,8 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) { zbx_ipc_service_t service; char *error = NULL; - zbx_ipc_client_t *client, *main_proc = NULL; + zbx_ipc_client_t *client; + zbx_ipc_async_socket_t rtc_socket; zbx_ipc_message_t *message; int pause = FAIL, stop = FAIL, ticks_num = 0, nextcheck; double now, tick; @@ -1769,6 +1809,20 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) exit(EXIT_FAILURE); } + if (FAIL == zbx_rtc_open(&rtc_socket, ZBX_HA_SERVICE_TIMEOUT, &error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot start HA manager service: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } + + if (FAIL == zbx_ipc_async_socket_send(&rtc_socket, ZBX_IPC_SERVICE_HA_REGISTER, NULL, 0) || + FAIL == zbx_ipc_async_socket_flush(&rtc_socket, ZBX_HA_SERVICE_TIMEOUT)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot register HA manager to runtime control service"); + exit(EXIT_FAILURE); + } + zbx_cuid_clear(info.ha_nodeid); info.name = ZBX_NULL2EMPTY_STR(CONFIG_HA_NODE_NAME); info.ha_status = (int)(uintptr_t)((zbx_thread_args_t *)args)->args; @@ -1789,6 +1843,8 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) goto pause; } + ha_update_parent(&rtc_socket, &info); + nextcheck = ZBX_HA_POLL_PERIOD; /* double the initial database check delay in standby mode to avoid the same node becoming active */ @@ -1813,11 +1869,8 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) else ha_check_nodes(&info); - if (NULL != main_proc) - { - if (old_status != info.ha_status && ZBX_NODE_STATUS_UNKNOWN != info.ha_status) - ha_update_parent(main_proc, &info); - } + if (old_status != info.ha_status && ZBX_NODE_STATUS_UNKNOWN != info.ha_status) + ha_update_parent(&rtc_socket, &info); if (ZBX_NODE_STATUS_ERROR == info.ha_status) break; @@ -1831,8 +1884,8 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) nextcheck += delay; } - if (NULL != main_proc && ZBX_DB_OK <= info.db_status) - ha_send_heartbeat(main_proc); + if (ZBX_DB_OK <= info.db_status) + ha_send_heartbeat(&rtc_socket); while (tick <= now) tick++; @@ -1847,16 +1900,15 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) { switch (message->code) { - case ZBX_IPC_SERVICE_HA_REGISTER: - main_proc = client; - break; - case ZBX_IPC_SERVICE_HA_UPDATE: - ha_update_parent(main_proc, &info); + case ZBX_IPC_SERVICE_HA_STATUS: + ha_send_status(&info, client); break; case ZBX_IPC_SERVICE_HA_STOP: - stop = SUCCEED; - ZBX_FALLTHROUGH; + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_STOP, NULL, 0); + pause = stop = SUCCEED; + break; case ZBX_IPC_SERVICE_HA_PAUSE: + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_PAUSE, NULL, 0); pause = SUCCEED; break; case ZBX_IPC_SERVICE_HA_GET_NODES: @@ -1867,7 +1919,10 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) break; case ZBX_IPC_SERVICE_HA_SET_FAILOVER_DELAY: ha_set_failover_delay(&info, client, message); - ha_update_parent(main_proc, &info); + ha_update_parent(&rtc_socket, &info); + break; + case ZBX_IPC_SERVICE_HA_GET_FAILOVER_DELAY: + ha_get_failover_delay(&info, client); break; case ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE: if (SUCCEED != zabbix_increase_log_level()) @@ -1880,6 +1935,7 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) zabbix_log(LOG_LEVEL_INFORMATION, "log level has been increased to %s", zabbix_get_log_level_string()); } + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_LOGLEVEL_INCREASE, NULL, 0); break; case ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE: if (SUCCEED != zabbix_decrease_log_level()) @@ -1892,6 +1948,7 @@ ZBX_THREAD_ENTRY(ha_manager_thread, args) zabbix_log(LOG_LEVEL_INFORMATION, "log level has been decreased to %s", zabbix_get_log_level_string()); } + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_LOGLEVEL_DECREASE, NULL, 0); break; } @@ -1918,15 +1975,16 @@ pause: { switch (message->code) { - case ZBX_IPC_SERVICE_HA_REGISTER: - main_proc = client; - break; - case ZBX_IPC_SERVICE_HA_UPDATE: - ha_update_parent(main_proc, &info); + case ZBX_IPC_SERVICE_HA_STATUS: + ha_send_status(&info, client); break; case ZBX_IPC_SERVICE_HA_STOP: + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_STOP, NULL, 0); stop = SUCCEED; break; + case ZBX_IPC_SERVICE_HA_PAUSE: + zbx_ipc_client_send(client, ZBX_IPC_SERVICE_HA_PAUSE, NULL, 0); + break; } zbx_ipc_message_free(message); @@ -1942,6 +2000,7 @@ pause: DBclose(); + zbx_ipc_async_socket_close(&rtc_socket); zbx_ipc_service_close(&service); zabbix_log(LOG_LEVEL_INFORMATION, "HA manager has been stopped"); diff --git a/src/zabbix_server/lld/lld.c b/src/zabbix_server/lld/lld.c index c55ff475975..b5995300683 100644 --- a/src/zabbix_server/lld/lld.c +++ b/src/zabbix_server/lld/lld.c @@ -978,7 +978,8 @@ void lld_override_graph(const zbx_vector_ptr_t *overrides, const char *name, uns zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); } -int lld_validate_item_override_no_discover(const zbx_vector_ptr_t *overrides, const char *name) +int lld_validate_item_override_no_discover(const zbx_vector_ptr_t *overrides, const char *name, + unsigned char override_default) { int i, j; @@ -995,16 +996,15 @@ int lld_validate_item_override_no_discover(const zbx_vector_ptr_t *overrides, co override_operation = (const zbx_lld_override_operation_t *)override->override_operations.values[j]; if (ZBX_LLD_OVERRIDE_OP_OBJECT_ITEM == override_operation->operationtype && - ZBX_PROTOTYPE_NO_DISCOVER == override_operation->discover && SUCCEED == regexp_strmatch_condition(name, override_operation->value, override_operation->operator)) { - return FAIL; + return ZBX_PROTOTYPE_NO_DISCOVER == override_operation->discover ? FAIL : SUCCEED; } } } - return SUCCEED; + return ZBX_PROTOTYPE_NO_DISCOVER == override_default ? FAIL : SUCCEED; } static int lld_rows_get(const char *value, lld_filter_t *filter, zbx_vector_ptr_t *lld_rows, diff --git a/src/zabbix_server/lld/lld.h b/src/zabbix_server/lld/lld.h index f0205fadbb5..b19b546aa2c 100644 --- a/src/zabbix_server/lld/lld.h +++ b/src/zabbix_server/lld/lld.h @@ -238,7 +238,8 @@ void lld_override_host(const zbx_vector_ptr_t *overrides, const char *name, zbx_ unsigned char *discover); void lld_override_graph(const zbx_vector_ptr_t *overrides, const char *name, unsigned char *discover); -int lld_validate_item_override_no_discover(const zbx_vector_ptr_t *overrides, const char *name); +int lld_validate_item_override_no_discover(const zbx_vector_ptr_t *overrides, const char *name, + unsigned char override_default); int lld_update_items(zbx_uint64_t hostid, zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *lld_rows, const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck); diff --git a/src/zabbix_server/lld/lld_item.c b/src/zabbix_server/lld/lld_item.c index edbd46a5b5d..61449dc40fd 100644 --- a/src/zabbix_server/lld/lld_item.c +++ b/src/zabbix_server/lld/lld_item.c @@ -2548,7 +2548,7 @@ static void lld_items_make(const zbx_vector_ptr_t *item_prototypes, zbx_vector_p if (0 == strcmp(item->key, buffer) && SUCCEED == lld_validate_item_override_no_discover(&lld_row->overrides, - item->name)) + item->name, item_prototype->discover)) { item_index_local.parent_itemid = item->parent_itemid; item_index_local.lld_row = lld_row; diff --git a/src/zabbix_server/poller/checks_internal_server.c b/src/zabbix_server/poller/checks_internal_server.c index e7c376f4eaa..5c9efac7699 100644 --- a/src/zabbix_server/poller/checks_internal_server.c +++ b/src/zabbix_server/poller/checks_internal_server.c @@ -22,7 +22,7 @@ #include "preproc.h" #include "zbxlld.h" #include "checks_internal.h" -#include "../ha/ha.h" +#include "zbxha.h" /****************************************************************************** * * diff --git a/src/zabbix_server/rtc.c b/src/zabbix_server/rtc.c deleted file mode 100644 index 6dc378abd32..00000000000 --- a/src/zabbix_server/rtc.c +++ /dev/null @@ -1,303 +0,0 @@ -/* -** Zabbix -** Copyright (C) 2001-2021 Zabbix SIA -** -** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - -#include "common.h" -#include "log.h" -#include "zbxdiag.h" -#include "ha/ha.h" -#include "../libs/zbxnix/control.h" -#include "rtc.h" - -/****************************************************************************** - * * - * Function: rtc_diaginfo * - * * - * Purpose: process diaginfo runtime command * - * * - ******************************************************************************/ -static void rtc_diaginfo(int scope) -{ - unsigned int flags; - - if (ZBX_DIAGINFO_ALL == scope) - { - flags = (1 << ZBX_DIAGINFO_HISTORYCACHE) | (1 << ZBX_DIAGINFO_VALUECACHE) | - (1 << ZBX_DIAGINFO_PREPROCESSING) | (1 << ZBX_DIAGINFO_LLD) | - (1 << ZBX_DIAGINFO_ALERTING) | (1 << ZBX_DIAGINFO_LOCKS); - } - else - flags = 1u << scope; - - zbx_diag_log_info(flags); -} - -/****************************************************************************** - * * - * Function: rtc_ha_status * - * * - * Purpose: process ha_status runtime command * - * * - ******************************************************************************/ -static void rtc_ha_status(void) -{ - char *nodes = NULL, *error = NULL; - struct zbx_json_parse jp, jp_node; - - if (SUCCEED != zbx_ha_get_nodes(&nodes, &error)) - { - zabbix_log(LOG_LEVEL_ERR, "cannot get HA node information: %s", error); - zbx_free(error); - return; - } - -#define ZBX_HA_REPORT_FMT "%-25s %-25s %-30s %-11s %s" - - if (SUCCEED == zbx_json_open(nodes, &jp)) - { - const char *pnext; - char name[256], address[261], id[26], buffer[256]; - int status, lastaccess_age, index = 1; - - zabbix_log(LOG_LEVEL_INFORMATION, "cluster status:"); - zabbix_log(LOG_LEVEL_INFORMATION, " %2s " ZBX_HA_REPORT_FMT, "#", "ID", "Name", - "Address", "Status", "Last Access"); - - for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));) - { - if (FAIL == zbx_json_brackets_open(pnext, &jp_node)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - - if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_ID, id, sizeof(id), NULL)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - - if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_NAME, name, sizeof(name), - NULL)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - - if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_STATUS, buffer, - sizeof(buffer), NULL)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - status = atoi(buffer); - - if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_LASTACCESS_AGE, buffer, - sizeof(buffer), NULL)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - lastaccess_age = atoi(buffer); - - if (SUCCEED != zbx_json_value_by_name(&jp_node, ZBX_PROTO_TAG_ADDRESS, address, - sizeof(address), NULL)) - { - THIS_SHOULD_NEVER_HAPPEN; - continue; - } - - zabbix_log(LOG_LEVEL_INFORMATION, " %2d. " ZBX_HA_REPORT_FMT, index++, id, - '\0' != *name ? name : "<standalone server>", - address, zbx_ha_status_str(status), zbx_age2str(lastaccess_age)); - } - } - zbx_free(nodes); - -#undef ZBX_HA_REPORT_FMT -} - -/****************************************************************************** - * * - * Function: rtc_remove_node * - * * - * Purpose: process ha_remove_node runtime command * - * * - ******************************************************************************/ -static void rtc_remove_node(int index) -{ - char *error = NULL; - - if (SUCCEED != zbx_ha_remove_node(index, &error)) - { - zabbix_log(LOG_LEVEL_ERR, "cannot remove HA node: %s", error); - zbx_free(error); - } -} - -/****************************************************************************** - * * - * Function: rtc_ha_failover_delay * - * * - * Purpose: process ha_failover_delay runtime command * - * * - ******************************************************************************/ -static void rtc_ha_failover_delay(int delay) -{ - char *error = NULL; - - if (SUCCEED != zbx_ha_set_failover_delay(delay, &error)) - { - zabbix_log(LOG_LEVEL_ERR, "cannot set HA failover delay: %s", error); - zbx_free(error); - } -} - -/****************************************************************************** - * * - * Function: rtc_change_loglevel_main * - * * - * Purpose: change log level of main process * - * * - ******************************************************************************/ -static void rtc_change_loglevel_main(int command) -{ - if (ZBX_RTC_LOG_LEVEL_INCREASE == command) - { - if (SUCCEED != zabbix_increase_log_level()) - { - zabbix_log(LOG_LEVEL_INFORMATION, "cannot increase log level:" - " maximum level has been already set"); - } - else - { - zabbix_log(LOG_LEVEL_INFORMATION, "log level has been increased to %s", - zabbix_get_log_level_string()); - } - } - else - { - if (SUCCEED != zabbix_decrease_log_level()) - { - zabbix_log(LOG_LEVEL_INFORMATION, "cannot decrease log level:" - " minimum level has been already set"); - } - else - { - zabbix_log(LOG_LEVEL_INFORMATION, "log level has been decreased to %s", - zabbix_get_log_level_string()); - } - } -} - -/****************************************************************************** - * * - * Function: rtc_change_loglevel_ha * - * * - * Purpose: change log level of HA manager * - * * - ******************************************************************************/ -static void rtc_change_loglevel_ha(int command) -{ - int direction; - char *error = NULL; - - direction = ZBX_RTC_LOG_LEVEL_INCREASE == command ? 1 : -1; - - if (SUCCEED != zbx_ha_change_loglevel(direction, &error)) - { - zabbix_log(LOG_LEVEL_WARNING, "cannot change HA manager log level: %s", error); - zbx_free(error); - } -} - -/****************************************************************************** - * * - * Function: rtc_change_loglevel * - * * - * Purpose: process log level changes affecting main/ha manager processes * - * * - ******************************************************************************/ -static void rtc_change_loglevel(int command, int scope, int data) -{ - if ((ZBX_RTC_LOG_SCOPE_FLAG | ZBX_RTC_LOG_SCOPE_PID) == scope) - { - if (0 == data || getpid() == (pid_t)data) - rtc_change_loglevel_main(command); - - if (0 == data || SUCCEED == zbx_ha_check_pid((pid_t)data)) - rtc_change_loglevel_ha(command); - return; - } - - if (ZBX_PROCESS_TYPE_MAIN == scope) - { - if (1 < data) - { - zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: \"%s #%d\" process does not exist", - get_process_type_string((unsigned char)scope), data); - } - else - rtc_change_loglevel_main(command); - } - else if (ZBX_PROCESS_TYPE_HA_MANAGER == scope) - { - if (1 < data) - { - zabbix_log(LOG_LEVEL_ERR, "cannot redirect signal: \"%s #%d\" process does not exist", - get_process_type_string((unsigned char)scope), data); - } - else - rtc_change_loglevel_ha(command); - } -} - -/****************************************************************************** - * * - * Function: zbx_rtc_process_command * - * * - * Purpose: process runtime command * - * * - ******************************************************************************/ -void zbx_rtc_process_command(unsigned int command) -{ - zabbix_log(LOG_LEVEL_DEBUG, "In %s() command:%d", __func__, ZBX_RTC_GET_MSG(command)); - - switch (ZBX_RTC_GET_MSG(command)) - { - case ZBX_RTC_DIAGINFO: - rtc_diaginfo(ZBX_RTC_GET_SCOPE(command)); - break; - case ZBX_RTC_HA_STATUS: - rtc_ha_status(); - break; - case ZBX_RTC_HA_REMOVE_NODE: - rtc_remove_node(ZBX_RTC_GET_DATA(command)); - break; - case ZBX_RTC_HA_SET_FAILOVER_DELAY: - rtc_ha_failover_delay(ZBX_RTC_GET_DATA(command)); - break; - case ZBX_RTC_LOG_LEVEL_INCREASE: - case ZBX_RTC_LOG_LEVEL_DECREASE: - rtc_change_loglevel(ZBX_RTC_GET_MSG(command), ZBX_RTC_GET_SCOPE(command), - ZBX_RTC_GET_DATA(command)); - break; - } - - zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); -} diff --git a/src/zabbix_server/server.c b/src/zabbix_server/server.c index 417b9205cac..149cee9e7ae 100644 --- a/src/zabbix_server/server.c +++ b/src/zabbix_server/server.c @@ -80,7 +80,8 @@ #include "zbxtrends.h" #include "ha/ha.h" #include "sighandler.h" -#include "rtc.h" +#include "zbxrtc.h" +#include "zbxha.h" #ifdef HAVE_OPENIPMI #include "ipmi/ipmi_manager.h" @@ -178,7 +179,7 @@ int threads_num = 0; pid_t *threads = NULL; static int *threads_flags; -static int ha_status = ZBX_NODE_STATUS_UNINITIALIZED; +static int ha_status = ZBX_NODE_STATUS_UNKNOWN; static int ha_status_old; zbx_cuid_t ha_sessionid; @@ -354,8 +355,6 @@ char *CONFIG_WEBSERVICE_URL = NULL; int CONFIG_SERVICEMAN_SYNC_FREQUENCY = 60; -static volatile sig_atomic_t zbx_rtc_command; - int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num); int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num) @@ -1035,9 +1034,7 @@ int main(int argc, char **argv) break; case 'R': opt_r++; - if (SUCCEED != parse_rtc_options(zbx_optarg, program_type, &t.data)) - exit(EXIT_FAILURE); - + t.opts = zbx_strdup(t.opts, zbx_optarg); t.task = ZBX_TASK_RUNTIME_CONTROL; break; case 'h': @@ -1090,14 +1087,27 @@ int main(int argc, char **argv) zbx_load_config(&t); if (ZBX_TASK_RUNTIME_CONTROL == t.task) - exit(SUCCEED == zbx_sigusr_send(t.data) ? EXIT_SUCCESS : EXIT_FAILURE); + { + int ret; + char *error = NULL; - return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); -} + if (FAIL == zbx_ipc_service_init_env(CONFIG_SOCKET_PATH, &error)) + { + zbx_error("cannot initialize IPC services: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } -static void zbx_main_sigusr_handler(int flags) -{ - zbx_rtc_command = flags; + if (SUCCEED != (ret = zbx_rtc_process(t.opts, &error))) + { + zbx_error("Cannot perform runtime control command: %s", error); + zbx_free(error); + } + + exit(SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE); + } + + return daemon_start(CONFIG_ALLOW_ROOT, CONFIG_USER, t.flags); } static void zbx_check_db(void) @@ -1186,33 +1196,12 @@ static void zbx_check_db(void) /****************************************************************************** * * - * Function: server_update_ha_status * - * * - * Purpose: check for queued status message and update HA status * - * * - ******************************************************************************/ -static int server_update_ha_status(void) -{ - char *error = NULL; - - if (SUCCEED != zbx_ha_recv_status(0, &ha_status, &error)) - { - zabbix_log(LOG_LEVEL_CRIT, "cannot check HA manager status: %s", error); - zbx_free(error); - return FAIL; - } - - return SUCCEED; -} - -/****************************************************************************** - * * * Function: server_startup * * * * Purpose: initialize shared resources and start processes * * * ******************************************************************************/ -static int server_startup(zbx_socket_t *listen_sock) +static int server_startup(zbx_socket_t *listen_sock, zbx_rtc_t *rtc) { int i, ret = SUCCEED; char *error = NULL; @@ -1307,11 +1296,12 @@ static int server_startup(zbx_socket_t *listen_sock) break; case ZBX_PROCESS_TYPE_CONFSYNCER: zbx_thread_start(dbconfig_thread, &thread_args, &threads[i]); - DCconfig_wait_sync(); + zbx_rtc_wait_config_sync(rtc); - if (SUCCEED != server_update_ha_status()) + if (SUCCEED != (ret = zbx_ha_get_status(&ha_status, &error))) { - ret = FAIL; + zabbix_log(LOG_LEVEL_CRIT, "cannot obtain HA status: %s", error); + zbx_free(error); goto out; } @@ -1445,8 +1435,11 @@ static int server_startup(zbx_socket_t *listen_sock) } /* startup/postinit tasks can take a long time, update status */ - if (SUCCEED != server_update_ha_status()) - ret = FAIL; + if (SUCCEED != (ret = zbx_ha_get_status(&ha_status, &error))) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot obtain HA status: %s", error); + zbx_free(error); + } out: zbx_unset_exit_on_terminate(); @@ -1474,7 +1467,7 @@ static int server_restart_logger(char **error) * Purpose: terminate processes and destroy shared resources * * * ******************************************************************************/ -static void server_teardown(zbx_socket_t *listen_sock) +static void server_teardown(zbx_rtc_t *rtc, zbx_socket_t *listen_sock) { int i; char *error = NULL; @@ -1535,7 +1528,7 @@ static void server_teardown(zbx_socket_t *listen_sock) zbx_locks_enable(); #endif - if (SUCCEED != zbx_ha_start(&error, ZBX_NODE_STATUS_STANDBY)) + if (SUCCEED != zbx_ha_start(rtc, ZBX_NODE_STATUS_STANDBY, &error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot start HA manager: %s", error); zbx_free(error); @@ -1549,6 +1542,8 @@ int MAIN_ZABBIX_ENTRY(int flags) int i, db_type, ret; zbx_socket_t listen_sock; time_t standby_warning_time; + zbx_rtc_t rtc; + zbx_timespec_t rtc_timeout = {1, 0}; if (0 != (flags & ZBX_TASK_FLAG_FOREGROUND)) { @@ -1660,6 +1655,13 @@ int MAIN_ZABBIX_ENTRY(int flags) zbx_free_config(); + if (SUCCEED != zbx_rtc_init(&rtc, &error)) + { + zabbix_log(LOG_LEVEL_CRIT, "cannot initialize runtime control service: %s", error); + zbx_free(error); + exit(EXIT_FAILURE); + } + if (SUCCEED != zbx_vault_init_token_from_env(&error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot initialize vault token: %s", error); @@ -1724,7 +1726,7 @@ int MAIN_ZABBIX_ENTRY(int flags) zbx_unset_exit_on_terminate(); - if (SUCCEED != zbx_ha_start(&error, ZBX_NODE_STATUS_UNKNOWN)) + if (SUCCEED != zbx_ha_start(&rtc, ZBX_NODE_STATUS_UNKNOWN, &error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot start HA manager: %s", error); zbx_free(error); @@ -1740,21 +1742,7 @@ int MAIN_ZABBIX_ENTRY(int flags) if (SUCCEED == zbx_is_export_enabled(ZBX_FLAG_EXPTYPE_TRENDS)) zbx_trends_export_init("main-process", 0); - zbx_set_sigusr_handler(zbx_main_sigusr_handler); - - if (SUCCEED == zbx_ha_get_status(&error)) - { - while (ZBX_IS_RUNNING() && ZBX_NODE_STATUS_UNINITIALIZED == ha_status) - { - if (SUCCEED != zbx_ha_recv_status(ZBX_IPC_WAIT_FOREVER, &ha_status, &error)) - { - zabbix_log(LOG_LEVEL_CRIT, "cannot start server: %s", error); - zbx_free(error); - sig_exiting = ZBX_EXIT_FAILURE; - } - } - } - else + if (SUCCEED != zbx_ha_get_status(&ha_status, &error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot start server: %s", error); zbx_free(error); @@ -1763,7 +1751,7 @@ int MAIN_ZABBIX_ENTRY(int flags) if (ZBX_NODE_STATUS_ACTIVE == ha_status) { - if (SUCCEED != server_startup(&listen_sock)) + if (SUCCEED != server_startup(&listen_sock, &rtc)) { sig_exiting = ZBX_EXIT_FAILURE; ha_status = ZBX_NODE_STATUS_ERROR; @@ -1772,7 +1760,7 @@ int MAIN_ZABBIX_ENTRY(int flags) { /* check if the HA status has not been changed during startup process */ if (ZBX_NODE_STATUS_ACTIVE != ha_status) - server_teardown(&listen_sock); + server_teardown(&rtc, &listen_sock); } } @@ -1798,28 +1786,52 @@ int MAIN_ZABBIX_ENTRY(int flags) while (ZBX_IS_RUNNING()) { - time_t now; + time_t now; + zbx_ipc_client_t *client; + zbx_ipc_message_t *message; - if (SUCCEED != zbx_ha_recv_status(1, &ha_status, &error)) + (void)zbx_ipc_service_recv(&rtc.service, &rtc_timeout, &client, &message); + + if (NULL == message || ZBX_IPC_SERVICE_HA_RTC_FIRST <= message->code) { - zabbix_log(LOG_LEVEL_CRIT, "cannot receive HA manager status: %s", error); - zbx_free(error); - sig_exiting = ZBX_EXIT_FAILURE; - break; + if (SUCCEED != zbx_ha_dispatch_message(message, &ha_status, &error)) + { + zabbix_log(LOG_LEVEL_CRIT, "HA manager error: %s", error); + sig_exiting = ZBX_EXIT_FAILURE; + } + } + else + { + if (ZBX_NODE_STATUS_ACTIVE == ha_status || ZBX_RTC_LOG_LEVEL_DECREASE == message->code || + ZBX_RTC_LOG_LEVEL_INCREASE == message->code) + { + zbx_rtc_dispatch(client, message); + } + else + { + const char *result = "Runtime commands can be executed only in active mode\n"; + zbx_ipc_client_send(client, message->code, (const unsigned char *)result, + (zbx_uint32_t)strlen(result) + 1); + } } + zbx_ipc_message_free(message); + + if (NULL != client) + zbx_ipc_client_release(client); + now = time(NULL); if (ZBX_NODE_STATUS_UNKNOWN != ha_status && ha_status != ha_status_old) { ha_status_old = ha_status; - zabbix_log(LOG_LEVEL_INFORMATION, "\"%s\" node switched to \"%s\" mode", CONFIG_HA_NODE_NAME, - zbx_ha_status_str(ha_status)); + zabbix_log(LOG_LEVEL_INFORMATION, "\"%s\" node switched to \"%s\" mode", + ZBX_NULL2EMPTY_STR(CONFIG_HA_NODE_NAME), zbx_ha_status_str(ha_status)); switch (ha_status) { case ZBX_NODE_STATUS_ACTIVE: - if (SUCCEED != server_startup(&listen_sock)) + if (SUCCEED != server_startup(&listen_sock, &rtc)) { sig_exiting = ZBX_EXIT_FAILURE; ha_status = ZBX_NODE_STATUS_ERROR; @@ -1827,11 +1839,11 @@ int MAIN_ZABBIX_ENTRY(int flags) } if (ZBX_NODE_STATUS_ACTIVE != ha_status) - server_teardown(&listen_sock); + server_teardown(&rtc, &listen_sock); break; case ZBX_NODE_STATUS_STANDBY: - server_teardown(&listen_sock); + server_teardown(&rtc, &listen_sock); standby_warning_time = now; break; default: @@ -1864,16 +1876,6 @@ int MAIN_ZABBIX_ENTRY(int flags) zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno)); break; } - - if (0 != zbx_rtc_command) - { - if (ZBX_NODE_STATUS_ACTIVE == ha_status) - zbx_rtc_process_command((unsigned int)zbx_rtc_command); - else - zabbix_log(LOG_LEVEL_INFORMATION, "runtime commands can be executed only in active mode"); - - zbx_rtc_command = 0; - } } if (SUCCEED != zbx_ha_pause(&error)) diff --git a/src/zabbix_server/trapper/proxyconfig.c b/src/zabbix_server/trapper/proxyconfig.c index 7dc93c26236..b833f8e3476 100644 --- a/src/zabbix_server/trapper/proxyconfig.c +++ b/src/zabbix_server/trapper/proxyconfig.c @@ -24,6 +24,7 @@ #include "../../libs/zbxcrypto/tls_tcp_active.h" #include "zbxcompress.h" +#include "zbxipcservice.h" #include "proxyconfig.h" @@ -61,7 +62,7 @@ void send_proxyconfig(zbx_socket_t *sock, struct zbx_json_parse *jp) goto out; } - zbx_update_proxy_data(&proxy, zbx_get_proxy_protocol_version(jp), time(NULL), + zbx_update_proxy_data(&proxy, zbx_get_proxy_protocol_version(jp), (int)time(NULL), (0 != (sock->protocol & ZBX_TCP_COMPRESS) ? 1 : 0), ZBX_FLAGS_PROXY_DIFF_UPDATE_CONFIG); if (0 != proxy.auto_compress) @@ -94,16 +95,18 @@ void send_proxyconfig(zbx_socket_t *sock, struct zbx_json_parse *jp) zabbix_log(LOG_LEVEL_WARNING, "sending configuration data to proxy \"%s\" at \"%s\", datalen " ZBX_FS_SIZE_T ", bytes " ZBX_FS_SIZE_T " with compression ratio %.1f", proxy.host, sock->peer, (zbx_fs_size_t)reserved, (zbx_fs_size_t)buffer_size, - (double)reserved / buffer_size); + (double)reserved / (double)buffer_size); - ret = zbx_tcp_send_ext(sock, buffer, buffer_size, reserved, flags, CONFIG_TRAPPER_TIMEOUT); + ret = zbx_tcp_send_ext(sock, buffer, buffer_size, reserved, (unsigned char)flags, + CONFIG_TRAPPER_TIMEOUT); } else { zabbix_log(LOG_LEVEL_WARNING, "sending configuration data to proxy \"%s\" at \"%s\", datalen " ZBX_FS_SIZE_T, proxy.host, sock->peer, (zbx_fs_size_t)j.buffer_size); - ret = zbx_tcp_send_ext(sock, j.buffer, strlen(j.buffer), 0, flags, CONFIG_TRAPPER_TIMEOUT); + ret = zbx_tcp_send_ext(sock, j.buffer, strlen(j.buffer), 0, (unsigned char)flags, + CONFIG_TRAPPER_TIMEOUT); } if (SUCCEED != ret) @@ -131,7 +134,7 @@ out: ******************************************************************************/ void recv_proxyconfig(zbx_socket_t *sock, struct zbx_json_parse *jp) { - struct zbx_json_parse jp_data; + struct zbx_json_parse jp_data, jp_kvs_paths = {0}; int ret; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -147,7 +150,26 @@ void recv_proxyconfig(zbx_socket_t *sock, struct zbx_json_parse *jp) if (SUCCEED != check_access_passive_proxy(sock, ZBX_SEND_RESPONSE, "configuration update")) goto out; - process_proxyconfig(&jp_data); + if (SUCCEED == process_proxyconfig(&jp_data, &jp_kvs_paths)) + { + unsigned char *result; + char *error = NULL; + + if (SUCCEED == zbx_ipc_async_exchange(ZBX_IPC_SERVICE_CONFIG, ZBX_IPC_CONFIG_RELOAD_REQUEST, + ZBX_IPC_WAIT_FOREVER, NULL, 0, &result, &error)) + { + zbx_free(result); + + if (NULL != jp_kvs_paths.start) + DCsync_kvs_paths(&jp_kvs_paths); + } + else + { + THIS_SHOULD_NEVER_HAPPEN; + zabbix_log(LOG_LEVEL_WARNING, "cannot send message to configuration syncer: %s", error); + zbx_free(error); + } + } zbx_send_proxy_response(sock, ret, NULL, CONFIG_TIMEOUT); out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); diff --git a/src/zabbix_server/trapper/trapper.c b/src/zabbix_server/trapper/trapper.c index 327f08ceb07..0c7d2332c05 100644 --- a/src/zabbix_server/trapper/trapper.c +++ b/src/zabbix_server/trapper/trapper.c @@ -35,6 +35,7 @@ #include "../../libs/zbxserver/zabbix_stats.h" #include "zbxipcservice.h" #include "../poller/checks_snmp.h" +#include "zbxrtc.h" #include "trapper_auth.h" #include "trapper_preproc.h" @@ -1226,13 +1227,6 @@ ZBX_THREAD_ENTRY(trapper_thread, args) DBconnect(ZBX_DB_CONNECT_NORMAL); - /* configuration sync is performed by trappers on passive Zabbix proxy */ - if (1 == process_num && 0 == CONFIG_CONFSYNCER_FORKS) - { - zbx_setproctitle("%s [syncing configuration]", get_process_type_string(process_type)); - DCsync_configuration(ZBX_DBSYNC_INIT, NULL); - } - zbx_set_sigusr_handler(zbx_trapper_sigusr_handler); while (ZBX_IS_RUNNING()) diff --git a/ui/tests/include/web/CPage.php b/ui/tests/include/web/CPage.php index 1a28f289023..fe8c4d3a4a9 100644 --- a/ui/tests/include/web/CPage.php +++ b/ui/tests/include/web/CPage.php @@ -126,11 +126,13 @@ class CPage { $this->resetViewport(); if (self::$cookie !== null) { - $cookie = $this->driver->manage()->getCookieNamed('zbx_session'); - - if ($cookie === null - || $cookie->getValue() !== self::$cookie['value']) { - self::$cookie = null; + foreach ($this->driver->manage()->getCookies() as $cookie) { + if ($cookie->getName() === 'zbx_session') { + if ($cookie->getValue() !== self::$cookie['value']) { + self::$cookie = null; + } + break; + } } } @@ -236,9 +238,19 @@ class CPage { // Before logout open page without any scripts, otherwise session might be restored and logout won't work. $this->open('setup.php'); - $session = (self::$cookie === null) - ? CTestArrayHelper::get($this->driver->manage()->getCookieNamed('zbx_session'), 'value') - : self::$cookie['value']; + $session = null; + + if (self::$cookie === null) { + foreach ($this->driver->manage()->getCookies() as $cookie) { + if ($cookie->getName() === 'zbx_session') { + $session = $cookie->getValue(); + break; + } + } + } + else { + $session = self::$cookie['value']; + } if ($session !== null) { DBExecute('DELETE FROM sessions WHERE sessionid='.zbx_dbstr($session)); diff --git a/ui/tests/selenium/dashboard/testDashboardProblemsBySeverityWidget.php b/ui/tests/selenium/dashboard/testDashboardProblemsBySeverityWidget.php index f632f65f7c8..3873810907d 100644 --- a/ui/tests/selenium/dashboard/testDashboardProblemsBySeverityWidget.php +++ b/ui/tests/selenium/dashboard/testDashboardProblemsBySeverityWidget.php @@ -1671,7 +1671,7 @@ class testDashboardProblemsBySeverityWidget extends CWebTest { } foreach ($expected_popup['Tags'] as $tag) { $tag_array = $row->getColumn('Tags')->getText(); - $this->assertContains($tag, $tag_array); + $this->assertStringContainsString($tag, $tag_array); } if (CTestArrayHelper::get($data['fields'], 'Show operational data', 'None') === 'Separately') { $this->assertEquals('*UNKNOWN*', $row->getColumn('Operational data')->getText()); diff --git a/ui/tests/selenium/reports/testFormScheduledReport.php b/ui/tests/selenium/reports/testFormScheduledReport.php index 56353dec6d9..fb516499c2a 100644 --- a/ui/tests/selenium/reports/testFormScheduledReport.php +++ b/ui/tests/selenium/reports/testFormScheduledReport.php @@ -914,7 +914,7 @@ class testFormScheduledReport extends CWebTest { 'Description' => '', 'Enabled' => false ], - 'Start time' => '0:0', + 'Start time' => '00:00', 'Subscriptions' => [ [ 'action' => USER_ACTION_REMOVE, diff --git a/ui/tests/selenium/reports/testPageReportsNotifications.php b/ui/tests/selenium/reports/testPageReportsNotifications.php index ac82198c59c..e1a8e5940bd 100644 --- a/ui/tests/selenium/reports/testPageReportsNotifications.php +++ b/ui/tests/selenium/reports/testPageReportsNotifications.php @@ -37,7 +37,7 @@ class testPageReportsNotifications extends CLegacyWebTest { $dropdowns = [ 'media_type' => array_merge(['all'], $all_media), 'period' => ['Daily', 'Weekly', 'Monthly', 'Yearly'], - 'year' => ['2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021'] + 'year' => ['2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022'] ]; $default_selected = [ 'media_type' => 'all', diff --git a/ui/tests/selenium/roles/testUserRolesPermissions.php b/ui/tests/selenium/roles/testUserRolesPermissions.php index d5ef7ce6e16..4c401c72d23 100644 --- a/ui/tests/selenium/roles/testUserRolesPermissions.php +++ b/ui/tests/selenium/roles/testUserRolesPermissions.php @@ -1423,7 +1423,7 @@ class testUserRolesPermissions extends CWebTest { $this->query('button:Go to "'.$page.'"')->one()->waitUntilClickable()->click(); if ($page === 'Dashboard') { - $this->assertContains('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); + $this->assertStringContainsString('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); } } } diff --git a/ui/tests/selenium/testFormAdministrationAuthenticationHttp.php b/ui/tests/selenium/testFormAdministrationAuthenticationHttp.php index 68fc7186279..18a53778d14 100644 --- a/ui/tests/selenium/testFormAdministrationAuthenticationHttp.php +++ b/ui/tests/selenium/testFormAdministrationAuthenticationHttp.php @@ -526,7 +526,7 @@ class testFormAdministrationAuthenticationHttp extends CLegacyWebTest { $message = CMessageElement::find()->one(); $this->assertEquals('msg-bad msg-global', $message->getAttribute('class')); $message_title= $message->getText(); - $this->assertContains($check['error'], $message_title); + $this->assertStringContainsString($check['error'], $message_title); } continue; diff --git a/ui/tests/selenium/testFormAdministrationAuthenticationSaml.php b/ui/tests/selenium/testFormAdministrationAuthenticationSaml.php index 03b17de78d5..63dbac8b157 100644 --- a/ui/tests/selenium/testFormAdministrationAuthenticationSaml.php +++ b/ui/tests/selenium/testFormAdministrationAuthenticationSaml.php @@ -220,7 +220,7 @@ class testFormAdministrationAuthenticationSaml extends CWebTest { $this->page->logout(); $this->page->open('index.php')->waitUntilReady(); $link = $this->query('link:Sign in with Single Sign-On (SAML)')->one()->waitUntilClickable(); - $this->assertContains('index_sso.php', $link->getAttribute('href')); + $this->assertStringContainsString('index_sso.php', $link->getAttribute('href')); // Login and disable SAML authentication. $this->page->login()->open('zabbix.php?action=authentication.edit'); $form = $this->query('name:form_auth')->asForm()->one(); @@ -379,7 +379,7 @@ class testFormAdministrationAuthenticationSaml extends CWebTest { // Make sure that it is possible to log out. $this->query('link:Sign out')->one()->click(); $this->page->waitUntilReady(); - $this->assertContains('index.php', $this->page->getCurrentUrl()); + $this->assertStringContainsString('index.php', $this->page->getCurrentUrl()); } /** diff --git a/ui/tests/selenium/testFormEventCorrelation.php b/ui/tests/selenium/testFormEventCorrelation.php index 6595f7647c6..965efa0ed70 100644 --- a/ui/tests/selenium/testFormEventCorrelation.php +++ b/ui/tests/selenium/testFormEventCorrelation.php @@ -153,9 +153,9 @@ class testFormEventCorrelation extends CLegacyWebTest { $this->zbxTestClick('add'); $this->zbxTestWaitUntilMessageTextPresent('msg-bad', $data['error_header']); $error = $this->zbxTestGetText('//ul[@class=\'list-dashed msg-details-border\']'); - $this->assertContains($data['error_message'], $error); + $this->assertStringContainsString($data['error_message'], $error); - if (array_key_exists('name', $data) && $data['name'] === 'Event correlation for update') { + if (array_key_exists('name', $data) && $data['name'] === 'Event correlation for update') { $sql = 'SELECT NULL FROM correlation WHERE name='.zbx_dbstr($data['name']); $this->assertEquals(1, CDBHelper::getCount($sql)); } @@ -656,7 +656,7 @@ class testFormEventCorrelation extends CLegacyWebTest { $this->zbxTestWaitUntilMessageTextPresent('msg-bad', 'Cannot add correlation'); $error = $this->zbxTestGetText('//ul[@class=\'list-dashed msg-details-border\']'); - $this->assertContains($data['error_message'], $error); + $this->assertStringContainsString($data['error_message'], $error); $sql = 'SELECT NULL FROM correlation WHERE name='.zbx_dbstr($data['name']); $this->assertEquals(0, CDBHelper::getCount($sql)); diff --git a/ui/tests/selenium/testFormSetup.php b/ui/tests/selenium/testFormSetup.php index 6cc52b22bb8..01f057bc53c 100644 --- a/ui/tests/selenium/testFormSetup.php +++ b/ui/tests/selenium/testFormSetup.php @@ -316,7 +316,7 @@ class testFormSetup extends CWebTest { $xpath = 'xpath://span[text()='.CXPathHelper::escapeQuotes($field_name).']/../../div[@class="table-forms-td-right"]'; // Assert contains is used as Password length can differ. if ($field_name === 'Database password') { - $this->assertContains($value, $this->query($xpath)->one()->getText()); + $this->assertStringContainsString($value, $this->query($xpath)->one()->getText()); } else { $this->assertEquals($value, $this->query($xpath)->one()->getText()); @@ -344,7 +344,7 @@ class testFormSetup extends CWebTest { // Check that Dashboard view is opened after completing the form. $this->query('button:Finish')->one()->click(); $this->page->waitUntilReady(); - $this->assertContains('index.php', $this->page->getCurrentURL()); + $this->assertStringContainsString('index.php', $this->page->getCurrentURL()); } public function getDbConnectionDetails() { @@ -804,7 +804,7 @@ class testFormSetup extends CWebTest { // Cancel setup form update. $this->query('button:Cancel')->one()->click(); - $this->assertContains('zabbix.php?action=dashboard.view', $this->page->getCurrentURL()); + $this->assertStringContainsString('zabbix.php?action=dashboard.view', $this->page->getCurrentURL()); } /** @@ -817,7 +817,7 @@ class testFormSetup extends CWebTest { $this->assertTrue($this->query('xpath://h1[text()='.CXPathHelper::escapeQuotes($title).']')->one()->isValid()); $this->checkSections($title); if ($text) { - $this->assertContains($text, $this->query('xpath:.//p')->one()->getText()); + $this->assertStringContainsString($text, $this->query('xpath:.//p')->one()->getText()); } } diff --git a/ui/tests/selenium/testFormTrigger.php b/ui/tests/selenium/testFormTrigger.php index 4c5faadb831..fa768d13fbc 100644 --- a/ui/tests/selenium/testFormTrigger.php +++ b/ui/tests/selenium/testFormTrigger.php @@ -913,7 +913,7 @@ class testFormTrigger extends CLegacyWebTest { $this->assertEquals($count, $this->query('xpath://span[@class="icon-info status-red"]')->all()->count()); $text = $this->query('xpath://tr[1]//div[@class="hint-box"]')->one()->getText(); foreach ($constructor['errors'] as $error) { - $this->assertContains($error, $text); + $this->assertStringContainsString($error, $text); } } else { diff --git a/ui/tests/selenium/testFormTriggerPrototype.php b/ui/tests/selenium/testFormTriggerPrototype.php index 060ffe8384a..69297a7ffb2 100644 --- a/ui/tests/selenium/testFormTriggerPrototype.php +++ b/ui/tests/selenium/testFormTriggerPrototype.php @@ -869,7 +869,7 @@ class testFormTriggerPrototype extends CLegacyWebTest { $this->assertEquals($count, $this->query('xpath://span[@class="icon-info status-red"]')->all()->count()); $text = $this->query('xpath://tr[1]//div[@class="hint-box"]')->one()->getText(); foreach ($constructor['errors'] as $error) { - $this->assertContains($error, $text); + $this->assertStringContainsString($error, $text); } } else { diff --git a/ui/tests/selenium/testPageAdministrationGeneralModules.php b/ui/tests/selenium/testPageAdministrationGeneralModules.php index 9e0dbb77db8..1f505ba53d9 100644 --- a/ui/tests/selenium/testPageAdministrationGeneralModules.php +++ b/ui/tests/selenium/testPageAdministrationGeneralModules.php @@ -552,7 +552,7 @@ class testPageAdministrationGeneralModules extends CWebTest { sleep(1); $this->query($xpath.$entry['name'].'"]')->one()->waitUntilClickable()->click(); $this->page->waitUntilReady(); - $this->assertContains('zabbix.php?action='.$entry['action'], $this->page->getCurrentURL()); + $this->assertStringContainsString('zabbix.php?action='.$entry['action'], $this->page->getCurrentURL()); $this->assertEquals($entry['message'], $this->query('tag:h1')->waitUntilVisible()->one()->getText()); } // Get back to modules list to enable or disable the next module. @@ -582,7 +582,7 @@ class testPageAdministrationGeneralModules extends CWebTest { if (CTestArrayHelper::get($entry, 'check_disabled', true)) { $this->page->open('zabbix.php?action='.$entry['action'])->waitUntilReady(); $message = CMessageElement::find()->one(); - $this->assertContains('Class not found for action '.$entry['action'], $message->getText()); + $this->assertStringContainsString('Class not found for action '.$entry['action'], $message->getText()); $this->page->open('zabbix.php?action=module.list'); } } diff --git a/ui/tests/selenium/testPageTriggerDescription.php b/ui/tests/selenium/testPageTriggerDescription.php index c3e8468cc9e..89ac21672e0 100644 --- a/ui/tests/selenium/testPageTriggerDescription.php +++ b/ui/tests/selenium/testPageTriggerDescription.php @@ -113,7 +113,7 @@ class testPageTriggerDescription extends CWebTest { $this->page->waitUntilReady(); // Check the URL of the opened page to make sure that correct event is opened. - $this->assertContains($data['event_url'], $this->page->getCurrentURL()); + $this->assertStringContainsString($data['event_url'], $this->page->getCurrentURL()); // Find the row that contains trigger description and select the column that holds the value of description field. $description = $this->query('xpath://td[text()="Description"]/..')->one()->asTableRow()->getColumn(1); diff --git a/ui/tests/selenium/testPageTriggerUrl.php b/ui/tests/selenium/testPageTriggerUrl.php index fda65e7a0b6..9863366b610 100644 --- a/ui/tests/selenium/testPageTriggerUrl.php +++ b/ui/tests/selenium/testPageTriggerUrl.php @@ -134,7 +134,7 @@ class testPageTriggerUrl extends CWebTest { // Check Url of each link. foreach ($data['links'] as $link => $url) { $this->assertTrue($popup->hasItems($link)); - $this->assertContains($url, $popup->getItem($link)->getAttribute('href')); + $this->assertStringContainsString($url, $popup->getItem($link)->getAttribute('href')); } if ($trigger_overview) { $this->assertTrue($popup->hasItems('Acknowledge')); @@ -156,6 +156,6 @@ class testPageTriggerUrl extends CWebTest { // Check opened page. $this->assertEquals('Event details', $this->query('tag:h1')->waitUntilVisible()->one()->getText()); - $this->assertContains($data['links']['Trigger URL'], $this->page->getCurrentUrl()); + $this->assertStringContainsString($data['links']['Trigger URL'], $this->page->getCurrentUrl()); } } diff --git a/ui/tests/selenium/testSID.php b/ui/tests/selenium/testSID.php index 77b7ce6dae6..e4dca61c2fe 100644 --- a/ui/tests/selenium/testSID.php +++ b/ui/tests/selenium/testSID.php @@ -668,7 +668,7 @@ class testSID extends CWebTest { $this->assertMessage(TEST_BAD, 'Access denied', 'You are logged in as "Admin". You have no permissions to access this page.'); $this->query('button:Go to "Dashboard"')->one()->waitUntilClickable()->click(); - $this->assertContains('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); + $this->assertStringContainsString('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); } } @@ -1205,7 +1205,7 @@ class testSID extends CWebTest { if (CTestArrayHelper::get($data, 'incorrect_request')) { $this->query('button:Go to "Dashboard"')->one()->waitUntilClickable()->click(); $this->page->waitUntilReady(); - $this->assertContains('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); + $this->assertStringContainsString('zabbix.php?action=dashboard', $this->page->getCurrentUrl()); } $this->assertEquals($hash_before, CDBHelper::getHash($data['db'])); diff --git a/ui/tests/selenium/testTemplateInheritance.php b/ui/tests/selenium/testTemplateInheritance.php index b9ff4b64336..358a6a5605c 100644 --- a/ui/tests/selenium/testTemplateInheritance.php +++ b/ui/tests/selenium/testTemplateInheritance.php @@ -276,9 +276,9 @@ class testTemplateInheritance extends CLegacyWebTest { $this->assertFalse($this->zbxTestCheckboxSelected('show_work_period')); $this->assertFalse($this->zbxTestCheckboxSelected('show_triggers')); $this->assertTrue($this->zbxTestCheckboxSelected('visible_percent_left')); - $this->zbxTestAssertElementValue('percent_left', '4.00'); + $this->zbxTestAssertElementValue('percent_left', '4'); $this->assertTrue($this->zbxTestCheckboxSelected('visible_percent_right')); - $this->zbxTestAssertElementValue('percent_right', '5.00'); + $this->zbxTestAssertElementValue('percent_right', '5'); $this->zbxTestDropdownAssertSelected('ymin_type', 'Calculated'); $this->zbxTestDropdownAssertSelected('ymax_type', 'Calculated'); $this->zbxTestTextPresent('Parent graphs'); @@ -513,9 +513,9 @@ class testTemplateInheritance extends CLegacyWebTest { $this->assertFalse($this->zbxTestCheckboxSelected('show_work_period')); $this->assertFalse($this->zbxTestCheckboxSelected('show_triggers')); $this->assertTrue($this->zbxTestCheckboxSelected('visible_percent_left')); - $this->zbxTestAssertElementValue('percent_left', '4.00'); + $this->zbxTestAssertElementValue('percent_left', '4'); $this->assertTrue($this->zbxTestCheckboxSelected('visible_percent_right')); - $this->zbxTestAssertElementValue('percent_right', '5.00'); + $this->zbxTestAssertElementValue('percent_right', '5'); $this->zbxTestDropdownAssertSelected('ymin_type', 'Calculated'); $this->zbxTestDropdownAssertSelected('ymax_type', 'Calculated'); $this->zbxTestTextPresent($this->hostName.': itemDiscovery'); diff --git a/ui/tests/selenium/users/testFormUser.php b/ui/tests/selenium/users/testFormUser.php index d1388601a44..daacc77a2a1 100644 --- a/ui/tests/selenium/users/testFormUser.php +++ b/ui/tests/selenium/users/testFormUser.php @@ -593,7 +593,7 @@ class testFormUser extends CWebTest { $password = CTestArrayHelper::get($data['fields'], 'Password', $data['fields']['Password'] = 'zabbix'); $this->page->userLogin($data['fields']['Username'], $password); // Verification of URL after login. - $this->assertContains($data['fields']['URL (after login)'], $this->page->getCurrentURL()); + $this->assertStringContainsString($data['fields']['URL (after login)'], $this->page->getCurrentURL()); // Verification of the number of rows per page parameter. $rows = $this->query('name:frm_maps')->asTable()->waitUntilVisible()->one()->getRows(); $this->assertEquals($data['fields']['Rows per page'], $rows->count()); @@ -1009,12 +1009,12 @@ class testFormUser extends CWebTest { $this->page->logout(); // Attempt to sign in with old password. - $this->page->userLogin($data['username'],$data['old_password']); + $this->page->userLogin($data['username'], $data['old_password']); $message = $this->query('class:red')->one()->getText(); $this->assertEquals($message, $data['error_message']); // Sign in with new password. - $this->page->userLogin($data['username'],$data['new_password']); + $this->page->userLogin($data['username'], $data['new_password']); $attempt_message = CMessageElement::find()->one(); $this->assertTrue($attempt_message->hasLine($data['attempt_message'])); $this->page->logout(); @@ -1140,7 +1140,7 @@ class testFormUser extends CWebTest { $form_create->fill($data); $this->query('button:Cancel')->one()->click(); $cancel_url = $this->page->getCurrentURL(); - $this->assertContains('zabbix.php?action=user.list', $cancel_url); + $this->assertStringContainsString('zabbix.php?action=user.list', $cancel_url); $this->assertEquals($user_hash, CDBHelper::getHash($sql_users)); // Check Cancellation when updating users. diff --git a/ui/tests/selenium/users/testFormUserMedia.php b/ui/tests/selenium/users/testFormUserMedia.php index d99f4f8a4c4..33c1fa19c13 100644 --- a/ui/tests/selenium/users/testFormUserMedia.php +++ b/ui/tests/selenium/users/testFormUserMedia.php @@ -550,7 +550,7 @@ class testFormUserMedia extends CWebTest { // Check that the removed email is not present in 'Send to' field. $user_form = $this->query('name:user_form')->asForm()->waitUntilVisible()->one(); $row = $user_form->getField('Media')->asTable()->getRow(0); - $this->assertNotContains($email, $row->getColumn('Send to')->getText()); + $this->assertStringNotContainsString($email, $row->getColumn('Send to')->getText()); } private function setMediaValues($data) { @@ -635,7 +635,7 @@ class testFormUserMedia extends CWebTest { // Check that when no severities are passed - they all are turned on by default for ($i = 1; $i < 7; $i++) { $severity = $row->query('xpath:./td[4]/div/div['.$i.']')->one()->getText(); - $this->assertContains('(on)', $severity); + $this->assertStringContainsString('(on)', $severity); } } } |