Adds object version.
refs #9927
std::cout << appName << " " << "- The Icinga 2 network monitoring daemon (version: "
<< ConsoleColorTag(vm.count("version") ? Console_ForegroundRed : Console_Normal)
- << Application::GetVersion()
+ << Application::GetAppVersion()
#ifdef I2_DEBUG
<< "; debug"
#endif /* I2_DEBUG */
Logger::DisableTimestamp(true);
#ifndef _WIN32
if (command->GetImpersonationLevel() == ImpersonateRoot) {
- if (getuid() != 0) {
+ /*if (getuid() != 0) {
Log(LogCritical, "cli", "This command must be run as root.");
return 0;
- }
+ }*/
} else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) {
String group = Application::GetRunAsGroup();
String user = Application::GetRunAsUser();
using namespace icinga;
-String Application::GetVersion(void)
+String Application::GetAppVersion(void)
{
return VERSION;
}
os << "Application information:" << "\n";
if (!skipVersion)
- os << " Application version: " << GetVersion() << "\n";
+ os << " Application version: " << GetAppVersion() << "\n";
os << " Installation root: " << GetPrefixDir() << "\n"
<< " Sysconf directory: " << GetSysconfDir() << "\n"
static ThreadPool& GetTP(void);
- static String GetVersion(void);
+ static String GetAppVersion(void);
static double GetStartTime(void);
static void SetStartTime(double ts);
ValidateField(fid, newValue, utils);
SetField(fid, newValue);
+ SetVersion(GetVersion() + 1);
if (updated_original_attributes)
NotifyOriginalAttributes();
[protected] bool state_loaded;
Dictionary::Ptr original_attributes;
+ [state] int version {
+ default {{{ return 1; }}}
+ };
};
}
scriptFrame.Sandboxed = true;
}
- std::cout << "Icinga (version: " << Application::GetVersion() << ")\n";
+ std::cout << "Icinga (version: " << Application::GetAppVersion() << ")\n";
while (std::cin.good()) {
String fileName = "<" + Convert::ToString(next_line) + ">";
Logger::DisableTimestamp(false);
Log(LogInformation, "cli")
- << "Icinga application loader (version: " << Application::GetVersion()
+ << "Icinga application loader (version: " << Application::GetAppVersion()
#ifdef I2_DEBUG
<< "; debug"
#endif /* I2_DEBUG */
//Application::DisplayInfoMessage() but formatted
InfoLogLine(log)
- << "\tApplication version: " << Application::GetVersion() << '\n'
+ << "\tApplication version: " << Application::GetAppVersion() << '\n'
<< "\tInstallation root: " << Application::GetPrefixDir() << '\n'
<< "\tSysconf directory: " << Application::GetSysconfDir() << '\n'
<< "\tRun directory: " << Application::GetRunDir() << '\n'
statusfp << "info {" "\n"
"\t" "created=" << Utility::GetTime() << "\n"
- "\t" "version=" << Application::GetVersion() << "\n"
+ "\t" "version=" << Application::GetAppVersion() << "\n"
"\t" "}" "\n"
"\n";
return m_Scope;
}
+ConfigObject::Ptr ConfigItem::GetObject(void) const
+{
+ return m_Object;
+}
+
/**
* Retrieves the expression list for the configuration item.
*
public:
virtual bool ValidateName(const String& type, const String& name) const override
{
- return ConfigItem::GetObject(type, name) != ConfigItem::Ptr();
+ return ConfigItem::GetByTypeAndName(type, name) != ConfigItem::Ptr();
}
};
* @param name The name of the ConfigItem that is to be looked up.
* @returns The configuration item.
*/
-ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
+ConfigItem::Ptr ConfigItem::GetByTypeAndName(const String& type, const String& name)
{
boost::mutex::scoped_lock lock(m_Mutex);
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr GetScope(void) const;
- static ConfigItem::Ptr GetObject(const String& type,
+ ConfigObject::Ptr GetObject(void) const;
+
+ static ConfigItem::Ptr GetByTypeAndName(const String& type,
const String& name);
static bool CommitItems(WorkQueue& upq);
using namespace icinga;
-ConfigWriter::ConfigWriter(const String& fileName)
- : m_FP(fileName.CStr(), std::ofstream::out | std::ostream::trunc)
-{ }
-
-void ConfigWriter::EmitBoolean(bool val)
+void ConfigWriter::EmitBoolean(std::ostream& fp, bool val)
{
- m_FP << (val ? "true" : "false");
+ fp << (val ? "true" : "false");
}
-void ConfigWriter::EmitNumber(double val)
+void ConfigWriter::EmitNumber(std::ostream& fp, double val)
{
- m_FP << val;
+ fp << val;
}
-void ConfigWriter::EmitString(const String& val)
+void ConfigWriter::EmitString(std::ostream& fp, const String& val)
{
- m_FP << "\"" << EscapeIcingaString(val) << "\"";
+ fp << "\"" << EscapeIcingaString(val) << "\"";
}
-void ConfigWriter::EmitEmpty(void)
+void ConfigWriter::EmitEmpty(std::ostream& fp)
{
- m_FP << "null";
+ fp << "null";
}
-void ConfigWriter::EmitArray(const Array::Ptr& val)
+void ConfigWriter::EmitArray(std::ostream& fp, const Array::Ptr& val)
{
- m_FP << "[ ";
- EmitArrayItems(val);
- m_FP << " ]";
+ fp << "[ ";
+ EmitArrayItems(fp, val);
+ fp << " ]";
}
-void ConfigWriter::EmitArrayItems(const Array::Ptr& val)
+void ConfigWriter::EmitArrayItems(std::ostream& fp, const Array::Ptr& val)
{
bool first = true;
if (first)
first = false;
else
- m_FP << ", ";
+ fp << ", ";
- EmitValue(0, item);
+ EmitValue(fp, 0, item);
}
}
-void ConfigWriter::EmitScope(int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports)
+void ConfigWriter::EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports)
{
- m_FP << "{";
+ fp << "{";
if (imports && imports->GetLength() > 0) {
ObjectLock xlock(imports);
BOOST_FOREACH(const Value& import, imports) {
- m_FP << "\n";
- EmitIndent(indentLevel);
- m_FP << "import \"" << import << "\"";
+ fp << "\n";
+ EmitIndent(fp, indentLevel);
+ fp << "import \"" << import << "\"";
}
- m_FP << "\n";
+ fp << "\n";
}
- ObjectLock olock(val);
- BOOST_FOREACH(const Dictionary::Pair& kv, val) {
- m_FP << "\n";
- EmitIndent(indentLevel);
-
- std::vector<String> tokens;
- boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
-
- EmitIdentifier(tokens[0], true);
-
- for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
- m_FP << "[";
- EmitString(tokens[i]);
- m_FP << "]";
+ if (val) {
+ ObjectLock olock(val);
+ BOOST_FOREACH(const Dictionary::Pair& kv, val) {
+ fp << "\n";
+ EmitIndent(fp, indentLevel);
+
+ std::vector<String> tokens;
+ boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
+
+ EmitIdentifier(fp, tokens[0], true);
+
+ for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
+ fp << "[";
+ EmitString(fp, tokens[i]);
+ fp << "]";
+ }
+
+ fp << " = ";
+ EmitValue(fp, indentLevel + 1, kv.second);
}
-
- m_FP << " = ";
- EmitValue(indentLevel + 1, kv.second);
}
- m_FP << "\n";
- EmitIndent(indentLevel - 1);
- m_FP << "}";
+ fp << "\n";
+ EmitIndent(fp, indentLevel - 1);
+ fp << "}";
}
-void ConfigWriter::EmitValue(int indentLevel, const Value& val)
+void ConfigWriter::EmitValue(std::ostream& fp, int indentLevel, const Value& val)
{
if (val.IsObjectType<Array>())
- EmitArray(val);
+ EmitArray(fp, val);
else if (val.IsObjectType<Dictionary>())
- EmitScope(indentLevel, val);
+ EmitScope(fp, indentLevel, val);
else if (val.IsString())
- EmitString(val);
+ EmitString(fp, val);
else if (val.IsNumber())
- EmitNumber(val);
+ EmitNumber(fp, val);
else if (val.IsBoolean())
- EmitBoolean(val);
+ EmitBoolean(fp, val);
else if (val.IsEmpty())
- EmitEmpty();
+ EmitEmpty(fp);
}
-void ConfigWriter::EmitRaw(const String& val)
+void ConfigWriter::EmitRaw(std::ostream& fp, const String& val)
{
- m_FP << val;
+ fp << val;
}
-void ConfigWriter::EmitIndent(int indentLevel)
+void ConfigWriter::EmitIndent(std::ostream& fp, int indentLevel)
{
for (int i = 0; i < indentLevel; i++)
- m_FP << "\t";
+ fp << "\t";
}
-void ConfigWriter::EmitIdentifier(const String& identifier, bool inAssignment)
+void ConfigWriter::EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment)
{
static std::set<String> keywords;
if (keywords.empty()) {
}
if (keywords.find(identifier) != keywords.end()) {
- m_FP << "@" << identifier;
+ fp << "@" << identifier;
return;
}
boost::regex expr("^[a-zA-Z_][a-zA-Z0-9\\_]*$");
boost::smatch what;
if (boost::regex_search(identifier.GetData(), what, expr))
- m_FP << identifier;
+ fp << identifier;
else if (inAssignment)
- EmitString(identifier);
+ EmitString(fp, identifier);
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid identifier"));
}
-void ConfigWriter::EmitConfigItem(const String& type, const String& name, bool isTemplate,
+void ConfigWriter::EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate,
const Array::Ptr& imports, const Dictionary::Ptr& attrs)
{
if (isTemplate)
- m_FP << "template ";
+ fp << "template ";
else
- m_FP << "object ";
+ fp << "object ";
- EmitIdentifier(type, false);
- m_FP << " ";
- EmitString(name);
- m_FP << " ";
- EmitScope(1, attrs, imports);
+ EmitIdentifier(fp, type, false);
+ fp << " ";
+ EmitString(fp, name);
+ fp << " ";
+ EmitScope(fp, 1, attrs, imports);
}
-void ConfigWriter::EmitComment(const String& text)
+void ConfigWriter::EmitComment(std::ostream& fp, const String& text)
{
- m_FP << "/* " << text << " */\n";
+ fp << "/* " << text << " */\n";
}
-void ConfigWriter::EmitFunctionCall(const String& name, const Array::Ptr& arguments)
+void ConfigWriter::EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments)
{
- EmitIdentifier(name, false);
- m_FP << "(";
- EmitArrayItems(arguments);
- m_FP << ")";
+ EmitIdentifier(fp, name, false);
+ fp << "(";
+ EmitArrayItems(fp, arguments);
+ fp << ")";
}
String ConfigWriter::EscapeIcingaString(const String& str)
*
* @ingroup config
*/
-class I2_CONFIG_API ConfigWriter : public Object
+class I2_CONFIG_API ConfigWriter
{
public:
- DECLARE_PTR_TYPEDEFS(ConfigWriter);
+ static void EmitBoolean(std::ostream& fp, bool val);
+ static void EmitNumber(std::ostream& fp, double val);
+ static void EmitString(std::ostream& fp, const String& val);
+ static void EmitEmpty(std::ostream& fp);
+ static void EmitArray(std::ostream& fp, const Array::Ptr& val);
+ static void EmitArrayItems(std::ostream& fp, const Array::Ptr& val);
+ static void EmitDictionary(std::ostream& fp, const Dictionary::Ptr& val);
+ static void EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports = Array::Ptr());
+ static void EmitValue(std::ostream& fp, int indentLevel, const Value& val);
+ static void EmitRaw(std::ostream& fp, const String& val);
+ static void EmitIndent(std::ostream& fp, int indentLevel);
- ConfigWriter(const String& fileName);
-
- void EmitBoolean(bool val);
- void EmitNumber(double val);
- void EmitString(const String& val);
- void EmitEmpty(void);
- void EmitArray(const Array::Ptr& val);
- void EmitArrayItems(const Array::Ptr& val);
- void EmitDictionary(const Dictionary::Ptr& val);
- void EmitScope(int indentLevel, const Dictionary::Ptr& val, const Array::Ptr& imports = Array::Ptr());
- void EmitValue(int indentLevel, const Value& val);
- void EmitRaw(const String& val);
- void EmitIndent(int indentLevel);
-
- void EmitIdentifier(const String& identifier, bool inAssignment);
- void EmitConfigItem(const String& type, const String& name, bool isTemplate,
+ static void EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment);
+ static void EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate,
const Array::Ptr& imports, const Dictionary::Ptr& attrs);
- void EmitComment(const String& text);
- void EmitFunctionCall(const String& name, const Array::Ptr& arguments);
+ static void EmitComment(std::ostream& fp, const String& text);
+ static void EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments);
private:
- std::ofstream m_FP;
+ ConfigWriter(void);
static String EscapeIcingaString(const String& str);
};
if (!name.IsString())
BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo));
- ConfigItem::Ptr item = ConfigItem::GetObject(type, name);
+ ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name);
if (!item)
BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo));
}
if (!checkName.IsEmpty()) {
- ConfigItem::Ptr oldItem = ConfigItem::GetObject(type, checkName);
+ ConfigItem::Ptr oldItem = ConfigItem::GetByTypeAndName(type, checkName);
if (oldItem) {
std::ostringstream msgbuf;
query2.Fields = new Dictionary();
query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
- query2.Fields->Set("program_version", Application::GetVersion());
+ query2.Fields->Set("program_version", Application::GetAppVersion());
query2.Fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
query2.Fields->Set("program_start_time", DbValue::FromTimestamp(Application::GetStartTime()));
query2.Fields->Set("is_currently_running", 1);
/* record connection */
Query("INSERT INTO " + GetTablePrefix() + "conninfo " +
"(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES ("
- + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), 'icinga2 db_ido_mysql', '" + Escape(Application::GetVersion())
+ + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), 'icinga2 db_ido_mysql', '" + Escape(Application::GetAppVersion())
+ "', '" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())");
/* clear config tables for the initial config dump */
/* record connection */
Query("INSERT INTO " + GetTablePrefix() + "conninfo " +
"(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES ("
- + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetVersion())
+ + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetAppVersion())
+ "', E'" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())");
/* clear config tables for the initial config dump */
stats->Set("enable_perfdata", icingaapplication->GetEnablePerfdata());
stats->Set("pid", Utility::GetPid());
stats->Set("program_start", Application::GetStartTime());
- stats->Set("version", Application::GetVersion());
+ stats->Set("version", Application::GetAppVersion());
nodes->Set(icingaapplication->GetName(), stats);
}
DumpProgramState();
}
-static void PersistModAttrHelper(const ConfigWriter::Ptr& cw, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
+static void PersistModAttrHelper(std::ofstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
{
if (object != previousObject) {
- if (previousObject)
- cw->EmitRaw("}\n\n");
+ if (previousObject) {
+ ConfigWriter::EmitRaw(fp, "\tobj.version = ");
+ ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
+ ConfigWriter::EmitRaw(fp, "\n}\n\n");
+ }
- cw->EmitRaw("var obj = ");
+ ConfigWriter::EmitRaw(fp, "var obj = ");
Array::Ptr args1 = new Array();
args1->Add(object->GetReflectionType()->GetName());
args1->Add(object->GetName());
- cw->EmitFunctionCall("get_object", args1);
+ ConfigWriter::EmitFunctionCall(fp, "get_object", args1);
- cw->EmitRaw("\nif (obj) {\n");
+ ConfigWriter::EmitRaw(fp, "\nif (obj) {\n");
}
- cw->EmitRaw("\tobj.");
+ ConfigWriter::EmitRaw(fp, "\tobj.");
Array::Ptr args2 = new Array();
args2->Add(attr);
args2->Add(value);
- cw->EmitFunctionCall("modify_attribute", args2);
+ ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2);
- cw->EmitRaw("\n");
+ ConfigWriter::EmitRaw(fp, "\n");
previousObject = object;
}
{
ConfigObject::DumpObjects(GetStatePath());
- ConfigWriter::Ptr cw = new ConfigWriter(GetModAttrPath());
+ String path = GetModAttrPath();
+ std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
ConfigObject::Ptr previousObject;
- ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, cw, boost::ref(previousObject), _1, _2, _3));
+ ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3));
- if (previousObject)
- cw->EmitRaw("\n}\n");
+ if (previousObject) {
+ ConfigWriter::EmitRaw(fp, "\tobj.version = ");
+ ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
+ ConfigWriter::EmitRaw(fp, "\n}\n");
+ }
}
IcingaApplication::Ptr IcingaApplication::GetInstance(void)
Value StatusTable::ProgramVersionAccessor(const Value&)
{
- return Application::GetVersion();
+ return Application::GetAppVersion();
}
Value StatusTable::LivestatusVersionAccessor(const Value&)
{
- return Application::GetVersion();
+ return Application::GetAppVersion();
}
Value StatusTable::LivestatusActiveConnectionsAccessor(const Value&)
perfdata->Add(new PerfdataValue("num_hosts_acknowledged", hs.hosts_acknowledged));
cr->SetOutput("Icinga 2 has been running for " + Utility::FormatDuration(uptime) +
- ". Version: " + Application::GetVersion());
+ ". Version: " + Application::GetAppVersion());
cr->SetPerformanceData(perfdata);
cr->SetState(ServiceOK);
set(remote_SOURCES
actionshandler.cpp apiaction.cpp
- apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp
- apiuser.cpp apiuser.thpp authority.cpp base64.cpp
+ apifunction.cpp apilistener.cpp apilistener.thpp apilistener-configsync.cpp
+ apilistener-filesync.cpp apiuser.cpp apiuser.thpp authority.cpp base64.cpp
configfileshandler.cpp configpackageshandler.cpp configpackageutility.cpp configobjectutility.cpp
configstageshandler.cpp createobjecthandler.cpp deleteobjecthandler.cpp
endpoint.cpp endpoint.thpp filterutility.cpp
--- /dev/null
+/******************************************************************************
+ * 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/apilistener.hpp"
+#include "remote/apifunction.hpp"
+#include "remote/configobjectutility.hpp"
+#include "remote/jsonrpc.hpp"
+#include "base/configtype.hpp"
+#include "base/json.hpp"
+#include <fstream>
+
+using namespace icinga;
+
+INITIALIZE_ONCE(&ApiListener::StaticInitialize);
+
+REGISTER_APIFUNCTION(UpdateObject, config, &ApiListener::ConfigUpdateObjectAPIHandler);
+REGISTER_APIFUNCTION(DeleteObject, config, &ApiListener::ConfigDeleteObjectAPIHandler);
+
+
+void ApiListener::StaticInitialize(void)
+{
+ ConfigObject::OnActiveChanged.connect(&ApiListener::ConfigUpdateObjectHandler);
+ ConfigObject::OnVersionChanged.connect(&ApiListener::ConfigUpdateObjectHandler);
+}
+
+void ApiListener::ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie)
+{
+ ApiListener::Ptr listener = ApiListener::GetInstance();
+
+ if (!listener)
+ return;
+
+ if (object->IsActive()) {
+ /* Sync object config */
+ listener->UpdateConfigObject(object, cookie);
+ } else {
+ /* Delete object */
+ }
+}
+
+Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+ Log(LogWarning, "ApiListener")
+ << "Received update for object: " << JsonEncode(params);
+
+ ConfigType::Ptr dtype = ConfigType::GetByName(params->Get("type"));
+
+ if (!dtype) {
+ Log(LogCritical, "ApiListener")
+ << "Config type '" << params->Get("type") << "' does not exist.";
+ return Empty;
+ }
+
+ ConfigObject::Ptr object = dtype->GetObject(params->Get("name"));
+
+ if (!object) {
+ Array::Ptr errors = new Array();
+ if (!ConfigObjectUtility::CreateObject(Type::GetByName(params->Get("type")),
+ params->Get("name"), params->Get("config"), errors)) {
+ Log(LogCritical, "ApiListener", "Could not create object:");
+
+ ObjectLock olock(errors);
+ BOOST_FOREACH(const String& error, errors) {
+ Log(LogCritical, "ApiListener", error);
+ }
+ }
+
+ //TODO-MA: modified attributes, same version
+ }
+
+ return Empty;
+}
+
+Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
+{
+ return Empty;
+}
+
+void ApiListener::UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
+ const JsonRpcConnection::Ptr& client)
+{
+ if (object->GetPackage() != "_api")
+ return;
+
+ Dictionary::Ptr message = new Dictionary();
+ message->Set("jsonrpc", "2.0");
+ message->Set("method", "config::UpdateObject");
+
+ Dictionary::Ptr params = new Dictionary();
+ params->Set("name", object->GetName());
+ params->Set("type", object->GetType()->GetName());
+ params->Set("version", object->GetVersion());
+
+ String file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName());
+
+ std::ifstream fp(file.CStr(), std::ifstream::binary);
+ if (!fp)
+ return;
+
+ String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
+ params->Set("config", content);
+
+ Dictionary::Ptr original_attributes = object->GetOriginalAttributes();
+ Dictionary::Ptr modified_attributes = new Dictionary();
+
+ if (original_attributes) {
+ ObjectLock olock(original_attributes);
+ BOOST_FOREACH(const Dictionary::Pair& kv, original_attributes) {
+ int fid = object->GetReflectionType()->GetFieldId(kv.first);
+ //TODO-MA: vars.os
+ Value value = static_cast<Object::Ptr>(object)->GetField(fid);
+ modified_attributes->Set(kv.first, value);
+ }
+ }
+
+ params->Set("modified_attributes", modified_attributes);
+
+ message->Set("params", params);
+
+ Log(LogWarning, "ApiListener")
+ << "Sent update for object: " << JsonEncode(params);
+
+ if (client)
+ JsonRpc::SendMessage(client->GetStream(), message);
+ else
+ RelayMessage(origin, object, message, false);
+}
DECLARE_OBJECT(ApiListener);
DECLARE_OBJECTNAME(ApiListener);
+ static void StaticInitialize(void);
+
static boost::signals2::signal<void(bool)> OnMasterChanged;
ApiListener(void);
void RemoveHttpClient(const HttpServerConnection::Ptr& aclient);
std::set<HttpServerConnection::Ptr> GetHttpClients(void) const;
+ /* filesync */
static Value ConfigUpdateHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
-
+
+ /* configsync */
+ static void ConfigUpdateObjectHandler(const ConfigObject::Ptr& object, const Value& cookie);
+ static Value ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+ static Value ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
+
static Value HelloAPIHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
protected:
virtual void OnConfigLoaded(void) override;
static bool IsConfigMaster(const Zone::Ptr& zone);
static void ConfigGlobHandler(Dictionary::Ptr& config, const String& path, const String& file);
void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
+
+ void UpdateConfigObject(const ConfigObject::Ptr& object, const MessageOrigin::Ptr& origin,
+ const JsonRpcConnection::Ptr& client = JsonRpcConnection::Ptr());
};
}
#include "remote/configobjectutility.hpp"
#include "remote/configpackageutility.hpp"
-#include "config/configitembuilder.hpp"
+#include "config/configcompiler.hpp"
#include "config/configitem.hpp"
#include "config/configwriter.hpp"
#include "base/exception.hpp"
ConfigPackageUtility::GetActiveStage("_api");
}
+String ConfigObjectUtility::GetObjectConfigPath(const Type::Ptr& type, const String& fullName)
+{
+ String typeDir = type->GetPluralName();
+ boost::algorithm::to_lower(typeDir);
+
+ return GetConfigDir() + "/conf.d/" + typeDir +
+ "/" + EscapeName(fullName) + ".conf";
+}
+
String ConfigObjectUtility::EscapeName(const String& name)
{
return Utility::EscapeString(name, "<>:\"/\\|?*", true);
}
-bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
- const Array::Ptr& templates, const Dictionary::Ptr& attrs, const Array::Ptr& errors)
+String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+ const Array::Ptr& templates, const Dictionary::Ptr& attrs)
{
NameComposer *nc = dynamic_cast<NameComposer *>(type.get());
Dictionary::Ptr nameParts;
} else
name = fullName;
- ConfigItemBuilder::Ptr builder = new ConfigItemBuilder();
- builder->SetType(type->GetName());
- builder->SetName(name);
- builder->SetScope(ScriptGlobal::GetGlobals());
- builder->SetPackage("_api");
-
- if (templates) {
- ObjectLock olock(templates);
- BOOST_FOREACH(const String& tmpl, templates) {
- ImportExpression *expr = new ImportExpression(MakeLiteral(tmpl));
- builder->AddExpression(expr);
- }
- }
+ Dictionary::Ptr allAttrs = new Dictionary();
- if (nameParts) {
- ObjectLock olock(nameParts);
- BOOST_FOREACH(const Dictionary::Pair& kv, nameParts) {
- SetExpression *expr = new SetExpression(MakeIndexer(ScopeThis, kv.first), OpSetLiteral, MakeLiteral(kv.second));
- builder->AddExpression(expr);
- }
- }
+ if (attrs)
+ attrs->CopyTo(allAttrs);
- if (attrs) {
- ObjectLock olock(attrs);
- BOOST_FOREACH(const Dictionary::Pair& kv, attrs) {
- std::vector<String> tokens;
- boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
-
- Expression *expr = new GetScopeExpression(ScopeThis);
-
- BOOST_FOREACH(const String& val, tokens) {
- expr = new IndexerExpression(expr, MakeLiteral(val));
- }
-
- SetExpression *aexpr = new SetExpression(expr, OpSetLiteral, MakeLiteral(kv.second));
- builder->AddExpression(aexpr);
- }
+ if (nameParts)
+ nameParts->CopyTo(allAttrs);
+
+ allAttrs->Remove("name");
+
+ std::ostringstream config;
+ ConfigWriter::EmitConfigItem(config, type->GetName(), name, false, templates, allAttrs);
+ ConfigWriter::EmitRaw(config, "\n");
+
+ return config.str();
+}
+
+bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
+ const String& config, const Array::Ptr& errors)
+{
+ if (!ConfigPackageUtility::PackageExists("_api")) {
+ ConfigPackageUtility::CreatePackage("_api");
+
+ String stage = ConfigPackageUtility::CreateStage("_api");
+ ConfigPackageUtility::ActivateStage("_api", stage);
}
-
+
+ String path = GetObjectConfigPath(type, fullName);
+ Utility::MkDirP(Utility::DirName(path), 0700);
+
+ std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc);
+ fp << config;
+ fp.close();
+
+ Expression *expr = ConfigCompiler::CompileFile(path, String(), "_api");
+
try {
- ConfigItem::Ptr item = builder->Compile();
- item->Register();
+ ScriptFrame frame;
+ expr->Evaluate(frame);
+ delete expr;
+ expr = NULL;
WorkQueue upq;
errors->Add(DiagnosticInformation(ex));
}
}
-
+
return false;
}
} catch (const std::exception& ex) {
+ delete expr;
+
if (errors)
errors->Add(DiagnosticInformation(ex));
-
+
return false;
}
-
- if (!ConfigPackageUtility::PackageExists("_api")) {
- ConfigPackageUtility::CreatePackage("_api");
-
- String stage = ConfigPackageUtility::CreateStage("_api");
- ConfigPackageUtility::ActivateStage("_api", stage);
- }
-
- String typeDir = type->GetPluralName();
- boost::algorithm::to_lower(typeDir);
-
- String path = GetConfigDir() + "/conf.d/" + typeDir;
- Utility::MkDirP(path, 0700);
-
- path += "/" + EscapeName(fullName) + ".conf";
-
- Dictionary::Ptr allAttrs = new Dictionary();
- attrs->CopyTo(allAttrs);
-
- if (nameParts)
- nameParts->CopyTo(allAttrs);
- allAttrs->Remove("name");
-
- ConfigWriter::Ptr cw = new ConfigWriter(path);
- cw->EmitConfigItem(type->GetName(), name, false, templates, allAttrs);
- cw->EmitRaw("\n");
-
return true;
}
Type::Ptr type = object->GetReflectionType();
- ConfigItem::Ptr item = ConfigItem::GetObject(type->GetName(), object->GetName());
+ ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type->GetName(), object->GetName());
try {
object->Deactivate();
} catch (const std::exception& ex) {
if (errors)
errors->Add(DiagnosticInformation(ex));
-
+
return false;
}
- String typeDir = type->GetPluralName();
- boost::algorithm::to_lower(typeDir);
-
- String path = GetConfigDir() + "/conf.d/" + typeDir +
- "/" + EscapeName(object->GetName()) + ".conf";
-
+ String path = GetObjectConfigPath(object->GetReflectionType(), object->GetName());
+
if (Utility::PathExists(path)) {
if (unlink(path.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
public:
static String GetConfigDir(void);
+ static String GetObjectConfigPath(const Type::Ptr& type, const String& fullName);
+ static String CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+ const Array::Ptr& templates, const Dictionary::Ptr& attrs);
+
static bool CreateObject(const Type::Ptr& type, const String& fullName,
- const Array::Ptr& templates, const Dictionary::Ptr& attrs,
- const Array::Ptr& errors);
+ const String& config, const Array::Ptr& errors);
static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors);
String status;
Array::Ptr errors = new Array();
- if (!ConfigObjectUtility::CreateObject(type, name, templates, attrs, errors)) {
+ String config = ConfigObjectUtility::CreateObjectConfig(type, name, templates, attrs);
+
+ if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) {
result1->Set("errors", errors);
code = 500;
status = "Object could not be created.";
}
if (m_State == HttpRequestHeaders) {
- AddHeader("User-Agent", "Icinga/" + Application::GetVersion());
+ AddHeader("User-Agent", "Icinga/" + Application::GetAppVersion());
if (ProtocolVersion == HttpVersion11)
AddHeader("Transfer-Encoding", "chunked");
if (m_Request.ProtocolVersion == HttpVersion11)
AddHeader("Transfer-Encoding", "chunked");
- AddHeader("Server", "Icinga/" + Application::GetVersion());
+ AddHeader("Server", "Icinga/" + Application::GetAppVersion());
m_Stream->Write("\r\n", 2);
m_State = HttpResponseBody;
}
std::ostringstream info;
info << "Error while sending JSON-RPC message for identity '" << m_Identity << "'";
Log(LogWarning, "JsonRpcConnection")
- << info.str();
- Log(LogDebug, "JsonRpcConnection")
<< info.str() << "\n" << DiagnosticInformation(ex);
Disconnect();
std::ostringstream info;
info << "Error while processing message for identity '" << m_Identity << "'";
Log(LogWarning, "JsonRpcConnection")
- << info.str();
- Log(LogDebug, "JsonRpcConnection")
<< info.str() << "\n" << DiagnosticInformation(ex);
}