From 0d4a68adc399dc20e4360a9037dfcf4f4b8df01f Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Mon, 7 Mar 2022 17:52:08 +0100 Subject: [PATCH] ConfigStagesHandler: Don't allow concurrent package updates anymore To prevent Icinga2 from being restarted while one or more requests are still in progress and end up as corrupted stages without status file and startup logs. --- lib/remote/configstageshandler.cpp | 12 +++++++++++- lib/remote/configstageshandler.hpp | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/remote/configstageshandler.cpp b/lib/remote/configstageshandler.cpp index a34e35cbc..ee8a6470b 100644 --- a/lib/remote/configstageshandler.cpp +++ b/lib/remote/configstageshandler.cpp @@ -5,12 +5,15 @@ #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/application.hpp" +#include "base/defer.hpp" #include "base/exception.hpp" using namespace icinga; REGISTER_URLHANDLER("/v1/config/stages", ConfigStagesHandler); +std::atomic ConfigStagesHandler::m_RunningPackageUpdates (false); + bool ConfigStagesHandler::HandleRequest( AsioTlsStream& stream, const ApiUser::Ptr& user, @@ -128,12 +131,19 @@ void ConfigStagesHandler::HandlePost( if (reload && !activate) BOOST_THROW_EXCEPTION(std::invalid_argument("Parameter 'reload' must be false when 'activate' is false.")); + if (m_RunningPackageUpdates.exchange(true)) { + return HttpUtility::SendJsonError(response, params, 423, + "Conflicting request, there is already an ongoing package update in progress. Please try it again later."); + } + + auto resetPackageUpdates (Shared::Make([]() { ConfigStagesHandler::m_RunningPackageUpdates.store(false); })); + boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticPackageMutex()); stageName = ConfigPackageUtility::CreateStage(packageName, files); /* validate the config. on success, activate stage and reload */ - ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName, activate, reload); + ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName, activate, reload, resetPackageUpdates); } catch (const std::exception& ex) { return HttpUtility::SendJsonError(response, params, 500, "Stage creation failed.", diff --git a/lib/remote/configstageshandler.hpp b/lib/remote/configstageshandler.hpp index c6d644366..88f248c8f 100644 --- a/lib/remote/configstageshandler.hpp +++ b/lib/remote/configstageshandler.hpp @@ -4,6 +4,7 @@ #define CONFIGSTAGESHANDLER_H #include "remote/httphandler.hpp" +#include namespace icinga { @@ -47,6 +48,7 @@ private: const Dictionary::Ptr& params ); + static std::atomic m_RunningPackageUpdates; }; }