Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion multiapps-controller-database-migration/pom.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>multiapps-controller-database-migration</artifactId>
Expand Down Expand Up @@ -45,6 +45,10 @@
<groupId>org.cloudfoundry.multiapps</groupId>
<artifactId>multiapps-controller-persistence</artifactId>
</dependency>
<dependency>
<groupId>org.cloudfoundry.multiapps</groupId>
<artifactId>multiapps-common</artifactId>
</dependency>
<dependency>
<groupId>io.pivotal.cfenv</groupId>
<artifactId>java-cfenv</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
package org.cloudfoundry.multiapps.controller.database.migration;

import java.io.IOException;
import java.io.InputStream;
import javax.sql.DataSource;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.cloudfoundry.multiapps.common.util.JsonUtil;
import org.cloudfoundry.multiapps.controller.database.migration.executor.DatabaseSequenceMigrationExecutor;
import org.cloudfoundry.multiapps.controller.database.migration.executor.DatabaseTableMigrationExecutor;
import org.cloudfoundry.multiapps.controller.database.migration.executor.ImmutableDatabaseSequenceMigrationExecutor;
import org.cloudfoundry.multiapps.controller.database.migration.executor.ImmutableDatabaseTableMigrationExecutor;
import org.cloudfoundry.multiapps.controller.database.migration.extractor.DataSourceEnvironmentExtractor;

import java.io.IOException;
import java.io.InputStream;
import javax.sql.DataSource;
import org.cloudfoundry.multiapps.controller.persistence.dto.DatabaseServiceKey;

