Search code examples
spring-bootgoogle-cloud-platformgoogle-cloud-sql

Connection issue with Spring boot 3.2 and Google Cloud Mysql


I'm working on transitioning to Google Cloud MySQL. We are currently connected to our own managed mysql server and it is working fine. We are using four separate MySql connections so the setup is not straightforward. Here are my changes specifically for Google Cloud MySQL

pom.xml:

<dependencies>
    ....
     <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>spring-cloud-gcp-starter-sql-mysql</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.cloud.sql</groupId>
        <artifactId>mysql-socket-factory-connector-j-8</artifactId>
    </dependency>
 .....
  </dependencies>
<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>com.google.cloud</groupId>
           <artifactId>spring-cloud-gcp-dependencies</artifactId>
           <version>5.0.0</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
   </dependencies>
</dependencyManagement>

application.properties:

    spring.cloud.gcp.project-id=PROJECT_ID
    spring.cloud.gcp.credentials.location=classpath:CREDENTIAL_FILE_LOCATION
    spring.cloud.gcp.sql.enabled=false
    
    userdb.read.datasource.url=jdbc:mysql:///DB_NAME?cloudSqlInstance=INSTANCE_NAME&socketFactory=com.google.cloud.sql.mysql.SocketFactory
    userdb.read.datasource.username=USERNAME
    userdb.read.datasource.password=PASSWORD   
    userdb.read.datasource.tomcat.max-wait=5000
    userdb.read.datasource.tomcat.max-active=2
    userdb.read.datasource.tomcat.test-on-borrow=true
    # THREE MORE SIMILAR CONNECTION SETTINGS

I have configured the credentials in addition to the connection settings. The rest of my code is as is, what do you think I'm doing wrong? Below is the error I'm getting:

: HikariPool-1 - Exception during pool initialization.

java.sql.SQLNonTransientConnectionException: Could not create connection to database server.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:111) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:98) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:90) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:64) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:995) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:809) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:440) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:239) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:188) ~[mysql-connector-j-8.1.0.jar:8.1.0

Caused by: java.lang.RuntimeException: Unable to obtain credentials to communicate with the Cloud SQL API
    at com.google.cloud.sql.core.ApplicationDefaultCredentialFactory.getCredentials(ApplicationDefaultCredentialFactory.java:42) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.ApplicationDefaultCredentialFactory.create(ApplicationDefaultCredentialFactory.java:32) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.CoreSocketFactory.apiFetcher(CoreSocketFactory.java:417) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.CoreSocketFactory.lambda$getCloudSqlInstance$0(CoreSocketFactory.java:396) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) ~[?:?]

Caused by: java.io.IOException: Your default credentials were not found. To set up Application Default Credentials for your environment, see https://cloud.google.com/docs/authentication/external/set-up-adc.
    at com.google.auth.oauth2.DefaultCredentialsProvider.getDefaultCredentials(DefaultCredentialsProvider.java:127) ~[google-auth-library-oauth2-http-1.20.0.jar:1.20.0]
    at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:129) ~[google-auth-library-oauth2-http-1.20.0.jar:1.20.0]
    at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:101) ~[google-auth-library-oauth2-http-1.20.0.jar:1.20.0]
    at com.google.cloud.sql.core.ApplicationDefaultCredentialFactory.getCredentials(ApplicationDefaultCredentialFactory.java:40) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.ApplicationDefaultCredentialFactory.create(ApplicationDefaultCredentialFactory.java:32) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.CoreSocketFactory.apiFetcher(CoreSocketFactory.java:417) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at com.google.cloud.sql.core.CoreSocketFactory.lambda$getCloudSqlInstance$0(CoreSocketFactory.java:396) ~[jdbc-socket-factory-core-1.14.1.jar:1.14.1]
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) ~[?:?]

Solution

  • After spending many hours, the solution turns out to be very simple. Adding it here in case some folks run into the similar issue. I was using spring.cloud.gcp.credentials.location property to set the credentials but the google cloud sql connection factory library doesn't care about that. We need to use gcloud auth application-default login command to create and credential and gcloud command saves it in your folder: /Users/your_user_name/.config/gcloud/application_default_credentials.json . The spring boot app automatically picks it up, not need to set it using with spring.cloud.gcp.credentials.location file.