bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors)
{
	std::vector<Object::Ptr> parents = DependencyGraph::GetParents(object);

	Type::Ptr type = object->GetReflectionType();

	if (!parents.empty() && !cascade) {
		if (errors)
			errors->Add("Object '" + object->GetName() + "' 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);
	}

	ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, object->GetName());

	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));

		return false;
	}

	String path = GetObjectConfigPath(object->GetReflectionType(), object->GetName());

	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;
}
Example #2
0
static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
{
	if (object != previousObject) {
		if (previousObject) {
			ConfigWriter::EmitRaw(fp, "\tobj.version = ");
			ConfigWriter::EmitValue(fp, 0, previousObject->GetVersion());
			ConfigWriter::EmitRaw(fp, "\n}\n\n");
		}

		ConfigWriter::EmitRaw(fp, "var obj = ");

		Array::Ptr args1 = new Array();
		args1->Add(object->GetReflectionType()->GetName());
		args1->Add(object->GetName());
		ConfigWriter::EmitFunctionCall(fp, "get_object", args1);

		ConfigWriter::EmitRaw(fp, "\nif (obj) {\n");
	}

	ConfigWriter::EmitRaw(fp, "\tobj.");

	Array::Ptr args2 = new Array();
	args2->Add(attr);
	args2->Add(value);
	ConfigWriter::EmitFunctionCall(fp, "modify_attribute", args2);

	ConfigWriter::EmitRaw(fp, "\n");

	previousObject = object;
}
Example #3
0
void ApiListener::PersistMessage(const Dictionary::Ptr& message, const ConfigObject::Ptr& secobj)
{
	double ts = message->Get("ts");

	ASSERT(ts != 0);

	Dictionary::Ptr pmessage = new Dictionary();
	pmessage->Set("timestamp", ts);

	pmessage->Set("message", JsonEncode(message));

	if (secobj) {
		Dictionary::Ptr secname = new Dictionary();
		secname->Set("type", secobj->GetReflectionType()->GetName());
		secname->Set("name", secobj->GetName());
		pmessage->Set("secobj", secname);
	}

	boost::mutex::scoped_lock lock(m_LogLock);
	if (m_LogFile) {
		NetString::WriteStringToStream(m_LogFile, JsonEncode(pmessage));
		m_LogMessageCount++;
		SetLogMessageTimestamp(ts);

		if (m_LogMessageCount > 50000) {
			CloseLogFile();
			RotateLogFile();
			OpenLogFile();
		}
	}
}
Example #4
0
bool Zone::CanAccessObject(const ConfigObject::Ptr& object)
{
	Zone::Ptr object_zone;

	if (object->GetReflectionType() == Zone::TypeInstance)
		object_zone = static_pointer_cast<Zone>(object);
	else
		object_zone = static_pointer_cast<Zone>(object->GetZone());

	if (!object_zone)
		object_zone = Zone::GetLocalZone();

	return object_zone->IsChildOf(this);
}
Example #5
0
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;
}
Example #6
0
void ApiListener::SyncRelayMessage(const MessageOrigin::Ptr& origin,
    const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
{
	double ts = Utility::GetTime();
	message->Set("ts", ts);

	Log(LogNotice, "ApiListener")
	    << "Relaying '" << message->Get("method") << "' message";

	if (origin && origin->FromZone)
		message->Set("originZone", origin->FromZone->GetName());

	Zone::Ptr target_zone;

	if (secobj) {
		if (secobj->GetReflectionType() == Zone::TypeInstance)
			target_zone = static_pointer_cast<Zone>(secobj);
		else
			target_zone = static_pointer_cast<Zone>(secobj->GetZone());
	}

	if (!target_zone)
		target_zone = Zone::GetLocalZone();

	Endpoint::Ptr master = GetMaster();

	bool need_log = !RelayMessageOne(target_zone, origin, message, master);

	for (const Zone::Ptr& zone : target_zone->GetAllParents()) {
		if (!RelayMessageOne(zone, origin, message, master))
			need_log = true;
	}

	if (log && need_log)
		PersistMessage(message, secobj);
}
Example #7
0
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;
}