]> granicus.if.org Git - icinga2/commitdiff
Livestatus: Add GroupBy tables: hostsbygroup, servicesbygroup, servicesbyhostgroup
authorMichael Friedrich <michael.friedrich@gmail.com>
Fri, 13 Feb 2015 14:50:20 +0000 (15:50 +0100)
committerMichael Friedrich <michael.friedrich@gmail.com>
Wed, 18 Feb 2015 16:51:26 +0000 (17:51 +0100)
fixes #7361

Signed-off-by: Michael Friedrich <michael.friedrich@gmail.com>
63 files changed:
lib/livestatus/column.cpp
lib/livestatus/column.hpp
lib/livestatus/commandstable.cpp
lib/livestatus/commentstable.cpp
lib/livestatus/contactgroupstable.cpp
lib/livestatus/contactstable.cpp
lib/livestatus/downtimestable.cpp
lib/livestatus/endpointstable.cpp
lib/livestatus/hostgroupstable.cpp
lib/livestatus/hoststable.cpp
lib/livestatus/hoststable.hpp
lib/livestatus/livestatusquery.cpp
lib/livestatus/logtable.cpp
lib/livestatus/servicegroupstable.cpp
lib/livestatus/servicestable.cpp
lib/livestatus/servicestable.hpp
lib/livestatus/statehisttable.cpp
lib/livestatus/statustable.cpp
lib/livestatus/table.cpp
lib/livestatus/table.hpp
lib/livestatus/timeperiodstable.cpp
test/livestatus/queries/commands/command [moved from test/livestatus/queries/command/command with 100% similarity]
test/livestatus/queries/commands/modattr [moved from test/livestatus/queries/command/modattr with 100% similarity]
test/livestatus/queries/comments/comment [moved from test/livestatus/queries/comment/comment with 100% similarity]
test/livestatus/queries/comments/comment_short [moved from test/livestatus/queries/comment/comment_short with 100% similarity]
test/livestatus/queries/contacts/contacts [moved from test/livestatus/queries/contact/contacts with 100% similarity]
test/livestatus/queries/contacts/group [moved from test/livestatus/queries/contact/group with 100% similarity]
test/livestatus/queries/contacts/modattr [moved from test/livestatus/queries/contact/modattr with 100% similarity]
test/livestatus/queries/downtimes/downtime [moved from test/livestatus/queries/downtime/downtime with 100% similarity]
test/livestatus/queries/downtimes/downtime_short [moved from test/livestatus/queries/downtime/downtime_short with 100% similarity]
test/livestatus/queries/hosts/bygroup [new file with mode: 0644]
test/livestatus/queries/hosts/check [moved from test/livestatus/queries/host/check with 100% similarity]
test/livestatus/queries/hosts/command [moved from test/livestatus/queries/host/command with 100% similarity]
test/livestatus/queries/hosts/comment [moved from test/livestatus/queries/host/comment with 100% similarity]
test/livestatus/queries/hosts/contact [moved from test/livestatus/queries/host/contact with 100% similarity]
test/livestatus/queries/hosts/customvar [moved from test/livestatus/queries/host/customvar with 100% similarity]
test/livestatus/queries/hosts/downtime [moved from test/livestatus/queries/host/downtime with 100% similarity]
test/livestatus/queries/hosts/extra [moved from test/livestatus/queries/host/extra with 100% similarity]
test/livestatus/queries/hosts/group [moved from test/livestatus/queries/host/group with 100% similarity]
test/livestatus/queries/hosts/host [moved from test/livestatus/queries/host/host with 100% similarity]
test/livestatus/queries/hosts/host_nagvis [moved from test/livestatus/queries/host/host_nagvis with 100% similarity]
test/livestatus/queries/hosts/legacy [moved from test/livestatus/queries/host/legacy with 100% similarity]
test/livestatus/queries/hosts/modattr [moved from test/livestatus/queries/host/modattr with 100% similarity]
test/livestatus/queries/hosts/notification [moved from test/livestatus/queries/host/notification with 100% similarity]
test/livestatus/queries/hosts/services [moved from test/livestatus/queries/host/services with 100% similarity]
test/livestatus/queries/hosts/state [moved from test/livestatus/queries/host/state with 100% similarity]
test/livestatus/queries/hosts/stats_sum [moved from test/livestatus/queries/host/stats_sum with 100% similarity]
test/livestatus/queries/services/bygroup [new file with mode: 0644]
test/livestatus/queries/services/byhostgroup [new file with mode: 0644]
test/livestatus/queries/services/check [moved from test/livestatus/queries/service/check with 100% similarity]
test/livestatus/queries/services/command [moved from test/livestatus/queries/service/command with 100% similarity]
test/livestatus/queries/services/comment [moved from test/livestatus/queries/service/comment with 100% similarity]
test/livestatus/queries/services/contact [moved from test/livestatus/queries/service/contact with 100% similarity]
test/livestatus/queries/services/customvar [moved from test/livestatus/queries/service/customvar with 100% similarity]
test/livestatus/queries/services/downtime [moved from test/livestatus/queries/service/downtime with 100% similarity]
test/livestatus/queries/services/extra [moved from test/livestatus/queries/service/extra with 100% similarity]
test/livestatus/queries/services/group [moved from test/livestatus/queries/service/group with 100% similarity]
test/livestatus/queries/services/legacy [moved from test/livestatus/queries/service/legacy with 100% similarity]
test/livestatus/queries/services/modattr [moved from test/livestatus/queries/service/modattr with 100% similarity]
test/livestatus/queries/services/notification [moved from test/livestatus/queries/service/notification with 100% similarity]
test/livestatus/queries/services/services [moved from test/livestatus/queries/service/services with 100% similarity]
test/livestatus/queries/services/state [moved from test/livestatus/queries/service/state with 100% similarity]
test/livestatus/queries/timeperiods/timeperiod [moved from test/livestatus/queries/timeperiod/timeperiod with 100% similarity]

