From 9b7251abb9f74f6a90796e19d798bdc148b774ad Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 6 Jul 2012 11:22:38 +0200 Subject: [PATCH] Implemented 'services' property for host definitions. --- components/Makefile.am | 1 + components/convenience/Makefile.am | 33 ++++ .../convenience/conveniencecomponent.cpp | 181 ++++++++++++++++++ components/convenience/conveniencecomponent.h | 44 +++++ components/convenience/i2-convenience.h | 39 ++++ configure.ac | 1 + dyn/configitem.cpp | 19 +- dyn/configitem.h | 10 +- dyn/expression.cpp | 52 +++-- icinga/icingaapplication.cpp | 5 + 10 files changed, 360 insertions(+), 25 deletions(-) create mode 100644 components/convenience/Makefile.am create mode 100644 components/convenience/conveniencecomponent.cpp create mode 100644 components/convenience/conveniencecomponent.h create mode 100644 components/convenience/i2-convenience.h diff --git a/components/Makefile.am b/components/Makefile.am index b54490e97..422b8c10c 100644 --- a/components/Makefile.am +++ b/components/Makefile.am @@ -6,6 +6,7 @@ SUBDIRS = \ cibsync \ compat \ configfile \ + convenience \ delegation \ demo \ discovery diff --git a/components/convenience/Makefile.am b/components/convenience/Makefile.am new file mode 100644 index 000000000..919f6ab08 --- /dev/null +++ b/components/convenience/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = \ + convenience.la + +convenience_la_SOURCES = \ + conveniencecomponent.cpp \ + conveniencecomponent.h \ + i2-convenience.h + +convenience_la_CPPFLAGS = \ + $(BOOST_CPPFLAGS) \ + -I${top_srcdir}/base \ + -I${top_srcdir}/dyn \ + -I${top_srcdir}/jsonrpc \ + -I${top_srcdir}/icinga \ + -I${top_srcdir}/cib + +convenience_la_LDFLAGS = \ + $(BOOST_LDFLAGS) \ + -module \ + -no-undefined \ + @RELEASE_INFO@ \ + @VERSION_INFO@ + +convenience_la_LIBADD = \ + $(BOOST_SIGNALS_LIB) \ + $(BOOST_THREAD_LIB) \ + ${top_builddir}/base/libbase.la \ + ${top_builddir}/dyn/libdyn.la \ + ${top_builddir}/jsonrpc/libjsonrpc.la \ + ${top_builddir}/icinga/libicinga.la \ + ${top_builddir}/cib/libcib.la diff --git a/components/convenience/conveniencecomponent.cpp b/components/convenience/conveniencecomponent.cpp new file mode 100644 index 000000000..644427c50 --- /dev/null +++ b/components/convenience/conveniencecomponent.cpp @@ -0,0 +1,181 @@ +/****************************************************************************** + * 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-convenience.h" + +using namespace icinga; + +/** + * Returns the name of the component. + * + * @returns The name. + */ +string ConvenienceComponent::GetName(void) const +{ + return "convenience"; +} + +/** + * Starts the component. + */ +void ConvenienceComponent::Start(void) +{ + ConfigItem::Set::Ptr itemSet = ConfigItem::GetAllObjects(); + itemSet->OnObjectAdded.connect(boost::bind(&ConvenienceComponent::HostAddedHandler, this, _2)); + itemSet->OnObjectCommitted.connect(boost::bind(&ConvenienceComponent::HostCommittedHandler, this, _2)); + itemSet->OnObjectRemoved.connect(boost::bind(&ConvenienceComponent::HostRemovedHandler, this, _2)); +} + +/** + * Stops the component. + */ +void ConvenienceComponent::Stop(void) +{ +} + +void ConvenienceComponent::HostAddedHandler(const ConfigItem::Ptr& item) +{ + HostCommittedHandler(item); +} + +void ConvenienceComponent::HostCommittedHandler(const ConfigItem::Ptr& item) +{ + if (item->GetType() != "host") + return; + + ConfigObject::Ptr host = ConfigObject::GetObject("host", item->GetName()); + Dictionary::Ptr oldServices; + host->GetTag("convenience-services", &oldServices); + + Dictionary::Ptr newServices; + newServices = boost::make_shared(); + + Dictionary::Ptr serviceDescs; + host->GetProperty("services", &serviceDescs); + + if (serviceDescs) { + Dictionary::Iterator it; + for (it = serviceDescs->Begin(); it != serviceDescs->End(); it++) { + Variant desc = it->second; + ConfigItem::Ptr serviceItem; + + string name; + + if (desc.GetType() == VariantString) { + stringstream namebuf; + namebuf << item->GetName() << "-" << string(desc); + name = namebuf.str(); + + serviceItem = boost::make_shared("service", name, item->GetDebugInfo()); + serviceItem->AddParent(desc); + + ExpressionList::Ptr exprl = boost::make_shared(); + + Expression localExpr("__local", OperatorSet, 1, item->GetDebugInfo()); + exprl->AddExpression(localExpr); + + Expression abstractExpr("__abstract", OperatorSet, 0, item->GetDebugInfo()); + exprl->AddExpression(abstractExpr); + + Expression typeExpr("__type", OperatorSet, "service", item->GetDebugInfo()); + exprl->AddExpression(typeExpr); + + Expression nameExpr("__name", OperatorSet, name, item->GetDebugInfo()); + exprl->AddExpression(nameExpr); + + Expression hostExpr("host_name", OperatorSet, item->GetName(), item->GetDebugInfo()); + exprl->AddExpression(hostExpr); + + Expression aliasExpr("alias", OperatorSet, string(desc), item->GetDebugInfo()); + exprl->AddExpression(aliasExpr); + + Dictionary::Ptr macros; + if (host->GetProperty("macros", ¯os)) { + Expression macrosExpr("macros", OperatorPlus, macros, item->GetDebugInfo()); + exprl->AddExpression(macrosExpr); + } + + long checkInterval; + if (host->GetProperty("check_interval", &checkInterval)) { + Expression checkExpr("check_interval", OperatorSet, checkInterval, item->GetDebugInfo()); + exprl->AddExpression(checkExpr); + } + + long retryInterval; + if (host->GetProperty("retry_interval", &retryInterval)) { + Expression retryExpr("retry_interval", OperatorSet, retryInterval, item->GetDebugInfo()); + exprl->AddExpression(retryExpr); + } + + Dictionary::Ptr sgroups; + if (host->GetProperty("servicegroups", &sgroups)) { + Expression sgroupsExpr("servicegroups", OperatorPlus, sgroups, item->GetDebugInfo()); + exprl->AddExpression(sgroupsExpr); + } + + Dictionary::Ptr checkers; + if (host->GetProperty("checkers", &checkers)) { + Expression checkersExpr("checkers", OperatorSet, checkers, item->GetDebugInfo()); + exprl->AddExpression(checkersExpr); + } + + serviceItem->SetExpressionList(exprl); + ConfigObject::Ptr service = serviceItem->Commit(); + + newServices->SetProperty(name, serviceItem); + } else { + throw runtime_error("Not supported."); + } + } + } + + if (oldServices) { + Dictionary::Iterator it; + for (it = oldServices->Begin(); it != oldServices->End(); it++) { + ConfigItem::Ptr service = static_pointer_cast(it->second.GetObject()); + + if (!newServices->Contains(service->GetName())) + service->Unregister(); + } + } + + //host.GetConfigObject()->SetTag("convenience-services", newServices); +} + +void ConvenienceComponent::HostRemovedHandler(const ConfigItem::Ptr& item) +{ + if (item->GetType() != "host") + return; + + ConfigObject::Ptr host = item->GetConfigObject(); + + Dictionary::Ptr services; + host->GetTag("convenience-services", &services); + + if (!services) + return; + + Dictionary::Iterator it; + for (it = services->Begin(); it != services->End(); it++) { + ConfigItem::Ptr service = static_pointer_cast(it->second.GetObject()); + service->Unregister(); + } +} + +EXPORT_COMPONENT(convenience, ConvenienceComponent); diff --git a/components/convenience/conveniencecomponent.h b/components/convenience/conveniencecomponent.h new file mode 100644 index 000000000..8eb73e4ea --- /dev/null +++ b/components/convenience/conveniencecomponent.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * 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 CONVENIENCECOMPONENT_H +#define CONVENIENCECOMPONENT_H + +namespace icinga +{ + +/** + * @ingroup convenience + */ +class ConvenienceComponent : public Component +{ +public: + virtual string GetName(void) const; + virtual void Start(void); + virtual void Stop(void); + +private: + void HostAddedHandler(const ConfigItem::Ptr& item); + void HostCommittedHandler(const ConfigItem::Ptr& item); + void HostRemovedHandler(const ConfigItem::Ptr& item); +}; + +} + +#endif /* CONVENIENCECOMPONENT_H */ diff --git a/components/convenience/i2-convenience.h b/components/convenience/i2-convenience.h new file mode 100644 index 000000000..f65ffdc4a --- /dev/null +++ b/components/convenience/i2-convenience.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * 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 I2CONVENIENCE_H +#define I2CONVENIENCE_H + +/** + * @defgroup convenience Convenience component + * + * The convenience component takes service definitions from host objects + * and creates service objects. Technically this isn't strictly necessary but + * makes defining services a lot easier for users. + */ + +#include +#include +#include +#include +#include + +#include "conveniencecomponent.h" + +#endif /* I2CONVENIENCE_H */ diff --git a/configure.ac b/configure.ac index 1678990d7..f03165723 100644 --- a/configure.ac +++ b/configure.ac @@ -72,6 +72,7 @@ components/checker/Makefile components/cibsync/Makefile components/compat/Makefile components/configfile/Makefile +components/convenience/Makefile components/delegation/Makefile components/demo/Makefile components/discovery/Makefile diff --git a/dyn/configitem.cpp b/dyn/configitem.cpp index 5d45e73ca..37e693ea0 100644 --- a/dyn/configitem.cpp +++ b/dyn/configitem.cpp @@ -36,6 +36,11 @@ string ConfigItem::GetName(void) const return m_Name; } +DebugInfo ConfigItem::GetDebugInfo(void) const +{ + return m_DebugInfo; +} + ExpressionList::Ptr ConfigItem::GetExpressionList(void) const { return m_ExpressionList; @@ -74,7 +79,7 @@ void ConfigItem::CalculateProperties(Dictionary::Ptr dictionary) const m_ExpressionList->Execute(dictionary); } -ObjectSet::Ptr ConfigItem::GetAllObjects(void) +ConfigItem::Set::Ptr ConfigItem::GetAllObjects(void) { static ObjectSet::Ptr allObjects; @@ -105,7 +110,7 @@ ConfigItem::TNMap::Ptr ConfigItem::GetObjectsByTypeAndName(void) return tnmap; } -void ConfigItem::Commit(void) +ConfigObject::Ptr ConfigItem::Commit(void) { ConfigObject::Ptr dobj = m_ConfigObject.lock(); @@ -127,6 +132,9 @@ void ConfigItem::Commit(void) else dobj->Commit(); + /* TODO: Figure out whether there are any child objects which inherit + * from this config item and Commit() them as well */ + ConfigItem::Ptr ci = GetObject(GetType(), GetName()); ConfigItem::Ptr self = GetSelf(); if (ci && ci != self) { @@ -134,6 +142,8 @@ void ConfigItem::Commit(void) GetAllObjects()->RemoveObject(ci); } GetAllObjects()->CheckObject(self); + + return dobj; } void ConfigItem::Unregister(void) @@ -146,6 +156,11 @@ void ConfigItem::Unregister(void) GetAllObjects()->RemoveObject(GetSelf()); } +ConfigObject::Ptr ConfigItem::GetConfigObject(void) const +{ + return m_ConfigObject.lock(); +} + ConfigItem::Ptr ConfigItem::GetObject(const string& type, const string& name) { ConfigItem::TNMap::Range range; diff --git a/dyn/configitem.h b/dyn/configitem.h index 4358ce93f..fd93590b8 100644 --- a/dyn/configitem.h +++ b/dyn/configitem.h @@ -28,6 +28,8 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; + typedef ObjectSet Set; + typedef ObjectMap, ConfigItem::Ptr> TNMap; ConfigItem(const string& type, const string& name, const DebugInfo& debuginfo); @@ -43,10 +45,14 @@ public: void CalculateProperties(Dictionary::Ptr dictionary) const; - void Commit(void); + ConfigObject::Ptr Commit(void); void Unregister(void); - static ObjectSet::Ptr GetAllObjects(void); + ConfigObject::Ptr GetConfigObject(void) const; + + DebugInfo GetDebugInfo(void) const; + + static Set::Ptr GetAllObjects(void); static TNMap::Ptr GetObjectsByTypeAndName(void); static ConfigItem::Ptr GetObject(const string& type, const string& name); diff --git a/dyn/expression.cpp b/dyn/expression.cpp index 64413f1dc..0096aa4e2 100644 --- a/dyn/expression.cpp +++ b/dyn/expression.cpp @@ -30,42 +30,52 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const { Variant oldValue, newValue; - ExpressionList::Ptr exprl; - if (m_Value.GetType() == VariantObject) - exprl = dynamic_pointer_cast(m_Value.GetObject()); + ExpressionList::Ptr valueExprl; + Dictionary::Ptr valueDict; + if (m_Value.GetType() == VariantObject) { + valueExprl = dynamic_pointer_cast(m_Value.GetObject()); + valueDict = dynamic_pointer_cast(m_Value.GetObject()); + } newValue = m_Value; + Dictionary::Ptr dict; + switch (m_Operator) { case OperatorSet: - if (exprl) { - Dictionary::Ptr dict = boost::make_shared(); - exprl->Execute(dict); + if (valueExprl) { + dict = boost::make_shared(); + valueExprl->Execute(dict); newValue = dict; } break; case OperatorPlus: - if (exprl) { - dictionary->GetProperty(m_Key, &oldValue); + dictionary->GetProperty(m_Key, &oldValue); - Dictionary::Ptr dict; - if (oldValue.GetType() == VariantObject) - dict = dynamic_pointer_cast(oldValue.GetObject()); + if (oldValue.GetType() == VariantObject) + dict = dynamic_pointer_cast(oldValue.GetObject()); - if (!dict) { - if (!oldValue.IsEmpty()) { - stringstream message; - message << "Wrong argument types for += (non-dictionary and dictionary) (" << m_DebugInfo << ")"; - throw domain_error(message.str()); - } - - dict = boost::make_shared(); + if (!dict) { + if (!oldValue.IsEmpty()) { + stringstream message; + message << "Wrong argument types for += (non-dictionary and dictionary) (" << m_DebugInfo << ")"; + throw domain_error(message.str()); } - exprl->Execute(dict); - newValue = dict; + dict = boost::make_shared(); + } + + newValue = dict; + + if (valueExprl) { + valueExprl->Execute(dict); + } else if (valueDict) { + Dictionary::Iterator it; + for (it = valueDict->Begin(); it != valueDict->End(); it++) { + dict->SetProperty(it->first, it->second); + } } else { stringstream message; message << "+= only works for dictionaries (" << m_DebugInfo << ")"; diff --git a/icinga/icingaapplication.cpp b/icinga/icingaapplication.cpp index 16b9f9e3f..562ea9529 100644 --- a/icinga/icingaapplication.cpp +++ b/icinga/icingaapplication.cpp @@ -61,6 +61,11 @@ int IcingaApplication::Main(const vector& args) componentObjects->OnObjectRemoved.connect(boost::bind(&IcingaApplication::DeletedComponentHandler, this, _2)); componentObjects->Start(); + /* load convenience config component */ + ConfigObject::Ptr convenienceComponentConfig = boost::make_shared("component", "convenience"); + convenienceComponentConfig->SetLocal(true); + convenienceComponentConfig->Commit(); + /* load config file */ ConfigObject::Ptr fileComponentConfig = boost::make_shared("component", "configfile"); fileComponentConfig->SetLocal(true); -- 2.40.0