void IdoPgsqlConnection::FillIDCache(const DbType::Ptr& type)
{
	String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id, config_hash FROM " + GetTablePrefix() + type->GetTable() + "s";
	IdoPgsqlResult result = Query(query);

	Dictionary::Ptr row;

	int index = 0;
	while ((row = FetchRow(result, index))) {
		index++;
		DbReference dbref(row->Get("object_id"));
		SetInsertID(type, dbref, DbReference(row->Get(type->GetTable() + "_id")));
		SetConfigHash(type, dbref, row->Get("config_hash"));
	}
}
Exemple #2
0
DbObject::Ptr DbObject::GetOrCreateByObject(const ConfigObject::Ptr& object)
{
	boost::mutex::scoped_lock lock(GetStaticMutex());

	DbObject::Ptr dbobj = object->GetExtension("DbObject");

	if (dbobj)
		return dbobj;

	DbType::Ptr dbtype = DbType::GetByName(object->GetType()->GetName());

	if (!dbtype)
		return DbObject::Ptr();

	Service::Ptr service;
	String name1, name2;

	service = dynamic_pointer_cast<Service>(object);

	if (service) {
		Host::Ptr host = service->GetHost();

		name1 = service->GetHost()->GetName();
		name2 = service->GetShortName();
	} else {
		if (object->GetType() == ConfigType::GetByName("CheckCommand") ||
		    object->GetType() == ConfigType::GetByName("EventCommand") ||
		    object->GetType() == ConfigType::GetByName("NotificationCommand")) {
			Command::Ptr command = dynamic_pointer_cast<Command>(object);
			name1 = CompatUtility::GetCommandName(command);
		}
		else
			name1 = object->GetName();
	}

	dbobj = dbtype->GetOrCreateObjectByName(name1, name2);

	dbobj->SetObject(object);
	object->SetExtension("DbObject", dbobj);

	return dbobj;
}
Exemple #3
0
DbObject::Ptr DbObject::GetOrCreateByObject(const DynamicObject::Ptr& object)
{
	DbObject::Ptr dbobj = static_pointer_cast<DbObject>(object->GetExtension("DbObject"));

	if (dbobj)
		return dbobj;

	DbType::Ptr dbtype = DbType::GetByName(object->GetType()->GetName());

	if (!dbtype)
		return DbObject::Ptr();

	Service::Ptr service;
	String name1, name2;

	service = dynamic_pointer_cast<Service>(object);

	if (service) {
		Host::Ptr host = service->GetHost();

		if (!host)
			return DbObject::Ptr();

		name1 = service->GetHost()->GetName();
		name2 = service->GetShortName();
	} else {
		name1 = object->GetName();
	}

	dbobj = dbtype->GetOrCreateObjectByName(name1, name2);

	{
		ObjectLock olock(object);
		dbobj->SetObject(object);
		object->SetExtension("DbObject", dbobj);
	}

	return dbobj;
}
void IdoPgsqlConnection::Reconnect(void)
{
	AssertOnWorkQueue();

	CONTEXT("Reconnecting to PostgreSQL IDO database '" + GetName() + "'");

	double startTime = Utility::GetTime();

	SetShouldConnect(true);

	bool reconnect = false;

	if (GetConnected()) {
		/* Check if we're really still connected */
		try {
			Query("SELECT 1");
			return;
		} catch (const std::exception&) {
			PQfinish(m_Connection);
			SetConnected(false);
			reconnect = true;
		}
	}

	ClearIDCache();

	String ihost, iport, iuser, ipasswd, idb;
	const char *host, *port, *user , *passwd, *db;

	ihost = GetHost();
	iport = GetPort();
	iuser = GetUser();
	ipasswd = GetPassword();
	idb = GetDatabase();

	host = (!ihost.IsEmpty()) ? ihost.CStr() : NULL;
	port = (!iport.IsEmpty()) ? iport.CStr() : NULL;
	user = (!iuser.IsEmpty()) ? iuser.CStr() : NULL;
	passwd = (!ipasswd.IsEmpty()) ? ipasswd.CStr() : NULL;
	db = (!idb.IsEmpty()) ? idb.CStr() : NULL;

	m_Connection = PQsetdbLogin(host, port, NULL, NULL, db, user, passwd);

	if (!m_Connection)
		return;

	if (PQstatus(m_Connection) != CONNECTION_OK) {
		String message = PQerrorMessage(m_Connection);
		PQfinish(m_Connection);
		SetConnected(false);

		Log(LogCritical, "IdoPgsqlConnection")
		    << "Connection to database '" << db << "' with user '" << user << "' on '" << host << ":" << port
		    << "' failed: \"" << message << "\"";

		BOOST_THROW_EXCEPTION(std::runtime_error(message));
	}

	SetConnected(true);

	IdoPgsqlResult result;

	/* explicitely require legacy mode for string escaping in PostgreSQL >= 9.1
	 * changing standard_conforming_strings to on by default
	 */
	if (PQserverVersion(m_Connection) >= 90100)
		result = Query("SET standard_conforming_strings TO off");

	String dbVersionName = "idoutils";
	result = Query("SELECT version FROM " + GetTablePrefix() + "dbversion WHERE name=E'" + Escape(dbVersionName) + "'");

	Dictionary::Ptr row = FetchRow(result, 0);

	if (!row) {
		PQfinish(m_Connection);
		SetConnected(false);

		Log(LogCritical, "IdoPgsqlConnection", "Schema does not provide any valid version! Verify your schema installation.");

		Application::Exit(EXIT_FAILURE);
	}

	String version = row->Get("version");

	SetSchemaVersion(version);

	if (Utility::CompareVersion(IDO_COMPAT_SCHEMA_VERSION, version) < 0) {
		PQfinish(m_Connection);
		SetConnected(false);

		Log(LogCritical, "IdoPgsqlConnection")
		    << "Schema version '" << version << "' does not match the required version '"
		    << IDO_COMPAT_SCHEMA_VERSION << "' (or newer)! Please check the upgrade documentation.";

		Application::Exit(EXIT_FAILURE);
	}

	String instanceName = GetInstanceName();

	result = Query("SELECT instance_id FROM " + GetTablePrefix() + "instances WHERE instance_name = E'" + Escape(instanceName) + "'");
	row = FetchRow(result, 0);

	if (!row) {
		Query("INSERT INTO " + GetTablePrefix() + "instances (instance_name, instance_description) VALUES (E'" + Escape(instanceName) + "', E'" + Escape(GetInstanceDescription()) + "')");
		m_InstanceID = GetSequenceValue(GetTablePrefix() + "instances", "instance_id");
	} else {
		m_InstanceID = DbReference(row->Get("instance_id"));
	}

	Endpoint::Ptr my_endpoint = Endpoint::GetLocalEndpoint();

	/* we have an endpoint in a cluster setup, so decide if we can proceed here */
	if (my_endpoint && GetHAMode() == HARunOnce) {
		/* get the current endpoint writing to programstatus table */
		result = Query("SELECT UNIX_TIMESTAMP(status_update_time) AS status_update_time, endpoint_name FROM " +
		    GetTablePrefix() + "programstatus WHERE instance_id = " + Convert::ToString(m_InstanceID));
		row = FetchRow(result, 0);

		String endpoint_name;

		if (row)
			endpoint_name = row->Get("endpoint_name");
		else
			Log(LogNotice, "IdoPgsqlConnection", "Empty program status table");

		/* if we did not write into the database earlier, another instance is active */
		if (endpoint_name != my_endpoint->GetName()) {
			double status_update_time;

			if (row)
				status_update_time = row->Get("status_update_time");
			else
				status_update_time = 0;

			double status_update_age = Utility::GetTime() - status_update_time;

			Log(LogNotice, "IdoPgsqlConnection")
			    << "Last update by '" << endpoint_name << "' was " << status_update_age << "s ago.";

			if (status_update_age < GetFailoverTimeout()) {
				PQfinish(m_Connection);
				SetConnected(false);
				SetShouldConnect(false);

				return;
			}

			/* activate the IDO only, if we're authoritative in this zone */
			if (IsPaused()) {
				Log(LogNotice, "IdoPgsqlConnection")
				    << "Local endpoint '" << my_endpoint->GetName() << "' is not authoritative, bailing out.";

				PQfinish(m_Connection);
				SetConnected(false);

				return;
			}
		}

		Log(LogNotice, "IdoPgsqlConnection", "Enabling IDO connection.");
	}

	Log(LogInformation, "IdoPgsqlConnection")
	    << "pgSQL IDO instance id: " << static_cast<long>(m_InstanceID) << " (schema version: '" + version + "')";

	Query("BEGIN");

	/* update programstatus table */
	UpdateProgramStatus();

	/* record connection */
	Query("INSERT INTO " + GetTablePrefix() + "conninfo " +
	    "(instance_id, connect_time, last_checkin_time, agent_name, agent_version, connect_type, data_start_time) VALUES ("
	    + Convert::ToString(static_cast<long>(m_InstanceID)) + ", NOW(), NOW(), E'icinga2 db_ido_pgsql', E'" + Escape(Application::GetAppVersion())
	    + "', E'" + (reconnect ? "RECONNECT" : "INITIAL") + "', NOW())");

	/* clear config tables for the initial config dump */
	PrepareDatabase();

	std::ostringstream q1buf;
	q1buf << "SELECT object_id, objecttype_id, name1, name2, is_active FROM " + GetTablePrefix() + "objects WHERE instance_id = " << static_cast<long>(m_InstanceID);
	result = Query(q1buf.str());

	std::vector<DbObject::Ptr> activeDbObjs;

	int index = 0;
	while ((row = FetchRow(result, index))) {
		index++;

		DbType::Ptr dbtype = DbType::GetByID(row->Get("objecttype_id"));

		if (!dbtype)
			continue;

		DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2"));
		SetObjectID(dbobj, DbReference(row->Get("object_id")));
		bool active = row->Get("is_active");
		SetObjectActive(dbobj, active);

		if (active)
			activeDbObjs.push_back(dbobj);
	}

	SetIDCacheValid(true);

	EnableActiveChangedHandler();

	for (const DbObject::Ptr& dbobj : activeDbObjs) {
		if (dbobj->GetObject())
			continue;

		Log(LogNotice, "IdoPgsqlConnection")
		    << "Deactivate deleted object name1: '" << dbobj->GetName1()
		    << "' name2: '" << dbobj->GetName2() + "'.";
		DeactivateObject(dbobj);
	}

	UpdateAllObjects();

	m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::ClearTablesBySession, this), PriorityLow);

	m_QueryQueue.Enqueue(boost::bind(&IdoPgsqlConnection::FinishConnect, this, startTime), PriorityLow);
}
Exemple #5
0
void DbType::RegisterType(const DbType::Ptr& type)
{
	boost::mutex::scoped_lock lock(GetStaticMutex());
	GetTypes()[type->GetName()] = type;
}