From 6fbf9495102d3b9a21b79de1c6605aa56f8db4a0 Mon Sep 17 00:00:00 2001 From: David Boucher Date: Wed, 15 May 2024 09:57:27 +0200 Subject: [PATCH 01/11] enh(broker/lua): lua cache is now updated on service_status/host_status events REFS: MON-60933 --- bbdo/neb.proto | 34 +-- .../com/centreon/broker/lua/macro_cache.hh | 36 +-- broker/lua/src/luabinding.cc | 2 - broker/lua/src/macro_cache.cc | 226 +++++++++++++++--- broker/sql/src/stream.cc | 36 +-- tests/bam/bam_pb.robot | 20 -- tests/broker-engine/lua-cache.robot | 188 +++++++++++++++ tests/resources/Common.py | 2 +- tests/resources/resources.robot | 15 +- 9 files changed, 455 insertions(+), 104 deletions(-) create mode 100644 tests/broker-engine/lua-cache.robot diff --git a/bbdo/neb.proto b/bbdo/neb.proto index 65cfc597b41..a4a74a6f110 100644 --- a/bbdo/neb.proto +++ b/bbdo/neb.proto @@ -1,20 +1,20 @@ -/* -** Copyright 2022 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 -*/ +/** + * Copyright 2022-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 + */ syntax = "proto3"; diff --git a/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh b/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh index e22a6d6c3ad..dbd9cd3822a 100644 --- a/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh +++ b/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh @@ -1,20 +1,20 @@ -/* -** Copyright 2018-2022 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 -*/ +/** + * Copyright 2018-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 CCB_LUA_MACRO_CACHE_HH #define CCB_LUA_MACRO_CACHE_HH @@ -118,6 +118,7 @@ class macro_cache { void _process_pb_instance(std::shared_ptr const& data); void _process_host(std::shared_ptr const& data); void _process_pb_host(std::shared_ptr const& data); + void _process_pb_host_status(std::shared_ptr const& data); void _process_pb_adaptive_host(std::shared_ptr const& data); void _process_host_group(std::shared_ptr const& data); void _process_host_group_member(std::shared_ptr const& data); @@ -125,6 +126,7 @@ class macro_cache { void _process_pb_custom_variable(std::shared_ptr const& data); void _process_service(std::shared_ptr const& data); void _process_pb_service(std::shared_ptr const& data); + void _process_pb_service_status(std::shared_ptr const& data); void _process_pb_adaptive_service(std::shared_ptr const& data); void _process_service_group(std::shared_ptr const& data); void _process_service_group_member(std::shared_ptr const& data); diff --git a/broker/lua/src/luabinding.cc b/broker/lua/src/luabinding.cc index 4f69cdbb9fe..3c561e37b78 100644 --- a/broker/lua/src/luabinding.cc +++ b/broker/lua/src/luabinding.cc @@ -297,8 +297,6 @@ int luabinding::write(std::shared_ptr const& data) noexcept { int retval = 0; if (log_v2::lua()->level() == spdlog::level::trace) { SPDLOG_LOGGER_TRACE(log_v2::lua(), "lua: luabinding::write call {}", *data); - } else { - SPDLOG_LOGGER_DEBUG(log_v2::lua(), "lua: luabinding::write call"); } // Give data to cache. diff --git a/broker/lua/src/macro_cache.cc b/broker/lua/src/macro_cache.cc index 39300d0c08c..53a0bf9cad8 100644 --- a/broker/lua/src/macro_cache.cc +++ b/broker/lua/src/macro_cache.cc @@ -1,20 +1,20 @@ -/* -** Copyright 2017-2022 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 -*/ +/** + * Copyright 2017-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/broker/lua/macro_cache.hh" #include "bbdo/bam/dimension_ba_bv_relation_event.hh" @@ -515,6 +515,9 @@ void macro_cache::write(std::shared_ptr const& data) { case neb::pb_host::static_type(): _process_pb_host(data); break; + case neb::pb_host_status::static_type(): + _process_pb_host_status(data); + break; case neb::pb_adaptive_host::static_type(): _process_pb_adaptive_host(data); break; @@ -530,6 +533,9 @@ void macro_cache::write(std::shared_ptr const& data) { case neb::pb_service::static_type(): _process_pb_service(data); break; + case neb::pb_service_status::static_type(): + _process_pb_service_status(data); + break; case neb::pb_adaptive_service::static_type(): _process_pb_adaptive_service(data); break; @@ -633,6 +639,84 @@ void macro_cache::_process_pb_host(std::shared_ptr const& data) { _hosts.erase(h->obj().host_id()); } +void macro_cache::_process_pb_host_status( + const std::shared_ptr& data) { + const auto& s = std::static_pointer_cast(data); + const auto& obj = s->obj(); + + SPDLOG_LOGGER_DEBUG(log_v2::lua(), "lua: processing host status ({})", + obj.host_id()); + + auto it = _hosts.find(obj.host_id()); + if (it == _hosts.end()) { + log_v2::lua()->warn( + "lua: Attempt to update host ({}) in lua cache, but it does not " + "exist. Maybe Engine should be restarted to update the cache.", + obj.host_id()); + return; + } + + if (it->second->type() == make_type(io::neb, neb::de_host)) { + auto& hst = *std::static_pointer_cast(it->second); + hst.has_been_checked = obj.checked(); + hst.check_type = obj.check_type(); + hst.current_state = obj.state(); + hst.state_type = obj.state_type(); + hst.last_state_change = obj.last_state_change(); + hst.last_hard_state = obj.last_hard_state(); + hst.last_hard_state_change = obj.last_hard_state_change(); + hst.last_time_up = obj.last_time_up(); + hst.last_time_down = obj.last_time_down(); + hst.last_time_unreachable = obj.last_time_unreachable(); + hst.output = obj.output(); + hst.perf_data = obj.perfdata(); + hst.is_flapping = obj.flapping(); + hst.percent_state_change = obj.percent_state_change(); + hst.latency = obj.latency(); + hst.execution_time = obj.execution_time(); + hst.last_check = obj.last_check(); + hst.next_check = obj.next_check(); + hst.should_be_scheduled = obj.should_be_scheduled(); + hst.current_check_attempt = obj.check_attempt(); + hst.notification_number = obj.notification_number(); + hst.no_more_notifications = obj.no_more_notifications(); + hst.last_notification = obj.last_notification(); + hst.next_notification = obj.next_host_notification(); + hst.acknowledgement_type = obj.acknowledgement_type(); + hst.downtime_depth = obj.scheduled_downtime_depth(); + } else if (it->second->type() == make_type(io::neb, neb::de_pb_host)) { + auto& hst = std::static_pointer_cast(it->second)->mut_obj(); + hst.set_checked(obj.checked()); + hst.set_check_type(static_cast(obj.check_type())); + hst.set_state(static_cast(obj.state())); + hst.set_state_type(static_cast(obj.state_type())); + hst.set_last_state_change(obj.last_state_change()); + hst.set_last_hard_state(static_cast(obj.last_hard_state())); + hst.set_last_hard_state_change(obj.last_hard_state_change()); + hst.set_last_time_up(obj.last_time_up()); + hst.set_last_time_down(obj.last_time_down()); + hst.set_last_time_unreachable(obj.last_time_unreachable()); + hst.set_output(obj.output()); + hst.set_perfdata(obj.perfdata()); + hst.set_flapping(obj.flapping()); + hst.set_percent_state_change(obj.percent_state_change()); + hst.set_latency(obj.latency()); + hst.set_execution_time(obj.execution_time()); + hst.set_last_check(obj.last_check()); + hst.set_next_check(obj.next_check()); + hst.set_should_be_scheduled(obj.should_be_scheduled()); + hst.set_check_attempt(obj.check_attempt()); + hst.set_notification_number(obj.notification_number()); + hst.set_no_more_notifications(obj.no_more_notifications()); + hst.set_last_notification(obj.last_notification()); + hst.set_next_host_notification(obj.next_host_notification()); + hst.set_acknowledgement_type(obj.acknowledgement_type()); + hst.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); + } else { + log_v2::lua()->error("lua: The host ({}) stored in cache is corrupted", + obj.host_id()); + } +} /** * Process a pb adaptive host event. * @@ -727,10 +811,12 @@ void macro_cache::_process_pb_adaptive_host( void macro_cache::_process_host_group(std::shared_ptr const& data) { std::shared_ptr const& hg = std::static_pointer_cast(data); - SPDLOG_LOGGER_DEBUG(log_v2::lua(), "lua: processing host group '{}' of id {}", - hg->name, hg->id); + SPDLOG_LOGGER_DEBUG(log_v2::lua(), + "lua: processing host group '{}' of id {} enabled: {}", + hg->name, hg->id, hg->enabled); if (hg->enabled) _host_groups[hg->id] = hg; + // erasure is desactivated because a group cen be owned by several pollers } /** @@ -785,6 +871,89 @@ void macro_cache::_process_pb_service(std::shared_ptr const& data) { _services.erase({s->obj().host_id(), s->obj().service_id()}); } +void macro_cache::_process_pb_service_status( + const std::shared_ptr& data) { + const auto& s = std::static_pointer_cast(data); + const auto& obj = s->obj(); + + SPDLOG_LOGGER_DEBUG(log_v2::lua(), "lua: processing service status ({}, {})", + obj.host_id(), obj.service_id()); + + auto it = _services.find({obj.host_id(), obj.service_id()}); + if (it == _services.end()) { + log_v2::lua()->warn( + "lua: Attempt to update service ({}, {}) in lua cache, but it does not " + "exist. Maybe Engine should be restarted to update the cache.", + obj.host_id(), obj.service_id()); + return; + } + + if (it->second->type() == make_type(io::neb, neb::de_service)) { + auto& svc = *std::static_pointer_cast(it->second); + svc.has_been_checked = obj.checked(); + svc.check_type = obj.check_type(); + svc.current_state = obj.state(); + svc.state_type = obj.state_type(); + svc.last_state_change = obj.last_state_change(); + svc.last_hard_state = obj.last_hard_state(); + svc.last_hard_state_change = obj.last_hard_state_change(); + svc.last_time_ok = obj.last_time_ok(); + svc.last_time_warning = obj.last_time_warning(); + svc.last_time_critical = obj.last_time_critical(); + svc.last_time_unknown = obj.last_time_unknown(); + svc.output = obj.output(); + svc.perf_data = obj.perfdata(); + svc.is_flapping = obj.flapping(); + svc.percent_state_change = obj.percent_state_change(); + svc.latency = obj.latency(); + svc.execution_time = obj.execution_time(); + svc.last_check = obj.last_check(); + svc.next_check = obj.next_check(); + svc.should_be_scheduled = obj.should_be_scheduled(); + svc.current_check_attempt = obj.check_attempt(); + svc.notification_number = obj.notification_number(); + svc.no_more_notifications = obj.no_more_notifications(); + svc.last_notification = obj.last_notification(); + svc.next_notification = obj.next_notification(); + svc.acknowledgement_type = obj.acknowledgement_type(); + svc.downtime_depth = obj.scheduled_downtime_depth(); + } else if (it->second->type() == make_type(io::neb, neb::de_pb_service)) { + auto& svc = + std::static_pointer_cast(it->second)->mut_obj(); + svc.set_checked(obj.checked()); + svc.set_check_type(static_cast(obj.check_type())); + svc.set_state(static_cast(obj.state())); + svc.set_state_type(static_cast(obj.state_type())); + svc.set_last_state_change(obj.last_state_change()); + svc.set_last_hard_state(static_cast(obj.last_hard_state())); + svc.set_last_hard_state_change(obj.last_hard_state_change()); + svc.set_last_time_ok(obj.last_time_ok()); + svc.set_last_time_warning(obj.last_time_warning()); + svc.set_last_time_critical(obj.last_time_critical()); + svc.set_last_time_unknown(obj.last_time_unknown()); + svc.set_output(obj.output()); + svc.set_perfdata(obj.perfdata()); + svc.set_flapping(obj.flapping()); + svc.set_percent_state_change(obj.percent_state_change()); + svc.set_latency(obj.latency()); + svc.set_execution_time(obj.execution_time()); + svc.set_last_check(obj.last_check()); + svc.set_next_check(obj.next_check()); + svc.set_should_be_scheduled(obj.should_be_scheduled()); + svc.set_check_attempt(obj.check_attempt()); + svc.set_notification_number(obj.notification_number()); + svc.set_no_more_notifications(obj.no_more_notifications()); + svc.set_last_notification(obj.last_notification()); + svc.set_next_notification(obj.next_notification()); + svc.set_acknowledgement_type(obj.acknowledgement_type()); + svc.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); + } else { + log_v2::lua()->error( + "lua: The service ({}, {}) stored in cache is corrupted", obj.host_id(), + obj.service_id()); + } +} + /** * Process a pb service event. * @@ -887,6 +1056,7 @@ void macro_cache::_process_service_group( sg->id); if (sg->enabled) _service_groups[sg->id] = sg; + // erasure is desactivated because a group cen be owned by several pollers } /** @@ -1020,10 +1190,10 @@ void macro_cache::_process_dimension_ba_bv_relation_event( } else { auto const& rel = std::static_pointer_cast(data); - SPDLOG_LOGGER_DEBUG( - log_v2::lua(), - "lua: processing dimension ba bv relation event (ba_id: {}, bv_id: {})", - rel->ba_id, rel->bv_id); + SPDLOG_LOGGER_DEBUG(log_v2::lua(), + "lua: processing dimension ba bv relation event " + "(ba_id: {}, bv_id: {})", + rel->ba_id, rel->bv_id); auto pb_data(std::make_shared()); pb_data->mut_obj().set_ba_id(rel->ba_id); pb_data->mut_obj().set_bv_id(rel->bv_id); @@ -1102,11 +1272,11 @@ void macro_cache::_process_custom_variable( std::shared_ptr const& data) { auto const& cv = std::static_pointer_cast(data); if (cv->name == "CRITICALITY_LEVEL") { - SPDLOG_LOGGER_DEBUG( - log_v2::lua(), - "lua: processing custom variable representing a criticality level for " - "host_id {} and service_id {} and level {}", - cv->host_id, cv->service_id, cv->value); + SPDLOG_LOGGER_DEBUG(log_v2::lua(), + "lua: processing custom variable representing a " + "criticality level for " + "host_id {} and service_id {} and level {}", + cv->host_id, cv->service_id, cv->value); int32_t value = std::atoi(cv->value.c_str()); if (value) _custom_vars[{cv->host_id, cv->service_id}] = cv; diff --git a/broker/sql/src/stream.cc b/broker/sql/src/stream.cc index 5ab090229dc..e691d976f06 100644 --- a/broker/sql/src/stream.cc +++ b/broker/sql/src/stream.cc @@ -1,20 +1,20 @@ -/* -** Copyright 2009-2021 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 -*/ +/** + * Copyright 2009-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/broker/sql/stream.hh" @@ -58,7 +58,7 @@ stream::stream(database_config const& dbcfg, uint32_t cleanup_check_interval, uint32_t loop_timeout, uint32_t instance_timeout, - bool with_state_events) + bool with_state_events [[maybe_unused]]) : io::stream("SQL"), _mysql(dbcfg), // _cleanup_thread(dbcfg.get_type(), diff --git a/tests/bam/bam_pb.robot b/tests/bam/bam_pb.robot index 9eda36f3980..63f70fb8a48 100644 --- a/tests/bam/bam_pb.robot +++ b/tests/bam/bam_pb.robot @@ -151,11 +151,6 @@ BAWORST2 ${result} Ctn Check Ba Status With Timeout test 0 60 Ctn Dump Ba On Error ${result} ${id_ba__sid[0]} Should Be True ${result} The BA test is not OK as expected - ${result} Ctn Check Ba Output With Timeout - ... test - ... Status is OK - All KPIs are in an OK state - ... 10 - Should Be True ${result} The BA test has not the expected output # boolean critical => ba test critical Ctn Process Service Result Hard @@ -169,11 +164,6 @@ BAWORST2 ${result} Ctn Check Ba Status With Timeout test 2 60 Ctn Dump Ba On Error ${result} ${id_ba__sid[0]} Should Be True ${result} The BA test is not CRITICAL as expected - ${result} Ctn Check Ba Output With Timeout - ... test - ... Status is CRITICAL - At least one KPI is in a CRITICAL state: KPI Boolean rule bool test is in CRITICAL state - ... 10 - Should Be True ${result} The BA test has not the expected output # child ba critical Ctn Process Service Result Hard @@ -190,11 +180,6 @@ BAWORST2 ${result} Ctn Check Ba Status With Timeout test 2 60 Ctn Dump Ba On Error ${result} ${id_ba__sid[0]} Should Be True ${result} The BA test is not CRITICAL as expected - ${result} Ctn Check Ba Output With Timeout - ... test - ... Status is CRITICAL - At least one KPI is in a CRITICAL state: KPI Business Activity test_child is in CRITICAL state, KPI Boolean rule bool test is in CRITICAL state - ... 10 - Should Be True ${result} The BA test has not the expected output # boolean rule ok stay in critical Ctn Process Service Result Hard @@ -208,11 +193,6 @@ BAWORST2 ${result} Ctn Check Ba Status With Timeout test 2 60 Ctn Dump Ba On Error ${result} ${id_ba__sid[0]} Should Be True ${result} The BA test is not CRITICAL as expected - ${result} Ctn Check Ba Output With Timeout - ... test - ... Status is CRITICAL - At least one KPI is in a CRITICAL state: KPI Business Activity test_child is in CRITICAL state - ... 10 - Should Be True ${result} The BA test has not the expected output BABEST_SERVICE_CRITICAL [Documentation] With bbdo version 3.0.1, a BA of type 'best' with 2 serv, ba is critical only if the 2 services are critical diff --git a/tests/broker-engine/lua-cache.robot b/tests/broker-engine/lua-cache.robot new file mode 100644 index 00000000000..27c30747c93 --- /dev/null +++ b/tests/broker-engine/lua-cache.robot @@ -0,0 +1,188 @@ +*** Settings *** +Documentation Centreon Broker and Engine progressively add services + +Resource ../resources/resources.robot +Library ../resources/Broker.py +Library ../resources/Engine.py +Library DateTime + +Suite Setup Ctn Clean Before Suite +Suite Teardown Ctn Clean After Suite +Test Setup Ctn Stop Processes +Test Teardown Ctn Save Logs If Failed + + +*** Test Cases *** +LCDNU + [Documentation] the lua cache updates correctly service cache. + [Tags] broker engine services lua MON-24745 MON-60933 + Ctn Clear Commands Status + Ctn Clear Retention + + Remove File /tmp/test-LUA.log + Ctn Config Engine ${1} ${1} ${1} + Ctn Config Broker central + Ctn Config Broker module + Ctn Config Broker rrd + Ctn Config BBDO3 1 + Ctn Broker Config Log central neb trace + Ctn Broker Config Log central sql error + Ctn Broker Config Log central lua debug + Ctn Config Broker Sql Output central unified_sql + + ${new_content} Catenate SEPARATOR=\n + ... function init(params) + ... broker_log:set_parameters(2, '/tmp/test-LUA.log') + ... broker_log:info(0, 'lua start test') + ... end + ... + ... function write(e) + ... if e._type == 65563 then --Service id + ... broker_log:info(0, 'configuration of ('.. e.host_id.. ','.. e.service_id.. ')') + ... local svc = broker_cache:get_service(e.host_id,e.service_id) + ... broker_log:info(0, broker.json_encode(svc)) + ... end + ... if e._type == 65565 then --service status ID + ... broker_log:info(0, 'Status of ('.. e.host_id.. ','.. e.service_id.. ')') + ... local svc = broker_cache:get_service(e.host_id,e.service_id) + ... local field = {"checked", "check_type", "state", "state_type", "last_state_change", "last_hard_state", "last_hard_state_change", "last_time_ok", "last_time_warning", "last_time_critical", "last_time_unknown", "output", "perfdata", "flapping", "percent_state_change", "latency", "execution_time", "last_check", "next_check", "should_be_scheduled", "check_attempt", "notification_number", "no_more_notifications", "last_notification", "next_notification", "acknowledgement_type", "scheduled_downtime_depth"} + ... local ko = 0 + ... for i, v in ipairs(field) do + ... if svc[v] ~= e[v] then + ... broker_log:info(0, v.." doesn't match (".. svc[v].." ~= ".. e[v]..")") + ... ko = ko + 1 + ... end + ... end + ... if ko == 0 then + ... broker_log:info(0, "Service cache OK") + ... end + ... end + ... return true + ... end + + # Create the initial LUA script file + Create File /tmp/test-LUA.lua ${new_content} + + Ctn Broker Config Add Lua Output central test-LUA /tmp/test-LUA.lua + + ${start} Get Current Date + Ctn Start Broker + Ctn Start Engine + Ctn Wait For Engine To Be Ready ${start} ${1} + + Wait Until Created /tmp/test-LUA.log + FOR ${i} IN RANGE 60 + ${result} Grep File /tmp/test-LUA.log configuration of (1,1) regexp=False + IF len("""${result}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${result} Configuration error + + ## Time to set the service to OK hard + + Ctn Process Service Result Hard host_1 service_1 ${0} The service_1 is OK + + ## check that we check the correct service + FOR ${i} IN RANGE 60 + ${grep_res} Grep File /tmp/test-LUA.log Status of + IF len("""${grep_res}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${result} No message about the service (1,1) status + + FOR ${i} IN RANGE 60 + ${grep_res} Grep File /tmp/test-LUA.log Service cache OK regexp=False + IF len("""${grep_res}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${grep_res} Some checks failed + + Ctn Stop Engine + Ctn Kindly Stop Broker + + +LCDNUH + [Documentation] the lua cache updates correctly host cache + [Tags] broker engine services lua MON-24745 MON-60933 + Ctn Clear Commands Status + Ctn Clear Retention + + Remove File /tmp/test-LUA.log + Ctn Config Engine ${1} ${1} ${1} + Ctn Config Broker central + Ctn Config Broker module + Ctn Config Broker rrd + Ctn Config BBDO3 1 + Ctn Broker Config Log central neb trace + Ctn Broker Config Log central sql error + Ctn Broker Config Log central lua debug + Ctn Config Broker Sql Output central unified_sql + + ${new_content} Catenate SEPARATOR=\n + ... function init(params) + ... broker_log:set_parameters(2, '/tmp/test-LUA.log') + ... broker_log:info(0, 'lua start test') + ... end + ... + ... function write(e) + ... if e._type == 65566 then --Host ID + ... broker_log:info(0, 'configuration of ('.. e.host_id.. ')') + ... end + ... if e._type == 65568 then --Host status ID + ... broker_log:info(0, 'Status of ('.. e.host_id.. ')') + ... local host = broker_cache:get_host(e.host_id) + ... local field = {"checked", "check_type", "state", "state_type", "last_state_change", "last_hard_state", "last_hard_state_change", "last_time_up", "last_time_down", "last_time_unreachable", "output", "perfdata", "flapping", "percent_state_change", "latency", "execution_time", "last_check", "next_check", "should_be_scheduled", "check_attempt", "notification_number", "no_more_notifications", "last_notification", "next_host_notification", "acknowledgement_type", "scheduled_downtime_depth"} + ... local ko = 0 + ... for i, v in ipairs(field) do + ... if host[v] ~= e[v] then + ... broker_log:info(0, v.." doesn't match (".. host[v].." ~= ".. e[v]..")") + ... ko = ko + 1 + ... end + ... end + ... if ko == 0 then + ... broker_log:info(0, "Host cache OK") + ... end + ... end + ... return true + ... end + + # Create the initial LUA script file + Create File /tmp/test-LUA.lua ${new_content} + + Ctn Broker Config Add Lua Output central test-LUA /tmp/test-LUA.lua + + ${start} Get Current Date + Ctn Start Broker + Ctn Start Engine + Ctn Wait For Engine To Be Ready ${start} ${1} + + Wait Until Created /tmp/test-LUA.log + FOR ${i} IN RANGE 60 + ${result} Grep File /tmp/test-LUA.log configuration of (1) regexp=False + IF len("""${result}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${result} Configuration error + + ## Time to set the host to UP hard + + FOR ${i} IN RANGE ${3} + Ctn Process Host Check Result host_1 0 host_1 UP + END + + FOR ${i} IN RANGE 60 + ${grep_res} Grep File /tmp/test-LUA.log Status of + IF len("""${grep_res}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${result} No message about the host (1) status + + FOR ${i} IN RANGE 60 + ${grep_res} Grep File /tmp/test-LUA.log Host cache OK regexp=False + IF len("""${grep_res}""") > 0 BREAK + Sleep 1s + END + Should Not Be Empty ${grep_res} Some checks failed + + Ctn Stop Engine + Ctn Kindly Stop Broker diff --git a/tests/resources/Common.py b/tests/resources/Common.py index 7b2bc3f6935..afb7fa36a4b 100644 --- a/tests/resources/Common.py +++ b/tests/resources/Common.py @@ -771,7 +771,7 @@ def ctn_check_ba_output_with_timeout(ba_name: str, expected_output: str, timeout logger.console(f"ba: {result[0]}") if result[0]['current_status'] is not None and result[0]['comment'] == expected_output: return True - time.sleep(5) + time.sleep(2) return False diff --git a/tests/resources/resources.robot b/tests/resources/resources.robot index bcf444b6592..d51b50a8e96 100644 --- a/tests/resources/resources.robot +++ b/tests/resources/resources.robot @@ -40,7 +40,7 @@ Ctn Clean Before Suite Ctn Clear Engine Logs Ctn Clear Broker Logs -Ctn Clean Before Suite With rrdcached +Ctn Clean Before Suite With Rrdcached Ctn Clean Before Suite log to console Starting RRDCached Run Process /usr/bin/rrdcached -l unix:${BROKER_LIB}/rrdcached.sock -V LOG_DEBUG -F @@ -286,3 +286,16 @@ Ctn Process Service Result Hard ... ${svc} ... ${state} ... ${output} + +Ctn Wait For Engine To Be Ready + [Arguments] ${start} ${nbEngine}=1 + FOR ${i} IN RANGE ${nbEngine} + # Let's wait for the external command check start + ${content} Create List check_for_external_commands() + ${result} Ctn Find In Log With Timeout + ... ${ENGINE_LOG}/config${i}/centengine.log + ... ${start} ${content} 60 + Should Be True + ... ${result} + ... A message telling check_for_external_commands() should be available in config${i}/centengine.log. + END From 8f2349b6486a3160f5764880bf9eacb44cfa84bd Mon Sep 17 00:00:00 2001 From: May <110405507+mushroomempires@users.noreply.github.com> Date: Mon, 27 May 2024 16:14:50 +0200 Subject: [PATCH 02/11] fix (#1368) --- .github/actions/promote-to-stable/action.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/actions/promote-to-stable/action.yml b/.github/actions/promote-to-stable/action.yml index 21faf196312..0316115449d 100644 --- a/.github/actions/promote-to-stable/action.yml +++ b/.github/actions/promote-to-stable/action.yml @@ -122,7 +122,13 @@ runs: echo "[DEBUG] - Distrib: ${{ inputs.distrib }}" echo "[DEBUG] - Get path of testing DEB packages to promote to stable." - SRC_PATHS=$(jf rt search --include-dirs apt-standard-${{ inputs.major_version }}-testing/pool/${{ inputs.module_name }}/*${{ inputs.major_version }}.${{ inputs.minor_version }}*${{ inputs.distrib }}*.deb | jq -r '.[].path') + + case "${{ inputs.major_version }}" in + "22.10"|"23.04"|"23.10") + SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*.deb | jq -r '.[].path') + *) + SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*${{ inputs.distrib }}*.deb | jq -r '.[].path') + esac if [[ ${SRC_PATHS[@]} ]]; then for SRC_PATH in ${SRC_PATHS[@]}; do @@ -143,7 +149,14 @@ runs: jf rt download $ARTIFACT --flat done - for ARTIFACT_DL in $(dir|grep -E "*.deb"); do + case "${{ inputs.major_version }}" in + "22.10"|"23.04"|"23.10") + ARTIFACT_SEARCH_PATTERN=".+\.deb" + *) + ARTIFACT_SEARCH_PATTERN=".+${{ inputs.distrib }}.+\.deb" + esac + + for ARTIFACT_DL in $(dir -1|grep -E $ARTIFACT_SEARCH_PATTERN); do ARCH=$(echo $ARTIFACT_DL | cut -d '_' -f3 | cut -d '.' -f1) DISTRIB=$(echo $ARTIFACT_DL | cut -d '_' -f2 | cut -d '-' -f2) if [[ "${{ inputs.distrib }}" != "$DISTRIB" ]]; then From c620be636e84efea3cadacdaf6d491abf5a3e836 Mon Sep 17 00:00:00 2001 From: May <110405507+mushroomempires@users.noreply.github.com> Date: Tue, 28 May 2024 11:08:19 +0200 Subject: [PATCH 03/11] fix(ci): add missing semicolons in debian promote action (#1371) (#1375) --- .github/actions/promote-to-stable/action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/actions/promote-to-stable/action.yml b/.github/actions/promote-to-stable/action.yml index 45cb675a025..df267f5acfc 100644 --- a/.github/actions/promote-to-stable/action.yml +++ b/.github/actions/promote-to-stable/action.yml @@ -126,8 +126,10 @@ runs: case "${{ inputs.major_version }}" in "22.10"|"23.04"|"23.10") SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*.deb | jq -r '.[].path') + ;; *) SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*${{ inputs.distrib }}*.deb | jq -r '.[].path') + ;; esac if [[ ${SRC_PATHS[@]} ]]; then @@ -152,8 +154,10 @@ runs: case "${{ inputs.major_version }}" in "22.10"|"23.04"|"23.10") ARTIFACT_SEARCH_PATTERN=".+\.deb" + ;; *) ARTIFACT_SEARCH_PATTERN=".+${{ inputs.distrib }}.+\.deb" + ;; esac for ARTIFACT_DL in $(dir -1|grep -E $ARTIFACT_SEARCH_PATTERN); do From 0614823d8d4e37e5be9ea57ec23f55df962dad96 Mon Sep 17 00:00:00 2001 From: jean-christophe81 <98889244+jean-christophe81@users.noreply.github.com> Date: Tue, 28 May 2024 16:24:30 +0200 Subject: [PATCH 04/11] enh(engine): Engine can be started with configuration files that complete the current ones (#1351) When engine is started, there is now a '-c' option to specify a configuration file. REFS: MON-71615 --- broker/neb/CMakeLists.txt | 1 - broker/neb/src/broker.cc | 12 + .../engine/configuration/extended_conf.hh | 72 ++ .../centreon/engine/configuration/state.hh | 71 +- engine/inc/com/centreon/engine/log_v2.hh | 10 +- engine/precomp_inc/precomp.hh | 15 +- engine/src/checkable.cc | 37 +- engine/src/configuration/CMakeLists.txt | 29 +- engine/src/configuration/extended_conf.cc | 92 +++ engine/src/configuration/state.cc | 656 +++++++++++------- engine/src/events/loop.cc | 44 +- engine/src/main.cc | 69 +- .../configuration/applier/applier-state.cc | 50 ++ tests/engine/extended_conf.robot | 62 ++ tests/resources/Engine.py | 27 + 15 files changed, 848 insertions(+), 399 deletions(-) create mode 100644 engine/inc/com/centreon/engine/configuration/extended_conf.hh create mode 100644 engine/src/configuration/extended_conf.cc create mode 100644 tests/engine/extended_conf.robot diff --git a/broker/neb/CMakeLists.txt b/broker/neb/CMakeLists.txt index 5a118318fa2..3ae0d5444a0 100644 --- a/broker/neb/CMakeLists.txt +++ b/broker/neb/CMakeLists.txt @@ -117,7 +117,6 @@ add_library( target_link_libraries(${NEB} nebbase CONAN_PKG::spdlog) set_target_properties("${NEB}" PROPERTIES PREFIX "") -target_precompile_headers(${NEB} REUSE_FROM nebbase) install(TARGETS "${NEB}" LIBRARY DESTINATION "${PREFIX_MODULES}") # Centreon Engine/Nagios module. diff --git a/broker/neb/src/broker.cc b/broker/neb/src/broker.cc index 3338093a97b..ff8a11a2e3e 100644 --- a/broker/neb/src/broker.cc +++ b/broker/neb/src/broker.cc @@ -16,6 +16,18 @@ ** For more information : contact@centreon.com */ +#include + +#include +#include + +#include +#include + +#include + +namespace asio = boost::asio; + #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/io/protocols.hh" #include "com/centreon/broker/log_v2.hh" diff --git a/engine/inc/com/centreon/engine/configuration/extended_conf.hh b/engine/inc/com/centreon/engine/configuration/extended_conf.hh new file mode 100644 index 00000000000..18e68f4bdd2 --- /dev/null +++ b/engine/inc/com/centreon/engine/configuration/extended_conf.hh @@ -0,0 +1,72 @@ +/** + * Copyright 2022-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_CONFIGURATION_EXTENDED_STATE_HH +#define CCE_CONFIGURATION_EXTENDED_STATE_HH + +namespace com::centreon::engine::configuration { + +class state; + +/** + * @brief contain json data of a config file passed in param to centengine + * command line + * + */ +class extended_conf { + std::string _path; + struct stat _file_info; + nlohmann::json _content; + + static std::list> _confs; + + public: + extended_conf(const std::string& path); + ~extended_conf() = default; + extended_conf(const extended_conf&) = delete; + extended_conf& operator=(const extended_conf&) = delete; + void reload(); + + static void update_state(state& dest); + + template + static void load_all(file_path_iterator begin, file_path_iterator); +}; + +/** + * @brief try to load all extra configuration files + * if one or more fail, we continue + * + * @tparam file_path_iterator + * @param begin + * @param end + */ +template +void extended_conf::load_all(file_path_iterator begin, file_path_iterator end) { + _confs.clear(); + for (; begin != end; ++begin) { + try { + _confs.emplace_back(std::make_unique(*begin)); + } catch (const std::exception&) { + } + } +} + +} // namespace com::centreon::engine::configuration + +#endif diff --git a/engine/inc/com/centreon/engine/configuration/state.hh b/engine/inc/com/centreon/engine/configuration/state.hh index 8a053809f9b..46df81da7f7 100644 --- a/engine/inc/com/centreon/engine/configuration/state.hh +++ b/engine/inc/com/centreon/engine/configuration/state.hh @@ -20,6 +20,12 @@ #ifndef CCE_CONFIGURATION_STATE_HH #define CCE_CONFIGURATION_STATE_HH +// don't put it in precomp.hpp because it includes time.h to all sources (not +// compatible with custom gettimeofday in utils.cc) +#include + +#include "com/centreon/engine/log_v2.hh" + #include "com/centreon/engine/configuration/anomalydetection.hh" #include "com/centreon/engine/configuration/command.hh" #include "com/centreon/engine/configuration/connector.hh" @@ -38,9 +44,20 @@ #include "com/centreon/engine/configuration/timeperiod.hh" #include "com/centreon/engine/logging/logger.hh" -CCE_BEGIN() +namespace com::centreon::engine::configuration { + +class setter_base { + protected: + const std::string_view _field_name; + + public: + setter_base(const std::string_view& field_name) : _field_name(field_name) {} + + virtual ~setter_base() = default; + virtual bool apply_from_cfg(state& obj, const char* value) = 0; + virtual bool apply_from_json(state& obj, const nlohmann::json& doc) = 0; +}; -namespace configuration { /** * @class state state.hh * @brief Simple configuration state class. @@ -168,8 +185,8 @@ class state { void date_format(date_type value); std::string const& debug_file() const noexcept; void debug_file(std::string const& value); - unsigned long long debug_level() const noexcept; - void debug_level(unsigned long long value); + uint64_t debug_level() const noexcept; + void debug_level(uint64_t value); unsigned int debug_verbosity() const noexcept; void debug_verbosity(unsigned int value); bool enable_environment_macros() const noexcept; @@ -436,9 +453,15 @@ class state { bool use_true_regexp_matching() const noexcept; void use_true_regexp_matching(bool value); - private: - typedef bool (*setter_func)(state&, char const*); + using setter_map = + absl::flat_hash_map>; + static const setter_map& get_setters() { return _setters; } + + void apply_extended_conf(const std::string& file_path, + const nlohmann::json& json_doc); + private: + static void _init_setter(); void _set_aggregate_status_updates(std::string const& value); void _set_auth_file(std::string const& value); void _set_bare_update_check(std::string const& value); @@ -477,35 +500,6 @@ class state { void _set_temp_path(std::string const& value); void _set_use_embedded_perl_implicitly(std::string const& value); - template - struct setter { - static bool generic(state& obj, char const* value) { - try { - U val(0); - if (!string::to(value, val)) - return (false); - (obj.*ptr)(val); - } catch (std::exception const& e) { - engine_logger(logging::log_config_error, logging::basic) << e.what(); - return (false); - } - return (true); - } - }; - - template - struct setter { - static bool generic(state& obj, char const* value) { - try { - (obj.*ptr)(value); - } catch (std::exception const& e) { - engine_logger(logging::log_config_error, logging::basic) << e.what(); - return (false); - } - return (true); - } - }; - bool _accept_passive_host_checks; bool _accept_passive_service_checks; int _additional_freshness_latency; @@ -539,7 +533,7 @@ class state { set_contact _contacts; date_type _date_format; std::string _debug_file; - unsigned long long _debug_level; + uint64_t _debug_level; unsigned int _debug_verbosity; bool _enable_environment_macros; bool _enable_event_handlers; @@ -627,7 +621,7 @@ class state { std::string _service_perfdata_file_processing_command; unsigned int _service_perfdata_file_processing_interval; std::string _service_perfdata_file_template; - static std::unordered_map const _setters; + static setter_map _setters; float _sleep_time; bool _soft_state_dependencies; std::string _state_retention_file; @@ -662,8 +656,7 @@ class state { std::string _use_timezone; bool _use_true_regexp_matching; }; -} // namespace configuration -CCE_END() +} // namespace com::centreon::engine::configuration #endif // !CCE_CONFIGURATION_STATE_HH diff --git a/engine/inc/com/centreon/engine/log_v2.hh b/engine/inc/com/centreon/engine/log_v2.hh index e6e41f59f8c..c5501d1540e 100644 --- a/engine/inc/com/centreon/engine/log_v2.hh +++ b/engine/inc/com/centreon/engine/log_v2.hh @@ -18,10 +18,13 @@ #ifndef CCE_LOG_V2_HH #define CCE_LOG_V2_HH -#include "com/centreon/engine/configuration/state.hh" #include "log_v2_base.hh" -CCE_BEGIN() +namespace com::centreon::engine { +namespace configuration { +class state; +} + class log_v2 : public log_v2_base { std::array, 13> _log; std::atomic_bool _running; @@ -117,6 +120,7 @@ class log_v2 : public log_v2_base { return _instance->get_logger(log_v2::log_runtime, "runtime"); } }; -CCE_END() + +} // namespace com::centreon::engine #endif /* !CCE_LOG_V2_HH */ diff --git a/engine/precomp_inc/precomp.hh b/engine/precomp_inc/precomp.hh index dd2249aa5fd..907e95cffe6 100644 --- a/engine/precomp_inc/precomp.hh +++ b/engine/precomp_inc/precomp.hh @@ -31,10 +31,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -61,11 +57,22 @@ #include #include #include +#include #include #include #include #include +#include + +#include +#include +#include +#include +#include + +#include + #include "com/centreon/engine/namespace.hh" namespace fmt { diff --git a/engine/src/checkable.cc b/engine/src/checkable.cc index d9280a9c2aa..d52b6d50856 100644 --- a/engine/src/checkable.cc +++ b/engine/src/checkable.cc @@ -1,25 +1,26 @@ -/* -** Copyright 2011-2019,2022 Centreon -** -** This file is part of Centreon Engine. -** -** Centreon Engine is free software: you can redistribute it and/or -** modify it under the terms of the GNU General Public License version 2 -** as published by the Free Software Foundation. -** -** Centreon Engine 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 Centreon Engine. If not, see -** . -*/ +/** + * Copyright 2011-2019,2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine 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 Centreon Engine. If not, see + * . + */ #include "com/centreon/engine/checkable.hh" #include "com/centreon/engine/exceptions/error.hh" #include "com/centreon/engine/log_v2.hh" +#include "com/centreon/engine/logging/logger.hh" using namespace com::centreon::engine; using namespace com::centreon::engine::logging; diff --git a/engine/src/configuration/CMakeLists.txt b/engine/src/configuration/CMakeLists.txt index 8749367e68f..d4cd76d7837 100644 --- a/engine/src/configuration/CMakeLists.txt +++ b/engine/src/configuration/CMakeLists.txt @@ -35,6 +35,7 @@ set( "${SRC_DIR}/connector.cc" "${SRC_DIR}/contact.cc" "${SRC_DIR}/contactgroup.cc" + "${SRC_DIR}/extended_conf.cc" "${SRC_DIR}/group.cc" "${SRC_DIR}/host.cc" "${SRC_DIR}/hostdependency.cc" @@ -54,33 +55,5 @@ set( "${SRC_DIR}/severity.cc" "${SRC_DIR}/tag.cc" "${SRC_DIR}/timeperiod.cc" - - # Headers. - "${INC_DIR}/anomalydetection.hh" - "${INC_DIR}/command.hh" - "${INC_DIR}/connector.hh" - "${INC_DIR}/contactgroup.hh" - "${INC_DIR}/contact.hh" - "${INC_DIR}/file_info.hh" - "${INC_DIR}/group.hh" - "${INC_DIR}/host.hh" - "${INC_DIR}/hostdependency.hh" - "${INC_DIR}/hostescalation.hh" - "${INC_DIR}/hostextinfo.hh" - "${INC_DIR}/hostgroup.hh" - "${INC_DIR}/object.hh" - "${INC_DIR}/parser.hh" - "${INC_DIR}/point_2d.hh" - "${INC_DIR}/point_3d.hh" - "${INC_DIR}/servicedependency.hh" - "${INC_DIR}/serviceescalation.hh" - "${INC_DIR}/serviceextinfo.hh" - "${INC_DIR}/servicegroup.hh" - "${INC_DIR}/service.hh" - "${INC_DIR}/severity.hh" - "${INC_DIR}/state.hh" - "${INC_DIR}/tag.hh" - "${INC_DIR}/timeperiod.hh" - PARENT_SCOPE ) diff --git a/engine/src/configuration/extended_conf.cc b/engine/src/configuration/extended_conf.cc new file mode 100644 index 00000000000..62159f2ea49 --- /dev/null +++ b/engine/src/configuration/extended_conf.cc @@ -0,0 +1,92 @@ +/** + * Copyright 2022-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/configuration/extended_conf.hh" +#include "com/centreon/engine/configuration/state.hh" +#include "com/centreon/exceptions/msg_fmt.hh" + +using namespace com::centreon::engine::configuration; + +std::list> extended_conf::_confs; + +/** + * @brief Construct a new extended state::extended state object + * + * @param path of the configuration file + * @throw exception if json malformed + */ +extended_conf::extended_conf(const std::string& path) : _path(path) { + if (::stat(_path.c_str(), &_file_info)) { + SPDLOG_LOGGER_ERROR(log_v2::config(), "can't access to {}", _path); + throw exceptions::msg_fmt("can't access to {}", _path); + } + try { + std::ifstream f(_path); + _content = nlohmann::json::parse(f); + SPDLOG_LOGGER_INFO(log_v2::config(), "extended conf file {} loaded", _path); + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR( + log_v2::config(), + "extended_conf::extended_conf : fail to read json content from {}: {}", + _path, e.what()); + throw; + } +} + +/** + * @brief checks if the file has been updated. + * In that case, file is parsed. In case of failure, we continue to use old + * version + * + */ +void extended_conf::reload() { + struct stat file_info; + if (::stat(_path.c_str(), &file_info)) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "can't access to {} anymore => we keep old content", + _path); + return; + } + if (!memcmp(&file_info, &_file_info, sizeof(struct stat))) { + return; + } + try { + std::ifstream f(_path); + auto new_content = nlohmann::json::parse(f); + _content = std::move(new_content); + _file_info = file_info; + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "extended_conf::extended_conf : fail to read json " + "content from {} => we keep old content, cause: {}", + _path, e.what()); + } +} + +/** + * @brief reload all optional configuration files if needed + * Then these configuration content are applied to dest + * + * @param dest + */ +void extended_conf::update_state(state& dest) { + for (auto& conf_file : _confs) { + conf_file->reload(); + dest.apply_extended_conf(conf_file->_path, conf_file->_content); + } +} diff --git a/engine/src/configuration/state.cc b/engine/src/configuration/state.cc index 79e41a540a7..275a85c5f6a 100644 --- a/engine/src/configuration/state.cc +++ b/engine/src/configuration/state.cc @@ -1,21 +1,25 @@ -/* -** Copyright 2011-2013,2015-2017, 2021-2022 Centreon -** -** This file is part of Centreon Engine. -** -** Centreon Engine is free software: you can redistribute it and/or -** modify it under the terms of the GNU General Public License version 2 -** as published by the Free Software Foundation. -** -** Centreon Engine 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 Centreon Engine. If not, see -** . -*/ +/** + * Copyright 2011-2013,2015-2017, 2021-2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine 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 Centreon Engine. If not, see + * . + */ + +#include + +#include #include "com/centreon/engine/configuration/state.hh" @@ -32,233 +36,348 @@ using namespace com::centreon::engine; using namespace com::centreon::engine::configuration; using namespace com::centreon::engine::logging; -#define SETTER(type, method) &state::setter::generic - -std::unordered_map const state::_setters{ - {"accept_passive_host_checks", SETTER(bool, accept_passive_host_checks)}, - {"accept_passive_service_checks", - SETTER(bool, accept_passive_service_checks)}, - {"additional_freshness_latency", SETTER(int, additional_freshness_latency)}, - {"admin_email", SETTER(std::string const&, admin_email)}, - {"admin_pager", SETTER(std::string const&, admin_pager)}, - {"aggregate_status_updates", - SETTER(std::string const&, _set_aggregate_status_updates)}, - {"allow_empty_hostgroup_assignment", - SETTER(bool, allow_empty_hostgroup_assignment)}, - {"auth_file", SETTER(std::string const&, _set_auth_file)}, - {"auto_reschedule_checks", SETTER(bool, auto_reschedule_checks)}, - {"auto_rescheduling_interval", - SETTER(unsigned int, auto_rescheduling_interval)}, - {"auto_rescheduling_window", - SETTER(unsigned int, auto_rescheduling_window)}, - {"bare_update_check", SETTER(std::string const&, _set_bare_update_check)}, - {"broker_module_directory", - SETTER(std::string const&, broker_module_directory)}, - {"broker_module", SETTER(std::string const&, _set_broker_module)}, - {"cached_host_check_horizon", - SETTER(unsigned long, cached_host_check_horizon)}, - {"cached_service_check_horizon", - SETTER(unsigned long, cached_service_check_horizon)}, - {"cfg_dir", SETTER(std::string const&, _set_cfg_dir)}, - {"cfg_file", SETTER(std::string const&, _set_cfg_file)}, - {"check_external_commands", SETTER(bool, check_external_commands)}, - {"check_for_orphaned_hosts", SETTER(bool, check_orphaned_hosts)}, - {"check_for_orphaned_services", SETTER(bool, check_orphaned_services)}, - {"check_for_updates", SETTER(std::string const&, _set_check_for_updates)}, - {"check_host_freshness", SETTER(bool, check_host_freshness)}, - {"check_result_reaper_frequency", - SETTER(unsigned int, check_reaper_interval)}, - {"check_service_freshness", SETTER(bool, check_service_freshness)}, - {"child_processes_fork_twice", - SETTER(std::string const&, _set_child_processes_fork_twice)}, - {"command_check_interval", - SETTER(std::string const&, _set_command_check_interval)}, - {"command_file", SETTER(std::string const&, command_file)}, - {"comment_file", SETTER(std::string const&, _set_comment_file)}, - {"daemon_dumps_core", SETTER(std::string const&, _set_daemon_dumps_core)}, - {"date_format", SETTER(std::string const&, _set_date_format)}, - {"debug_file", SETTER(std::string const&, debug_file)}, - {"debug_level", SETTER(unsigned long long, debug_level)}, - {"debug_verbosity", SETTER(unsigned int, debug_verbosity)}, - {"downtime_file", SETTER(std::string const&, _set_downtime_file)}, - {"enable_embedded_perl", - SETTER(std::string const&, _set_enable_embedded_perl)}, - {"enable_environment_macros", SETTER(bool, enable_environment_macros)}, - {"enable_event_handlers", SETTER(bool, enable_event_handlers)}, - {"enable_failure_prediction", - SETTER(std::string const&, _set_enable_failure_prediction)}, - {"enable_flap_detection", SETTER(bool, enable_flap_detection)}, - {"enable_macros_filter", SETTER(bool, enable_macros_filter)}, - {"enable_notifications", SETTER(bool, enable_notifications)}, - {"enable_predictive_host_dependency_checks", - SETTER(bool, enable_predictive_host_dependency_checks)}, - {"enable_predictive_service_dependency_checks", - SETTER(bool, enable_predictive_service_dependency_checks)}, - {"event_broker_options", - SETTER(std::string const&, _set_event_broker_options)}, - {"event_handler_timeout", SETTER(unsigned int, event_handler_timeout)}, - {"execute_host_checks", SETTER(bool, execute_host_checks)}, - {"execute_service_checks", SETTER(bool, execute_service_checks)}, - {"external_command_buffer_slots", - SETTER(int, external_command_buffer_slots)}, - {"free_child_process_memory", - SETTER(std::string const&, _set_free_child_process_memory)}, - {"global_host_event_handler", - SETTER(std::string const&, global_host_event_handler)}, - {"global_service_event_handler", - SETTER(std::string const&, global_service_event_handler)}, - {"high_host_flap_threshold", SETTER(float, high_host_flap_threshold)}, - {"high_service_flap_threshold", SETTER(float, high_service_flap_threshold)}, - {"host_check_timeout", SETTER(unsigned int, host_check_timeout)}, - {"host_freshness_check_interval", - SETTER(unsigned int, host_freshness_check_interval)}, - {"host_inter_check_delay_method", - SETTER(std::string const&, _set_host_inter_check_delay_method)}, - {"host_perfdata_command", - SETTER(std::string const&, host_perfdata_command)}, - {"host_perfdata_file", SETTER(std::string const&, host_perfdata_file)}, - {"host_perfdata_file_mode", - SETTER(std::string const&, _set_host_perfdata_file_mode)}, - {"host_perfdata_file_processing_command", - SETTER(std::string const&, host_perfdata_file_processing_command)}, - {"host_perfdata_file_processing_interval", - SETTER(unsigned int, host_perfdata_file_processing_interval)}, - {"host_perfdata_file_template", - SETTER(std::string const&, host_perfdata_file_template)}, - {"illegal_macro_output_chars", - SETTER(std::string const&, illegal_output_chars)}, - {"illegal_object_name_chars", - SETTER(std::string const&, illegal_object_chars)}, - {"interval_length", SETTER(unsigned int, interval_length)}, - {"lock_file", SETTER(std::string const&, _set_lock_file)}, - {"log_archive_path", SETTER(std::string const&, _set_log_archive_path)}, - {"log_event_handlers", SETTER(bool, log_event_handlers)}, - {"log_external_commands", SETTER(bool, log_external_commands)}, - {"log_file", SETTER(std::string const&, log_file)}, - {"log_host_retries", SETTER(bool, log_host_retries)}, - {"log_initial_states", SETTER(std::string const&, _set_log_initial_states)}, - {"log_notifications", SETTER(bool, log_notifications)}, - {"log_passive_checks", SETTER(bool, log_passive_checks)}, - {"log_pid", SETTER(bool, log_pid)}, - {"log_file_line", SETTER(bool, log_file_line)}, - {"log_rotation_method", - SETTER(std::string const&, _set_log_rotation_method)}, - {"log_service_retries", SETTER(bool, log_service_retries)}, - {"low_host_flap_threshold", SETTER(float, low_host_flap_threshold)}, - {"low_service_flap_threshold", SETTER(float, low_service_flap_threshold)}, - {"macros_filter", SETTER(std::string const&, macros_filter)}, - {"max_concurrent_checks", - SETTER(unsigned int, max_parallel_service_checks)}, - {"max_debug_file_size", SETTER(unsigned long, max_debug_file_size)}, - {"max_host_check_spread", SETTER(unsigned int, max_host_check_spread)}, - {"max_log_file_size", SETTER(unsigned long, max_log_file_size)}, - {"log_flush_period", SETTER(uint32_t, log_flush_period)}, - {"max_service_check_spread", - SETTER(unsigned int, max_service_check_spread)}, - {"nagios_group", SETTER(std::string const&, _set_nagios_group)}, - {"nagios_user", SETTER(std::string const&, _set_nagios_user)}, - {"notification_timeout", SETTER(unsigned int, notification_timeout)}, - {"object_cache_file", SETTER(std::string const&, _set_object_cache_file)}, - {"obsess_over_hosts", SETTER(bool, obsess_over_hosts)}, - {"obsess_over_services", SETTER(bool, obsess_over_services)}, - {"ochp_command", SETTER(std::string const&, ochp_command)}, - {"ochp_timeout", SETTER(unsigned int, ochp_timeout)}, - {"ocsp_command", SETTER(std::string const&, ocsp_command)}, - {"ocsp_timeout", SETTER(unsigned int, ocsp_timeout)}, - {"p1_file", SETTER(std::string const&, _set_p1_file)}, - {"perfdata_timeout", SETTER(int, perfdata_timeout)}, - {"poller_name", SETTER(std::string const&, poller_name)}, - {"poller_id", SETTER(uint32_t, poller_id)}, - {"rpc_port", SETTER(uint16_t, rpc_port)}, - {"rpc_listen_address", SETTER(const std::string&, rpc_listen_address)}, - {"precached_object_file", - SETTER(std::string const&, _set_precached_object_file)}, - {"process_performance_data", SETTER(bool, process_performance_data)}, - {"resource_file", SETTER(std::string const&, _set_resource_file)}, - {"retained_contact_host_attribute_mask", - SETTER(unsigned long, retained_contact_host_attribute_mask)}, - {"retained_contact_service_attribute_mask", - SETTER(unsigned long, retained_contact_service_attribute_mask)}, - {"retained_host_attribute_mask", - SETTER(unsigned long, retained_host_attribute_mask)}, - {"retained_process_host_attribute_mask", - SETTER(unsigned long, retained_process_host_attribute_mask)}, - {"retained_process_service_attribute_mask", - SETTER(std::string const&, _set_retained_process_service_attribute_mask)}, - {"retained_service_attribute_mask", - SETTER(std::string const&, _set_retained_service_attribute_mask)}, - {"retain_state_information", SETTER(bool, retain_state_information)}, - {"retention_scheduling_horizon", - SETTER(unsigned int, retention_scheduling_horizon)}, - {"retention_update_interval", - SETTER(unsigned int, retention_update_interval)}, - {"service_check_timeout", SETTER(unsigned int, service_check_timeout)}, - {"service_freshness_check_interval", - SETTER(unsigned int, service_freshness_check_interval)}, - {"service_inter_check_delay_method", - SETTER(std::string const&, _set_service_inter_check_delay_method)}, - {"service_interleave_factor", - SETTER(std::string const&, _set_service_interleave_factor_method)}, - {"service_perfdata_command", - SETTER(std::string const&, service_perfdata_command)}, - {"service_perfdata_file", - SETTER(std::string const&, service_perfdata_file)}, - {"service_perfdata_file_mode", - SETTER(std::string const&, _set_service_perfdata_file_mode)}, - {"service_perfdata_file_processing_command", - SETTER(std::string const&, service_perfdata_file_processing_command)}, - {"service_perfdata_file_processing_interval", - SETTER(unsigned int, service_perfdata_file_processing_interval)}, - {"service_perfdata_file_template", - SETTER(std::string const&, service_perfdata_file_template)}, - {"service_reaper_frequency", SETTER(unsigned int, check_reaper_interval)}, - {"sleep_time", SETTER(float, sleep_time)}, - {"soft_state_dependencies", SETTER(bool, soft_state_dependencies)}, - {"state_retention_file", SETTER(std::string const&, state_retention_file)}, - {"status_file", SETTER(std::string const&, status_file)}, - {"status_update_interval", SETTER(unsigned int, status_update_interval)}, - {"temp_file", SETTER(std::string const&, _set_temp_file)}, - {"temp_path", SETTER(std::string const&, _set_temp_path)}, - {"time_change_threshold", SETTER(unsigned int, time_change_threshold)}, - {"use_aggressive_host_checking", - SETTER(bool, use_aggressive_host_checking)}, - {"use_agressive_host_checking", SETTER(bool, use_aggressive_host_checking)}, - {"use_embedded_perl_implicitly", - SETTER(std::string const&, _set_use_embedded_perl_implicitly)}, - {"use_large_installation_tweaks", - SETTER(bool, use_large_installation_tweaks)}, - {"instance_heartbeat_interval", - SETTER(uint32_t, instance_heartbeat_interval)}, - {"use_regexp_matching", SETTER(bool, use_regexp_matches)}, - {"use_retained_program_state", SETTER(bool, use_retained_program_state)}, - {"use_retained_scheduling_info", - SETTER(bool, use_retained_scheduling_info)}, - {"use_setpgid", SETTER(bool, use_setpgid)}, - {"use_syslog", SETTER(bool, use_syslog)}, - {"log_v2_enabled", SETTER(bool, log_v2_enabled)}, - {"log_legacy_enabled", SETTER(bool, log_legacy_enabled)}, - {"log_v2_logger", SETTER(std::string const&, log_v2_logger)}, - {"log_level_functions", SETTER(std::string const&, log_level_functions)}, - {"log_level_config", SETTER(std::string const&, log_level_config)}, - {"log_level_events", SETTER(std::string const&, log_level_events)}, - {"log_level_checks", SETTER(std::string const&, log_level_checks)}, - {"log_level_notifications", - SETTER(std::string const&, log_level_notifications)}, - {"log_level_eventbroker", - SETTER(std::string const&, log_level_eventbroker)}, - {"log_level_external_command", - SETTER(std::string const&, log_level_external_command)}, - {"log_level_commands", SETTER(std::string const&, log_level_commands)}, - {"log_level_downtimes", SETTER(std::string const&, log_level_downtimes)}, - {"log_level_comments", SETTER(std::string const&, log_level_comments)}, - {"log_level_macros", SETTER(std::string const&, log_level_macros)}, - {"log_level_process", SETTER(std::string const&, log_level_process)}, - {"log_level_runtime", SETTER(std::string const&, log_level_runtime)}, - {"use_timezone", SETTER(std::string const&, use_timezone)}, - {"use_true_regexp_matching", SETTER(bool, use_true_regexp_matching)}, - {"xcddefault_comment_file", SETTER(std::string const&, _set_comment_file)}, - {"xdddefault_downtime_file", - SETTER(std::string const&, _set_downtime_file)}}; + +/** + * nlohmann json object can be casted to bool, string, int64_t, uint64_t + * The goal of these overrides is to use the correct conversion type operator for the state attribute type +*/ + +/** + * float and double +*/ +template {}, + bool>::type = true> +static dest_type from_nlohmann_cast(double value) { + return boost::numeric_cast(value); +} + +/** + * unsigned integer +*/ +template {} && + !std::is_floating_point{}, + bool>::type = true> +static dest_type from_nlohmann_cast(uint64_t value) { + return boost::numeric_cast(value); +} + + +/** + * signed integer +*/ +template {} && + !std::is_floating_point{}, + bool>::type = true> +static dest_type from_nlohmann_cast(int64_t value) { + return boost::numeric_cast(value); +} + +namespace com::centreon::engine::configuration::detail { +template +struct setter : public setter_base { + setter(const std::string_view& field_name) : setter_base(field_name) {} + bool apply_from_cfg(state& obj, char const* value) override { + try { + U val(0); + if (!string::to(value, val)) + return false; + (obj.*ptr)(val); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "fail to update {} with value {}: {}", + setter_base::_field_name, value, e.what()); + return false; + } + return true; + } + + bool apply_from_json(state& obj, const nlohmann::json& doc) override { + try { + U val = from_nlohmann_cast(doc[setter_base::_field_name.data()]); + (obj.*ptr)(val); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), "fail to update {} : {}", + setter_base::_field_name, e.what()); + return false; + } + return true; + } +}; + +template +struct setter : public setter_base { + setter(const std::string_view& field_name) : setter_base(field_name) {} + bool apply_from_cfg(state& obj, char const* value) override { + try { + bool val(0); + if (!string::to(value, val)) + return false; + (obj.*ptr)(val); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "fail to update {} with value {}: {}", + setter_base::_field_name, value, e.what()); + return false; + } + return true; + } + + bool apply_from_json(state& obj, const nlohmann::json& doc) override { + try { + bool val = doc[setter_base::_field_name.data()]; + (obj.*ptr)(val); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), "fail to update {} : {}", + setter_base::_field_name, e.what()); + return false; + } + return true; + } +}; + +template +struct setter : public setter_base { + setter(const std::string_view& field_name) : setter_base(field_name) {} + bool apply_from_cfg(state& obj, char const* value) override { + try { + (obj.*ptr)(value); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "fail to update {} with value {}: {}", _field_name, + value, e.what()); + return false; + } + return true; + } + bool apply_from_json(state& obj, const nlohmann::json& doc) override { + try { + std::string val = doc[setter_base::_field_name.data()]; + (obj.*ptr)(val); + } catch (std::exception const& e) { + SPDLOG_LOGGER_ERROR(log_v2::config(), "fail to update {} : {}", + _field_name, e.what()); + return false; + } + return true; + } +}; +}; // namespace com::centreon::engine::configuration::detail + +#define SETTER(type, method, field) \ + _setters.emplace(std::make_pair( \ + field, std::make_unique>(field))) + +state::setter_map state::_setters; + +void state::_init_setter() { + SETTER(bool, accept_passive_host_checks, "accept_passive_host_checks"); + SETTER(bool, accept_passive_service_checks, "accept_passive_service_checks"); + SETTER(int, additional_freshness_latency, "additional_freshness_latency"); + SETTER(std::string const&, admin_email, "admin_email"); + SETTER(std::string const&, admin_pager, "admin_pager"); + SETTER(std::string const&, _set_aggregate_status_updates, + "aggregate_status_updates"); + SETTER(bool, allow_empty_hostgroup_assignment, + "allow_empty_hostgroup_assignment"); + SETTER(std::string const&, _set_auth_file, "auth_file"); + SETTER(bool, auto_reschedule_checks, "auto_reschedule_checks"); + SETTER(unsigned int, auto_rescheduling_interval, + "auto_rescheduling_interval"); + SETTER(unsigned int, auto_rescheduling_window, "auto_rescheduling_window"); + SETTER(std::string const&, _set_bare_update_check, "bare_update_check"); + SETTER(std::string const&, broker_module_directory, + "broker_module_directory"); + SETTER(std::string const&, _set_broker_module, "broker_module"); + SETTER(unsigned long, cached_host_check_horizon, "cached_host_check_horizon"); + SETTER(unsigned long, cached_service_check_horizon, + "cached_service_check_horizon"); + SETTER(std::string const&, _set_cfg_dir, "cfg_dir"); + SETTER(std::string const&, _set_cfg_file, "cfg_file"); + SETTER(bool, check_external_commands, "check_external_commands"); + SETTER(bool, check_orphaned_hosts, "check_for_orphaned_hosts"); + SETTER(bool, check_orphaned_services, "check_for_orphaned_services"); + SETTER(std::string const&, _set_check_for_updates, "check_for_updates"); + SETTER(bool, check_host_freshness, "check_host_freshness"); + SETTER(unsigned int, check_reaper_interval, "check_result_reaper_frequency"); + SETTER(bool, check_service_freshness, "check_service_freshness"); + SETTER(std::string const&, _set_child_processes_fork_twice, + "child_processes_fork_twice"); + SETTER(std::string const&, _set_command_check_interval, + "command_check_interval"); + SETTER(std::string const&, command_file, "command_file"); + SETTER(std::string const&, _set_comment_file, "comment_file"); + SETTER(std::string const&, _set_daemon_dumps_core, "daemon_dumps_core"); + SETTER(std::string const&, _set_date_format, "date_format"); + SETTER(std::string const&, debug_file, "debug_file"); + SETTER(uint64_t, debug_level, "debug_level"); + SETTER(unsigned int, debug_verbosity, "debug_verbosity"); + SETTER(std::string const&, _set_downtime_file, "downtime_file"); + SETTER(std::string const&, _set_enable_embedded_perl, "enable_embedded_perl"); + SETTER(bool, enable_environment_macros, "enable_environment_macros"); + SETTER(bool, enable_event_handlers, "enable_event_handlers"); + SETTER(std::string const&, _set_enable_failure_prediction, + "enable_failure_prediction"); + SETTER(bool, enable_flap_detection, "enable_flap_detection"); + SETTER(bool, enable_macros_filter, "enable_macros_filter"); + SETTER(bool, enable_notifications, "enable_notifications"); + SETTER(bool, enable_predictive_host_dependency_checks, + "enable_predictive_host_dependency_checks"); + SETTER(bool, enable_predictive_service_dependency_checks, + "enable_predictive_service_dependency_checks"); + SETTER(std::string const&, _set_event_broker_options, "event_broker_options"); + SETTER(unsigned int, event_handler_timeout, "event_handler_timeout"); + SETTER(bool, execute_host_checks, "execute_host_checks"); + SETTER(bool, execute_service_checks, "execute_service_checks"); + SETTER(int, external_command_buffer_slots, "external_command_buffer_slots"); + SETTER(std::string const&, _set_free_child_process_memory, + "free_child_process_memory"); + SETTER(std::string const&, global_host_event_handler, + "global_host_event_handler"); + SETTER(std::string const&, global_service_event_handler, + "global_service_event_handler"); + SETTER(float, high_host_flap_threshold, "high_host_flap_threshold"); + SETTER(float, high_service_flap_threshold, "high_service_flap_threshold"); + SETTER(unsigned int, host_check_timeout, "host_check_timeout"); + SETTER(unsigned int, host_freshness_check_interval, + "host_freshness_check_interval"); + SETTER(std::string const&, _set_host_inter_check_delay_method, + "host_inter_check_delay_method"); + SETTER(std::string const&, host_perfdata_command, "host_perfdata_command"); + SETTER(std::string const&, host_perfdata_file, "host_perfdata_file"); + SETTER(std::string const&, _set_host_perfdata_file_mode, + "host_perfdata_file_mode"); + SETTER(std::string const&, host_perfdata_file_processing_command, + "host_perfdata_file_processing_command"); + SETTER(unsigned int, host_perfdata_file_processing_interval, + "host_perfdata_file_processing_interval"); + SETTER(std::string const&, host_perfdata_file_template, + "host_perfdata_file_template"); + SETTER(std::string const&, illegal_output_chars, + "illegal_macro_output_chars"); + SETTER(std::string const&, illegal_object_chars, "illegal_object_name_chars"); + SETTER(unsigned int, interval_length, "interval_length"); + SETTER(std::string const&, _set_lock_file, "lock_file"); + SETTER(std::string const&, _set_log_archive_path, "log_archive_path"); + SETTER(bool, log_event_handlers, "log_event_handlers"); + SETTER(bool, log_external_commands, "log_external_commands"); + SETTER(std::string const&, log_file, "log_file"); + SETTER(bool, log_host_retries, "log_host_retries"); + SETTER(std::string const&, _set_log_initial_states, "log_initial_states"); + SETTER(bool, log_notifications, "log_notifications"); + SETTER(bool, log_passive_checks, "log_passive_checks"); + SETTER(bool, log_pid, "log_pid"); + SETTER(bool, log_file_line, "log_file_line"); + SETTER(std::string const&, _set_log_rotation_method, "log_rotation_method"); + SETTER(bool, log_service_retries, "log_service_retries"); + SETTER(float, low_host_flap_threshold, "low_host_flap_threshold"); + SETTER(float, low_service_flap_threshold, "low_service_flap_threshold"); + SETTER(std::string const&, macros_filter, "macros_filter"); + SETTER(unsigned int, max_parallel_service_checks, "max_concurrent_checks"); + SETTER(unsigned long, max_debug_file_size, "max_debug_file_size"); + SETTER(unsigned int, max_host_check_spread, "max_host_check_spread"); + SETTER(unsigned long, max_log_file_size, "max_log_file_size"); + SETTER(uint32_t, log_flush_period, "log_flush_period"); + SETTER(unsigned int, max_service_check_spread, "max_service_check_spread"); + SETTER(std::string const&, _set_nagios_group, "nagios_group"); + SETTER(std::string const&, _set_nagios_user, "nagios_user"); + SETTER(unsigned int, notification_timeout, "notification_timeout"); + SETTER(std::string const&, _set_object_cache_file, "object_cache_file"); + SETTER(bool, obsess_over_hosts, "obsess_over_hosts"); + SETTER(bool, obsess_over_services, "obsess_over_services"); + SETTER(std::string const&, ochp_command, "ochp_command"); + SETTER(unsigned int, ochp_timeout, "ochp_timeout"); + SETTER(std::string const&, ocsp_command, "ocsp_command"); + SETTER(unsigned int, ocsp_timeout, "ocsp_timeout"); + SETTER(std::string const&, _set_p1_file, "p1_file"); + SETTER(int, perfdata_timeout, "perfdata_timeout"); + SETTER(std::string const&, poller_name, "poller_name"); + SETTER(uint32_t, poller_id, "poller_id"); + SETTER(uint16_t, rpc_port, "rpc_port"); + SETTER(const std::string&, rpc_listen_address, "rpc_listen_address"); + SETTER(std::string const&, _set_precached_object_file, + "precached_object_file"); + SETTER(bool, process_performance_data, "process_performance_data"); + SETTER(std::string const&, _set_resource_file, "resource_file"); + SETTER(unsigned long, retained_contact_host_attribute_mask, + "retained_contact_host_attribute_mask"); + SETTER(unsigned long, retained_contact_service_attribute_mask, + "retained_contact_service_attribute_mask"); + SETTER(unsigned long, retained_host_attribute_mask, + "retained_host_attribute_mask"); + SETTER(unsigned long, retained_process_host_attribute_mask, + "retained_process_host_attribute_mask"); + SETTER(std::string const&, _set_retained_process_service_attribute_mask, + "retained_process_service_attribute_mask"); + SETTER(std::string const&, _set_retained_service_attribute_mask, + "retained_service_attribute_mask"); + SETTER(bool, retain_state_information, "retain_state_information"); + SETTER(unsigned int, retention_scheduling_horizon, + "retention_scheduling_horizon"); + SETTER(unsigned int, retention_update_interval, "retention_update_interval"); + SETTER(unsigned int, service_check_timeout, "service_check_timeout"); + SETTER(unsigned int, service_freshness_check_interval, + "service_freshness_check_interval"); + SETTER(std::string const&, _set_service_inter_check_delay_method, + "service_inter_check_delay_method"); + SETTER(std::string const&, _set_service_interleave_factor_method, + "service_interleave_factor"); + SETTER(std::string const&, service_perfdata_command, + "service_perfdata_command"); + SETTER(std::string const&, service_perfdata_file, "service_perfdata_file"); + SETTER(std::string const&, _set_service_perfdata_file_mode, + "service_perfdata_file_mode"); + SETTER(std::string const&, service_perfdata_file_processing_command, + "service_perfdata_file_processing_command"); + SETTER(unsigned int, service_perfdata_file_processing_interval, + "service_perfdata_file_processing_interval"); + SETTER(std::string const&, service_perfdata_file_template, + "service_perfdata_file_template"); + SETTER(unsigned int, check_reaper_interval, "service_reaper_frequency"); + SETTER(float, sleep_time, "sleep_time"); + SETTER(bool, soft_state_dependencies, "soft_state_dependencies"); + SETTER(std::string const&, state_retention_file, "state_retention_file"); + SETTER(std::string const&, status_file, "status_file"); + SETTER(unsigned int, status_update_interval, "status_update_interval"); + SETTER(std::string const&, _set_temp_file, "temp_file"); + SETTER(std::string const&, _set_temp_path, "temp_path"); + SETTER(unsigned int, time_change_threshold, "time_change_threshold"); + SETTER(bool, use_aggressive_host_checking, "use_aggressive_host_checking"); + SETTER(bool, use_aggressive_host_checking, "use_agressive_host_checking"); + SETTER(std::string const&, _set_use_embedded_perl_implicitly, + "use_embedded_perl_implicitly"); + SETTER(bool, use_large_installation_tweaks, "use_large_installation_tweaks"); + SETTER(uint32_t, instance_heartbeat_interval, "instance_heartbeat_interval"); + SETTER(bool, use_regexp_matches, "use_regexp_matching"); + SETTER(bool, use_retained_program_state, "use_retained_program_state"); + SETTER(bool, use_retained_scheduling_info, "use_retained_scheduling_info"); + SETTER(bool, use_setpgid, "use_setpgid"); + SETTER(bool, use_syslog, "use_syslog"); + SETTER(bool, log_v2_enabled, "log_v2_enabled"); + SETTER(bool, log_legacy_enabled, "log_legacy_enabled"); + SETTER(std::string const&, log_v2_logger, "log_v2_logger"); + SETTER(std::string const&, log_level_functions, "log_level_functions"); + SETTER(std::string const&, log_level_config, "log_level_config"); + SETTER(std::string const&, log_level_events, "log_level_events"); + SETTER(std::string const&, log_level_checks, "log_level_checks"); + SETTER(std::string const&, log_level_notifications, + "log_level_notifications"); + SETTER(std::string const&, log_level_eventbroker, "log_level_eventbroker"); + SETTER(std::string const&, log_level_external_command, + "log_level_external_command"); + SETTER(std::string const&, log_level_commands, "log_level_commands"); + SETTER(std::string const&, log_level_downtimes, "log_level_downtimes"); + SETTER(std::string const&, log_level_comments, "log_level_comments"); + SETTER(std::string const&, log_level_macros, "log_level_macros"); + SETTER(std::string const&, log_level_process, "log_level_process"); + SETTER(std::string const&, log_level_runtime, "log_level_runtime"); + SETTER(std::string const&, use_timezone, "use_timezone"); + SETTER(bool, use_true_regexp_matching, "use_true_regexp_matching"); + SETTER(std::string const&, _set_comment_file, "xcddefault_comment_file"); + SETTER(std::string const&, _set_downtime_file, "xdddefault_downtime_file"); +} // Default values. static bool const default_accept_passive_host_checks(true); @@ -283,7 +402,7 @@ static int const default_command_check_interval(-1); static std::string const default_command_file(DEFAULT_COMMAND_FILE); static state::date_type const default_date_format(state::us); static std::string const default_debug_file(DEFAULT_DEBUG_FILE); -static unsigned long long const default_debug_level(0); +static uint64_t const default_debug_level(0); static unsigned int const default_debug_verbosity(1); static bool const default_enable_environment_macros(false); static bool const default_enable_event_handlers(true); @@ -532,7 +651,10 @@ state::state() _log_level_process(default_log_level_process), _log_level_runtime(default_log_level_runtime), _use_timezone(default_use_timezone), - _use_true_regexp_matching(default_use_true_regexp_matching) {} + _use_true_regexp_matching(default_use_true_regexp_matching) { + static absl::once_flag _init_call_once; + absl::call_once(_init_call_once, _init_setter); +} /** * Copy constructor. @@ -1644,7 +1766,7 @@ void state::debug_file(std::string const& value) { * * @return The debug_level value. */ -unsigned long long state::debug_level() const noexcept { +uint64_t state::debug_level() const noexcept { return _debug_level; } @@ -1653,9 +1775,9 @@ unsigned long long state::debug_level() const noexcept { * * @param[in] value The new debug_level value. */ -void state::debug_level(unsigned long long value) { +void state::debug_level(uint64_t value) { if (value == std::numeric_limits::max()) - _debug_level = static_cast(all); + _debug_level = static_cast(all); else _debug_level = value; } @@ -3555,10 +3677,9 @@ void state::status_update_interval(unsigned int value) { */ bool state::set(char const* key, char const* value) { try { - std::unordered_map::const_iterator it{ - _setters.find(key)}; + auto it = _setters.find(std::string_view(key)); if (it != _setters.end()) - return (it->second)(*this, value); + return (it->second)->apply_from_cfg(*this, value); } catch (std::exception const& e) { engine_logger(log_config_error, basic) << e.what(); log_v2::config()->error(e.what()); @@ -4319,7 +4440,8 @@ void state::_set_command_check_interval(std::string const& value) { _command_check_interval_is_seconds = true; val.erase(val.begin() + pos); } - setter::generic(*this, val.c_str()); + detail::setter("").apply_from_cfg( + *this, val.c_str()); } /** @@ -4411,8 +4533,8 @@ void state::_set_enable_failure_prediction(std::string const& value) { */ void state::_set_event_broker_options(std::string const& value) { if (value != "-1") - setter::generic(*this, - value.c_str()); + detail::setter("") + .apply_from_cfg(*this, value.c_str()); else { _event_broker_options = BROKER_EVERYTHING; } @@ -4762,3 +4884,25 @@ bool state::enable_macros_filter() const noexcept { void state::enable_macros_filter(bool value) { _enable_macros_filter = value; } + +/** + * @brief modify state according json passed in parameter + * + * @param file_path + * @param json_doc + */ +void state::apply_extended_conf(const std::string& file_path, + const nlohmann::json& json_doc) { + SPDLOG_LOGGER_INFO(log_v2::config(), "apply conf from file {}", file_path); + for (const auto& member : json_doc.items()) { + auto setter = _setters.find(member.key()); + if (setter == _setters.end()) { + SPDLOG_LOGGER_ERROR(log_v2::config(), "unknown field: {} in file {}", + member.key(), file_path); + } else if (!setter->second->apply_from_json(*this, json_doc)) { + SPDLOG_LOGGER_ERROR(log_v2::config(), + "fail to update field: {} from file {}", + member.key(), file_path); + } + } +} diff --git a/engine/src/events/loop.cc b/engine/src/events/loop.cc index adba45ebd71..025d16595fe 100644 --- a/engine/src/events/loop.cc +++ b/engine/src/events/loop.cc @@ -1,24 +1,24 @@ -/* -** Copyright 1999-2009 Ethan Galstad -** Copyright 2009-2010 Nagios Core Development Team and Community Contributors -** Copyright 2011-2013 Merethis -** Copyright 2013-2022 Centreon -** -** This file is part of Centreon Engine. -** -** Centreon Engine is free software: you can redistribute it and/or -** modify it under the terms of the GNU General Public License version 2 -** as published by the Free Software Foundation. -** -** Centreon Engine 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 Centreon Engine. If not, see -** . -*/ +/** + * Copyright 1999-2009 Ethan Galstad + * Copyright 2009-2010 Nagios Core Development Team and Community Contributors + * Copyright 2011-2013 Merethis + * Copyright 2013-2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine 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 Centreon Engine. If not, see + * . + */ #include "com/centreon/engine/events/loop.hh" #include @@ -27,6 +27,7 @@ #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/command_manager.hh" #include "com/centreon/engine/configuration/applier/state.hh" +#include "com/centreon/engine/configuration/extended_conf.hh" #include "com/centreon/engine/configuration/parser.hh" #include "com/centreon/engine/globals.hh" #include "com/centreon/engine/log_v2.hh" @@ -101,6 +102,7 @@ static void apply_conf(std::atomic* reloading) { std::string path(::config->cfg_main()); p.parse(path, config); } + configuration::extended_conf::update_state(config); configuration::applier::state::instance().apply(config); engine_logger(log_info_message, basic) << "Configuration reloaded, main loop continuing."; diff --git a/engine/src/main.cc b/engine/src/main.cc index fc40d4db300..3a0e29aa45f 100644 --- a/engine/src/main.cc +++ b/engine/src/main.cc @@ -1,23 +1,23 @@ -/* -** Copyright 1999-2009 Ethan Galstad -** Copyright 2009-2010 Nagios Core Development Team and Community Contributors -** Copyright 2011-2021 Centreon -** -** This file is part of Centreon Engine. -** -** Centreon Engine is free software: you can redistribute it and/or -** modify it under the terms of the GNU General Public License version 2 -** as published by the Free Software Foundation. -** -** Centreon Engine 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 Centreon Engine. If not, see -** . -*/ +/** + * Copyright 1999-2009 Ethan Galstad + * Copyright 2009-2010 Nagios Core Development Team and Community Contributors + * Copyright 2011-2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine 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 Centreon Engine. If not, see + * . + */ #ifdef HAVE_GETOPT_H #include @@ -40,6 +40,7 @@ #include "com/centreon/engine/config.hh" #include "com/centreon/engine/configuration/applier/logging.hh" #include "com/centreon/engine/configuration/applier/state.hh" +#include "com/centreon/engine/configuration/extended_conf.hh" #include "com/centreon/engine/configuration/parser.hh" #include "com/centreon/engine/configuration/state.hh" #include "com/centreon/engine/diagnostic.hh" @@ -94,14 +95,15 @@ int main(int argc, char* argv[]) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option const long_options[] = { - {"diagnose", no_argument, NULL, 'D'}, - {"dont-verify-paths", no_argument, NULL, 'x'}, - {"help", no_argument, NULL, 'h'}, - {"license", no_argument, NULL, 'V'}, - {"test-scheduling", no_argument, NULL, 's'}, - {"verify-config", no_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, - {NULL, no_argument, NULL, '\0'}}; + {"diagnose", no_argument, nullptr, 'D'}, + {"dont-verify-paths", no_argument, nullptr, 'x'}, + {"help", no_argument, nullptr, 'h'}, + {"license", no_argument, nullptr, 'V'}, + {"test-scheduling", no_argument, nullptr, 's'}, + {"verify-config", no_argument, nullptr, 'v'}, + {"version", no_argument, nullptr, 'V'}, + {"config-file", optional_argument, nullptr, 'c'}, + {NULL, no_argument, nullptr, '\0'}}; #endif // HAVE_GETOPT_H // Load singletons and global variable. @@ -120,11 +122,12 @@ int main(int argc, char* argv[]) { bool display_license(false); bool error(false); bool diagnose(false); + std::vector extended_conf_file; // Process all command line arguments. int c; #ifdef HAVE_GETOPT_H - while ((c = getopt_long(argc, argv, "+hVvsxD", long_options, + while ((c = getopt_long(argc, argv, "+hVvsxDc", long_options, &option_index)) != -1) { #else while ((c = getopt(argc, argv, "+hVvsxD")) != -1) { @@ -151,6 +154,10 @@ int main(int argc, char* argv[]) { case 'D': // Diagnostic. diagnose = true; break; + case 'c': + if (optarg) + extended_conf_file.push_back(optarg); + break; default: error = true; } @@ -348,6 +355,10 @@ int main(int argc, char* argv[]) { p.parse(config_file, config); } + configuration::extended_conf::load_all(extended_conf_file.begin(), + extended_conf_file.end()); + + configuration::extended_conf::update_state(config); uint16_t port = config.rpc_port(); if (!port) { diff --git a/engine/tests/configuration/applier/applier-state.cc b/engine/tests/configuration/applier/applier-state.cc index 499e127ec2a..7d40edd2668 100644 --- a/engine/tests/configuration/applier/applier-state.cc +++ b/engine/tests/configuration/applier/applier-state.cc @@ -20,6 +20,7 @@ #include #include #include "com/centreon/engine/configuration/applier/state.hh" +#include "com/centreon/engine/configuration/extended_conf.hh" #include "com/centreon/engine/configuration/parser.hh" #include "com/centreon/engine/globals.hh" @@ -1017,3 +1018,52 @@ TEST_F(ApplierState, StateLegacyParsingHostdependencyWithoutHost) { CreateBadConf(ConfigurationObject::HOSTDEPENDENCY); ASSERT_THROW(p.parse("/tmp/centengine.cfg", config), std::exception); } + +TEST_F(ApplierState, extended_override_conf) { + configuration::state config; + configuration::parser p; + CreateConf(); + p.parse("/tmp/centengine.cfg", config); + + const char* file_paths[] = {"/tmp/extended_conf.json"}; + CreateFile(file_paths[0], + R"({"instance_heartbeat_interval":120, + "log_level_functions":"debug", + "log_level_checks":"trace", + "enable_flap_detection": true, + "rpc_port": 12345, + "high_service_flap_threshold": 45.789, + "event_handler_timeout":8945613, + "debug_level": 40000000000 +})"); + + configuration::extended_conf::load_all(file_paths, file_paths + 1); + configuration::extended_conf::update_state(config); + ASSERT_EQ(config.log_level_functions(), std::string("debug")); + ASSERT_EQ(config.log_level_checks(), std::string("trace")); + ASSERT_EQ(config.instance_heartbeat_interval(), 120); + ASSERT_EQ(config.enable_flap_detection(), true); + ASSERT_EQ(config.rpc_port(), 12345); + ASSERT_NEAR(config.high_service_flap_threshold(), 45.789, 0.001); + ASSERT_EQ(config.event_handler_timeout(), 8945613); + ASSERT_EQ(config.debug_level(), 40000000000); +} + +TEST_F(ApplierState, extended_override_conf_overflow) { + configuration::state config; + configuration::parser p; + CreateConf(); + p.parse("/tmp/centengine.cfg", config); + + const char* file_paths[] = {"/tmp/extended_conf.json"}; + CreateFile(file_paths[0], + R"({ + "enable_flap_detection": "etetge", + "rpc_port": 12345456 +})"); + + configuration::extended_conf::load_all(file_paths, file_paths + 1); + configuration::extended_conf::update_state(config); + ASSERT_EQ(config.enable_flap_detection(), false); + ASSERT_EQ(config.rpc_port(), 0); +} diff --git a/tests/engine/extended_conf.robot b/tests/engine/extended_conf.robot new file mode 100644 index 00000000000..12e45841a09 --- /dev/null +++ b/tests/engine/extended_conf.robot @@ -0,0 +1,62 @@ +*** Settings *** +Documentation Centreon Engine forced checks tests + +Resource ../resources/resources.robot +Library DateTime +Library ../resources/Broker.py +Library ../resources/Engine.py + +Suite Setup Ctn Clean Before Suite +Suite Teardown Ctn Clean After Suite +Test Setup Ctn Stop Processes +Test Teardown Run Keywords Ctn Stop engine AND Ctn Save Logs If Failed + + +*** Test Cases *** +EXT_CONF1 + [Documentation] Engine configuration is overided by json conf + [Tags] engine MON-71614 + Ctn Config Engine ${1} + Ctn Config Broker module ${1} + Create File /tmp/centengine_extend.json {"log_level_checks": "trace", "log_level_comments": "debug"} + ${start} Get Current Date + Start Process + ... /usr/sbin/centengine + ... --config-file\=/tmp/centengine_extend.json + ... ${EtcRoot}/centreon-engine/config0/centengine.cfg + ... alias=e0 + Ctn Wait For Engine To Be Ready ${start} ${1} + ${level} Ctn Get Engine Log Level 50001 checks + Should Be Equal ${level} trace log_level_checks must be the extended conf value + ${level} Ctn Get Engine Log Level 50001 comments + Should Be Equal ${level} debug log_level_comments must be the extended conf value + +EXT_CONF2 + [Documentation] Engine configuration is overided by json conf after reload + [Tags] engine MON-71614 + Ctn Config Engine ${1} + Ctn Config Broker module ${1} + Create File /tmp/centengine_extend.json {} + ${start} Get Current Date + Start Process + ... /usr/sbin/centengine + ... --config-file\=/tmp/centengine_extend.json + ... ${EtcRoot}/centreon-engine/config0/centengine.cfg + ... alias=e0 + Ctn Wait For Engine To Be Ready ${start} ${1} + Create File /tmp/centengine_extend.json {"log_level_checks": "trace", "log_level_comments": "debug"} + + ${start} Get Current Date + Send Signal To Process SIGHUP e0 + ${content} Create List Need reload. + ${result} Ctn Find In Log With Timeout + ... ${ENGINE_LOG}/config0/centengine.log + ... ${start} ${content} 60 + Should Be True + ... ${result} + ... A message telling Need reload. should be available in config0/centengine.log. + + ${level} Ctn Get Engine Log Level 50001 checks + Should Be Equal ${level} trace log_level_checks must be the extended conf value + ${level} Ctn Get Engine Log Level 50001 comments + Should Be Equal ${level} debug log_level_comments must be the extended conf value diff --git a/tests/resources/Engine.py b/tests/resources/Engine.py index d7d67d13f9d..4d2bb789166 100755 --- a/tests/resources/Engine.py +++ b/tests/resources/Engine.py @@ -1,5 +1,6 @@ import Common import grpc +from google.protobuf import empty_pb2 import engine_pb2 import engine_pb2_grpc from array import array @@ -3103,3 +3104,29 @@ def ctn_config_host_command_status(idx: int, cmd_name: str, status: int): with open(filename, "w") as f: f.writelines(lines) + +def ctn_get_engine_log_level(port, log, timeout=TIMEOUT): + """ + Get the log level of a given logger. The timeout is due to the way we ask + for this information ; we use gRPC and the server may not be correctly + started. + + Args: + port: The gRPC port to use. + log: The logger name. + + Returns: + A string with the log level. + """ + limit = time.time() + timeout + while time.time() < limit: + logger.console("Try to call GetLogInfo") + time.sleep(1) + with grpc.insecure_channel("127.0.0.1:{}".format(port)) as channel: + stub = engine_pb2_grpc.EngineStub(channel) + try: + logs = stub.GetLogInfo(empty_pb2.Empty()) + return logs.loggers[0].level[log] + except Exception as inst: + #except: + logger.console("gRPC server not ready") From b936addc461c6c54fb8f213f353e6af53fc5c332 Mon Sep 17 00:00:00 2001 From: jean-christophe81 <98889244+jean-christophe81@users.noreply.github.com> Date: Tue, 28 May 2024 16:28:18 +0200 Subject: [PATCH 05/11] enh(engine): Allow bypass the notification inhibitions for recovery notifications (#1260) (#1352) REFS: MON-74113 --- engine/doc/engine-doc.md | 28 +++++++++++++ .../centreon/engine/configuration/state.hh | 3 ++ engine/src/configuration/applier/state.cc | 2 + engine/src/configuration/state.cc | 42 ++++++++++++++++++- engine/src/main.cc | 4 +- engine/src/notifier.cc | 27 ++++++++---- tests/engine/extended_conf.robot | 12 +----- tests/resources/Engine.py | 32 ++++++++++++++ tests/resources/resources.robot | 21 ++++++++++ 9 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 engine/doc/engine-doc.md diff --git a/engine/doc/engine-doc.md b/engine/doc/engine-doc.md new file mode 100644 index 00000000000..c8fbeeba416 --- /dev/null +++ b/engine/doc/engine-doc.md @@ -0,0 +1,28 @@ +# Engine documentation {#mainpage} + +## Extended configuration +Users can pass an additional configuration file to engine. Gorgone is not aware of this file, so users can override centengine.cfg configuration. +Each entry found in additional json configuration file overrides its twin in `centengine.cfg`. + +### examples of command line +```sh +/usr/sbin/centengine --config-file=/tmp/centengine_extend.json /etc/centreon-engine/centengine.cfg + +/usr/sbin/centengine --c /tmp/file1.json --c /tmp/file2.json /etc/centreon-engine/centengine.cfg +``` + +In the second case, values of file1.json will override values of centengine.cfg and values of file2.json will override values of file1.json + +### file format +```json +{ + "send_recovery_notifications_anyways": true +} +``` + +### implementation detail +In `state.cc` all setters have two methods: +* `apply_from_cfg` +* `apply_from_json`. + +On configuration update, we first parse the `centengine.cfg` and all the `*.cfg` files, and then we parse additional configuration files. diff --git a/engine/inc/com/centreon/engine/configuration/state.hh b/engine/inc/com/centreon/engine/configuration/state.hh index 46df81da7f7..106b9f026ab 100644 --- a/engine/inc/com/centreon/engine/configuration/state.hh +++ b/engine/inc/com/centreon/engine/configuration/state.hh @@ -452,6 +452,8 @@ class state { void use_timezone(std::string const& value); bool use_true_regexp_matching() const noexcept; void use_true_regexp_matching(bool value); + bool use_send_recovery_notifications_anyways() const; + void use_send_recovery_notifications_anyways(bool value); using setter_map = absl::flat_hash_map>; @@ -655,6 +657,7 @@ class state { std::string _log_level_runtime; std::string _use_timezone; bool _use_true_regexp_matching; + bool _send_recovery_notifications_anyways; }; } // namespace com::centreon::engine::configuration diff --git a/engine/src/configuration/applier/state.cc b/engine/src/configuration/applier/state.cc index 5b004767b52..812266a8743 100644 --- a/engine/src/configuration/applier/state.cc +++ b/engine/src/configuration/applier/state.cc @@ -457,6 +457,8 @@ void applier::state::_apply(configuration::state const& new_cfg) { config->log_level_comments(new_cfg.log_level_comments()); config->log_level_macros(new_cfg.log_level_macros()); config->use_true_regexp_matching(new_cfg.use_true_regexp_matching()); + config->use_send_recovery_notifications_anyways( + new_cfg.use_send_recovery_notifications_anyways()); config->user(new_cfg.user()); // Set this variable just the first time. diff --git a/engine/src/configuration/state.cc b/engine/src/configuration/state.cc index 275a85c5f6a..cdd7f78709d 100644 --- a/engine/src/configuration/state.cc +++ b/engine/src/configuration/state.cc @@ -377,6 +377,8 @@ void state::_init_setter() { SETTER(bool, use_true_regexp_matching, "use_true_regexp_matching"); SETTER(std::string const&, _set_comment_file, "xcddefault_comment_file"); SETTER(std::string const&, _set_downtime_file, "xdddefault_downtime_file"); + SETTER(bool, use_send_recovery_notifications_anyways, + "send_recovery_notifications_anyways"); } // Default values. @@ -651,7 +653,8 @@ state::state() _log_level_process(default_log_level_process), _log_level_runtime(default_log_level_runtime), _use_timezone(default_use_timezone), - _use_true_regexp_matching(default_use_true_regexp_matching) { + _use_true_regexp_matching(default_use_true_regexp_matching), + _send_recovery_notifications_anyways(false) { static absl::once_flag _init_call_once; absl::call_once(_init_call_once, _init_setter); } @@ -834,6 +837,8 @@ state& state::operator=(state const& right) { _log_level_runtime = right._log_level_runtime; _use_timezone = right._use_timezone; _use_true_regexp_matching = right._use_true_regexp_matching; + _send_recovery_notifications_anyways = + right._send_recovery_notifications_anyways; } return *this; } @@ -998,7 +1003,9 @@ bool state::operator==(state const& right) const noexcept { _log_level_process == right._log_level_process && _log_level_runtime == right._log_level_runtime && _use_timezone == right._use_timezone && - _use_true_regexp_matching == right._use_true_regexp_matching); + _use_true_regexp_matching == right._use_true_regexp_matching && + _send_recovery_notifications_anyways == + right._send_recovery_notifications_anyways); } /** @@ -4885,6 +4892,37 @@ void state::enable_macros_filter(bool value) { _enable_macros_filter = value; } +/** + * @brief Get _send_recovery_notifications_anyways + * + * Having a resource that has entered a non-OK state during a notification + * period and goes back to an OK state out of a notification period, then only + * if send_recovery_notifications_anyways is set to 1, the recovery notification + * must be sent to all users that have previously received the alert + * notification. + * + * @return true + * @return false + */ +bool state::use_send_recovery_notifications_anyways() const { + return _send_recovery_notifications_anyways; +} + +/** + * @brief + * + * Having a resource that has entered a non-OK state during a notification + * period and goes back to an OK state out of a notification period, then only + * if send_recovery_notifications_anyways is set to 1, the recovery notification + * must be sent to all users that have previously received the alert + * notification. + * + * @param value true if have to nitify anyway + */ +void state::use_send_recovery_notifications_anyways(bool value) { + _send_recovery_notifications_anyways = value; +} + /** * @brief modify state according json passed in parameter * diff --git a/engine/src/main.cc b/engine/src/main.cc index 3a0e29aa45f..84545c5c0fd 100644 --- a/engine/src/main.cc +++ b/engine/src/main.cc @@ -26,9 +26,9 @@ #include #include -#include #include #include +#include #include #include @@ -156,7 +156,7 @@ int main(int argc, char* argv[]) { break; case 'c': if (optarg) - extended_conf_file.push_back(optarg); + extended_conf_file.emplace_back(optarg); break; default: error = true; diff --git a/engine/src/notifier.cc b/engine/src/notifier.cc index 2f99e7e06fa..e9303502d45 100644 --- a/engine/src/notifier.cc +++ b/engine/src/notifier.cc @@ -458,16 +458,27 @@ bool notifier::_is_notification_viable_recovery(reason_type type std::time_t now; std::time(&now); + // if use_send_recovery_notifications_anyways flag is set, we don't take + // timeperiod into account for recovery if (!check_time_against_period_for_notif(now, tp)) { - engine_logger(dbg_notifications, more) - << "This notifier shouldn't have notifications sent out " - "at this time."; - SPDLOG_LOGGER_DEBUG(log_v2::notifications(), - "This notifier shouldn't have notifications sent out " - "at this time."); - retval = false; - send_later = true; + if (config->use_send_recovery_notifications_anyways()) { + SPDLOG_LOGGER_DEBUG(log_v2::notifications(), + "send_recovery_notifications_anyways flag enabled, " + "recovery notification is viable even if we are " + "out of timeperiod at this time."); + } else { + engine_logger(dbg_notifications, more) + << "This notifier shouldn't have notifications sent out " + "at this time."; + SPDLOG_LOGGER_DEBUG( + log_v2::notifications(), + "This notifier shouldn't have notifications sent out " + "at this time."); + retval = false; + send_later = true; + } } + /* if this notifier is currently in a scheduled downtime period, don't send * the notification */ else if (is_in_downtime()) { diff --git a/tests/engine/extended_conf.robot b/tests/engine/extended_conf.robot index 12e45841a09..747faa13a6f 100644 --- a/tests/engine/extended_conf.robot +++ b/tests/engine/extended_conf.robot @@ -20,11 +20,7 @@ EXT_CONF1 Ctn Config Broker module ${1} Create File /tmp/centengine_extend.json {"log_level_checks": "trace", "log_level_comments": "debug"} ${start} Get Current Date - Start Process - ... /usr/sbin/centengine - ... --config-file\=/tmp/centengine_extend.json - ... ${EtcRoot}/centreon-engine/config0/centengine.cfg - ... alias=e0 + Ctn Start Engine With Extend Conf Ctn Wait For Engine To Be Ready ${start} ${1} ${level} Ctn Get Engine Log Level 50001 checks Should Be Equal ${level} trace log_level_checks must be the extended conf value @@ -38,11 +34,7 @@ EXT_CONF2 Ctn Config Broker module ${1} Create File /tmp/centengine_extend.json {} ${start} Get Current Date - Start Process - ... /usr/sbin/centengine - ... --config-file\=/tmp/centengine_extend.json - ... ${EtcRoot}/centreon-engine/config0/centengine.cfg - ... alias=e0 + Ctn Start Engine With Extend Conf Ctn Wait For Engine To Be Ready ${start} ${1} Create File /tmp/centengine_extend.json {"log_level_checks": "trace", "log_level_comments": "debug"} diff --git a/tests/resources/Engine.py b/tests/resources/Engine.py index 4d2bb789166..cdb92dea2af 100755 --- a/tests/resources/Engine.py +++ b/tests/resources/Engine.py @@ -4,6 +4,8 @@ import engine_pb2 import engine_pb2_grpc from array import array +from dateutil import parser +import datetime from os import makedirs, chmod from os.path import exists, dirname from xml.etree.ElementTree import Comment @@ -3130,3 +3132,33 @@ def ctn_get_engine_log_level(port, log, timeout=TIMEOUT): except Exception as inst: #except: logger.console("gRPC server not ready") + + + +def ctn_create_single_day_time_period(idx: int, time_period_name: str, date, minute_duration: int): + """ + Create a single day time period with a single time range from date to date + minute_duration + Args + idx: poller index + time_period_name: must be unique + date: time range start + minute_duration: time range length in minutes + """ + try: + my_date = parser.parse(date) + except: + my_date = datetime.fromtimestamp(date) + + filename = f"{ETC_ROOT}/centreon-engine/config{idx}/timeperiods.cfg" + + begin = my_date.time() + end = my_date + datetime.timedelta(minutes=minute_duration) + + with open(filename, "a+") as f: + f.write(f""" +define timeperiod {{ + timeperiod_name {time_period_name} + alias {time_period_name} + {my_date.date().isoformat()} {begin.strftime("%H:%M")}-{end.time().strftime("%H:%M")} +}} +""") diff --git a/tests/resources/resources.robot b/tests/resources/resources.robot index d51b50a8e96..739d5f2780d 100644 --- a/tests/resources/resources.robot +++ b/tests/resources/resources.robot @@ -142,6 +142,27 @@ Ctn Start Engine Start Process /usr/sbin/centengine ${conf} alias=${alias} END +Ctn Start Engine With Extend Conf + ${count} Ctn Get Engines Count + FOR ${idx} IN RANGE 0 ${count} + ${alias} Catenate SEPARATOR= e ${idx} + ${conf} Catenate SEPARATOR= ${EtcRoot} /centreon-engine/config ${idx} /centengine.cfg + ${log} Catenate SEPARATOR= ${VarRoot} /log/centreon-engine/config ${idx} + ${lib} Catenate SEPARATOR= ${VarRoot} /lib/centreon-engine/config ${idx} + Create Directory ${log} + Create Directory ${lib} + TRY + Remove File ${lib}/rw/centengine.cmd + EXCEPT + Log can't remove ${lib}/rw/centengine.cmd don't worry + END + Start Process + ... /usr/sbin/centengine + ... --config-file\=/tmp/centengine_extend.json + ... ${conf} + ... alias=${alias} + END + Ctn Restart Engine Ctn Stop Engine Ctn Start Engine From 9e5e96f7f2d2a9393e5f1be55d0fdbb329dda337 Mon Sep 17 00:00:00 2001 From: May <110405507+mushroomempires@users.noreply.github.com> Date: Thu, 30 May 2024 14:25:13 +0200 Subject: [PATCH 06/11] fix(ci): force ubuntu 22.04 usage in all (mostly veracode) pipelines (#1386) --- .github/workflows/veracode-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/veracode-analysis.yml b/.github/workflows/veracode-analysis.yml index 86c8f4cd936..9b7a18ff150 100644 --- a/.github/workflows/veracode-analysis.yml +++ b/.github/workflows/veracode-analysis.yml @@ -29,7 +29,7 @@ on: jobs: routing: name: Check before analysis - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: development_stage: ${{ steps.routing-mode.outputs.development_stage }} @@ -141,7 +141,7 @@ jobs: name: Sandbox scan needs: [routing, build] if: needs.routing.outputs.development_stage != 'Development' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Promote latest scan From 376a2537c4bb3d1f0f3545c5bced447072a03fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Chapron?= <34628915+sc979@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:25:03 +0200 Subject: [PATCH 07/11] fix(ci): force veracode action to 0.2.6 (#1403) --- .github/workflows/veracode-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/veracode-analysis.yml b/.github/workflows/veracode-analysis.yml index 9b7a18ff150..b2851b9d474 100644 --- a/.github/workflows/veracode-analysis.yml +++ b/.github/workflows/veracode-analysis.yml @@ -61,7 +61,7 @@ jobs: password: ${{ secrets.docker_registry_passwd }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Compiling Cpp sources run: | @@ -162,13 +162,13 @@ jobs: delete-on-promote: false - name: Get build binary - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: "${{ inputs.module_name }}-${{ github.sha }}-${{ github.run_id }}-veracode-binary.tar.gz" key: "${{ inputs.module_name }}-${{ github.sha }}-${{ github.run_id }}-veracode-binary" - name: Sandbox scan - uses: veracode/veracode-uploadandscan-action@0.2.6 + uses: veracode/veracode-uploadandscan-action@f7e1fbf02c5c899fba9f12e3f537b62f2f1230e1 # master using 0.2.6 continue-on-error: ${{ vars.VERACODE_CONTINUE_ON_ERROR == 'true' }} with: appname: "${{ inputs.module_name }}" From 8b29026f51a1bb37f6ffa973152790f89e88fea5 Mon Sep 17 00:00:00 2001 From: pkippes <144150042+pkippes@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:52:03 +0200 Subject: [PATCH 08/11] chore(release): bump collect to 23.04.13 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cafcea94b08..bc97382e572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ endif() # Version. set(COLLECT_MAJOR 23) set(COLLECT_MINOR 04) -set(COLLECT_PATCH 12) +set(COLLECT_PATCH 13) set(COLLECT_VERSION "${COLLECT_MAJOR}.${COLLECT_MINOR}.${COLLECT_PATCH}") add_definitions(-DCENTREON_CONNECTOR_VERSION=\"${COLLECT_VERSION}\") From 8cf07007ff93d8daa49f539bc09a3ba314338687 Mon Sep 17 00:00:00 2001 From: pkippes <144150042+pkippes@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:52:30 +0200 Subject: [PATCH 09/11] chore(release): bump collect to 23.04.13 --- .version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.version b/.version index 34efdaaa577..810960651fb 100644 --- a/.version +++ b/.version @@ -1,2 +1,2 @@ MAJOR=23.04 -MINOR=12 +MINOR=13 From 30d52528fdd7009c817e1b1efedf38ba79af23fe Mon Sep 17 00:00:00 2001 From: tuntoja <58987095+tuntoja@users.noreply.github.com> Date: Wed, 12 Jun 2024 08:39:39 +0200 Subject: [PATCH 10/11] fix(release): fix release action divergence (#1425) --- .github/actions/release/action.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index f527522462f..988f0208cfc 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -39,6 +39,10 @@ runs: SCOPE_VERSION="COLLECT" MINOR_VERSION_FILE_PATH=".version" RELEASE_CLOUD=0 + RELEASE_CLOUD=0 # (0 = not a release cloud, 1 = release cloud) + MAJOR_VERSION="" + MINOR_VERSION="" + CURRENT_STABLE_BRANCH_MAJOR_VERSION="" # Get current stable branch name # If MASTER, use root .version @@ -138,9 +142,9 @@ runs: fi # Rebuild NEW_STABLE_TAGS as an array - for i in ${NEW_STABLE_TAGS[@]}; do - NEW_RELEASE_TAGS+=("$i") - done + # for i in ${NEW_STABLE_TAGS[@]}; do + # NEW_RELEASE_TAGS+=("$i") + # done # Create GITHUB release for each release components # Abort if no tags @@ -200,7 +204,7 @@ runs: # Send to JIRA API release echo "Sending to JIRA API release: $JIRA_RELEASE_DATA" curl --fail --request POST \ - --url 'https://${{ inputs.jira_base_url }}/rest/api/3/version' \ + --url "${{ inputs.jira_base_url }}/rest/api/3/version" \ --user '${{ inputs.jira_user_email }}:${{ inputs.jira_api_token }}' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ From c63c536355abad4624d25fb13fa2c042ce625fdc Mon Sep 17 00:00:00 2001 From: tuntoja <58987095+tuntoja@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:18:01 +0200 Subject: [PATCH 11/11] fix(release): add release_id to data sent to JIRA release (#1450) (#1452) --- .github/actions/release/action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index 988f0208cfc..7b3f8cb2f0b 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -186,6 +186,7 @@ runs: JIRA_RELEASE_NAME="" JIRA_PROJECT_ID="${{ inputs.jira_project_id }}" JIRA_RELEASE_RELEASED="false" + JIRA_RELEASE_ID="$(git log |grep -E "^\s+Centreon.*#[0-9]{5,}#)" |grep -Eo "([0-9]{5,})" |head -n 1)" # Create JIRA version for each released component echo "Creating JIRA releases." @@ -195,7 +196,7 @@ runs: # Build JSON with release information for JIRA API JIRA_RELEASE_DATA=$(jq -nc \ --arg archived "$JIRA_RELEASE_ARCHIVED" \ - --arg description "$TAG" \ + --arg description "$JIRA_RELEASE_ID $TAG" \ --arg releaseDate "$JIRA_RELEASE_DATE" \ --arg name "$TAG" \ --arg projectId "$JIRA_PROJECT_ID" \