index 664e88caf5ff70ba705b640ad330299410f47d2e..44f70f12b353ecac1458791310ab59ba6e1cfb19 100644 (file)
@@ -25,12 +25,12 @@ Column::Column(const ValueAccessor& valueAccessor, const ObjectAccessor& objectA
        : m_ValueAccessor(valueAccessor), m_ObjectAccessor(objectAccessor)
 { }
 
-Value Column::ExtractValue(const Value& urow) const
+Value Column::ExtractValue(const Value& urow, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject) const
 {
        Value row;
 
        if (!m_ObjectAccessor.empty())
-               row = m_ObjectAccessor(urow);
+               row = m_ObjectAccessor(urow, groupByType, groupByObject);
        else
                row = urow;
 
index c9fb516ae07dc09903f43a810984e6eaf9035503..74618dac1e8771decee305a22a794e2c42b6694e 100644 (file)
@@ -28,15 +28,21 @@ using namespace icinga;
 namespace icinga
 {
 
+enum LivestatusGroupByType {
+       LivestatusGroupByNone,
+       LivestatusGroupByHostGroup,
+       LivestatusGroupByServiceGroup
+};
+
 class Column
 {
 public:
        typedef boost::function<Value (const Value&)> ValueAccessor;
-       typedef boost::function<Value (const Value&)> ObjectAccessor;
+       typedef boost::function<Value (const Value&, LivestatusGroupByType, const Object::Ptr&)> ObjectAccessor;
 
        Column(const ValueAccessor& valueAccessor, const ObjectAccessor& objectAccessor);
 
-       Value ExtractValue(const Value& urow) const;
+       Value ExtractValue(const Value& urow, LivestatusGroupByType groupByType = LivestatusGroupByNone, const Object::Ptr& groupByObject = Empty) const;
 
 private:
        ValueAccessor m_ValueAccessor;
index 756f1d322235c25b7d521082bcbaa8bd0380eec3..b36a8bd0d3d59b80209cbe4682b50aac9f80bfcd 100644 (file)
@@ -61,27 +61,27 @@ String CommandsTable::GetPrefix(void) const
 void CommandsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjectsByType<CheckCommand>()) {
-               addRowFn(object);
+               addRowFn(object, LivestatusGroupByNone, Empty);
        }
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjectsByType<EventCommand>()) {
-               addRowFn(object);
+               addRowFn(object, LivestatusGroupByNone, Empty);
        }
        BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjectsByType<NotificationCommand>()) {
-               addRowFn(object);
+               addRowFn(object, LivestatusGroupByNone, Empty);
        }
 }
 
 Value CommandsTable::NameAccessor(const Value& row)
 {
        Command::Ptr command = static_cast<Command::Ptr>(row);
-       
+
        return CompatUtility::GetCommandName(command);
 }
 
 Value CommandsTable::LineAccessor(const Value& row)
 {
        Command::Ptr command = static_cast<Command::Ptr>(row);
-       
+
        if (!command)
                return Empty;
 
index 47541598387a95ea0fe3ddb021d116a4abbb42e8..4feb6b53414ebc67d137650f5955ad982d39d9dd 100644 (file)
@@ -74,7 +74,7 @@ void CommentsTable::FetchRows(const AddRowFunction& addRowFn)
                Comment::Ptr comment;
                BOOST_FOREACH(tie(id, comment), comments) {
                        if (Host::GetOwnerByCommentID(id) == host)
-                               addRowFn(comment);
+                               addRowFn(comment, LivestatusGroupByNone, Empty);
                }
        }
 
