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
11 changes: 11 additions & 0 deletions client/conf/db.properties.in
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ db.cloud.driver=@DBDRIVER@
db.cloud.port=3306
db.cloud.name=cloud

# Connection URI to the database "cloud". When this property is set, only the following properties will be used along with it: db.cloud.maxActive, db.cloud.maxIdle, db.cloud.maxWait, db.cloud.username, db.cloud.password, db.cloud.driver, db.cloud.validationQuery, db.cloud.isolation.level. Other properties will be ignored.
db.cloud.uri=


# CloudStack database tuning parameters
db.cloud.maxActive=250
db.cloud.maxIdle=30
Expand Down Expand Up @@ -61,6 +65,10 @@ db.usage.driver=@DBDRIVER@
db.usage.port=3306
db.usage.name=cloud_usage

# Connection URI to the database "usage". When this property is set, only the following properties will be used along with it: db.usage.maxActive, db.cloud.maxIdle, db.cloud.maxWait, db.usage.username, db.usage.password, db.usage.driver, db.usage.validationQuery, db.usage.isolation.level. Other properties will be ignored.
db.usage.uri=


# usage database tuning parameters
db.usage.maxActive=100
db.usage.maxIdle=30
Expand All @@ -79,6 +87,9 @@ db.simulator.maxIdle=30
db.simulator.maxWait=10000
db.simulator.autoReconnect=true

# Connection URI to the database "simulator". When this property is set, only the following properties will be used along with it: db.simulator.host, db.simulator.port, db.simulator.name, db.simulator.autoReconnect. Other properties will be ignored.
db.simulator.uri=


