Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add all additional Cloud SQL Java Connector parameters - add one test #3313

Closed
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
7 changes: 7 additions & 0 deletions docs/src/main/asciidoc/sql.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ Used to authenticate and authorize new connections to a Google Cloud SQL instanc
Used to authenticate and authorize new connections to a Google Cloud SQL instance. | No
| Default credentials provided by the Spring Framework on Google Cloud Core Starter
| `spring.cloud.gcp.sql.enableIamAuth` | Specifies whether to enable IAM database authentication (PostgreSQL only). | No | `False`
| `spring.cloud.gcp.sql.refreshStrategy` | The strategy used to refresh the Google Cloud SQL authentication tokens. Valid values: `background` - refresh credentials using a background thread, `lazy` - refresh credentials during connection attempts. | No | "background"
| `spring.cloud.gcp.sql.targetPrincipal` | The service account to impersonate when connecting to the database and database admin API. | No | (empty)
| `spring.cloud.gcp.sql.delegates` | A comma-separated list of service accounts delegates. | No | (empty)
| `spring.cloud.gcp.sql.universeDomain` | A universe domain for the TPC environment. | No | "googleapis.com"
| `spring.cloud.gcp.sql.adminRootUrl` | An alternate root url for the Cloud SQL admin API. | No | (empty)
| `spring.cloud.gcp.sql.adminServicePath` | An alternate path to the SQL Admin API endpoint. | No | (empty)
| `spring.cloud.gcp.sql.adminQuotaProject` | A project ID for quota and billing. | No | (empty)
|===

=== Troubleshooting tips
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

package com.google.cloud.spring.autoconfigure.sql;

import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -54,12 +58,49 @@ public String getJdbcUrl() {
this.properties.getDatabaseName(),
this.properties.getInstanceConnectionName());

// Build additional JDBC url parameters from the configuration.
Map<String, String> urlParams = new LinkedHashMap<>();
if (StringUtils.hasText(properties.getIpTypes())) {
jdbcUrl += "&ipTypes=" + properties.getIpTypes();
urlParams.put("ipTypes", properties.getIpTypes());
}

if (properties.isEnableIamAuth()) {
jdbcUrl += "&enableIamAuth=true&sslmode=disable";
urlParams.put("enableIamAuth", "true");
urlParams.put("sslmode", "disable");
}
if (StringUtils.hasText(properties.getTargetPrincipal())) {
urlParams.put("cloudSqlTargetPrincipal", properties.getTargetPrincipal());
}
if (StringUtils.hasText(properties.getDelegates())) {
urlParams.put("cloudSqlDelegates", properties.getDelegates());
}
if (StringUtils.hasText(properties.getAdminRootUrl())) {
urlParams.put("cloudSqlAdminRootUrl", properties.getAdminRootUrl());
}
if (StringUtils.hasText(properties.getAdminServicePath())) {
urlParams.put("cloudSqlAdminServicePath", properties.getAdminServicePath());
}
if (StringUtils.hasText(properties.getAdminQuotaProject())) {
urlParams.put("cloudSqlAdminQuotaProject", properties.getAdminQuotaProject());
}
if (StringUtils.hasText(properties.getUniverseDomain())) {
urlParams.put("cloudSqlUniverseDomain", properties.getUniverseDomain());
}
if (StringUtils.hasText(properties.getRefreshStrategy())) {
urlParams.put("cloudSqlRefreshStrategy", properties.getRefreshStrategy());
}

// Convert map to a string of url parameters
String urlParamsString =
urlParams.entrySet().stream()
.map(
entry ->
URLEncoder.encode(entry.getKey()) + "=" + URLEncoder.encode(entry.getValue()))
.collect(Collectors.joining("&"));

// Append url parameters to the JDBC URL.
if (StringUtils.hasText(urlParamsString)) {
jdbcUrl = jdbcUrl + "&" + urlParamsString;
}

return jdbcUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,44 @@ public class GcpCloudSqlProperties {

/** Specifies whether to enable IAM database authentication (PostgreSQL only). */
private boolean enableIamAuth;
/**
* The target principal to use for service account impersonation. Corresponds to
* Cloud SQL Java Connector JDBC property cloudSqlTargetPrincipal
*/
private String targetPrincipal;

/**
* The chain of delegated service accounts to use for service account impersonation.
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlDelegates
*/
private String delegates;

/**
* The alternate admin root url for the Cloud SQL Admin API.
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlAdminRootUrl.
*/
private String adminRootUrl;
/**
* The alternate service path for the Cloud SQL Admin API
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlAdminServicePath.
*/
private String adminServicePath;
/**
* The quota project to use for API requests.
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlAdminQuotaProject
*/
private String adminQuotaProject;
/**
* The universe domain to use for API requests
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlUniverseDomain
*/
private String universeDomain;
/**
* The refresh strategy to use for API requests
* Corresponds to Cloud SQL Java Connector JDBC property cloudSqlRefreshStrategy
*/
private String refreshStrategy;


public String getDatabaseName() {
return this.databaseName;
Expand Down Expand Up @@ -76,4 +114,60 @@ public boolean isEnableIamAuth() {
public void setEnableIamAuth(boolean enableIamAuth) {
this.enableIamAuth = enableIamAuth;
}

public String getTargetPrincipal() {
return targetPrincipal;
}

public void setTargetPrincipal(String targetPrincipal) {
this.targetPrincipal = targetPrincipal;
}

public String getDelegates() {
return delegates;
}

public void setDelegates(String delegates) {
this.delegates = delegates;
}

public String getAdminRootUrl() {
return adminRootUrl;
}

public void setAdminRootUrl(String adminRootUrl) {
this.adminRootUrl = adminRootUrl;
}

public String getAdminServicePath() {
return adminServicePath;
}

public void setAdminServicePath(String adminServicePath) {
this.adminServicePath = adminServicePath;
}

public String getAdminQuotaProject() {
return adminQuotaProject;
}

public void setAdminQuotaProject(String adminQuotaProject) {
this.adminQuotaProject = adminQuotaProject;
}

public String getUniverseDomain() {
return universeDomain;
}

public void setUniverseDomain(String universeDomain) {
this.universeDomain = universeDomain;
}

public String getRefreshStrategy() {
return refreshStrategy;
}

public void setRefreshStrategy(String refreshStrategy) {
this.refreshStrategy = refreshStrategy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.api.gax.core.NoCredentialsProvider;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfigurations;
Expand Down Expand Up @@ -122,6 +123,53 @@ void testCloudSqlDataSourceWithIgnoredProvidedUrl() {
});
}

@Test
void testCloudSqlSpringDatasourceWithAllOptions() {
this.contextRunner
.withPropertyValues(
"spring.cloud.gcp.sql.admin-quota-project=someAdminQuotaProjectValue",
"spring.cloud.gcp.sql.admin-root-url=someAdminRootUrlValue",
"spring.cloud.gcp.sql.admin-service-path=someAdminServicePathValue",
"spring.cloud.gcp.sql.database-name=test-database",
"spring.cloud.gcp.sql.delegates=delegate1,delegate2",
"spring.cloud.gcp.sql.enable-iam-auth=true",
"spring.cloud.gcp.sql.instance-connection-name=tubular-bells:singapore:test-instance",
"spring.cloud.gcp.sql.ip-types=PRIVATE",
"spring.cloud.gcp.sql.refresh-strategy=lazy",
"spring.cloud.gcp.sql.target-principal=target-principal",
"spring.cloud.gcp.sql.universe-domain=someUniverseDomainValue",
"spring.datasource.username=foo",
"spring.datasource.password=bar")
.run(
context -> {
HikariDataSource dataSource = (HikariDataSource) context.getBean(DataSource.class);
assertThat(dataSource)
.returns("com.mysql.cj.jdbc.Driver", HikariDataSource::getDriverClassName)
.returns("foo", HikariDataSource::getUsername)
.returns("bar", HikariDataSource::getPassword)
.extracting(HikariDataSource::getJdbcUrl)
.asInstanceOf(InstanceOfAssertFactories.STRING)
.startsWith("jdbc:mysql://google/test-database?"
+ "socketFactory=com.google.cloud.sql.mysql.SocketFactory")
.satisfies(
jdbcUrl -> assertThat(jdbcUrl.substring(jdbcUrl.indexOf('&') + 1).split("&"))
.containsExactlyInAnyOrder(
"cloudSqlAdminQuotaProject=someAdminQuotaProjectValue",
"cloudSqlAdminRootUrl=someAdminRootUrlValue",
"cloudSqlAdminServicePath=someAdminServicePathValue",
"cloudSqlDelegates=delegate1%2Cdelegate2",
"cloudSqlInstance=tubular-bells:singapore:test-instance",
"cloudSqlRefreshStrategy=lazy",
"cloudSqlTargetPrincipal=target-principal",
"cloudSqlUniverseDomain=someUniverseDomainValue",
"enableIamAuth=true",
"ipTypes=PRIVATE",
"sslmode=disable"));
assertThat(getSpringDatasourceDriverClassName(context))
.matches("com.mysql.cj.jdbc.Driver");
});
}

@Test
void testCloudSqlAppEngineDataSourceDefaultUserNameMySqlTest() {
this.contextRunner
Expand Down
Loading