Skip to content

Commit

Permalink
Allow easily overriding database, username and password for Dev Services
Browse files Browse the repository at this point in the history
Not all database containers support everything but it's implemented for
all everything that is supported.
  • Loading branch information
gsmet committed Jun 21, 2022
1 parent 8a0fe37 commit c7b90ee
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 31 deletions.
21 changes: 16 additions & 5 deletions docs/src/main/asciidoc/databases-dev-services.adoc
Expand Up @@ -85,13 +85,13 @@ Login credentials are the same for most databases, except when the database requ
|Database |Username |Password |Database name

|PostgreSQL, MariaDB, MySQL, IBM Db2, H2
|quarkus
|quarkus
|quarkus
|`quarkus` for the default datasource or name of the datasource
|`quarkus`
|`quarkus`

|Microsoft SQL Server
|SA
|Quarkuspassword1
|`SA`
|`Quarkus123`
|

|===
Expand All @@ -102,6 +102,15 @@ The Microsoft SQL Server Testcontainer doesn't support defining the username or
It also requires a strong password.
====

[TIP]
====
For databases supporting it
(i.e. all of them except Microsoft SQL Server for which it is only possible to override the password),
you can override the database name, username and password used by the Dev Service.
See <<configuration-reference>> for more information.
====

Keep in mind that, except if configured otherwise (see below), a Dev Service runs on a random port.
For instance, when you run PostgreSQL as a Dev Service and have `psql` installed on the host, you can connect via:

Expand Down Expand Up @@ -134,6 +143,8 @@ quarkus.datasource."datasource-name".devservices.port=<your fixed port> <2>
<1> Fixed port for the default datasource.
<2> Fixed port for a named datasource.


[[configuration-reference]]
== Configuration Reference

Dev Services for Databases support the following configuration options:
Expand Down
Expand Up @@ -8,8 +8,8 @@ private DatabaseDefaultSetupConfig() {
public static final String DEFAULT_DATABASE_USERNAME = "quarkus";

public static final String DEFAULT_DATABASE_PASSWORD = "quarkus";

// mssql container enforces a 'strong' password with min 8 chars, upper/lowercase, number or special char
public static final String DEFAULT_DATABASE_STRONG_PASSWORD = "Quarkuspassword1";
public static final String DEFAULT_DATABASE_STRONG_PASSWORD = "Quarkus123";

public static final String DEFAULT_DATABASE_NAME = "quarkus";
}
Expand Up @@ -11,17 +11,26 @@ public class DevServicesDatasourceContainerConfig {
private final Map<String, String> additionalJdbcUrlProperties;
private final OptionalInt fixedExposedPort;
private final Optional<String> command;
private final Optional<String> dbName;
private final Optional<String> username;
private final Optional<String> password;

public DevServicesDatasourceContainerConfig(Optional<String> imageName,
Map<String, String> containerProperties,
Map<String, String> additionalJdbcUrlProperties,
OptionalInt port,
Optional<String> command) {
Optional<String> command,
Optional<String> dbName,
Optional<String> username,
Optional<String> password) {
this.imageName = imageName;
this.containerProperties = containerProperties;
this.additionalJdbcUrlProperties = additionalJdbcUrlProperties;
this.fixedExposedPort = port;
this.command = command;
this.dbName = dbName;
this.username = username;
this.password = password;
}

public Optional<String> getImageName() {
Expand All @@ -43,4 +52,16 @@ public OptionalInt getFixedExposedPort() {
public Optional<String> getCommand() {
return command;
}

public Optional<String> getDbName() {
return dbName;
}

public Optional<String> getUsername() {
return username;
}

public Optional<String> getPassword() {
return password;
}
}
Expand Up @@ -267,7 +267,10 @@ private RunningDevService startDevDb(String dbName,
dataSourceBuildTimeConfig.devservices.containerProperties,
dataSourceBuildTimeConfig.devservices.properties,
dataSourceBuildTimeConfig.devservices.port,
dataSourceBuildTimeConfig.devservices.command);
dataSourceBuildTimeConfig.devservices.command,
dataSourceBuildTimeConfig.devservices.dbName,
dataSourceBuildTimeConfig.devservices.username,
dataSourceBuildTimeConfig.devservices.password);

DevServicesDatasourceProvider.RunningDevServicesDatasource datasource = devDbProvider
.startDatabase(ConfigProvider.getConfig().getOptionalValue(prefix + "username", String.class),
Expand Down
Expand Up @@ -59,4 +59,21 @@ public class DevServicesBuildTimeConfig {
@ConfigItem
public Optional<String> command;

/**
* The name of the database to use if this Dev Service supports overriding it.
*/
@ConfigItem
public Optional<String> dbName;

/**
* The username to use if this Dev Service supports overriding it.
*/
@ConfigItem
public Optional<String> username;

/**
* The password to use if this Dev Service supports overriding it.
*/
@ConfigItem
public Optional<String> password;
}
Expand Up @@ -39,9 +39,14 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withUsername(username.orElse(DEFAULT_DATABASE_USERNAME))
.withPassword(password.orElse(DEFAULT_DATABASE_PASSWORD))
.withDatabaseName(datasourceName.orElse(DEFAULT_DATABASE_NAME))

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

container.withUsername(effectiveUsername)
.withPassword(effectivePassword)
.withDatabaseName(effectiveDbName)
.withReuse(true);
containerConfig.getAdditionalJdbcUrlProperties().forEach(container::withUrlParam);
containerConfig.getCommand().ifPresent(container::setCommand);
Expand Down
@@ -1,5 +1,7 @@
package io.quarkus.devservices.derby.deployment;

import static io.quarkus.datasource.deployment.spi.DatabaseDefaultSetupConfig.DEFAULT_DATABASE_NAME;

import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
Expand Down Expand Up @@ -36,6 +38,9 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
int port = containerConfig.getFixedExposedPort().isPresent()
? containerConfig.getFixedExposedPort().getAsInt()
: 1527 + (launchMode == LaunchMode.TEST ? 0 : 1);

String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

NetworkServerControl server = new NetworkServerControl(InetAddress.getByName("localhost"), port);
server.start(new PrintWriter(System.out));
for (int i = 1; i <= NUMBER_OF_PINGS; i++) {
Expand Down Expand Up @@ -65,7 +70,7 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
additionalArgs.append(i.getValue());
}
return new RunningDevServicesDatasource(null,
"jdbc:derby://localhost:" + port + "/memory:" + datasourceName.orElse("quarkus") + ";create=true"
"jdbc:derby://localhost:" + port + "/memory:" + effectiveDbName + ";create=true"
+ additionalArgs.toString(),
null,
null,
Expand Down
Expand Up @@ -43,6 +43,10 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
"-ifNotExists");
tcpServer.start();

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

StringBuilder additionalArgs = new StringBuilder();
for (Map.Entry<String, String> i : containerConfig.getAdditionalJdbcUrlProperties().entrySet()) {
additionalArgs.append(";");
Expand All @@ -54,13 +58,13 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
LOG.info("Dev Services for H2 started.");

String connectionUrl = "jdbc:h2:tcp://localhost:" + tcpServer.getPort() + "/mem:"
+ datasourceName.orElse(DEFAULT_DATABASE_NAME)
+ effectiveDbName
+ ";DB_CLOSE_DELAY=-1" + additionalArgs.toString();
return new RunningDevServicesDatasource(null,
connectionUrl,
null,
DEFAULT_DATABASE_USERNAME,
DEFAULT_DATABASE_PASSWORD,
effectiveUsername,
effectivePassword,
new Closeable() {
@Override
public void close() throws IOException {
Expand All @@ -70,8 +74,8 @@ public void close() throws IOException {
//make sure the DB is removed on close
try (Connection connection = DriverManager.getConnection(
connectionUrl,
DEFAULT_DATABASE_USERNAME,
DEFAULT_DATABASE_PASSWORD)) {
effectiveUsername,
effectivePassword)) {
try (Statement statement = connection.createStatement()) {
statement.execute("SET DB_CLOSE_DELAY 0");
}
Expand Down
Expand Up @@ -42,9 +42,14 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withUsername(username.orElse(DEFAULT_DATABASE_USERNAME))
.withPassword(password.orElse(DEFAULT_DATABASE_PASSWORD))
.withDatabaseName(datasourceName.orElse(DEFAULT_DATABASE_NAME))

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

container.withUsername(effectiveUsername)
.withPassword(effectivePassword)
.withDatabaseName(effectiveDbName)
.withReuse(true);

if (containerConfig.getContainerProperties().containsKey(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME)) {
Expand Down
Expand Up @@ -37,7 +37,12 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withPassword(password.orElse(DEFAULT_DATABASE_STRONG_PASSWORD))

String effectivePassword = containerConfig.getPassword()
.orElse(password.orElse(DEFAULT_DATABASE_STRONG_PASSWORD));

// Defining the database name and the username is not supported by this container yet
container.withPassword(effectivePassword)
.withReuse(true);
containerConfig.getAdditionalJdbcUrlProperties().forEach(container::withUrlParam);
containerConfig.getCommand().ifPresent(container::setCommand);
Expand Down
Expand Up @@ -41,9 +41,14 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withUsername(username.orElse(DEFAULT_DATABASE_USERNAME))
.withPassword(password.orElse(DEFAULT_DATABASE_PASSWORD))
.withDatabaseName(datasourceName.orElse(DEFAULT_DATABASE_NAME))

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

container.withUsername(effectiveUsername)
.withPassword(effectivePassword)
.withDatabaseName(effectiveDbName)
.withReuse(true);

if (containerConfig.getContainerProperties().containsKey(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME)) {
Expand Down
Expand Up @@ -42,9 +42,14 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withUsername(username.orElse(DEFAULT_DATABASE_USERNAME))
.withPassword(password.orElse(DEFAULT_DATABASE_PASSWORD))
.withDatabaseName(datasourceName.orElse(DEFAULT_DATABASE_NAME))

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

container.withUsername(effectiveUsername)
.withPassword(effectivePassword)
.withDatabaseName(effectiveDbName)
.withReuse(true);

// We need to limit the maximum amount of CPUs being used by the container;
Expand Down
Expand Up @@ -46,9 +46,14 @@ public RunningDevServicesDatasource startDatabase(Optional<String> username, Opt
containerConfig.getFixedExposedPort(),
!devServicesSharedNetworkBuildItem.isEmpty());
startupTimeout.ifPresent(container::withStartupTimeout);
container.withUsername(username.orElse(DEFAULT_DATABASE_USERNAME))
.withPassword(password.orElse(DEFAULT_DATABASE_PASSWORD))
.withDatabaseName(datasourceName.orElse(DEFAULT_DATABASE_NAME))

String effectiveUsername = containerConfig.getUsername().orElse(username.orElse(DEFAULT_DATABASE_USERNAME));
String effectivePassword = containerConfig.getPassword().orElse(password.orElse(DEFAULT_DATABASE_PASSWORD));
String effectiveDbName = containerConfig.getDbName().orElse(datasourceName.orElse(DEFAULT_DATABASE_NAME));

container.withUsername(effectiveUsername)
.withPassword(effectivePassword)
.withDatabaseName(effectiveDbName)
.withReuse(true);
containerConfig.getAdditionalJdbcUrlProperties().forEach(container::withUrlParam);
containerConfig.getCommand().ifPresent(container::setCommand);
Expand Down

0 comments on commit c7b90ee

Please sign in to comment.