From 294b72018121164f5da10e4340c2f6ad9074bfc5 Mon Sep 17 00:00:00 2001 From: jean-christophe81 <98889244+jean-christophe81@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:23:43 +0100 Subject: [PATCH] Mon 145030 cma ceip (#1950) feat(agent, engine, broker): CEIP collects statistics abour agent usage fix(test): agent tests * add os version to agent info --- agent/CMakeLists.txt | 5 +- agent/inc/com/centreon/agent/agent_info.hh | 31 +++ agent/native_linux/src/agent_info.cc | 74 +++++++ .../inc/com/centreon/agent/check_cpu.hh | 13 +- .../inc/com/centreon/agent/ntdll.hh | 51 +++++ agent/native_windows/src/agent_info.cc | 61 ++++++ agent/native_windows/src/check_cpu.cc | 55 +---- agent/native_windows/src/check_service.cc | 7 +- agent/native_windows/src/ntdll.cc | 59 ++++++ agent/proto/agent.proto | 2 + agent/src/check_health.cc | 4 + agent/src/main.cc | 3 + agent/src/main_win.cc | 21 +- agent/src/streaming_client.cc | 10 +- agent/src/streaming_server.cc | 10 +- agent/test/CMakeLists.txt | 2 +- agent/test/check_windows_cpu_test.cc | 15 +- agent/test/test_main.cc | 11 +- bbdo/events.hh | 1 + bbdo/neb.proto | 17 ++ .../com/centreon/broker/sql/mysql_error.hh | 3 +- .../inc/com/centreon/broker/neb/callbacks.hh | 2 + .../inc/com/centreon/broker/neb/internal.hh | 3 + broker/neb/src/broker.cc | 5 +- broker/neb/src/callbacks.cc | 32 ++- .../com/centreon/broker/unified_sql/stream.hh | 4 +- broker/unified_sql/src/stream.cc | 2 +- broker/unified_sql/src/stream_sql.cc | 56 ++++++ engine/inc/com/centreon/engine/broker.hh | 5 + .../inc/com/centreon/engine/nebcallbacks.hh | 3 +- engine/inc/com/centreon/engine/nebstructs.hh | 31 +++ engine/modules/opentelemetry/CMakeLists.txt | 1 + .../centreon_agent/agent_impl.hh | 11 +- .../centreon_agent/agent_reverse_client.hh | 6 +- .../centreon_agent/agent_service.hh | 9 +- .../centreon_agent/agent_stat.hh | 78 ++++++++ .../centreon_agent/to_agent_connector.hh | 9 +- .../modules/opentelemetry/open_telemetry.hh | 2 + .../modules/opentelemetry/otl_server.hh | 6 +- .../src/centreon_agent/agent_impl.cc | 12 +- .../centreon_agent/agent_reverse_client.cc | 10 +- .../src/centreon_agent/agent_service.cc | 20 +- .../src/centreon_agent/agent_stat.cc | 188 ++++++++++++++++++ .../src/centreon_agent/to_agent_connector.cc | 26 ++- .../opentelemetry/src/open_telemetry.cc | 8 +- .../modules/opentelemetry/src/otl_server.cc | 13 +- engine/src/broker.cc | 11 + engine/tests/opentelemetry/otl_server_test.cc | 5 +- resources/centreon_storage.sql | 12 ++ tests/broker-engine/cma.robot | 51 +++++ tests/resources/Common.py | 46 ++++- 51 files changed, 975 insertions(+), 147 deletions(-) create mode 100644 agent/inc/com/centreon/agent/agent_info.hh create mode 100644 agent/native_linux/src/agent_info.cc create mode 100644 agent/native_windows/inc/com/centreon/agent/ntdll.hh create mode 100644 agent/native_windows/src/agent_info.cc create mode 100644 agent/native_windows/src/ntdll.cc create mode 100644 engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_stat.hh create mode 100644 engine/modules/opentelemetry/src/centreon_agent/agent_stat.cc diff --git a/agent/CMakeLists.txt b/agent/CMakeLists.txt index fcb871ef427..385a2addd1a 100644 --- a/agent/CMakeLists.txt +++ b/agent/CMakeLists.txt @@ -107,6 +107,7 @@ set(NATIVE_INC "${PROJECT_SOURCE_DIR}/${NATIVE_DIR}/inc/com/centreon/agent") set(NATIVE_SRC "${PROJECT_SOURCE_DIR}/${NATIVE_DIR}/src") set( SRC_COMMON + ${NATIVE_SRC}/agent_info.cc ${NATIVE_SRC}/check_cpu.cc ${SRC_DIR}/agent.grpc.pb.cc ${SRC_DIR}/agent.pb.cc @@ -131,6 +132,7 @@ set( SRC_WINDOWS ${NATIVE_SRC}/check_drive_size.cc ${NATIVE_SRC}/check_memory.cc ${NATIVE_SRC}/check_service.cc + ${NATIVE_SRC}/ntdll.cc ) set( SRC_LINUX @@ -195,7 +197,8 @@ else() gRPC::gpr gRPC::grpc gRPC::grpc++ gRPC::grpc++_alts absl::any absl::log absl::base absl::bits Boost::program_options - fmt::fmt) + fmt::fmt + pdh) if(WITH_BUILD_AGENT_INSTALLER OR WITH_BUILD_AGENT_MODIFIER) add_subdirectory(installer) diff --git a/agent/inc/com/centreon/agent/agent_info.hh b/agent/inc/com/centreon/agent/agent_info.hh new file mode 100644 index 00000000000..33ecb345146 --- /dev/null +++ b/agent/inc/com/centreon/agent/agent_info.hh @@ -0,0 +1,31 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_AGENT_INFO_HH +#define CENTREON_AGENT_AGENT_INFO_HH + +#include "agent.pb.h" + +namespace com::centreon::agent { + +void read_os_version(); + +void fill_agent_info(const std::string& supervised_host, + ::com::centreon::agent::AgentInfo* agent_info); +} // namespace com::centreon::agent +#endif \ No newline at end of file diff --git a/agent/native_linux/src/agent_info.cc b/agent/native_linux/src/agent_info.cc new file mode 100644 index 00000000000..42d6d26f6a2 --- /dev/null +++ b/agent/native_linux/src/agent_info.cc @@ -0,0 +1,74 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "agent_info.hh" +#include "version.hh" + +static std::string _os; +static std::string _os_version; + +/** + * @brief read os version + * to call at the beginning of program + * + */ +void com::centreon::agent::read_os_version() { + std::fstream os_release("/etc/os-release", std::fstream::in); + if (os_release.is_open()) { + enum { os_found = 1, version_found = 2, all_found = 3 }; + unsigned found = 0; + std::string line; + while (std::getline(os_release, line) && found != all_found) { + if (!line.compare(0, 3, "ID=")) { + line.erase(0, 3); + boost::algorithm::trim_if(line, [](const char c) { + return c == '"' || c == ' ' || c == '\''; + }); + _os = line; + found |= os_found; + } else if (!line.compare(0, 11, "VERSION_ID=")) { + line.erase(0, 11); + boost::algorithm::trim_if(line, [](const char c) { + return c == '"' || c == ' ' || c == '\''; + }); + _os_version = line; + found |= version_found; + } + } + } +} + +/** + * @brief fill agent_info with agent and os versions + * + * @param supervised_host host configured + * @param agent_info pointer to object to fill + */ +void com::centreon::agent::fill_agent_info( + const std::string& supervised_host, + ::com::centreon::agent::AgentInfo* agent_info) { + agent_info->mutable_centreon_version()->set_major( + CENTREON_AGENT_VERSION_MAJOR); + agent_info->mutable_centreon_version()->set_minor( + CENTREON_AGENT_VERSION_MINOR); + agent_info->mutable_centreon_version()->set_patch( + CENTREON_AGENT_VERSION_PATCH); + agent_info->set_host(supervised_host); + agent_info->set_os(_os); + agent_info->set_os_version(_os_version); +} diff --git a/agent/native_windows/inc/com/centreon/agent/check_cpu.hh b/agent/native_windows/inc/com/centreon/agent/check_cpu.hh index f1d8421293d..94654fffad5 100644 --- a/agent/native_windows/inc/com/centreon/agent/check_cpu.hh +++ b/agent/native_windows/inc/com/centreon/agent/check_cpu.hh @@ -19,6 +19,8 @@ #ifndef CENTREON_AGENT_CHECK_CPU_HH #define CENTREON_AGENT_CHECK_CPU_HH +#include "ntdll.hh" + #include "native_check_cpu_base.hh" namespace com::centreon::agent { @@ -26,17 +28,6 @@ namespace com::centreon::agent { namespace check_cpu_detail { enum e_proc_stat_index { user = 0, system, idle, interrupt, dpc, nb_field }; -/**As winternl.h may be included, we define our own - * SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION */ -struct M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; -}; - /** * @brief this class contains all counter for one core contained in a * M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structure diff --git a/agent/native_windows/inc/com/centreon/agent/ntdll.hh b/agent/native_windows/inc/com/centreon/agent/ntdll.hh new file mode 100644 index 00000000000..c4f57edc3d3 --- /dev/null +++ b/agent/native_windows/inc/com/centreon/agent/ntdll.hh @@ -0,0 +1,51 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_NTDLL_HH +#define CENTREON_AGENT_NTDLL_HH + +namespace com::centreon::agent { + +/**As winternl.h may be included, we define our own + * SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION */ +struct M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +}; + +void load_nt_dll(); + +typedef LONG(WINAPI* NtQuerySystemInformationPtr)(ULONG SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + +extern NtQuerySystemInformationPtr nt_query_system_information; + +typedef NTSTATUS(NTAPI* RtlGetVersionPtr)( + POSVERSIONINFOEXW lpVersionInformation); + +extern RtlGetVersionPtr rtl_get_version; + +} // namespace com::centreon::agent + +#endif diff --git a/agent/native_windows/src/agent_info.cc b/agent/native_windows/src/agent_info.cc new file mode 100644 index 00000000000..f2250aca5bd --- /dev/null +++ b/agent/native_windows/src/agent_info.cc @@ -0,0 +1,61 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "agent_info.hh" +#include "ntdll.hh" +#include "version.hh" + +static std::string _os; +static std::string _os_version; + +/** + * @brief read os version + * to call at the beginning of program + * + */ +void com::centreon::agent::read_os_version() { + RTL_OSVERSIONINFOEXW osvi; + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (rtl_get_version(&osvi) == 0) { + _os = osvi.wProductType == VER_NT_SERVER ? "windows-server" : "windows"; + _os_version = std::to_string(osvi.dwMajorVersion) + "." + + std::to_string(osvi.dwMinorVersion) + "." + + std::to_string(osvi.dwBuildNumber); + } +} + +/** + * @brief fill agent_info with agent and os versions + * + * @param supervised_host host configured + * @param agent_info pointer to object to fill + */ +void com::centreon::agent::fill_agent_info( + const std::string& supervised_host, + ::com::centreon::agent::AgentInfo* agent_info) { + agent_info->mutable_centreon_version()->set_major( + CENTREON_AGENT_VERSION_MAJOR); + agent_info->mutable_centreon_version()->set_minor( + CENTREON_AGENT_VERSION_MINOR); + agent_info->mutable_centreon_version()->set_patch( + CENTREON_AGENT_VERSION_PATCH); + agent_info->set_host(supervised_host); + agent_info->set_os(_os); + agent_info->set_os_version(_os_version); +} \ No newline at end of file diff --git a/agent/native_windows/src/check_cpu.cc b/agent/native_windows/src/check_cpu.cc index 96ccc641ae3..90e83d924f4 100644 --- a/agent/native_windows/src/check_cpu.cc +++ b/agent/native_windows/src/check_cpu.cc @@ -22,10 +22,10 @@ #include #include "check_cpu.hh" +#include "com/centreon/common/rapidjson_helper.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "native_check_cpu_base.cc" -#pragma comment(lib, "pdh.lib") - using namespace com::centreon::agent; using namespace com::centreon::agent::check_cpu_detail; @@ -33,23 +33,6 @@ using namespace com::centreon::agent::check_cpu_detail; Kernel measure method ***************************************************************************/ -namespace com::centreon::agent::check_cpu_detail { - -// ntdll.dll handle -static HMODULE _ntdll = nullptr; - -typedef LONG(WINAPI* NtQuerySystemInformationPtr)(ULONG SystemInformationClass, - PVOID SystemInformation, - ULONG SystemInformationLength, - PULONG ReturnLength); - -// NtQuerySystemInformation function address -static NtQuerySystemInformationPtr _nt_query_system_information = nullptr; - -constexpr ULONG SystemProcessorPerformanceInformationClass = 8; - -} // namespace com::centreon::agent::check_cpu_detail - /** * @brief Construct a kernel_per_cpu_time object from a * SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION @@ -72,29 +55,6 @@ kernel_per_cpu_time::kernel_per_cpu_time( _total_used = _total - _metrics[e_proc_stat_index::idle]; } -/** - * @brief load ntdll.dll and get NtQuerySystemInformation address - * - */ -static void _ntdll_init() { - if (!_ntdll) { - _ntdll = LoadLibraryA("ntdll.dll"); - if (!_ntdll) { - throw std::runtime_error("Failed to load ntdll.dll"); - } - } - - if (!_nt_query_system_information) - // Obtenir le pointeur de fonction NtQuerySystemInformation - _nt_query_system_information = (NtQuerySystemInformationPtr)GetProcAddress( - _ntdll, "NtQuerySystemInformation"); - if (!_nt_query_system_information) { - FreeLibrary(_ntdll); - throw std::runtime_error( - "Failed to get address of NtQuerySystemInformation"); - } -} - /** * @brief Construct a new kernel cpu time snapshot::kernel cpu time snapshot * object it loads alls CPUs time and compute the average @@ -110,9 +70,10 @@ kernel_cpu_time_snapshot::kernel_cpu_time_snapshot(unsigned nb_core) { memset(buffer.get(), 0, buffer_size); - if (_nt_query_system_information(SystemProcessorPerformanceInformationClass, - buffer.get(), buffer_size, - &return_length) != 0) { + if (nt_query_system_information( + 8 /*SystemProcessorPerformanceInformationClass*/ + , + buffer.get(), buffer_size, &return_length) != 0) { throw std::runtime_error("Failed to get kernel cpu time"); } @@ -447,9 +408,7 @@ check_cpu::check_cpu(const std::shared_ptr& io_context, throw; } - if (_use_nt_query_system_information) { - _ntdll_init(); - } else { + if (!_use_nt_query_system_information) { _pdh_counters = std::make_unique(); } } diff --git a/agent/native_windows/src/check_service.cc b/agent/native_windows/src/check_service.cc index f62679ab656..03781d5d53e 100644 --- a/agent/native_windows/src/check_service.cc +++ b/agent/native_windows/src/check_service.cc @@ -546,14 +546,15 @@ check_service::check_service( stat), _filter(args), _enumerator(_enumerator_constructor()) { - if (!args.IsObject()) { - return; - } _measure_to_status.emplace( std::make_tuple(e_service_metric::nb_service_metric, e_service_metric::nb_service_metric, e_status::ok), std::make_unique()); + if (!args.IsObject()) { + return; + } + for (auto member_iter = args.MemberBegin(); member_iter != args.MemberEnd(); ++member_iter) { std::string key = absl::AsciiStrToLower(member_iter->name.GetString()); diff --git a/agent/native_windows/src/ntdll.cc b/agent/native_windows/src/ntdll.cc new file mode 100644 index 00000000000..df0207ffa8c --- /dev/null +++ b/agent/native_windows/src/ntdll.cc @@ -0,0 +1,59 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "ntdll.hh" + +namespace com::centreon::agent { + +// ntdll.dll handle +static HMODULE _ntdll = nullptr; + +NtQuerySystemInformationPtr nt_query_system_information = nullptr; +RtlGetVersionPtr rtl_get_version = nullptr; + +/** + * @brief load ntdll.dll and get NtQuerySystemInformation and RtlGetVersion + * address + * + */ +void load_nt_dll() { + if (!_ntdll) { + _ntdll = LoadLibraryA("ntdll.dll"); + if (!_ntdll) { + throw std::runtime_error("Failed to load ntdll.dll"); + } + } + + // get NtQuerySystemInformation Pointer + nt_query_system_information = (NtQuerySystemInformationPtr)GetProcAddress( + _ntdll, "NtQuerySystemInformation"); + if (!nt_query_system_information) { + FreeLibrary(_ntdll); + _ntdll = nullptr; + throw std::runtime_error( + "Failed to get address of NtQuerySystemInformation"); + } + + rtl_get_version = (RtlGetVersionPtr)GetProcAddress(_ntdll, "RtlGetVersion"); + if (!rtl_get_version) { + FreeLibrary(_ntdll); + _ntdll = nullptr; + throw std::runtime_error("Failed to get address of RtlGetVersion"); + } +} +} // namespace com::centreon::agent \ No newline at end of file diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto index 5a9190d2c12..f555d0e169a 100644 --- a/agent/proto/agent.proto +++ b/agent/proto/agent.proto @@ -63,6 +63,8 @@ message AgentInfo { //host name of the computer of the agent string host=1; Version centreon_version=2; + string os=3; //can be alma, windows, etc + string os_version=4; } //Agent configuration sent by Engine diff --git a/agent/src/check_health.cc b/agent/src/check_health.cc index 2e9668acb21..4414de8ce52 100644 --- a/agent/src/check_health.cc +++ b/agent/src/check_health.cc @@ -59,6 +59,10 @@ check_health::check_health(const std::shared_ptr& io_context, cnf, std::move(handler), stat), + _warning_check_interval(0), + _critical_check_interval(0), + _warning_check_duration(0), + _critical_check_duration(0), _measure_timer(*io_context) { com::centreon::common::rapidjson_helper arg(args); try { diff --git a/agent/src/main.cc b/agent/src/main.cc index aac284607ea..42ca20cd889 100644 --- a/agent/src/main.cc +++ b/agent/src/main.cc @@ -20,6 +20,7 @@ #include #include +#include "agent_info.hh" #include "check_cpu.hh" #include "check_health.hh" @@ -190,6 +191,8 @@ int main(int argc, char* argv[]) { return -1; } + read_os_version(); + if (conf.use_reverse_connection()) { _streaming_server = streaming_server::load(g_io_context, g_logger, grpc_conf, conf.get_host()); diff --git a/agent/src/main_win.cc b/agent/src/main_win.cc index 09128e057b4..c6c10608eca 100644 --- a/agent/src/main_win.cc +++ b/agent/src/main_win.cc @@ -17,6 +17,7 @@ */ #include +#include "agent_info.hh" #include "check_cpu.hh" #include "check_health.hh" #include "check_memory.hh" @@ -31,6 +32,7 @@ #include "config.hh" #include "drive_size.hh" +#include "ntdll.hh" #include "streaming_client.hh" #include "streaming_server.hh" @@ -220,15 +222,18 @@ int _main(bool service_start) { return -1; } - if (conf.use_reverse_connection()) { - _streaming_server = streaming_server::load(g_io_context, g_logger, - grpc_conf, conf.get_host()); - } else { - _streaming_client = streaming_client::load(g_io_context, g_logger, - grpc_conf, conf.get_host()); - } - try { + load_nt_dll(); + read_os_version(); + + if (conf.use_reverse_connection()) { + _streaming_server = streaming_server::load(g_io_context, g_logger, + grpc_conf, conf.get_host()); + } else { + _streaming_client = streaming_client::load(g_io_context, g_logger, + grpc_conf, conf.get_host()); + } + g_io_context->run(); } catch (const std::exception& e) { SPDLOG_LOGGER_CRITICAL(g_logger, "unhandled exception: {}", e.what()); diff --git a/agent/src/streaming_client.cc b/agent/src/streaming_client.cc index d93b7d93a65..df8960d05ff 100644 --- a/agent/src/streaming_client.cc +++ b/agent/src/streaming_client.cc @@ -16,10 +16,9 @@ * For more information : contact@centreon.com */ +#include "agent_info.hh" #include "streaming_client.hh" -#include "check_exec.hh" #include "com/centreon/common/defer.hh" -#include "version.hh" using namespace com::centreon::agent; @@ -144,12 +143,7 @@ void streaming_client::_create_reactor() { // identifies to engine std::shared_ptr who_i_am = std::make_shared(); - auto infos = who_i_am->mutable_init(); - - infos->mutable_centreon_version()->set_major(CENTREON_AGENT_VERSION_MAJOR); - infos->mutable_centreon_version()->set_minor(CENTREON_AGENT_VERSION_MINOR); - infos->mutable_centreon_version()->set_patch(CENTREON_AGENT_VERSION_PATCH); - infos->set_host(_supervised_host); + fill_agent_info(_supervised_host, who_i_am->mutable_init()); _reactor->write(who_i_am); } diff --git a/agent/src/streaming_server.cc b/agent/src/streaming_server.cc index 681ce348a25..e6ad15d6717 100644 --- a/agent/src/streaming_server.cc +++ b/agent/src/streaming_server.cc @@ -16,10 +16,9 @@ * For more information : contact@centreon.com */ +#include "agent_info.hh" #include "streaming_server.hh" -#include "check_exec.hh" #include "scheduler.hh" -#include "version.hh" using namespace com::centreon::agent; @@ -88,12 +87,7 @@ void server_reactor::_start() { // identifies to engine std::shared_ptr who_i_am = std::make_shared(); - auto infos = who_i_am->mutable_init(); - - infos->mutable_centreon_version()->set_major(CENTREON_AGENT_VERSION_MAJOR); - infos->mutable_centreon_version()->set_minor(CENTREON_AGENT_VERSION_MINOR); - infos->mutable_centreon_version()->set_patch(CENTREON_AGENT_VERSION_PATCH); - infos->set_host(_supervised_host); + fill_agent_info(_supervised_host, who_i_am->mutable_init()); write(who_i_am); } diff --git a/agent/test/CMakeLists.txt b/agent/test/CMakeLists.txt index 6150262e440..89da2f4b434 100644 --- a/agent/test/CMakeLists.txt +++ b/agent/test/CMakeLists.txt @@ -77,7 +77,7 @@ else() Boost::program_options gRPC::gpr gRPC::grpc gRPC::grpc++ gRPC::grpc++_alts fmt::fmt - ) + pdh) endif() add_dependencies(ut_agent centreon_common centagent_lib) diff --git a/agent/test/check_windows_cpu_test.cc b/agent/test/check_windows_cpu_test.cc index cce9d371679..5826a585208 100644 --- a/agent/test/check_windows_cpu_test.cc +++ b/agent/test/check_windows_cpu_test.cc @@ -28,7 +28,7 @@ using namespace com::centreon::agent; using namespace std::string_literals; TEST(native_check_cpu_windows, construct) { - check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info; + M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info; info.IdleTime.QuadPart = 60; info.KernelTime.QuadPart = 70; info.UserTime.QuadPart = 25; @@ -50,13 +50,14 @@ TEST(native_check_cpu_windows, construct) { ASSERT_EQ(k.get_proportional_used(), 0.4); } -constexpr check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[2] = - {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; +constexpr M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[2] = { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}}; TEST(native_check_cpu_windows, output_no_threshold) { check_cpu_detail::kernel_cpu_time_snapshot first(info, info + 2); - check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; + M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; info2[0].IdleTime.QuadPart = 60; info2[0].KernelTime.QuadPart = 70; info2[0].UserTime.QuadPart = 25; @@ -117,7 +118,7 @@ TEST(native_check_cpu_windows, output_no_threshold) { TEST(native_check_cpu_windows, output_no_threshold_detailed) { check_cpu_detail::kernel_cpu_time_snapshot first(info, info + 2); - check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; + M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; info2[0].IdleTime.QuadPart = 60; info2[0].KernelTime.QuadPart = 70; info2[0].UserTime.QuadPart = 25; @@ -213,7 +214,7 @@ TEST(native_check_cpu_windows, output_no_threshold_detailed) { TEST(native_check_cpu_windows, output_threshold) { check_cpu_detail::kernel_cpu_time_snapshot first(info, info + 2); - check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; + M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; info2[0].IdleTime.QuadPart = 60; info2[0].KernelTime.QuadPart = 70; info2[0].UserTime.QuadPart = 25; @@ -287,7 +288,7 @@ TEST(native_check_cpu_windows, output_threshold) { TEST(native_check_cpu_windows, output_threshold_detailed) { check_cpu_detail::kernel_cpu_time_snapshot first(info, info + 2); - check_cpu_detail::M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; + M_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info2[2]; info2[0].IdleTime.QuadPart = 60; info2[0].KernelTime.QuadPart = 70; info2[0].UserTime.QuadPart = 25; diff --git a/agent/test/test_main.cc b/agent/test/test_main.cc index eea1558b443..e13a6cc5d44 100644 --- a/agent/test/test_main.cc +++ b/agent/test/test_main.cc @@ -18,17 +18,22 @@ #include +#ifdef _WIN32 +#include "ntdll.hh" +#endif + std::shared_ptr g_io_context( std::make_shared()); class CentreonEngineEnvironment : public testing::Environment { public: -#ifndef _WIN32 void SetUp() override { +#ifndef _WIN32 setenv("TZ", ":Europe/Paris", 1); - return; - } +#else + com::centreon::agent::load_nt_dll(); #endif + } }; /** diff --git a/bbdo/events.hh b/bbdo/events.hh index 35321c6f7e2..7db7d897269 100644 --- a/bbdo/events.hh +++ b/bbdo/events.hh @@ -156,6 +156,7 @@ enum data_element { de_pb_instance_configuration = 54, de_pb_adaptive_service_status = 55, de_pb_adaptive_host_status = 56, + de_pb_agent_stats = 57 }; } // namespace neb namespace storage { diff --git a/bbdo/neb.proto b/bbdo/neb.proto index bb5bc4051be..2380428539b 100644 --- a/bbdo/neb.proto +++ b/bbdo/neb.proto @@ -842,3 +842,20 @@ message TagInfo { uint64 id = 1; TagType type = 2; } + +/* Ignore */ +message AgentInfo { + uint32 major = 1; + uint32 minor = 2; + uint32 patch = 3; + bool reverse = 4; + string os = 5; + string os_version = 6; + uint32 nb_agent = 7; +} + +/* io::neb, neb::de_pb_agent_stats, 57 */ +message AgentStats { + int64 poller_id = 1; + repeated AgentInfo stats = 2; +} \ No newline at end of file diff --git a/broker/core/sql/inc/com/centreon/broker/sql/mysql_error.hh b/broker/core/sql/inc/com/centreon/broker/sql/mysql_error.hh index 651d02c54ba..68dd4ddb4b4 100644 --- a/broker/core/sql/inc/com/centreon/broker/sql/mysql_error.hh +++ b/broker/core/sql/inc/com/centreon/broker/sql/mysql_error.hh @@ -114,6 +114,7 @@ class mysql_error { update_services_enabled = 78, update_hosts_resources_enabled = 79, update_services_resources_enabled = 80, + insert_update_agent_information = 81 }; static constexpr const char* msg[]{ @@ -199,7 +200,7 @@ class mysql_error { "could not update the enabled flag in services table: ", "could not update the enabled flag in resources table for host: ", "could not update the enabled flag in resources table for service: ", - }; + "could not insert or update agent_information table: "}; mysql_error() : _active(false) {} mysql_error(mysql_error const& other) = delete; diff --git a/broker/neb/inc/com/centreon/broker/neb/callbacks.hh b/broker/neb/inc/com/centreon/broker/neb/callbacks.hh index f9ee10a1cb1..d411463a499 100644 --- a/broker/neb/inc/com/centreon/broker/neb/callbacks.hh +++ b/broker/neb/inc/com/centreon/broker/neb/callbacks.hh @@ -70,6 +70,8 @@ int callback_pb_bench(int callback_type, void* data); int callback_otl_metrics(int callback_type, void* data); +int callback_agent_stats(int callback_type, void* data); + void unregister_callbacks(); } // namespace neb diff --git a/broker/neb/inc/com/centreon/broker/neb/internal.hh b/broker/neb/inc/com/centreon/broker/neb/internal.hh index 249be673d4d..d57d1131eb0 100644 --- a/broker/neb/inc/com/centreon/broker/neb/internal.hh +++ b/broker/neb/inc/com/centreon/broker/neb/internal.hh @@ -126,6 +126,9 @@ using pb_otl_metrics = io::protobuf< opentelemetry::proto::collector::metrics::v1::ExportMetricsServiceRequest, make_type(io::storage, storage::de_pb_otl_metrics)>; +using pb_agent_stats = + io::protobuf; + } // namespace neb } // namespace com::centreon::broker diff --git a/broker/neb/src/broker.cc b/broker/neb/src/broker.cc index c69613aacc8..f75dba58b76 100644 --- a/broker/neb/src/broker.cc +++ b/broker/neb/src/broker.cc @@ -167,8 +167,7 @@ void broker_module_init(void const* arg) { &neb::pb_host_status::operations, "hosts"); e.register_event(make_type(io::neb, neb::de_pb_adaptive_host_status), "AdaptiveHostStatus", - &neb::pb_adaptive_host_status::operations, - "hosts"); + &neb::pb_adaptive_host_status::operations, "hosts"); e.register_event(make_type(io::neb, neb::de_pb_severity), "Severity", &neb::pb_severity::operations, "severities"); @@ -228,6 +227,8 @@ void broker_module_init(void const* arg) { &neb::pb_instance_configuration::operations, "no_table"); e.register_event(neb::pb_otl_metrics::static_type(), "OTLMetrics", &neb::pb_otl_metrics::operations, "otl_metrics"); + e.register_event(neb::pb_agent_stats::static_type(), "AgentStats", + &neb::pb_agent_stats::operations, "agent_information"); } } } diff --git a/broker/neb/src/callbacks.cc b/broker/neb/src/callbacks.cc index c6dbc69e4fd..deeabb59047 100644 --- a/broker/neb/src/callbacks.cc +++ b/broker/neb/src/callbacks.cc @@ -27,6 +27,7 @@ #include "com/centreon/broker/config/parser.hh" #include "com/centreon/broker/neb/events.hh" #include "com/centreon/broker/neb/initial.hh" +#include "com/centreon/broker/neb/internal.hh" #include "com/centreon/broker/neb/set_log_data.hh" #include "com/centreon/common/file.hh" #include "com/centreon/common/time.hh" @@ -35,6 +36,7 @@ #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/events/loop.hh" #include "com/centreon/engine/globals.hh" +#include "com/centreon/engine/nebcallbacks.hh" #include "com/centreon/engine/nebstructs.hh" #include "com/centreon/engine/severity.hh" @@ -112,7 +114,8 @@ static struct { {NEBCALLBACK_GROUP_DATA, &neb::callback_group}, {NEBCALLBACK_GROUP_MEMBER_DATA, &neb::callback_group_member}, {NEBCALLBACK_RELATION_DATA, &neb::callback_relation}, - {NEBCALLBACK_BENCH_DATA, &neb::callback_pb_bench}}; + {NEBCALLBACK_BENCH_DATA, &neb::callback_pb_bench}, + {NEBCALLBACK_AGENT_STATS, &neb::callback_agent_stats}}; static struct { uint32_t macro; @@ -124,7 +127,8 @@ static struct { {NEBCALLBACK_GROUP_DATA, &neb::callback_pb_group}, {NEBCALLBACK_GROUP_MEMBER_DATA, &neb::callback_pb_group_member}, {NEBCALLBACK_RELATION_DATA, &neb::callback_pb_relation}, - {NEBCALLBACK_BENCH_DATA, &neb::callback_pb_bench}}; + {NEBCALLBACK_BENCH_DATA, &neb::callback_pb_bench}, + {NEBCALLBACK_AGENT_STATS, &neb::callback_agent_stats}}; // Registered callbacks. std::list> neb::gl_registered_callbacks; @@ -3793,6 +3797,30 @@ int neb::callback_otl_metrics(int, void* data) { return 0; } +int neb::callback_agent_stats(int, void* data) { + nebstruct_agent_stats_data* ds = + static_cast(data); + + auto to_send = std::make_shared(); + + to_send->mut_obj().set_poller_id( + config::applier::state::instance().poller_id()); + + for (const auto& cumul_data : *ds->data) { + AgentInfo* to_fill = to_send->mut_obj().add_stats(); + to_fill->set_major(cumul_data.major); + to_fill->set_minor(cumul_data.minor); + to_fill->set_patch(cumul_data.patch); + to_fill->set_reverse(cumul_data.reverse); + to_fill->set_os(cumul_data.os); + to_fill->set_os_version(cumul_data.os_version); + to_fill->set_nb_agent(cumul_data.nb_agent); + } + + gl_publisher.write(to_send); + return 0; +} + /** * Unregister callbacks. */ diff --git a/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh b/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh index 9e7e81cd058..079064e1406 100644 --- a/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh +++ b/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh @@ -408,6 +408,8 @@ class stream : public io::stream { database::mysql_stmt _index_data_query; database::mysql_stmt _metrics_insert; + database::mysql_stmt _agent_information_insert_update; + void _update_hosts_and_services_of_unresponsive_instances(); void _update_hosts_and_services_of_instance(uint32_t id, bool responsive); void _update_timestamp(uint32_t instance_id); @@ -467,7 +469,7 @@ class stream : public io::stream { void _process_tag(const std::shared_ptr& d); void _process_pb_log(const std::shared_ptr& d); void _process_pb_responsive_instance(const std::shared_ptr& d); - + void _process_agent_stats(const std::shared_ptr& d); void _unified_sql_process_service_status(const std::shared_ptr& d); void _check_and_update_index_cache(const Service& ss); diff --git a/broker/unified_sql/src/stream.cc b/broker/unified_sql/src/stream.cc index 30d1b924188..15660a814f8 100644 --- a/broker/unified_sql/src/stream.cc +++ b/broker/unified_sql/src/stream.cc @@ -108,7 +108,7 @@ constexpr void (stream::*const stream::neb_processing_table[])( &stream::_process_pb_instance_configuration, &stream::_process_pb_adaptive_service_status, &stream::_process_pb_adaptive_host_status, -}; + &stream::_process_agent_stats}; constexpr size_t neb_processing_table_size = sizeof(stream::neb_processing_table) / diff --git a/broker/unified_sql/src/stream_sql.cc b/broker/unified_sql/src/stream_sql.cc index acb608750d3..63b5e512767 100644 --- a/broker/unified_sql/src/stream_sql.cc +++ b/broker/unified_sql/src/stream_sql.cc @@ -16,6 +16,10 @@ * For more information : contact@centreon.com */ +#include +#include +#include +#include #include "bbdo/storage/index_mapping.hh" #include "com/centreon/broker/cache/global_cache.hh" #include "com/centreon/broker/misc/string.hh" @@ -292,6 +296,10 @@ void stream::_update_hosts_and_services_of_instance(uint32_t id, id); _mysql.run_query(query, database::mysql_error::restore_instances, conn); _add_action(conn, actions::services); + query = fmt::format( + "UPDATE agent_information SET enabled = 1 WHERE poller_id={}", id); + _mysql.run_query(query, database::mysql_error::restore_instances, conn); + _add_action(conn, actions::services); } else { query = fmt::format( "UPDATE instances SET outdated=TRUE WHERE instance_id={}", id); @@ -306,6 +314,10 @@ void stream::_update_hosts_and_services_of_instance(uint32_t id, id); _mysql.run_query(query, database::mysql_error::restore_instances, conn); _add_action(conn, actions::hosts); + query = fmt::format( + "UPDATE agent_information SET enabled = 0 WHERE poller_id={}", id); + _mysql.run_query(query, database::mysql_error::restore_instances, conn); + _add_action(conn, actions::services); } auto bbdo = config::applier::state::instance().get_bbdo_version(); SPDLOG_LOGGER_TRACE( @@ -5169,6 +5181,50 @@ void stream::_process_tag(const std::shared_ptr& d) { } } +void stream::_process_agent_stats(const std::shared_ptr& d) { + SPDLOG_LOGGER_INFO(_logger_sql, "unified_sql: processing agent stats"); + std::shared_ptr as{ + std::static_pointer_cast(d)}; + + std::string json_infos; + + const AgentStats& stats = as->obj(); + + using namespace rapidjson; + Document doc(rapidjson::kArrayType); + + for (const AgentInfo& info : stats.stats()) { + rapidjson::Value stat(rapidjson::kObjectType); + stat.AddMember("agent_major", info.major(), doc.GetAllocator()); + stat.AddMember("agent_minor", info.minor(), doc.GetAllocator()); + stat.AddMember("agent_patch", info.patch(), doc.GetAllocator()); + stat.AddMember("reverse", info.reverse(), doc.GetAllocator()); + stat.AddMember("os", StringRef(info.os().c_str()), doc.GetAllocator()); + stat.AddMember("os_version", StringRef(info.os_version().c_str()), + doc.GetAllocator()); + stat.AddMember("nb_agent", info.nb_agent(), doc.GetAllocator()); + doc.PushBack(stat, doc.GetAllocator()); + } + StringBuffer out_buff; + Writer writer(out_buff); + doc.Accept(writer); + + if (!_agent_information_insert_update.prepared()) { + _agent_information_insert_update = _mysql.prepare_query( + "INSERT INTO agent_information (poller_id, enabled, infos) VALUES " + "(?,?,?) ON DUPLICATE KEY UPDATE enabled=VALUES(enabled), " + "infos=VALUES(infos)"); + } + int32_t conn = _mysql.choose_connection_by_instance(stats.poller_id()); + + _agent_information_insert_update.bind_value_as_u32(0, stats.poller_id()); + _agent_information_insert_update.bind_value_as_bool(1, true); + _agent_information_insert_update.bind_value_as_str(2, out_buff.GetString()); + _mysql.run_statement(_agent_information_insert_update, + database::mysql_error::insert_update_agent_information, + conn); +} + /** * Process a responsive instance event. * diff --git a/engine/inc/com/centreon/engine/broker.hh b/engine/inc/com/centreon/engine/broker.hh index d1bececa863..e755b1d3cf1 100644 --- a/engine/inc/com/centreon/engine/broker.hh +++ b/engine/inc/com/centreon/engine/broker.hh @@ -22,6 +22,7 @@ #ifndef CCE_BROKER_HH #define CCE_BROKER_HH +#include "bbdo/neb.pb.h" #include "com/centreon/engine/commands/command.hh" #include "com/centreon/engine/comment.hh" #include "com/centreon/engine/events/timed_event.hh" @@ -520,6 +521,10 @@ struct timeval get_broker_timestamp(struct timeval const* timestamp); void broker_bench(unsigned id, const std::chrono::system_clock::time_point& mess_create); +struct nebstruct_agent_stats_data; + +void broker_agent_stats(nebstruct_agent_stats_data& stats); + #ifdef __cplusplus } #endif /* C++ */ diff --git a/engine/inc/com/centreon/engine/nebcallbacks.hh b/engine/inc/com/centreon/engine/nebcallbacks.hh index d382b6950f7..ac333b2c047 100644 --- a/engine/inc/com/centreon/engine/nebcallbacks.hh +++ b/engine/inc/com/centreon/engine/nebcallbacks.hh @@ -75,7 +75,8 @@ #define NEBCALLBACK_BENCH_DATA 45 #define NEBCALLBACK_OTL_METRICS 46 -#define NEBCALLBACK_NUMITEMS 47 /* Total number of callback types we have. */ +#define NEBCALLBACK_AGENT_STATS 47 +#define NEBCALLBACK_NUMITEMS 48 /* Total number of callback types we have. */ #ifdef __cplusplus extern "C" { diff --git a/engine/inc/com/centreon/engine/nebstructs.hh b/engine/inc/com/centreon/engine/nebstructs.hh index 271aa3b53d5..2b175542c6d 100644 --- a/engine/inc/com/centreon/engine/nebstructs.hh +++ b/engine/inc/com/centreon/engine/nebstructs.hh @@ -21,6 +21,8 @@ #ifndef CCE_NEBSTRUCTS_HH #define CCE_NEBSTRUCTS_HH +#include +#include "bbdo/neb.pb.h" #include "com/centreon/engine/comment.hh" /* Acknowledgement structure. */ @@ -255,4 +257,33 @@ typedef struct nebstruct_bench_struct { std::chrono::system_clock::time_point mess_create; } nebstruct_bench_data; +struct nebstruct_agent_stats_data { + struct cumul_data { + cumul_data(unsigned maj, + unsigned min, + unsigned pat, + bool rev, + const std::string& operating_system, + const std::string& os_ver, + size_t nb_ag) + : major(maj), + minor(min), + patch(pat), + reverse(rev), + os(operating_system), + os_version(os_ver), + nb_agent(nb_ag) {} + + unsigned major; + unsigned minor; + unsigned patch; + bool reverse; + std::string os; + std::string os_version; + size_t nb_agent; + }; + + std::unique_ptr> data; +}; + #endif /* !CCE_NEBSTRUCTS_HH */ diff --git a/engine/modules/opentelemetry/CMakeLists.txt b/engine/modules/opentelemetry/CMakeLists.txt index 84d6cb98a19..ad04953c771 100644 --- a/engine/modules/opentelemetry/CMakeLists.txt +++ b/engine/modules/opentelemetry/CMakeLists.txt @@ -69,6 +69,7 @@ ${SRC_DIR}/centreon_agent/agent_config.cc ${SRC_DIR}/centreon_agent/agent_impl.cc ${SRC_DIR}/centreon_agent/agent_reverse_client.cc ${SRC_DIR}/centreon_agent/agent_service.cc +${SRC_DIR}/centreon_agent/agent_stat.cc ${SRC_DIR}/centreon_agent/to_agent_connector.cc ${SRC_DIR}/grpc_config.cc ${SRC_DIR}/host_serv_extractor.cc diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh index c1e1a4a5c06..21695050119 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh @@ -19,7 +19,8 @@ #ifndef CCE_MOD_OTL_CENTREON_AGENT_AGENT_IMPL_HH #define CCE_MOD_OTL_CENTREON_AGENT_AGENT_IMPL_HH -#include "centreon_agent/agent.grpc.pb.h" +#include "agent_stat.hh" + #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_config.hh" #include "com/centreon/engine/modules/opentelemetry/otl_data_point.hh" @@ -39,6 +40,7 @@ class agent_impl public std::enable_shared_from_this> { std::shared_ptr _io_context; const std::string_view _class_name; + const bool _reversed; whitelist_cache _whitelist_cache; @@ -70,6 +72,9 @@ class agent_impl protected: std::shared_ptr _logger; bool _alive ABSL_GUARDED_BY(_protect); + + agent_stat::pointer _stats; + mutable absl::Mutex _protect; public: @@ -77,7 +82,9 @@ class agent_impl const std::string_view class_name, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + bool reversed, + const agent_stat::pointer& stats); virtual ~agent_impl(); diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_reverse_client.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_reverse_client.hh index cc02b91e8af..3d01a5ca314 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_reverse_client.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_reverse_client.hh @@ -20,6 +20,7 @@ #define CCE_MOD_OTL_CENTREON_AGENT_AGENT_REVERSE_CLIENT_HH #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_config.hh" +#include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_stat.hh" #include "com/centreon/engine/modules/opentelemetry/otl_data_point.hh" namespace com::centreon::engine::modules::opentelemetry::centreon_agent { @@ -39,6 +40,8 @@ class agent_reverse_client { absl::Mutex _agents_m; config_to_client _agents ABSL_GUARDED_BY(_agents_m); + agent_stat::pointer _agent_stats; + virtual config_to_client::iterator _create_new_client_connection( const grpc_config::pointer& agent_endpoint, const agent_config::pointer& agent_conf) @@ -50,7 +53,8 @@ class agent_reverse_client { agent_reverse_client( const std::shared_ptr& io_context, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); virtual ~agent_reverse_client(); diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_service.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_service.hh index a58f8263a50..54abebd58c7 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_service.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_service.hh @@ -19,6 +19,7 @@ #ifndef CCE_MOD_OTL_CENTREON_AGENT_AGENT_SERVICE_HH #define CCE_MOD_OTL_CENTREON_AGENT_AGENT_SERVICE_HH +#include "centreon_agent/agent.grpc.pb.h" #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_config.hh" #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh" @@ -38,11 +39,14 @@ class agent_service : public agent::AgentService::Service, metric_handler _metric_handler; std::shared_ptr _logger; + agent_stat::pointer _stats; + public: agent_service(const std::shared_ptr& io_context, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); void init(); @@ -50,7 +54,8 @@ class agent_service : public agent::AgentService::Service, const std::shared_ptr& io_context, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); // disable synchronous version of this method ::grpc::Status Export( diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_stat.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_stat.hh new file mode 100644 index 00000000000..90f50a3f124 --- /dev/null +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_stat.hh @@ -0,0 +1,78 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CCE_MOD_OTL_CENTREON_AGENT_AGENT_STAT_HH +#define CCE_MOD_OTL_CENTREON_AGENT_AGENT_STAT_HH + +#include +#include +#include +#include +#include "centreon_agent/agent.pb.h" + +namespace com::centreon::engine::modules::opentelemetry::centreon_agent { + +class agent_stat : public std::enable_shared_from_this { + using agent_info_set = std::set; + struct group_by_key + : public std::tuple< + unsigned /*agent major version*/, + unsigned /*agent minor version*/, + unsigned /*agent patch*/, + bool /*reverse*/, + std::string /*os almalinux, windows, windows-server...*/, + std::string /*os version*/> { + public: + group_by_key(const com::centreon::agent::AgentInfo& agent_info, + bool reversed); + }; + + using agent_info_map = absl::flat_hash_map; + + agent_info_map _data ABSL_GUARDED_BY(_protect); + + std::shared_ptr _io_context; + asio::system_timer _send_timer ABSL_GUARDED_BY(_protect); + bool _dirty ABSL_GUARDED_BY(_protect); + + mutable absl::Mutex _protect; + + void _on_stat_update() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(_protect); + + void _start_send_timer(); + void _send_timer_handler(const boost::system::error_code& err); + + public: + using pointer = std::shared_ptr; + + agent_stat(const std::shared_ptr& io_context); + + static pointer load(const std::shared_ptr& io_context); + + void stop_send_timer(); + + void add_agent(const com::centreon::agent::AgentInfo& agent_info, + bool reversed, + const void* reactor); + void remove_agent(const com::centreon::agent::AgentInfo& agent_info, + bool reversed, + const void* reactor); +}; + +} // namespace com::centreon::engine::modules::opentelemetry::centreon_agent +#endif \ No newline at end of file diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/to_agent_connector.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/to_agent_connector.hh index 3fc016aebb9..31c8d943849 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/to_agent_connector.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/to_agent_connector.hh @@ -20,6 +20,7 @@ #define CCE_MOD_OTL_CENTREON_AGENT_AGENT_CLIENT_HH #include "centreon_agent/agent.grpc.pb.h" +#include "centreon_agent/agent_stat.hh" #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_config.hh" #include "com/centreon/common/grpc/grpc_client.hh" @@ -47,12 +48,15 @@ class to_agent_connector absl::Mutex _connection_m; std::shared_ptr _connection ABSL_GUARDED_BY(_connection_m); + agent_stat::pointer _stats; + public: to_agent_connector(const grpc_config::pointer& agent_endpoint_conf, const std::shared_ptr& io_context, const agent_config::pointer& agent_conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); virtual ~to_agent_connector(); @@ -63,7 +67,8 @@ class to_agent_connector const std::shared_ptr& io_context, const agent_config::pointer& agent_conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); void refresh_agent_configuration_if_needed( const agent_config::pointer& new_conf); diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/open_telemetry.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/open_telemetry.hh index b30ba4664b3..a2777f95376 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/open_telemetry.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/open_telemetry.hh @@ -59,6 +59,8 @@ class open_telemetry : public commands::otel::open_telemetry_base { std::shared_ptr _io_context; mutable std::mutex _protect; + centreon_agent::agent_stat::pointer _agent_stats; + void _forward_to_broker(const std::vector& unknown); void _create_telegraf_conf_server( diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/otl_server.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/otl_server.hh index 935aac30d9c..728f96e1dab 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/otl_server.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/otl_server.hh @@ -46,7 +46,8 @@ class otl_server : public common::grpc::grpc_server_base { const grpc_config::pointer& conf, const centreon_agent::agent_config::pointer& agent_config, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const centreon_agent::agent_stat::pointer& agent_stats); void start(); public: @@ -59,7 +60,8 @@ class otl_server : public common::grpc::grpc_server_base { const grpc_config::pointer& conf, const centreon_agent::agent_config::pointer& agent_config, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const centreon_agent::agent_stat::pointer& agent_stats); void update_agent_config( const centreon_agent::agent_config::pointer& agent_config); diff --git a/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc b/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc index 1309b3f3de0..c57e7cc822f 100644 --- a/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc +++ b/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc @@ -57,14 +57,18 @@ agent_impl::agent_impl( const std::string_view class_name, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger) + const std::shared_ptr& logger, + bool reversed, + const agent_stat::pointer& stats) : _io_context(io_context), _class_name(class_name), + _reversed(reversed), _conf(conf), _metric_handler(handler), _write_pending(false), _logger(logger), - _alive(true) { + _alive(true), + _stats(stats) { SPDLOG_LOGGER_DEBUG(logger, "create {} this={:p}", _class_name, static_cast(this)); } @@ -76,6 +80,9 @@ agent_impl::agent_impl( */ template agent_impl::~agent_impl() { + if (_agent_info && _agent_info->has_init()) { + _stats->remove_agent(_agent_info->init(), _reversed, this); + } SPDLOG_LOGGER_DEBUG(_logger, "delete {} this={:p}", _class_name, static_cast(this)); } @@ -216,6 +223,7 @@ void agent_impl::on_request( agent_conf = _conf; _last_sent_config.reset(); } + _stats->add_agent(_agent_info->init(), _reversed, this); SPDLOG_LOGGER_DEBUG(_logger, "init from {}", get_peer()); calc_and_send_config_if_needed(agent_conf); } diff --git a/engine/modules/opentelemetry/src/centreon_agent/agent_reverse_client.cc b/engine/modules/opentelemetry/src/centreon_agent/agent_reverse_client.cc index 7c38cee5ad4..3f5ceaa54e3 100644 --- a/engine/modules/opentelemetry/src/centreon_agent/agent_reverse_client.cc +++ b/engine/modules/opentelemetry/src/centreon_agent/agent_reverse_client.cc @@ -31,8 +31,12 @@ using namespace com::centreon::engine::modules::opentelemetry::centreon_agent; agent_reverse_client::agent_reverse_client( const std::shared_ptr& io_context, const metric_handler& handler, - const std::shared_ptr& logger) - : _io_context(io_context), _metric_handler(handler), _logger(logger) {} + const std::shared_ptr& logger, + const agent_stat::pointer& stats) + : _io_context(io_context), + _metric_handler(handler), + _logger(logger), + _agent_stats(stats) {} /** * @brief Destroy the agent reverse client::agent reverse client object @@ -112,7 +116,7 @@ agent_reverse_client::_create_new_client_connection( auto insert_res = _agents.try_emplace( agent_endpoint, to_agent_connector::load(agent_endpoint, _io_context, agent_conf, - _metric_handler, _logger)); + _metric_handler, _logger, _agent_stats)); return insert_res.first; } diff --git a/engine/modules/opentelemetry/src/centreon_agent/agent_service.cc b/engine/modules/opentelemetry/src/centreon_agent/agent_service.cc index 8fea6fcb1bc..fa403d03cf3 100644 --- a/engine/modules/opentelemetry/src/centreon_agent/agent_service.cc +++ b/engine/modules/opentelemetry/src/centreon_agent/agent_service.cc @@ -37,14 +37,17 @@ class server_bireactor const agent_config::pointer& conf, const otel_request_handler& handler, const std::shared_ptr& logger, - const std::string& peer) + const std::string& peer, + agent_stat::pointer& stats) : agent_impl<::grpc::ServerBidiReactor>( io_context, "agent_server", conf, handler, - logger), + logger, + false, + stats), _peer(peer) { SPDLOG_LOGGER_DEBUG(_logger, "connected with agent {}", _peer); } @@ -84,11 +87,13 @@ agent_service::agent_service( const std::shared_ptr& io_context, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger) + const std::shared_ptr& logger, + const agent_stat::pointer& stats) : _io_context(io_context), _conf(conf), _metric_handler(handler), - _logger(logger) { + _logger(logger), + _stats(stats) { if (!_conf) { _conf = std::make_shared(60, 100, 10, 30); SPDLOG_LOGGER_INFO(logger, @@ -109,9 +114,10 @@ std::shared_ptr agent_service::load( const std::shared_ptr& io_context, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger) { + const std::shared_ptr& logger, + const agent_stat::pointer& stats) { std::shared_ptr ret = std::make_shared( - io_context, conf, std::move(handler), logger); + io_context, conf, std::move(handler), logger, stats); ret->init(); return ret; } @@ -144,7 +150,7 @@ agent_service::Export(::grpc::CallbackServerContext* context) { { absl::MutexLock l(&_conf_m); new_reactor = std::make_shared( - _io_context, _conf, _metric_handler, _logger, context->peer()); + _io_context, _conf, _metric_handler, _logger, context->peer(), _stats); } server_bireactor::register_stream(new_reactor); new_reactor->start_read(); diff --git a/engine/modules/opentelemetry/src/centreon_agent/agent_stat.cc b/engine/modules/opentelemetry/src/centreon_agent/agent_stat.cc new file mode 100644 index 00000000000..62c794c4ddc --- /dev/null +++ b/engine/modules/opentelemetry/src/centreon_agent/agent_stat.cc @@ -0,0 +1,188 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "com/centreon/engine/globals.hh" +#include "com/centreon/engine/host.hh" +#include "com/centreon/engine/nebstructs.hh" +#include "com/centreon/engine/service.hh" + +#include "com/centreon/engine/broker.hh" +#include "com/centreon/engine/command_manager.hh" + +#include +#include +#include +#include +#include "centreon_agent/agent_stat.hh" + +using namespace com::centreon::engine::modules::opentelemetry::centreon_agent; + +/** + * @brief Construct a new agent stat::agent stat object don't use it, use load + * instead + * + * @param io_context + */ +agent_stat::agent_stat(const std::shared_ptr& io_context) + : _io_context(io_context), _send_timer(*io_context), _dirty(false) {} + +/** + * @brief static method to construct a agent_stat object + * + * @param context + * @return agent_stat::pointer + */ +agent_stat::pointer agent_stat::load( + const std::shared_ptr& io_context) { + pointer ret = std::make_shared(io_context); + ret->_start_send_timer(); + return ret; +} + +/** + * @brief Construct a new agent stat::group by key::group by key object + * + * @param agent_info + * @param reversed + */ +agent_stat::group_by_key::group_by_key( + const com::centreon::agent::AgentInfo& agent_info, + bool reversed) + : std::tuple( + agent_info.centreon_version().major(), + agent_info.centreon_version().minor(), + agent_info.centreon_version().patch(), + reversed, + agent_info.os(), + agent_info.os_version()) {} + +/** + * @brief Adds an agent to the agent statistics. + * + * This function adds an agent to the internal data structure that keeps track + * of agent statistics. If the agent is not already present, it is added to the + * data structure. + * + * @param agent_info The information about the agent to be added. + * @param reversed A boolean flag indicating whether the agent is connected in + * reverse mode + * @param reactor A pointer to the reactor object associated with the agent + */ +void agent_stat::add_agent(const com::centreon::agent::AgentInfo& agent_info, + bool reversed, + const void* reactor) { + group_by_key key(agent_info, reversed); + absl::MutexLock l(&_protect); + auto it = _data.find(key); + if (it == _data.end()) { + it = _data.emplace(key, agent_info_set()).first; + } + if (it->second.insert(reactor).second) { + // The agent was added. + _dirty = true; + } +} + +/** + * @brief Removes an agent from the agent statistics. + * + * This function removes an agent from the internal data structure that keeps + * track of agent statistics. If the agent is present, it is removed from the + * data structure. If the set of agents for the given key becomes empty after + * removal, the key is also removed from the data structure. + * + * @param agent_info The information about the agent to be removed. + * @param reversed A boolean flag indicating whether the agent is connected in + * reverse mode. + * @param reactor The pointer to the reactor object that is removed. + */ +void agent_stat::remove_agent(const com::centreon::agent::AgentInfo& agent_info, + bool reversed, + const void* reactor) { + group_by_key key(agent_info, reversed); + absl::MutexLock l(&_protect); + auto it = _data.find(key); + if (it != _data.end()) { + size_t erased = it->second.erase(reactor); + if (it->second.empty()) { + _data.erase(it); + } + if (erased) { + // The agent was removed. + _dirty = true; + } + } +} + +/** + * @brief When an agent connect or disconnect from engine, we send a message to + * broker + * + */ +void agent_stat::_on_stat_update() const { + nebstruct_agent_stats_data stats; + stats.data = + std::make_unique>(); + stats.data->reserve(_data.size()); + for (const auto& agent : _data) { + stats.data->emplace_back(std::get<0>(agent.first), std::get<1>(agent.first), + std::get<2>(agent.first), std::get<3>(agent.first), + std::get<4>(agent.first), std::get<5>(agent.first), + agent.second.size()); + } + + // we post all check results in the main thread + auto fn = + std::packaged_task([to_send = std::move(stats)]() mutable { + broker_agent_stats(to_send); + return OK; + }); + command_manager::instance().enqueue(std::move(fn)); +} + +void agent_stat::_start_send_timer() { + absl::MutexLock l(&_protect); + _send_timer.expires_from_now(std::chrono::minutes(1)); + _send_timer.async_wait( + [this, me = shared_from_this()](const boost::system::error_code& err) { + _send_timer_handler(err); + }); +} + +void agent_stat::_send_timer_handler(const boost::system::error_code& err) { + if (err) { + return; + } + { + absl::MutexLock l(&_protect); + if (_dirty) { + _dirty = false; + _on_stat_update(); + } + } + _start_send_timer(); +} + +/** + * @brief to call on module unload + * + */ +void agent_stat::stop_send_timer() { + absl::MutexLock l(&_protect); + _send_timer.cancel(); +} diff --git a/engine/modules/opentelemetry/src/centreon_agent/to_agent_connector.cc b/engine/modules/opentelemetry/src/centreon_agent/to_agent_connector.cc index 4a2fbd8baf4..5b9e402dd74 100644 --- a/engine/modules/opentelemetry/src/centreon_agent/to_agent_connector.cc +++ b/engine/modules/opentelemetry/src/centreon_agent/to_agent_connector.cc @@ -43,7 +43,8 @@ class agent_connection const std::shared_ptr& parent, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger); + const std::shared_ptr& logger, + const agent_stat::pointer& stats); ::grpc::ClientContext& get_context() { return _context; } @@ -67,14 +68,17 @@ agent_connection::agent_connection( const std::shared_ptr& parent, const agent_config::pointer& conf, const metric_handler& handler, - const std::shared_ptr& logger) + const std::shared_ptr& logger, + const agent_stat::pointer& stats) : agent_impl<::grpc::ClientBidiReactor>( io_context, "reverse_client", conf, handler, - logger), + logger, + true, + stats), _parent(parent) { _peer = parent->get_conf()->get_hostport(); } @@ -119,12 +123,14 @@ to_agent_connector::to_agent_connector( const std::shared_ptr& io_context, const agent_config::pointer& agent_conf, const metric_handler& handler, - const std::shared_ptr& logger) + const std::shared_ptr& logger, + const agent_stat::pointer& stats) : common::grpc::grpc_client_base(agent_endpoint_conf, logger), _io_context(io_context), _metric_handler(handler), _conf(agent_conf), - _alive(true) { + _alive(true), + _stats(stats) { _stub = agent::ReversedAgentService::NewStub(_channel); } @@ -150,10 +156,11 @@ std::shared_ptr to_agent_connector::load( const std::shared_ptr& io_context, const agent_config::pointer& agent_conf, const metric_handler& handler, - const std::shared_ptr& logger) { + const std::shared_ptr& logger, + const agent_stat::pointer& stats) { std::shared_ptr ret = std::make_shared(agent_endpoint_conf, io_context, - agent_conf, handler, logger); + agent_conf, handler, logger, stats); ret->start(); return ret; } @@ -172,8 +179,9 @@ void to_agent_connector::start() { _connection->shutdown(); _connection.reset(); } - _connection = std::make_shared( - _io_context, shared_from_this(), _conf, _metric_handler, get_logger()); + _connection = + std::make_shared(_io_context, shared_from_this(), _conf, + _metric_handler, get_logger(), _stats); agent_connection::register_stream(_connection); _stub->async()->Import(&_connection->get_context(), _connection.get()); _connection->start_read(); diff --git a/engine/modules/opentelemetry/src/open_telemetry.cc b/engine/modules/opentelemetry/src/open_telemetry.cc index 44ef0e93e88..33934574764 100644 --- a/engine/modules/opentelemetry/src/open_telemetry.cc +++ b/engine/modules/opentelemetry/src/open_telemetry.cc @@ -46,7 +46,8 @@ open_telemetry::open_telemetry( const std::shared_ptr& logger) : _config_file_path(config_file_path), _logger(logger), - _io_context(io_context) { + _io_context(io_context), + _agent_stats(centreon_agent::agent_stat::load(io_context)) { SPDLOG_LOGGER_INFO(_logger, "load of open telemetry module"); } @@ -104,7 +105,7 @@ void open_telemetry::_reload() { [me = shared_from_this()](const metric_request_ptr& request) { me->on_metric(request); }, - _logger); + _logger, _agent_stats); } _agent_reverse_client->update(_conf->get_centreon_agent_config()); } @@ -157,7 +158,7 @@ void open_telemetry::_create_otl_server( [me = shared_from_this()](const metric_request_ptr& request) { me->on_metric(request); }, - _logger); + _logger, _agent_stats); } catch (const std::exception& e) { SPDLOG_LOGGER_ERROR(_logger, "fail to create opentelemetry grpc server: {}", e.what()); @@ -249,6 +250,7 @@ void open_telemetry::_shutdown() { if (to_shutdown) { to_shutdown->shutdown(std::chrono::seconds(10)); } + _agent_stats->stop_send_timer(); } /** diff --git a/engine/modules/opentelemetry/src/otl_server.cc b/engine/modules/opentelemetry/src/otl_server.cc index 7efb1c7885d..ec599b1a8c1 100644 --- a/engine/modules/opentelemetry/src/otl_server.cc +++ b/engine/modules/opentelemetry/src/otl_server.cc @@ -288,14 +288,16 @@ otl_server::otl_server( const grpc_config::pointer& conf, const centreon_agent::agent_config::pointer& agent_config, const metric_handler& handler, - const std::shared_ptr& logger) + const std::shared_ptr& logger, + const centreon_agent::agent_stat::pointer& agent_stats) : common::grpc::grpc_server_base(conf, logger), _service(detail::metric_service::load(handler, logger)), _agent_service(centreon_agent::agent_service::load(io_context, agent_config, handler, - logger)) {} + logger, + agent_stats)) {} /** * @brief Destroy the otl server::otl server object @@ -317,9 +319,10 @@ otl_server::pointer otl_server::load( const grpc_config::pointer& conf, const centreon_agent::agent_config::pointer& agent_config, const metric_handler& handler, - const std::shared_ptr& logger) { - otl_server::pointer ret( - new otl_server(io_context, conf, agent_config, handler, logger)); + const std::shared_ptr& logger, + const centreon_agent::agent_stat::pointer& agent_stats) { + otl_server::pointer ret(new otl_server(io_context, conf, agent_config, + handler, logger, agent_stats)); ret->start(); return ret; } diff --git a/engine/src/broker.cc b/engine/src/broker.cc index a382422ee1b..08a8b81f6ce 100644 --- a/engine/src/broker.cc +++ b/engine/src/broker.cc @@ -1124,4 +1124,15 @@ void broker_bench(unsigned id, // Make callbacks. neb_make_callbacks(NEBCALLBACK_BENCH_DATA, &ds); } + +/** + * @brief send agent usage statistics to broker + * + * @param stats + */ +void broker_agent_stats(nebstruct_agent_stats_data& stats) { + // Fill struct with relevant data. + // Make callbacks. + neb_make_callbacks(NEBCALLBACK_AGENT_STATS, &stats); +} } diff --git a/engine/tests/opentelemetry/otl_server_test.cc b/engine/tests/opentelemetry/otl_server_test.cc index 5d6291a6cc3..b74c9b9ef4f 100644 --- a/engine/tests/opentelemetry/otl_server_test.cc +++ b/engine/tests/opentelemetry/otl_server_test.cc @@ -85,8 +85,9 @@ class otl_server_test : public ::testing::Test { const metric_handler_type& handler) { std::shared_ptr agent_conf = std::make_shared(60, 100, 60, 10); - _server = otl_server::load(g_io_context, conf, agent_conf, handler, - spdlog::default_logger()); + _server = otl_server::load( + g_io_context, conf, agent_conf, handler, spdlog::default_logger(), + std::make_shared(g_io_context)); } }; diff --git a/resources/centreon_storage.sql b/resources/centreon_storage.sql index 5291012a92d..9960cd531a0 100644 --- a/resources/centreon_storage.sql +++ b/resources/centreon_storage.sql @@ -1526,3 +1526,15 @@ CREATE TABLE mod_bam_reporting_timeperiods ( ) ENGINE=InnoDB CHARACTER SET utf8; SET FOREIGN_KEY_CHECKS=1; + +-- +-- Agent CEIP +-- +CREATE TABLE `centreon_storage`.`agent_information` ( + `poller_id` BIGINT(20) NOT NULL, + `enabled` TINYINT(1) NOT NULL DEFAULT 1, + `infos` JSON NOT NULL, + + PRIMARY KEY (`poller_id`), + KEY(enabled) +) ENGINE=InnoDB CHARACTER SET utf8; diff --git a/tests/broker-engine/cma.robot b/tests/broker-engine/cma.robot index 8e4d9dd0da7..e79a806e01b 100644 --- a/tests/broker-engine/cma.robot +++ b/tests/broker-engine/cma.robot @@ -745,6 +745,57 @@ BEOTEL_CENTREON_AGENT_CHECK_HEALTH Should Be True ${result} resources table not updated for service_2 +BEOTEL_CENTREON_AGENT_CEIP + [Documentation] we connect an agent to engine and we expect a row in agent_information table + [Tags] broker engine opentelemetry MON-145030 + Ctn Config Engine ${1} ${2} ${2} + Ctn Add Otl ServerModule + ... 0 + ... {"otel_server":{"host": "0.0.0.0","port": 4317},"max_length_grpc_log":0,"centreon_agent":{"check_interval":10, "export_period":15}} + Ctn Config Add Otl Connector + ... 0 + ... OTEL connector + ... opentelemetry --processor=centreon_agent --extractor=attributes --host_path=resource_metrics.resource.attributes.host.name --service_path=resource_metrics.resource.attributes.service.name + Ctn Engine Config Replace Value In Services ${0} service_1 check_command cpu_check + Ctn Engine Config Replace Value In Services ${0} service_2 check_command health_check + Ctn Set Services Passive 0 service_[1-2] + + + Ctn Engine Config Add Command ${0} cpu_check {"check": "cpu_percentage"} OTEL connector + Ctn Engine Config Add Command ${0} health_check {"check": "health"} OTEL connector + + Ctn Engine Config Set Value 0 log_level_checks trace + + Ctn Clear Db metrics + + Ctn Config Broker central + Ctn Config Broker module + Ctn Config Broker rrd + Ctn Config BBDO3 1 + Ctn Config Centreon Agent + Ctn Broker Config Log central sql trace + Ctn Broker Config Output Set central central-broker-unified-sql instance_timeout 10 + + Ctn Clear Retention + + ${start} Ctn Get Round Current Date + Ctn Start Broker + Ctn Start Engine + Ctn Start Agent + + # Let's wait for the otel server start + Ctn Wait For Otel Server To Be Ready ${start} + + ${result} Ctn Check Agent Information 1 1 120 + Should Be True ${result} agent_information table not updated as expected + + Log To Console "stop engine" + Ctn Stop Engine + ${result} Ctn Check Agent Information 0 0 120 + Should Be True ${result} agent_information table not updated as expected + + + *** Keywords *** Ctn Create Cert And Init [Documentation] create key and certificates used by agent and engine on linux side diff --git a/tests/resources/Common.py b/tests/resources/Common.py index 1caf302c36a..76da0cd8c95 100644 --- a/tests/resources/Common.py +++ b/tests/resources/Common.py @@ -2010,4 +2010,48 @@ def ctn_check_service_perfdata(host: str, serv: str, timeout: int, precision: fl return True time.sleep(1) logger.console(f"unexpected result: {result}") - return False \ No newline at end of file + return False + + +def ctn_check_agent_information(total_nb_agent: int, nb_poller:int, timeout: int): + """ + Check if agent_information table is filled. Collect version is also checked + total_nb_agent (int): total number of agents + nb_poller (int): nb poller with at least one agent connected. + timeout (int): The timeout value for the check. + """ + collect_version = ctn_get_collect_version() + + collect_major = int(collect_version.split(".")[0]) + collect_minor = int(collect_version.split(".")[1]) + collect_patch = int(collect_version.split(".")[2]) + + limit = time.time() + timeout + query = "SELECT infos FROM agent_information WHERE enabled = 1" + while time.time() < limit: + connection = pymysql.connect(host=DB_HOST, + user=DB_USER, + password=DB_PASS, + database=DB_NAME_STORAGE, + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor) + with connection: + with connection.cursor() as cursor: + cursor.execute(query) + result = cursor.fetchall() + if len(result) == nb_poller: + nb_agent = 0 + for res in result: + logger.console(f"infos: {res['infos']}") + agent_infos = json.loads(res['infos']) + for by_agent_info in agent_infos: + if by_agent_info['agent_major'] != collect_major or by_agent_info['agent_minor'] != collect_minor or by_agent_info['agent_patch'] != collect_patch: + logger.console(f"unexpected version: {by_agent_info['agent_major']}.{by_agent_info['agent_minor']}.{by_agent_info['agent_patch']}") + return False + nb_agent += by_agent_info['nb_agent'] + if nb_agent == total_nb_agent: + return True + time.sleep(1) + logger.console(f"unexpected result: {result}") + return False +