]> granicus.if.org Git - icinga2/commitdiff
Implement support for unregistering objects
authorGunnar Beutner <gunnar@beutner.name>
Thu, 13 Aug 2015 07:02:52 +0000 (09:02 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Sat, 15 Aug 2015 18:07:11 +0000 (20:07 +0200)
refs #9101

27 files changed:
lib/base/dynamicobject.cpp
lib/base/dynamicobject.hpp
lib/base/dynamicobject.ti
lib/base/dynamictype.cpp
lib/base/dynamictype.hpp
lib/base/type.cpp
lib/base/type.hpp
lib/cli/daemoncommand.cpp
lib/cli/daemonutility.cpp
lib/config/configitem.cpp
lib/config/configitem.hpp
lib/icinga/dependency.cpp
lib/icinga/dependency.ti
lib/icinga/notification.cpp
lib/icinga/notification.ti
lib/icinga/scheduleddowntime.cpp
lib/icinga/scheduleddowntime.ti
lib/icinga/service.cpp
lib/icinga/service.ti
lib/remote/CMakeLists.txt
lib/remote/createobjecthandler.cpp
lib/remote/deleteobjecthandler.cpp [new file with mode: 0644]
lib/remote/deleteobjecthandler.hpp [new file with mode: 0644]
lib/remote/filterutility.cpp
lib/remote/filterutility.hpp
lib/remote/modifyobjecthandler.cpp
test/livestatus.cpp

index 229e4e5b314a1e72fce48f39623442a18b87d0a4..91175af36fd0d1590e11c5de6a710cee769a816a 100644 (file)
@@ -177,6 +177,14 @@ void DynamicObject::Register(void)
        dtype->RegisterObject(this);
 }
 
+void DynamicObject::Unregister(void)
+{
+       ASSERT(!OwnsLock());
+
+       DynamicType::Ptr dtype = GetType();
+       dtype->UnregisterObject(this);
+}
+
 void DynamicObject::Start(void)
 {
        ASSERT(!OwnsLock());
index 1a60e0f3d71dd66d0514d4635d74b7a17e77f971..8bca65ef2e9e964bf9f87e2ea843e9587c4d3bc7 100644 (file)
@@ -58,6 +58,7 @@ public:
        bool IsAttributeModified(const String& attr) const;
 
        void Register(void);
+       void Unregister(void);
 
        void Activate(void);
        void Deactivate(void);
index 8724ac19eb1c3fdaedad002e90cc532bf7117684..c45dfc50f950a6f47e4af5950a358e5461a0833a 100644 (file)
@@ -34,6 +34,7 @@ enum HAMode
 class NameComposer {
 public:
        virtual String MakeName(const String& shortName, const Object::Ptr& context) const = 0;
+       virtual Dictionary::Ptr ParseName(const String& name) const = 0;
 };
 }}}
 
index 27b84eb31217772e410f04c6a848b2f7514b8627..e6386dcd8865bffb359d9e18128e81712c34c275 100644 (file)
@@ -113,6 +113,18 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
        }
 }
 
+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);
index 3c0abb788742732d8b02e3e700a3e74e4f8911e0..9670857e2822bd3258e41b08ff1508a04f7ee214 100644 (file)
@@ -46,6 +46,7 @@ public:
        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);
index 01a209ced6ecd4dbf0ba3adb2d19b91ba99380e1..b8058bb455c17b68a90b37b9bcd01088a9a1c609 100644 (file)
@@ -56,6 +56,16 @@ Type::Ptr Type::GetByName(const String& name)
        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();
index 42189a3c9abcffaecb265c7251eaf575ee66c48c..c373be00ae057cc8816bba38cc44e1b474f44e71 100644 (file)
@@ -80,6 +80,8 @@ public:
        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;
index 39fedd495e8be6c5fe7a6e58136ff3ab9edfbb9b..7c9b6a625b32f4cb43c6c8caf2dd93755b071bdc 100644 (file)
@@ -258,10 +258,14 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
                }
        }
 
