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

View File

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

View File

@ -91,7 +91,7 @@ public abstract class PostgreSqlInitializer extends SystemAction {
protected File getDataStoreFile(RuntimeConfiguration runtimeConfiguration, protected File getDataStoreFile(RuntimeConfiguration runtimeConfiguration,
ComponentConfiguration realmConfiguration, String realmName) { 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); return realmConfiguration.getDataFile(dataStoreKey, null, runtimeConfiguration, true);
} }
} }

View File

@ -16,7 +16,10 @@
package li.strolch.persistence.xml; package li.strolch.persistence.xml;
import static li.strolch.agent.impl.DefaultRealmHandler.PREFIX_DATA_STORE_FILE; 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.runtime.StrolchConstants.makeRealmKey;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.io.File; import java.io.File;
import java.text.MessageFormat; 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.RuntimeConfiguration;
import li.strolch.runtime.configuration.StrolchConfiguration; import li.strolch.runtime.configuration.StrolchConfiguration;
import li.strolch.runtime.configuration.StrolchConfigurationException; import li.strolch.runtime.configuration.StrolchConfigurationException;
import li.strolch.utils.helper.StringHelper;
import li.strolch.xmlpers.api.*; import li.strolch.xmlpers.api.*;
/** /**
@ -79,18 +83,21 @@ public class XmlPersistenceHandler extends StrolchComponent implements Persisten
if (realm.getMode().isTransient()) if (realm.getMode().isTransient())
continue; continue;
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM); String dbUseEnvKey = makeRealmKey(realmName, PROP_USE_ENV, false);
String dbStorePathKey = makeRealmKey(realmName, PROP_DB_STORE_PATH); boolean dbUseEnv = configuration.getBoolean(dbUseEnvKey, false);
String dbVerboseKey = makeRealmKey(realmName, PROP_VERBOSE);
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) { if (dbIgnoreRealm) {
logger.info("Ignoring any DB configuration for Realm " + realmName); logger.info("Ignoring any DB configuration for Realm " + realmName);
continue; continue;
} }
String dbStorePath = configuration.getString(dbStorePathKey, null); String dbStorePath = getConfigString(configuration, dbStorePathKey, dbUseEnv);
boolean verbose = configuration.getBoolean(dbVerboseKey, Boolean.FALSE); boolean verbose = getConfigBoolean(configuration, dbVerboseKey, dbUseEnv);
// validate URL // validate URL
if (dbStorePaths.contains(dbStorePath)) if (dbStorePaths.contains(dbStorePath))
@ -128,6 +135,26 @@ public class XmlPersistenceHandler extends StrolchComponent implements Persisten
super.initialize(configuration); 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 @Override
public void start() throws Exception { 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_ALLOW_DATA_INIT_ON_EMPTY_DB = "allowDataInitOnEmptyDb";
public static final String PROP_DB_VERSION = "db_version"; public static final String PROP_DB_VERSION = "db_version";
public static final String RESOURCE_DB_VERSION = "/{0}_db_version.properties"; public static final String RESOURCE_DB_VERSION = "/{0}_db_version.properties";
public static final String ENV_DB_HOST_OVERRIDE = "DB_HOST_OVERRIDE";
} }