dtype->RegisterObject(this);
}
+void DynamicObject::Unregister(void)
+{
+ ASSERT(!OwnsLock());
+
+ DynamicType::Ptr dtype = GetType();
+ dtype->UnregisterObject(this);
+}
+
void DynamicObject::Start(void)
{
ASSERT(!OwnsLock());
bool IsAttributeModified(const String& attr) const;
void Register(void);
+ void Unregister(void);
void Activate(void);
void Deactivate(void);
class NameComposer {
public:
virtual String MakeName(const String& shortName, const Object::Ptr& context) const = 0;
+ virtual Dictionary::Ptr ParseName(const String& name) const = 0;
};
}}}
}
}
+void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
+{
+ String name = object->GetName();
+
+ {
+ ObjectLock olock(this);
+
+ m_ObjectMap.erase(name);
+ m_ObjectVector.erase(std::remove(m_ObjectVector.begin(), m_ObjectVector.end(), object), m_ObjectVector.end());
+ }
+}
+
DynamicObject::Ptr DynamicType::GetObject(const String& name) const
{
ObjectLock olock(this);
DynamicObject::Ptr GetObject(const String& name) const;
void RegisterObject(const DynamicObject::Ptr& object);
+ void UnregisterObject(const DynamicObject::Ptr& object);
static std::vector<DynamicType::Ptr> GetTypes(void);
std::pair<DynamicTypeIterator<DynamicObject>, DynamicTypeIterator<DynamicObject> > GetObjects(void);
return ptype;
}
+String Type::GetPluralName(void) const
+{
+ String name = GetName();
+
+ if (name[name.GetLength() - 1] == 'y')
+ return name.SubStr(0, name.GetLength() - 1) + "ies";
+ else
+ return name + "s";
+}
+
Object::Ptr Type::Instantiate(void) const
{
ObjectFactory factory = GetFactory();
virtual Field GetFieldInfo(int id) const = 0;
virtual int GetFieldCount(void) const = 0;
+ String GetPluralName(void) const;
+
Object::Ptr Instantiate(void) const;
bool IsAssignableFrom(const Type::Ptr& other) const;
}
}
- // activate config only after daemonization: it starts threads and that is not compatible with fork()
- if (!ConfigItem::ActivateItems()) {
- Log(LogCritical, "cli", "Error activating configuration.");
- return EXIT_FAILURE;
+ {
+ WorkQueue upq(25000, Application::GetConcurrency());
+
+ // activate config only after daemonization: it starts threads and that is not compatible with fork()
+ if (!ConfigItem::ActivateItems(upq, true)) {
+ Log(LogCritical, "cli", "Error activating configuration.");
+ return EXIT_FAILURE;
+ }
}
if (vm.count("daemonize")) {
if (!DaemonUtility::ValidateConfigFiles(configs, objectsFile))
return false;
- bool result = ConfigItem::CommitItems();
+ WorkQueue upq(25000, Application::GetConcurrency());
+ bool result = ConfigItem::CommitItems(upq);
if (!result)
return false;
}
}
+/**
+ * Unregisters the configuration item.
+ */
+void ConfigItem::Unregister(void)
+{
+ if (m_Object)
+ m_Object->Unregister();
+
+ boost::mutex::scoped_lock lock(m_Mutex);
+ m_UnnamedItems.erase(std::remove(m_UnnamedItems.begin(), m_UnnamedItems.end(), this), m_UnnamedItems.end());
+ m_Items[m_Type].erase(m_Name);
+}
+
/**
* Retrieves a configuration item by type and name.
*
return it2->second;
}
-bool ConfigItem::CommitNewItems(WorkQueue& upq)
+bool ConfigItem::CommitNewItems(WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems)
{
typedef std::pair<ConfigItem::Ptr, bool> ItemPair;
std::vector<ItemPair> items;
return true;
BOOST_FOREACH(const ItemPair& ip, items) {
+ newItems.push_back(ip.first);
upq.Enqueue(boost::bind(&ConfigItem::Commit, ip.first, ip.second));
}
if (upq.HasExceptions())
return false;
- if (!CommitNewItems(upq))
+ if (!CommitNewItems(upq, newItems))
return false;
}
}
return true;
}
-bool ConfigItem::CommitItems(void)
+bool ConfigItem::CommitItems(WorkQueue& upq)
{
- WorkQueue upq(25000, Application::GetConcurrency());
-
Log(LogInformation, "ConfigItem", "Committing config items");
- if (!CommitNewItems(upq)) {
+ std::vector<ConfigItem::Ptr> newItems;
+
+ if (!CommitNewItems(upq, newItems)) {
upq.ReportExceptions("config");
+
+ BOOST_FOREACH(const ConfigItem::Ptr& item, newItems) {
+ item->Unregister();
+ }
+
return false;
}
ApplyRule::CheckMatches();
/* log stats for external parsers */
- BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
- int count = std::distance(type->GetObjects().first, type->GetObjects().second);
- if (count > 0)
- Log(LogInformation, "ConfigItem")
- << "Checked " << count << " " << type->GetName() << "(s).";
+ typedef std::map<Type::Ptr, int> ItemCountMap;
+ ItemCountMap itemCounts;
+ BOOST_FOREACH(const ConfigItem::Ptr& item, newItems) {
+ itemCounts[item->m_Object->GetReflectionType()]++;
+ }
+
+ BOOST_FOREACH(const ItemCountMap::value_type& kv, itemCounts) {
+ Log(LogInformation, "ConfigItem")
+ << "Instantiated " << kv.second << " " << kv.first->GetPluralName() << ".";
}
return true;
}
-bool ConfigItem::ActivateItems(void)
+bool ConfigItem::ActivateItems(WorkQueue& upq, bool restoreState)
{
- /* restore the previous program state */
- try {
- DynamicObject::RestoreObjects(Application::GetStatePath());
- } catch (const std::exception& ex) {
- Log(LogCritical, "ConfigItem")
- << "Failed to restore state file: " << DiagnosticInformation(ex);
+ if (restoreState) {
+ /* restore the previous program state */
+ try {
+ DynamicObject::RestoreObjects(Application::GetStatePath());
+ } catch (const std::exception& ex) {
+ Log(LogCritical, "ConfigItem")
+ << "Failed to restore state file: " << DiagnosticInformation(ex);
+ }
}
Log(LogInformation, "ConfigItem", "Triggering Start signal for config items");
- WorkQueue upq(25000, Application::GetConcurrency());
-
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
if (object->IsActive())
{
WorkQueue upq(25000, Application::GetConcurrency());
- if (!CommitNewItems(upq)) {
- upq.ReportExceptions("ConfigItem");
-
- boost::mutex::scoped_lock lock(m_Mutex);
- m_Items.clear();
- m_UnnamedItems.clear();
-
+ if (!CommitItems(upq))
return false;
- }
-
- BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
- BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
- if (object->IsActive())
- continue;
-
-#ifdef I2_DEBUG
- Log(LogDebug, "ConfigItem")
- << "Activating object '" << object->GetName() << "' of type '" << object->GetType()->GetName() << "'";
-#endif /* I2_DEBUG */
- upq.Enqueue(boost::bind(&DynamicObject::Activate, object));
- }
- }
-
- upq.Join();
-
- if (upq.HasExceptions()) {
- upq.ReportExceptions("ConfigItem");
-
- boost::mutex::scoped_lock lock(m_Mutex);
- m_Items.clear();
- m_UnnamedItems.clear();
+ if (!ActivateItems(upq, false))
return false;
- }
return true;
}
DynamicObject::Ptr Commit(bool discard = true);
void Register(void);
+ void Unregister(void);
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const;
static ConfigItem::Ptr GetObject(const String& type,
const String& name);
- static bool CommitItems(void);
- static bool ActivateItems(void);
+ static bool CommitItems(WorkQueue& upq);
+ static bool ActivateItems(WorkQueue& upq, bool restoreState);
static bool CommitAndActivate(void);
static ConfigItem::Ptr GetObjectUnlocked(const String& type,
const String& name);
- static bool CommitNewItems(WorkQueue& upq);
+ static bool CommitNewItems(WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems);
};
}
#include "base/logger.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
using namespace icinga;
return name;
}
+Dictionary::Ptr DependencyNameComposer::ParseName(const String& name) const
+{
+ std::vector<String> tokens;
+ boost::algorithm::split(tokens, name, boost::is_any_of("!"));
+
+ if (tokens.size() < 2)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Dependency name."));
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("child_host_name", tokens[0]);
+
+ if (tokens.size() > 2) {
+ result->Set("child_service_name", tokens[1]);
+ result->Set("name", tokens[2]);
+ } else {
+ result->Set("name", tokens[1]);
+ }
+
+ return result;
+}
+
void Dependency::OnConfigLoaded(void)
{
Value defaultFilter;
{
public:
virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+ virtual Dictionary::Ptr ParseName(const String& name) const;
};
}}}
#include "base/initialize.hpp"
#include "base/scriptglobal.hpp"
#include <boost/foreach.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
using namespace icinga;
return name;
}
+Dictionary::Ptr NotificationNameComposer::ParseName(const String& name) const
+{
+ std::vector<String> tokens;
+ boost::algorithm::split(tokens, name, boost::is_any_of("!"));
+
+ if (tokens.size() < 2)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Notification name."));
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("host_name", tokens[0]);
+
+ if (tokens.size() > 2) {
+ result->Set("service_name", tokens[1]);
+ result->Set("name", tokens[2]);
+ } else {
+ result->Set("name", tokens[1]);
+ }
+
+ return result;
+}
+
void Notification::StaticInitialize(void)
{
ScriptGlobal::Set("OK", StateFilterOK);
{
public:
virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+ virtual Dictionary::Ptr ParseName(const String& name) const;
};
}}}
#include "base/logger.hpp"
#include "base/exception.hpp"
#include <boost/foreach.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
using namespace icinga;
return name;
}
+Dictionary::Ptr ScheduledDowntimeNameComposer::ParseName(const String& name) const
+{
+ std::vector<String> tokens;
+ boost::algorithm::split(tokens, name, boost::is_any_of("!"));
+
+ if (tokens.size() < 2)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid ScheduledDowntime name."));
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("host_name", tokens[0]);
+
+ if (tokens.size() > 2) {
+ result->Set("service_name", tokens[1]);
+ result->Set("name", tokens[2]);
+ } else {
+ result->Set("name", tokens[1]);
+ }
+
+ return result;
+}
+
void ScheduledDowntime::StaticInitialize(void)
{
l_Timer = new Timer();
{
public:
virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+ virtual Dictionary::Ptr ParseName(const String& name) const;
};
}}}
#include "base/utility.hpp"
#include <boost/foreach.hpp>
#include <boost/bind/apply.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
using namespace icinga;
return service->GetHostName() + "!" + shortName;
}
+Dictionary::Ptr ServiceNameComposer::ParseName(const String& name) const
+{
+ std::vector<String> tokens;
+ boost::algorithm::split(tokens, name, boost::is_any_of("!"));
+
+ if (tokens.size() < 2)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid Service name."));
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("host_name", tokens[0]);
+ result->Set("name", tokens[1]);
+
+ return result;
+}
+
void Service::OnAllConfigLoaded(void)
{
Checkable::OnAllConfigLoaded();
{
public:
virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+ virtual Dictionary::Ptr ParseName(const String& name) const;
};
}}}
set(remote_SOURCES
actionshandler.cpp apiaction.cpp
apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp
- apiuser.cpp apiuser.thpp authority.cpp base64.cpp createobjecthandler.cpp configfileshandler.cpp
- configmoduleshandler.cpp configmoduleutility.cpp configstageshandler.cpp
+ apiuser.cpp apiuser.thpp authority.cpp base64.cpp createobjecthandler.cpp deleteobjecthandler.cpp
+ configfileshandler.cpp configmoduleshandler.cpp configmoduleutility.cpp configstageshandler.cpp
endpoint.cpp endpoint.thpp filterutility.cpp
httpchunkedencoding.cpp httpconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
httputility.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
String name = request.RequestUrl->GetPath()[2];
+ NameComposer *nc = dynamic_cast<NameComposer *>(type.get());
+ Dictionary::Ptr nameParts;
+
+ if (nc) {
+ nameParts = nc->ParseName(name);
+ name = nameParts->Get("name");
+ }
+
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
ConfigItemBuilder::Ptr builder = new ConfigItemBuilder();
}
}
+ if (nameParts) {
+ ObjectLock olock(nameParts);
+ BOOST_FOREACH(const Dictionary::Pair& kv, nameParts) {
+ SetExpression *expr = new SetExpression(MakeIndexer(ScopeThis, kv.first), OpSetLiteral, MakeLiteral(kv.second));
+ builder->AddExpression(expr);
+ }
+ }
+
Dictionary::Ptr attrs = params->Get("attrs");
if (attrs) {
ConfigItem::Ptr item = builder->Compile();
item->Register();
- ConfigItem::CommitAndActivate();
+ WorkQueue upq;
Dictionary::Ptr result1 = new Dictionary();
- result1->Set("code", 200);
- result1->Set("status", "Object created.");
+ int code;
+ String status;
+
+ if (!ConfigItem::CommitItems(upq) || !ConfigItem::ActivateItems(upq, false)) {
+ code = 500;
+ status = "Object could not be created.";
+
+ Array::Ptr errors = new Array();
+ BOOST_FOREACH(const boost::exception_ptr& ex, upq.GetExceptions()) {
+ errors->Add(DiagnosticInformation(ex));
+ }
+ result1->Set("errors", errors);
+ } else {
+ code = 200;
+ status = "Object created";
+ }
+
+ result1->Set("code", code);
+ result1->Set("status", status);
Array::Ptr results = new Array();
results->Add(result1);
Dictionary::Ptr result = new Dictionary();
result->Set("results", results);
- response.SetStatus(200, "OK");
+ response.SetStatus(code, status);
HttpUtility::SendJsonBody(response, result);
return true;
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#include "remote/deleteobjecthandler.hpp"
+#include "remote/httputility.hpp"
+#include "remote/filterutility.hpp"
+#include "remote/apiaction.hpp"
+#include "config/configitem.hpp"
+#include "base/exception.hpp"
+#include "base/serializer.hpp"
+#include <boost/algorithm/string.hpp>
+#include <set>
+
+using namespace icinga;
+
+REGISTER_URLHANDLER("/v1", DeleteObjectHandler);
+
+bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+{
+ if (request.RequestMethod != "DELETE")
+ return false;
+
+ if (request.RequestUrl->GetPath().size() < 2)
+ return false;
+
+ Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]);
+
+ if (!type)
+ return false;
+
+ QueryDescription qd;
+ qd.Types.insert(type);
+
+ Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
+
+ params->Set("type", type->GetName());
+
+ if (request.RequestUrl->GetPath().size() >= 3) {
+ String attr = type->GetName();
+ boost::algorithm::to_lower(attr);
+ params->Set(attr, request.RequestUrl->GetPath()[2]);
+ }
+
+ std::vector<DynamicObject::Ptr> objs = FilterUtility::GetFilterTargets(qd, params);
+
+ Array::Ptr results = new Array();
+
+ BOOST_FOREACH(const DynamicObject::Ptr& obj, objs) {
+ Dictionary::Ptr result1 = new Dictionary();
+ result1->Set("type", type->GetName());
+ result1->Set("name", obj->GetName());
+
+ ConfigItem::Ptr item = ConfigItem::GetObject(type->GetName(), obj->GetName());
+
+ try {
+ obj->Deactivate();
+
+ if (item)
+ item->Unregister();
+ else
+ obj->Unregister();
+
+ result1->Set("code", 200);
+ result1->Set("status", "Object was deleted.");
+ } catch (const std::exception& ex) {
+ result1->Set("code", 500);
+ result1->Set("status", "Object could not be deleted: " + DiagnosticInformation(ex));
+ }
+
+ results->Add(result1);
+ }
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("results", results);
+
+ response.SetStatus(200, "OK");
+ HttpUtility::SendJsonBody(response, result);
+
+ return true;
+}
+
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#ifndef DELETEOBJECTHANDLER_H
+#define DELETEOBJECTHANDLER_H
+
+#include "remote/httphandler.hpp"
+
+namespace icinga
+{
+
+class I2_REMOTE_API DeleteObjectHandler : public HttpHandler
+{
+public:
+ DECLARE_PTR_TYPEDEFS(DeleteObjectHandler);
+
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+};
+
+}
+
+#endif /* DELETEOBJECTHANDLER_H */
Type::Ptr type = Type::GetByName(dtype->GetName());
ASSERT(type);
- String pname = GetPluralName(type);
+ String pname = type->GetPluralName();
boost::algorithm::to_lower(pname);
if (uname == pname)
return Type::Ptr();
}
-String FilterUtility::GetPluralName(const Type::Ptr& type)
-{
- String name = type->GetName();
-
- if (name[name.GetLength() - 1] == 'y')
- return name.SubStr(0, name.GetLength() - 1) + "ies";
- else
- return name + "s";
-}
-
DynamicObject::Ptr FilterUtility::GetObjectByTypeAndName(const String& type, const String& name)
{
DynamicType::Ptr dtype = DynamicType::GetByName(type);
result.push_back(obj);
}
- attr = GetPluralName(type);
+ attr = type->GetPluralName();
boost::algorithm::to_lower(attr);
if (query->Contains(attr)) {
class I2_REMOTE_API FilterUtility
{
public:
- static String GetPluralName(const Type::Ptr& type);
static Type::Ptr TypeFromPluralName(const String& pluralName);
static DynamicObject::Ptr GetObjectByTypeAndName(const String& type, const String& name);
static std::vector<DynamicObject::Ptr> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query);
BOOST_FOREACH(const DynamicObject::Ptr& obj, objs) {
Dictionary::Ptr result1 = new Dictionary();
- result1->Set("type", obj->GetReflectionType()->GetName());
+ result1->Set("type", type->GetName());
result1->Set("name", obj->GetName());
String key;
DaemonUtility::LoadConfigFiles(configs, "icinga2.debug", "icinga2.vars");
/* ignore config errors */
- ConfigItem::ActivateItems();
+ WorkQueue upq;
+ ConfigItem::ActivateItems(upq, false);
}
~GlobalConfigFixture()