@@ -87,7 +87,7 @@ void CommentsTable::FetchRows(const AddRowFunction& addRowFn)
                Comment::Ptr comment;
                BOOST_FOREACH(tie(id, comment), comments) {
                        if (Service::GetOwnerByCommentID(id) == service)
-                               addRowFn(comment);
+                               addRowFn(comment, LivestatusGroupByNone, Empty);
                }
        }
 }
index 43ef038f17c434641ad6fe0a72808effbf043e93..604aa73b7bdff30443e0d004b61184a887ce4430 100644 (file)
@@ -50,7 +50,7 @@ String ContactGroupsTable::GetPrefix(void) const
 void ContactGroupsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const UserGroup::Ptr& ug, DynamicType::GetObjectsByType<UserGroup>()) {
-               addRowFn(ug);
+               addRowFn(ug, LivestatusGroupByNone, Empty);
        }
 }
 
index 35a61d5bebe6f84584cce51cc3aa37478f09fe2b..e6400e5ee23b40349db5e94a2c1603a1a384ba93 100644 (file)
@@ -71,7 +71,7 @@ String ContactsTable::GetPrefix(void) const
 void ContactsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const User::Ptr& user, DynamicType::GetObjectsByType<User>()) {
-               addRowFn(user);
+               addRowFn(user, LivestatusGroupByNone, Empty);
        }
 }
 
index 742ff82063d043568f39f18f0287534b8cba0b2d..49bdd3933ca1b6b9561e17923f05c0d636d04089 100644 (file)
@@ -74,7 +74,7 @@ void DowntimesTable::FetchRows(const AddRowFunction& addRowFn)
                Downtime::Ptr downtime;
                BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
                        if (Host::GetOwnerByDowntimeID(id) == host)
-                               addRowFn(downtime);
+                               addRowFn(downtime, LivestatusGroupByNone, Empty);
                }
        }
 
@@ -87,7 +87,7 @@ void DowntimesTable::FetchRows(const AddRowFunction& addRowFn)
                Downtime::Ptr downtime;
                BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
                        if (Service::GetOwnerByDowntimeID(id) == service)
-                               addRowFn(downtime);
+                               addRowFn(downtime, LivestatusGroupByNone, Empty);
                }
        }
 }
index c206ecd5d892e63e2a60a8d9fd3b3474354b449f..be546685ff70bcb5a4022276fc43c3241d271c19 100644 (file)
@@ -61,7 +61,7 @@ String EndpointsTable::GetPrefix(void) const
 void EndpointsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjectsByType<Endpoint>()) {
-               addRowFn(endpoint);
+               addRowFn(endpoint, LivestatusGroupByNone, Empty);
        }
 }
 
@@ -110,6 +110,3 @@ Value EndpointsTable::IsConnectedAccessor(const Value& row)
 
        return is_connected;
 }
-
-
-
index db46c5c21e249d63732c31261f4728d968db0160..ee1f6c4c085a51ee25d631d264a30efe227a0d0a 100644 (file)
@@ -74,7 +74,7 @@ String HostGroupsTable::GetPrefix(void) const
 void HostGroupsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const HostGroup::Ptr& hg, DynamicType::GetObjectsByType<HostGroup>()) {
-               addRowFn(hg);
+               addRowFn(hg, LivestatusGroupByNone, Empty);
        }
 }
 
index b477bbc800ddab01d70cf556e7d1563781721d5a..f99549034c4e423fe1859d9495e3e376950e90ad 100644 (file)
  ******************************************************************************/
 
 #include "livestatus/hoststable.hpp"
