: 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;
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;
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;
Comment::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {
if (Host::GetOwnerByCommentID(id) == host)
- addRowFn(comment);
+ addRowFn(comment, LivestatusGroupByNone, Empty);
}
}
Comment::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) {
if (Service::GetOwnerByCommentID(id) == service)
- addRowFn(comment);
+ addRowFn(comment, LivestatusGroupByNone, Empty);
}
}
}
void ContactGroupsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const UserGroup::Ptr& ug, DynamicType::GetObjectsByType<UserGroup>()) {
- addRowFn(ug);
+ addRowFn(ug, LivestatusGroupByNone, Empty);
}
}
void ContactsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const User::Ptr& user, DynamicType::GetObjectsByType<User>()) {
- addRowFn(user);
+ addRowFn(user, LivestatusGroupByNone, Empty);
}
}
Downtime::Ptr downtime;
BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
if (Host::GetOwnerByDowntimeID(id) == host)
- addRowFn(downtime);
+ addRowFn(downtime, LivestatusGroupByNone, Empty);
}
}
Downtime::Ptr downtime;
BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
if (Service::GetOwnerByDowntimeID(id) == service)
- addRowFn(downtime);
+ addRowFn(downtime, LivestatusGroupByNone, Empty);
}
}
}
void EndpointsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjectsByType<Endpoint>()) {
- addRowFn(endpoint);
+ addRowFn(endpoint, LivestatusGroupByNone, Empty);
}
}
return is_connected;
}
-
-
-
void HostGroupsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const HostGroup::Ptr& hg, DynamicType::GetObjectsByType<HostGroup>()) {
- addRowFn(hg);
+ addRowFn(hg, LivestatusGroupByNone, Empty);
}
}
******************************************************************************/
#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);
}
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
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);
if (!host)
return Empty;
-
return host->GetAddress();
}
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());
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);
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)
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) {
if (m_ColumnHeaders)
header->Add(columnName);
- row->Add(column.ExtractValue(object));
+ row->Add(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject));
}
if (m_ColumnHeaders) {
/* 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();
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));
}
}
AddColumns(this);
}
-
-
void LogTable::AddColumns(Table *table, const String& prefix,
const Column::ObjectAccessor& objectAccessor)
{
/* 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&)
{
return static_cast<Dictionary::Ptr>(row)->Get("command_name");
}
-
-
-
void ServiceGroupsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const ServiceGroup::Ptr& sg, DynamicType::GetObjectsByType<ServiceGroup>()) {
- addRowFn(sg);
+ addRowFn(sg, LivestatusGroupByNone, Empty);
}
}
#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)
{
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
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);
+ }
}
}
Value service;
if (parentObjectAccessor)
- service = parentObjectAccessor(row);
+ service = parentObjectAccessor(row, LivestatusGroupByNone, Empty);
else
service = row;
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);
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());
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);
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);
}
}
}
Object::Ptr obj = new Object();
/* Return a fake row. */
- addRowFn(obj);
+ addRowFn(obj, LivestatusGroupByNone, Empty);
}
Value StatusTable::ConnectionsAccessor(const Value&)
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)
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")
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&)
{
return new Dictionary();
}
+
+LivestatusGroupByType Table::GetGroupByType(void) const
+{
+ return m_GroupByType;
+}
#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;
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;
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);
};
}
void TimePeriodsTable::FetchRows(const AddRowFunction& addRowFn)
{
BOOST_FOREACH(const TimePeriod::Ptr& tp, DynamicType::GetObjectsByType<TimePeriod>()) {
- addRowFn(tp);
+ addRowFn(tp, LivestatusGroupByNone, Empty);
}
}
{
return (static_cast<TimePeriod::Ptr>(row)->IsInside(Utility::GetTime()) ? 1 : 0);
}
-
-
--- /dev/null
+GET hostsbygroup
+Columns: hostgroup_name host_name
+ResponseHeader: fixed16
+
--- /dev/null
+GET servicesbygroup
+Columns: servicegroup_name host_name service_description
+ResponseHeader: fixed16
+
--- /dev/null
+GET servicesbyhostgroup
+Columns: hostgroup_name host_name service_description
+ResponseHeader: fixed16
+