-       // 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")) {
index ffc680248ce64a09d4211636ff915b7d646ec1f7..49cf2c528ffa6f211b31480e28fbdba28cd3f19a 100644 (file)
@@ -123,7 +123,8 @@ bool DaemonUtility::LoadConfigFiles(const std::vector<std::string>& configs,
        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;
index d0e02e9c2b1a46425c4ddfc0d503d23612543cde..82930ff5ebdd1071062831e2e2595aea34386de1 100644 (file)
@@ -268,6 +268,19 @@ void ConfigItem::Register(void)
        }
 }
 
+/**
+ * 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.
  *
@@ -292,7 +305,7 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& 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;
@@ -320,6 +333,7 @@ bool ConfigItem::CommitNewItems(WorkQueue& upq)
                return true;
 
        BOOST_FOREACH(const ItemPair& ip, items) {
+               newItems.push_back(ip.first);
                upq.Enqueue(boost::bind(&ConfigItem::Commit, ip.first, ip.second));
        }
 
@@ -398,7 +412,7 @@ bool ConfigItem::CommitNewItems(WorkQueue& upq)
                        if (upq.HasExceptions())
                                return false;
 
-                       if (!CommitNewItems(upq))
+                       if (!CommitNewItems(upq, newItems))
                                return false;
                }
        }
@@ -406,44 +420,53 @@ bool ConfigItem::CommitNewItems(WorkQueue& upq)
        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())
@@ -481,40 +504,11 @@ bool ConfigItem::CommitAndActivate(void)
 {
        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;
 }
index 4b0309224f9513587e94bb93084cc496a16adfe9..8425336deb7457024a7b4bf7f582a6c438b23fd4 100644 (file)
@@ -55,6 +55,7 @@ public:
 
        DynamicObject::Ptr Commit(bool discard = true);
        void Register(void);
+       void Unregister(void);
 
        DebugInfo GetDebugInfo(void) const;
        Dictionary::Ptr GetScope(void) const;
@@ -64,8 +65,8 @@ public:
        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);
 
@@ -97,7 +98,7 @@ private:
        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);
 };
 
 }
index 28de23d02eb4d2b1c85b929b940aa58ce46ea1df..fc1545e125606829a0e18a08ab542a5071440a32 100644 (file)
@@ -23,6 +23,8 @@
 #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;
 
@@ -45,6 +47,27 @@ String DependencyNameComposer::MakeName(const String& shortName, const Object::P
        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;
index 741d3877b7439b0380915cc72bdd19934da09f49..2d70896636552ab284ff7cb309806c94b287b7e6 100644 (file)
@@ -30,6 +30,7 @@ class I2_ICINGA_API DependencyNameComposer : public NameComposer
 {
 public:
        virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+       virtual Dictionary::Ptr ParseName(const String& name) const;
 };
 }}}
 
index 162b3e971063b3627d8ab6b3908d534a443abc8e..45ba8ba439cdd44c4d1a70776dd7c326b2f7197b 100644 (file)
@@ -29,6 +29,8 @@
 #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;
 
@@ -54,6 +56,27 @@ String NotificationNameComposer::MakeName(const String& shortName, const Object:
        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);
index 4cedb95d1b2cebd9c012095bd11d4845efa66f61..28c8b4b701216c601ff40999e9ce726d34828f44 100644 (file)
@@ -29,6 +29,7 @@ class I2_ICINGA_API NotificationNameComposer : public NameComposer
 {
 public:
        virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+       virtual Dictionary::Ptr ParseName(const String& name) const;
 };
 }}}
 
index 8428738a5df8359cfbd75de54f680559a741ed40..21d14f477bb9a729eb94c8460d138abcee892099 100644 (file)
@@ -31,6 +31,8 @@
 #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;
 
@@ -57,6 +59,27 @@ String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Ob
        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();
index 729a0e08dab853a25bc7073d2450b5f46d8b4878..c41363aebd4e9e1d2f6dc9ba753e3aaac6452d21 100644 (file)
@@ -29,6 +29,7 @@ class I2_ICINGA_API ScheduledDowntimeNameComposer : public NameComposer
 {
 public:
        virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+       virtual Dictionary::Ptr ParseName(const String& name) const;
 };
 }}}
 
index f9e7e915e4b78e90e96dd63cf90d00ba3bdfe1a9..aa713a6c01a58aceb7d0966edb98076d0b705fd9 100644 (file)
@@ -27,6 +27,8 @@
 #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;
 
@@ -42,6 +44,21 @@ String ServiceNameComposer::MakeName(const String& shortName, const Object::Ptr&
        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();
index 276aa7887e7d2414bdd3fad9c597252f6de2bbc2..49e96bf55308f97242eef1f0557de87c1c24f17c 100644 (file)
@@ -32,6 +32,7 @@ class I2_ICINGA_API ServiceNameComposer : public NameComposer
 {
 public:
        virtual String MakeName(const String& shortName, const Object::Ptr& context) const;
+       virtual Dictionary::Ptr ParseName(const String& name) const;
 };
 }}}
 
index 6791bd12eb4ce8ae24c4459f0b1b83313ba989a4..1e3b3cbafc2a83dc1a7ab27f11777f0151e07281 100644 (file)
@@ -23,8 +23,8 @@ mkclass_target(zone.ti zone.tcpp zone.thpp)
 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
index d535a5e422ce9cf91e1e5912f6dec4aec29c39e0..a6b568941a5cb433e186dccb38c29dc674cf5c2f 100644 (file)
@@ -47,6 +47,14 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
 
        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();
@@ -64,6 +72,14 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
                }
        }
 
+       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) {
@@ -77,11 +93,28 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
        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);
@@ -89,7 +122,7 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
        Dictionary::Ptr result = new Dictionary();
        result->Set("results", results);
 
-       response.SetStatus(200, "OK");
+       response.SetStatus(code, status);
        HttpUtility::SendJsonBody(response, result);
 
        return true;
diff --git a/lib/remote/deleteobjecthandler.cpp b/lib/remote/deleteobjecthandler.cpp
new file mode 100644 (file)
index 0000000..aa21b79
--- /dev/null
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * 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;
+}
+
diff --git a/lib/remote/deleteobjecthandler.hpp b/lib/remote/deleteobjecthandler.hpp
new file mode 100644 (file)
index 0000000..ec35e9d
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * 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 */
index 2764b2c0e9a4e7162a47b0d8a856ac70158165ce..143939b56eb81f437c603e3a5ba9454a37dd979a 100644 (file)
@@ -38,7 +38,7 @@ Type::Ptr FilterUtility::TypeFromPluralName(const String& pluralName)
                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)