+#include "livestatus/hostgroupstable.hpp"
+#include "livestatus/endpointstable.hpp"
 #include "icinga/host.hpp"
 #include "icinga/service.hpp"
+#include "icinga/hostgroup.hpp"
 #include "icinga/checkcommand.hpp"
 #include "icinga/eventcommand.hpp"
 #include "icinga/timeperiod.hpp"
 #include "base/json.hpp"
 #include "base/convert.hpp"
 #include "base/utility.hpp"
-#include <boost/algorithm/string/classification.hpp>
 #include <boost/foreach.hpp>
 #include <boost/tuple/tuple.hpp>
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
 
 using namespace icinga;
 
-HostsTable::HostsTable(void)
+HostsTable::HostsTable(LivestatusGroupByType type)
+    :Table(type)
 {
        AddColumns(this);
 }
@@ -162,6 +164,14 @@ void HostsTable::AddColumns(Table *table, const String& prefix,
        table->AddColumn(prefix + "check_source", Column(&HostsTable::CheckSourceAccessor, objectAccessor));
        table->AddColumn(prefix + "is_reachable", Column(&HostsTable::IsReachableAccessor, objectAccessor));
        table->AddColumn(prefix + "cv_is_json", Column(&HostsTable::CVIsJsonAccessor, objectAccessor));
+
+       /* add additional group by values received through the object accessor */
+       if (table->GetGroupByType() == LivestatusGroupByHostGroup) {
+               /* _1 = row, _2 = groupByType, _3 = groupByObject */
+               Log(LogDebug, "Livestatus")
+                   << "Processing hosts group by hostgroup table.";
+               HostGroupsTable::AddColumns(table, "hostgroup_", boost::bind(&HostsTable::HostGroupAccessor, _1, _2, _3));
+       }
 }
 
 String HostsTable::GetName(void) const
@@ -176,11 +186,32 @@ String HostsTable::GetPrefix(void) const
 
 void HostsTable::FetchRows(const AddRowFunction& addRowFn)
 {
-       BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
-               addRowFn(host);
+       if (GetGroupByType() == LivestatusGroupByHostGroup) {
+               BOOST_FOREACH(const HostGroup::Ptr& hg, DynamicType::GetObjectsByType<HostGroup>()) {
+                       BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
+                               /* the caller must know which groupby type and value are set for this row */
+                               addRowFn(host, LivestatusGroupByHostGroup, hg);
+                       }
+               }
+       } else {
+               BOOST_FOREACH(const Host::Ptr& host, DynamicType::GetObjectsByType<Host>()) {
+                       addRowFn(host, LivestatusGroupByNone, Empty);
+               }
        }
 }
 
+Object::Ptr HostsTable::HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject)
+{
+       /* return the current group by value set from within FetchRows()
+        * this is the hostgrouo object used for the table join inside
+        * in AddColumns()
+        */
+       if (groupByType == LivestatusGroupByHostGroup)
+               return groupByObject;
+
+       return Object::Ptr();
+}
+
 Value HostsTable::NameAccessor(const Value& row)
 {
        Host::Ptr host = static_cast<Host::Ptr>(row);
@@ -208,7 +239,6 @@ Value HostsTable::AddressAccessor(const Value& row)
        if (!host)
                return Empty;
 
-
        return host->GetAddress();
 }
 
index 8fb8b01c0a19f91a03643caae2f2a6c2467cc4b9..8b6c61cda5cd036aefefc872ba8a88f93b0be84d 100644 (file)
@@ -35,7 +35,7 @@ class HostsTable : public Table
 public:
        DECLARE_PTR_TYPEDEFS(HostsTable);
 
-       HostsTable(void);
+       HostsTable(LivestatusGroupByType type = LivestatusGroupByNone);
 
        static void AddColumns(Table *table, const String& prefix = String(),
            const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
@@ -46,6 +46,8 @@ public:
 protected:
        virtual void FetchRows(const AddRowFunction& addRowFn);
 
+       static Object::Ptr HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject);
+
        static Value NameAccessor(const Value& row);
        static Value DisplayNameAccessor(const Value& row);
        static Value AddressAccessor(const Value& row);
index ad92901195c423c3ca9940b3e5a19f3a74433fe7..604ed110f18b7d211f9a0d8f358ec6f71693be01 100644 (file)
@@ -495,7 +495,7 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                return;
        }
 
