[New] Allow to override DB config in env

This commit is contained in:
Robert von Burg 2023-02-10 10:07:44 +01:00
parent 405704968e
commit 8d8bfd0ede
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
5 changed files with 101 additions and 35 deletions

View File

@ -16,6 +16,7 @@
package li.strolch.runtime;
import static li.strolch.utils.helper.StringHelper.DOT;
import static li.strolch.utils.helper.StringHelper.UNDERLINE;
import li.strolch.agent.api.ObserverHandler;
import li.strolch.model.StrolchModelConstants;
@ -46,10 +47,14 @@ public class StrolchConstants extends StrolchModelConstants {
public static final String TYPE_STROLCH_JOB = "StrolchJob";
public static String makeRealmKey(String realmName, String key) {
return makeRealmKey(realmName, key, false);
}
public static String makeRealmKey(String realmName, String key, boolean useEnv) {
String realmKey = key;
if (!realmName.equals(DEFAULT_REALM))
realmKey += DOT + realmName;
return realmKey;
realmKey += (useEnv ? UNDERLINE : DOT) + realmName;
return useEnv ? realmKey.replace(DOT, UNDERLINE).toUpperCase() : realmKey;
}
/**

View File

@ -16,7 +16,9 @@
package li.strolch.runtime.configuration;
import static li.strolch.db.DbConstants.*;
import static li.strolch.runtime.StrolchConstants.DEFAULT_REALM;
import static li.strolch.runtime.StrolchConstants.makeRealmKey;
import static li.strolch.utils.helper.StringHelper.*;
import javax.sql.DataSource;
import java.sql.Connection;
@ -29,7 +31,6 @@ import java.util.Set;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.persistence.api.StrolchPersistenceException;
import li.strolch.runtime.StrolchConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -61,36 +62,44 @@ public abstract class DbConnectionBuilder {
if (realm.getMode().isTransient())
continue;
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM);
String dbUrlKey = makeRealmKey(realmName, PROP_DB_URL);
String dbUsernameKey = makeRealmKey(realmName, PROP_DB_USERNAME);
String dbPasswordKey = makeRealmKey(realmName, PROP_DB_PASSWORD);
String dbUseEnvKey = makeRealmKey(realmName, PROP_USE_ENV, false);
boolean dbUseEnv = this.configuration.getBoolean(dbUseEnvKey, false);
if (dbUseEnv)
logger.info("Configuration specifies to use environment variables to configure DB access...");
boolean dbIgnoreRealm = this.configuration.getBoolean(dbIgnoreRealmKey, Boolean.FALSE);
String dbUrlKey = makeRealmKey(realmName, PROP_DB_URL, dbUseEnv);
String dbUsernameKey = makeRealmKey(realmName, PROP_DB_USERNAME, dbUseEnv);
String dbPasswordKey = makeRealmKey(realmName, PROP_DB_PASSWORD, dbUseEnv);
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM, false);
boolean dbIgnoreRealm = this.configuration.getBoolean(dbIgnoreRealmKey, false);
if (dbIgnoreRealm) {
logger.info("[" + realm + "] Ignoring any DB configuration for Realm " + realmName);
continue;
}
String dbUrl = this.configuration.getString(dbUrlKey, null);
String username = this.configuration.getString(dbUsernameKey, null);
String password = this.configuration.getString(dbPasswordKey, null);
String dbUrl = getConfigString(dbUrlKey, dbUseEnv);
String username = getConfigString(dbUsernameKey, dbUseEnv);
String password = getConfigString(dbPasswordKey, dbUseEnv);
if (this.configuration.getBoolean(PROP_DB_ALLOW_HOST_OVERRIDE_ENV, false) //
&& System.getProperties().containsKey(PROP_DB_HOST_OVERRIDE)) {
dbUrl = overridePostgresqlHost(realm.getRealm(), dbUrl);
dbUrl = overridePostgresqlHost(realm.getRealm(), dbUrl, dbUseEnv);
}
// find any pool configuration values
Set<String> propertyKeys = this.configuration.getPropertyKeys();
Map<String, String> properties = dbUseEnv ? System.getenv() : this.configuration.getAsMap();
String dbPoolPrefix = dbUseEnv ?
PROP_DB_POOL_PREFIX.replace(DOT, UNDERLINE).toUpperCase() :
PROP_DB_POOL_PREFIX;
Properties props = new Properties();
for (String key : propertyKeys) {
if (!key.startsWith(PROP_DB_POOL_PREFIX))
for (String key : properties.keySet()) {
if (!key.startsWith(dbPoolPrefix))
continue;
// TODO we should change how properties for realms are configured
// since defaultRealm does not have to be on the key, we need this hack:
String[] segments = key.split("\\.");
String[] segments = key.split(dbUseEnv ? UNDERLINE : "\\.");
String poolKey;
String foundRealm;
if (segments.length == 4) {
@ -98,7 +107,7 @@ public abstract class DbConnectionBuilder {
foundRealm = segments[3];
} else if (segments.length == 3) {
// default realm
foundRealm = StrolchConstants.DEFAULT_REALM;
foundRealm = DEFAULT_REALM;
} else {
throw new IllegalArgumentException("Can't detect realm of this property: " + key);
}
@ -107,39 +116,62 @@ public abstract class DbConnectionBuilder {
continue;
poolKey = segments[2];
String value = this.configuration.getString(key, null);
String value = properties.get(key);
props.setProperty(poolKey, value);
}
DataSource ds = build(realmName, dbUrl, username, password, props);
dsMap.put(realmName, ds);
DataSource dataSource = build(realmName, dbUrl, username, password, props);
dsMap.put(realmName, dataSource);
}
return dsMap;
}
public static String overridePostgresqlHost(String realm, String dbUrl) {
if (!System.getProperties().containsKey(PROP_DB_HOST_OVERRIDE))
return dbUrl;
private String getConfigString(String dbKey, boolean useEnv) {
if (!useEnv)
return this.configuration.getString(dbKey, null);
String value = System.getenv(dbKey);
if (isEmpty(value))
throw new IllegalStateException("Missing environment variable " + dbKey);
return value;
}
public static String overridePostgresqlHost(String realmName, String dbUrl) {
return overridePostgresqlHost(realmName, dbUrl, false);
}
public static String overridePostgresqlHost(String realmName, String dbUrl, boolean useEnv) {
String hostOverride;
if (useEnv) {
if (!System.getenv().containsKey(ENV_DB_HOST_OVERRIDE))
return dbUrl;
String hostOverrideKey = makeRealmKey(realmName, PROP_DB_HOST_OVERRIDE, true);
hostOverride = System.getenv(hostOverrideKey);
} else {
if (!System.getProperties().containsKey(PROP_DB_HOST_OVERRIDE))
return dbUrl;
String hostOverrideKey = makeRealmKey(realmName, PROP_DB_HOST_OVERRIDE, false);
hostOverride = System.getProperty(hostOverrideKey);
}
if (!dbUrl.startsWith("jdbc:postgresql://"))
throw new IllegalStateException("DB URL is invalid: " + dbUrl);
String tmp = dbUrl.substring("jdbc:postgresql://".length());
String host = tmp.substring(0, tmp.indexOf('/'));
String dbName = tmp.substring(tmp.indexOf('/'));
String hostOverride = System.getProperty(PROP_DB_HOST_OVERRIDE);
if (host.equals(hostOverride))
return dbUrl;
logger.warn("[" + realm + "] Replacing db host " + host + " with override " + hostOverride);
logger.warn("[" + realmName + "] Replacing db host " + host + " with override " + hostOverride);
dbUrl = "jdbc:postgresql://" + hostOverride + dbName;
logger.warn("[" + realm + "] DB URL is now " + dbUrl);
logger.warn("[" + realmName + "] DB URL is now " + dbUrl);
return dbUrl;
}
protected abstract DataSource build(String realm, String url, String username, String password, Properties proops);
protected abstract DataSource build(String realm, String url, String username, String password, Properties props);
protected void validateConnection(DataSource ds) {
try (Connection con = ds.getConnection()) {

View File

@ -91,7 +91,7 @@ public abstract class PostgreSqlInitializer extends SystemAction {
protected File getDataStoreFile(RuntimeConfiguration runtimeConfiguration,
ComponentConfiguration realmConfiguration, String realmName) {
String dataStoreKey = makeRealmKey(realmName, PREFIX_DATA_STORE_FILE);
String dataStoreKey = makeRealmKey(realmName, PREFIX_DATA_STORE_FILE, false);
return realmConfiguration.getDataFile(dataStoreKey, null, runtimeConfiguration, true);
}
}

View File

@ -16,7 +16,10 @@
package li.strolch.persistence.xml;
import static li.strolch.agent.impl.DefaultRealmHandler.PREFIX_DATA_STORE_FILE;
import static li.strolch.db.DbConstants.PROP_DB_IGNORE_REALM;
import static li.strolch.db.DbConstants.PROP_USE_ENV;
import static li.strolch.runtime.StrolchConstants.makeRealmKey;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.io.File;
import java.text.MessageFormat;
@ -42,6 +45,7 @@ import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.runtime.configuration.RuntimeConfiguration;
import li.strolch.runtime.configuration.StrolchConfiguration;
import li.strolch.runtime.configuration.StrolchConfigurationException;
import li.strolch.utils.helper.StringHelper;
import li.strolch.xmlpers.api.*;
/**
@ -79,18 +83,21 @@ public class XmlPersistenceHandler extends StrolchComponent implements Persisten
if (realm.getMode().isTransient())
continue;
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM);
String dbStorePathKey = makeRealmKey(realmName, PROP_DB_STORE_PATH);
String dbVerboseKey = makeRealmKey(realmName, PROP_VERBOSE);
String dbUseEnvKey = makeRealmKey(realmName, PROP_USE_ENV, false);
boolean dbUseEnv = configuration.getBoolean(dbUseEnvKey, false);
boolean dbIgnoreRealm = configuration.getBoolean(dbIgnoreRealmKey, Boolean.FALSE);
String dbStorePathKey = makeRealmKey(realmName, PROP_DB_STORE_PATH, dbUseEnv);
String dbVerboseKey = makeRealmKey(realmName, PROP_VERBOSE, dbUseEnv);
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM, false);
boolean dbIgnoreRealm = configuration.getBoolean(dbIgnoreRealmKey, false);
if (dbIgnoreRealm) {
logger.info("Ignoring any DB configuration for Realm " + realmName);
continue;
}
String dbStorePath = configuration.getString(dbStorePathKey, null);
boolean verbose = configuration.getBoolean(dbVerboseKey, Boolean.FALSE);
String dbStorePath = getConfigString(configuration, dbStorePathKey, dbUseEnv);
boolean verbose = getConfigBoolean(configuration, dbVerboseKey, dbUseEnv);
// validate URL
if (dbStorePaths.contains(dbStorePath))
@ -128,6 +135,26 @@ public class XmlPersistenceHandler extends StrolchComponent implements Persisten
super.initialize(configuration);
}
private String getConfigString(ComponentConfiguration configuration, String dbKey, boolean useEnv) {
if (!useEnv)
return configuration.getString(dbKey, null);
String value = System.getenv(dbKey);
if (isEmpty(value))
throw new IllegalStateException("Missing environment variable " + dbKey);
return value;
}
private Boolean getConfigBoolean(ComponentConfiguration configuration, String dbKey, boolean useEnv) {
if (!useEnv)
return configuration.getBoolean(dbKey, false);
String value = System.getenv(dbKey);
if (isEmpty(value))
throw new IllegalStateException("Missing environment variable " + dbKey);
return StringHelper.parseBoolean(value);
}
@Override
public void start() throws Exception {

View File

@ -35,4 +35,6 @@ public class DbConstants {
public static final String PROP_ALLOW_DATA_INIT_ON_EMPTY_DB = "allowDataInitOnEmptyDb";
public static final String PROP_DB_VERSION = "db_version";
public static final String RESOURCE_DB_VERSION = "/{0}_db_version.properties";
public static final String ENV_DB_HOST_OVERRIDE = "DB_HOST_OVERRIDE";
}