Implement status api handler

Global statistics, features, etc.

fixes #10116
This commit is contained in:
Jean-Marcel Flach 2015-09-21 11:44:58 +02:00 committed by Michael Friedrich
parent e19a36c659
commit 4ef9761fee
23 changed files with 279 additions and 26 deletions

View File

@ -123,9 +123,10 @@ Once the API user is configured make sure to restart Icinga 2:
Now pass the basic auth information to curl and send a GET request to the API:
$ curl -u root:icinga -k -s 'https://nbmif.int.netways.de:5665/v1'
$ curl -u root:icinga -k -s 'https://localhost:5665/v1'
In case you will get `Unauthorized` make sure to check the API user credentials.
In case you will get an `Unauthorized` error message make sure to
check the API user credentials.
### <a id="icinga2-api-permissions"></a> Permissions
@ -187,26 +188,27 @@ The Icinga 2 API provides multiple url endpoints
/v1/actions | Endpoint for running specific [API actions](9-icinga2-api.md#icinga2-api-actions).
/v1/config | Endpoint for [managing configuration modules](9-icinga2-api.md#icinga2-api-config-management).
/v1/events | Endpoint for subscribing to [API events](9-icinga2-api.md#icinga2-api-actions).
/v1/types | Endpoint for listing Icinga 2 configuration object types and their attributes.
/v1/status | Endpoint for receiving icinga2 [status and statistics](9-icinga2-api.md#icinga2-api-status).
/v1/types | Endpoint for listing Icinga 2 configuration object types and their attributes.
Additionally there are endpoints for each [config object type](6-object-types.md#object-types):
**TODO** Update
Url Endpoints | Description
----------------------|----------------------------------------------------
/v1/hosts | Endpoint for retreiving and updating [Host](6-object-types.md#objecttype-host) objects.
------------------|----------------------------------------------------
/v1/hosts | Endpoint for retreiving and updating [Host](6-object-types.md#objecttype-host) objects.
/v1/services | Endpoint for retreiving and updating [Service](6-object-types.md#objecttype-service) objects.
/v1/notifications | Endpoint for retreiving and updating [Notification](6-object-types.md#objecttype-notification) objects.
/v1/dependencies | Endpoint for retreiving and updating [Dependency](6-object-types.md#objecttype-dependency) objects.
/v1/users | Endpoint for retreiving and updating [User](6-object-types.md#objecttype-user) objects.
/v1/users | Endpoint for retreiving and updating [User](6-object-types.md#objecttype-user) objects.
/v1/checkcommands | Endpoint for retreiving and updating [CheckCommand](6-object-types.md#objecttype-checkcommand) objects.
/v1/eventcommands | Endpoint for retreiving and updating [EventCommand](6-object-types.md#objecttype-eventcommand) objects.
/v1/notificationcommands | Endpoint for retreiving and updating [NotificationCommand](6-object-types.md#objecttype-notificationcommand) objects.
/v1/hostgroups | Endpoint for retreiving and updating [HostGroup](6-object-types.md#objecttype-hostgroup) objects.
/v1/servicegroups | Endpoint for retreiving and updating [ServiceGroup](6-object-types.md#objecttype-servicegroup) objects.
/v1/usergroups | Endpoint for retreiving and updating [UserGroup](6-object-types.md#objecttype-usergroup) objects.
/v1/zones | Endpoint for retreiving and updating [Zone](6-object-types.md#objecttype-zone) objects.
/v1/zones | Endpoint for retreiving and updating [Zone](6-object-types.md#objecttype-zone) objects.
/v1/endpoints | Endpoint for retreiving and updating [Endpoint](6-object-types.md#objecttype-endpoint) objects.
/v1/timeperiods | Endpoint for retreiving and updating [TimePeriod](6-object-types.md#objecttype-timeperiod) objects.
@ -295,6 +297,56 @@ Reschedule a service check for all services in NOT-OK state:
**TODO** https://dev.icinga.org/issues/9078
## <a id="icinga2-api-status"></a> Status and Statistics
Contains a list of sub url endpoints which provide the status and statistics
of available and enabled features. Any filters are ignored.
Example for the main url endpoint `/v1/status`:
$ curl -k -s -u root:icinga 'https://localhost:5665/v1/status' | python -m json.tool
{
"results": [
{
"name": "ApiListener"
},
...
{
"name": "Collection"
},
...
]
}
`/v1/status/Collection` is always available as virtual status url endpoint.
It provides all feature status information into a collected overview.
Example for the icinga application url endpoint `/v1/status/IcingaApplication`:
$ curl -k -s -u root:icinga 'https://localhost:5665/v1/status/IcingaApplication' | python -m json.tool
{
"results": [
{
"perfdata": [],
"status": {
"icingaapplication": {
"app": {
"enable_event_handlers": true,
"enable_flapping": true,
"enable_host_checks": true,
"enable_notifications": true,
"enable_perfdata": true,
"enable_service_checks": true,
"node_name": "mbmif.int.netways.de",
"pid": 59819.0,
"program_start": 1443019345.093372,
"version": "v2.3.0-573-g380a131"
}
}
}
}
]
}
## <a id="icinga2-api-objects"></a> API Objects

View File

@ -28,7 +28,7 @@ using namespace icinga;
REGISTER_TYPE(FileLogger);
REGISTER_STATSFUNCTION(FileLoggerStats, &FileLogger::StatsFunc);
REGISTER_STATSFUNCTION(FileLogger, &FileLogger::StatsFunc);
void FileLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -28,7 +28,7 @@ using namespace icinga;
REGISTER_TYPE(SyslogLogger);
REGISTER_STATSFUNCTION(SyslogLoggerStats, &SyslogLogger::StatsFunc);
REGISTER_STATSFUNCTION(SyslogLogger, &SyslogLogger::StatsFunc);
void SyslogLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -36,7 +36,7 @@ using namespace icinga;
REGISTER_TYPE(CheckerComponent);
REGISTER_STATSFUNCTION(CheckerComponentStats, &CheckerComponent::StatsFunc);
REGISTER_STATSFUNCTION(CheckerComponent, &CheckerComponent::StatsFunc);
void CheckerComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{

View File

@ -38,7 +38,7 @@ using namespace icinga;
REGISTER_TYPE(CheckResultReader);
REGISTER_STATSFUNCTION(CheckResultReaderStats, &CheckResultReader::StatsFunc);
REGISTER_STATSFUNCTION(CheckResultReader, &CheckResultReader::StatsFunc);
void CheckResultReader::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -41,7 +41,7 @@ using namespace icinga;
REGISTER_TYPE(CompatLogger);
REGISTER_STATSFUNCTION(CompatLoggerStats, &CompatLogger::StatsFunc);
REGISTER_STATSFUNCTION(CompatLogger, &CompatLogger::StatsFunc);
void CompatLogger::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -30,7 +30,7 @@ using namespace icinga;
REGISTER_TYPE(ExternalCommandListener);
REGISTER_STATSFUNCTION(ExternalCommandListenerStats, &ExternalCommandListener::StatsFunc);
REGISTER_STATSFUNCTION(ExternalCommandListener, &ExternalCommandListener::StatsFunc);
void ExternalCommandListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -48,7 +48,7 @@ using namespace icinga;
REGISTER_TYPE(StatusDataWriter);
REGISTER_STATSFUNCTION(StatusDataWriterStats, &StatusDataWriter::StatsFunc);
REGISTER_STATSFUNCTION(StatusDataWriter, &StatusDataWriter::StatsFunc);
void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -36,7 +36,7 @@
using namespace icinga;
REGISTER_TYPE(IdoMysqlConnection);
REGISTER_STATSFUNCTION(IdoMysqlConnectionStats, &IdoMysqlConnection::StatsFunc);
REGISTER_STATSFUNCTION(IdoMysqlConnection, &IdoMysqlConnection::StatsFunc);
IdoMysqlConnection::IdoMysqlConnection(void)
: m_QueryQueue(500000)

View File

@ -38,7 +38,7 @@ using namespace icinga;
REGISTER_TYPE(IdoPgsqlConnection);
REGISTER_STATSFUNCTION(IdoPgsqlConnectionStats, &IdoPgsqlConnection::StatsFunc);
REGISTER_STATSFUNCTION(IdoPgsqlConnection, &IdoPgsqlConnection::StatsFunc);
IdoPgsqlConnection::IdoPgsqlConnection(void)
: m_QueryQueue(500000)

View File

@ -20,6 +20,7 @@
#include "icinga/cib.hpp"
#include "icinga/host.hpp"
#include "icinga/service.hpp"
#include "icinga/perfdatavalue.hpp"
#include "base/objectlock.hpp"
#include "base/utility.hpp"
#include "base/configtype.hpp"
@ -256,3 +257,62 @@ std::pair<Dictionary::Ptr, Array::Ptr> CIB::GetFeatureStats(void)
return std::make_pair(status, perfdata);
}
REGISTER_STATSFUNCTION(CIB, &CIB::StatsFunc);
void CIB::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) {
double interval = Utility::GetTime() - Application::GetStartTime();
if (interval > 60)
interval = 60;
status->Set("active_host_checks", GetActiveHostChecksStatistics(interval) / interval);
status->Set("passive_host_checks", GetPassiveHostChecksStatistics(interval) / interval);
status->Set("active_host_checks_1min", GetActiveHostChecksStatistics(60));
status->Set("passive_host_checks_1min", GetPassiveHostChecksStatistics(60));
status->Set("active_host_checks_5min", GetActiveHostChecksStatistics(60 * 5));
status->Set("passive_host_checks_5min", GetPassiveHostChecksStatistics(60 * 5));
status->Set("active_host_checks_15min", GetActiveHostChecksStatistics(60 * 15));
status->Set("passive_host_checks_15min", GetPassiveHostChecksStatistics(60 * 15));
status->Set("active_service_checks", GetActiveServiceChecksStatistics(interval) / interval);
status->Set("passive_service_checks", GetPassiveServiceChecksStatistics(interval) / interval);
status->Set("active_service_checks_1min", GetActiveServiceChecksStatistics(60));
status->Set("passive_service_checks_1min", GetPassiveServiceChecksStatistics(60));
status->Set("active_service_checks_5min", GetActiveServiceChecksStatistics(60 * 5));
status->Set("passive_service_checks_5min", GetPassiveServiceChecksStatistics(60 * 5));
status->Set("active_service_checks_15min", GetActiveServiceChecksStatistics(60 * 15));
status->Set("passive_service_checks_15min", GetPassiveServiceChecksStatistics(60 * 15));
CheckableCheckStatistics scs = CalculateServiceCheckStats();
status->Set("min_latency", scs.min_latency);
status->Set("max_latency", scs.max_latency);
status->Set("avg_latency", scs.avg_latency);
status->Set("min_execution_time", scs.min_latency);
status->Set("max_execution_time", scs.max_latency);
status->Set("avg_execution_time", scs.avg_execution_time);
ServiceStatistics ss = CalculateServiceStats();
status->Set("num_services_ok", ss.services_ok);
status->Set("num_services_warning", ss.services_warning);
status->Set("num_services_critical", ss.services_critical);
status->Set("num_services_unknown", ss.services_unknown);
status->Set("num_services_pending", ss.services_pending);
status->Set("num_services_unreachable", ss.services_unreachable);
status->Set("num_services_flapping", ss.services_flapping);
status->Set("num_services_in_downtime", ss.services_in_downtime);
status->Set("num_services_acknowledged", ss.services_acknowledged);
double uptime = Utility::GetTime() - Application::GetStartTime();
status->Set("uptime", uptime);
HostStatistics hs = CalculateHostStats();
status->Set("num_hosts_up", hs.hosts_up);
status->Set("num_hosts_down", hs.hosts_down);
status->Set("num_hosts_unreachable", hs.hosts_unreachable);
status->Set("num_hosts_flapping", hs.hosts_flapping);
status->Set("num_hosts_in_downtime", hs.hosts_in_downtime);
status->Set("num_hosts_acknowledged", hs.hosts_acknowledged);
}

View File

@ -87,6 +87,8 @@ public:
static std::pair<Dictionary::Ptr, Array::Ptr> GetFeatureStats(void);
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
private:
CIB(void);

View File

@ -60,7 +60,7 @@ void IcingaApplication::StaticInitialize(void)
ScriptGlobal::Set("ApplicationType", "IcingaApplication");
}
REGISTER_STATSFUNCTION(IcingaApplicationStats, &IcingaApplication::StatsFunc);
REGISTER_STATSFUNCTION(IcingaApplication, &IcingaApplication::StatsFunc);
void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{

View File

@ -34,7 +34,7 @@ using namespace icinga;
REGISTER_TYPE(IcingaStatusWriter);
REGISTER_STATSFUNCTION(IcingaStatusWriterStats, &IcingaStatusWriter::StatsFunc);
REGISTER_STATSFUNCTION(IcingaStatusWriter, &IcingaStatusWriter::StatsFunc);
void IcingaStatusWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{

View File

@ -41,7 +41,7 @@ static int l_ClientsConnected = 0;
static int l_Connections = 0;
static boost::mutex l_ComponentMutex;
REGISTER_STATSFUNCTION(LivestatusListenerStats, &LivestatusListener::StatsFunc);
REGISTER_STATSFUNCTION(LivestatusListener, &LivestatusListener::StatsFunc);
void LivestatusListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{

View File

@ -33,7 +33,7 @@ using namespace icinga;
REGISTER_TYPE(NotificationComponent);
REGISTER_STATSFUNCTION(NotificationComponentStats, &NotificationComponent::StatsFunc);
REGISTER_STATSFUNCTION(NotificationComponent, &NotificationComponent::StatsFunc);
void NotificationComponent::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -45,7 +45,7 @@ using namespace icinga;
REGISTER_TYPE(GraphiteWriter);
REGISTER_STATSFUNCTION(GraphiteWriterStats, &GraphiteWriter::StatsFunc);
REGISTER_STATSFUNCTION(GraphiteWriter, &GraphiteWriter::StatsFunc);
void GraphiteWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -45,7 +45,7 @@ using namespace icinga;
REGISTER_TYPE(OpenTsdbWriter);
REGISTER_STATSFUNCTION(OpenTsdbWriterStats, &OpenTsdbWriter::StatsFunc);
REGISTER_STATSFUNCTION(OpenTsdbWriter, &OpenTsdbWriter::StatsFunc);
void OpenTsdbWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -36,7 +36,7 @@ using namespace icinga;
REGISTER_TYPE(PerfdataWriter);
REGISTER_STATSFUNCTION(PerfdataWriterStats, &PerfdataWriter::StatsFunc);
REGISTER_STATSFUNCTION(PerfdataWriter, &PerfdataWriter::StatsFunc);
void PerfdataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
{

View File

@ -29,7 +29,7 @@ set(remote_SOURCES
endpoint.cpp endpoint.thpp filterutility.cpp
httpchunkedencoding.cpp httpclientconnection.cpp httpserverconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
httputility.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
messageorigin.cpp modifyobjecthandler.cpp statusqueryhandler.cpp typequeryhandler.cpp
messageorigin.cpp modifyobjecthandler.cpp statushandler.cpp statusqueryhandler.cpp typequeryhandler.cpp
url.cpp zone.cpp zone.thpp
)

View File

@ -42,7 +42,7 @@ REGISTER_TYPE(ApiListener);
boost::signals2::signal<void(bool)> ApiListener::OnMasterChanged;
REGISTER_STATSFUNCTION(ApiListenerStats, &ApiListener::StatsFunc);
REGISTER_STATSFUNCTION(ApiListener, &ApiListener::StatsFunc);
REGISTER_APIFUNCTION(Hello, icinga, &ApiListener::HelloAPIHandler);
@ -833,7 +833,6 @@ void ApiListener::ReplayLog(const JsonRpcConnection::Ptr& client)
void ApiListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
Dictionary::Ptr nodes = new Dictionary();
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats;
ApiListener::Ptr listener = ApiListener::GetInstance();

View File

@ -0,0 +1,101 @@
/******************************************************************************
* 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/statushandler.hpp"
#include "remote/httputility.hpp"
#include "base/serializer.hpp"
#include "base/statsfunction.hpp"
using namespace icinga;
REGISTER_URLHANDLER("/v1/status", StatusHandler);
bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
Dictionary::Ptr result = new Dictionary();
if (request.RequestMethod != "GET") {
response.SetStatus(400, "Bad request");
result->Set("info", "Request must be type GET");
HttpUtility::SendJsonBody(response, result);
return true;
}
if (request.RequestUrl->GetPath().size() < 2) {
response.SetStatus(400, "Bad request");
HttpUtility::SendJsonBody(response, result);
return true;
}
Array::Ptr results = new Array();
Dictionary::Ptr resultInner = new Dictionary();
if (request.RequestUrl->GetPath().size() > 2) {
StatsFunction::Ptr funcptr = StatsFunctionRegistry::GetInstance()->GetItem(request.RequestUrl->GetPath()[2]);
resultInner = new Dictionary();
if (!funcptr)
return false;
results->Add(resultInner);
Dictionary::Ptr status = new Dictionary();
Array::Ptr perfdata = new Array();
funcptr->Invoke(status, perfdata);
resultInner->Set("status", status);
resultInner->Set("perfdata", perfdata);
} else {
typedef std::pair<String, StatsFunction::Ptr> kv_pair;
BOOST_FOREACH(const kv_pair& kv, StatsFunctionRegistry::GetInstance()->GetItems()) {
resultInner = new Dictionary();
resultInner->Set("name", kv.first);
results->Add(resultInner);
}
}
result->Set("results", results);
response.SetStatus(200, "OK");
HttpUtility::SendJsonBody(response, result);
return true;
}
REGISTER_STATSFUNCTION(Collection, &StatusHandler::StatsFunc);
void StatusHandler::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
{
typedef std::pair<String, StatsFunction::Ptr> kv_pair;
BOOST_FOREACH(const kv_pair& kv, StatsFunctionRegistry::GetInstance()->GetItems()) {
if (kv.first == "Collection") //TODO Find a better name
continue;
Dictionary::Ptr funcStatus = new Dictionary();
Array::Ptr funcPData = new Array();
kv.second->Invoke(funcStatus, funcPData);
Dictionary::Ptr result = new Dictionary();
result->Set("status", funcStatus);
result->Set("perfdata", funcPData);
status->Set(kv.first, result);
}
}

View File

@ -0,0 +1,39 @@
/******************************************************************************
* 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 STATUSHANDLER_H
#define STATUSHANDLER_H
#include "remote/httphandler.hpp"
namespace icinga
{
class I2_REMOTE_API StatusHandler : public HttpHandler
{
public:
DECLARE_PTR_TYPEDEFS(StatusHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
};
}
#endif /* STATUSHANDLER_H */