public class DatabaseMigration {

private static final Logger LOGGER = (Logger) LogManager.getLogger(DatabaseMigration.class);
private static final String DATABASE_TARGET_SERVICE_KEY = "DATABASE_TARGET_SERVICE_KEY";

public static void main(String[] args) {
configureLogger();
LOGGER.info("Starting database migration...");
DatabaseServiceKey databaseServiceKey = getServiceKeyFromEnvironment();
DataSourceEnvironmentExtractor environmentExtractor = new DataSourceEnvironmentExtractor();
DataSource sourceDataSource = environmentExtractor.extractDataSource("deploy-service-database-source");
DataSource targetDataSource = environmentExtractor.extractDataSource("deploy-service-database");
DataSource sourceDataSource = environmentExtractor.extractDataSource(databaseServiceKey);

DatabaseSequenceMigrationExecutor sequenceMigrationExecutor = ImmutableDatabaseSequenceMigrationExecutor.builder()
.sourceDataSource(sourceDataSource)
.targetDataSource(targetDataSource)
.sourceDataSource(
sourceDataSource)
.targetDataSource(
targetDataSource)
.build();

DatabaseTableMigrationExecutor tableMigrationExecutor = ImmutableDatabaseTableMigrationExecutor.builder()
Expand All @@ -36,13 +41,17 @@ public static void main(String[] args) {
.build();
sequenceMigrationExecutor.executeMigration("configuration_entry_sequence");
sequenceMigrationExecutor.executeMigration("configuration_subscription_sequence");

tableMigrationExecutor.executeMigration("configuration_registry");
tableMigrationExecutor.executeMigration("configuration_subscription");

LOGGER.info("Database migration completed.");
}

private static DatabaseServiceKey getServiceKeyFromEnvironment() {
String databaseTargetServiceKey = System.getenv(DATABASE_TARGET_SERVICE_KEY);
return new DatabaseServiceKey(JsonUtil.convertJsonToMap(databaseTargetServiceKey));
}

private static void configureLogger() {
ClassLoader classLoader = DatabaseMigration.class.getClassLoader();
if (classLoader != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import javax.sql.DataSource;

import io.pivotal.cfenv.jdbc.CfJdbcService;
import org.cloudfoundry.multiapps.controller.persistence.dto.DatabaseServiceKey;
import org.cloudfoundry.multiapps.controller.persistence.util.DataSourceFactory;
import org.cloudfoundry.multiapps.controller.persistence.util.EnvironmentServicesFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.pivotal.cfenv.jdbc.CfJdbcService;

public class DataSourceEnvironmentExtractor {

private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceEnvironmentExtractor.class);
Expand All @@ -19,6 +19,10 @@ public DataSource extractDataSource(String serviceName) {
return createDataSource(service);
}

public DataSource extractDataSource(DatabaseServiceKey databaseServiceKey) {
return createDataSource(databaseServiceKey);
}

private CfJdbcService findService(String serviceName) {
return new EnvironmentServicesFinder().findJdbcService(serviceName);
}
Expand All @@ -27,4 +31,7 @@ private DataSource createDataSource(CfJdbcService service) {
return new DataSourceFactory().createDataSource(service);
}

private DataSource createDataSource(DatabaseServiceKey databaseServiceKey) {
return new DataSourceFactory().createDataSource(databaseServiceKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.cloudfoundry.multiapps.controller.persistence.dto;

import java.text.MessageFormat;
import java.util.Map;

public class DatabaseServiceKey {

private final Map<String, Object> credentials;
private static final String JDBC_URI_TEMPLATE = "jdbc:postgresql://{0}:{1}/{2}?user={3}&password={4}";

public DatabaseServiceKey(Map<String, Object> credentials) {
this.credentials = credentials;
}

public String getUsername() {
return getValueFromCredentials("username");
}

public String getPassword() {
return getValueFromCredentials("password");
}

public String getJdbcUri() {
return MessageFormat.format(JDBC_URI_TEMPLATE, getHostname(), getPort(), getDbName(), getUsername(), getPassword());
}

private String getHostname() {
return getValueFromCredentials("hostname");
}

private String getPort() {
return getValueFromCredentials("port");
}

private String getDbName() {
return getValueFromCredentials("dbname");
}

private String getValueFromCredentials(String key) {
return getCredentialsObject().get(key)
.toString();
}

private Map<String, Object> getCredentialsObject() {
return (Map<String, Object>) credentials.get("credentials");
}
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,61 @@
package org.cloudfoundry.multiapps.controller.persistence.util;

import java.nio.file.Path;

import javax.sql.DataSource;

import org.cloudfoundry.multiapps.controller.persistence.Constants;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import io.pivotal.cfenv.jdbc.CfJdbcService;
import jakarta.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.cloudfoundry.multiapps.controller.persistence.Constants;
import org.cloudfoundry.multiapps.controller.persistence.dto.DatabaseServiceKey;

@Named
public class DataSourceFactory {

private static final Logger LOGGER = (Logger) LogManager.getLogger(DataSourceFactory.class);

public DataSource createDataSource(CfJdbcService service) {
return createDataSource(service, null, null);
}

public DataSource createDataSource(DatabaseServiceKey databaseServiceKey) {
DatabaseConfig databaseConfig = createDatabaseConfigFromDatabaseServiceKey(databaseServiceKey);
return new HikariDataSource(createHikariConfig(databaseConfig, null, "null"));
}

public DataSource createDataSource(CfJdbcService service, Integer maximumPoolSize, String appInstanceTemplate) {
return new HikariDataSource(createHikariConfig(service, maximumPoolSize, appInstanceTemplate));
DatabaseConfig databaseConfig = createDatabaseConfigFromCfJdbcService(service);
return new HikariDataSource(createHikariConfig(databaseConfig, maximumPoolSize, appInstanceTemplate));
}

private HikariConfig createHikariConfig(CfJdbcService service, Integer maximumPoolSize, String appInstanceTemplate) {
private HikariConfig createHikariConfig(DatabaseConfig databaseConfig, Integer maximumPoolSize, String appInstanceTemplate) {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setUsername(service.getUsername());
hikariConfig.setPassword(service.getPassword());
hikariConfig.setJdbcUrl(service.getJdbcUrl());
hikariConfig.setUsername(databaseConfig.username);
hikariConfig.setPassword(databaseConfig.password);
hikariConfig.setJdbcUrl(databaseConfig.jdbcUrl);
hikariConfig.setConnectionTimeout(60000);
hikariConfig.setIdleTimeout(60000);
hikariConfig.setMinimumIdle(10);
hikariConfig.addDataSourceProperty("tcpKeepAlive", true);
hikariConfig.addDataSourceProperty("ApplicationName", appInstanceTemplate);

configureSSLClientKeyIfExists(service, hikariConfig);
configureSSLClientKeyIfExists(databaseConfig, hikariConfig);

if (appInstanceTemplate != null) {
hikariConfig.addDataSourceProperty("ApplicationName", appInstanceTemplate);
}
if (maximumPoolSize != null) {
hikariConfig.setMaximumPoolSize(maximumPoolSize);
}
hikariConfig.setRegisterMbeans(true);
return hikariConfig;
}

private void configureSSLClientKeyIfExists(CfJdbcService service, HikariConfig hikariConfig) {
String clientKey = (String) service.getCredentials()
.getMap()
.get("sslkey");
if (clientKey != null) {
configureClientCertificate(clientKey, hikariConfig);
private void configureSSLClientKeyIfExists(DatabaseConfig service, HikariConfig hikariConfig) {
if (service.sslKey != null) {
configureClientCertificate(service.sslKey, hikariConfig);
}
}

Expand All @@ -58,4 +65,19 @@ private void configureClientCertificate(String clientKey, HikariConfig hikariCon
hikariConfig.addDataSourceProperty("sslkey", encodedKeyPath.toAbsolutePath());
}

private DatabaseConfig createDatabaseConfigFromCfJdbcService(CfJdbcService service) {
String clientKey = (String) service.getCredentials()
.getMap()
.get("sslkey");
return new DatabaseConfig(service.getUsername(), service.getPassword(), service.getJdbcUrl(), clientKey);
}

private DatabaseConfig createDatabaseConfigFromDatabaseServiceKey(DatabaseServiceKey databaseServiceKey) {
return new DatabaseConfig(databaseServiceKey.getUsername(), databaseServiceKey.getPassword(), databaseServiceKey.getJdbcUri(),
null);
}

private record DatabaseConfig(String username, String password, String jdbcUrl, String sslKey) {
}

}