-       std::vector<Value> objects = table->FilterRows(m_Filter);
+       std::vector<LivestatusRowValue> objects = table->FilterRows(m_Filter);
        std::vector<String> columns;
 
        if (m_Columns.size() > 0)
@@ -508,7 +508,7 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
        if (m_Aggregators.empty()) {
                Array::Ptr header = new Array();
 
-               BOOST_FOREACH(const Value& object, objects) {
+               BOOST_FOREACH(const LivestatusRowValue& object, objects) {
                        Array::Ptr row = new Array();
 
                        BOOST_FOREACH(const String& columnName, columns) {
@@ -517,7 +517,7 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                                if (m_ColumnHeaders)
                                        header->Add(columnName);
 
-                               row->Add(column.ExtractValue(object));
+                               row->Add(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject));
                        }
 
                        if (m_ColumnHeaders) {
@@ -533,8 +533,8 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
 
                /* add aggregated stats */
                BOOST_FOREACH(const Aggregator::Ptr aggregator, m_Aggregators) {
-                       BOOST_FOREACH(const Value& object, objects) {
-                               aggregator->Apply(table, object);
+                       BOOST_FOREACH(const LivestatusRowValue& object, objects) {
+                               aggregator->Apply(table, object.Row);
                        }
 
                        stats[index] = aggregator->GetResult();
@@ -566,7 +566,9 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                        BOOST_FOREACH(const String& columnName, m_Columns) {
                                Column column = table->GetColumn(columnName);
 
-                               row->Add(column.ExtractValue(objects[0])); // first object wins
+                               LivestatusRowValue object = objects[0]; //first object wins
+
+                               row->Add(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject));
                        }
                }
 
index 6bc8d90cddeb5a36f298be3bbc8a802257e675fa..cf53c29e95c7e3071db723e2626c3c81124f66b9 100644 (file)
@@ -57,8 +57,6 @@ LogTable::LogTable(const String& compat_log_path, time_t from, time_t until)
        AddColumns(this);
 }
 
-
-
 void LogTable::AddColumns(Table *table, const String& prefix,
     const Column::ObjectAccessor& objectAccessor)
 {
@@ -112,7 +110,7 @@ void LogTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line
        /* additional attributes only for log table */
        log_entry_attrs->Set("lineno", lineno);
 
-       addRowFn(log_entry_attrs);
+       addRowFn(log_entry_attrs, LivestatusGroupByNone, Empty);
 }
 
 Object::Ptr LogTable::HostAccessor(const Value& row, const Column::ObjectAccessor&)
@@ -244,6 +242,3 @@ Value LogTable::CommandNameAccessor(const Value& row)
 {
        return static_cast<Dictionary::Ptr>(row)->Get("command_name");
 }
-
-
-
index 0a3c8ee8ec89a1b5517b8c8ae9e157b79d7dee82..a7c4ac64c98f5336fc5fda9cf28108e577ea7f70 100644 (file)
@@ -65,7 +65,7 @@ String ServiceGroupsTable::GetPrefix(void) const
 void ServiceGroupsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const ServiceGroup::Ptr& sg, DynamicType::GetObjectsByType<ServiceGroup>()) {
-               addRowFn(sg);
+               addRowFn(sg, LivestatusGroupByNone, Empty);
        }
 }
 
index e4240f5644ca15c2ce9046a8e9ac31b6ce9a9ac0..b4576c52743374a534b97e1135f16ba0d44a4e85 100644 (file)
 
 #include "livestatus/servicestable.hpp"
 #include "livestatus/hoststable.hpp"
+#include "livestatus/servicegroupstable.hpp"
+#include "livestatus/hostgroupstable.hpp"
 #include "livestatus/endpointstable.hpp"
 #include "icinga/service.hpp"
+#include "icinga/servicegroup.hpp"
+#include "icinga/hostgroup.hpp"
 #include "icinga/checkcommand.hpp"
 #include "icinga/eventcommand.hpp"
 #include "icinga/timeperiod.hpp"
 
 using namespace icinga;
 
-ServicesTable::ServicesTable(void)
+ServicesTable::ServicesTable(LivestatusGroupByType type)
+    : Table(type)
 {
        AddColumns(this);
 }
 
