cliParser->addSwitch("syslog", 0, "Log to syslog");
#endif
cliParser->addOption("logfile", 'l', "Log to a file", "path");
+ cliParser->addSwitch("config-from-environment", 0, "Load configuration from environment variables");
cliParser->addOption("select-backend", 0, "Switch storage backend (migrating data if possible)", "backendidentifier");
cliParser->addOption("select-authenticator", 0, "Select authentication backend", "authidentifier");
cliParser->addSwitch("add-user", 0, "Starts an interactive session to add a new core user");
}
-Storage::State AbstractSqlStorage::init(const QVariantMap &settings)
+Storage::State AbstractSqlStorage::init(const QVariantMap &settings,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- setConnectionProperties(settings);
+ setConnectionProperties(settings, environment, loadFromEnvironment);
_debug = Quassel::isOptionSet("debug");
}
-bool AbstractSqlStorage::setup(const QVariantMap &settings)
+bool AbstractSqlStorage::setup(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- setConnectionProperties(settings);
+ setConnectionProperties(settings, environment, loadFromEnvironment);
QSqlDatabase db = logDb();
if (!db.isOpen()) {
qCritical() << "Unable to setup Logging Backend!";
virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
public slots:
- virtual State init(const QVariantMap &settings = QVariantMap());
- virtual bool setup(const QVariantMap &settings = QVariantMap());
+ virtual State init(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false);
+ virtual bool setup(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false);
protected:
inline virtual void sync() {};
virtual bool updateSchemaVersion(int newVersion) = 0;
virtual bool setupSchemaVersion(int version) = 0;
- virtual void setConnectionProperties(const QVariantMap &properties) = 0;
+ virtual void setConnectionProperties(const QVariantMap &properties,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment) = 0;
virtual QString driverName() = 0;
inline virtual QString hostName() { return QString(); }
inline virtual int port() { return -1; }
#pragma once
#include <QObject>
+#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QVariant>
* \param settings Hostname, port, username, password, ...
* \return True if and only if the authenticator provider was initialized successfully.
*/
- virtual bool setup(const QVariantMap &settings = QVariantMap()) = 0;
+ virtual bool setup(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false) = 0;
//! Initialize the authenticator provider
/** \param settings Hostname, port, username, password, ...
* \return the State the authenticator backend is now in (see authenticator::State)
*/
- virtual State init(const QVariantMap &settings = QVariantMap()) = 0;
+ virtual State init(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false) = 0;
//! Validate a username with a given password.
/** \param user The username to validate
void Core::init()
{
- CoreSettings cs;
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ bool config_from_environment = Quassel::isOptionSet("config-from-environment");
+
+ QString db_backend;
+ QVariantMap db_connectionProperties;
+
+ QString auth_authenticator;
+ QVariantMap auth_properties;
+
+ bool writeError = false;
+
+ if (config_from_environment) {
+ db_backend = environment.value("DB_BACKEND");
+ auth_authenticator = environment.value("AUTH_AUTHENTICATOR");
+ } else {
+ CoreSettings cs;
+
+ QVariantMap dbsettings = cs.storageSettings().toMap();
+ db_backend = dbsettings.value("Backend").toString();
+ db_connectionProperties = dbsettings.value("ConnectionProperties").toMap();
+
+ QVariantMap authSettings = cs.authSettings().toMap();
+ auth_authenticator = authSettings.value("Authenticator", "Database").toString();
+ auth_properties = authSettings.value("AuthProperties").toMap();
+
+ writeError = !cs.isWritable();
+ }
+
// legacy
- QVariantMap dbsettings = cs.storageSettings().toMap();
- _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
+ _configured = initStorage(db_backend, db_connectionProperties, environment, config_from_environment);
// Not entirely sure what is 'legacy' about the above, but it seems to be the way things work!
if (_configured) {
- QVariantMap authSettings = cs.authSettings().toMap();
- initAuthenticator(authSettings.value("Authenticator", "Database").toString(), authSettings.value("AuthProperties").toMap());
+ initAuthenticator(auth_authenticator, auth_properties, environment, config_from_environment);
}
if (Quassel::isOptionSet("select-backend") || Quassel::isOptionSet("select-authenticator")) {
}
if (!_configured) {
- if (_registeredStorageBackends.size() == 0) {
- quWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting..."));
- quWarning() << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
- "Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n"
- "to work."));
- exit(EXIT_FAILURE); // TODO make this less brutal (especially for mono client -> popup)
- }
- quWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
+ if (config_from_environment) {
+ _configured = initStorage(db_backend, db_connectionProperties, environment, config_from_environment, true);
+ initAuthenticator(auth_authenticator, auth_properties, environment, config_from_environment, true);
- if (!cs.isWritable()) {
- qWarning() << "Cannot write quasselcore configuration; probably a permission problem.";
- exit(EXIT_FAILURE);
- }
+ if (!_configured) {
+ qWarning() << "Cannot configure from environment";
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if (_registeredStorageBackends.empty()) {
+ quWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting..."));
+ quWarning()
+ << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
+ "Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n"
+ "to work."));
+ exit(EXIT_FAILURE); // TODO make this less brutal (especially for mono client -> popup)
+ }
+ quWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
+ if (writeError) {
+ qWarning() << "Cannot write quasselcore configuration; probably a permission problem.";
+ exit(EXIT_FAILURE);
+ }
+ }
}
if (Quassel::isOptionSet("add-user")) {
if (adminUser.isEmpty() || adminPassword.isEmpty()) {
return tr("Admin user or password not set.");
}
- if (!(_configured = initStorage(backend, setupData, true))) {
+ if (!(_configured = initStorage(backend, setupData, {}, false, true))) {
return tr("Could not setup storage!");
}
quInfo() << "Selected authenticator:" << authenticator;
- if (!(_configured = initAuthenticator(authenticator, authSetupData, true)))
+ if (!(_configured = initAuthenticator(authenticator, authSetupData, {}, false, true)))
{
return tr("Could not setup authenticator!");
}
// old db settings:
// "Type" => "sqlite"
-bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool setup)
+bool Core::initStorage(const QString &backend, const QVariantMap &settings,
+ const QProcessEnvironment &environment, bool loadFromEnvironment, bool setup)
{
if (backend.isEmpty()) {
quWarning() << "No storage backend selected!";
return false;
}
- Storage::State storageState = storage->init(settings);
+ Storage::State storageState = storage->init(settings, environment, loadFromEnvironment);
switch (storageState) {
case Storage::NeedsSetup:
if (!setup)
return false; // trigger setup process
- if (storage->setup(settings))
- return initStorage(backend, settings, false);
+ if (storage->setup(settings, environment, loadFromEnvironment))
+ return initStorage(backend, settings, environment, loadFromEnvironment, false);
return false;
// if initialization wasn't successful, we quit to keep from coming up unconfigured
// FIXME: Apparently, this is the legacy way of initting storage backends?
// If there's a not-legacy way, it should be used here
-bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup)
+bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings,
+ const QProcessEnvironment &environment, bool loadFromEnvironment,
+ bool setup)
{
if (backend.isEmpty()) {
quWarning() << "No authenticator selected!";
return false;
}
- Authenticator::State authState = auth->init(settings);
+ Authenticator::State authState = auth->init(settings, environment, loadFromEnvironment);
switch (authState) {
case Authenticator::NeedsSetup:
if (!setup)
return false; // trigger setup process
- if (auth->setup(settings))
- return initAuthenticator(backend, settings, false);
+ if (auth->setup(settings, environment, loadFromEnvironment))
+ return initAuthenticator(backend, settings, environment, loadFromEnvironment, false);
return false;
// if initialization wasn't successful, we quit to keep from coming up unconfigured
void incomingConnection();
void clientDisconnected();
- bool initStorage(const QString &backend, const QVariantMap &settings, bool setup = false);
- bool initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup = false);
+ bool initStorage(const QString &backend, const QVariantMap &settings,
+ const QProcessEnvironment &environment, bool loadFromEnvironment,
+ bool setup = false);
+ bool initAuthenticator(const QString &backend, const QVariantMap &settings,
+ const QProcessEnvironment &environment, bool loadFromEnvironment,
+ bool setup = false);
void socketError(QAbstractSocket::SocketError err, const QString &errorString);
void setupClientSession(RemotePeer *, UserId);
}
-void LdapAuthenticator::setAuthProperties(const QVariantMap &properties)
+void LdapAuthenticator::setAuthProperties(const QVariantMap &properties,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- _hostName = properties["Hostname"].toString();
- _port = properties["Port"].toInt();
- _bindDN = properties["BindDN"].toString();
- _bindPassword = properties["BindPassword"].toString();
- _baseDN = properties["BaseDN"].toString();
- _filter = properties["Filter"].toString();
- _uidAttribute = properties["UidAttribute"].toString();
+ if (loadFromEnvironment) {
+ _hostName = environment.value("AUTH_LDAP_HOSTNAME");
+ _port = environment.value("AUTH_LDAP_PORT").toInt();
+ _bindDN = environment.value("AUTH_LDAP_BIND_DN");
+ _bindPassword = environment.value("AUTH_LDAP_BIND_PASSWORD");
+ _baseDN = environment.value("AUTH_LDAP_BASE_DN");
+ _filter = environment.value("AUTH_LDAP_FILTER");
+ _uidAttribute = environment.value("AUTH_LDAP_UID_ATTRIBUTE");
+ } else {
+ _hostName = properties["Hostname"].toString();
+ _port = properties["Port"].toInt();
+ _bindDN = properties["BindDN"].toString();
+ _bindPassword = properties["BindPassword"].toString();
+ _baseDN = properties["BaseDN"].toString();
+ _filter = properties["Filter"].toString();
+ _uidAttribute = properties["UidAttribute"].toString();
+ }
}
// TODO: this code is sufficiently general that in the future, perhaps an abstract
}
-bool LdapAuthenticator::setup(const QVariantMap &settings)
+bool LdapAuthenticator::setup(const QVariantMap &settings,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- setAuthProperties(settings);
+ setAuthProperties(settings, environment, loadFromEnvironment);
bool status = ldapConnect();
return status;
}
-Authenticator::State LdapAuthenticator::init(const QVariantMap &settings)
+Authenticator::State LdapAuthenticator::init(const QVariantMap &settings,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- setAuthProperties(settings);
+ setAuthProperties(settings, environment, loadFromEnvironment);
bool status = ldapConnect();
if (!status) {
bool canChangePassword() const override { return false; }
- bool setup(const QVariantMap &settings = {}) override;
- State init(const QVariantMap &settings = {}) override;
+ bool setup(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment) override;
+ State init(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment) override;
UserId validateUser(const QString &user, const QString &password) override;
protected:
- void setAuthProperties(const QVariantMap &properties);
+ void setAuthProperties(const QVariantMap &properties, const QProcessEnvironment &environment,
+ bool loadFromEnvironment);
bool ldapConnect();
void ldapDisconnect();
bool ldapAuth(const QString &username, const QString &password);
properties["Hostname"] = _hostName;
properties["Port"] = _port;
properties["Database"] = _databaseName;
- writer->setConnectionProperties(properties);
+ writer->setConnectionProperties(properties, {}, false);
return std::unique_ptr<AbstractSqlMigrationWriter>{writer};
}
}
-void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties)
+void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
- _userName = properties["Username"].toString();
- _password = properties["Password"].toString();
- _hostName = properties["Hostname"].toString();
- _port = properties["Port"].toInt();
- _databaseName = properties["Database"].toString();
+ if (loadFromEnvironment) {
+ _userName = environment.value("DB_PGSQL_USERNAME");
+ _password = environment.value("DB_PGSQL_PASSWORD");
+ _hostName = environment.value("DB_PGSQL_HOSTNAME");
+ _port = environment.value("DB_PGSQL_PORT").toInt();
+ _databaseName = environment.value("DB_PGSQL_DATABASE");
+ } else {
+ _userName = properties["Username"].toString();
+ _password = properties["Password"].toString();
+ _hostName = properties["Hostname"].toString();
+ _port = properties["Port"].toInt();
+ _databaseName = properties["Database"].toString();
+ }
}
protected:
bool initDbSession(QSqlDatabase &db) override;
- void setConnectionProperties(const QVariantMap &properties) override;
+ void setConnectionProperties(const QVariantMap &properties,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment) override;
QString driverName() override { return "QPSQL"; }
QString hostName() override { return _hostName; }
int port() override { return _port; }
}
-bool SqlAuthenticator::setup(const QVariantMap &settings)
+bool SqlAuthenticator::setup(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
Q_UNUSED(settings)
+ Q_UNUSED(environment)
+ Q_UNUSED(loadFromEnvironment)
return true;
}
-Authenticator::State SqlAuthenticator::init(const QVariantMap &settings)
+Authenticator::State SqlAuthenticator::init(const QVariantMap &settings,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment)
{
Q_UNUSED(settings)
+ Q_UNUSED(environment)
+ Q_UNUSED(loadFromEnvironment)
// TODO: FIXME: this should check if the storage provider is ready, but I don't
// know if there's an exposed way to do that at the moment.
virtual inline bool canChangePassword() const { return true; }
- bool setup(const QVariantMap &settings = QVariantMap());
- State init(const QVariantMap &settings = QVariantMap());
+ bool setup(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment);
+ State init(const QVariantMap &settings, const QProcessEnvironment &environment,
+ bool loadFromEnvironment);
UserId validateUser(const QString &user, const QString &password);
/* User handling */
QString getAuthUserName(UserId user) override;
protected:
- void setConnectionProperties(const QVariantMap & /* properties */) override {}
+ void setConnectionProperties(const QVariantMap &properties,
+ const QProcessEnvironment &environment,
+ bool loadFromEnvironment) override {
+ Q_UNUSED(properties);
+ Q_UNUSED(environment);
+ Q_UNUSED(loadFromEnvironment);
+ }
+ // SQLite does not have any connection properties to set
QString driverName() override { return "QSQLITE"; }
QString databaseName() override { return backlogFile(); }
int installedSchemaVersion() override;
* \param settings Hostname, port, username, password, ...
* \return True if and only if the storage provider was initialized successfully.
*/
- virtual bool setup(const QVariantMap &settings = QVariantMap()) = 0;
+ virtual bool setup(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false) = 0;
//! Initialize the storage provider
/** \param settings Hostname, port, username, password, ...
* \return the State the storage backend is now in (see Storage::State)
*/
- virtual State init(const QVariantMap &settings = QVariantMap()) = 0;
+ virtual State init(const QVariantMap &settings = QVariantMap(),
+ const QProcessEnvironment &environment = {},
+ bool loadFromEnvironment = false) = 0;
//! Makes temp data persistent
/** This Method is periodically called by the Quassel Core to make temporary