mirror of
https://github.com/Icinga/icinga2.git
synced 2025-08-17 15:48:17 +02:00
Once the new worker process has read the config, it also includes a `include */include.conf` statement within the config packages root directory, and from there on we must not allow to delete any stage directory from the config package. Otherwise, when the worker actually evaluates that include statement, it will fail to find the directory where the include file is located, or the `active.conf` file, which is included from each stage's `include.conf` file, thus causing the worker fail. Co-Authored-By: Johannes Schmidt <johannes.schmidt@icinga.com>
194 lines
5.3 KiB
C++
194 lines
5.3 KiB
C++
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
|
|
|
#include "remote/configpackageshandler.hpp"
|
|
#include "remote/configpackageutility.hpp"
|
|
#include "remote/configobjectslock.hpp"
|
|
#include "remote/httputility.hpp"
|
|
#include "remote/filterutility.hpp"
|
|
#include "base/exception.hpp"
|
|
|
|
using namespace icinga;
|
|
|
|
REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler);
|
|
|
|
bool ConfigPackagesHandler::HandleRequest(
|
|
const WaitGroup::Ptr&,
|
|
AsioTlsStream& stream,
|
|
const ApiUser::Ptr& user,
|
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
|
const Url::Ptr& url,
|
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
|
const Dictionary::Ptr& params,
|
|
boost::asio::yield_context& yc,
|
|
HttpServerConnection& server
|
|
)
|
|
{
|
|
namespace http = boost::beast::http;
|
|
|
|
if (url->GetPath().size() > 4)
|
|
return false;
|
|
|
|
if (request.method() == http::verb::get)
|
|
HandleGet(user, request, url, response, params);
|
|
else if (request.method() == http::verb::post)
|
|
HandlePost(user, request, url, response, params);
|
|
else if (request.method() == http::verb::delete_)
|
|
HandleDelete(user, request, url, response, params);
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ConfigPackagesHandler::HandleGet(
|
|
const ApiUser::Ptr& user,
|
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
|
const Url::Ptr& url,
|
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
|
const Dictionary::Ptr& params
|
|
)
|
|
{
|
|
namespace http = boost::beast::http;
|
|
|
|
FilterUtility::CheckPermission(user, "config/query");
|
|
|
|
std::vector<String> packages;
|
|
|
|
try {
|
|
packages = ConfigPackageUtility::GetPackages();
|
|
} catch (const std::exception& ex) {
|
|
HttpUtility::SendJsonError(response, params, 500, "Could not retrieve packages.",
|
|
DiagnosticInformation(ex));
|
|
return;
|
|
}
|
|
|
|
ArrayData results;
|
|
|
|
{
|
|
std::unique_lock<std::mutex> lock(ConfigPackageUtility::GetStaticPackageMutex());
|
|
|
|
for (const String& package : packages) {
|
|
String activeStage;
|
|
|
|
try {
|
|
activeStage = ConfigPackageUtility::GetActiveStage(package);
|
|
} catch (const std::exception&) { } /* Should never happen. */
|
|
|
|
results.emplace_back(new Dictionary({
|
|
{ "name", package },
|
|
{ "stages", Array::FromVector(ConfigPackageUtility::GetStages(package)) },
|
|
{ "active-stage", activeStage }
|
|
}));
|
|
}
|
|
}
|
|
|
|
Dictionary::Ptr result = new Dictionary({
|
|
{ "results", new Array(std::move(results)) }
|
|
});
|
|
|
|
response.result(http::status::ok);
|
|
HttpUtility::SendJsonBody(response, params, result);
|
|
}
|
|
|
|
void ConfigPackagesHandler::HandlePost(
|
|
const ApiUser::Ptr& user,
|
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
|
const Url::Ptr& url,
|
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
|
const Dictionary::Ptr& params
|
|
)
|
|
{
|
|
namespace http = boost::beast::http;
|
|
|
|
FilterUtility::CheckPermission(user, "config/modify");
|
|
|
|
if (url->GetPath().size() >= 4)
|
|
params->Set("package", url->GetPath()[3]);
|
|
|
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
|
|
|
if (!ConfigPackageUtility::ValidatePackageName(packageName)) {
|
|
HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
|
return;
|
|
}
|
|
|
|
ConfigObjectsSharedLock configObjectsSharedLock(std::try_to_lock);
|
|
if (!configObjectsSharedLock) {
|
|
HttpUtility::SendJsonError(response, params, 503, "Icinga is reloading");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
std::unique_lock<std::mutex> lock(ConfigPackageUtility::GetStaticPackageMutex());
|
|
|
|
ConfigPackageUtility::CreatePackage(packageName);
|
|
} catch (const std::exception& ex) {
|
|
HttpUtility::SendJsonError(response, params, 500, "Could not create package '" + packageName + "'.",
|
|
DiagnosticInformation(ex));
|
|
return;
|
|
}
|
|
|
|
Dictionary::Ptr result1 = new Dictionary({
|
|
{ "code", 200 },
|
|
{ "package", packageName },
|
|
{ "status", "Created package." }
|
|
});
|
|
|
|
Dictionary::Ptr result = new Dictionary({
|
|
{ "results", new Array({ result1 }) }
|
|
});
|
|
|
|
response.result(http::status::ok);
|
|
HttpUtility::SendJsonBody(response, params, result);
|
|
}
|
|
|
|
void ConfigPackagesHandler::HandleDelete(
|
|
const ApiUser::Ptr& user,
|
|
boost::beast::http::request<boost::beast::http::string_body>& request,
|
|
const Url::Ptr& url,
|
|
boost::beast::http::response<boost::beast::http::string_body>& response,
|
|
const Dictionary::Ptr& params
|
|
)
|
|
{
|
|
namespace http = boost::beast::http;
|
|
|
|
FilterUtility::CheckPermission(user, "config/modify");
|
|
|
|
if (url->GetPath().size() >= 4)
|
|
params->Set("package", url->GetPath()[3]);
|
|
|
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
|
|
|
if (!ConfigPackageUtility::ValidatePackageName(packageName)) {
|
|
HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
|
return;
|
|
}
|
|
|
|
ConfigObjectsSharedLock lock(std::try_to_lock);
|
|
if (!lock) {
|
|
HttpUtility::SendJsonError(response, params, 503, "Icinga is reloading");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
ConfigPackageUtility::DeletePackage(packageName);
|
|
} catch (const std::exception& ex) {
|
|
HttpUtility::SendJsonError(response, params, 500, "Failed to delete package '" + packageName + "'.",
|
|
DiagnosticInformation(ex));
|
|
return;
|
|
}
|
|
|
|
Dictionary::Ptr result1 = new Dictionary({
|
|
{ "code", 200 },
|
|
{ "package", packageName },
|
|
{ "status", "Deleted package." }
|
|
});
|
|
|
|
Dictionary::Ptr result = new Dictionary({
|
|
{ "results", new Array({ result1 }) }
|
|
});
|
|
|
|
response.result(http::status::ok);
|
|
HttpUtility::SendJsonBody(response, params, result);
|
|
}
|