mirror of https://github.com/Icinga/icinga2.git
Merge branch 'feature/db-endpoints-5636' into next
Fixes #5636 Fixes #5690 Fixes #5810 Fixes #5811 Fixes #5812
This commit is contained in:
commit
fee925720d
|
@ -16,16 +16,15 @@
|
||||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
mkclass_target(clusterlistener.ti clusterlistener.th)
|
mkclass_target(clusterlistener.ti clusterlistener.th)
|
||||||
mkclass_target(endpoint.ti endpoint.th)
|
|
||||||
|
|
||||||
mkembedconfig_target(cluster-type.conf cluster-type.cpp)
|
mkembedconfig_target(cluster-type.conf cluster-type.cpp)
|
||||||
|
|
||||||
add_library(cluster SHARED
|
add_library(cluster SHARED
|
||||||
clusterchecktask.cpp clusterlistener.cpp clusterlistener.th
|
clusterchecktask.cpp clusterlistener.cpp clusterlistener.th
|
||||||
endpoint.cpp endpoint.th jsonrpc.cpp cluster-type.cpp
|
cluster-type.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(cluster ${Boost_LIBRARIES} base config icinga)
|
target_link_libraries(cluster ${Boost_LIBRARIES} base config icinga remote)
|
||||||
|
|
||||||
set_target_properties (
|
set_target_properties (
|
||||||
cluster PROPERTIES
|
cluster PROPERTIES
|
||||||
|
|
|
@ -36,27 +36,3 @@ type ClusterListener {
|
||||||
%attribute name(Endpoint) "*"
|
%attribute name(Endpoint) "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Endpoint {
|
|
||||||
%require "host",
|
|
||||||
%attribute string "host",
|
|
||||||
|
|
||||||
%require "port",
|
|
||||||
%attribute string "port",
|
|
||||||
|
|
||||||
%attribute array "config_files" {
|
|
||||||
%attribute string "*"
|
|
||||||
},
|
|
||||||
|
|
||||||
%attribute array "config_files_recursive" {
|
|
||||||
%attribute string "*",
|
|
||||||
%attribute dictionary "*" {
|
|
||||||
%attribute string "path",
|
|
||||||
%attribute string "pattern"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
%attribute array "accept_config" {
|
|
||||||
%attribute name(Endpoint) "*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "cluster/clusterchecktask.h"
|
#include "cluster/clusterchecktask.h"
|
||||||
#include "cluster/endpoint.h"
|
|
||||||
#include "cluster/clusterlistener.h"
|
#include "cluster/clusterlistener.h"
|
||||||
|
#include "remote/endpoint.h"
|
||||||
#include "icinga/cib.h"
|
#include "icinga/cib.h"
|
||||||
#include "icinga/service.h"
|
#include "icinga/service.h"
|
||||||
#include "icinga/icingaapplication.h"
|
#include "icinga/icingaapplication.h"
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "cluster/clusterlistener.h"
|
#include "cluster/clusterlistener.h"
|
||||||
#include "cluster/endpoint.h"
|
#include "remote/endpoint.h"
|
||||||
#include "icinga/cib.h"
|
#include "icinga/cib.h"
|
||||||
#include "icinga/domain.h"
|
#include "icinga/domain.h"
|
||||||
#include "icinga/icingaapplication.h"
|
#include "icinga/icingaapplication.h"
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "base/stdiostream.h"
|
#include "base/stdiostream.h"
|
||||||
#include "base/workqueue.h"
|
#include "base/workqueue.h"
|
||||||
#include "icinga/service.h"
|
#include "icinga/service.h"
|
||||||
#include "cluster/endpoint.h"
|
#include "remote/endpoint.h"
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
|
|
|
@ -1376,6 +1376,12 @@ CREATE TABLE IF NOT EXISTS icinga_endpointstatus (
|
||||||
|
|
||||||
ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_contactstatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_programstatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_comments ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_scheduleddowntime ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_runtimevariables ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_customvariablestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
|
||||||
ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
@ -1392,6 +1398,10 @@ ALTER TABLE icinga_servicechecks ADD COLUMN endpoint_object_id bigint default NU
|
||||||
ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
|
||||||
|
ALTER TABLE icinga_servicestatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_hoststatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_statehistory ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
|
||||||
|
|
||||||
-- -----------------------------------------
|
-- -----------------------------------------
|
||||||
-- add index (delete)
|
-- add index (delete)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
ALTER TABLE icinga_servicestatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_hoststatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_statehistory ADD COLUMN check_source_object_id bigint default NULL;
|
|
@ -1404,6 +1404,12 @@ CREATE TABLE IF NOT EXISTS icinga_endpointstatus (
|
||||||
|
|
||||||
ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_servicestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_hoststatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_contactstatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_programstatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_comments ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_scheduleddowntime ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_runtimevariables ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_customvariablestatus ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
|
||||||
ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_acknowledgements ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_commenthistory ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
@ -1420,6 +1426,9 @@ ALTER TABLE icinga_servicechecks ADD COLUMN endpoint_object_id bigint default NU
|
||||||
ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_statehistory ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL;
|
ALTER TABLE icinga_systemcommands ADD COLUMN endpoint_object_id bigint default NULL;
|
||||||
|
|
||||||
|
ALTER TABLE icinga_servicestatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_hoststatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_statehistory ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
|
||||||
-- -----------------------------------------
|
-- -----------------------------------------
|
||||||
-- add index (delete)
|
-- add index (delete)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
ALTER TABLE icinga_servicestatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_hoststatus ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
ALTER TABLE icinga_statehistory ADD COLUMN check_source_object_id bigint default NULL;
|
||||||
|
|
|
@ -19,9 +19,18 @@ mkclass_target(listener.ti listener.th)
|
||||||
|
|
||||||
mkembedconfig_target(livestatus-type.conf livestatus-type.cpp)
|
mkembedconfig_target(livestatus-type.conf livestatus-type.cpp)
|
||||||
|
|
||||||
add_library(livestatus SHARED aggregator.cpp andfilter.cpp attributefilter.cpp avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp commentstable.cpp contactgroupstable.cpp contactstable.cpp countaggregator.cpp downtimestable.cpp filter.cpp historytable.cpp hostgroupstable.cpp hoststable.cpp invavgaggregator.cpp invsumaggregator.cpp listener.cpp listener.th logutility.cpp logtable.cpp maxaggregator.cpp minaggregator.cpp negatefilter.cpp orfilter.cpp query.cpp servicegroupstable.cpp servicestable.cpp statehisttable.cpp statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp timeperiodstable.cpp livestatus-type.cpp)
|
add_library(livestatus SHARED aggregator.cpp andfilter.cpp attributefilter.cpp
|
||||||
|
avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp
|
||||||
|
commentstable.cpp contactgroupstable.cpp contactstable.cpp countaggregator.cpp
|
||||||
|
downtimestable.cpp endpointstable.cpp filter.cpp historytable.cpp
|
||||||
|
hostgroupstable.cpp hoststable.cpp invavgaggregator.cpp invsumaggregator.cpp
|
||||||
|
listener.cpp listener.th logutility.cpp logtable.cpp maxaggregator.cpp
|
||||||
|
minaggregator.cpp negatefilter.cpp orfilter.cpp query.cpp
|
||||||
|
servicegroupstable.cpp servicestable.cpp statehisttable.cpp
|
||||||
|
statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp
|
||||||
|
timeperiodstable.cpp livestatus-type.cpp)
|
||||||
|
|
||||||
target_link_libraries(livestatus ${Boost_LIBRARIES} base config icinga)
|
target_link_libraries(livestatus ${Boost_LIBRARIES} base config icinga remote)
|
||||||
|
|
||||||
set_target_properties (
|
set_target_properties (
|
||||||
livestatus PROPERTIES
|
livestatus PROPERTIES
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-2014 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 "livestatus/endpointstable.h"
|
||||||
|
#include "icinga/host.h"
|
||||||
|
#include "icinga/service.h"
|
||||||
|
#include "icinga/icingaapplication.h"
|
||||||
|
#include "remote/endpoint.h"
|
||||||
|
#include "base/dynamictype.h"
|
||||||
|
#include "base/objectlock.h"
|
||||||
|
#include "base/convert.h"
|
||||||
|
#include "base/utility.h"
|
||||||
|
#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;
|
||||||
|
|
||||||
|
EndpointsTable::EndpointsTable(void)
|
||||||
|
{
|
||||||
|
AddColumns(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointsTable::AddColumns(Table *table, const String& prefix,
|
||||||
|
const Column::ObjectAccessor& objectAccessor)
|
||||||
|
{
|
||||||
|
table->AddColumn(prefix + "name", Column(&EndpointsTable::NameAccessor, objectAccessor));
|
||||||
|
table->AddColumn(prefix + "identity", Column(&EndpointsTable::IdentityAccessor, objectAccessor));
|
||||||
|
table->AddColumn(prefix + "node", Column(&EndpointsTable::NodeAccessor, objectAccessor));
|
||||||
|
table->AddColumn(prefix + "is_connected", Column(&EndpointsTable::IsConnectedAccessor, objectAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
String EndpointsTable::GetName(void) const
|
||||||
|
{
|
||||||
|
return "endpoints";
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointsTable::FetchRows(const AddRowFunction& addRowFn)
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const Endpoint::Ptr& endpoint, DynamicType::GetObjects<Endpoint>()) {
|
||||||
|
addRowFn(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value EndpointsTable::NameAccessor(const Value& row)
|
||||||
|
{
|
||||||
|
Endpoint::Ptr endpoint = static_cast<Endpoint::Ptr>(row);
|
||||||
|
|
||||||
|
if (!endpoint)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
return endpoint->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value EndpointsTable::IdentityAccessor(const Value& row)
|
||||||
|
{
|
||||||
|
Endpoint::Ptr endpoint = static_cast<Endpoint::Ptr>(row);
|
||||||
|
|
||||||
|
if (!endpoint)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
return endpoint->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value EndpointsTable::NodeAccessor(const Value& row)
|
||||||
|
{
|
||||||
|
Endpoint::Ptr endpoint = static_cast<Endpoint::Ptr>(row);
|
||||||
|
|
||||||
|
if (!endpoint)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
return IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value EndpointsTable::IsConnectedAccessor(const Value& row)
|
||||||
|
{
|
||||||
|
Endpoint::Ptr endpoint = static_cast<Endpoint::Ptr>(row);
|
||||||
|
|
||||||
|
if (!endpoint)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
unsigned int is_connected = endpoint->IsConnected() ? 1 : 0;
|
||||||
|
|
||||||
|
/* if identity is equal to node, fake is_connected */
|
||||||
|
if (endpoint->GetName() == IcingaApplication::GetInstance()->GetNodeName())
|
||||||
|
is_connected = 1;
|
||||||
|
|
||||||
|
return is_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-2014 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 ENDPOINTSTABLE_H
|
||||||
|
#define ENDPOINTSTABLE_H
|
||||||
|
|
||||||
|
#include "livestatus/table.h"
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup livestatus
|
||||||
|
*/
|
||||||
|
class EndpointsTable : public Table
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_PTR_TYPEDEFS(EndpointsTable);
|
||||||
|
|
||||||
|
EndpointsTable(void);
|
||||||
|
|
||||||
|
static void AddColumns(Table *table, const String& prefix = String(),
|
||||||
|
const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
|
||||||
|
|
||||||
|
virtual String GetName(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void FetchRows(const AddRowFunction& addRowFn);
|
||||||
|
|
||||||
|
static Value NameAccessor(const Value& row);
|
||||||
|
static Value IdentityAccessor(const Value& row);
|
||||||
|
static Value NodeAccessor(const Value& row);
|
||||||
|
static Value IsConnectedAccessor(const Value& row);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENDPOINTSTABLE_H */
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "livestatus/servicestable.h"
|
#include "livestatus/servicestable.h"
|
||||||
#include "livestatus/hoststable.h"
|
#include "livestatus/hoststable.h"
|
||||||
|
#include "livestatus/endpointstable.h"
|
||||||
#include "icinga/service.h"
|
#include "icinga/service.h"
|
||||||
#include "icinga/checkcommand.h"
|
#include "icinga/checkcommand.h"
|
||||||
#include "icinga/eventcommand.h"
|
#include "icinga/eventcommand.h"
|
||||||
|
@ -125,6 +126,7 @@ void ServicesTable::AddColumns(Table *table, const String& prefix,
|
||||||
table->AddColumn(prefix + "custom_variables", Column(&ServicesTable::CustomVariablesAccessor, objectAccessor));
|
table->AddColumn(prefix + "custom_variables", Column(&ServicesTable::CustomVariablesAccessor, objectAccessor));
|
||||||
table->AddColumn(prefix + "groups", Column(&ServicesTable::GroupsAccessor, objectAccessor));
|
table->AddColumn(prefix + "groups", Column(&ServicesTable::GroupsAccessor, objectAccessor));
|
||||||
table->AddColumn(prefix + "contact_groups", Column(&ServicesTable::ContactGroupsAccessor, objectAccessor));
|
table->AddColumn(prefix + "contact_groups", Column(&ServicesTable::ContactGroupsAccessor, objectAccessor));
|
||||||
|
table->AddColumn(prefix + "check_source", Column(&ServicesTable::CheckSourceAccessor, objectAccessor));
|
||||||
|
|
||||||
HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor));
|
HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor));
|
||||||
}
|
}
|
||||||
|
@ -1158,4 +1160,19 @@ Value ServicesTable::ContactGroupsAccessor(const Value& row)
|
||||||
return contactgroup_names;
|
return contactgroup_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value ServicesTable::CheckSourceAccessor(const Value& row)
|
||||||
|
{
|
||||||
|
Service::Ptr service = static_cast<Service::Ptr>(row);
|
||||||
|
|
||||||
|
if (!service)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
CheckResult::Ptr cr = service->GetLastCheckResult();
|
||||||
|
|
||||||
|
if (cr)
|
||||||
|
return cr->GetCheckSource();
|
||||||
|
|
||||||
|
return Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,7 @@ protected:
|
||||||
static Value CustomVariablesAccessor(const Value& row);
|
static Value CustomVariablesAccessor(const Value& row);
|
||||||
static Value GroupsAccessor(const Value& row);
|
static Value GroupsAccessor(const Value& row);
|
||||||
static Value ContactGroupsAccessor(const Value& row);
|
static Value ContactGroupsAccessor(const Value& row);
|
||||||
|
static Value CheckSourceAccessor(const Value& row);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "livestatus/commandstable.h"
|
#include "livestatus/commandstable.h"
|
||||||
#include "livestatus/commentstable.h"
|
#include "livestatus/commentstable.h"
|
||||||
#include "livestatus/downtimestable.h"
|
#include "livestatus/downtimestable.h"
|
||||||
|
#include "livestatus/endpointstable.h"
|
||||||
#include "livestatus/timeperiodstable.h"
|
#include "livestatus/timeperiodstable.h"
|
||||||
#include "livestatus/logtable.h"
|
#include "livestatus/logtable.h"
|
||||||
#include "livestatus/statehisttable.h"
|
#include "livestatus/statehisttable.h"
|
||||||
|
@ -71,6 +72,8 @@ Table::Ptr Table::GetByName(const String& name, const String& compat_log_path, c
|
||||||
return make_shared<LogTable>(compat_log_path, from, until);
|
return make_shared<LogTable>(compat_log_path, from, until);
|
||||||
else if (name == "statehist")
|
else if (name == "statehist")
|
||||||
return make_shared<StateHistTable>(compat_log_path, from, until);
|
return make_shared<StateHistTable>(compat_log_path, from, until);
|
||||||
|
else if (name == "endpoints")
|
||||||
|
return make_shared<EndpointsTable>();
|
||||||
|
|
||||||
return Table::Ptr();
|
return Table::Ptr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
### <a id="schemas"></id> Schemas
|
||||||
|
|
||||||
|
#### DB IDO
|
||||||
|
|
||||||
|
New tables: endpoints, endpointstatus
|
||||||
|
name, identity, node, is_connected
|
||||||
|
|
||||||
|
New columns: endpoint_object_id, check_source_object_id
|
||||||
|
|
||||||
|
#### Livestatus
|
||||||
|
|
||||||
|
New table: endpoints
|
||||||
|
name, identity, node, is_connected
|
||||||
|
|
||||||
|
New columns: check_source, endpoint
|
|
@ -21,3 +21,4 @@ add_subdirectory(icinga)
|
||||||
add_subdirectory(db_ido)
|
add_subdirectory(db_ido)
|
||||||
add_subdirectory(methods)
|
add_subdirectory(methods)
|
||||||
add_subdirectory(hello)
|
add_subdirectory(hello)
|
||||||
|
add_subdirectory(remote)
|
||||||
|
|
|
@ -44,7 +44,7 @@ INITIALIZE_ONCE(&DynamicObject::StaticInitialize);
|
||||||
|
|
||||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStarted;
|
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStarted;
|
||||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStopped;
|
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStopped;
|
||||||
boost::signals2::signal<void (const DynamicObject::Ptr&)> DynamicObject::OnStateChanged;
|
boost::signals2::signal<void (const DynamicObject::Ptr&, const String&)> DynamicObject::OnStateChanged;
|
||||||
boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> DynamicObject::OnAuthorityChanged;
|
boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> DynamicObject::OnAuthorityChanged;
|
||||||
|
|
||||||
void DynamicObject::StaticInitialize(void)
|
void DynamicObject::StaticInitialize(void)
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
|
|
||||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStarted;
|
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStarted;
|
||||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStopped;
|
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStopped;
|
||||||
static boost::signals2::signal<void (const DynamicObject::Ptr&)> OnStateChanged;
|
static boost::signals2::signal<void (const DynamicObject::Ptr&, const String&)> OnStateChanged;
|
||||||
static boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> OnAuthorityChanged;
|
static boost::signals2::signal<void (const DynamicObject::Ptr&, const String&, bool)> OnAuthorityChanged;
|
||||||
|
|
||||||
Value InvokeMethod(const String& method, const std::vector<Value>& arguments);
|
Value InvokeMethod(const String& method, const std::vector<Value>& arguments);
|
||||||
|
|
|
@ -22,13 +22,13 @@ mkembedconfig_target(db_ido-type.conf db_ido-type.cpp)
|
||||||
add_library(db_ido SHARED
|
add_library(db_ido SHARED
|
||||||
commanddbobject.cpp dbconnection.cpp dbconnection.th dbconnection.th
|
commanddbobject.cpp dbconnection.cpp dbconnection.th dbconnection.th
|
||||||
db_ido-type.cpp dbobject.cpp dbquery.cpp dbreference.cpp dbtype.cpp
|
db_ido-type.cpp dbobject.cpp dbquery.cpp dbreference.cpp dbtype.cpp
|
||||||
dbvalue.cpp hostdbobject.cpp hostgroupdbobject.cpp servicedbobject.cpp
|
dbvalue.cpp endpointdbobject.cpp hostdbobject.cpp hostgroupdbobject.cpp
|
||||||
servicegroupdbobject.cpp timeperioddbobject.cpp userdbobject.cpp
|
servicedbobject.cpp servicegroupdbobject.cpp timeperioddbobject.cpp
|
||||||
usergroupdbobject.cpp
|
userdbobject.cpp usergroupdbobject.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
target_link_libraries(db_ido ${Boost_LIBRARIES} base config icinga)
|
target_link_libraries(db_ido ${Boost_LIBRARIES} base config icinga remote)
|
||||||
|
|
||||||
set_target_properties (
|
set_target_properties (
|
||||||
db_ido PROPERTIES
|
db_ido PROPERTIES
|
||||||
|
|
|
@ -326,6 +326,8 @@ void DbConnection::PrepareDatabase(void)
|
||||||
//ClearConfigTable("contactstatus");
|
//ClearConfigTable("contactstatus");
|
||||||
ClearConfigTable("customvariables");
|
ClearConfigTable("customvariables");
|
||||||
ClearConfigTable("customvariablestatus");
|
ClearConfigTable("customvariablestatus");
|
||||||
|
ClearConfigTable("endpoints");
|
||||||
|
ClearConfigTable("endpointstatus");
|
||||||
ClearConfigTable("host_contactgroups");
|
ClearConfigTable("host_contactgroups");
|
||||||
ClearConfigTable("host_contacts");
|
ClearConfigTable("host_contacts");
|
||||||
ClearConfigTable("host_parenthosts");
|
ClearConfigTable("host_parenthosts");
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "db_ido/dbtype.h"
|
#include "db_ido/dbtype.h"
|
||||||
#include "db_ido/dbvalue.h"
|
#include "db_ido/dbvalue.h"
|
||||||
#include "icinga/service.h"
|
#include "icinga/service.h"
|
||||||
|
#include "remote/endpoint.h"
|
||||||
#include "base/dynamictype.h"
|
#include "base/dynamictype.h"
|
||||||
#include "base/objectlock.h"
|
#include "base/objectlock.h"
|
||||||
#include "base/utility.h"
|
#include "base/utility.h"
|
||||||
|
@ -108,7 +109,20 @@ void DbObject::SendStatusUpdate(void)
|
||||||
query.Category = DbCatState;
|
query.Category = DbCatState;
|
||||||
query.Fields = fields;
|
query.Fields = fields;
|
||||||
query.Fields->Set(GetType()->GetIDColumn(), GetObject());
|
query.Fields->Set(GetType()->GetIDColumn(), GetObject());
|
||||||
|
|
||||||
|
/* do not override our own endpoint dbobject id */
|
||||||
|
if (GetType()->GetTable() != "endpoint") {
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Log(LogDebug, "db_ido", "Endpoint node: '" + node + "' status update for '" + GetObject()->GetName() + "'");
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
query.Fields->Set("endpoint_object_id", endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
query.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
|
query.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
|
||||||
query.WhereCriteria = make_shared<Dictionary>();
|
query.WhereCriteria = make_shared<Dictionary>();
|
||||||
query.WhereCriteria->Set(GetType()->GetIDColumn(), GetObject());
|
query.WhereCriteria->Set(GetType()->GetIDColumn(), GetObject());
|
||||||
|
|
|
@ -49,6 +49,7 @@ enum DbObjectType
|
||||||
DbObjectTypeContact = 10,
|
DbObjectTypeContact = 10,
|
||||||
DbObjectTypeContactGroup = 11,
|
DbObjectTypeContactGroup = 11,
|
||||||
DbObjectTypeCommand = 12,
|
DbObjectTypeCommand = 12,
|
||||||
|
DbObjectTypeEndpoint = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-present 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 "db_ido/endpointdbobject.h"
|
||||||
|
#include "db_ido/dbtype.h"
|
||||||
|
#include "db_ido/dbvalue.h"
|
||||||
|
#include "icinga/icingaapplication.h"
|
||||||
|
#include "base/objectlock.h"
|
||||||
|
#include "base/initialize.h"
|
||||||
|
#include "base/dynamictype.h"
|
||||||
|
#include "base/utility.h"
|
||||||
|
#include "base/convert.h"
|
||||||
|
#include "base/logger_fwd.h"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
|
||||||
|
REGISTER_DBTYPE(Endpoint, "endpoint", DbObjectTypeEndpoint, "endpoint_object_id", EndpointDbObject);
|
||||||
|
|
||||||
|
INITIALIZE_ONCE(&EndpointDbObject::StaticInitialize);
|
||||||
|
|
||||||
|
void EndpointDbObject::StaticInitialize(void)
|
||||||
|
{
|
||||||
|
Endpoint::OnConnected.connect(boost::bind(&EndpointDbObject::UpdateConnectedStatus, _1));
|
||||||
|
Endpoint::OnDisconnected.connect(boost::bind(&EndpointDbObject::UpdateDisconnectedStatus, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointDbObject::EndpointDbObject(const DbType::Ptr& type, const String& name1, const String& name2)
|
||||||
|
: DbObject(type, name1, name2)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Dictionary::Ptr EndpointDbObject::GetConfigFields(void) const
|
||||||
|
{
|
||||||
|
Dictionary::Ptr fields = make_shared<Dictionary>();
|
||||||
|
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(GetObject());
|
||||||
|
|
||||||
|
fields->Set("identity", endpoint->GetName());
|
||||||
|
fields->Set("node", IcingaApplication::GetInstance()->GetNodeName());
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr EndpointDbObject::GetStatusFields(void) const
|
||||||
|
{
|
||||||
|
Dictionary::Ptr fields = make_shared<Dictionary>();
|
||||||
|
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(GetObject());
|
||||||
|
|
||||||
|
Log(LogDebug, "db_ido", "update status for endpoint '" + endpoint->GetName() + "'");
|
||||||
|
|
||||||
|
fields->Set("identity", endpoint->GetName());
|
||||||
|
fields->Set("node", IcingaApplication::GetInstance()->GetNodeName());
|
||||||
|
fields->Set("is_connected", EndpointIsConnected(endpoint));
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointDbObject::UpdateConnectedStatus(const Endpoint::Ptr& endpoint)
|
||||||
|
{
|
||||||
|
UpdateConnectedStatusInternal(endpoint, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointDbObject::UpdateDisconnectedStatus(const Endpoint::Ptr& endpoint)
|
||||||
|
{
|
||||||
|
UpdateConnectedStatusInternal(endpoint, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointDbObject::UpdateConnectedStatusInternal(const Endpoint::Ptr& endpoint, bool connected)
|
||||||
|
{
|
||||||
|
Log(LogDebug, "db_ido", "update is_connected=" + Convert::ToString(connected ? 1 : 0) + " for endpoint '" + endpoint->GetName() + "'");
|
||||||
|
|
||||||
|
DbQuery query1;
|
||||||
|
query1.Table = "endpointstatus";
|
||||||
|
query1.Type = DbQueryUpdate;
|
||||||
|
|
||||||
|
Dictionary::Ptr fields1 = make_shared<Dictionary>();
|
||||||
|
fields1->Set("is_connected", (connected ? 1 : 0));
|
||||||
|
fields1->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
|
||||||
|
query1.Fields = fields1;
|
||||||
|
|
||||||
|
query1.WhereCriteria = make_shared<Dictionary>();
|
||||||
|
query1.WhereCriteria->Set("endpoint_object_id", endpoint);
|
||||||
|
query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
OnQuery(query1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int EndpointDbObject::EndpointIsConnected(const Endpoint::Ptr& endpoint)
|
||||||
|
{
|
||||||
|
unsigned int is_connected = endpoint->IsConnected() ? 1 : 0;
|
||||||
|
|
||||||
|
/* if identity is equal to node, fake is_connected */
|
||||||
|
if (endpoint->GetName() == IcingaApplication::GetInstance()->GetNodeName())
|
||||||
|
is_connected = 1;
|
||||||
|
|
||||||
|
return is_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointDbObject::OnConfigUpdate(void)
|
||||||
|
{
|
||||||
|
/* update current status on config dump once */
|
||||||
|
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(GetObject());
|
||||||
|
|
||||||
|
DbQuery query1;
|
||||||
|
query1.Table = "endpointstatus";
|
||||||
|
query1.Type = DbQueryInsert;
|
||||||
|
|
||||||
|
Dictionary::Ptr fields1 = make_shared<Dictionary>();
|
||||||
|
fields1->Set("identity", endpoint->GetName());
|
||||||
|
fields1->Set("node", IcingaApplication::GetInstance()->GetNodeName());
|
||||||
|
fields1->Set("is_connected", EndpointIsConnected(endpoint));
|
||||||
|
fields1->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
query1.Fields = fields1;
|
||||||
|
|
||||||
|
OnQuery(query1);
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-present 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 ENDPOINTDBOBJECT_H
|
||||||
|
#define ENDPOINTDBOBJECT_H
|
||||||
|
|
||||||
|
#include "db_ido/dbobject.h"
|
||||||
|
#include "base/dynamicobject.h"
|
||||||
|
#include "remote/endpoint.h"
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Command database object.
|
||||||
|
*
|
||||||
|
* @ingroup ido
|
||||||
|
*/
|
||||||
|
class EndpointDbObject : public DbObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_PTR_TYPEDEFS(EndpointDbObject);
|
||||||
|
|
||||||
|
EndpointDbObject(const shared_ptr<DbType>& type, const String& name1, const String& name2);
|
||||||
|
|
||||||
|
static void StaticInitialize(void);
|
||||||
|
|
||||||
|
virtual Dictionary::Ptr GetConfigFields(void) const;
|
||||||
|
virtual Dictionary::Ptr GetStatusFields(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnConfigUpdate(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void UpdateConnectedStatus(const Endpoint::Ptr& endpoint);
|
||||||
|
static void UpdateDisconnectedStatus(const Endpoint::Ptr& endpoint);
|
||||||
|
static void UpdateConnectedStatusInternal(const Endpoint::Ptr& endpoint, bool connected);
|
||||||
|
static int EndpointIsConnected(const Endpoint::Ptr& endpoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENDPOINTDBOBJECT_H */
|
|
@ -25,6 +25,7 @@
|
||||||
#include "base/initialize.h"
|
#include "base/initialize.h"
|
||||||
#include "base/dynamictype.h"
|
#include "base/dynamictype.h"
|
||||||
#include "base/utility.h"
|
#include "base/utility.h"
|
||||||
|
#include "remote/endpoint.h"
|
||||||
#include "icinga/notification.h"
|
#include "icinga/notification.h"
|
||||||
#include "icinga/checkcommand.h"
|
#include "icinga/checkcommand.h"
|
||||||
#include "icinga/eventcommand.h"
|
#include "icinga/eventcommand.h"
|
||||||
|
@ -144,7 +145,14 @@ Dictionary::Ptr ServiceDbObject::GetStatusFields(void) const
|
||||||
fields->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
fields->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
||||||
fields->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
fields->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
||||||
fields->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
|
fields->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
|
||||||
fields->Set("check_source", cr->GetCheckSource());
|
|
||||||
|
String check_source = cr->GetCheckSource();
|
||||||
|
fields->Set("check_source", check_source);
|
||||||
|
|
||||||
|
Endpoint::Ptr check_endpoint = Endpoint::GetByName(check_source);
|
||||||
|
|
||||||
|
if(check_endpoint)
|
||||||
|
fields->Set("check_source_object_id", check_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
fields->Set("current_state", CompatUtility::GetServiceCurrentState(service));
|
fields->Set("current_state", CompatUtility::GetServiceCurrentState(service));
|
||||||
|
@ -398,6 +406,12 @@ void ServiceDbObject::AddCommentByType(const DynamicObject::Ptr& object, const C
|
||||||
fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
|
fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
DbQuery query1;
|
DbQuery query1;
|
||||||
if (!historical) {
|
if (!historical) {
|
||||||
query1.Table = "comments";
|
query1.Table = "comments";
|
||||||
|
@ -563,6 +577,12 @@ void ServiceDbObject::AddDowntimeByType(const DynamicObject::Ptr& object, const
|
||||||
fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
|
fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
DbQuery query1;
|
DbQuery query1;
|
||||||
if (!historical) {
|
if (!historical) {
|
||||||
query1.Table = "scheduleddowntime";
|
query1.Table = "scheduleddowntime";
|
||||||
|
@ -746,6 +766,12 @@ void ServiceDbObject::AddAcknowledgementHistory(const Service::Ptr& service, con
|
||||||
fields1->Set("end_time", DbValue::FromTimestamp(end_time));
|
fields1->Set("end_time", DbValue::FromTimestamp(end_time));
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -796,6 +822,12 @@ void ServiceDbObject::AddNotificationHistory(const Notification::Ptr& notificati
|
||||||
fields1->Set("contacts_notified", static_cast<long>(users.size()));
|
fields1->Set("contacts_notified", static_cast<long>(users.size()));
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -862,11 +894,24 @@ void ServiceDbObject::AddStateChangeHistory(const Service::Ptr& service, const C
|
||||||
if (cr) {
|
if (cr) {
|
||||||
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
|
||||||
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
|
||||||
fields1->Set("check_source", cr->GetCheckSource());
|
|
||||||
|
String check_source = cr->GetCheckSource();
|
||||||
|
fields1->Set("check_source", check_source);
|
||||||
|
|
||||||
|
Endpoint::Ptr check_endpoint = Endpoint::GetByName(check_source);
|
||||||
|
|
||||||
|
if(check_endpoint)
|
||||||
|
fields1->Set("check_source_object_id", check_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -1170,6 +1215,12 @@ void ServiceDbObject::AddLogHistory(const Service::Ptr& service, String buffer,
|
||||||
|
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -1226,6 +1277,12 @@ void ServiceDbObject::AddFlappingHistory(const Service::Ptr& service, FlappingSt
|
||||||
|
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -1285,6 +1342,12 @@ void ServiceDbObject::AddServiceCheckHistory(const Service::Ptr& service, const
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
fields1->Set("service_object_id", service);
|
fields1->Set("service_object_id", service);
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -1331,6 +1394,12 @@ void ServiceDbObject::AddEventHandlerHistory(const Service::Ptr& service)
|
||||||
|
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
|
|
||||||
|
@ -1364,6 +1433,12 @@ void ServiceDbObject::AddExternalCommandHistory(double time, const String& comma
|
||||||
|
|
||||||
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
|
||||||
|
|
||||||
|
String node = IcingaApplication::GetInstance()->GetNodeName();
|
||||||
|
|
||||||
|
Endpoint::Ptr endpoint = Endpoint::GetByName(node);
|
||||||
|
if (endpoint)
|
||||||
|
fields1->Set("endpoint_object_id", endpoint);
|
||||||
|
|
||||||
query1.Fields = fields1;
|
query1.Fields = fields1;
|
||||||
OnQuery(query1);
|
OnQuery(query1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,7 +417,7 @@ void Service::ProcessCheckResult(const CheckResult::Ptr& cr, const String& autho
|
||||||
OnNewCheckResult(GetSelf(), cr, authority);
|
OnNewCheckResult(GetSelf(), cr, authority);
|
||||||
|
|
||||||
/* signal status updates to for example db_ido */
|
/* signal status updates to for example db_ido */
|
||||||
OnStateChanged(GetSelf());
|
OnStateChanged(GetSelf(), authority);
|
||||||
|
|
||||||
if (hardChange)
|
if (hardChange)
|
||||||
OnStateChange(GetSelf(), cr, StateTypeHard, authority);
|
OnStateChange(GetSelf(), cr, StateTypeHard, authority);
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Icinga 2
|
||||||
|
# Copyright (C) 2012-present 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.
|
||||||
|
|
||||||
|
mkclass_target(endpoint.ti endpoint.th)
|
||||||
|
|
||||||
|
mkembedconfig_target(remote-type.conf remote-type.cpp)
|
||||||
|
|
||||||
|
add_library(remote SHARED
|
||||||
|
endpoint.cpp endpoint.th jsonrpc.cpp remote-type.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(remote ${Boost_LIBRARIES} base config)
|
||||||
|
|
||||||
|
set_target_properties (
|
||||||
|
remote PROPERTIES
|
||||||
|
INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/icinga2
|
||||||
|
DEFINE_SYMBOL I2_REMOTE_BUILD
|
||||||
|
FOLDER Lib
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS remote
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "cluster/endpoint.h"
|
#include "remote/endpoint.h"
|
||||||
#include "cluster/jsonrpc.h"
|
#include "remote/jsonrpc.h"
|
||||||
#include "base/application.h"
|
#include "base/application.h"
|
||||||
#include "base/dynamictype.h"
|
#include "base/dynamictype.h"
|
||||||
#include "base/objectlock.h"
|
#include "base/objectlock.h"
|
||||||
|
@ -32,6 +32,7 @@ using namespace icinga;
|
||||||
REGISTER_TYPE(Endpoint);
|
REGISTER_TYPE(Endpoint);
|
||||||
|
|
||||||
boost::signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnConnected;
|
boost::signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnConnected;
|
||||||
|
boost::signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnDisconnected;
|
||||||
boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> Endpoint::OnMessageReceived;
|
boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> Endpoint::OnMessageReceived;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +62,10 @@ void Endpoint::SetClient(const Stream::Ptr& client)
|
||||||
thread.detach();
|
thread.detach();
|
||||||
|
|
||||||
OnConnected(GetSelf());
|
OnConnected(GetSelf());
|
||||||
|
Log(LogWarning, "remote", "Endpoint connected: " + GetName());
|
||||||
|
} else {
|
||||||
|
OnDisconnected(GetSelf());
|
||||||
|
Log(LogWarning, "remote", "Endpoint disconnected: " + GetName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,9 +81,12 @@ void Endpoint::SendMessage(const Dictionary::Ptr& message)
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
std::ostringstream msgbuf;
|
std::ostringstream msgbuf;
|
||||||
msgbuf << "Error while sending JSON-RPC message for endpoint '" << GetName() << "': " << DiagnosticInformation(ex);
|
msgbuf << "Error while sending JSON-RPC message for endpoint '" << GetName() << "': " << DiagnosticInformation(ex);
|
||||||
Log(LogWarning, "cluster", msgbuf.str());
|
Log(LogWarning, "remote", msgbuf.str());
|
||||||
|
|
||||||
m_Client.reset();
|
m_Client.reset();
|
||||||
|
|
||||||
|
OnDisconnected(GetSelf());
|
||||||
|
Log(LogWarning, "remote", "Endpoint disconnected: " + GetName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,10 +100,13 @@ void Endpoint::MessageThreadProc(const Stream::Ptr& stream)
|
||||||
try {
|
try {
|
||||||
message = JsonRpc::ReadMessage(stream);
|
message = JsonRpc::ReadMessage(stream);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
Log(LogWarning, "cluster", "Error while reading JSON-RPC message for endpoint '" + GetName() + "': " + DiagnosticInformation(ex));
|
Log(LogWarning, "remote", "Error while reading JSON-RPC message for endpoint '" + GetName() + "': " + DiagnosticInformation(ex));
|
||||||
|
|
||||||
m_Client.reset();
|
m_Client.reset();
|
||||||
|
|
||||||
|
OnDisconnected(GetSelf());
|
||||||
|
Log(LogWarning, "remote", "Endpoint disconnected: " + GetName());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
#ifndef ENDPOINT_H
|
#ifndef ENDPOINT_H
|
||||||
#define ENDPOINT_H
|
#define ENDPOINT_H
|
||||||
|
|
||||||
#include "cluster/endpoint.th"
|
#include "remote/endpoint.th"
|
||||||
#include "base/stream.h"
|
#include "base/stream.h"
|
||||||
#include "base/array.h"
|
#include "base/array.h"
|
||||||
|
#include "remote/i2-remote.h"
|
||||||
#include <boost/signals2.hpp>
|
#include <boost/signals2.hpp>
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
|
@ -35,13 +36,14 @@ class EndpointManager;
|
||||||
*
|
*
|
||||||
* @ingroup cluster
|
* @ingroup cluster
|
||||||
*/
|
*/
|
||||||
class Endpoint : public ObjectImpl<Endpoint>
|
class I2_REMOTE_API Endpoint : public ObjectImpl<Endpoint>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DECLARE_PTR_TYPEDEFS(Endpoint);
|
DECLARE_PTR_TYPEDEFS(Endpoint);
|
||||||
DECLARE_TYPENAME(Endpoint);
|
DECLARE_TYPENAME(Endpoint);
|
||||||
|
|
||||||
static boost::signals2::signal<void (const Endpoint::Ptr&)> OnConnected;
|
static boost::signals2::signal<void (const Endpoint::Ptr&)> OnConnected;
|
||||||
|
static boost::signals2::signal<void (const Endpoint::Ptr&)> OnDisconnected;
|
||||||
static boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> OnMessageReceived;
|
static boost::signals2::signal<void (const Endpoint::Ptr&, const Dictionary::Ptr&)> OnMessageReceived;
|
||||||
|
|
||||||
Stream::Ptr GetClient(void) const;
|
Stream::Ptr GetClient(void) const;
|
|
@ -0,0 +1,37 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-present 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 I2REMOTE_H
|
||||||
|
#define I2REMOTE_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup remote Remote library
|
||||||
|
*
|
||||||
|
* The Icinga library implements remote cluster functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "base/i2-base.h"
|
||||||
|
|
||||||
|
#ifdef I2_REMOTE_BUILD
|
||||||
|
# define I2_REMOTE_API I2_EXPORT
|
||||||
|
#else /* I2_REMOTE_BUILD */
|
||||||
|
# define I2_REMOTE_API I2_IMPORT
|
||||||
|
#endif /* I2_REMOTE_BUILD */
|
||||||
|
|
||||||
|
#endif /* I2REMOTE_H */
|
|
@ -17,7 +17,7 @@
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "cluster/jsonrpc.h"
|
#include "remote/jsonrpc.h"
|
||||||
#include "base/netstring.h"
|
#include "base/netstring.h"
|
||||||
#include "base/objectlock.h"
|
#include "base/objectlock.h"
|
||||||
#include "base/logger_fwd.h"
|
#include "base/logger_fwd.h"
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "base/stream.h"
|
#include "base/stream.h"
|
||||||
#include "base/dictionary.h"
|
#include "base/dictionary.h"
|
||||||
|
#include "remote/i2-remote.h"
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
|
@ -29,9 +30,9 @@ namespace icinga
|
||||||
/**
|
/**
|
||||||
* A JSON-RPC connection.
|
* A JSON-RPC connection.
|
||||||
*
|
*
|
||||||
* @ingroup cluster
|
* @ingroup remote
|
||||||
*/
|
*/
|
||||||
class JsonRpc
|
class I2_REMOTE_API JsonRpc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message);
|
static void SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message);
|
|
@ -0,0 +1,42 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Icinga 2 *
|
||||||
|
* Copyright (C) 2012-present 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. *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
type Endpoint {
|
||||||
|
%require "host",
|
||||||
|
%attribute string "host",
|
||||||
|
|
||||||
|
%require "port",
|
||||||
|
%attribute string "port",
|
||||||
|
|
||||||
|
%attribute array "config_files" {
|
||||||
|
%attribute string "*"
|
||||||
|
},
|
||||||
|
|
||||||
|
%attribute array "config_files_recursive" {
|
||||||
|
%attribute string "*",
|
||||||
|
%attribute dictionary "*" {
|
||||||
|
%attribute string "path",
|
||||||
|
%attribute string "pattern"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
%attribute array "accept_config" {
|
||||||
|
%attribute name(Endpoint) "*"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
GET endpoints
|
||||||
|
ResponseHeader: fixed16
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
GET services
|
||||||
|
Columns: description host_name plugin_output check_source
|
||||||
|
ResponseHeader: fixed16
|
||||||
|
|
Loading…
Reference in New Issue