Implement basic livestatus GET queries.

This commit is contained in:
Gunnar Beutner 2013-03-10 09:23:13 +01:00
parent 98ba1424b5
commit d7efa9e24c
17 changed files with 456 additions and 50 deletions

View File

@ -4,14 +4,18 @@ pkglib_LTLIBRARIES = \
livestatus.la
livestatus_la_SOURCES = \
livestatuscomponent.cpp \
livestatuscomponent.h \
livestatusconnection.cpp \
livestatusconnection.h \
livestatusquery.cpp \
livestatusquery.h \
livestatustable.cpp \
livestatustable.h \
component.cpp \
component.h \
connection.cpp \
connection.h \
filter.cpp \
filter.h \
query.cpp \
query.h \
statustable.cpp \
statustable.h \
table.cpp \
table.h \
i2-livestatus.h
livestatus_la_CPPFLAGS = \

View File

@ -20,6 +20,7 @@
#include "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
REGISTER_COMPONENT("livestatus", LivestatusComponent);

View File

@ -20,7 +20,7 @@
#ifndef LIVESTATUSCOMPONENT_H
#define LIVESTATUSCOMPONENT_H
namespace icinga
namespace livestatus
{
/**

View File

@ -20,6 +20,7 @@
#include "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
LivestatusConnection::LivestatusConnection(const Stream::Ptr& stream)
: Connection(stream)
@ -47,7 +48,7 @@ void LivestatusConnection::ProcessData(void)
if (line.GetLength() > 0 && !GetStream()->IsReadEOF())
return;
LivestatusQuery::Ptr query = boost::make_shared<LivestatusQuery>(m_Lines);
Query::Ptr query = boost::make_shared<Query>(m_Lines);
m_Lines.clear();
query->Execute(GetStream());

View File

@ -20,7 +20,7 @@
#ifndef LIVESTATUSCONNECTION_H
#define LIVESTATUSCONNECTION_H
namespace icinga
namespace livestatus
{
class LivestatusConnection : public Connection

View File

@ -0,0 +1,26 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
Filter::Filter(void)
{ }

View File

@ -0,0 +1,43 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 FILTER_H
#define FILTER_H
namespace livestatus
{
/**
* @ingroup livestatus
*/
class Filter : public Object
{
public:
typedef shared_ptr<Filter> Ptr;
typedef weak_ptr<Filter> WeakPtr;
virtual bool Apply(const Object::Ptr& object) = 0;
protected:
Filter(void);
};
}
#endif /* FILTER_H */

View File

@ -30,9 +30,13 @@
#include <i2-remoting.h>
#include <i2-icinga.h>
#include "livestatusconnection.h"
#include "livestatusquery.h"
#include "livestatustable.h"
#include "livestatuscomponent.h"
using namespace icinga;
#include "connection.h"
#include "query.h"
#include "filter.h"
#include "table.h"
#include "statustable.h"
#include "component.h"
#endif /* I2LIVESTATUS_H */

View File

@ -19,17 +19,21 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="filter.h" />
<ClInclude Include="i2-livestatus.h" />
<ClInclude Include="livestatuscomponent.h" />
<ClInclude Include="livestatusconnection.h" />
<ClInclude Include="livestatusquery.h" />
<ClInclude Include="livestatustable.h" />
<ClInclude Include="component.h" />
<ClInclude Include="connection.h" />
<ClInclude Include="query.h" />
<ClInclude Include="statustable.h" />
<ClInclude Include="table.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="livestatuscomponent.cpp" />
<ClCompile Include="livestatusconnection.cpp" />
<ClCompile Include="livestatusquery.cpp" />
<ClCompile Include="livestatustable.cpp" />
<ClCompile Include="component.cpp" />
<ClCompile Include="connection.cpp" />
<ClCompile Include="filter.cpp" />
<ClCompile Include="query.cpp" />
<ClCompile Include="statustable.cpp" />
<ClCompile Include="table.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{950E8743-BB34-4F8A-99EC-C87E8FC0EB3F}</ProjectGuid>

