static inline Value ConstructorCall(const Type::Ptr& type, const DebugInfo& debugInfo = DebugInfo()) { if (type->GetName() == "String") return ""; else if (type->GetName() == "Number") return 0; else if (type->GetName() == "Boolean") return false; else { Object::Ptr object = type->Instantiate(); if (!object) BOOST_THROW_EXCEPTION(ScriptError("Failed to instantiate object of type '" + type->GetName() + "'", debugInfo)); return object; } }
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"; }
static inline Value NewObject(ScriptFrame& frame, bool abstract, const String& type, const String& name, const boost::shared_ptr<Expression>& filter, const String& zone, std::map<String, Expression *> *closedVars, const boost::shared_ptr<Expression>& expression, const DebugInfo& debugInfo = DebugInfo()) { ConfigItemBuilder::Ptr item = new ConfigItemBuilder(debugInfo); String checkName = name; if (!abstract) { Type::Ptr ptype = Type::GetByName(type); NameComposer *nc = dynamic_cast<NameComposer *>(ptype.get()); if (nc) checkName = nc->MakeName(name, Dictionary::Ptr()); } if (!checkName.IsEmpty()) { ConfigItem::Ptr oldItem = ConfigItem::GetObject(type, checkName); if (oldItem) { std::ostringstream msgbuf; msgbuf << "Object '" << name << "' of type '" << type << "' re-defined: " << debugInfo << "; previous definition: " << oldItem->GetDebugInfo(); BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debugInfo)); } } item->SetType(type); if (name.FindFirstOf("!") != String::NPos) { std::ostringstream msgbuf; msgbuf << "Name for object '" << name << "' of type '" << type << "' is invalid: Object names may not contain '!'"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debugInfo)); } item->SetName(name); item->AddExpression(new OwnedExpression(expression)); item->SetAbstract(abstract); item->SetScope(EvaluateClosedVars(frame, closedVars)); item->SetZone(zone); item->SetFilter(filter); item->Compile()->Register(); return Empty; }
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)); }
Value icinga::GetPrototypeField(const Value& context, const String& field, bool not_found_error, const DebugInfo& debugInfo) { Type::Ptr ctype = context.GetReflectionType(); Type::Ptr type = ctype; do { Object::Ptr object = type->GetPrototype(); if (object && object->HasOwnField(field)) return object->GetFieldByName(field, false, debugInfo); type = type->GetBaseType(); } while (type); if (not_found_error) BOOST_THROW_EXCEPTION(ScriptError("Invalid field access (for value of type '" + ctype->GetName() + "'): '" + field + "'", debugInfo)); else return Empty; }
bool StatusQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { if (request.RequestMethod != "GET") return false; if (request.RequestUrl->GetPath().size() < 2) return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]); if (!type) return false; QueryDescription qd; qd.Types.insert(type); std::vector<String> joinTypes; joinTypes.push_back(type->GetName()); Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 3) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[2]); } std::vector<ConfigObject::Ptr> objs = FilterUtility::GetFilterTargets(qd, params); 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); } }
ValidationError::ValidationError(const ConfigObject::Ptr& object, const std::vector<String>& attributePath, const String& message) : m_Object(object), m_AttributePath(attributePath), m_Message(message) { String path; BOOST_FOREACH(const String& attribute, attributePath) { if (!path.IsEmpty()) path += " -> "; path += "'" + attribute + "'"; } Type::Ptr type = object->GetReflectionType(); m_What = "Validation failed for object '" + object->GetName() + "' of type '" + type->GetName() + "'"; if (!path.IsEmpty()) m_What += "; Attribute " + path; m_What += ": " + message; }
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); }
void CCodeGenerator::operator()(Assignment* expr) { // Handle all types of assignment, including member assignment Expression::Ptr init = expr->initializer(); if (dynamic_cast<Empty*>(init.pointer())) { return_ = Operand(env_->integer("0")); } else { return_ = emit(init); } String::Ptr id = expr->identifier(); Variable::Ptr var = variable(id); Attribute::Ptr attr = class_ ? class_->attribute(id) : 0; if (var) { // Assignment to a local var that has already been initialized once in // the current scope. Type::Ptr type = var->type(); if (!type->is_value()) { refcount_dec(Operand(var->name())); } line(); out_ << id->string() << " = " << return_ << ";\n"; if (!type->is_value()) { refcount_inc(Operand(var->name())); } } else if (attr) { // Assignment to an attribute within a class /* Type::Ptr type = expr->type(); Variable::Ptr self = variable(env_->name("__self")); Operand addr = Operand::addr(, attr->slot()); Operand old = load(addr); if (!type->is_value() && !attr->is_weak()) { refcount_dec(old); } store(addr, return_); if (!type->is_value() && !attr->is_weak()) { refcount_inc(return_); } */ assert(!"not impl"); } else { // Assignment to a local var that has not yet been initialized in the // current scope. Type::Ptr declared = expr->declared_type(); if (declared->is_top()) { declared = expr->type(); } line(); brace(); operator()(declared); out_ << " " << id->string() << " = " << return_ << "; "; out_ << "(void)" << id->string() << ";\n"; variable(new Variable(id, declared)); if (!declared->is_value()) { refcount_inc(return_); } } }
ConfigType::Ptr ConfigType::GetByName(const String& name) { boost::mutex::scoped_lock lock(GetStaticMutex()); ConfigType::TypeMap::const_iterator tt = InternalGetTypeMap().find(name); if (tt == InternalGetTypeMap().end()) { Type::Ptr type = Type::GetByName(name); if (!type || !ConfigObject::TypeInstance->IsAssignableFrom(type) || type->IsAbstract()) return ConfigType::Ptr(); ConfigType::Ptr dtype = new ConfigType(name); InternalGetTypeMap()[type->GetName()] = dtype; InternalGetTypeVector().push_back(dtype); return dtype; } return tt->second; }
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); } }
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; }
Type::Ptr FilterUtility::TypeFromPluralName(const String& pluralName) { String uname = pluralName; boost::algorithm::to_lower(uname); { Dictionary::Ptr globals = ScriptGlobal::GetGlobals(); ObjectLock olock(globals); BOOST_FOREACH(const Dictionary::Pair& kv, globals) { if (!kv.second.IsObjectType<Type>()) continue; Type::Ptr type = kv.second; String pname = type->GetPluralName(); boost::algorithm::to_lower(pname); if (uname == pname) return type; } } return Type::Ptr(); }
Array::Ptr ScriptUtils::GetObjects(const Type::Ptr& type) { if (!type) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type: Must not be null")); ConfigType *ctype = dynamic_cast<ConfigType *>(type.get()); if (!ctype) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type: Type must inherit from 'ConfigObject'")); Array::Ptr result = new Array(); for (const ConfigObject::Ptr& object : ctype->GetObjects()) result->Add(object); return result; }
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)); } }
bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName, const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation) { { boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex()); if (!ConfigPackageUtility::PackageExists("_api")) { ConfigPackageUtility::CreatePackage("_api"); String stage = ConfigPackageUtility::CreateStage("_api"); ConfigPackageUtility::ActivateStage("_api", stage); } } ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, fullName); if (item) { errors->Add("Object '" + fullName + "' already exists."); return false; } String path = GetObjectConfigPath(type, fullName); Utility::MkDirP(Utility::DirName(path), 0700); if (Utility::PathExists(path)) { errors->Add("Cannot create object '" + fullName + "'. Configuration file '" + path + "' already exists."); return false; } std::ofstream fp(path.CStr(), std::ofstream::out | std::ostream::trunc); fp << config; fp.close(); std::unique_ptr<Expression> expr = ConfigCompiler::CompileFile(path, String(), "_api"); try { ActivationScope ascope; ScriptFrame frame(true); expr->Evaluate(frame); expr.reset(); WorkQueue upq; upq.SetName("ConfigObjectUtility::CreateObject"); std::vector<ConfigItem::Ptr> newItems; /* Disable logging for object creation, but do so ourselves later on. */ if (!ConfigItem::CommitItems(ascope.GetContext(), upq, newItems, true) || !ConfigItem::ActivateItems(upq, newItems, true, true)) { if (errors) { if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } for (const boost::exception_ptr& ex : upq.GetExceptions()) { errors->Add(DiagnosticInformation(ex, false)); if (diagnosticInformation) diagnosticInformation->Add(DiagnosticInformation(ex)); } } return false; } ApiListener::UpdateObjectAuthority(); Log(LogInformation, "ConfigObjectUtility") << "Created and activated object '" << fullName << "' of type '" << type->GetName() << "'."; } catch (const std::exception& ex) { if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } if (errors) errors->Add(DiagnosticInformation(ex, false)); if (diagnosticInformation) diagnosticInformation->Add(DiagnosticInformation(ex)); return false; } return true; }
/** * Commits the configuration item by creating a DynamicObject * object. * * @returns The DynamicObject that was created/updated. */ DynamicObject::Ptr ConfigItem::Commit(bool discard) { ASSERT(!OwnsLock()); #ifdef _DEBUG Log(LogDebug, "ConfigItem") << "Commit called for ConfigItem Type=" << GetType() << ", Name=" << GetName(); #endif /* _DEBUG */ /* Make sure the type is valid. */ Type::Ptr type = Type::GetByName(GetType()); ASSERT(type && Type::GetByName("DynamicObject")->IsAssignableFrom(type)); if (IsAbstract()) return DynamicObject::Ptr(); DynamicObject::Ptr dobj = static_pointer_cast<DynamicObject>(type->Instantiate()); dobj->SetDebugInfo(m_DebugInfo); dobj->SetTypeName(m_Type); dobj->SetZone(m_Zone); Dictionary::Ptr locals = new Dictionary(); locals->Set("__parent", m_Scope); m_Scope.reset(); dobj->SetParentScope(locals); locals.reset(); dobj->SetName(m_Name); DebugHint debugHints; try { m_Expression->Evaluate(dobj, &debugHints); } catch (const ConfigError& ex) { const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex); ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); } catch (const std::exception& ex) { ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); } if (discard) m_Expression.reset(); dobj->SetParentScope(Object::Ptr()); String name = m_Name; NameComposer *nc = dynamic_cast<NameComposer *>(type.get()); if (nc) { name = nc->MakeName(m_Name, dobj); if (name.IsEmpty()) BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object")); } if (name != m_Name) dobj->SetShortName(m_Name); dobj->SetName(name); Dictionary::Ptr attrs = Serialize(dobj, FAConfig); Dictionary::Ptr persistentItem = new Dictionary(); persistentItem->Set("type", GetType()); persistentItem->Set("name", GetName()); persistentItem->Set("properties", attrs); persistentItem->Set("debug_hints", debugHints.ToDictionary()); ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); persistentItem.reset(); ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); if (!ctype) ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'"); else { TypeRuleUtilities utils; try { attrs->Remove("name"); ctype->ValidateItem(GetName(), attrs, GetDebugInfo(), &utils); } catch (const ConfigError& ex) { const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex); ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); } catch (const std::exception& ex) { ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); } } dobj->Register(); m_Object = dobj; return dobj; }
void Type::Register(const Type::Ptr& type) { VERIFY(GetByName(type->GetName()) == NULL); GetTypes()[type->GetName()] = type; }
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; }
void ConfigObject::DumpModifiedAttributes(const boost::function<void(const ConfigObject::Ptr&, const String&, const Value&)>& callback) { for (const Type::Ptr& type : Type::GetAllTypes()) { ConfigType *dtype = dynamic_cast<ConfigType *>(type.get()); if (!dtype) continue; for (const ConfigObject::Ptr& object : dtype->GetObjects()) { Dictionary::Ptr originalAttributes = object->GetOriginalAttributes(); if (!originalAttributes) continue; ObjectLock olock(originalAttributes); for (const Dictionary::Pair& kv : originalAttributes) { String key = kv.first; Type::Ptr type = object->GetReflectionType(); std::vector<String> tokens; boost::algorithm::split(tokens, key, boost::is_any_of(".")); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Value currentValue = object->GetField(fid); Value modifiedValue; if (tokens.size() > 1) { Value current = currentValue; 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]; if (!dict->Contains(key)) break; current = dict->Get(key); } 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]; modifiedValue = dict->Get(key); } else modifiedValue = currentValue; callback(object, key, modifiedValue); } } } }
void ConfigObject::RestoreAttribute(const String& attr, bool updateVersion) { Type::Ptr type = GetReflectionType(); std::vector<String> tokens = attr.Split("."); String fieldName = tokens[0]; int fid = type->GetFieldId(fieldName); Value currentValue = GetField(fid); Dictionary::Ptr original_attributes = GetOriginalAttributes(); if (!original_attributes) return; Value oldValue = original_attributes->Get(attr); Value newValue; if (tokens.size() > 1) { newValue = currentValue.Clone(); Value current = newValue; if (current.IsEmpty()) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existent object attribute")); 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->Contains(key)) BOOST_THROW_EXCEPTION(std::invalid_argument("Cannot restore non-existent object attribute")); current = dict->Get(key); } 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; std::vector<String> restoredAttrs; { ObjectLock olock(original_attributes); for (const auto& kv : original_attributes) { std::vector<String> originalTokens = String(kv.first).Split("."); if (tokens.size() > originalTokens.size()) continue; bool match = true; for (std::vector<String>::size_type i = 0; i < tokens.size(); i++) { if (tokens[i] != originalTokens[i]) { match = false; break; } } if (!match) continue; Dictionary::Ptr dict; if (tokens.size() == originalTokens.size()) dict = current; else { Value currentSub = current; for (std::vector<String>::size_type i = tokens.size() - 1; i < originalTokens.size() - 1; i++) { dict = currentSub; currentSub = dict->Get(originalTokens[i]); if (!currentSub.IsObjectType<Dictionary>()) { currentSub = new Dictionary(); dict->Set(originalTokens[i], currentSub); } } dict = currentSub; } dict->Set(originalTokens[originalTokens.size() - 1], kv.second); restoredAttrs.push_back(kv.first); } } for (const String& attr : restoredAttrs) original_attributes->Remove(attr); } else { newValue = oldValue; } original_attributes->Remove(attr); SetField(fid, newValue); if (updateVersion) SetVersion(Utility::GetTime()); }
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)); }
void Type::Register(const Type::Ptr& type) { VERIFY(GetByName(type->GetName()) == NULL); ScriptGlobal::Set(type->GetName(), type); }
* 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 "base/objecttype.hpp" #include "base/initialize.hpp" using namespace icinga; INITIALIZE_ONCE_WITH_PRIORITY([]() { Type::Ptr type = new ObjectType(); type->SetPrototype(Object::GetPrototype()); Type::Register(type); Object::TypeInstance = type; }, 20); ObjectType::ObjectType(void) { } String ObjectType::GetName(void) const { return "Object"; } Type::Ptr ObjectType::GetBaseType(void) const {
bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation) { std::vector<Object::Ptr> parents = DependencyGraph::GetParents(object); Type::Ptr type = object->GetReflectionType(); String name = object->GetName(); if (!parents.empty() && !cascade) { if (errors) { errors->Add("Object '" + name + "' of type '" + type->GetName() + "' cannot be deleted because other objects depend on it. " "Use cascading delete to delete it anyway."); } return false; } for (const Object::Ptr& pobj : parents) { ConfigObject::Ptr parentObj = dynamic_pointer_cast<ConfigObject>(pobj); if (!parentObj) continue; DeleteObjectHelper(parentObj, cascade, errors, diagnosticInformation); } ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name); try { /* mark this object for cluster delete event */ object->SetExtension("ConfigObjectDeleted", true); /* triggers signal for DB IDO and other interfaces */ object->Deactivate(true); if (item) item->Unregister(); else object->Unregister(); } catch (const std::exception& ex) { if (errors) errors->Add(DiagnosticInformation(ex, false)); if (diagnosticInformation) diagnosticInformation->Add(DiagnosticInformation(ex)); return false; } String path = GetObjectConfigPath(object->GetReflectionType(), name); if (Utility::PathExists(path)) { if (unlink(path.CStr()) < 0 && errno != ENOENT) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("unlink") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path)); } } return true; }
/** * Commits the configuration item by creating a ConfigObject * object. * * @returns The ConfigObject that was created/updated. */ ConfigObject::Ptr ConfigItem::Commit(bool discard) { #ifdef I2_DEBUG Log(LogDebug, "ConfigItem") << "Commit called for ConfigItem Type=" << GetType() << ", Name=" << GetName(); #endif /* I2_DEBUG */ /* Make sure the type is valid. */ Type::Ptr type = Type::GetByName(GetType()); ASSERT(type && ConfigObject::TypeInstance->IsAssignableFrom(type)); if (IsAbstract()) return ConfigObject::Ptr(); ConfigObject::Ptr dobj = static_pointer_cast<ConfigObject>(type->Instantiate()); dobj->SetDebugInfo(m_DebugInfo); dobj->SetZoneName(m_Zone); dobj->SetPackage(m_Package); dobj->SetName(m_Name); DebugHint debugHints; ScriptFrame frame(dobj); if (m_Scope) m_Scope->CopyTo(frame.Locals); try { m_Expression->Evaluate(frame, &debugHints); } catch (const std::exception& ex) { if (m_IgnoreOnError) { Log(LogWarning, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex); return ConfigObject::Ptr(); } throw; } if (discard) m_Expression.reset(); String item_name; String short_name = dobj->GetShortName(); if (!short_name.IsEmpty()) { item_name = short_name; dobj->SetName(short_name); } else item_name = m_Name; String name = item_name; NameComposer *nc = dynamic_cast<NameComposer *>(type.get()); if (nc) { name = nc->MakeName(name, dobj); if (name.IsEmpty()) BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object")); } if (name != item_name) dobj->SetShortName(item_name); dobj->SetName(name); try { dobj->OnConfigLoaded(); } catch (const std::exception& ex) { if (m_IgnoreOnError) { Log(LogWarning, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex); return ConfigObject::Ptr(); } throw; } Dictionary::Ptr persistentItem = new Dictionary(); persistentItem->Set("type", GetType()); persistentItem->Set("name", GetName()); persistentItem->Set("properties", Serialize(dobj, FAConfig)); Dictionary::Ptr dhint = debugHints.ToDictionary(); persistentItem->Set("debug_hints", dhint); Array::Ptr di = new Array(); di->Add(m_DebugInfo.Path); di->Add(m_DebugInfo.FirstLine); di->Add(m_DebugInfo.FirstColumn); di->Add(m_DebugInfo.LastLine); di->Add(m_DebugInfo.LastColumn); persistentItem->Set("debug_info", di); try { DefaultValidationUtils utils; dobj->Validate(FAConfig, utils); } catch (ValidationError& ex) { if (m_IgnoreOnError) { Log(LogWarning, "ConfigObject") << "Ignoring config object '" << m_Name << "' of type '" << m_Type << "' due to errors: " << DiagnosticInformation(ex); return ConfigObject::Ptr(); } ex.SetDebugHint(dhint); throw; } ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); persistentItem.reset(); dhint.reset(); dobj->Register(); m_Object = dobj; return dobj; }
bool ModifyObjectHandler::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 != "POST") 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/modify/" + type->GetName(); 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, 404, "No objects found.", HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : ""); return true; } Dictionary::Ptr attrs = params->Get("attrs"); Array::Ptr results = new Array(); for (const ConfigObject::Ptr& obj : objs) { Dictionary::Ptr result1 = new Dictionary(); result1->Set("type", type->GetName()); result1->Set("name", obj->GetName()); String key; try { if (attrs) { ObjectLock olock(attrs); for (const Dictionary::Pair& kv : attrs) { key = kv.first; obj->ModifyAttribute(kv.first, kv.second); } } result1->Set("code", 200); result1->Set("status", "Attributes updated."); } catch (const std::exception& ex) { result1->Set("code", 500); result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex)); } results->Add(result1); } Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; }
bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { if (request.RequestUrl->GetPath().size() != 4) return false; if (request.RequestMethod != "PUT") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } FilterUtility::CheckPermission(user, "objects/create/" + type->GetName()); String name = request.RequestUrl->GetPath()[3]; Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request); Array::Ptr templates = params->Get("templates"); Dictionary::Ptr attrs = params->Get("attrs"); Dictionary::Ptr result1 = new Dictionary(); int code; String status; Array::Ptr errors = new Array(); bool ignoreOnError = false; if (params->Contains("ignore_on_error")) ignoreOnError = HttpUtility::GetLastParameter(params, "ignore_on_error"); String config = ConfigObjectUtility::CreateObjectConfig(type, name, ignoreOnError, templates, attrs); if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) { result1->Set("errors", errors); HttpUtility::SendJsonError(response, 500, "Object could not be created."); return true; } ConfigType::Ptr dtype = ConfigType::GetByName(type->GetName()); ConfigObject::Ptr obj = dtype->GetObject(name); result1->Set("code", 200); if (obj) result1->Set("status", "Object was created"); else if (!obj && ignoreOnError) result1->Set("status", "Object was not created but 'ignore_on_error' was set to true"); Array::Ptr results = new Array(); results->Add(result1); Dictionary::Ptr result = new Dictionary(); result->Set("results", results); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, result); return true; }