From af7c70b4329755913554bc96dd4f7a127e4210d8 Mon Sep 17 00:00:00 2001 From: Sechkem Date: Wed, 15 Jul 2026 16:33:43 +0100 Subject: [PATCH] fix(agent) : check file rebuild map every time. (#3560) * fix(agent) : check file rebuild map every time REFS: MON-202359 --- agent/native_windows/src/check_files.cc | 15 ++++- agent/test/check_windows_files_test.cc | 79 +++++++++++++++++++++++++ centreon_cmake.bat | 39 ++++++++---- 3 files changed, 120 insertions(+), 13 deletions(-) diff --git a/agent/native_windows/src/check_files.cc b/agent/native_windows/src/check_files.cc index 2abb341342c..fc8deb8dc0d 100644 --- a/agent/native_windows/src/check_files.cc +++ b/agent/native_windows/src/check_files.cc @@ -352,7 +352,12 @@ void ::check_files_detail::filter::find_files() { fs::path search_path(_root_path); + // rebuild the map on each scan + absl::flat_hash_map> + new_files_metadata; + if (!fs::exists(search_path) || !fs::is_directory(search_path)) { + _files_metadata = std::move(new_files_metadata); return; } @@ -378,7 +383,13 @@ void ::check_files_detail::filter::find_files() { if (_file_filter && !_file_filter->check(*metadata)) { continue; // skip to next if the data don't match the filter } - _files_metadata[std::move(path_str)] = std::move(metadata); + new_files_metadata[std::move(path_str)] = std::move(metadata); + } else { + // File unchanged since the previous scan: reuse. + auto previous = _files_metadata.find(path_str); + if (previous != _files_metadata.end()) { + new_files_metadata[path_str] = std::move(previous->second); + } } } } @@ -386,6 +397,8 @@ void ::check_files_detail::filter::find_files() { continue; // Skip files that cannot be accessed or processed } } + + _files_metadata = std::move(new_files_metadata); } /********************************************************************************************* * check_files_thread diff --git a/agent/test/check_windows_files_test.cc b/agent/test/check_windows_files_test.cc index cc84ce5952a..0948923f872 100644 --- a/agent/test/check_windows_files_test.cc +++ b/agent/test/check_windows_files_test.cc @@ -746,4 +746,83 @@ TEST_F(check_files_test, two_checks_same_path) { // check if a change of lines is detected ASSERT_EQ(number_lines + 20, new_number_lines); +} + +// the status must be re-evaluated on every check. +// A "critical-status": "count > 0" check must go CRITICAL when a matching file +// appears and go back to OK once that file is removed. Before the fix the +// filter metadata map was never cleared, so a deleted file lingered and the +// check stayed CRITICAL forever. +TEST_F(check_files_test, status_updates_when_file_added_and_removed) { + namespace fs = std::filesystem; + + fs::path dir = fs::temp_directory_path() / "check_files_add_remove_fixture"; + fs::remove_all(dir); + fs::create_directories(dir); + fs::path watched = dir / "test.txt"; + + std::string json_str = fmt::format(R"cfg({{ + "path": "{}", + "max-depth": 0, + "pattern": "test.txt", + "critical-status": "count > 0", + "output-syntax": "${{status}}: ${{problem_count}}/${{count}} files (${{problem_list}})", + "ok-syntax": "${{status}}: ${{ok_count}} files found", + "verbose": false + }})cfg", + dir.generic_string()); + + std::cout << "JSON String: " << json_str << std::endl; + rapidjson::Document check_args; + check_args.Parse(json_str.c_str()); + + absl::Mutex wait_m; + std::string output; + int status = -1; + bool complete = false; + + auto is_complete = [&]() { return complete; }; + + auto checker = std::make_shared( + g_io_context, spdlog::default_logger(), std::chrono::system_clock::now(), + serv, check_args, nullptr, + [&]([[maybe_unused]] const std::shared_ptr& caller, int st, + [[maybe_unused]] const std::list& + perfdata, + const std::list& outputs) { + absl::MutexLock lck(wait_m); + complete = true; + status = st; + output = outputs.front(); + }, + std::make_shared()); + + auto run_one_check = [&]() { + { + absl::MutexLock lk(&wait_m); + complete = false; + } + checker->start_check(std::chrono::seconds(20)); + absl::MutexLock lk(&wait_m); + wait_m.Await(absl::Condition(&is_complete)); + }; + + // 1) no matching file yet -> OK + run_one_check(); + EXPECT_EQ(status, e_status::ok) + << "expected OK when no file is present, got: " << output; + + // 2) create the file -> count > 0 -> CRITICAL + { std::ofstream(watched) << "hello\n"; } + run_one_check(); + EXPECT_EQ(status, e_status::critical) + << "expected CRITICAL once the file exists, got: " << output; + + // 3) remove the file -> status must return to OK + fs::remove(watched); + run_one_check(); + EXPECT_EQ(status, e_status::ok) + << "expected OK after the file is removed, got: " << output; + + fs::remove_all(dir); } \ No newline at end of file diff --git a/centreon_cmake.bat b/centreon_cmake.bat index 07bb3e28e38..98a471b6c8f 100644 --- a/centreon_cmake.bat +++ b/centreon_cmake.bat @@ -27,20 +27,35 @@ IF ERRORLEVEL 1 ( exit /B ) -if not defined VCPKG_ROOT ( - echo "install vcpkg" - set "current_dir=%cd%" - cd /D %USERPROFILE% - git clone https://github.com/microsoft/vcpkg.git - cd vcpkg && bootstrap-vcpkg.bat - cd /D %current_dir% - set "VCPKG_ROOT=%USERPROFILE%\vcpkg" - set "PATH=%VCPKG_ROOT%;%PATH%" - echo "Please add this variables to environment for future compile:" - echo "VCPKG_ROOT=%USERPROFILE%\vcpkg" - echo "PATH=%VCPKG_ROOT%;%PATH%" +:: Use a vcpkg clone local to this repository (like CI does), pinned to the +:: same commit as the builtin-baseline CI injects in +:: .github\scripts\windows-agent-compile.ps1. vcpkg.json has no +:: builtin-baseline (Linux CI resolves a different one), so dependency +:: versions come from whatever VCPKG_ROOT has checked out: if that clone +:: moves, every port's ABI hash changes, the local binary cache misses and +:: grpc/abseil/boost rebuild from source. Pinning the checkout keeps builds +:: reproducible and fast. +set "vcpkg_commit=d015e31e90838a4c9dfa3eed45979bc70d9357fc" +set "VCPKG_ROOT=%~dp0vcpkg" + +if not exist "%VCPKG_ROOT%\.git" ( + echo install vcpkg in %VCPKG_ROOT% + git clone https://github.com/microsoft/vcpkg.git "%VCPKG_ROOT%" ) +for /f %%i in ('git -C "%VCPKG_ROOT%" rev-parse HEAD') do set "vcpkg_head=%%i" +if not "%vcpkg_head%" == "%vcpkg_commit%" ( + echo pinning vcpkg to commit %vcpkg_commit% + git -C "%VCPKG_ROOT%" fetch origin + git -C "%VCPKG_ROOT%" checkout %vcpkg_commit% + call "%VCPKG_ROOT%\bootstrap-vcpkg.bat" +) + +if not exist "%VCPKG_ROOT%\vcpkg.exe" ( + call "%VCPKG_ROOT%\bootstrap-vcpkg.bat" +) + +set "PATH=%VCPKG_ROOT%;%PATH%" cmake.exe --preset=%build_type%