View File

@ -12,30 +12,42 @@
<ClInclude Include="i2-livestatus.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="livestatuscomponent.h">
<ClInclude Include="connection.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="livestatusconnection.h">
<ClInclude Include="component.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="livestatusquery.h">
<ClInclude Include="query.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="livestatustable.h">
<ClInclude Include="table.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="statustable.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="filter.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="livestatuscomponent.cpp">
<ClCompile Include="component.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="livestatustable.cpp">
<ClCompile Include="connection.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="livestatusconnection.cpp">
<ClCompile Include="query.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="livestatusquery.cpp">
<ClCompile Include="table.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="statustable.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="filter.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>

View File

@ -20,11 +20,10 @@
#include "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
LivestatusQuery::LivestatusQuery(const vector<String>& lines)
: m_KeepAlive(false), m_ColumnHeaders(true), m_Limit(-1)
Query::Query(const vector<String>& lines)
: m_OutputFormat("csv"), m_KeepAlive(false), m_ColumnHeaders(true), m_Limit(-1)
{
String line = lines[0];
@ -55,15 +54,100 @@ LivestatusQuery::LivestatusQuery(const vector<String>& lines)
if (header == "ResponseHeader")
m_ResponseHeader = params;
else if (header == "OutputFormat")
m_OutputFormat = params;
else if (header == "Columns")
m_Columns = params.Split(is_any_of(" "));
}
}
void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
void Query::PrintResultSet(ostream& fp, const vector<String>& columns, const Array::Ptr& rs)
{
Logger::Write(LogInformation, "livestatus", "Table: " + m_Table);
if (m_OutputFormat == "csv" && m_Columns.size() == 0) {
bool first = true;
BOOST_FOREACH(const String& column, columns) {
if (first)
first = false;
else
fp << ";";
fp << column;
}
fp << "\n";
}
if (m_OutputFormat == "csv") {
ObjectLock olock(rs);
BOOST_FOREACH(const Array::Ptr& row, rs) {
bool first = true;
ObjectLock rlock(row);
BOOST_FOREACH(const Value& value, row) {
if (first)
first = false;
else
fp << ";";
fp << Convert::ToString(value);
}
fp << "\n";
}
} else if (m_OutputFormat == "json") {
fp << Value(rs).Serialize();
}
}
void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream)
void Query::ExecuteGetHelper(const Stream::Ptr& stream)
{
Logger::Write(LogInformation, "livestatus", "Table: " + m_Table);
Table::Ptr table = Table::GetByName(m_Table);
if (!table) {
SendResponse(stream, 404, "Table '" + m_Table + "' does not exist.");
return;
}
vector<Object::Ptr> objects = table->FilterRows(Filter::Ptr());
vector<String> columns;
if (m_Columns.size() > 0)
columns = m_Columns;
else
columns = table->GetColumnNames();
Array::Ptr rs = boost::make_shared<Array>();
BOOST_FOREACH(const Object::Ptr& object, objects) {
Array::Ptr row = boost::make_shared<Array>();
BOOST_FOREACH(const String& column, columns) {
Table::ColumnAccessor accessor = table->GetColumn(column);
if (accessor.empty()) {
SendResponse(stream, 450, "Column '" + column + "' does not exist.");
return;
}
row->Add(accessor(object));
}
rs->Add(row);
}
stringstream result;
PrintResultSet(result, columns, rs);
SendResponse(stream, 200, result.str());
}
void Query::ExecuteCommandHelper(const Stream::Ptr& stream)
{
try {
Logger::Write(LogInformation, "livestatus", "Executing command: " + m_Command);
@ -74,12 +158,12 @@ void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream)
}
}
void LivestatusQuery::ExecuteErrorHelper(const Stream::Ptr& stream)
void Query::ExecuteErrorHelper(const Stream::Ptr& stream)
{
PrintFixed16(stream, m_ErrorCode, m_ErrorMessage);
}
void LivestatusQuery::SendResponse(const Stream::Ptr& stream, int code, const String& data)
void Query::SendResponse(const Stream::Ptr& stream, int code, const String& data)
{
if (m_ResponseHeader == "fixed16")
PrintFixed16(stream, code, data);
@ -88,7 +172,7 @@ void LivestatusQuery::SendResponse(const Stream::Ptr& stream, int code, const St
stream->Write(data.CStr(), data.GetLength());
}
void LivestatusQuery::PrintFixed16(const Stream::Ptr& stream, int code, const String& data)
void Query::PrintFixed16(const Stream::Ptr& stream, int code, const String& data)
{
ASSERT(code >= 100 && code <= 999);
@ -99,7 +183,7 @@ void LivestatusQuery::PrintFixed16(const Stream::Ptr& stream, int code, const St
stream->Write(header.CStr(), header.GetLength());
}
void LivestatusQuery::Execute(const Stream::Ptr& stream)
void Query::Execute(const Stream::Ptr& stream)
{
Logger::Write(LogInformation, "livestatus", "Executing livestatus query: " + m_Verb);

View File

@ -17,22 +17,22 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef LIVESTATUSQUERY_H
#define LIVESTATUSQUERY_H
#ifndef QUERY_H
#define QUERY_H
namespace icinga
namespace livestatus
{
/**
* @ingroup livestatus
*/
class LivestatusQuery : public Object
class Query : public Object
{
public:
typedef shared_ptr<LivestatusQuery> Ptr;
typedef weak_ptr<LivestatusQuery> WeakPtr;
typedef shared_ptr<Query> Ptr;
typedef weak_ptr<Query> WeakPtr;
LivestatusQuery(const vector<String>& lines);
Query(const vector<String>& lines);
void Execute(const Stream::Ptr& stream);
@ -58,6 +58,8 @@ private:
int m_ErrorCode;
String m_ErrorMessage;
void PrintResultSet(ostream& fp, const vector<String>& columns, const Array::Ptr& rs);
void ExecuteGetHelper(const Stream::Ptr& stream);
void ExecuteCommandHelper(const Stream::Ptr& stream);
void ExecuteErrorHelper(const Stream::Ptr& stream);
@ -68,4 +70,4 @@ private:
}
#endif /* LIVESTATUSQUERY_H */
#endif /* QUERY_H */

View File

@ -0,0 +1,99 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
StatusTable::StatusTable(void)
{
AddColumn("neb_callbacks", &Table::ZeroAccessor);
AddColumn("neb_callbacks_rate", &Table::ZeroAccessor);
AddColumn("requests", &Table::ZeroAccessor);
AddColumn("requests_rate", &Table::ZeroAccessor);
AddColumn("connections", &Table::ZeroAccessor);
AddColumn("connections_rate", &Table::ZeroAccessor);
AddColumn("service_checks", &Table::ZeroAccessor);
AddColumn("service_checks_rate", &Table::ZeroAccessor);
AddColumn("host_checks", &Table::ZeroAccessor);
AddColumn("host_checks_rate", &Table::ZeroAccessor);
AddColumn("forks", &Table::ZeroAccessor);
AddColumn("forks_rate", &Table::ZeroAccessor);
AddColumn("log_messages", &Table::ZeroAccessor);
AddColumn("log_messages_rate", &Table::ZeroAccessor);
AddColumn("external_commands", &Table::ZeroAccessor);
AddColumn("external_commands_rate", &Table::ZeroAccessor);
AddColumn("livechecks", &Table::ZeroAccessor);
AddColumn("livechecks_rate", &Table::ZeroAccessor);
AddColumn("livecheck_overflows", &Table::ZeroAccessor);
AddColumn("livecheck_overflows_rate", &Table::ZeroAccessor);
AddColumn("nagios_pid", &Table::ZeroAccessor);
AddColumn("enable_notifications", &Table::ZeroAccessor);
AddColumn("execute_service_checks", &Table::ZeroAccessor);
AddColumn("accept_passive_service_checks", &Table::ZeroAccessor);
AddColumn("execute_host_checks", &Table::ZeroAccessor);
AddColumn("accept_passive_host_checks", &Table::ZeroAccessor);
AddColumn("enable_event_handlers", &Table::ZeroAccessor);
AddColumn("obsess_over_services", &Table::ZeroAccessor);
AddColumn("obsess_over_hosts", &Table::ZeroAccessor);
AddColumn("check_service_freshness", &Table::ZeroAccessor);
AddColumn("check_host_freshness", &Table::ZeroAccessor);
AddColumn("enable_flap_detection", &Table::ZeroAccessor);
AddColumn("process_performance_data", &Table::ZeroAccessor);
AddColumn("check_external_commands", &Table::ZeroAccessor);
AddColumn("program_start", &Table::ZeroAccessor);
AddColumn("last_command_check", &Table::ZeroAccessor);
AddColumn("last_log_rotation", &Table::ZeroAccessor);
AddColumn("interval_length", &Table::ZeroAccessor);
AddColumn("num_hosts", &Table::ZeroAccessor);
AddColumn("num_services", &Table::ZeroAccessor);
AddColumn("program_version", &Table::ZeroAccessor);
AddColumn("external_command_buffer_slots", &Table::ZeroAccessor);
AddColumn("external_command_buffer_usage", &Table::ZeroAccessor);
AddColumn("external_command_buffer_max", &Table::ZeroAccessor);
AddColumn("cached_log_messages", &Table::ZeroAccessor);
AddColumn("livestatus_version", &Table::ZeroAccessor);
AddColumn("livestatus_active_connections", &Table::ZeroAccessor);
AddColumn("livestatus_queued_connections", &Table::ZeroAccessor);
AddColumn("livestatus_threads", &Table::ZeroAccessor);
}
String StatusTable::GetName(void) const
{
return "status";
}
void StatusTable::FetchRows(const function<void (const Object::Ptr&)>& addRowFn)
{
Object::Ptr obj = boost::make_shared<Object>();
/* Return a fake row. */
addRowFn(obj);
}

View File

@ -0,0 +1,45 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 STATUSTABLE_H
#define STATUSTABLE_H
namespace livestatus
{
/**
* @ingroup livestatus
*/
class StatusTable : public Table
{
public:
typedef shared_ptr<StatusTable> Ptr;
typedef weak_ptr<StatusTable> WeakPtr;
StatusTable(void);
virtual String GetName(void) const;
protected:
virtual void FetchRows(const function<void (const Object::Ptr&)>& addRowFn);
};
}
#endif /* STATUSTABLE_H */

View File

@ -0,0 +1,81 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 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 "i2-livestatus.h"
using namespace icinga;
using namespace livestatus;
Table::Table(void)
{ }
Table::Ptr Table::GetByName(const String& name)
{
if (name == "status")
return boost::make_shared<StatusTable>();
return Table::Ptr();
}
void Table::AddColumn(const String& name, const ColumnAccessor& accessor)
{
m_Columns[name] = accessor;
}
Table::ColumnAccessor Table::GetColumn(const String& name) const
{
map<String, ColumnAccessor>::const_iterator it = m_Columns.find(name);
if (it == m_Columns.end())
return ColumnAccessor();
return it->second;
}
vector<String> Table::GetColumnNames(void) const
{
vector<String> names;
String name;
BOOST_FOREACH(tie(name, tuples::ignore), m_Columns) {
names.push_back(name);
}
return names;
}
vector<Object::Ptr> Table::FilterRows(const Filter::Ptr& filter)
{
vector<Object::Ptr> rs;
FetchRows(boost::bind(&Table::FilteredAddRow, boost::ref(rs), filter, _1));
return rs;
}
void Table::FilteredAddRow(vector<Object::Ptr>& rs, const Filter::Ptr& filter, const Object::Ptr& object)
{
if (!filter || filter->Apply(object))
rs.push_back(object);
}
Value Table::ZeroAccessor(const Object::Ptr&)
{
return 0;
}