@@ -48,16 +48,6 @@ Type::Ptr FilterUtility::TypeFromPluralName(const String& pluralName)
        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);
@@ -82,7 +72,7 @@ std::vector<DynamicObject::Ptr> FilterUtility::GetFilterTargets(const QueryDescr
                        result.push_back(obj);
                }
 
-               attr = GetPluralName(type);
+               attr = type->GetPluralName();
                boost::algorithm::to_lower(attr);
 
                if (query->Contains(attr)) {
index b7c28821d3d38f92e81447fda1026db352cf0e66..42a3d27607cac3ae356cac3f905ef597970ef458 100644 (file)
@@ -41,7 +41,6 @@ struct QueryDescription
 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);
index 842a30a9683e853a9d221d38cf9da5558bba704c..296392261c6468c07a74f275965c5e88ee3277a4 100644 (file)
@@ -65,7 +65,7 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
        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;
index f876eb5776d8c320b3a075bfe7cb12755acff917..b59876c5e5ad2e111438b110916a862261ae1cef 100644 (file)
@@ -87,7 +87,8 @@ struct GlobalConfigFixture {
                DaemonUtility::LoadConfigFiles(configs, "icinga2.debug", "icinga2.vars");
 
                /* ignore config errors */
-               ConfigItem::ActivateItems();
+               WorkQueue upq;
+               ConfigItem::ActivateItems(upq, false);
        }
 
        ~GlobalConfigFixture()