# High Availability And Cluster Properties
db.ha.enabled=false
Expand Down
5 changes: 5 additions & 0 deletions framework/db/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class DriverLoader {
DRIVERS.put("jdbc:mysql", "com.mysql.cj.jdbc.Driver");
DRIVERS.put("jdbc:postgresql", "org.postgresql.Driver");
DRIVERS.put("jdbc:h2", "org.h2.Driver");
DRIVERS.put("jdbc:mariadb", "org.mariadb.jdbc.Driver");

LOADED_DRIVERS = new ArrayList<String>();
}
Expand Down
153 changes: 112 additions & 41 deletions framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
Expand Down Expand Up @@ -1001,7 +1002,7 @@ public String toString() {
private static DataSource s_ds;
private static DataSource s_usageDS;
private static DataSource s_simulatorDS;
private static boolean s_dbHAEnabled;
protected static boolean s_dbHAEnabled;

static {
// Initialize with assumed db.properties file
Expand Down Expand Up @@ -1032,11 +1033,6 @@ public static void initDataSource(Properties dbProps) {
final long cloudMaxWait = Long.parseLong(dbProps.getProperty("db.cloud.maxWait"));
final String cloudUsername = dbProps.getProperty("db.cloud.username");
final String cloudPassword = dbProps.getProperty("db.cloud.password");
final String cloudHost = dbProps.getProperty("db.cloud.host");
final String cloudDriver = dbProps.getProperty("db.cloud.driver");
final int cloudPort = Integer.parseInt(dbProps.getProperty("db.cloud.port"));
final String cloudDbName = dbProps.getProperty("db.cloud.name");
final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect"));
final String cloudValidationQuery = dbProps.getProperty("db.cloud.validationQuery");
final String cloudIsolationLevel = dbProps.getProperty("db.cloud.isolation.level");

Expand All @@ -1059,16 +1055,6 @@ public static void initDataSource(Properties dbProps) {
final boolean cloudTestWhileIdle = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testWhileIdle"));
final long cloudTimeBtwEvictionRunsMillis = Long.parseLong(dbProps.getProperty("db.cloud.timeBetweenEvictionRunsMillis"));
final long cloudMinEvcitableIdleTimeMillis = Long.parseLong(dbProps.getProperty("db.cloud.minEvictableIdleTimeMillis"));
final boolean cloudPoolPreparedStatements = Boolean.parseBoolean(dbProps.getProperty("db.cloud.poolPreparedStatements"));
final String url = dbProps.getProperty("db.cloud.url.params");

String cloudDbHAParams = null;
String cloudReplicas = null;
if (s_dbHAEnabled) {
cloudDbHAParams = getDBHAParams("cloud", dbProps);
cloudReplicas = dbProps.getProperty("db.cloud.replicas");
s_logger.info("The replicas configured for Cloud Data base is/are : " + cloudReplicas);
}

final boolean useSSL = Boolean.parseBoolean(dbProps.getProperty("db.cloud.useSSL"));
if (useSSL) {
Expand All @@ -1078,13 +1064,12 @@ public static void initDataSource(Properties dbProps) {
System.setProperty("javax.net.ssl.trustStorePassword", dbProps.getProperty("db.cloud.trustStorePassword"));
}

final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudReplicas : "") + ":" + cloudPort + "/" + cloudDbName +
"?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") +
(s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
DriverLoader.loadDriver(cloudDriver);
Pair<String, String> cloudUriAndDriver = getConnectionUriAndDriver(dbProps, loadBalanceStrategy, useSSL, "cloud");

DriverLoader.loadDriver(cloudUriAndDriver.second());

// Default Data Source for CloudStack
s_ds = createDataSource(cloudConnectionUri, cloudUsername, cloudPassword, cloudMaxActive, cloudMaxIdle, cloudMaxWait,
s_ds = createDataSource(cloudUriAndDriver.first(), cloudUsername, cloudPassword, cloudMaxActive, cloudMaxIdle, cloudMaxWait,
cloudTimeBtwEvictionRunsMillis, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle, cloudTestOnBorrow,
cloudValidationQuery, isolationLevel);

Expand All @@ -1094,20 +1079,13 @@ public static void initDataSource(Properties dbProps) {
final long usageMaxWait = Long.parseLong(dbProps.getProperty("db.usage.maxWait"));
final String usageUsername = dbProps.getProperty("db.usage.username");
final String usagePassword = dbProps.getProperty("db.usage.password");
final String usageHost = dbProps.getProperty("db.usage.host");
final String usageDriver = dbProps.getProperty("db.usage.driver");
final int usagePort = Integer.parseInt(dbProps.getProperty("db.usage.port"));
final String usageDbName = dbProps.getProperty("db.usage.name");
final boolean usageAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.usage.autoReconnect"));
final String usageUrl = dbProps.getProperty("db.usage.url.params");

final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.replicas") : "") + ":" + usagePort +
"/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") +
(s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
DriverLoader.loadDriver(usageDriver);

Pair<String, String> usageUriAndDriver = getConnectionUriAndDriver(dbProps, loadBalanceStrategy, useSSL, "usage");

DriverLoader.loadDriver(usageUriAndDriver.second());

// Data Source for usage server
s_usageDS = createDataSource(usageConnectionUri, usageUsername, usagePassword,
s_usageDS = createDataSource(usageUriAndDriver.first(), usageUsername, usagePassword,
usageMaxActive, usageMaxIdle, usageMaxWait, null, null, null, null,
null, isolationLevel);

Expand All @@ -1118,14 +1096,28 @@ public static void initDataSource(Properties dbProps) {
final long simulatorMaxWait = Long.parseLong(dbProps.getProperty("db.simulator.maxWait"));
final String simulatorUsername = dbProps.getProperty("db.simulator.username");
final String simulatorPassword = dbProps.getProperty("db.simulator.password");
final String simulatorHost = dbProps.getProperty("db.simulator.host");
final String simulatorDriver = dbProps.getProperty("db.simulator.driver");
final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port"));
final String simulatorDbName = dbProps.getProperty("db.simulator.name");
final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect"));

final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" +
simulatorAutoReconnect;

String simulatorDriver;
String simulatorConnectionUri;
String simulatorUri = dbProps.getProperty("db.simulator.uri");

if (StringUtils.isEmpty(simulatorUri)) {
simulatorDriver = dbProps.getProperty("db.simulator.driver");
final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port"));
final String simulatorDbName = dbProps.getProperty("db.simulator.name");
final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect"));
final String simulatorHost = dbProps.getProperty("db.simulator.host");

simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" +
simulatorAutoReconnect;
} else {
s_logger.warn("db.simulator.uri was set, ignoring the following properties on db.properties: [db.simulator.driver, db.simulator.host, db.simulator.port, "
+ "db.simulator.name, db.simulator.autoReconnect].");
String[] splitUri = simulatorUri.split(":");
simulatorDriver = String.format("%s:%s", splitUri[0], splitUri[1]);
simulatorConnectionUri = simulatorUri;
}

DriverLoader.loadDriver(simulatorDriver);

s_simulatorDS = createDataSource(simulatorConnectionUri, simulatorUsername, simulatorPassword,
Expand All @@ -1143,6 +1135,85 @@ public static void initDataSource(Properties dbProps) {
}
}

protected static Pair<String, String> getConnectionUriAndDriver(Properties dbProps, String loadBalanceStrategy, boolean useSSL, String schema) {
String connectionUri;
String driver;
String propertyUri = dbProps.getProperty(String.format("db.%s.uri", schema));

if (StringUtils.isEmpty(propertyUri)) {
driver = dbProps.getProperty(String.format("db.%s.driver", schema));
connectionUri = getPropertiesAndBuildConnectionUri(dbProps, loadBalanceStrategy, driver, useSSL, schema);
} else {
s_logger.warn(String.format("db.%s.uri was set, ignoring the following properties for schema %s of db.properties: [host, port, name, driver, autoReconnect, url.params,"
+ " replicas, ha.loadBalanceStrategy, ha.enable, failOverReadOnly, reconnectAtTxEnd, autoReconnectForPools, secondsBeforeRetrySource, queriesBeforeRetrySource, "
+ "initialTimeout].", schema, schema));

String[] splitUri = propertyUri.split(":");
driver = String.format("%s:%s", splitUri[0], splitUri[1]);

connectionUri = propertyUri;
}
s_logger.info(String.format("Using the following URI to connect to %s database [%s].", schema, connectionUri));
return new Pair<>(connectionUri, driver);
}

protected static String getPropertiesAndBuildConnectionUri(Properties dbProps, String loadBalanceStrategy, String driver, boolean useSSL, String schema) {
String host = dbProps.getProperty(String.format("db.%s.host", schema));
int port = Integer.parseInt(dbProps.getProperty(String.format("db.%s.port", schema)));
String dbName = dbProps.getProperty(String.format("db.%s.name", schema));
boolean autoReconnect = Boolean.parseBoolean(dbProps.getProperty(String.format("db.%s.autoReconnect", schema)));
String urlParams = dbProps.getProperty(String.format("db.%s.url.params", schema));

String replicas = null;
String dbHaParams = null;
if (s_dbHAEnabled) {
dbHaParams = getDBHAParams(schema, dbProps);
replicas = dbProps.getProperty(String.format("db.%s.replicas", schema));
s_logger.info(String.format("The replicas configured for %s data base are %s.", schema, replicas));
}

return buildConnectionUri(loadBalanceStrategy, driver, useSSL, host, replicas, port, dbName, autoReconnect, urlParams, dbHaParams);
}

protected static String buildConnectionUri(String loadBalanceStrategy, String driver, boolean useSSL, String host, String replicas, int port, String dbName, boolean autoReconnect,
String urlParams, String dbHaParams) {

StringBuilder connectionUri = new StringBuilder();
connectionUri.append(driver);
connectionUri.append("://");
connectionUri.append(host);

if (s_dbHAEnabled) {
connectionUri.append(",");
connectionUri.append(replicas);
}

connectionUri.append(":");
connectionUri.append(port);
connectionUri.append("/");
connectionUri.append(dbName);
connectionUri.append("?autoReconnect=");
connectionUri.append(autoReconnect);

if (urlParams != null) {
connectionUri.append("&");
connectionUri.append(urlParams);
}

if (useSSL) {
connectionUri.append("&useSSL=true");
}

if (s_dbHAEnabled) {
connectionUri.append("&");
connectionUri.append(dbHaParams);
connectionUri.append("&loadBalanceStrategy=");
connectionUri.append(loadBalanceStrategy);
}

return connectionUri.toString();
}

/**
* Creates a data source
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.utils.db;

import com.cloud.utils.Pair;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.Properties;

@RunWith(MockitoJUnitRunner.class)
public class TransactionLegacyTest {

Properties properties;

@Before
public void setup(){
properties = new Properties();
properties.setProperty("db.cloud.host", "host");
properties.setProperty("db.cloud.port", "5555");
properties.setProperty("db.cloud.name", "name");
properties.setProperty("db.cloud.autoReconnect", "false");
properties.setProperty("db.cloud.url.params", "someParams");
TransactionLegacy.s_dbHAEnabled = false;
}
@Test
public void getConnectionUriAndDriverTestWithoutUri() {
properties.setProperty("db.cloud.uri", "");
properties.setProperty("db.cloud.driver", "driver");

Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");

Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams", result.first());
Assert.assertEquals("driver", result.second());
}

@Test
public void getConnectionUriAndDriverTestWithUri() {
properties.setProperty("db.cloud.uri", "jdbc:driver:myFavoriteUri");

Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");

Assert.assertEquals("jdbc:driver:myFavoriteUri", result.first());
Assert.assertEquals("jdbc:driver", result.second());
}

@Test
public void getPropertiesAndBuildConnectionUriTestDbHaDisabled() {
String result = TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", "driver", true, "cloud");

Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams&useSSL=true", result);
}

@Test
public void getPropertiesAndBuildConnectionUriTestDbHaEnabled() {
TransactionLegacy.s_dbHAEnabled = true;
properties.setProperty("db.cloud.failOverReadOnly", "true");
properties.setProperty("db.cloud.reconnectAtTxEnd", "false");
properties.setProperty("db.cloud.autoReconnectForPools", "true");
properties.setProperty("db.cloud.secondsBeforeRetrySource", "25");
properties.setProperty("db.cloud.queriesBeforeRetrySource", "105");
properties.setProperty("db.cloud.initialTimeout", "1000");
properties.setProperty("db.cloud.replicas", "second_host");

String result = TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", "driver", true, "cloud");

Assert.assertEquals("driver://host,second_host:5555/name?autoReconnect=false&someParams&useSSL=true&failOverReadOnly=true&reconnectAtTxEnd=false&autoReconnectFor"
+ "Pools=true&secondsBeforeRetrySource=25&queriesBeforeRetrySource=105&initialTimeout=1000&loadBalanceStrategy=strat", result);
}

@Test
public void buildConnectionUriTestDbHaDisabled() {
String result = TransactionLegacy.buildConnectionUri(null, "driver", false, "host", null, 5555, "cloud", false, null, null);

Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false", result);
}

@Test
public void buildConnectionUriTestDbHaEnabled() {
TransactionLegacy.s_dbHAEnabled = true;

String result = TransactionLegacy.buildConnectionUri("strat", "driver", false, "host", "second_host", 5555, "cloud", false, null, "dbHaParams");

Assert.assertEquals("driver://host,second_host:5555/cloud?autoReconnect=false&dbHaParams&loadBalanceStrategy=strat", result);
}

@Test
public void buildConnectionUriTestUrlParamsNotNull() {
String result = TransactionLegacy.buildConnectionUri(null, "driver", false, "host", null, 5555, "cloud", false, "urlParams", null);

Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&urlParams", result);
}

@Test
public void buildConnectionUriTestUseSslTrue() {
String result = TransactionLegacy.buildConnectionUri(null, "driver", true, "host", null, 5555, "cloud", false, null, null);

Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&useSSL=true", result);
}
}