+
 void ServicesTable::AddColumns(Table *table, const String& prefix,
     const Column::ObjectAccessor& objectAccessor)
 {
@@ -133,6 +139,19 @@ void ServicesTable::AddColumns(Table *table, const String& prefix,
        table->AddColumn(prefix + "cv_is_json", Column(&ServicesTable::CVIsJsonAccessor, objectAccessor));
 
        HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor));
+
+       /* add additional group by values received through the object accessor */
+       if (table->GetGroupByType() == LivestatusGroupByServiceGroup) {
+               /* _1 = row, _2 = groupByType, _3 = groupByObject */
+               Log(LogDebug, "Livestatus")
+                   << "Processing services group by servicegroup table.";
+               ServiceGroupsTable::AddColumns(table, "servicegroup_", boost::bind(&ServicesTable::ServiceGroupAccessor, _1, _2, _3));
+       } else if (table->GetGroupByType() == LivestatusGroupByHostGroup) {
+               /* _1 = row, _2 = groupByType, _3 = groupByObject */
+               Log(LogDebug, "Livestatus")
+                   << "Processing services group by hostgroup table.";
+               HostGroupsTable::AddColumns(table, "hostgroup_", boost::bind(&ServicesTable::HostGroupAccessor, _1, _2, _3));
+       }
 }
 
 String ServicesTable::GetName(void) const
@@ -147,8 +166,28 @@ String ServicesTable::GetPrefix(void) const
 
 void ServicesTable::FetchRows(const AddRowFunction& addRowFn)
 {
-       BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjectsByType<Service>()) {
-               addRowFn(service);
+       if (GetGroupByType() == LivestatusGroupByServiceGroup) {
+               BOOST_FOREACH(const ServiceGroup::Ptr& sg, DynamicType::GetObjectsByType<ServiceGroup>()) {
+                       BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
+                               /* the caller must know which groupby type and value are set for this row */
+                               addRowFn(service, LivestatusGroupByServiceGroup, sg);
+                       }
+               }
+       } else if (GetGroupByType() == LivestatusGroupByHostGroup) {
+               BOOST_FOREACH(const HostGroup::Ptr& hg, DynamicType::GetObjectsByType<HostGroup>()) {
+                       ObjectLock ylock(hg);
+                       BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
+                               ObjectLock ylock(host);
+                               BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
+                                       /* the caller must know which groupby type and value are set for this row */
+                                       addRowFn(service, LivestatusGroupByHostGroup, hg);
+                               }
+                       }
+               }
+       } else {
+               BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjectsByType<Service>()) {
+                       addRowFn(service, LivestatusGroupByNone, Empty);
+               }
        }
 }
 
@@ -157,7 +196,7 @@ Object::Ptr ServicesTable::HostAccessor(const Value& row, const Column::ObjectAc
        Value service;
 
        if (parentObjectAccessor)
-               service = parentObjectAccessor(row);
+               service = parentObjectAccessor(row, LivestatusGroupByNone, Empty);
        else
                service = row;
 
@@ -169,6 +208,30 @@ Object::Ptr ServicesTable::HostAccessor(const Value& row, const Column::ObjectAc
        return svc->GetHost();
 }
 
+Object::Ptr ServicesTable::ServiceGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject)
+{
+       /* return the current group by value set from within FetchRows()
+        * this is the servicegroup object used for the table join inside
+        * in AddColumns()
+        */
+       if (groupByType == LivestatusGroupByServiceGroup)
+               return groupByObject;
+
+       return Object::Ptr();
+}
+
+Object::Ptr ServicesTable::HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject)
+{
+       /* return the current group by value set from within FetchRows()
+        * this is the servicegroup object used for the table join inside
+        * in AddColumns()
+        */
+       if (groupByType == LivestatusGroupByHostGroup)
+               return groupByObject;
+
+       return Object::Ptr();
+}
+
 Value ServicesTable::ShortNameAccessor(const Value& row)
 {
        Service::Ptr service = static_cast<Service::Ptr>(row);
index a222fa56883e8136cc9dea03c9806c48a78e825a..f0f99ca79d569d8de46b1e2a47bd7c173b53fedc 100644 (file)
@@ -35,7 +35,7 @@ class ServicesTable : public Table
 public:
        DECLARE_PTR_TYPEDEFS(ServicesTable);
 
-       ServicesTable(void);
+       ServicesTable(LivestatusGroupByType type = LivestatusGroupByNone);
 
        static void AddColumns(Table *table, const String& prefix = String(),
            const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
@@ -47,6 +47,8 @@ protected:
        virtual void FetchRows(const AddRowFunction& addRowFn);
 
        static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor);
+       static Object::Ptr ServiceGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject);
+       static Object::Ptr HostGroupAccessor(const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject);
 
        static Value ShortNameAccessor(const Value& row);
        static Value DisplayNameAccessor(const Value& row);
