mirror of https://github.com/Icinga/icinga2.git
parent
3a1ce23aeb
commit
d587c962ce
|
@ -93,7 +93,8 @@ static bool LoadConfigFiles(const String& appType)
|
|||
|
||||
String zonesDir = Application::GetZonesDir();
|
||||
|
||||
Utility::Glob(Application::GetZonesDir() + "/*", &IncludeZoneDirRecursive, GlobDirectory);
|
||||
if (!zonesDir.IsEmpty())
|
||||
Utility::Glob(Application::GetZonesDir() + "/*", &IncludeZoneDirRecursive, GlobDirectory);
|
||||
Utility::Glob(Application::GetLocalStateDir() + "/lib/icinga2/api/zones/*", &IncludeNonLocalZone, GlobDirectory);
|
||||
|
||||
/* Load cluster config files - this should probably be in libremote but
|
||||
|
|
|
@ -129,7 +129,7 @@ Value ApiEvents::CheckResultAPIHandler(const MessageOrigin& origin, const Dictio
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->ProcessCheckResult(cr, origin);
|
||||
|
@ -182,7 +182,7 @@ Value ApiEvents::NextCheckChangedAPIHandler(const MessageOrigin& origin, const D
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetNextCheck(params->Get("next_check"), origin);
|
||||
|
@ -219,7 +219,7 @@ Value ApiEvents::NextNotificationChangedAPIHandler(const MessageOrigin& origin,
|
|||
if (!notification)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(notification))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(notification))
|
||||
return Empty;
|
||||
|
||||
notification->SetNextNotification(params->Get("next_notification"), origin);
|
||||
|
@ -272,7 +272,7 @@ Value ApiEvents::ForceNextCheckChangedAPIHandler(const MessageOrigin& origin, co
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetForceNextCheck(params->Get("forced"), origin);
|
||||
|
@ -325,7 +325,7 @@ Value ApiEvents::ForceNextNotificationChangedAPIHandler(const MessageOrigin& ori
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetForceNextNotification(params->Get("forced"), origin);
|
||||
|
@ -378,7 +378,7 @@ Value ApiEvents::EnableActiveChecksChangedAPIHandler(const MessageOrigin& origin
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableActiveChecks(params->Get("enabled"), origin);
|
||||
|
@ -431,7 +431,7 @@ Value ApiEvents::EnablePassiveChecksChangedAPIHandler(const MessageOrigin& origi
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnablePassiveChecks(params->Get("enabled"), origin);
|
||||
|
@ -484,7 +484,7 @@ Value ApiEvents::EnableNotificationsChangedAPIHandler(const MessageOrigin& origi
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableNotifications(params->Get("enabled"), origin);
|
||||
|
@ -537,7 +537,7 @@ Value ApiEvents::EnableFlappingChangedAPIHandler(const MessageOrigin& origin, co
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->SetEnableFlapping(params->Get("enabled"), origin);
|
||||
|
@ -590,7 +590,7 @@ Value ApiEvents::CommentAddedAPIHandler(const MessageOrigin& origin, const Dicti
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
Comment::Ptr comment = Deserialize(params->Get("comment"), true);
|
||||
|
@ -646,7 +646,7 @@ Value ApiEvents::CommentRemovedAPIHandler(const MessageOrigin& origin, const Dic
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->RemoveComment(params->Get("id"), origin);
|
||||
|
@ -699,7 +699,7 @@ Value ApiEvents::DowntimeAddedAPIHandler(const MessageOrigin& origin, const Dict
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
Downtime::Ptr downtime = Deserialize(params->Get("downtime"), true);
|
||||
|
@ -758,7 +758,7 @@ Value ApiEvents::DowntimeRemovedAPIHandler(const MessageOrigin& origin, const Di
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->RemoveDowntime(params->Get("id"), false, origin);
|
||||
|
@ -816,7 +816,7 @@ Value ApiEvents::AcknowledgementSetAPIHandler(const MessageOrigin& origin, const
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->AcknowledgeProblem(params->Get("author"), params->Get("comment"),
|
||||
|
@ -870,7 +870,7 @@ Value ApiEvents::AcknowledgementClearedAPIHandler(const MessageOrigin& origin, c
|
|||
if (!checkable)
|
||||
return Empty;
|
||||
|
||||
if (origin.FromZone && !origin.FromZone->CanAccessObject(checkable))
|
||||
if (!origin.FromZone || !origin.FromZone->CanAccessObject(checkable))
|
||||
return Empty;
|
||||
|
||||
checkable->ClearAcknowledgement(origin);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
******************************************************************************/
|
||||
|
||||
#include "remote/apilistener.h"
|
||||
#include "remote/apifunction.h"
|
||||
#include "base/dynamictype.h"
|
||||
#include "base/logger_fwd.h"
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -25,6 +26,8 @@
|
|||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler);
|
||||
|
||||
bool ApiListener::IsConfigMaster(const Zone::Ptr& zone) const
|
||||
{
|
||||
String path = Application::GetZonesDir() + "/" + zone->GetName();
|
||||
|
@ -43,33 +46,23 @@ void ApiListener::ConfigGlobHandler(const Dictionary::Ptr& config, const String&
|
|||
config->Set(file.SubStr(path.GetLength()), content);
|
||||
}
|
||||
|
||||
void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
|
||||
Dictionary::Ptr ApiListener::LoadConfigDir(const String& dir)
|
||||
{
|
||||
Log(LogInformation, "remote", "Syncing zone: " + zone->GetName());
|
||||
Dictionary::Ptr config = make_shared<Dictionary>();
|
||||
Utility::GlobRecursive(dir, "*.conf", boost::bind(&ApiListener::ConfigGlobHandler, config, dir, _1), GlobFile);
|
||||
return config;
|
||||
}
|
||||
|
||||
String dirNew = Application::GetZonesDir() + "/" + zone->GetName();
|
||||
String dirOld = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
|
||||
bool ApiListener::UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir)
|
||||
{
|
||||
bool configChange = false;
|
||||
|
||||
#ifndef _WIN32
|
||||
if (mkdir(dirOld.CStr(), 0700) < 0 && errno != EEXIST) {
|
||||
#else /*_ WIN32 */
|
||||
if (mkdir(dirOld.CStr()) < 0 && errno != EEXIST) {
|
||||
#endif /* _WIN32 */
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("mkdir")
|
||||
<< boost::errinfo_errno(errno)
|
||||
<< boost::errinfo_file_name(dirOld));
|
||||
}
|
||||
|
||||
Dictionary::Ptr configNew = make_shared<Dictionary>();
|
||||
Utility::GlobRecursive(dirNew, "*.conf", boost::bind(&ApiListener::ConfigGlobHandler, configNew, dirNew, _1), GlobFile);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, newConfig) {
|
||||
if (oldConfig->Get(kv.first) != kv.second) {
|
||||
configChange = true;
|
||||
|
||||
Dictionary::Ptr configOld = make_shared<Dictionary>();
|
||||
Utility::GlobRecursive(dirOld, "*.conf", boost::bind(&ApiListener::ConfigGlobHandler, configOld, dirOld, _1), GlobFile);
|
||||
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, configNew) {
|
||||
if (configOld->Get(kv.first) != kv.second) {
|
||||
String path = dirOld + "/" + kv.first;
|
||||
String path = configDir + "/" + kv.first;
|
||||
Log(LogInformation, "remote", "Updating configuration file: " + path);
|
||||
|
||||
std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||
|
@ -78,12 +71,40 @@ void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, configOld) {
|
||||
if (!configNew->Contains(kv.first)) {
|
||||
String path = dirOld + "/" + kv.first;
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, oldConfig) {
|
||||
if (!newConfig->Contains(kv.first)) {
|
||||
configChange = true;
|
||||
|
||||
String path = configDir + "/" + kv.first;
|
||||
(void) unlink(path.CStr());
|
||||
}
|
||||
}
|
||||
|
||||
return configChange;
|
||||
}
|
||||
|
||||
void ApiListener::SyncZoneDir(const Zone::Ptr& zone) const
|
||||
{
|
||||
Log(LogInformation, "remote", "Syncing zone: " + zone->GetName());
|
||||
|
||||
String newDir = Application::GetZonesDir() + "/" + zone->GetName();
|
||||
String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
|
||||
|
||||
#ifndef _WIN32
|
||||
if (mkdir(oldDir.CStr(), 0700) < 0 && errno != EEXIST) {
|
||||
#else /*_ WIN32 */
|
||||
if (mkdir(oldDir.CStr()) < 0 && errno != EEXIST) {
|
||||
#endif /* _WIN32 */
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("mkdir")
|
||||
<< boost::errinfo_errno(errno)
|
||||
<< boost::errinfo_file_name(oldDir));
|
||||
}
|
||||
|
||||
Dictionary::Ptr newConfig = LoadConfigDir(newDir);
|
||||
Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
|
||||
|
||||
UpdateConfigDir(oldConfig, newConfig, oldDir);
|
||||
}
|
||||
|
||||
void ApiListener::SyncZoneDirs(void) const
|
||||
|
@ -94,13 +115,85 @@ void ApiListener::SyncZoneDirs(void) const
|
|||
|
||||
SyncZoneDir(zone);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiListener::SendConfigUpdate(const ApiClient::Ptr& aclient)
|
||||
{
|
||||
Endpoint::Ptr endpoint = aclient->GetEndpoint();
|
||||
ASSERT(endpoint);
|
||||
|
||||
Zone::Ptr azone = endpoint->GetZone();
|
||||
Zone::Ptr lzone = Zone::GetLocalZone();
|
||||
|
||||
/* don't try to send config updates to our master */
|
||||
if (lzone->IsChildOf(azone))
|
||||
return;
|
||||
|
||||
Dictionary::Ptr configUpdate = make_shared<Dictionary>();
|
||||
|
||||
String zonesDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones";
|
||||
|
||||
BOOST_FOREACH(const Zone::Ptr& zone, DynamicType::GetObjects<Zone>()) {
|
||||
String zoneDir = zonesDir + "/" + zone->GetName();
|
||||
|
||||
if (!zone->IsChildOf(azone) || !Utility::PathExists(zoneDir))
|
||||
continue;
|
||||
|
||||
configUpdate->Set(zone->GetName(), LoadConfigDir(zonesDir + "/" + zone->GetName()));
|
||||
}
|
||||
|
||||
Dictionary::Ptr params = make_shared<Dictionary>();
|
||||
params->Set("update", configUpdate);
|
||||
|
||||
Dictionary::Ptr message = make_shared<Dictionary>();
|
||||
message->Set("jsonrpc", "2.0");
|
||||
message->Set("method", "config::Update");
|
||||
message->Set("params", params);
|
||||
|
||||
aclient->SendMessage(message);
|
||||
}
|
||||
|
||||
Value ApiListener::ConfigUpdateHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||
{
|
||||
if (!origin.FromZone || !Zone::GetLocalZone()->IsChildOf(origin.FromZone))
|
||||
return Empty;
|
||||
|
||||
Dictionary::Ptr update = params->Get("update");
|
||||
|
||||
bool configChange = false;
|
||||
|
||||
// TODO: remove configuration files for zones which don't exist anymore (i.e. don't have a Zone object)
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, update) {
|
||||
Zone::Ptr zone = Zone::GetByName(kv.first);
|
||||
|
||||
if (!zone) {
|
||||
Log(LogWarning, "remote", "Ignoring config update for unknown zone: " + kv.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
String oldDir = Application::GetLocalStateDir() + "/lib/icinga2/api/zones/" + zone->GetName();
|
||||
|
||||
#ifndef _WIN32
|
||||
if (mkdir(oldDir.CStr(), 0700) < 0 && errno != EEXIST) {
|
||||
#else /*_ WIN32 */
|
||||
if (mkdir(oldDir.CStr()) < 0 && errno != EEXIST) {
|
||||
#endif /* _WIN32 */
|
||||
BOOST_THROW_EXCEPTION(posix_error()
|
||||
<< boost::errinfo_api_function("mkdir")
|
||||
<< boost::errinfo_errno(errno)
|
||||
<< boost::errinfo_file_name(oldDir));
|
||||
}
|
||||
|
||||
Dictionary::Ptr newConfig = kv.second;
|
||||
Dictionary::Ptr oldConfig = LoadConfigDir(oldDir);
|
||||
|
||||
if (UpdateConfigDir(oldConfig, newConfig, oldDir))
|
||||
configChange = true;
|
||||
}
|
||||
|
||||
if (configChange) {
|
||||
Log(LogInformation, "remote", "Restarting after configuration change.");
|
||||
Application::RequestRestart();
|
||||
}
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
|
|
@ -223,6 +223,8 @@ void ApiListener::NewClientHandler(const Socket::Ptr& client, ConnectionRole rol
|
|||
ReplayLog(aclient);
|
||||
}
|
||||
|
||||
SendConfigUpdate(aclient);
|
||||
|
||||
endpoint->AddClient(aclient);
|
||||
} else
|
||||
AddAnonymousClient(aclient);
|
||||
|
|
|
@ -65,6 +65,8 @@ public:
|
|||
void RemoveAnonymousClient(const ApiClient::Ptr& aclient);
|
||||
std::set<ApiClient::Ptr> GetAnonymousClients(void) const;
|
||||
|
||||
static Value ConfigUpdateHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||
|
||||
protected:
|
||||
virtual void OnConfigLoaded(void);
|
||||
virtual void Start(void);
|
||||
|
@ -101,11 +103,13 @@ private:
|
|||
static void LogGlobHandler(std::vector<int>& files, const String& file);
|
||||
void ReplayLog(const ApiClient::Ptr& client);
|
||||
|
||||
static Dictionary::Ptr LoadConfigDir(const String& dir);
|
||||
static bool UpdateConfigDir(const Dictionary::Ptr& oldConfig, const Dictionary::Ptr& newConfig, const String& configDir);
|
||||
void SyncZoneDirs(void) const;
|
||||
void SyncZoneDir(const Zone::Ptr& zone) const;
|
||||
bool IsConfigMaster(const Zone::Ptr& zone) const;
|
||||
static void ConfigGlobHandler(const Dictionary::Ptr& config, const String& path, const String& file);
|
||||
|
||||
void SendConfigUpdate(const ApiClient::Ptr& aclient);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ std::set<Endpoint::Ptr> Zone::GetEndpoints(void) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Zone::CanAccessObject(const DynamicObject::Ptr& object) const
|
||||
bool Zone::CanAccessObject(const DynamicObject::Ptr& object)
|
||||
{
|
||||
Zone::Ptr object_zone;
|
||||
|
||||
|
@ -51,11 +51,18 @@ bool Zone::CanAccessObject(const DynamicObject::Ptr& object) const
|
|||
if (!object_zone)
|
||||
object_zone = Zone::GetLocalZone();
|
||||
|
||||
while (object_zone) {
|
||||
if (object_zone.get() == this)
|
||||
return object_zone->IsChildOf(GetSelf());
|
||||
}
|
||||
|
||||
bool Zone::IsChildOf(const Zone::Ptr& zone)
|
||||
{
|
||||
Zone::Ptr azone = GetSelf();
|
||||
|
||||
while (azone) {
|
||||
if (azone == zone)
|
||||
return true;
|
||||
|
||||
object_zone = object_zone->GetParent();
|
||||
azone = azone->GetParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -39,7 +39,8 @@ public:
|
|||
Zone::Ptr GetParent(void) const;
|
||||
std::set<Endpoint::Ptr> GetEndpoints(void) const;
|
||||
|
||||
bool CanAccessObject(const DynamicObject::Ptr& object) const;
|
||||
bool CanAccessObject(const DynamicObject::Ptr& object);
|
||||
bool IsChildOf(const Zone::Ptr& zone);
|
||||
|
||||
static Zone::Ptr GetLocalZone(void);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue