Improve filter support for /v1/templates

refs #11941
This commit is contained in:
Gunnar Beutner 2016-06-16 08:28:57 +02:00
parent 5e3ea4720f
commit 28dee2b79b
4 changed files with 28 additions and 21 deletions

View File

@ -644,7 +644,11 @@ in:
A list of all available configuration types is available in the
[object types](6-object-types.md#object-types) chapter.
A [filter](9-icinga2-api.md#icinga2-api-filters) may be provided for this query type.
A [filter](9-icinga2-api.md#icinga2-api-filters) may be provided for this query type. The
template object can be accessed in the filter using the `tmpl` variable:
$ curl -u root:root -k 'https://localhost:5661/v1/templates/hosts' -H "Accept: application/json" -X PUT -H "X-HTTP-Method-Override: GET" \
-d '{ "filter": "match(\"g*\", tmpl.name)" }'
Instead of using a filter you can optionally specify the template name in the
URL path when querying a single object:

View File

@ -133,9 +133,9 @@ bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter,
}
static void FilteredAddTarget(ScriptFrame& permissionFrame, Expression *permissionFilter,
ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const Object::Ptr& target)
ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const String& variableName, const Object::Ptr& target)
{
if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target) && FilterUtility::EvaluateFilter(frame, ufilter, target))
if (FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName) && FilterUtility::EvaluateFilter(frame, ufilter, target, variableName))
result.push_back(target);
}
@ -187,7 +187,7 @@ void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& perm
BOOST_THROW_EXCEPTION(ScriptError("Missing permission: " + requiredPermission));
}
std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user)
std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user, const String& variableName)
{
std::vector<Value> result;
@ -214,7 +214,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
String name = HttpUtility::GetLastParameter(query, attr);
Object::Ptr target = provider->GetTargetByName(type, name);
if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target))
if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName))
BOOST_THROW_EXCEPTION(ScriptError("Access denied to object '" + name + "' of type '" + type + "'"));
result.push_back(target);
@ -230,7 +230,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
BOOST_FOREACH(const String& name, names) {
Object::Ptr target = provider->GetTargetByName(type, name);
if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target))
if (!FilterUtility::EvaluateFilter(permissionFrame, permissionFilter, target, variableName))
BOOST_THROW_EXCEPTION(ScriptError("Access denied to object '" + name + "' of type '" + type + "'"));
result.push_back(target);
@ -275,7 +275,7 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
try {
provider->FindTargets(type, boost::bind(&FilteredAddTarget,
boost::ref(permissionFrame), permissionFilter,
boost::ref(frame), ufilter, boost::ref(result), _1));
boost::ref(frame), ufilter, boost::ref(result), variableName, _1));
} catch (const std::exception& ex) {
delete ufilter;
throw;

View File

@ -69,7 +69,8 @@ class I2_REMOTE_API FilterUtility
public:
static Type::Ptr TypeFromPluralName(const String& pluralName);
static void CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **filter = NULL);
static std::vector<Value> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user);
static std::vector<Value> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query,
const ApiUser::Ptr& user, const String& variableName = String());
static bool EvaluateFilter(ScriptFrame& frame, Expression *filter,
const Object::Ptr& target, const String& variableName = String());
};

View File

@ -36,14 +36,20 @@ class TemplateTargetProvider : public TargetProvider
public:
DECLARE_PTR_TYPEDEFS(TemplateTargetProvider);
static Dictionary::Ptr GetTargetForTemplate(const ConfigItem::Ptr& item)
{
Dictionary::Ptr target = new Dictionary();
target->Set("name", item->GetName());
target->Set("type", item->GetType());
return target;
}
virtual void FindTargets(const String& type,
const boost::function<void (const Value&)>& addTarget) const override
{
std::vector<ConfigItem::Ptr> targets = ConfigItem::GetItems(type);
BOOST_FOREACH(const ConfigItem::Ptr& target, targets) {
if (target->IsAbstract())
addTarget(target);
BOOST_FOREACH(const ConfigItem::Ptr& item, ConfigItem::GetItems(type)) {
if (item->IsAbstract())
addTarget(GetTargetForTemplate(item));
}
}
@ -54,7 +60,7 @@ public:
if (!item || !item->IsAbstract())
BOOST_THROW_EXCEPTION(std::invalid_argument("Template does not exist."));
return item;
return GetTargetForTemplate(item);
}
virtual bool IsValidType(const String& type) const override
@ -104,7 +110,7 @@ bool TemplateQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
std::vector<Value> objs;
try {
objs = FilterUtility::GetFilterTargets(qd, params, user);
objs = FilterUtility::GetFilterTargets(qd, params, user, "tmpl");
} catch (const std::exception& ex) {
HttpUtility::SendJsonError(response, 404,
"No templates found.",
@ -114,12 +120,8 @@ bool TemplateQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
Array::Ptr results = new Array();
BOOST_FOREACH(const ConfigItem::Ptr& obj, objs) {
Dictionary::Ptr result1 = new Dictionary();
results->Add(result1);
result1->Set("type", obj->GetType());
result1->Set("name", obj->GetName());
BOOST_FOREACH(const Dictionary::Ptr& obj, objs) {
results->Add(obj);
}
Dictionary::Ptr result = new Dictionary();