index 99a1183cf8f67960e9892679d55362b4b1f0583a..a9008512c971ee6e1b3c5df2e2c18f6ad96a3dd4 100644 (file)
@@ -271,7 +271,7 @@ void StateHistTable::FetchRows(const AddRowFunction& addRowFn)
        BOOST_FOREACH(boost::tie(checkable, boost::tuples::ignore), m_CheckablesCache) {
                BOOST_FOREACH(const Dictionary::Ptr& state_hist_bag, m_CheckablesCache[checkable]) {
                        /* pass a dictionary from state history array */
-                       addRowFn(state_hist_bag);
+                       addRowFn(state_hist_bag, LivestatusGroupByNone, Empty);
                }
        }
 }
index 84a9cc56b7515f0b2b7fb97f3d5a20bf08f4eb4d..2a2078256ffff1fbf9d7e7978124dd624eea5d47 100644 (file)
@@ -118,7 +118,7 @@ void StatusTable::FetchRows(const AddRowFunction& addRowFn)
        Object::Ptr obj = new Object();
 
        /* Return a fake row. */
-       addRowFn(obj);
+       addRowFn(obj, LivestatusGroupByNone, Empty);
 }
 
 Value StatusTable::ConnectionsAccessor(const Value&)
index 20c606591b1e416dd2affd5071fcfe2b7ff2edff..15e5e3c38e0fd7a4e7de1abf7c5db1673d69e4a5 100644 (file)
@@ -42,7 +42,8 @@
 
 using namespace icinga;
 
-Table::Table(void)
+Table::Table(LivestatusGroupByType type)
+    : m_GroupByType(type), m_GroupByObject(Empty)
 { }
 
 Table::Ptr Table::GetByName(const String& name, const String& compat_log_path, const unsigned long& from, const unsigned long& until)
@@ -57,10 +58,16 @@ Table::Ptr Table::GetByName(const String& name, const String& compat_log_path, c
                return new HostGroupsTable();
        else if (name == "hosts")
                return new HostsTable();
+       else if (name == "hostsbygroup")
+               return new HostsTable(LivestatusGroupByHostGroup);
        else if (name == "servicegroups")
                return new ServiceGroupsTable();
        else if (name == "services")
                return new ServicesTable();
+       else if (name == "servicesbygroup")
+               return new ServicesTable(LivestatusGroupByServiceGroup);
+       else if (name == "servicesbyhostgroup")
+               return new ServicesTable(LivestatusGroupByHostGroup);
        else if (name == "commands")
                return new CommandsTable();
        else if (name == "comments")
@@ -117,19 +124,25 @@ std::vector<String> Table::GetColumnNames(void) const
        return names;
 }
 
-std::vector<Value> Table::FilterRows(const Filter::Ptr& filter)
+std::vector<LivestatusRowValue> Table::FilterRows(const Filter::Ptr& filter)
 {
-       std::vector<Value> rs;
+       std::vector<LivestatusRowValue> rs;
 
-       FetchRows(boost::bind(&Table::FilteredAddRow, this, boost::ref(rs), filter, _1));
+       FetchRows(boost::bind(&Table::FilteredAddRow, this, boost::ref(rs), filter, _1, _2, _3));
 
        return rs;
 }
 
-void Table::FilteredAddRow(std::vector<Value>& rs, const Filter::Ptr& filter, const Value& row)
+void Table::FilteredAddRow(std::vector<LivestatusRowValue>& rs, const Filter::Ptr& filter, const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject)
 {
-       if (!filter || filter->Apply(this, row))
-               rs.push_back(row);
+       if (!filter || filter->Apply(this, row)) {
+               LivestatusRowValue rval;
+               rval.Row = row;
+               rval.GroupByType = groupByType;
+               rval.GroupByObject = groupByObject;
+
+               rs.push_back(rval);
+       }
 }
 
 Value Table::ZeroAccessor(const Value&)
