/* ** Copyright (C) 2001-2024 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** 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 Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "zbxdiscovery.h" #include "zbxserialize.h" #include "zbx_discoverer_constants.h" #include "zbxalgo.h" #include "zbxcacheconfig.h" #include "zbxipcservice.h" #include "zbxjson.h" #include "zbxstats.h" #define DISCOVERER_INITIALIZED_YES 1 static int discoverer_initialized = 0; void zbx_discoverer_init(void) { discoverer_initialized = DISCOVERER_INITIALIZED_YES; } /****************************************************************************** * * * Purpose: frees discovery check * * * ******************************************************************************/ void zbx_discovery_dcheck_free(zbx_dc_dcheck_t *dcheck) { zbx_free(dcheck->key_); zbx_free(dcheck->ports); if (SVC_SNMPv1 == dcheck->type || SVC_SNMPv2c == dcheck->type || SVC_SNMPv3 == dcheck->type) { zbx_free(dcheck->snmp_community); zbx_free(dcheck->snmpv3_securityname); zbx_free(dcheck->snmpv3_authpassphrase); zbx_free(dcheck->snmpv3_privpassphrase); zbx_free(dcheck->snmpv3_contextname); } zbx_free(dcheck); } /****************************************************************************** * * * Purpose: frees discovery rule * * * ******************************************************************************/ void zbx_discovery_drule_free(zbx_dc_drule_t *drule) { zbx_free(drule->delay_str); zbx_free(drule->iprange); zbx_free(drule->name); zbx_vector_dc_dcheck_ptr_clear_ext(&drule->dchecks, zbx_discovery_dcheck_free); zbx_vector_dc_dcheck_ptr_destroy(&drule->dchecks); zbx_free(drule); } /****************************************************************************** * * * Purpose: sends command to discovery manager * * * * Parameters: code - [IN] message code * * data - [IN] message data * * size - [IN] message data size * * response - [OUT] response message (can be NULL if response is * * not requested) * * * ******************************************************************************/ static void discovery_send(zbx_uint32_t code, unsigned char *data, zbx_uint32_t size, zbx_ipc_message_t *response) { char *error = NULL; static zbx_ipc_socket_t socket = {0}; /* each process has a permanent connection to discovery manager */ if (0 == socket.fd && FAIL == zbx_ipc_socket_open(&socket, ZBX_IPC_SERVICE_DISCOVERER, SEC_PER_MIN, &error)) { zabbix_log(LOG_LEVEL_CRIT, "cannot connect to discoverer service: %s", error); exit(EXIT_FAILURE); } if (FAIL == zbx_ipc_socket_write(&socket, code, data, size)) { zabbix_log(LOG_LEVEL_CRIT, "cannot send data to discoverer service"); exit(EXIT_FAILURE); } if (NULL != response && FAIL == zbx_ipc_socket_read(&socket, response)) { zabbix_log(LOG_LEVEL_CRIT, "cannot receive data from discoverer service"); exit(EXIT_FAILURE); } } /****************************************************************************** * * * Purpose: gets queue size (enqueued checks count) of discovery manager * * * * Parameters: size - [OUT] enqueued item count * * error - [OUT] error message * * * * Return value: SUCCEED - queue size retrieved * * FAIL - discovery manager is not initialized * * * ******************************************************************************/ int zbx_discovery_get_queue_size(zbx_uint64_t *size, char **error) { zbx_ipc_message_t message; if (DISCOVERER_INITIALIZED_YES != discoverer_initialized) { if (NULL != error) { *error = zbx_strdup(NULL, "discoverer is not initialized: please check \"StartDiscoverers\"" " configuration parameter"); } return FAIL; } zbx_ipc_message_init(&message); discovery_send(ZBX_IPC_DISCOVERER_QUEUE, NULL, 0, &message); memcpy(size, message.data, sizeof(zbx_uint64_t)); zbx_ipc_message_clean(&message); return SUCCEED; } /****************************************************************************** * * * Purpose: unpacks worker usage statistics * * * * Parameters: usage - [OUT] worker usage statistics * * count - [OUT] * * data - [IN] input data * * * ******************************************************************************/ static void discovery_unpack_usage_stats(zbx_vector_dbl_t *usage, int *count, const unsigned char *data) { const unsigned char *offset = data; int usage_num; offset += zbx_deserialize_value(offset, &usage_num); zbx_vector_dbl_reserve(usage, (size_t)usage_num); for (int i = 0; i < usage_num; i++) { double busy; offset += zbx_deserialize_value(offset, &busy); zbx_vector_dbl_append(usage, busy); } (void)zbx_deserialize_value(offset, count); } /****************************************************************************** * * * Purpose: gets discovery manager diagnostic statistics * * * ******************************************************************************/ int zbx_discovery_get_usage_stats(zbx_vector_dbl_t *usage, int *count, char **error) { unsigned char *result; if (DISCOVERER_INITIALIZED_YES != discoverer_initialized) { *error = zbx_strdup(NULL, "discoverer is not initialized: please check \"StartDiscoverers\"" " configuration parameter"); return FAIL; } if (SUCCEED != zbx_ipc_async_exchange(ZBX_IPC_SERVICE_DISCOVERER, ZBX_IPC_DISCOVERER_USAGE_STATS, SEC_PER_MIN, NULL, 0, &result, error)) { return FAIL; } discovery_unpack_usage_stats(usage, count, result); zbx_free(result); return SUCCEED; } #undef DISCOVERER_INITIALIZED_YES /****************************************************************************** * * * Purpose: Packs diagnostic statistics data into a single buffer that can be * * used in IPC. * * Parameters: data - [OUT] memory buffer for packed data * * usage - [IN] worker usage statistics * * count - [IN] * * * ******************************************************************************/ zbx_uint32_t zbx_discovery_pack_usage_stats(unsigned char **data, const zbx_vector_dbl_t *usage, int count) { unsigned char *ptr; zbx_uint32_t data_len; data_len = (zbx_uint32_t)((unsigned int)usage->values_num * sizeof(double) + sizeof(int) + sizeof(int)); ptr = *data = (unsigned char *)zbx_malloc(NULL, data_len); ptr += zbx_serialize_value(ptr, usage->values_num); for (int i = 0; i < usage->values_num; i++) ptr += zbx_serialize_value(ptr, usage->values[i]); (void)zbx_serialize_value(ptr, count); return data_len; } void zbx_discovery_stats_ext_get(struct zbx_json *json, const void *arg) { zbx_uint64_t size; ZBX_UNUSED(arg); /* zabbix[discovery_queue] */ if (SUCCEED == zbx_discovery_get_queue_size(&size, NULL)) zbx_json_adduint64(json, "discovery_queue", size); } /****************************************************************************** * * * Purpose: gets discovery worker usage statistics * * * ******************************************************************************/ void zbx_discovery_get_worker_info(zbx_process_info_t *info) { zbx_vector_dbl_t usage; char *error = NULL; zbx_vector_dbl_create(&usage); memset(info, 0, sizeof(zbx_process_info_t)); if (SUCCEED != zbx_discovery_get_usage_stats(&usage, &info->count, &error)) { zabbix_log(LOG_LEVEL_WARNING, "cannot get discovery usage statistics: %s", error); zbx_free(error); goto out; } if (0 == usage.values_num) goto out; info->busy_min = info->busy_max = info->busy_avg = usage.values[0]; for (int i = 1; i < usage.values_num; i++) { if (usage.values[i] < info->busy_min) info->busy_min = usage.values[i]; if (usage.values[i] > info->busy_max) info->busy_max = usage.values[i]; info->busy_avg += usage.values[i]; } info->busy_avg /= (double)usage.values_num; info->idle_min = 100.0 - info->busy_min; info->idle_max = 100.0 - info->busy_max; info->idle_avg = 100.0 - info->busy_avg; info->count = usage.values_num; out: zbx_vector_dbl_destroy(&usage); }