String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName, bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs) { NameComposer *nc = dynamic_cast<NameComposer *>(type.get()); Dictionary::Ptr nameParts; String name; if (nc) { nameParts = nc->ParseName(fullName); name = nameParts->Get("name"); } else name = fullName; Dictionary::Ptr allAttrs = new Dictionary(); if (attrs) { attrs->CopyTo(allAttrs); ObjectLock olock(attrs); BOOST_FOREACH(const Dictionary::Pair& kv, attrs) { int fid = type->GetFieldId(kv.first.SubStr(0, kv.first.FindFirstOf("."))); if (fid < 0) BOOST_THROW_EXCEPTION(ScriptError("Invalid attribute specified: " + kv.first)); Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FAConfig) || kv.first == "name") BOOST_THROW_EXCEPTION(ScriptError("Attribute is marked for internal use only and may not be set: " + kv.first)); } }
Field PrimitiveType::GetFieldInfo(int id) const { Type::Ptr base = GetBaseType(); if (base) return base->GetFieldInfo(id); else throw std::runtime_error("Invalid field ID."); }
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/query/" + type->GetName(); std::vector<String> joinAttrs; joinAttrs.push_back(""); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if (field.Attributes & FANavigation) joinAttrs.push_back(field.Name); } Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user); Array::Ptr results = new Array(); std::set<String> attrs; Array::Ptr uattrs = params->Get("attrs"); if (uattrs) { ObjectLock olock(uattrs); BOOST_FOREACH(const String& uattr, uattrs) { attrs.insert(uattr); } }
static void AddSuggestions(std::vector<String>& matches, const String& word, const String& pword, bool withFields, const Value& value) { String prefix; if (!pword.IsEmpty()) prefix = pword + "."; if (value.IsObjectType<Dictionary>()) { Dictionary::Ptr dict = value; ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } if (value.IsObjectType<Namespace>()) { Namespace::Ptr ns = value; ObjectLock olock(ns); for (const Namespace::Pair& kv : ns) { AddSuggestion(matches, word, prefix + kv.first); } } if (withFields) { Type::Ptr type = value.GetReflectionType(); for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); AddSuggestion(matches, word, prefix + field.Name); } while (type) { Object::Ptr prototype = type->GetPrototype(); Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(prototype); if (dict) { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } type = type->GetBaseType(); } } }
BOOST_FOREACH(const ConfigObject::Ptr& obj, objs) { Dictionary::Ptr result1 = new Dictionary(); results->Add(result1); Dictionary::Ptr resultAttrs = new Dictionary(); result1->Set("attrs", resultAttrs); BOOST_FOREACH(const String& joinAttr, joinAttrs) { Object::Ptr joinedObj; String prefix; if (joinAttr.IsEmpty()) { joinedObj = obj; prefix = type->GetName(); } else { int fid = type->GetFieldId(joinAttr); joinedObj = obj->NavigateField(fid); if (!joinedObj) continue; Field field = type->GetFieldInfo(fid); prefix = field.NavigationName; } boost::algorithm::to_lower(prefix); Type::Ptr joinedType = joinedObj->GetReflectionType(); for (int fid = 0; fid < joinedType->GetFieldCount(); fid++) { Field field = joinedType->GetFieldInfo(fid); String aname = prefix + "." + field.Name; if (!attrs.empty() && attrs.find(aname) == attrs.end()) continue; Value val = joinedObj->GetField(fid); /* hide internal navigation fields */ if (field.Attributes & FANavigation) { Value nval = joinedObj->NavigateField(fid); if (val == nval) continue; } Value sval = Serialize(val, FAConfig | FAState); resultAttrs->Set(aname, sval); } }
void Object::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) { Type::Ptr type = GetReflectionType(); if (!type) BOOST_THROW_EXCEPTION(ScriptError("Cannot set field on object.", debugInfo)); int fid = type->GetFieldId(field); if (fid == -1) BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' does not exist.", debugInfo)); try { SetField(fid, value); } catch (const boost::bad_lexical_cast&) { Field fieldInfo = type->GetFieldInfo(fid); Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName); BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo)); } catch (const std::bad_cast&) { Field fieldInfo = type->GetFieldInfo(fid); Type::Ptr ftype = Type::GetByName(fieldInfo.TypeName); BOOST_THROW_EXCEPTION(ScriptError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "', expected '" + ftype->GetName() + "'", debugInfo)); } }
String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName, bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs) { NameComposer *nc = dynamic_cast<NameComposer *>(type.get()); Dictionary::Ptr nameParts; String name; if (nc) { nameParts = nc->ParseName(fullName); name = nameParts->Get("name"); } else name = fullName; Dictionary::Ptr allAttrs = new Dictionary(); if (attrs) { attrs->CopyTo(allAttrs); ObjectLock olock(attrs); for (const Dictionary::Pair& kv : attrs) { int fid = type->GetFieldId(kv.first.SubStr(0, kv.first.FindFirstOf("."))); if (fid < 0) BOOST_THROW_EXCEPTION(ScriptError("Invalid attribute specified: " + kv.first)); Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FAConfig) || kv.first == "name") BOOST_THROW_EXCEPTION(ScriptError("Attribute is marked for internal use only and may not be set: " + kv.first)); } } if (nameParts) nameParts->CopyTo(allAttrs); allAttrs->Remove("name"); /* update the version for config sync */ allAttrs->Set("version", Utility::GetTime()); std::ostringstream config; ConfigWriter::EmitConfigItem(config, type->GetName(), name, false, ignoreOnError, templates, allAttrs); ConfigWriter::EmitRaw(config, "\n"); return config.str(); }
bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName) { if (!filter) return true; Type::Ptr type = target->GetReflectionType(); String varName; if (variableName.IsEmpty()) varName = type->GetName().ToLower(); else varName = variableName; Namespace::Ptr frameNS; if (frame.Self.IsEmpty()) { frameNS = new Namespace(); frame.Self = frameNS; } else { /* Enforce a namespace object for 'frame.self'. */ ASSERT(frame.Self.IsObjectType<Namespace>()); frameNS = frame.Self; } frameNS->Set("obj", target); frameNS->Set(varName, target); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if ((field.Attributes & FANavigation) == 0) continue; Object::Ptr joinedObj = target->NavigateField(fid); if (field.NavigationName) frameNS->Set(field.NavigationName, joinedObj); else frameNS->Set(field.Name, joinedObj); } return Convert::ToBool(filter->Evaluate(frame)); }
bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName) { if (!filter) return true; Type::Ptr type = target->GetReflectionType(); String varName; if (variableName.IsEmpty()) varName = type->GetName().ToLower(); else varName = variableName; Dictionary::Ptr vars; if (frame.Self.IsEmpty()) { vars = new Dictionary(); frame.Self = vars; } else vars = frame.Self; vars->Set("obj", target); vars->Set(varName, target); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if ((field.Attributes & FANavigation) == 0) continue; Object::Ptr joinedObj = target->NavigateField(fid); if (field.NavigationName) vars->Set(field.NavigationName, joinedObj); else vars->Set(field.Name, joinedObj); } return Convert::ToBool(filter->Evaluate(frame)); }
Value Object::GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const { Type::Ptr type = GetReflectionType(); if (!type) return Empty; int fid = type->GetFieldId(field); if (fid == -1) return GetPrototypeField(const_cast<Object *>(this), field, true, debugInfo); if (sandboxed) { Field fieldInfo = type->GetFieldInfo(fid); if (fieldInfo.Attributes & FANoUserView) BOOST_THROW_EXCEPTION(ScriptError("Accessing the field '" + field + "' for type '" + type->GetName() + "' is not allowed in sandbox mode.", debugInfo)); } return GetField(fid); }
std::vector<String> icinga::GetFieldCompletionSuggestions(const Type::Ptr& type, const String& word) { std::vector<String> result; for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); if (!(field.Attributes & FAConfig) || field.Attributes & FAInternal) continue; if (strcmp(field.TypeName, "int") != 0 && strcmp(field.TypeName, "double") != 0 && strcmp(field.TypeName, "bool") != 0 && strcmp(field.TypeName, "String") != 0) continue; String fname = field.Name; String suggestion = fname + "="; if (suggestion.Find(word) == 0) result.push_back(suggestion); } return result; }
void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool updateVersion) { Dictionary::Ptr original_attributes = GetOriginalAttributes(); bool updated_original_attributes = false; Type::Ptr type = GetReflectionType(); std::vector<String> tokens = attr.Split("."); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Field field = type->GetFieldInfo(fid); if (field.Attributes & FANoUserModify) BOOST_THROW_EXCEPTION(std::invalid_argument("Attribute cannot be modified.")); if (field.Attributes & FAConfig) { if (!original_attributes) { original_attributes = new Dictionary(); SetOriginalAttributes(original_attributes, true); } } Value oldValue = GetField(fid); Value newValue; if (tokens.size() > 1) { newValue = oldValue.Clone(); Value current = newValue; if (current.IsEmpty()) { current = new Dictionary(); newValue = current; } String prefix = tokens[0]; for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) { if (!current.IsObjectType<Dictionary>()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[i]; prefix += "." + key; if (!dict->Get(key, ¤t)) { current = new Dictionary(); dict->Set(key, current); } } if (!current.IsObjectType<Dictionary>()) BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); Dictionary::Ptr dict = current; const String& key = tokens[tokens.size() - 1]; prefix += "." + key; /* clone it for original attributes */ oldValue = dict->Get(key).Clone(); if (field.Attributes & FAConfig) { updated_original_attributes = true; if (oldValue.IsObjectType<Dictionary>()) { Dictionary::Ptr oldDict = oldValue; ObjectLock olock(oldDict); for (const auto& kv : oldDict) { String key = prefix + "." + kv.first; if (!original_attributes->Contains(key)) original_attributes->Set(key, kv.second); } /* store the new value as null */ if (value.IsObjectType<Dictionary>()) { Dictionary::Ptr valueDict = value; ObjectLock olock(valueDict); for (const auto& kv : valueDict) { String key = attr + "." + kv.first; if (!original_attributes->Contains(key)) original_attributes->Set(key, Empty); } } } else if (!original_attributes->Contains(attr)) original_attributes->Set(attr, oldValue); } dict->Set(key, value); } else { newValue = value; if (field.Attributes & FAConfig) { if (!original_attributes->Contains(attr)) { updated_original_attributes = true; original_attributes->Set(attr, oldValue); } } } ModAttrValidationUtils utils; ValidateField(fid, Lazy<Value>{newValue}, utils); SetField(fid, newValue); if (updateVersion && (field.Attributes & FAConfig)) SetVersion(Utility::GetTime()); if (updated_original_attributes) NotifyOriginalAttributes(); }
Dictionary::Ptr ObjectQueryHandler::SerializeObjectAttrs(const Object::Ptr& object, const String& attrPrefix, const Array::Ptr& attrs, bool isJoin, bool allAttrs) { Type::Ptr type = object->GetReflectionType(); std::vector<int> fids; if (isJoin && attrs) { ObjectLock olock(attrs); for (const String& attr : attrs) { if (attr == attrPrefix) { allAttrs = true; break; } } } if (!isJoin && (!attrs || attrs->GetLength() == 0)) allAttrs = true; if (allAttrs) { for (int fid = 0; fid < type->GetFieldCount(); fid++) { fids.push_back(fid); } } else if (attrs) { ObjectLock olock(attrs); for (const String& attr : attrs) { String userAttr; if (isJoin) { String::SizeType dpos = attr.FindFirstOf("."); if (dpos == String::NPos) continue; String userJoinAttr = attr.SubStr(0, dpos); if (userJoinAttr != attrPrefix) continue; userAttr = attr.SubStr(dpos + 1); } else userAttr = attr; int fid = type->GetFieldId(userAttr); if (fid < 0) BOOST_THROW_EXCEPTION(ScriptError("Invalid field specified: " + userAttr)); fids.push_back(fid); } } DictionaryData resultAttrs; resultAttrs.reserve(fids.size()); for (int fid : fids) { Field field = type->GetFieldInfo(fid); Value val = object->GetField(fid); /* hide attributes which shouldn't be user-visible */ if (field.Attributes & FANoUserView) continue; /* hide internal navigation fields */ if (field.Attributes & FANavigation && !(field.Attributes & (FAConfig | FAState))) continue; Value sval = Serialize(val, FAConfig | FAState); resultAttrs.emplace_back(field.Name, sval); } return new Dictionary(std::move(resultAttrs)); }
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, params, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/query/" + type->GetName(); Array::Ptr uattrs, ujoins, umetas; try { uattrs = params->Get("attrs"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'attrs' attribute specified. Array type is required."); return true; } try { ujoins = params->Get("joins"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'joins' attribute specified. Array type is required."); return true; } try { umetas = params->Get("meta"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'meta' attribute specified. Array type is required."); return true; } bool allJoins = HttpUtility::GetLastParameter(params, "all_joins"); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector<Value> objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, params, 404, "No objects found.", DiagnosticInformation(ex)); return true; } ArrayData results; results.reserve(objs.size()); std::set<String> joinAttrs; std::set<String> userJoinAttrs; if (ujoins) { ObjectLock olock(ujoins); for (const String& ujoin : ujoins) { userJoinAttrs.insert(ujoin.SubStr(0, ujoin.FindFirstOf("."))); } } for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) continue; if (!allJoins && userJoinAttrs.find(field.NavigationName) == userJoinAttrs.end()) continue; joinAttrs.insert(field.Name); } for (const ConfigObject::Ptr& obj : objs) { DictionaryData result1{ { "name", obj->GetName() }, { "type", obj->GetReflectionType()->GetName() } }; DictionaryData metaAttrs; if (umetas) { ObjectLock olock(umetas); for (const String& meta : umetas) { if (meta == "used_by") { Array::Ptr used_by = new Array(); metaAttrs.emplace_back("used_by", used_by); for (const Object::Ptr& pobj : DependencyGraph::GetParents((obj))) { ConfigObject::Ptr configObj = dynamic_pointer_cast<ConfigObject>(pobj); if (!configObj) continue; used_by->Add(new Dictionary({ { "type", configObj->GetReflectionType()->GetName() }, { "name", configObj->GetName() } })); } } else if (meta == "location") { metaAttrs.emplace_back("location", obj->GetSourceLocation()); } else { HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for meta: " + meta); return true; } } } result1.emplace_back("meta", new Dictionary(std::move(metaAttrs))); try { result1.emplace_back("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, params, 400, ex.what()); return true; } DictionaryData joins; for (const String& joinAttr : joinAttrs) { Object::Ptr joinedObj; int fid = type->GetFieldId(joinAttr); if (fid < 0) { HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for join: " + joinAttr); return true; } Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) { HttpUtility::SendJsonError(response, params, 400, "Not a joinable field: " + joinAttr); return true; } joinedObj = obj->NavigateField(fid); if (!joinedObj) continue; String prefix = field.NavigationName; try { joins.emplace_back(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, params, 400, ex.what()); return true; } } result1.emplace_back("joins", new Dictionary(std::move(joins))); results.push_back(new Dictionary(std::move(result1))); } Dictionary::Ptr result = new Dictionary({ { "results", new Array(std::move(results)) } }); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, params, result); return true; }