Skip to content

Commit 30ca5d1

Browse files
JoaoJandreJoão Jandre
andauthored
Flexible URI for connection with DB and new MariaDB driver (#7895)
Co-authored-by: João Jandre <[email protected]>
1 parent 7b31a51 commit 30ca5d1

File tree

5 files changed

+246
-41
lines changed

5 files changed

+246
-41
lines changed

client/conf/db.properties.in

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ db.cloud.driver=@DBDRIVER@
2929
db.cloud.port=3306
3030
db.cloud.name=cloud
3131

32+
# 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.
33+
db.cloud.uri=
34+
35+
3236
# CloudStack database tuning parameters
3337
db.cloud.maxActive=250
3438
db.cloud.maxIdle=30
@@ -61,6 +65,10 @@ db.usage.driver=@DBDRIVER@
6165
db.usage.port=3306
6266
db.usage.name=cloud_usage
6367

68+
# 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.
69+
db.usage.uri=
70+
71+
6472
# usage database tuning parameters
6573
db.usage.maxActive=100
6674
db.usage.maxIdle=30
@@ -79,6 +87,9 @@ db.simulator.maxIdle=30
7987
db.simulator.maxWait=10000
8088
db.simulator.autoReconnect=true
8189

90+
# 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.
91+
db.simulator.uri=
92+
8293

8394
# High Availability And Cluster Properties
8495
db.ha.enabled=false

framework/db/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
<artifactId>cloud-utils</artifactId>
5454
<version>${project.version}</version>
5555
</dependency>
56+
<dependency>
57+
<groupId>org.mariadb.jdbc</groupId>
58+
<artifactId>mariadb-java-client</artifactId>
59+
<version>3.1.4</version>
60+
</dependency>
5661
</dependencies>
5762
<build>
5863
<plugins>

framework/db/src/main/java/com/cloud/utils/db/DriverLoader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class DriverLoader {
3838
DRIVERS.put("jdbc:mysql", "com.mysql.cj.jdbc.Driver");
3939
DRIVERS.put("jdbc:postgresql", "org.postgresql.Driver");
4040
DRIVERS.put("jdbc:h2", "org.h2.Driver");
41+
DRIVERS.put("jdbc:mariadb", "org.mariadb.jdbc.Driver");
4142

4243
LOADED_DRIVERS = new ArrayList<String>();
4344
}

framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java

Lines changed: 112 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.apache.commons.dbcp2.PoolableConnection;
3939
import org.apache.commons.dbcp2.PoolableConnectionFactory;
4040
import org.apache.commons.dbcp2.PoolingDataSource;
41+
import org.apache.commons.lang3.StringUtils;
4142
import org.apache.commons.pool2.ObjectPool;
4243
import org.apache.commons.pool2.impl.GenericObjectPool;
4344
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
@@ -1001,7 +1002,7 @@ public String toString() {
10011002
private static DataSource s_ds;
10021003
private static DataSource s_usageDS;
10031004
private static DataSource s_simulatorDS;
1004-
private static boolean s_dbHAEnabled;
1005+
protected static boolean s_dbHAEnabled;
10051006

10061007
static {
10071008
// Initialize with assumed db.properties file
@@ -1032,11 +1033,6 @@ public static void initDataSource(Properties dbProps) {
10321033
final long cloudMaxWait = Long.parseLong(dbProps.getProperty("db.cloud.maxWait"));
10331034
final String cloudUsername = dbProps.getProperty("db.cloud.username");
10341035
final String cloudPassword = dbProps.getProperty("db.cloud.password");
1035-
final String cloudHost = dbProps.getProperty("db.cloud.host");
1036-
final String cloudDriver = dbProps.getProperty("db.cloud.driver");
1037-
final int cloudPort = Integer.parseInt(dbProps.getProperty("db.cloud.port"));
1038-
final String cloudDbName = dbProps.getProperty("db.cloud.name");
1039-
final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect"));
10401036
final String cloudValidationQuery = dbProps.getProperty("db.cloud.validationQuery");
10411037
final String cloudIsolationLevel = dbProps.getProperty("db.cloud.isolation.level");
10421038

@@ -1059,16 +1055,6 @@ public static void initDataSource(Properties dbProps) {
10591055
final boolean cloudTestWhileIdle = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testWhileIdle"));
10601056
final long cloudTimeBtwEvictionRunsMillis = Long.parseLong(dbProps.getProperty("db.cloud.timeBetweenEvictionRunsMillis"));
10611057
final long cloudMinEvcitableIdleTimeMillis = Long.parseLong(dbProps.getProperty("db.cloud.minEvictableIdleTimeMillis"));
1062-
final boolean cloudPoolPreparedStatements = Boolean.parseBoolean(dbProps.getProperty("db.cloud.poolPreparedStatements"));
1063-
final String url = dbProps.getProperty("db.cloud.url.params");
1064-
1065-
String cloudDbHAParams = null;
1066-
String cloudReplicas = null;
1067-
if (s_dbHAEnabled) {
1068-
cloudDbHAParams = getDBHAParams("cloud", dbProps);
1069-
cloudReplicas = dbProps.getProperty("db.cloud.replicas");
1070-
s_logger.info("The replicas configured for Cloud Data base is/are : " + cloudReplicas);
1071-
}
10721058

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

1081-
final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudReplicas : "") + ":" + cloudPort + "/" + cloudDbName +
1082-
"?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") +
1083-
(s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
1084-
DriverLoader.loadDriver(cloudDriver);
1067+
Pair<String, String> cloudUriAndDriver = getConnectionUriAndDriver(dbProps, loadBalanceStrategy, useSSL, "cloud");
1068+
1069+
DriverLoader.loadDriver(cloudUriAndDriver.second());
10851070

10861071
// Default Data Source for CloudStack
1087-
s_ds = createDataSource(cloudConnectionUri, cloudUsername, cloudPassword, cloudMaxActive, cloudMaxIdle, cloudMaxWait,
1072+
s_ds = createDataSource(cloudUriAndDriver.first(), cloudUsername, cloudPassword, cloudMaxActive, cloudMaxIdle, cloudMaxWait,
10881073
cloudTimeBtwEvictionRunsMillis, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle, cloudTestOnBorrow,
10891074
cloudValidationQuery, isolationLevel);
10901075

@@ -1094,20 +1079,13 @@ public static void initDataSource(Properties dbProps) {
10941079
final long usageMaxWait = Long.parseLong(dbProps.getProperty("db.usage.maxWait"));
10951080
final String usageUsername = dbProps.getProperty("db.usage.username");
10961081
final String usagePassword = dbProps.getProperty("db.usage.password");
1097-
final String usageHost = dbProps.getProperty("db.usage.host");
1098-
final String usageDriver = dbProps.getProperty("db.usage.driver");
1099-
final int usagePort = Integer.parseInt(dbProps.getProperty("db.usage.port"));
1100-
final String usageDbName = dbProps.getProperty("db.usage.name");
1101-
final boolean usageAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.usage.autoReconnect"));
1102-
final String usageUrl = dbProps.getProperty("db.usage.url.params");
1103-
1104-
final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.replicas") : "") + ":" + usagePort +
1105-
"/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") +
1106-
(s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
1107-
DriverLoader.loadDriver(usageDriver);
1082+
1083+
Pair<String, String> usageUriAndDriver = getConnectionUriAndDriver(dbProps, loadBalanceStrategy, useSSL, "usage");
1084+
1085+
DriverLoader.loadDriver(usageUriAndDriver.second());
11081086

11091087
// Data Source for usage server
1110-
s_usageDS = createDataSource(usageConnectionUri, usageUsername, usagePassword,
1088+
s_usageDS = createDataSource(usageUriAndDriver.first(), usageUsername, usagePassword,
11111089
usageMaxActive, usageMaxIdle, usageMaxWait, null, null, null, null,
11121090
null, isolationLevel);
11131091

@@ -1118,14 +1096,28 @@ public static void initDataSource(Properties dbProps) {
11181096
final long simulatorMaxWait = Long.parseLong(dbProps.getProperty("db.simulator.maxWait"));
11191097
final String simulatorUsername = dbProps.getProperty("db.simulator.username");
11201098
final String simulatorPassword = dbProps.getProperty("db.simulator.password");
1121-
final String simulatorHost = dbProps.getProperty("db.simulator.host");
1122-
final String simulatorDriver = dbProps.getProperty("db.simulator.driver");
1123-
final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port"));
1124-
final String simulatorDbName = dbProps.getProperty("db.simulator.name");
1125-
final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect"));
1126-
1127-
final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" +
1128-
simulatorAutoReconnect;
1099+
1100+
String simulatorDriver;
1101+
String simulatorConnectionUri;
1102+
String simulatorUri = dbProps.getProperty("db.simulator.uri");
1103+
1104+
if (StringUtils.isEmpty(simulatorUri)) {
1105+
simulatorDriver = dbProps.getProperty("db.simulator.driver");
1106+
final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port"));
1107+
final String simulatorDbName = dbProps.getProperty("db.simulator.name");
1108+
final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect"));
1109+
final String simulatorHost = dbProps.getProperty("db.simulator.host");
1110+
1111+
simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" +
1112+
simulatorAutoReconnect;
1113+
} else {
1114+
s_logger.warn("db.simulator.uri was set, ignoring the following properties on db.properties: [db.simulator.driver, db.simulator.host, db.simulator.port, "
1115+
+ "db.simulator.name, db.simulator.autoReconnect].");
1116+
String[] splitUri = simulatorUri.split(":");
1117+
simulatorDriver = String.format("%s:%s", splitUri[0], splitUri[1]);
1118+
simulatorConnectionUri = simulatorUri;
1119+
}
1120+
11291121
DriverLoader.loadDriver(simulatorDriver);
11301122

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

1138+
protected static Pair<String, String> getConnectionUriAndDriver(Properties dbProps, String loadBalanceStrategy, boolean useSSL, String schema) {
1139+
String connectionUri;
1140+
String driver;
1141+
String propertyUri = dbProps.getProperty(String.format("db.%s.uri", schema));
1142+
1143+
if (StringUtils.isEmpty(propertyUri)) {
1144+
driver = dbProps.getProperty(String.format("db.%s.driver", schema));
1145+
connectionUri = getPropertiesAndBuildConnectionUri(dbProps, loadBalanceStrategy, driver, useSSL, schema);
1146+
} else {
1147+
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,"
1148+
+ " replicas, ha.loadBalanceStrategy, ha.enable, failOverReadOnly, reconnectAtTxEnd, autoReconnectForPools, secondsBeforeRetrySource, queriesBeforeRetrySource, "
1149+
+ "initialTimeout].", schema, schema));
1150+
1151+
String[] splitUri = propertyUri.split(":");
1152+
driver = String.format("%s:%s", splitUri[0], splitUri[1]);
1153+
1154+
connectionUri = propertyUri;
1155+
}
1156+
s_logger.info(String.format("Using the following URI to connect to %s database [%s].", schema, connectionUri));
1157+
return new Pair<>(connectionUri, driver);
1158+
}
1159+
1160+
protected static String getPropertiesAndBuildConnectionUri(Properties dbProps, String loadBalanceStrategy, String driver, boolean useSSL, String schema) {
1161+
String host = dbProps.getProperty(String.format("db.%s.host", schema));
1162+
int port = Integer.parseInt(dbProps.getProperty(String.format("db.%s.port", schema)));
1163+
String dbName = dbProps.getProperty(String.format("db.%s.name", schema));
1164+
boolean autoReconnect = Boolean.parseBoolean(dbProps.getProperty(String.format("db.%s.autoReconnect", schema)));
1165+
String urlParams = dbProps.getProperty(String.format("db.%s.url.params", schema));
1166+
1167+
String replicas = null;
1168+
String dbHaParams = null;
1169+
if (s_dbHAEnabled) {
1170+
dbHaParams = getDBHAParams(schema, dbProps);
1171+
replicas = dbProps.getProperty(String.format("db.%s.replicas", schema));
1172+
s_logger.info(String.format("The replicas configured for %s data base are %s.", schema, replicas));
1173+
}
1174+
1175+
return buildConnectionUri(loadBalanceStrategy, driver, useSSL, host, replicas, port, dbName, autoReconnect, urlParams, dbHaParams);
1176+
}
1177+
1178+
protected static String buildConnectionUri(String loadBalanceStrategy, String driver, boolean useSSL, String host, String replicas, int port, String dbName, boolean autoReconnect,
1179+
String urlParams, String dbHaParams) {
1180+
1181+
StringBuilder connectionUri = new StringBuilder();
1182+
connectionUri.append(driver);
1183+
connectionUri.append("://");
1184+
connectionUri.append(host);
1185+
1186+
if (s_dbHAEnabled) {
1187+
connectionUri.append(",");
1188+
connectionUri.append(replicas);
1189+
}
1190+
1191+
connectionUri.append(":");
1192+
connectionUri.append(port);
1193+
connectionUri.append("/");
1194+
connectionUri.append(dbName);
1195+
connectionUri.append("?autoReconnect=");
1196+
connectionUri.append(autoReconnect);
1197+
1198+
if (urlParams != null) {
1199+
connectionUri.append("&");
1200+
connectionUri.append(urlParams);
1201+
}
1202+
1203+
if (useSSL) {
1204+
connectionUri.append("&useSSL=true");
1205+
}
1206+
1207+
if (s_dbHAEnabled) {
1208+
connectionUri.append("&");
1209+
connectionUri.append(dbHaParams);
1210+
connectionUri.append("&loadBalanceStrategy=");
1211+
connectionUri.append(loadBalanceStrategy);
1212+
}
1213+
1214+
return connectionUri.toString();
1215+
}
1216+
11461217
/**
11471218
* Creates a data source
11481219
*/
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.utils.db;
18+
19+
import com.cloud.utils.Pair;
20+
import org.junit.Assert;
21+
import org.junit.Before;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.mockito.junit.MockitoJUnitRunner;
25+
26+
import java.util.Properties;
27+
28+
@RunWith(MockitoJUnitRunner.class)
29+
public class TransactionLegacyTest {
30+
31+
Properties properties;
32+
33+
@Before
34+
public void setup(){
35+
properties = new Properties();
36+
properties.setProperty("db.cloud.host", "host");
37+
properties.setProperty("db.cloud.port", "5555");
38+
properties.setProperty("db.cloud.name", "name");
39+
properties.setProperty("db.cloud.autoReconnect", "false");
40+
properties.setProperty("db.cloud.url.params", "someParams");
41+
TransactionLegacy.s_dbHAEnabled = false;
42+
}
43+
@Test
44+
public void getConnectionUriAndDriverTestWithoutUri() {
45+
properties.setProperty("db.cloud.uri", "");
46+
properties.setProperty("db.cloud.driver", "driver");
47+
48+
Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");
49+
50+
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams", result.first());
51+
Assert.assertEquals("driver", result.second());
52+
}
53+
54+
@Test
55+
public void getConnectionUriAndDriverTestWithUri() {
56+
properties.setProperty("db.cloud.uri", "jdbc:driver:myFavoriteUri");
57+
58+
Pair<String, String> result = TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");
59+
60+
Assert.assertEquals("jdbc:driver:myFavoriteUri", result.first());
61+
Assert.assertEquals("jdbc:driver", result.second());
62+
}
63+
64+
@Test
65+
public void getPropertiesAndBuildConnectionUriTestDbHaDisabled() {
66+
String result = TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", "driver", true, "cloud");
67+
68+
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams&useSSL=true", result);
69+
}
70+
71+
@Test
72+
public void getPropertiesAndBuildConnectionUriTestDbHaEnabled() {
73+
TransactionLegacy.s_dbHAEnabled = true;
74+
properties.setProperty("db.cloud.failOverReadOnly", "true");
75+
properties.setProperty("db.cloud.reconnectAtTxEnd", "false");
76+
properties.setProperty("db.cloud.autoReconnectForPools", "true");
77+
properties.setProperty("db.cloud.secondsBeforeRetrySource", "25");
78+
properties.setProperty("db.cloud.queriesBeforeRetrySource", "105");
79+
properties.setProperty("db.cloud.initialTimeout", "1000");
80+
properties.setProperty("db.cloud.replicas", "second_host");
81+
82+
String result = TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", "driver", true, "cloud");
83+
84+
Assert.assertEquals("driver://host,second_host:5555/name?autoReconnect=false&someParams&useSSL=true&failOverReadOnly=true&reconnectAtTxEnd=false&autoReconnectFor"
85+
+ "Pools=true&secondsBeforeRetrySource=25&queriesBeforeRetrySource=105&initialTimeout=1000&loadBalanceStrategy=strat", result);
86+
}
87+
88+
@Test
89+
public void buildConnectionUriTestDbHaDisabled() {
90+
String result = TransactionLegacy.buildConnectionUri(null, "driver", false, "host", null, 5555, "cloud", false, null, null);
91+
92+
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false", result);
93+
}
94+
95+
@Test
96+
public void buildConnectionUriTestDbHaEnabled() {
97+
TransactionLegacy.s_dbHAEnabled = true;
98+
99+
String result = TransactionLegacy.buildConnectionUri("strat", "driver", false, "host", "second_host", 5555, "cloud", false, null, "dbHaParams");
100+
101+
Assert.assertEquals("driver://host,second_host:5555/cloud?autoReconnect=false&dbHaParams&loadBalanceStrategy=strat", result);
102+
}
103+
104+
@Test
105+
public void buildConnectionUriTestUrlParamsNotNull() {
106+
String result = TransactionLegacy.buildConnectionUri(null, "driver", false, "host", null, 5555, "cloud", false, "urlParams", null);
107+
108+
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&urlParams", result);
109+
}
110+
111+
@Test
112+
public void buildConnectionUriTestUseSslTrue() {
113+
String result = TransactionLegacy.buildConnectionUri(null, "driver", true, "host", null, 5555, "cloud", false, null, null);
114+
115+
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&useSSL=true", result);
116+
}
117+
}

0 commit comments

Comments
 (0)