diff --git a/doc/9-appendix.md b/doc/9-appendix.md index cfdc7cbef..d00ece34a 100644 --- a/doc/9-appendix.md +++ b/doc/9-appendix.md @@ -212,6 +212,9 @@ New columns: ----------|-------------- hosts | is_reachable services | is_reachable + hosts | cv_is_json + services | cv_is_json + contacts | cv_is_json hosts | check_source services | check_source downtimes | triggers diff --git a/lib/icinga/compatutility.cpp b/lib/icinga/compatutility.cpp index bb2ab7570..2a699893e 100644 --- a/lib/icinga/compatutility.cpp +++ b/lib/icinga/compatutility.cpp @@ -126,7 +126,7 @@ String CompatUtility::GetCheckableCommandArgs(const Checkable::Ptr& checkable) Dictionary::Ptr command_vars = command->GetVars(); if (command_vars) { - BOOST_FOREACH(Dictionary::Pair kv, command_vars) { + BOOST_FOREACH(const Dictionary::Pair& kv, command_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); @@ -137,7 +137,7 @@ String CompatUtility::GetCheckableCommandArgs(const Checkable::Ptr& checkable) Dictionary::Ptr host_vars = host->GetVars(); if (host_vars) { - BOOST_FOREACH(Dictionary::Pair kv, host_vars) { + BOOST_FOREACH(const Dictionary::Pair& kv, host_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); @@ -151,7 +151,7 @@ String CompatUtility::GetCheckableCommandArgs(const Checkable::Ptr& checkable) Dictionary::Ptr service_vars = service->GetVars(); if (service_vars) { - BOOST_FOREACH(Dictionary::Pair kv, service_vars) { + BOOST_FOREACH(const Dictionary::Pair& kv, service_vars) { String macro = "$" + kv.first + "$"; // this is too simple if (command_line.Contains(macro)) args->Set(kv.first, kv.second); @@ -163,7 +163,7 @@ String CompatUtility::GetCheckableCommandArgs(const Checkable::Ptr& checkable) } String arg_string; - BOOST_FOREACH(Dictionary::Pair kv, args) { + BOOST_FOREACH(const Dictionary::Pair& kv, args) { arg_string += Convert::ToString(kv.first) + "=" + Convert::ToString(kv.second) + "!"; } return arg_string; @@ -388,12 +388,15 @@ Dictionary::Ptr CompatUtility::GetCustomAttributeConfig(const CustomVarObject::P if (!vars) return Dictionary::Ptr(); + String key; + Value value; + ObjectLock olock(vars); BOOST_FOREACH(const Dictionary::Pair& kv, vars) { - if (!kv.first.IsEmpty()) { - if (!IsLegacyAttribute(object, kv.first)) - varsvars->Set(kv.first, kv.second); - } + if (kv.first.IsEmpty() || IsLegacyAttribute(object, kv.first)) + continue; + + varsvars->Set(kv.first, kv.second); } return varsvars; diff --git a/lib/livestatus/contactstable.cpp b/lib/livestatus/contactstable.cpp index e62dc50ce..606ce995c 100644 --- a/lib/livestatus/contactstable.cpp +++ b/lib/livestatus/contactstable.cpp @@ -23,6 +23,7 @@ #include "icinga/compatutility.hpp" #include "base/dynamictype.hpp" #include "base/objectlock.hpp" +#include "base/json.hpp" #include "base/utility.hpp" #include #include @@ -53,6 +54,8 @@ void ContactsTable::AddColumns(Table *table, const String& prefix, table->AddColumn(prefix + "vars_variables", Column(&ContactsTable::CustomVariablesAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes", Column(&ContactsTable::ModifiedAttributesAccessor, objectAccessor)); table->AddColumn(prefix + "modified_attributes_list", Column(&ContactsTable::ModifiedAttributesListAccessor, objectAccessor)); + table->AddColumn(prefix + "cv_is_json", Column(&ContactsTable::CVIsJsonAccessor, objectAccessor)); + } String ContactsTable::GetName(void) const @@ -200,7 +203,12 @@ Value ContactsTable::CustomVariableNamesAccessor(const Value& row) if (!user) return Empty; - Dictionary::Ptr vars = user->GetVars(); + Dictionary::Ptr vars; + + { + ObjectLock olock(user); + vars = CompatUtility::GetCustomAttributeConfig(user); + } if (!vars) return Empty; @@ -208,10 +216,8 @@ Value ContactsTable::CustomVariableNamesAccessor(const Value& row) Array::Ptr cv = make_shared(); ObjectLock olock(vars); - String key; - Value value; - BOOST_FOREACH(boost::tie(key, value), vars) { - cv->Add(key); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + cv->Add(kv.first); } return cv; @@ -224,7 +230,12 @@ Value ContactsTable::CustomVariableValuesAccessor(const Value& row) if (!user) return Empty; - Dictionary::Ptr vars = user->GetVars(); + Dictionary::Ptr vars; + + { + ObjectLock olock(user); + vars = CompatUtility::GetCustomAttributeConfig(user); + } if (!vars) return Empty; @@ -232,10 +243,11 @@ Value ContactsTable::CustomVariableValuesAccessor(const Value& row) Array::Ptr cv = make_shared(); ObjectLock olock(vars); - String key; - Value value; - BOOST_FOREACH(boost::tie(key, value), vars) { - cv->Add(value); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv->Add(JsonEncode(kv.second)); + else + cv->Add(kv.second); } return cv; @@ -248,7 +260,12 @@ Value ContactsTable::CustomVariablesAccessor(const Value& row) if (!user) return Empty; - Dictionary::Ptr vars = user->GetVars(); + Dictionary::Ptr vars; + + { + ObjectLock olock(user); + vars = CompatUtility::GetCustomAttributeConfig(user); + } if (!vars) return Empty; @@ -256,18 +273,49 @@ Value ContactsTable::CustomVariablesAccessor(const Value& row) Array::Ptr cv = make_shared(); ObjectLock olock(vars); - String key; - Value value; - BOOST_FOREACH(boost::tie(key, value), vars) { + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { Array::Ptr key_val = make_shared(); - key_val->Add(key); - key_val->Add(value); + key_val->Add(kv.first); + + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + key_val->Add(JsonEncode(kv.second)); + else + key_val->Add(kv.second); + cv->Add(key_val); } return cv; } +Value ContactsTable::CVIsJsonAccessor(const Value& row) +{ + User::Ptr user = static_cast(row); + + if (!user) + return Empty; + + Dictionary::Ptr vars; + + { + ObjectLock olock(user); + vars = CompatUtility::GetCustomAttributeConfig(user); + } + + if (!vars) + return Empty; + + bool cv_is_json = false; + + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv_is_json = true; + } + + return cv_is_json; +} + Value ContactsTable::ModifiedAttributesAccessor(const Value& row) { User::Ptr user = static_cast(row); diff --git a/lib/livestatus/contactstable.hpp b/lib/livestatus/contactstable.hpp index e8997bc0f..3f9084efb 100644 --- a/lib/livestatus/contactstable.hpp +++ b/lib/livestatus/contactstable.hpp @@ -61,6 +61,7 @@ protected: static Value CustomVariablesAccessor(const Value& row); static Value ModifiedAttributesAccessor(const Value& row); static Value ModifiedAttributesListAccessor(const Value& row); + static Value CVIsJsonAccessor(const Value& row); }; } diff --git a/lib/livestatus/hoststable.cpp b/lib/livestatus/hoststable.cpp index 1359d3388..36c9a4b0c 100644 --- a/lib/livestatus/hoststable.cpp +++ b/lib/livestatus/hoststable.cpp @@ -28,6 +28,7 @@ #include "icinga/compatutility.hpp" #include "base/dynamictype.hpp" #include "base/objectlock.hpp" +#include "base/json.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include @@ -160,6 +161,7 @@ void HostsTable::AddColumns(Table *table, const String& prefix, table->AddColumn(prefix + "services_with_info", Column(&HostsTable::ServicesWithInfoAccessor, objectAccessor)); table->AddColumn(prefix + "check_source", Column(&HostsTable::CheckSourceAccessor, objectAccessor)); table->AddColumn(prefix + "is_reachable", Column(&HostsTable::IsReachableAccessor, objectAccessor)); + table->AddColumn(prefix + "cv_is_json", Column(&HostsTable::CVIsJsonAccessor, objectAccessor)); } String HostsTable::GetName(void) const @@ -1058,10 +1060,9 @@ Value HostsTable::CustomVariableNamesAccessor(const Value& row) Array::Ptr cv = make_shared(); - String key; - Value value; - BOOST_FOREACH(tie(key, value), vars) { - cv->Add(key); + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + cv->Add(kv.first); } return cv; @@ -1086,10 +1087,12 @@ Value HostsTable::CustomVariableValuesAccessor(const Value& row) Array::Ptr cv = make_shared(); - String key; - Value value; - BOOST_FOREACH(tie(key, value), vars) { - cv->Add(value); + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv->Add(JsonEncode(kv.second)); + else + cv->Add(kv.second); } return cv; @@ -1114,18 +1117,50 @@ Value HostsTable::CustomVariablesAccessor(const Value& row) Array::Ptr cv = make_shared(); - String key; - Value value; - BOOST_FOREACH(tie(key, value), vars) { + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { Array::Ptr key_val = make_shared(); - key_val->Add(key); - key_val->Add(value); + key_val->Add(kv.first); + + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + key_val->Add(JsonEncode(kv.second)); + else + key_val->Add(kv.second); + cv->Add(key_val); } return cv; } +Value HostsTable::CVIsJsonAccessor(const Value& row) +{ + Host::Ptr host = static_cast(row); + + if (!host) + return Empty; + + Dictionary::Ptr vars; + + { + ObjectLock olock(host); + vars = CompatUtility::GetCustomAttributeConfig(host); + } + + if (!vars) + return Empty; + + bool cv_is_json = false; + + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv_is_json = true; + } + + return cv_is_json; +} + Value HostsTable::ParentsAccessor(const Value& row) { Host::Ptr host = static_cast(row); diff --git a/lib/livestatus/hoststable.hpp b/lib/livestatus/hoststable.hpp index 57f260483..d033ad90b 100644 --- a/lib/livestatus/hoststable.hpp +++ b/lib/livestatus/hoststable.hpp @@ -143,6 +143,7 @@ protected: static Value ServicesWithInfoAccessor(const Value& row); static Value CheckSourceAccessor(const Value& row); static Value IsReachableAccessor(const Value& row); + static Value CVIsJsonAccessor(const Value& row); }; } diff --git a/lib/livestatus/servicestable.cpp b/lib/livestatus/servicestable.cpp index e001784e4..8bffa2b21 100644 --- a/lib/livestatus/servicestable.cpp +++ b/lib/livestatus/servicestable.cpp @@ -29,6 +29,7 @@ #include "icinga/compatutility.hpp" #include "base/dynamictype.hpp" #include "base/objectlock.hpp" +#include "base/json.hpp" #include "base/convert.hpp" #include "base/utility.hpp" #include @@ -129,6 +130,7 @@ void ServicesTable::AddColumns(Table *table, const String& prefix, table->AddColumn(prefix + "contact_groups", Column(&ServicesTable::ContactGroupsAccessor, objectAccessor)); table->AddColumn(prefix + "check_source", Column(&ServicesTable::CheckSourceAccessor, objectAccessor)); table->AddColumn(prefix + "is_reachable", Column(&ServicesTable::IsReachableAccessor, objectAccessor)); + table->AddColumn(prefix + "cv_is_json", Column(&ServicesTable::CVIsJsonAccessor, objectAccessor)); HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor)); } @@ -1063,8 +1065,8 @@ Value ServicesTable::CustomVariableNamesAccessor(const Value& row) Array::Ptr cv = make_shared(); ObjectLock olock(vars); - BOOST_FOREACH(const Dictionary::Pair kv, vars) { - cv->Add(kv.second); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + cv->Add(kv.first); } return cv; @@ -1091,7 +1093,10 @@ Value ServicesTable::CustomVariableValuesAccessor(const Value& row) ObjectLock olock(vars); BOOST_FOREACH(const Dictionary::Pair& kv, vars) { - cv->Add(kv.second); + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv->Add(JsonEncode(kv.second)); + else + cv->Add(kv.second); } return cv; @@ -1116,18 +1121,50 @@ Value ServicesTable::CustomVariablesAccessor(const Value& row) Array::Ptr cv = make_shared(); - String key; - Value value; - BOOST_FOREACH(tie(key, value), vars) { + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { Array::Ptr key_val = make_shared(); - key_val->Add(key); - key_val->Add(value); + key_val->Add(kv.first); + + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + key_val->Add(JsonEncode(kv.second)); + else + key_val->Add(kv.second); + cv->Add(key_val); } return cv; } +Value ServicesTable::CVIsJsonAccessor(const Value& row) +{ + Service::Ptr service = static_cast(row); + + if (!service) + return Empty; + + Dictionary::Ptr vars; + + { + ObjectLock olock(service); + vars = CompatUtility::GetCustomAttributeConfig(service); + } + + if (!vars) + return Empty; + + bool cv_is_json = false; + + ObjectLock olock(vars); + BOOST_FOREACH(const Dictionary::Pair& kv, vars) { + if (kv.second.IsObjectType() || kv.second.IsObjectType()) + cv_is_json = true; + } + + return cv_is_json; +} + Value ServicesTable::GroupsAccessor(const Value& row) { Service::Ptr service = static_cast(row); diff --git a/lib/livestatus/servicestable.hpp b/lib/livestatus/servicestable.hpp index 8446a5819..7b7e037e9 100644 --- a/lib/livestatus/servicestable.hpp +++ b/lib/livestatus/servicestable.hpp @@ -126,6 +126,7 @@ protected: static Value ContactGroupsAccessor(const Value& row); static Value CheckSourceAccessor(const Value& row); static Value IsReachableAccessor(const Value& row); + static Value CVIsJsonAccessor(const Value& row); }; } diff --git a/test/livestatus/queries/host/customvar b/test/livestatus/queries/host/customvar index b98ff3c54..57f2e0012 100644 --- a/test/livestatus/queries/host/customvar +++ b/test/livestatus/queries/host/customvar @@ -1,4 +1,4 @@ -GET hosts -Columns: custom_variable_names custom_variable_values custom_variables +GET hosts +Columns: name custom_variable_names custom_variable_values custom_variables cv_is_json ResponseHeader: fixed16 diff --git a/test/livestatus/queries/service/customvar b/test/livestatus/queries/service/customvar index 8f52f27a7..75c452ca4 100644 --- a/test/livestatus/queries/service/customvar +++ b/test/livestatus/queries/service/customvar @@ -1,4 +1,4 @@ GET services -Columns: custom_variable_names custom_variable_values custom_variables +Columns: host_name service_description custom_variables cv_is_json ResponseHeader: fixed16 diff --git a/test/livestatus/run_queries b/test/livestatus/run_queries index d137c3c52..63448c8ce 100755 --- a/test/livestatus/run_queries +++ b/test/livestatus/run_queries @@ -1,5 +1,7 @@ #!/bin/bash +NC=`which nc` +LIVESTATUSSOCKET="/var/run/icinga2/cmd/livestatus" LIVESTATUSHOST="127.0.0.1" LIVESTATUSPORT="6558" LIVESTATUSQUERIES="./queries" @@ -8,14 +10,14 @@ LIVESTATUSTABLE=$1 if [ -n "$LIVESTATUSTABLE" ]; then cat "$LIVESTATUSTABLE" - (cat "$LIVESTATUSTABLE"; sleep 1) | netcat $LIVESTATUSHOST $LIVESTATUSPORT + (cat "$LIVESTATUSTABLE"; sleep 1) | $NC -U $LIVESTATUSSOCKET else echo -e "Looking into $LIVESTATUSQUERIES\n" for q in $(find $LIVESTATUSQUERIES -type f) do cat $q - (cat $q; sleep 1) | netcat $LIVESTATUSHOST $LIVESTATUSPORT + (cat $q; sleep 1) | $NC -U $LIVESTATUSSOCKET echo -e "================================\n\n" done fi