@@ -156,3 +169,8 @@ Value Table::EmptyDictionaryAccessor(const Value&)
 {
        return new Dictionary();
 }
+
+LivestatusGroupByType Table::GetGroupByType(void) const
+{
+       return m_GroupByType;
+}
index fb348e18c8bb42be79211639b9d0e538a759c7fe..e27ed020148c4279b06d8134d343e178fc31330f 100644 (file)
 #include "livestatus/column.hpp"
 #include "base/object.hpp"
 #include "base/dictionary.hpp"
+#include "base/array.hpp"
 #include <vector>
 
 namespace icinga
 {
 
-typedef boost::function<void (const Value&)> AddRowFunction;
+struct LivestatusRowValue {
+       Value Row;
+       LivestatusGroupByType GroupByType;
+       Value GroupByObject;
+};
+
+
+typedef boost::function<void (const Value&, LivestatusGroupByType, const Object::Ptr&)> AddRowFunction;
 
 class Filter;
 
@@ -45,14 +53,16 @@ public:
        virtual String GetName(void) const = 0;
        virtual String GetPrefix(void) const = 0;
 
-       std::vector<Value> FilterRows(const intrusive_ptr<Filter>& filter);
+       std::vector<LivestatusRowValue> FilterRows(const intrusive_ptr<Filter>& filter);
 
        void AddColumn(const String& name, const Column& column);
        Column GetColumn(const String& name) const;
        std::vector<String> GetColumnNames(void) const;
 
+       virtual LivestatusGroupByType GetGroupByType(void) const;
+
 protected:
-       Table(void);
+       Table(LivestatusGroupByType type = LivestatusGroupByNone);
 
        virtual void FetchRows(const AddRowFunction& addRowFn) = 0;
 
@@ -62,10 +72,13 @@ protected:
        static Value EmptyArrayAccessor(const Value&);
        static Value EmptyDictionaryAccessor(const Value&);
 
+       LivestatusGroupByType m_GroupByType;
+       Value m_GroupByObject;
+
 private:
        std::map<String, Column> m_Columns;
 
-       void FilteredAddRow(std::vector<Value>& rs, const intrusive_ptr<Filter>& filter, const Value& row);
+       void FilteredAddRow(std::vector<LivestatusRowValue>& rs, const intrusive_ptr<Filter>& filter, const Value& row, LivestatusGroupByType groupByType, const Object::Ptr& groupByObject);
 };
 
 }
index 479a0708615d9807ba7f2ee1daba06a9d0d53599..66de70bb2d39839188add11da3a2bda920ea7795 100644 (file)
@@ -55,7 +55,7 @@ String TimePeriodsTable::GetPrefix(void) const
 void TimePeriodsTable::FetchRows(const AddRowFunction& addRowFn)
 {
        BOOST_FOREACH(const TimePeriod::Ptr& tp, DynamicType::GetObjectsByType<TimePeriod>()) {
-               addRowFn(tp);
+               addRowFn(tp, LivestatusGroupByNone, Empty);
        }
 }
 
@@ -73,5 +73,3 @@ Value TimePeriodsTable::InAccessor(const Value& row)
 {
        return (static_cast<TimePeriod::Ptr>(row)->IsInside(Utility::GetTime()) ? 1 : 0);
 }
-
-
diff --git a/test/livestatus/queries/hosts/bygroup b/test/livestatus/queries/hosts/bygroup
new file mode 100644 (file)
index 0000000..7485efc
--- /dev/null
@@ -0,0 +1,4 @@
+GET hostsbygroup
+Columns: hostgroup_name host_name
+ResponseHeader: fixed16
+
diff --git a/test/livestatus/queries/services/bygroup b/test/livestatus/queries/services/bygroup
new file mode 100644 (file)
index 0000000..668e5f1
--- /dev/null
@@ -0,0 +1,4 @@
+GET servicesbygroup
+Columns: servicegroup_name host_name service_description
+ResponseHeader: fixed16
+
diff --git a/test/livestatus/queries/services/byhostgroup b/test/livestatus/queries/services/byhostgroup
new file mode 100644 (file)
index 0000000..ddcdbe8
--- /dev/null
@@ -0,0 +1,4 @@
+GET servicesbyhostgroup
+Columns: hostgroup_name host_name service_description
+ResponseHeader: fixed16
+