├── .ci └── cloudbuild.yaml ├── .envrc.example ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── documentation_issue.yaml │ ├── feature_request.yaml │ └── question.yaml ├── auto-label.yaml ├── blunderbuss.yml ├── dependabot.yml ├── flakybot.yaml ├── generated-files-bot.yml ├── header-checker-lint.yml ├── labels.yml ├── release-please.yml ├── release-trigger.yml ├── renovate.json5 ├── scripts │ ├── run_tests.sh │ └── run_tests_graalvm_native.sh ├── sync-repo-settings.yaml ├── trusted-contribution.yml └── workflows │ ├── codeql.yml │ ├── labels.yaml │ ├── lint.yaml │ ├── scorecard.yml │ └── tests.yml ├── .gitignore ├── .kokoro ├── build.bat ├── build.sh ├── check_coverage.sh ├── coerce_logs.sh ├── common.cfg ├── common.sh ├── dependencies.sh ├── populate-secrets.sh ├── release │ ├── bump_snapshot.cfg │ ├── common.cfg │ ├── common.sh │ ├── drop.cfg │ ├── drop.sh │ ├── promote.cfg │ ├── promote.sh │ ├── publish_javadoc.cfg │ ├── publish_javadoc.sh │ ├── publish_javadoc11.cfg │ ├── publish_javadoc11.sh │ ├── snapshot.cfg │ ├── snapshot.sh │ ├── stage.cfg │ └── stage.sh ├── requirements.in ├── requirements.txt └── trampoline.sh ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── .release ├── generate_sha.sh ├── snapshot.sh ├── update_versions.sh └── upload_uberjars.yaml ├── .repo-metadata.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── checkstyle-suppressions.xml ├── core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ ├── AuthType.java │ │ │ ├── ConnectorConfig.java │ │ │ ├── ConnectorRegistry.java │ │ │ ├── CredentialFactory.java │ │ │ ├── IpType.java │ │ │ ├── RefreshStrategy.java │ │ │ ├── core │ │ │ ├── AccessTokenSupplier.java │ │ │ ├── ApiClientRetryingCallable.java │ │ │ ├── ApplicationDefaultCredentialFactory.java │ │ │ ├── AsyncRateLimiter.java │ │ │ ├── CloudSqlInstanceName.java │ │ │ ├── ConnectionConfig.java │ │ │ ├── ConnectionInfo.java │ │ │ ├── ConnectionInfoCache.java │ │ │ ├── ConnectionInfoRepository.java │ │ │ ├── ConnectionInfoRepositoryFactory.java │ │ │ ├── ConnectionMetadata.java │ │ │ ├── Connector.java │ │ │ ├── ConscryptWorkaroundDelegatingTrustManger.java │ │ │ ├── ConstantCredentialFactory.java │ │ │ ├── CoreSocketFactory.java │ │ │ ├── CredentialFactoryProvider.java │ │ │ ├── DefaultAccessTokenSupplier.java │ │ │ ├── DefaultConnectionInfoRepository.java │ │ │ ├── DefaultConnectionInfoRepositoryFactory.java │ │ │ ├── DnsInstanceConnectionNameResolver.java │ │ │ ├── DnsResolver.java │ │ │ ├── FileCredentialFactory.java │ │ │ ├── InstanceCheckingTrustManagerFactory.java │ │ │ ├── InstanceCheckingTrustManagerFactorySpi.java │ │ │ ├── InstanceCheckingTrustManger.java │ │ │ ├── InstanceConnectionNameResolver.java │ │ │ ├── InstanceMetadata.java │ │ │ ├── InternalConnectorRegistry.java │ │ │ ├── JndiDnsResolver.java │ │ │ ├── LazyRefreshConnectionInfoCache.java │ │ │ ├── LazyRefreshStrategy.java │ │ │ ├── MonitoredCache.java │ │ │ ├── RefreshAheadConnectionInfoCache.java │ │ │ ├── RefreshAheadStrategy.java │ │ │ ├── RefreshCalculator.java │ │ │ ├── RefreshStrategy.java │ │ │ ├── RetryingCallable.java │ │ │ ├── ServiceAccountImpersonatingCredentialFactory.java │ │ │ ├── SslData.java │ │ │ ├── SupplierCredentialFactory.java │ │ │ ├── TerminalException.java │ │ │ └── package-info.java │ │ │ ├── nativeimage │ │ │ └── CloudSqlFeature.java │ │ │ └── package-info.java │ └── resources │ │ ├── META-INF │ │ └── native-image │ │ │ └── com.google.cloud.sql │ │ │ └── cloud-sql-jdbc-socket-factory-parent │ │ │ ├── jni-unix-socket-config.json │ │ │ ├── native-image.properties │ │ │ ├── proxy-config.json │ │ │ └── resource-config.json │ │ └── com.google.cloud.sql │ │ └── project.properties │ └── test │ ├── java │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ ├── ConnectorConfigTest.java │ │ ├── CredentialFactoryTest.java │ │ └── core │ │ ├── ApiClientRetryingCallableTest.java │ │ ├── AsyncRateLimiterTest.java │ │ ├── BadConnectionFactory.java │ │ ├── CloudSqlCoreTestingBase.java │ │ ├── CloudSqlInstanceNameTest.java │ │ ├── ConnectionConfigTest.java │ │ ├── ConnectorTest.java │ │ ├── ConstantCredentialsFactoryTest.java │ │ ├── CredentialFactoryProviderTest.java │ │ ├── DefaultAccessTokenSupplierTest.java │ │ ├── DefaultConnectionInfoRepositoryIntegrationTests.java │ │ ├── DefaultConnectionInfoRepositoryTest.java │ │ ├── FakeSslServer.java │ │ ├── FakeUnixSocketServer.java │ │ ├── FileCredentialFactoryTest.java │ │ ├── InstanceCheckingTrustManagerFactoryTest.java │ │ ├── InternalConnectorRegistryTest.java │ │ ├── LazyRefreshConnectionInfoCacheTest.java │ │ ├── LazyRefreshStrategyTest.java │ │ ├── MockAdminApi.java │ │ ├── MonitoredCacheTest.java │ │ ├── PauseCondition.java │ │ ├── RefreshAheadConnectionInfoCacheConcurrencyTest.java │ │ ├── RefreshAheadConnectionInfoCacheTest.java │ │ ├── RefreshAheadStrategyTest.java │ │ ├── RefreshCalculatorTest.java │ │ ├── RetryingCallableTest.java │ │ ├── ServiceAccountImpersonatingCredentialFactoryIntegrationTests.java │ │ ├── StubConnectionInfoRepository.java │ │ ├── StubConnectionInfoRepositoryFactory.java │ │ ├── StubCredentialFactory.java │ │ ├── SupplierCredentialFactoryTest.java │ │ ├── TestCertificateGenerator.java │ │ ├── TestDataSupplier.java │ │ └── TestKeys.java │ └── resources │ ├── logback.xml │ └── sample-credentials.json ├── docs ├── configuration.md ├── jdbc.md └── r2dbc.md ├── java.header ├── jdbc ├── mariadb │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── mariadb │ │ │ └── SocketFactory.java │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── mariadb │ │ ├── JdbcMariaDBIamAuthIntegrationTests.java │ │ └── JdbcMariaDBIntegrationTests.java ├── mysql-j-8 │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── mysql │ │ │ └── SocketFactory.java │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── mysql │ │ ├── JdbcMysqlJ8DomainNameIntegrationTests.java │ │ ├── JdbcMysqlJ8IAMServiceAccountImpersonationIntegrationTests.java │ │ ├── JdbcMysqlJ8IamAuthIntegrationTests.java │ │ ├── JdbcMysqlJ8IntegrationTests.java │ │ ├── JdbcMysqlJ8McpIamAuthIntegrationTests.java │ │ ├── JdbcMysqlJ8McpIntegrationTests.java │ │ └── JdbcMysqlJ8ServiceAccountImpersonationIntegrationTests.java ├── postgres │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── postgres │ │ │ └── SocketFactory.java │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── postgres │ │ │ ├── JdbcPostgresCasIntegrationTests.java │ │ │ ├── JdbcPostgresCustomSanIntegrationTests.java │ │ │ ├── JdbcPostgresCustomerCasIntegrationTests.java │ │ │ ├── JdbcPostgresDomainNameIntegrationTests.java │ │ │ ├── JdbcPostgresIamAuthIntegrationTests.java │ │ │ ├── JdbcPostgresIntegrationTests.java │ │ │ ├── JdbcPostgresLazyRefreshIntegrationTests.java │ │ │ ├── JdbcPostgresMcpIntegrationTests.java │ │ │ ├── JdbcPostgresNamedConnectorIntegrationTests.java │ │ │ ├── JdbcPostgresQuotaProjecImpersonationtIntegrationTests.java │ │ │ ├── JdbcPostgresQuotaProjectIAMAuthIntegrationTests.java │ │ │ └── JdbcPostgresServiceAccountImpersonationIntegrationTests.java │ │ └── resources │ │ └── conscrypt-security.properties └── sqlserver │ ├── pom.xml │ └── src │ ├── main │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── sqlserver │ │ └── SocketFactory.java │ └── test │ └── java │ └── com │ └── google │ └── cloud │ └── sql │ └── sqlserver │ ├── JdbcSqlServerIntegrationTests.java │ └── JdbcSqlServerUnitTests.java ├── license-checks.xml ├── mvnw ├── mvnw.cmd ├── owlbot.py ├── pom.xml ├── r2dbc ├── core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── core │ │ │ ├── CloudSqlConnection.java │ │ │ ├── CloudSqlConnectionFactory.java │ │ │ └── GcpConnectionFactoryProvider.java │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── core │ │ │ ├── GcpConnectionFactoryProviderTest.java │ │ │ └── R2dbcTestKeys.java │ │ └── resources │ │ └── mockito-extensions │ │ └── org.mockito.plugins.MockMaker ├── mariadb │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── sql │ │ │ │ └── core │ │ │ │ └── GcpConnectionFactoryProviderMariadb.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── io.r2dbc.spi.ConnectionFactoryProvider │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── core │ │ ├── R2dbcMariadbIamAuthIntegrationTests.java │ │ └── R2dbcMariadbIntegrationTests.java ├── mysql │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── sql │ │ │ │ └── core │ │ │ │ └── GcpConnectionFactoryProviderMysql.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── io.r2dbc.spi.ConnectionFactoryProvider │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── core │ │ ├── R2dbcMysqlIamAuthIntegrationTests.java │ │ └── R2dbcMysqlIntegrationTests.java ├── postgres │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── sql │ │ │ │ └── core │ │ │ │ └── GcpConnectionFactoryProviderPostgres.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── io.r2dbc.spi.ConnectionFactoryProvider │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── sql │ │ └── core │ │ ├── R2dbcPostgresIamAuthIntegrationTests.java │ │ ├── R2dbcPostgresIntegrationTests.java │ │ └── R2dbcPostgresPoolRemoteValidationIntegrationTests.java └── sqlserver │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── sql │ │ │ └── core │ │ │ └── GcpConnectionFactoryProviderMssql.java │ └── resources │ │ └── META-INF │ │ └── services │ │ └── io.r2dbc.spi.ConnectionFactoryProvider │ └── test │ └── java │ └── com │ └── google │ └── cloud │ └── sql │ └── core │ └── R2dbcSqlserverIntegrationTests.java └── versions.txt /.envrc.example: -------------------------------------------------------------------------------- 1 | export GOOGLE_CLOUD_PROJECT="project-name" 2 | 3 | export MYSQL_CONNECTION_NAME="project:region:instance" 4 | export MYSQL_USER="mysql-user" 5 | export MYSQL_PASS="mysql-password" 6 | export MYSQL_DB="mysql-db-name" 7 | 8 | export POSTGRES_CONNECTION_NAME="project:region:instance" 9 | export POSTGRES_USER="postgres-user" 10 | export POSTGRES_PASS="postgres-password" 11 | export POSTGRES_DB="postgres-db-name" 12 | 13 | export SQLSERVER_CONNECTION_NAME="project:region:instance" 14 | export SQLSERVER_USER="sqlserver-user" 15 | export SQLSERVER_PASS="sqlserver-password" 16 | export SQLSERVER_DB="sqlserver-db-name" -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @GoogleCloudPlatform/cloud-sql-connectors 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: 🐞 Bug Report 16 | description: File a bug report 17 | title: "Brief summary of what bug or error was observed" 18 | labels: ["type: bug"] 19 | body: 20 | - type: markdown 21 | attributes: 22 | value: | 23 | Thanks for stopping by to let us know something could be better! 24 | 25 | Please run down the following list and make sure you've tried the usual "quick fixes": 26 | - Search the [current open issues](https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/issues) 27 | - Check for answers on [StackOverflow](https://stackoverflow.com/questions/tagged/google-cloud-sql) (under the 'google-cloud-sql' tag) 28 | 29 | If you are still having issues, please include as much information as possible below! :smile: 30 | - type: textarea 31 | id: bug-description 32 | attributes: 33 | label: Bug Description 34 | description: "Please enter a detailed description of the bug, and any information about what behavior you noticed and why it is defective or unintentional." 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: example-code 39 | attributes: 40 | label: Example code (or command) 41 | description: "Please paste any useful application code related to the bug below. (if your code is in a public repo, feel free to paste a link!)" 42 | render: Java 43 | - type: textarea 44 | id: stacktrace 45 | attributes: 46 | label: Stacktrace 47 | description: "Paste any relevant stacktrace or error you are running into here. Be sure to filter sensitive information!" 48 | render: bash 49 | - type: textarea 50 | id: repro 51 | attributes: 52 | label: Steps to reproduce? 53 | description: "How do you trigger this bug? Please walk us through it step by step." 54 | value: | 55 | 1. ? 56 | 2. ? 57 | 3. ? 58 | ... 59 | validations: 60 | required: true 61 | - type: textarea 62 | id: environment 63 | attributes: 64 | label: Environment 65 | description: "Let us know some details about the environment in which you are seeing the bug!" 66 | value: | 67 | 1. OS type and version: 68 | 2. Java SDK version: 69 | 3. Cloud SQL Java Socket Factory version: 70 | validations: 71 | required: true 72 | - type: textarea 73 | id: additional-details 74 | attributes: 75 | label: Additional Details 76 | description: "Any other information you want us to know?" 77 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation_issue.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: 📝 Documentation Issue 16 | description: Report wrong or missing information with the documentation in this repo. 17 | title: "Brief summary of what is missing or incorrect" 18 | labels: ["type: docs"] 19 | body: 20 | - type: markdown 21 | attributes: 22 | value: | 23 | Thanks for stopping by to let us know something could be better! :smile: 24 | 25 | Please explain below how we can improve our documentation. 26 | - type: textarea 27 | id: description 28 | attributes: 29 | label: Description 30 | description: "Provide a short description of what is missing or incorrect, as well as a link to the specific location of the issue." 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: potential-solution 35 | attributes: 36 | label: Potential Solution 37 | description: "What would you prefer the documentation say? Why would this information be more accurate or helpful?" 38 | - type: textarea 39 | id: additional-details 40 | attributes: 41 | label: Additional Details 42 | description: "Please reference any other relevant issues, PRs, descriptions, or screenshots here." 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: ✨ Feature Request 16 | description: Suggest an idea for new or improved behavior. 17 | title: "Brief summary of the proposed feature" 18 | labels: ["type: feature request"] 19 | body: 20 | - type: markdown 21 | attributes: 22 | value: | 23 | Thanks for stopping by to let us know something could be better! 24 | 25 | Please run down the following list before proceeding with your feature request: 26 | - Search the [current open issues](https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/issues) to prevent creating a duplicate. 27 | 28 | Please include as much information as possible below! :smile: 29 | - type: textarea 30 | id: feature-description 31 | attributes: 32 | label: Feature Description 33 | description: "A clear and concise description of what feature you would like to see, and why it would be useful to have added." 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: sample-code 38 | attributes: 39 | label: Sample code 40 | description: "If you already have an idea of what the implementation of this feature would like in code please provide it. (pseudo code is okay!)" 41 | render: Java 42 | - type: textarea 43 | id: alternatives-considered 44 | attributes: 45 | label: Alternatives Considered 46 | description: "Are there any workaround or third party tools to replicate this behavior? Why would adding this feature be preferred over them?" 47 | - type: textarea 48 | id: additional-details 49 | attributes: 50 | label: Additional Details 51 | description: "Any additional information we should know? Please reference it here (issues, PRs, descriptions, or screenshots)" 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: 💬 Question 16 | description: Questions on how something works or the best way to do something? 17 | title: "Brief summary of your question" 18 | labels: ["type: question"] 19 | body: 20 | - type: markdown 21 | attributes: 22 | value: | 23 | Thanks for stopping by to let us know something could be better! 24 | 25 | Please run down the following list and make sure you've tried the usual "quick fixes": 26 | - Search the [current open issues](https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/issues) for a similar question 27 | - Check for answers on [StackOverflow](https://stackoverflow.com/questions/tagged/google-cloud-sql) (under the 'google-cloud-sql' tag) 28 | 29 | If you still have a question, please include as much information as possible below! :smile: 30 | - type: textarea 31 | id: question 32 | attributes: 33 | label: Question 34 | description: "What's your question? Please provide as much relevant information as possible to reduce turnaround time." 35 | placeholder: "Example: How do I connect using this connector with Private IP from Cloud Run?" 36 | validations: 37 | required: true 38 | - type: textarea 39 | id: code 40 | attributes: 41 | label: Code 42 | description: "Please paste any useful application code that might be relevant to your question. (if your code is in a public repo, feel free to paste a link!)" 43 | render: Java 44 | - type: textarea 45 | id: additional-details 46 | attributes: 47 | label: Additional Details 48 | description: "Any other information you want us to know that might be helpful in answering your question? (link issues, PRs, descriptions, or screenshots)" 49 | -------------------------------------------------------------------------------- /.github/auto-label.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | requestsize: 15 | enabled: true 16 | -------------------------------------------------------------------------------- /.github/blunderbuss.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | assign_issues: 16 | - hessjcg 17 | - kgala2 18 | 19 | assign_prs: 20 | - hessjcg 21 | - kgala2 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | version: 2 16 | updates: 17 | - package-ecosystem: "maven" 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | # Disable version updates for Maven dependencies 22 | open-pull-requests-limit: 0 23 | - package-ecosystem: "pip" 24 | directory: "/" 25 | schedule: 26 | interval: "daily" 27 | # Disable version updates for pip dependencies 28 | open-pull-requests-limit: 0 29 | -------------------------------------------------------------------------------- /.github/flakybot.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | issuePriority: p2 16 | -------------------------------------------------------------------------------- /.github/generated-files-bot.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | externalManifests: 16 | - type: json 17 | file: 'synth.metadata' 18 | jsonpath: '$.generatedFiles[*]' 19 | - type: json 20 | file: '.github/readme/synth.metadata/synth.metadata' 21 | jsonpath: '$.generatedFiles[*]' 22 | ignoreAuthors: 23 | - 'renovate-bot' 24 | - 'yoshi-automation' 25 | - 'release-please[bot]' 26 | - 'gcf-owl-bot[bot]' 27 | -------------------------------------------------------------------------------- /.github/header-checker-lint.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | allowedCopyrightHolders: 16 | - 'Google LLC' 17 | allowedLicenses: 18 | - 'Apache-2.0' 19 | sourceFileExtensions: 20 | - 'java' 21 | - 'yaml' 22 | - 'yml' 23 | - 'xml' 24 | -------------------------------------------------------------------------------- /.github/release-please.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | bumpMinorPreMajor: true 16 | handleGHRelease: true 17 | releaseType: java-yoshi 18 | extraFiles: 19 | - docs/jdbc.md 20 | - docs/r2dbc.md 21 | -------------------------------------------------------------------------------- /.github/release-trigger.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | enabled: true 16 | multiScmName: cloud-sql-jdbc-socket-factory 17 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:recommended", 4 | "helpers:pinGitHubActionDigests", 5 | ":separateMajorReleases", 6 | ":combinePatchMinorReleases", 7 | ":ignoreUnstable", 8 | ":prImmediately", 9 | ":updateNotScheduled", 10 | ":automergeDisabled", 11 | ":ignoreModulesAndTests", 12 | ":maintainLockFilesDisabled" 13 | ], 14 | "commitMessagePrefix": "deps: ", 15 | "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], 16 | "rebaseWhen": "behind-base-branch", 17 | "dependencyDashboard": true, 18 | "dependencyDashboardLabels": ["type: process"], 19 | "semanticCommits": "disabled", 20 | "ignorePaths": [".kokoro/requirements.txt"], 21 | "ignoreDeps": [ 22 | "com.coveo:fmt-maven-plugin", 23 | "com.zaxxer:HikariCP", 24 | "com.google.googlejavaformat:google-java-format", 25 | "com.google.errorprone:error_prone_core", 26 | "ch.qos.logback:logback-classic" 27 | ], 28 | "packageRules": [ 29 | {"matchPackagePatterns": ["^com.google.guava:"], "versioning": "docker"}, 30 | { 31 | "matchPackagePatterns": [ 32 | "^org.apache.maven", 33 | "^org.jacoco:", 34 | "^org.codehaus.mojo:", 35 | "^org.sonatype.plugins:", 36 | "^com.coveo:", 37 | "^com.google.cloud:google-cloud-shared-config" 38 | ], 39 | "semanticCommitType": "build", 40 | "semanticCommitScope": "deps" 41 | }, 42 | { 43 | "matchPackagePatterns": ["^com.google.cloud:google-cloud-"], 44 | "ignoreUnstable": false 45 | }, 46 | {"matchPackageNames": ["mysql:mysql-connector-java"], "enabled": false}, 47 | { 48 | "matchPackageNames": ["com.google.guava:guava"], 49 | "allowedVersions": "/.+-android/" 50 | }, 51 | { 52 | "matchPackageNames": ["com.microsoft.sqlserver:mssql-jdbc"], 53 | "allowedVersions": "/.+jre8.?/" 54 | }, 55 | { 56 | "matchPackageNames": ["com.google.apis:google-api-services-sqladmin"], 57 | "allowedVersions": "/v1beta4-.*/" 58 | }, 59 | { 60 | "groupName": "Non-major dependencies", 61 | "matchManagers": ["maven"], 62 | "matchUpdateTypes": ["minor", "patch"] 63 | }, 64 | { 65 | "matchManagers": ["github-actions"], 66 | "groupName": "dependencies for github", 67 | "commitMessagePrefix": "chore(deps):" 68 | } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /.github/scripts/run_tests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2020 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # `-e` enables the script to automatically fail when a command fails 17 | set -ex 18 | 19 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 20 | PROJECT_DIR=$( dirname "$SCRIPT_DIR" ) 21 | 22 | if [[ $OSTYPE == 'darwin'* ]]; then 23 | # Add alias for 127.0.0.2 to be used as a loopback address 24 | # https://superuser.com/questions/458875/how-do-you-get-loopback-addresses-other-than-127-0-0-1-to-work-on-os-x 25 | sudo ifconfig lo0 alias 127.0.0.2 up 26 | sudo ifconfig lo0 alias 127.0.0.3 up 27 | fi 28 | 29 | echo -e "******************** Running tests... ********************\n" 30 | echo "Running tests using Java:" 31 | java -version 32 | 33 | # Use the mvn command 34 | if which mvn ; then 35 | mvn_cmd="mvn" 36 | else 37 | mvn_cmd="./mvnw" 38 | fi 39 | 40 | ls -al 41 | 42 | echo "Maven version: $($mvn_cmd --version)" 43 | 44 | echo "Job type: ${JOB_TYPE}" 45 | 46 | RETURN_CODE=0 47 | set +e 48 | 49 | case ${JOB_TYPE} in 50 | test) 51 | $mvn_cmd -e -B clean -ntp test -P coverage -Dcheckstyle.skip 52 | RETURN_CODE=$? 53 | ;; 54 | integration) 55 | $mvn_cmd -e -B clean -ntp verify -P e2e -P coverage -Dcheckstyle.skip 56 | RETURN_CODE=$? 57 | ;; 58 | esac 59 | 60 | echo -e "******************** Tests complete. ********************\n" 61 | echo "exiting with ${RETURN_CODE}" 62 | exit ${RETURN_CODE} 63 | -------------------------------------------------------------------------------- /.github/scripts/run_tests_graalvm_native.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2020 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # `-e` enables the script to automatically fail when a command fails 17 | set -e 18 | 19 | echo -e "******************** Installing modules... ********************\n" 20 | mvn -e -B install -DskipTests 21 | echo -e "******************** Installation complete. ********************\n" 22 | echo "JAVA_HOME: $JAVA_HOME" 23 | echo "Java version:" 24 | java -version 25 | 26 | # Why change directories to run the tests? Because GraalVM test execution 27 | # requires at least one matching test per Maven module. Not all modules in this 28 | # repository have "*IntegrationTests.java". 29 | # https://github.com/graalvm/native-build-tools/issues/188 30 | set +e 31 | declare -i return_code=0 32 | 33 | # Currently, jdbc/postgres works with GraalVM native image. 34 | # TODO(#824): Provide GraalVM configuration and enable native image tests below: 35 | # jdbc/mysql-j-5 jdbc/mysql-j-8 jdbc/sqlserver r2dbc/sqlserver r2dbc/sqlserver 36 | # r2dbc/mysql 37 | # https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/issues/824 38 | for test_directory in jdbc/postgres jdbc/mysql-j-8; do 39 | pushd ${test_directory} 40 | echo -e "******************** Running tests in ${test_directory} ********************\n" 41 | # Dependency convergence enforcer rule would fail with the junit dependencies 42 | # specified in "native" profile. The test-scope dependencies do not have any 43 | # effect to library users' class path. 44 | mvn -e -B clean verify -P e2e,native -P coverage 45 | result=$? 46 | return_code=$((return_code || result)) 47 | echo -e "******************** Tests complete in ${test_directory}, result: $result ********************\n" 48 | popd 49 | done 50 | exit ${return_code} 51 | -------------------------------------------------------------------------------- /.github/sync-repo-settings.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # Whether or not rebase-merging is enabled on this repository. 15 | # Defaults to `true` 16 | rebaseMergeAllowed: false 17 | 18 | # Whether or not squash-merging is enabled on this repository. 19 | # Defaults to `true` 20 | squashMergeAllowed: true 21 | 22 | # Whether or not PRs are merged with a merge commit on this repository. 23 | # Defaults to `false` 24 | mergeCommitAllowed: false 25 | 26 | # Rules for main branch protection 27 | branchProtectionRules: 28 | # Identifies the protection rule pattern. Name of the branch to be protected. 29 | # Defaults to `main` 30 | - pattern: main 31 | # Can admins overwrite branch protection. 32 | # Defaults to `true` 33 | isAdminEnforced: true 34 | # Number of approving reviews required to update matching branches. 35 | # Defaults to `1` 36 | requiredApprovingReviewCount: 1 37 | # Are reviews from code owners required to update matching branches. 38 | # Defaults to `false` 39 | requiresCodeOwnerReviews: true 40 | # Require up to date branches 41 | requiresStrictStatusChecks: true 42 | # List of required status check contexts that must pass for commits to be accepted to matching branches. 43 | requiredStatusCheckContexts: 44 | - "lint" 45 | - "unit tests (macos-latest, 8)" 46 | - "unit tests (macos-latest, 11)" 47 | - "unit tests (macos-latest, 17)" 48 | - "unit tests (windows-latest, 8)" 49 | - "unit tests (windows-latest, 11)" 50 | - "unit tests (windows-latest, 17)" 51 | - "unit tests (ubuntu-latest, 8)" 52 | - "unit tests (ubuntu-latest, 11)" 53 | - "unit tests (ubuntu-latest, 17)" 54 | - "units + e2e (ubuntu-latest, 17)" 55 | - "cla/google" 56 | # Wait until we make the repo public before bringing this back 57 | # - "OwlBot Post Processor" 58 | -------------------------------------------------------------------------------- /.github/trusted-contribution.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Trigger presubmit tests for trusted contributors 16 | # https://github.com/googleapis/repo-automation-bots/tree/main/packages/trusted-contribution 17 | # Install: https://github.com/apps/trusted-contributions-gcf 18 | 19 | trustedContributors: 20 | - "dependabot[bot]" 21 | - "renovate-bot" 22 | - "renovate[bot]" 23 | - "forking-renovate[bot]" 24 | - "release-please[bot]" 25 | annotations: 26 | # Trigger Cloud Build tests 27 | - type: comment 28 | text: "/gcbrun" 29 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: "CodeQL" 16 | 17 | on: 18 | push: 19 | branches: ["main"] 20 | pull_request: 21 | branches: ["main"] 22 | paths-ignore: 23 | - "**/*.md" 24 | - "**/*.txt" 25 | 26 | # Declare default permissions as read only. 27 | permissions: read-all 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | permissions: 34 | actions: read 35 | contents: read 36 | security-events: write 37 | 38 | strategy: 39 | fail-fast: false 40 | matrix: 41 | language: ["java"] 42 | 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 46 | 47 | # Initializes the CodeQL tools for scanning. 48 | - name: Initialize CodeQL 49 | uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 50 | with: 51 | languages: ${{ matrix.language }} 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 54 | # If this step fails, then you should remove it and run the build manually 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 57 | 58 | - name: Perform CodeQL Analysis 59 | uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 60 | with: 61 | category: "/language:${{matrix.language}}" 62 | -------------------------------------------------------------------------------- /.github/workflows/labels.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Sync labels 16 | on: 17 | push: 18 | branches: 19 | - main 20 | 21 | # Declare default permissions as read only. 22 | permissions: read-all 23 | 24 | jobs: 25 | build: 26 | runs-on: ubuntu-latest 27 | permissions: 28 | issues: write 29 | pull-requests: write 30 | steps: 31 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 32 | - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1.3.0 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: lint 16 | on: 17 | pull_request: 18 | 19 | # Declare default permissions as read only. 20 | permissions: read-all 21 | 22 | jobs: 23 | lint: 24 | name: checkstyle 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout code 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | - name: Set up JDK 17 30 | uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0 31 | with: 32 | distribution: "zulu" 33 | java-version: "17" 34 | - name: lint 35 | run: mvn -B compile -Plint 36 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: OSSF Scorecard 16 | on: 17 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 18 | branch_protection_rule: 19 | schedule: 20 | # weekly on Sunday 21 | - cron: '0 20 * * 0' 22 | push: 23 | branches: [ "main" ] 24 | 25 | # Declare default permissions as read only. 26 | permissions: read-all 27 | 28 | jobs: 29 | analysis: 30 | name: Scorecard analysis 31 | runs-on: ubuntu-latest 32 | permissions: 33 | # Needed to upload the results to code-scanning dashboard. 34 | security-events: write 35 | 36 | steps: 37 | - name: "Checkout code" 38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | with: 40 | persist-credentials: false 41 | 42 | - name: "Run analysis" 43 | uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 44 | with: 45 | results_file: results.sarif 46 | results_format: sarif 47 | 48 | - name: Filter SARIF to skip false positives 49 | # filter out DangerousWorkflow alerts as they do not account for safe use of labels to trigger actions 50 | env: 51 | SCORECARD_SKIPPED_RULE_IDS: "DangerousWorkflowID" 52 | run: | 53 | SCORECARD_SKIPPED_RULE_IDS_JSON=$(echo $SCORECARD_SKIPPED_RULE_IDS | jq -cR 'split(",")') 54 | # Trim the SARIF file to remove false positive detections 55 | cat results.sarif | jq '.runs[].results |= map(select(.ruleId as $id | '$SCORECARD_SKIPPED_RULE_IDS_JSON' | all($id != .)))' > resultsFiltered.sarif 56 | 57 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 58 | # format to the repository Actions tab. 59 | - name: "Upload artifact" 60 | uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 61 | with: 62 | name: SARIF file 63 | path: results.sarif 64 | retention-days: 5 65 | 66 | # Upload the results to GitHub's code scanning dashboard. 67 | - name: "Upload to code-scanning" 68 | uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 69 | with: 70 | sarif_file: resultsFiltered.sarif 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # misc java 2 | target/ 3 | *.class 4 | 5 | # IntelliJ 6 | .idea/ 7 | *.iml 8 | *.bak 9 | 10 | # vscode 11 | **/.project 12 | **/.settings/ 13 | **/.classpath 14 | 15 | # direnv 16 | .envrc 17 | 18 | # Package Files 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | 27 | # Packages 28 | dist 29 | bin 30 | var 31 | sdist 32 | target 33 | 34 | # Unit test / coverage reports 35 | .coverage 36 | .tox 37 | nosetests.xml 38 | 39 | # Translations 40 | *.mo 41 | 42 | # Mr Developer 43 | .mr.developer.cfg 44 | 45 | .metadata 46 | .project 47 | .pydevproject 48 | 49 | *.iml 50 | .idea 51 | .settings 52 | .DS_Store 53 | .classpath 54 | 55 | # API key file containing value of GOOGLE_API_KEY for integration tests 56 | api_key 57 | 58 | # Python utilities 59 | *.pyc 60 | artman-genfiles 61 | /venv 62 | /env 63 | 64 | .flattened-pom.xml 65 | .envrc 66 | 67 | # Package Files 68 | *.jar 69 | *.war 70 | *.nar 71 | *.ear 72 | *.zip 73 | *.tar.gz 74 | *.rar 75 | -------------------------------------------------------------------------------- /.kokoro/build.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2022 Google LLC 2 | :: 3 | :: Licensed under the Apache License, Version 2.0 (the "License"); 4 | :: you may not use this file except in compliance with the License. 5 | :: You may obtain a copy of the License at 6 | :: 7 | :: http://www.apache.org/licenses/LICENSE-2.0 8 | :: 9 | :: Unless required by applicable law or agreed to in writing, software 10 | :: distributed under the License is distributed on an "AS IS" BASIS, 11 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | :: See the License for the specific language governing permissions and 13 | :: limitations under the License. 14 | :: Github action job to test core java library features on 15 | :: downstream client libraries before they are released. 16 | :: See documentation in type-shell-output.bat 17 | 18 | "C:\Program Files\Git\bin\bash.exe" %~dp0build.sh 19 | -------------------------------------------------------------------------------- /.kokoro/check_coverage.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2023 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # `-e` enables the script to automatically fail when a command fails 17 | set -e 18 | 19 | export CUR_COVER=$(cat core/target/site/jacoco/index.html | grep -o 'Total[^%]*' | sed 's/<.*>//; s/Total//') 20 | echo "Current Coverage is $CUR_COVER%" 21 | if [ "$CUR_COVER" -lt 75 ]; then 22 | exit 1; 23 | fi 24 | -------------------------------------------------------------------------------- /.kokoro/coerce_logs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # This script finds and moves sponge logs so that they can be found by placer 17 | # and are not flagged as flaky by sponge. 18 | 19 | set -eo pipefail 20 | 21 | ## Get the directory of the build script 22 | scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}")) 23 | ## cd to the parent directory, i.e. the root of the git repo 24 | cd ${scriptDir}/.. 25 | 26 | job=$(basename ${KOKORO_JOB_NAME}) 27 | 28 | echo "coercing sponge logs..." 29 | for xml in `find . -name *-sponge_log.xml` 30 | do 31 | class=$(basename ${xml} | cut -d- -f2) 32 | dir=$(dirname ${xml})/${job}/${class} 33 | text=$(dirname ${xml})/${class}-sponge_log.txt 34 | mkdir -p ${dir} 35 | mv ${xml} ${dir}/sponge_log.xml 36 | mv ${text} ${dir}/sponge_log.txt 37 | done 38 | -------------------------------------------------------------------------------- /.kokoro/common.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | # Download trampoline resources. These will be in ${KOKORO_GFILE_DIR} 4 | gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" 5 | 6 | # All builds use the trampoline script to run in docker. 7 | build_file: "cloud-sql-jdbc-socket-factory/.kokoro/trampoline.sh" 8 | 9 | # Tell the trampoline which build file to use. 10 | env_vars: { 11 | key: "TRAMPOLINE_BUILD_FILE" 12 | value: "github/cloud-sql-jdbc-socket-factory/.kokoro/build.sh" 13 | } 14 | -------------------------------------------------------------------------------- /.kokoro/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2022 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | function retry_with_backoff { 17 | attempts_left=$1 18 | sleep_seconds=$2 19 | shift 2 20 | command=$@ 21 | 22 | 23 | # store current flag state 24 | flags=$- 25 | 26 | # allow a failures to continue 27 | set +e 28 | ${command} 29 | exit_code=$? 30 | 31 | # restore "e" flag 32 | if [[ ${flags} =~ e ]] 33 | then set -e 34 | else set +e 35 | fi 36 | 37 | if [[ $exit_code == 0 ]] 38 | then 39 | return 0 40 | fi 41 | 42 | # failure 43 | if [[ ${attempts_left} > 0 ]] 44 | then 45 | echo "failure (${exit_code}), sleeping ${sleep_seconds}..." 46 | sleep ${sleep_seconds} 47 | new_attempts=$((${attempts_left} - 1)) 48 | new_sleep=$((${sleep_seconds} * 2)) 49 | retry_with_backoff ${new_attempts} ${new_sleep} ${command} 50 | fi 51 | 52 | return $exit_code 53 | } 54 | 55 | ## Helper functionss 56 | function now() { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n'; } 57 | function msg() { println "$*" >&2; } 58 | function println() { printf '%s\n' "$(now) $*"; } 59 | 60 | ## Helper comment to trigger updated repo dependency release 61 | -------------------------------------------------------------------------------- /.kokoro/dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | shopt -s nullglob 18 | 19 | ## Get the directory of the build script 20 | scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}")) 21 | ## cd to the parent directory, i.e. the root of the git repo 22 | cd ${scriptDir}/.. 23 | 24 | # include common functions 25 | source ${scriptDir}/common.sh 26 | 27 | # Print out Java 28 | java -version 29 | echo $JOB_TYPE 30 | 31 | function determineMavenOpts() { 32 | local javaVersion=$( 33 | # filter down to the version line, then pull out the version between quotes, 34 | # then trim the version number down to its minimal number (removing any 35 | # update or suffix number). 36 | java -version 2>&1 | grep "version" \ 37 | | sed -E 's/^.*"(.*?)".*$/\1/g' \ 38 | | sed -E 's/^(1\.[0-9]\.0).*$/\1/g' 39 | ) 40 | 41 | if [[ $javaVersion == 17* ]] 42 | then 43 | # MaxPermSize is no longer supported as of jdk 17 44 | echo -n "-Xmx1024m" 45 | else 46 | echo -n "-Xmx1024m -XX:MaxPermSize=128m" 47 | fi 48 | } 49 | 50 | export MAVEN_OPTS=$(determineMavenOpts) 51 | 52 | # this should run maven enforcer 53 | retry_with_backoff 3 10 \ 54 | mvn install -B -V -ntp \ 55 | -DskipTests=true \ 56 | -Dmaven.javadoc.skip=true \ 57 | -Dclirr.skip=true 58 | 59 | mvn -B dependency:analyze -DfailOnWarning=true 60 | -------------------------------------------------------------------------------- /.kokoro/populate-secrets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} 19 | function msg { println "$*" >&2 ;} 20 | function println { printf '%s\n' "$(now) $*" ;} 21 | 22 | 23 | # Populates requested secrets set in SECRET_MANAGER_KEYS from service account: 24 | # kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com 25 | SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" 26 | msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" 27 | mkdir -p ${SECRET_LOCATION} 28 | for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") 29 | do 30 | msg "Retrieving secret ${key}" 31 | docker run --entrypoint=gcloud \ 32 | --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ 33 | gcr.io/google.com/cloudsdktool/cloud-sdk \ 34 | secrets versions access latest \ 35 | --project cloud-devrel-kokoro-resources \ 36 | --secret ${key} > \ 37 | "${SECRET_LOCATION}/${key}" 38 | if [[ $? == 0 ]]; then 39 | msg "Secret written to ${SECRET_LOCATION}/${key}" 40 | else 41 | msg "Error retrieving secret ${key}" 42 | fi 43 | done 44 | -------------------------------------------------------------------------------- /.kokoro/release/bump_snapshot.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | # Build logs will be here 4 | action { 5 | define_artifacts { 6 | regex: "**/*sponge_log.xml" 7 | } 8 | } 9 | 10 | # Download trampoline resources. 11 | gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" 12 | 13 | # Use the trampoline script to run in docker. 14 | build_file: "cloud-sql-jdbc-socket-factory/.kokoro/trampoline.sh" 15 | 16 | # Configure the docker image for kokoro-trampoline. 17 | env_vars: { 18 | key: "TRAMPOLINE_IMAGE" 19 | value: "gcr.io/cloud-devrel-kokoro-resources/node:10-user" 20 | } 21 | 22 | env_vars: { 23 | key: "TRAMPOLINE_BUILD_FILE" 24 | value: "github/cloud-sql-jdbc-socket-factory/.kokoro/release/bump_snapshot.sh" 25 | } 26 | 27 | # tokens used by release-please to keep an up-to-date release PR. 28 | before_action { 29 | fetch_keystore { 30 | keystore_resource { 31 | keystore_config_id: 73713 32 | keyname: "github-magic-proxy-key-release-please" 33 | } 34 | } 35 | } 36 | 37 | before_action { 38 | fetch_keystore { 39 | keystore_resource { 40 | keystore_config_id: 73713 41 | keyname: "github-magic-proxy-token-release-please" 42 | } 43 | } 44 | } 45 | 46 | before_action { 47 | fetch_keystore { 48 | keystore_resource { 49 | keystore_config_id: 73713 50 | keyname: "github-magic-proxy-url-release-please" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.kokoro/release/common.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | # Download trampoline resources. 4 | gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" 5 | 6 | # Use the trampoline script to run in docker. 7 | build_file: "cloud-sql-jdbc-socket-factory/.kokoro/trampoline.sh" 8 | 9 | # Configure the docker image for kokoro-trampoline. 10 | env_vars: { 11 | key: "TRAMPOLINE_IMAGE" 12 | value: "gcr.io/cloud-devrel-kokoro-resources/java11" 13 | } 14 | 15 | before_action { 16 | fetch_keystore { 17 | keystore_resource { 18 | keystore_config_id: 70247 19 | keyname: "maven-gpg-keyring" 20 | } 21 | } 22 | } 23 | 24 | before_action { 25 | fetch_keystore { 26 | keystore_resource { 27 | keystore_config_id: 70247 28 | keyname: "maven-gpg-passphrase" 29 | } 30 | } 31 | } 32 | 33 | before_action { 34 | fetch_keystore { 35 | keystore_resource { 36 | keystore_config_id: 70247 37 | keyname: "maven-gpg-pubkeyring" 38 | } 39 | } 40 | } 41 | 42 | before_action { 43 | fetch_keystore { 44 | keystore_resource { 45 | keystore_config_id: 70247 46 | keyname: "sonatype-credentials" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.kokoro/release/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2018 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | # Get secrets from keystore and set and environment variables 19 | setup_environment_secrets() { 20 | export GPG_PASSPHRASE=$(cat ${KOKORO_KEYSTORE_DIR}/70247_maven-gpg-passphrase) 21 | export GPG_TTY=$(tty) 22 | export GPG_HOMEDIR=/gpg 23 | mkdir $GPG_HOMEDIR 24 | mv ${KOKORO_KEYSTORE_DIR}/70247_maven-gpg-pubkeyring $GPG_HOMEDIR/pubring.gpg 25 | mv ${KOKORO_KEYSTORE_DIR}/70247_maven-gpg-keyring $GPG_HOMEDIR/secring.gpg 26 | export SONATYPE_USERNAME=$(cat ${KOKORO_KEYSTORE_DIR}/70247_sonatype-credentials | cut -f1 -d'|') 27 | export SONATYPE_PASSWORD=$(cat ${KOKORO_KEYSTORE_DIR}/70247_sonatype-credentials | cut -f2 -d'|') 28 | } 29 | 30 | create_settings_xml_file() { 31 | echo " 32 | 33 | 34 | ossrh 35 | ${SONATYPE_USERNAME} 36 | ${SONATYPE_PASSWORD} 37 | 38 | 39 | sonatype-nexus-staging 40 | ${SONATYPE_USERNAME} 41 | ${SONATYPE_PASSWORD} 42 | 43 | 44 | sonatype-nexus-snapshots 45 | ${SONATYPE_USERNAME} 46 | ${SONATYPE_PASSWORD} 47 | 48 | 49 | " > $1 50 | } -------------------------------------------------------------------------------- /.kokoro/release/drop.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | env_vars: { 4 | key: "TRAMPOLINE_BUILD_FILE" 5 | value: "github/cloud-sql-jdbc-socket-factory/.kokoro/release/drop.sh" 6 | } 7 | -------------------------------------------------------------------------------- /.kokoro/release/drop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2018 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | # STAGING_REPOSITORY_ID must be set 19 | if [ -z "${STAGING_REPOSITORY_ID}" ]; then 20 | echo "Missing STAGING_REPOSITORY_ID environment variable" 21 | exit 1 22 | fi 23 | 24 | source $(dirname "$0")/common.sh 25 | pushd $(dirname "$0")/../../ 26 | 27 | setup_environment_secrets 28 | create_settings_xml_file "settings.xml" 29 | 30 | mvn nexus-staging:drop -B \ 31 | --settings=settings.xml \ 32 | -DstagingRepositoryId=${STAGING_REPOSITORY_ID} 33 | -------------------------------------------------------------------------------- /.kokoro/release/promote.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | env_vars: { 4 | key: "TRAMPOLINE_BUILD_FILE" 5 | value: "github/cloud-sql-jdbc-socket-factory/.kokoro/release/promote.sh" 6 | } 7 | -------------------------------------------------------------------------------- /.kokoro/release/promote.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2018 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | # STAGING_REPOSITORY_ID must be set 19 | if [ -z "${STAGING_REPOSITORY_ID}" ]; then 20 | echo "Missing STAGING_REPOSITORY_ID environment variable" 21 | exit 1 22 | fi 23 | 24 | source $(dirname "$0")/common.sh 25 | 26 | pushd $(dirname "$0")/../../ 27 | 28 | setup_environment_secrets 29 | create_settings_xml_file "settings.xml" 30 | 31 | mvn nexus-staging:release -B \ 32 | -DperformRelease=true \ 33 | --settings=settings.xml \ 34 | -DstagingRepositoryId=${STAGING_REPOSITORY_ID} 35 | -------------------------------------------------------------------------------- /.kokoro/release/publish_javadoc.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/doc-templates/" 4 | 5 | env_vars: { 6 | key: "STAGING_BUCKET" 7 | value: "docs-staging" 8 | } 9 | 10 | env_vars: { 11 | key: "TRAMPOLINE_BUILD_FILE" 12 | value: "github/cloud-sql-jdbc-socket-factory/.kokoro/release/publish_javadoc.sh" 13 | } 14 | 15 | 16 | before_action { 17 | fetch_keystore { 18 | keystore_resource { 19 | keystore_config_id: 73713 20 | keyname: "docuploader_service_account" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.kokoro/release/publish_javadoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | if [[ -z "${CREDENTIALS}" ]]; then 19 | CREDENTIALS=${KOKORO_KEYSTORE_DIR}/73713_docuploader_service_account 20 | fi 21 | 22 | if [[ -z "${STAGING_BUCKET}" ]]; then 23 | echo "Need to set STAGING_BUCKET environment variable" 24 | exit 1 25 | fi 26 | 27 | # work from the git root directory 28 | pushd $(dirname "$0")/../../ 29 | 30 | # install docuploader package 31 | python3 -m pip install --require-hashes -r .kokoro/requirements.txt 32 | 33 | # compile all packages 34 | mvn clean install -B -q -DskipTests=true 35 | 36 | export NAME=jdbc-socket-factory-parent 37 | export VERSION=$(grep ${NAME}: versions.txt | cut -d: -f3) 38 | 39 | # build the docs 40 | mvn site -B -q 41 | 42 | pushd target/site/apidocs 43 | 44 | # create metadata 45 | python3 -m docuploader create-metadata \ 46 | --name ${NAME} \ 47 | --version ${VERSION} \ 48 | --language java 49 | 50 | # upload docs 51 | python3 -m docuploader upload . \ 52 | --credentials ${CREDENTIALS} \ 53 | --staging-bucket ${STAGING_BUCKET} 54 | -------------------------------------------------------------------------------- /.kokoro/release/publish_javadoc11.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | # cloud-rad production 4 | env_vars: { 5 | key: "STAGING_BUCKET_V2" 6 | value: "docs-staging-v2" 7 | } 8 | 9 | # Configure the docker image for kokoro-trampoline 10 | env_vars: { 11 | key: "TRAMPOLINE_IMAGE" 12 | value: "gcr.io/cloud-devrel-kokoro-resources/java11" 13 | } 14 | 15 | env_vars: { 16 | key: "TRAMPOLINE_BUILD_FILE" 17 | value: "github/jdbc-socket-factory-parent/.kokoro/release/publish_javadoc11.sh" 18 | } 19 | 20 | before_action { 21 | fetch_keystore { 22 | keystore_resource { 23 | keystore_config_id: 73713 24 | keyname: "docuploader_service_account" 25 | } 26 | } 27 | } 28 | 29 | # Downloads docfx doclet resource. This will be in ${KOKORO_GFILE_DIR}/ 30 | gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/docfx" 31 | -------------------------------------------------------------------------------- /.kokoro/release/publish_javadoc11.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | if [[ -z "${CREDENTIALS}" ]]; then 19 | CREDENTIALS=${KOKORO_KEYSTORE_DIR}/73713_docuploader_service_account 20 | fi 21 | 22 | if [[ -z "${STAGING_BUCKET_V2}" ]]; then 23 | echo "Need to set STAGING_BUCKET_V2 environment variable" 24 | exit 1 25 | fi 26 | 27 | # work from the git root directory 28 | pushd $(dirname "$0")/../../ 29 | 30 | # install docuploader package 31 | python3 -m pip install --require-hashes -r .kokoro/requirements.txt 32 | 33 | # compile all packages 34 | mvn clean install -B -q -DskipTests=true 35 | 36 | export NAME=jdbc-socket-factory-parent 37 | export VERSION=$(grep ${NAME}: versions.txt | cut -d: -f3) 38 | 39 | # cloud RAD generation 40 | mvn clean javadoc:aggregate -B -q -P docFX 41 | # include CHANGELOG 42 | cp CHANGELOG.md target/docfx-yml/history.md 43 | 44 | pushd target/docfx-yml 45 | 46 | # create metadata 47 | python3 -m docuploader create-metadata \ 48 | --name ${NAME} \ 49 | --version ${VERSION} \ 50 | --xrefs devsite://java/gax \ 51 | --xrefs devsite://java/google-cloud-core \ 52 | --xrefs devsite://java/api-common \ 53 | --xrefs devsite://java/proto-google-common-protos \ 54 | --xrefs devsite://java/google-api-client \ 55 | --xrefs devsite://java/google-http-client \ 56 | --xrefs devsite://java/protobuf \ 57 | --language java 58 | 59 | # upload yml to production bucket 60 | python3 -m docuploader upload . \ 61 | --credentials ${CREDENTIALS} \ 62 | --staging-bucket ${STAGING_BUCKET_V2} \ 63 | --destination-prefix docfx 64 | -------------------------------------------------------------------------------- /.kokoro/release/snapshot.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | env_vars: { 4 | key: "TRAMPOLINE_BUILD_FILE" 5 | value: "github/jdbc-socket-factory-parent/.kokoro/release/snapshot.sh" 6 | } 7 | 8 | 9 | action { 10 | define_artifacts { 11 | regex: "github/jdbc-socket-factory-parent/.*/target/.*\.jar" 12 | strip_prefix: "github/jdbc-socket-factory-parent" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.kokoro/release/snapshot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | source $(dirname "$0")/common.sh 19 | source $(dirname "$0")/../common.sh 20 | MAVEN_SETTINGS_FILE=$(realpath $(dirname "$0")/../../)/settings.xml 21 | pushd $(dirname "$0")/../../ 22 | 23 | # ensure we're trying to push a snapshot (no-result returns non-zero exit code) 24 | grep SNAPSHOT versions.txt 25 | 26 | setup_environment_secrets 27 | create_settings_xml_file "settings.xml" 28 | 29 | mvn clean deploy -B \ 30 | --settings ${MAVEN_SETTINGS_FILE} \ 31 | -DperformRelease=true \ 32 | -Dgpg.executable=gpg \ 33 | -Dgpg.passphrase=${GPG_PASSPHRASE} \ 34 | -Dgpg.homedir=${GPG_HOMEDIR} 35 | -------------------------------------------------------------------------------- /.kokoro/release/stage.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | env_vars: { 4 | key: "TRAMPOLINE_BUILD_FILE" 5 | value: "github/jdbc-socket-factory-parent/.kokoro/release/stage.sh" 6 | } 7 | 8 | # Need to save the properties file 9 | action { 10 | define_artifacts { 11 | regex: "github/jdbc-socket-factory-parent/target/nexus-staging/staging/*.properties" 12 | strip_prefix: "github/jdbc-socket-factory-parent" 13 | } 14 | } 15 | 16 | # Save jar artifacts for SBOM generation 17 | action { 18 | define_artifacts { 19 | regex: "github/jdbc-socket-factory-parent/.*/target/.*\.jar" 20 | strip_prefix: "github/jdbc-socket-factory-parent" 21 | } 22 | } 23 | 24 | env_vars: { 25 | key: "SECRET_MANAGER_KEYS" 26 | value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" 27 | } 28 | -------------------------------------------------------------------------------- /.kokoro/release/stage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2018 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eo pipefail 17 | 18 | # Start the releasetool reporter 19 | requirementsFile=$(realpath $(dirname "${BASH_SOURCE[0]}")/../requirements.txt) 20 | python3 -m pip install --require-hashes -r $requirementsFile 21 | python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script 22 | 23 | source $(dirname "$0")/common.sh 24 | source $(dirname "$0")/../common.sh 25 | MAVEN_SETTINGS_FILE=$(realpath $(dirname "$0")/../../)/settings.xml 26 | pushd $(dirname "$0")/../../ 27 | 28 | setup_environment_secrets 29 | create_settings_xml_file "settings.xml" 30 | 31 | # attempt to stage 3 times with exponential backoff (starting with 10 seconds) 32 | retry_with_backoff 3 10 \ 33 | mvn clean deploy -B \ 34 | --settings ${MAVEN_SETTINGS_FILE} \ 35 | -DskipTests=true \ 36 | -Dclirr.skip=true \ 37 | -DperformRelease=true \ 38 | -Dgpg.executable=gpg \ 39 | -Dgpg.passphrase=${GPG_PASSPHRASE} \ 40 | -Dgpg.homedir=${GPG_HOMEDIR} 41 | 42 | if [[ -n "${AUTORELEASE_PR}" ]] 43 | then 44 | mvn nexus-staging:release -B \ 45 | -DperformRelease=true \ 46 | --settings=settings.xml 47 | fi 48 | -------------------------------------------------------------------------------- /.kokoro/requirements.in: -------------------------------------------------------------------------------- 1 | gcp-docuploader 2 | gcp-releasetool>=1.10.5 # required for compatibility with cryptography>=39.x 3 | wheel 4 | setuptools 5 | typing-extensions 6 | click<8.1.0 7 | -------------------------------------------------------------------------------- /.kokoro/trampoline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2019 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -eo pipefail 16 | # Always run the cleanup script, regardless of the success of bouncing into 17 | # the container. 18 | function cleanup() { 19 | chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh 20 | ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh 21 | echo "cleanup"; 22 | } 23 | trap cleanup EXIT 24 | 25 | $(dirname $0)/populate-secrets.sh # Secret Manager secrets. 26 | python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" 27 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 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 | wrapperVersion=3.3.1 18 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 19 | -------------------------------------------------------------------------------- /.release/generate_sha.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2022 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | touch release_table.md 17 | types=("mysql-socket-factory" "postgres-socket-factory" "jdbc-sqlserver" "r2dbc-mysql" "r2dbc-postgres" "r2dbc-sqlserver") 18 | for t in "${types[@]}"; do 19 | echo "### $t" >> release_table.md 20 | echo "| filename | sha256 hash |" >> release_table.md 21 | echo "|----------|-------------|" >> release_table.md 22 | for f in $(gsutil ls "gs://$BUCKET_NAME/v$VERSION/*$t*"); do 23 | file=$(basename "$f") 24 | sha=$(gsutil cat "$f" | sha256sum --binary | head -c 64) 25 | echo "| [$file](https://storage.googleapis.com/$BUCKET_NAME/v$VERSION/$file) | $sha |" >> release_table.md 26 | done 27 | echo -e "\n\n" >> release_table.md 28 | done 29 | -------------------------------------------------------------------------------- /.release/snapshot.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2022 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | VERSION=$(cat version.txt) 17 | regex="([0-9]+).([0-9]+).([0-9]+)" 18 | 19 | if [[ $VERSION =~ $regex ]]; then 20 | major="${BASH_REMATCH[1]}" 21 | minor="${BASH_REMATCH[2]}" 22 | build="${BASH_REMATCH[3]}" 23 | fi 24 | 25 | build="$(echo $build + 1 | bc)" 26 | 27 | echo "${major}.${minor}.${build}-SNAPSHOT" > version.txt 28 | -------------------------------------------------------------------------------- /.release/update_versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2021 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | VERSION=$(cat version.txt) 17 | # Update parent pom version 18 | mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false 19 | 20 | # Update versions in README if not snapshot release 21 | if ! [[ $VERSION =~ .*SNAPSHOT ]] 22 | then 23 | sed -i.bak -E 's/[0-9]+\.[0-9]+\.[0-9]+/'"$VERSION"'/g' docs/*.md 24 | fi 25 | -------------------------------------------------------------------------------- /.release/upload_uberjars.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | steps: 16 | - id: jar-with-dependencies 17 | name: maven:3-jdk-11 18 | entrypoint: mvn 19 | args: ["-P", "jar-with-dependencies", "package", "-DskipTests", "-Dmaven.repo.local=/workspace/.m2"] 20 | - id: driver-and-dependencies 21 | name: maven:3-jdk-11 22 | entrypoint: mvn 23 | args: ["-P", "jar-with-driver-and-dependencies", "package", "-DskipTests", "-Dmaven.repo.local=/workspace/.m2"] 24 | artifacts: 25 | objects: 26 | location: "gs://${_BUCKET_NAME}/v${_VERSION}/" 27 | paths: 28 | - "jdbc/postgres/target/*dependencies.jar" 29 | - "jdbc/mysql-j-*/target/*dependencies.jar" 30 | - "jdbc/sqlserver/target/*dependencies.jar" 31 | - "r2dbc/mysql/target/*dependencies.jar" 32 | - "r2dbc/postgres/target/*dependencies.jar" 33 | - "r2dbc/sqlserver/target/*dependencies.jar" 34 | -------------------------------------------------------------------------------- /.repo-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_shortname": "cloud-sql-jdbc-socket-factory", 3 | "name_pretty": "Google Cloud SQL JDBC Socket Factory", 4 | "product_documentation": "https://cloud.google.com/sql", 5 | "release_level": "stable", 6 | "language": "java", 7 | "repo": "GoogleCloudPlatform/cloud-sql-jdbc-socket-factory", 8 | "repo_short": "cloud-sql-jdbc-socket-factory", 9 | "distribution_name": "com.google.cloud.sql:jdbc-socket-factory-parent", 10 | "api_id": "sqladmin.googleapis.com", 11 | "library_type": "OTHER", 12 | "codeowner_team": "@GoogleCloudPlatform/infra-db-sdk" 13 | } 14 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | To report a security issue, please use [g.co/vulnz](https://g.co/vulnz). 4 | 5 | The Google Security Team will respond within 5 working days of your report on g.co/vulnz. 6 | 7 | We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue. 8 | -------------------------------------------------------------------------------- /checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 22 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/AuthType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql; 18 | 19 | /** Enum for supported authentication methods. */ 20 | public enum AuthType { 21 | IAM, 22 | PASSWORD 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/ConnectorRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql; 18 | 19 | import com.google.cloud.sql.core.InternalConnectorRegistry; 20 | 21 | /** Configure the CloudSQL JDBC Connector. */ 22 | public final class ConnectorRegistry { 23 | 24 | /** 25 | * Register a named connection so that it can later be referenced by name in a JDBC or R2DBC URL. 26 | * 27 | * @param name the named connection name. 28 | * @param config the full configuration of the connection. 29 | */ 30 | public static void register(String name, ConnectorConfig config) { 31 | InternalConnectorRegistry.getInstance().register(name, config); 32 | } 33 | 34 | /** 35 | * Close a named connector. This will stop all background credential refresh processes. All future 36 | * attempts to connect via this named connection will fail. 37 | * 38 | * @param name the name of the connector to close. 39 | */ 40 | public static void close(String name) { 41 | InternalConnectorRegistry.getInstance().close(name); 42 | } 43 | 44 | /** 45 | * Shutdown the entire CloudSQL JDBC Connector. This will stop all background threads. All future 46 | * attempts to connect to a CloudSQL database will fail. 47 | */ 48 | public static void shutdown() { 49 | InternalConnectorRegistry.shutdownInstance(); 50 | } 51 | 52 | /** 53 | * Resets the entire CloudSQL JDBC Connector. This will stop all background threads. The next 54 | * attempt to open a connection or register a configuration will start a new ConnectorRegistry. 55 | */ 56 | public static void reset() { 57 | InternalConnectorRegistry.resetInstance(); 58 | } 59 | 60 | /** 61 | * Adds an external application name to the user agent string for tracking. This is known to be 62 | * used by the spring-cloud-gcp project. 63 | * 64 | * @throws IllegalStateException if the SQLAdmin client has already been initialized 65 | */ 66 | public static void addArtifactId(String artifactId) { 67 | InternalConnectorRegistry.addArtifactId(artifactId, false); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/IpType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql; 18 | 19 | /** IP types that for connecting to a Cloud SQL Database. */ 20 | public enum IpType { 21 | PUBLIC, 22 | PRIVATE, 23 | PSC; 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/RefreshStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql; 18 | 19 | /** Enum for supported refresh strategies. */ 20 | public enum RefreshStrategy { 21 | /** Use the Background refresh strategy. */ 22 | BACKGROUND, 23 | /** Use the Lazy refresh strategy. */ 24 | LAZY 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/AccessTokenSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.auth.oauth2.AccessToken; 20 | import java.io.IOException; 21 | import java.util.Optional; 22 | 23 | /** Supplies an AccessToken to use when authenticating with the Google API. */ 24 | @FunctionalInterface 25 | interface AccessTokenSupplier { 26 | 27 | /** 28 | * Returns a valid access token or Optional.empty() when no token is available. 29 | * 30 | * @return the access token 31 | * @throws IOException when an error occurs attempting to refresh the token. 32 | */ 33 | Optional get() throws IOException; 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ApiClientRetryingCallable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpResponseException; 20 | import java.util.concurrent.Callable; 21 | 22 | /** 23 | * Extends RetryingCallable with logic to only retry on HTTP errors with error codes in the 5xx 24 | * range. 25 | * 26 | * @param the return value for Callable 27 | */ 28 | class ApiClientRetryingCallable extends RetryingCallable { 29 | 30 | /** 31 | * Construct a new RetryLogic. 32 | * 33 | * @param callable the callable that should be retried 34 | */ 35 | public ApiClientRetryingCallable(Callable callable) { 36 | super(callable); 37 | } 38 | 39 | /** 40 | * Returns false indicating that there should be another attempt if the exception is an HTTP 41 | * response with an error code in the 5xx range. 42 | * 43 | * @param e the exception 44 | * @return false if this is a http response with a 5xx status code, otherwise true. 45 | */ 46 | @Override 47 | protected boolean isFatalException(Exception e) { 48 | // Only retry if the error is an HTTP response with a 5xx error code. 49 | if (e instanceof HttpResponseException) { 50 | HttpResponseException re = (HttpResponseException) e; 51 | return re.getStatusCode() < 500; 52 | } 53 | // Otherwise this is a fatal exception, no more tries. 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ApplicationDefaultCredentialFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.api.services.sqladmin.SQLAdminScopes; 21 | import com.google.auth.http.HttpCredentialsAdapter; 22 | import com.google.auth.oauth2.GoogleCredentials; 23 | import com.google.cloud.sql.CredentialFactory; 24 | import java.io.IOException; 25 | import java.util.Arrays; 26 | 27 | /** This class creates a HttpRequestInitializer from Application Default Credentials. */ 28 | class ApplicationDefaultCredentialFactory implements CredentialFactory { 29 | 30 | @Override 31 | public HttpRequestInitializer create() { 32 | GoogleCredentials credentials = getCredentials(); 33 | return new HttpCredentialsAdapter(credentials); 34 | } 35 | 36 | @Override 37 | public GoogleCredentials getCredentials() { 38 | GoogleCredentials credentials; 39 | try { 40 | credentials = GoogleCredentials.getApplicationDefault(); 41 | } catch (IOException err) { 42 | throw new RuntimeException( 43 | "Unable to obtain credentials to communicate with the Cloud SQL API", err); 44 | } 45 | 46 | if (credentials.createScopedRequired()) { 47 | credentials = 48 | credentials.createScoped( 49 | Arrays.asList(SQLAdminScopes.SQLSERVICE_ADMIN, SQLAdminScopes.CLOUD_PLATFORM)); 50 | } 51 | return credentials; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/AsyncRateLimiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.common.util.concurrent.Futures; 20 | import com.google.common.util.concurrent.ListenableFuture; 21 | import java.util.concurrent.ScheduledExecutorService; 22 | import java.util.concurrent.TimeUnit; 23 | import java.util.function.LongSupplier; 24 | 25 | /** 26 | * A simple, constant-time rate limit calculator. Ensures that there is always at least 27 | * delayBetweenAttempts milliseconds between attempts. 28 | */ 29 | class AsyncRateLimiter { 30 | private long nextOperationTimestamp; 31 | private final long delayBetweenAttempts; 32 | private final LongSupplier currentTimestampMs; 33 | 34 | /** 35 | * Creates a new AsyncRateLimiter uses the System.currentTimeMillis() as the current time. 36 | * 37 | * @param delayBetweenAttempts the required delay in milliseconds between attempts. 38 | */ 39 | AsyncRateLimiter(long delayBetweenAttempts) { 40 | this(delayBetweenAttempts, System::currentTimeMillis); 41 | } 42 | 43 | /** 44 | * Creates a new AsyncRateLimiter which uses a custom function for the current time. 45 | * 46 | * @param delayBetweenAttempts the required delay in milliseconds between attempts. 47 | * @param currentTimestampMs A function that supplies the current time in milliseconds 48 | */ 49 | AsyncRateLimiter(long delayBetweenAttempts, LongSupplier currentTimestampMs) { 50 | this.delayBetweenAttempts = delayBetweenAttempts; 51 | this.currentTimestampMs = currentTimestampMs; 52 | } 53 | 54 | /** 55 | * Returns the number of milliseconds to delay before proceeding with the rate limited operation. 56 | * If this returns > 0, the operation must call "acquire" again until it returns 0. 57 | */ 58 | private synchronized long nextDelayMs(long nowTimestampMs) { 59 | // allow exactly 1 operation to pass the timestamp. 60 | if (nextOperationTimestamp <= nowTimestampMs) { 61 | nextOperationTimestamp = nowTimestampMs + delayBetweenAttempts; 62 | return 0; 63 | } 64 | 65 | return nextOperationTimestamp - nowTimestampMs; 66 | } 67 | 68 | /** 69 | * Returns a future that will be done when the rate limit has been acquired. 70 | * 71 | * @param executor the executor to use to schedule future checks for available rate limits. 72 | */ 73 | public ListenableFuture acquireAsync(ScheduledExecutorService executor) { 74 | long limit = this.nextDelayMs(currentTimestampMs.getAsLong()); 75 | if (limit > 0) { 76 | return Futures.scheduleAsync( 77 | () -> this.acquireAsync(executor), limit, TimeUnit.MILLISECONDS, executor); 78 | } 79 | return Futures.immediateFuture(null); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConnectionInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.cloud.sql.IpType; 20 | import java.time.Instant; 21 | import java.util.Map; 22 | import java.util.stream.Collectors; 23 | import javax.net.ssl.SSLContext; 24 | 25 | /** Represents the results of a certificate and metadata refresh operation. */ 26 | class ConnectionInfo { 27 | 28 | private final InstanceMetadata instanceMetadata; 29 | private final SSLContext sslContext; 30 | private final SslData sslData; 31 | private final Instant expiration; 32 | 33 | ConnectionInfo(InstanceMetadata instanceMetadata, SslData sslData, Instant expiration) { 34 | this.instanceMetadata = instanceMetadata; 35 | this.sslData = sslData; 36 | this.sslContext = sslData.getSslContext(); 37 | this.expiration = expiration; 38 | } 39 | 40 | public Instant getExpiration() { 41 | return expiration; 42 | } 43 | 44 | SSLContext getSslContext() { 45 | return sslContext; 46 | } 47 | 48 | Map getIpAddrs() { 49 | return instanceMetadata.getIpAddrs(); 50 | } 51 | 52 | SslData getSslData() { 53 | return sslData; 54 | } 55 | 56 | ConnectionMetadata toConnectionMetadata( 57 | ConnectionConfig config, CloudSqlInstanceName instanceName) { 58 | String preferredIp = null; 59 | 60 | for (IpType ipType : config.getIpTypes()) { 61 | preferredIp = getIpAddrs().get(ipType); 62 | if (preferredIp != null) { 63 | break; 64 | } 65 | } 66 | if (preferredIp == null) { 67 | throw new IllegalArgumentException( 68 | String.format( 69 | "[%s] Cloud SQL instance does not have any IP addresses matching preferences (%s)", 70 | instanceName.getConnectionName(), 71 | config.getIpTypes().stream().map(IpType::toString).collect(Collectors.joining(",")))); 72 | } 73 | 74 | return new ConnectionMetadata( 75 | preferredIp, 76 | sslData.getKeyManagerFactory(), 77 | sslData.getTrustManagerFactory(), 78 | sslData.getSslContext()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConnectionInfoCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | /** ConnectionInfoCache is the contract for a caching strategy for ConnectionInfo. */ 20 | interface ConnectionInfoCache { 21 | 22 | /** 23 | * Returns metadata needed to create a connection to the instance. 24 | * 25 | * @return returns ConnectionMetadata containing the preferred IP and SSL connection data. 26 | * @throws IllegalArgumentException If the instance has no IP addresses matching the provided 27 | * preferences. 28 | */ 29 | ConnectionMetadata getConnectionMetadata(long timeoutMs); 30 | 31 | void forceRefresh(); 32 | 33 | void refreshIfExpired(); 34 | 35 | void close(); 36 | 37 | boolean isClosed(); 38 | 39 | ConnectionConfig getConfig(); 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConnectionInfoRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.cloud.sql.AuthType; 20 | import com.google.common.util.concurrent.ListenableFuture; 21 | import com.google.common.util.concurrent.ListeningScheduledExecutorService; 22 | import java.security.KeyPair; 23 | 24 | /** Internal Use Only: Gets the instance data for the CloudSqlInstance from the API. */ 25 | interface ConnectionInfoRepository { 26 | /** Internal Use Only: Gets the instance data for the CloudSqlInstance from the API. */ 27 | ListenableFuture getConnectionInfo( 28 | CloudSqlInstanceName instanceName, 29 | AccessTokenSupplier accessTokenSupplier, 30 | AuthType authType, 31 | ListeningScheduledExecutorService executor, 32 | ListenableFuture keyPair); 33 | 34 | ConnectionInfo getConnectionInfoSync( 35 | CloudSqlInstanceName instanceName, 36 | AccessTokenSupplier accessTokenSupplier, 37 | AuthType authType, 38 | KeyPair keyPair); 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConnectionInfoRepositoryFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.cloud.sql.ConnectorConfig; 21 | 22 | /** Factory interface for creating SQLAdmin clients to interact with Cloud SQL Admin API. */ 23 | interface ConnectionInfoRepositoryFactory { 24 | 25 | ConnectionInfoRepository create(HttpRequestInitializer credentials, ConnectorConfig config); 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConnectionMetadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import javax.net.ssl.KeyManagerFactory; 20 | import javax.net.ssl.SSLContext; 21 | import javax.net.ssl.TrustManagerFactory; 22 | 23 | /** 24 | * A value object containing configuration needed to set up an mTLS connection to a Cloud SQL 25 | * instance. 26 | */ 27 | public class ConnectionMetadata { 28 | private final String preferredIpAddress; 29 | private final KeyManagerFactory keyManagerFactory; 30 | private final TrustManagerFactory trustManagerFactory; 31 | private final SSLContext sslContext; 32 | 33 | /** Construct an immutable ConnectionMetadata. */ 34 | public ConnectionMetadata( 35 | String preferredIpAddress, 36 | KeyManagerFactory keyManagerFactory, 37 | TrustManagerFactory trustManagerFactory, 38 | SSLContext sslContext) { 39 | 40 | this.preferredIpAddress = preferredIpAddress; 41 | this.keyManagerFactory = keyManagerFactory; 42 | this.trustManagerFactory = trustManagerFactory; 43 | this.sslContext = sslContext; 44 | } 45 | 46 | public String getPreferredIpAddress() { 47 | return preferredIpAddress; 48 | } 49 | 50 | public KeyManagerFactory getKeyManagerFactory() { 51 | return keyManagerFactory; 52 | } 53 | 54 | public TrustManagerFactory getTrustManagerFactory() { 55 | return trustManagerFactory; 56 | } 57 | 58 | public SSLContext getSslContext() { 59 | return sslContext; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ConstantCredentialFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.auth.http.HttpCredentialsAdapter; 21 | import com.google.auth.oauth2.GoogleCredentials; 22 | import com.google.cloud.sql.CredentialFactory; 23 | 24 | class ConstantCredentialFactory implements CredentialFactory { 25 | 26 | private final GoogleCredentials credentials; 27 | 28 | public ConstantCredentialFactory(GoogleCredentials credentials) { 29 | this.credentials = credentials; 30 | } 31 | 32 | @Override 33 | public HttpRequestInitializer create() { 34 | return new HttpCredentialsAdapter(getCredentials()); 35 | } 36 | 37 | @Override 38 | public GoogleCredentials getCredentials() { 39 | return credentials; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/CoreSocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | /** 20 | * Implementation of informally used Java API to preserve compatibility with older code that uses 21 | * CoreSocketFactory. 22 | * 23 | * @deprecated Use the official java API instead. 24 | * @see com.google.cloud.sql.ConnectorRegistry 25 | */ 26 | @SuppressWarnings("InlineMeSuggester") 27 | @Deprecated 28 | public final class CoreSocketFactory { 29 | 30 | /** 31 | * Connection property name. 32 | * 33 | * @deprecated Use the public API instead. 34 | * @see ConnectionConfig#CLOUD_SQL_INSTANCE_PROPERTY 35 | */ 36 | @Deprecated 37 | public static final String CLOUD_SQL_INSTANCE_PROPERTY = 38 | ConnectionConfig.CLOUD_SQL_INSTANCE_PROPERTY; 39 | 40 | /** 41 | * Delegates property name. 42 | * 43 | * @deprecated Use the public API instead. 44 | * @see ConnectionConfig#CLOUD_SQL_DELEGATES_PROPERTY 45 | */ 46 | @Deprecated 47 | public static final String CLOUD_SQL_DELEGATES_PROPERTY = 48 | ConnectionConfig.CLOUD_SQL_DELEGATES_PROPERTY; 49 | 50 | /** 51 | * TargetPrincipal property name. 52 | * 53 | * @deprecated Use the public API instead. 54 | * @see ConnectionConfig#CLOUD_SQL_TARGET_PRINCIPAL_PROPERTY 55 | */ 56 | @Deprecated 57 | public static final String CLOUD_SQL_TARGET_PRINCIPAL_PROPERTY = 58 | ConnectionConfig.CLOUD_SQL_TARGET_PRINCIPAL_PROPERTY; 59 | 60 | /** 61 | * IpTypes default property value. 62 | * 63 | * @deprecated Use the public API instead. 64 | * @see ConnectionConfig#DEFAULT_IP_TYPES 65 | */ 66 | @Deprecated public static final String DEFAULT_IP_TYPES = ConnectionConfig.DEFAULT_IP_TYPES; 67 | 68 | /** 69 | * Property used to set the application name for the underlying SQLAdmin client. 70 | * 71 | * @deprecated Use {@link #setApplicationName(String)} to set the application name 72 | * programmatically. 73 | */ 74 | @Deprecated 75 | public static final String USER_TOKEN_PROPERTY_NAME = 76 | InternalConnectorRegistry.USER_TOKEN_PROPERTY_NAME; 77 | 78 | /** 79 | * Sets the application name for the user agent. 80 | * 81 | * @deprecated Use the official java API instead. 82 | * @see com.google.cloud.sql.ConnectorRegistry 83 | */ 84 | @Deprecated 85 | static void setApplicationName(String artifactId) { 86 | InternalConnectorRegistry.setApplicationName(artifactId); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/DefaultConnectionInfoRepositoryFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; 20 | import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer; 21 | import com.google.api.client.googleapis.services.GoogleClientRequestInitializer; 22 | import com.google.api.client.http.HttpRequestInitializer; 23 | import com.google.api.client.http.HttpTransport; 24 | import com.google.api.client.json.JsonFactory; 25 | import com.google.api.client.json.gson.GsonFactory; 26 | import com.google.api.services.sqladmin.SQLAdmin; 27 | import com.google.cloud.sql.ConnectorConfig; 28 | import java.io.IOException; 29 | import java.security.GeneralSecurityException; 30 | 31 | /** Factory for creating a SQLAdmin client that interacts with the real SQL Admin API. */ 32 | public class DefaultConnectionInfoRepositoryFactory implements ConnectionInfoRepositoryFactory { 33 | private final String userAgents; 34 | 35 | /** 36 | * Initializes a new SQLAdminApiClientFactory class from defaults and provided userAgents. 37 | * 38 | * @param userAgents string representing userAgents for the admin API client 39 | */ 40 | public DefaultConnectionInfoRepositoryFactory(String userAgents) { 41 | this.userAgents = userAgents; 42 | } 43 | 44 | @Override 45 | public DefaultConnectionInfoRepository create( 46 | HttpRequestInitializer requestInitializer, ConnectorConfig config) { 47 | SQLAdmin adminApiBuilder = getApiBuilder(requestInitializer, config); 48 | return new DefaultConnectionInfoRepository(adminApiBuilder); 49 | } 50 | 51 | private SQLAdmin getApiBuilder( 52 | HttpRequestInitializer requestInitializer, ConnectorConfig config) { 53 | HttpTransport httpTransport; 54 | try { 55 | httpTransport = GoogleNetHttpTransport.newTrustedTransport(); 56 | } catch (GeneralSecurityException | IOException err) { 57 | throw new RuntimeException("Unable to initialize HTTP transport", err); 58 | } 59 | 60 | JsonFactory jsonFactory = GsonFactory.getDefaultInstance(); 61 | SQLAdmin.Builder adminApiBuilder = 62 | new SQLAdmin.Builder(httpTransport, jsonFactory, requestInitializer) 63 | .setApplicationName(userAgents); 64 | if (config.getAdminRootUrl() != null) { 65 | adminApiBuilder.setRootUrl(config.getAdminRootUrl()); 66 | } 67 | if (config.getAdminServicePath() != null) { 68 | adminApiBuilder.setServicePath(config.getAdminServicePath()); 69 | } 70 | if (config.getAdminQuotaProject() != null) { 71 | GoogleClientRequestInitializer clientRequestInitializer = 72 | CommonGoogleClientRequestInitializer.newBuilder() 73 | .setUserProject(config.getAdminQuotaProject()) 74 | .build(); 75 | adminApiBuilder.setGoogleClientRequestInitializer(clientRequestInitializer); 76 | } 77 | if (config.getUniverseDomain() != null) { 78 | adminApiBuilder.setUniverseDomain(config.getUniverseDomain()); 79 | } 80 | return adminApiBuilder.build(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/DnsInstanceConnectionNameResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.util.Collection; 20 | import java.util.Objects; 21 | import javax.naming.NameNotFoundException; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * An implementation of InstanceConnectionNameResolver that uses DNS TXT records to resolve an 27 | * instance name from a domain name. 28 | */ 29 | class DnsInstanceConnectionNameResolver implements InstanceConnectionNameResolver { 30 | private static final Logger logger = 31 | LoggerFactory.getLogger(DnsInstanceConnectionNameResolver.class); 32 | 33 | private final DnsResolver dnsResolver; 34 | 35 | public DnsInstanceConnectionNameResolver(DnsResolver dnsResolver) { 36 | this.dnsResolver = dnsResolver; 37 | } 38 | 39 | @Override 40 | public CloudSqlInstanceName resolve(final String name) { 41 | if (CloudSqlInstanceName.isValidInstanceName(name)) { 42 | // name contains a well-formed instance name. 43 | return new CloudSqlInstanceName(name); 44 | } 45 | 46 | if (CloudSqlInstanceName.isValidDomain(name)) { 47 | // name contains a well-formed domain name. 48 | return resolveDomainName(name); 49 | } 50 | 51 | // name is not well-formed, and therefore cannot be resolved. 52 | throw new IllegalArgumentException( 53 | String.format( 54 | "Unable to resolve database instance for \"%s\". It should be a " 55 | + "well-formed instance name or domain name.", 56 | name)); 57 | } 58 | 59 | private CloudSqlInstanceName resolveDomainName(String name) { 60 | // Next, attempt to resolve DNS name. 61 | Collection instanceNames; 62 | try { 63 | instanceNames = this.dnsResolver.resolveTxt(name); 64 | } catch (NameNotFoundException ne) { 65 | // No DNS record found. This is not a valid instance name. 66 | throw new IllegalArgumentException( 67 | String.format( 68 | "Unable to resolve TXT record containing the instance name for " 69 | + "domain name \"%s\".", 70 | name)); 71 | } 72 | 73 | // Use the first valid instance name from the list 74 | // or throw an IllegalArgumentException if none of the values can be parsed. 75 | return instanceNames.stream() 76 | .map( 77 | target -> { 78 | try { 79 | return new CloudSqlInstanceName(target, name); 80 | } catch (IllegalArgumentException e) { 81 | logger.info( 82 | "Unable to parse instance name in TXT record for " 83 | + "domain name \"{}\" with target \"{}\"", 84 | name, 85 | target, 86 | e); 87 | return null; 88 | } 89 | }) 90 | .filter(Objects::nonNull) 91 | .findFirst() 92 | .orElseThrow( 93 | () -> 94 | new IllegalArgumentException( 95 | String.format("Unable to parse values of TXT record for \"%s\".", name))); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/DnsResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.util.Collection; 20 | import javax.naming.NameNotFoundException; 21 | 22 | /** Wraps the Java DNS API. */ 23 | interface DnsResolver { 24 | Collection resolveTxt(String domainName) throws NameNotFoundException; 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/FileCredentialFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.api.services.sqladmin.SQLAdminScopes; 21 | import com.google.auth.http.HttpCredentialsAdapter; 22 | import com.google.auth.oauth2.GoogleCredentials; 23 | import com.google.cloud.sql.CredentialFactory; 24 | import java.io.FileInputStream; 25 | import java.io.IOException; 26 | import java.util.Arrays; 27 | 28 | class FileCredentialFactory implements CredentialFactory { 29 | private final String path; 30 | 31 | FileCredentialFactory(String path) { 32 | this.path = path; 33 | } 34 | 35 | @Override 36 | public HttpRequestInitializer create() { 37 | return new HttpCredentialsAdapter(getCredentials()); 38 | } 39 | 40 | @Override 41 | public GoogleCredentials getCredentials() { 42 | GoogleCredentials credentials; 43 | try { 44 | credentials = GoogleCredentials.fromStream(new FileInputStream(path)); 45 | } catch (IOException e) { 46 | throw new IllegalStateException("Unable to load GoogleCredentials from file " + path, e); 47 | } 48 | 49 | if (credentials.createScopedRequired()) { 50 | credentials = 51 | credentials.createScoped( 52 | Arrays.asList(SQLAdminScopes.SQLSERVICE_ADMIN, SQLAdminScopes.CLOUD_PLATFORM)); 53 | } 54 | 55 | return credentials; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/InstanceCheckingTrustManagerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.io.IOException; 20 | import java.security.KeyStore; 21 | import java.security.KeyStoreException; 22 | import java.security.NoSuchAlgorithmException; 23 | import java.security.cert.Certificate; 24 | import java.security.cert.CertificateException; 25 | import javax.net.ssl.TrustManagerFactory; 26 | 27 | /** 28 | * Implement custom server certificate trust checks specific to Cloud SQL. 29 | * 30 | *

In the JVM, we need to implement 3 classes to make sure that we are capturing all the 31 | * TrustManager instances created by the Java Crypto provider so that the connector will: 32 | * 33 | *

class InstanceCheckingTrustManagerFactory extends TrustManagerFactory - has a bunch of final 34 | * methods that delegate to a TrustManagerFactorySpi. 35 | * 36 | *

class InstanceCheckingTrustManagerFactorySpi implements TrustManagerFactorySpi - can actually 37 | * intercept requests for the list of TrustManager instances and wrap them with our replacement 38 | * TrustManager. 39 | * 40 | *

class ConscryptWorkaroundTrustManager - the workaround for the Conscrypt bug. 41 | * 42 | *

class InstanceCheckingTrustManager - delegates TLS checks to the default provider and then 43 | * does custom hostname verification. 44 | */ 45 | class InstanceCheckingTrustManagerFactory extends TrustManagerFactory { 46 | 47 | static InstanceCheckingTrustManagerFactory newInstance(InstanceMetadata instanceMetadata) 48 | throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { 49 | 50 | TrustManagerFactory delegate = TrustManagerFactory.getInstance("X.509"); 51 | KeyStore trustedKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 52 | trustedKeyStore.load(null, null); 53 | 54 | // Add all the certificates in the chain of trust to the trust keystore. 55 | for (Certificate cert : instanceMetadata.getInstanceCaCertificates()) { 56 | trustedKeyStore.setCertificateEntry("ca" + cert.hashCode(), cert); 57 | } 58 | 59 | // Use a custom trust manager factory that checks the CN against the instance name 60 | // The delegate TrustManagerFactory will check the certificate chain, but will not do 61 | // hostname checking. 62 | InstanceCheckingTrustManagerFactory tmf = 63 | new InstanceCheckingTrustManagerFactory(instanceMetadata, delegate); 64 | tmf.init(trustedKeyStore); 65 | 66 | return tmf; 67 | } 68 | 69 | private InstanceCheckingTrustManagerFactory( 70 | InstanceMetadata instanceMetadata, TrustManagerFactory delegate) { 71 | super( 72 | new InstanceCheckingTrustManagerFactorySpi(instanceMetadata, delegate), 73 | delegate.getProvider(), 74 | delegate.getAlgorithm()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/InstanceCheckingTrustManagerFactorySpi.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.security.KeyStore; 21 | import java.security.KeyStoreException; 22 | import javax.net.ssl.ManagerFactoryParameters; 23 | import javax.net.ssl.TrustManager; 24 | import javax.net.ssl.TrustManagerFactory; 25 | import javax.net.ssl.TrustManagerFactorySpi; 26 | import javax.net.ssl.X509ExtendedTrustManager; 27 | 28 | /** 29 | * Part of the InstanceCheckingTrustManagerFactory that implements custom CloudSQL server 30 | * certificate checks. 31 | */ 32 | class InstanceCheckingTrustManagerFactorySpi extends TrustManagerFactorySpi { 33 | private final TrustManagerFactory delegate; 34 | private final InstanceMetadata instanceMetadata; 35 | 36 | InstanceCheckingTrustManagerFactorySpi( 37 | InstanceMetadata instanceMetadata, TrustManagerFactory delegate) { 38 | this.instanceMetadata = instanceMetadata; 39 | this.delegate = delegate; 40 | } 41 | 42 | @Override 43 | protected void engineInit(KeyStore ks) throws KeyStoreException { 44 | delegate.init(ks); 45 | } 46 | 47 | @Override 48 | protected void engineInit(ManagerFactoryParameters spec) 49 | throws InvalidAlgorithmParameterException { 50 | delegate.init(spec); 51 | } 52 | 53 | @Override 54 | protected TrustManager[] engineGetTrustManagers() { 55 | TrustManager[] tms = delegate.getTrustManagers(); 56 | TrustManager[] delegates = new TrustManager[tms.length]; 57 | for (int i = 0; i < tms.length; i++) { 58 | if (tms[i] instanceof X509ExtendedTrustManager) { 59 | X509ExtendedTrustManager tm = (X509ExtendedTrustManager) tms[i]; 60 | 61 | // Note: This is a workaround for Conscrypt bug #1033 62 | // Conscrypt is the JCE provider on some Google Cloud runtimes like DataProc. 63 | // https://github.com/google/conscrypt/issues/1033 64 | if (ConscryptWorkaroundDelegatingTrustManger.isWorkaroundNeeded()) { 65 | tm = new ConscryptWorkaroundDelegatingTrustManger(tm); 66 | } 67 | 68 | delegates[i] = new InstanceCheckingTrustManger(instanceMetadata, tm); 69 | } else { 70 | delegates[i] = tms[i]; 71 | } 72 | } 73 | return delegates; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/InstanceConnectionNameResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | /** Resolves the Cloud SQL Instance from the configuration name. */ 20 | interface InstanceConnectionNameResolver { 21 | 22 | /** 23 | * Resolves the CloudSqlInstanceName from a configuration string value. 24 | * 25 | * @param name the configuration string 26 | * @return the CloudSqlInstanceName 27 | * @throws IllegalArgumentException if the name cannot be resolved. 28 | */ 29 | CloudSqlInstanceName resolve(String name); 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/InstanceMetadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.cloud.sql.IpType; 20 | import java.security.cert.Certificate; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | /** Represents the results of @link #fetchMetadata(). */ 25 | class InstanceMetadata { 26 | 27 | private final CloudSqlInstanceName instanceName; 28 | private final Map ipAddrs; 29 | private final List instanceCaCertificates; 30 | private final boolean casManagedCertificate; 31 | private final String dnsName; 32 | private final boolean pscEnabled; 33 | 34 | InstanceMetadata( 35 | CloudSqlInstanceName instanceName, 36 | Map ipAddrs, 37 | List instanceCaCertificates, 38 | boolean casManagedCertificate, 39 | String dnsName, 40 | boolean pscEnabled) { 41 | this.instanceName = instanceName; 42 | this.ipAddrs = ipAddrs; 43 | this.instanceCaCertificates = instanceCaCertificates; 44 | this.casManagedCertificate = casManagedCertificate; 45 | this.dnsName = dnsName; 46 | this.pscEnabled = pscEnabled; 47 | } 48 | 49 | Map getIpAddrs() { 50 | return ipAddrs; 51 | } 52 | 53 | List getInstanceCaCertificates() { 54 | return instanceCaCertificates; 55 | } 56 | 57 | public boolean isCasManagedCertificate() { 58 | return casManagedCertificate; 59 | } 60 | 61 | public String getDnsName() { 62 | return dnsName; 63 | } 64 | 65 | public boolean isPscEnabled() { 66 | return pscEnabled; 67 | } 68 | 69 | public CloudSqlInstanceName getInstanceName() { 70 | return instanceName; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/JndiDnsResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.Hashtable; 22 | import java.util.stream.Collectors; 23 | import javax.naming.Context; 24 | import javax.naming.NameNotFoundException; 25 | import javax.naming.NamingException; 26 | import javax.naming.directory.Attribute; 27 | import javax.naming.directory.InitialDirContext; 28 | 29 | /** Implements DnsResolver using the Java JNDI built-in DNS directory. */ 30 | class JndiDnsResolver implements DnsResolver { 31 | private final String jndiPrefix; 32 | 33 | /** Creates a resolver using the system DNS settings. */ 34 | JndiDnsResolver() { 35 | this.jndiPrefix = "dns:"; 36 | } 37 | 38 | /** 39 | * Creates a DNS resolver that uses a specific DNS server. 40 | * 41 | * @param dnsServer the DNS server hostname 42 | * @param port the DNS server port (DNS servers usually use port 53) 43 | */ 44 | JndiDnsResolver(String dnsServer, int port) { 45 | this.jndiPrefix = "dns://" + dnsServer + ":" + port + "/"; 46 | } 47 | 48 | /** 49 | * Returns DNS records for a domain name, sorted alphabetically. 50 | * 51 | * @param domainName the domain name to lookup 52 | * @return the list of record 53 | * @throws javax.naming.NameNotFoundException when the domain name did not resolve. 54 | */ 55 | @Override 56 | @SuppressWarnings("JdkObsolete") 57 | public Collection resolveTxt(String domainName) 58 | throws javax.naming.NameNotFoundException { 59 | try { 60 | // Notice: This is old Java 1.2 style code. It uses the ancient JNDI DNS Provider api. 61 | // See https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-dns.html 62 | 63 | // Explicitly reference the JNDI DNS classes. This is required for GraalVM. 64 | Hashtable contextProps = new Hashtable<>(); 65 | contextProps.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); 66 | contextProps.put(Context.OBJECT_FACTORIES, "com.sun.jndi.url.dns.dnsURLContextFactory"); 67 | Attribute attr = 68 | new InitialDirContext(contextProps) 69 | .getAttributes(jndiPrefix + domainName, new String[] {"TXT"}) 70 | .get("TXT"); 71 | // attr.getAll() returns a Vector containing strings, one for each record returned by dns. 72 | return Collections.list(attr.getAll()).stream() 73 | .map((Object v) -> (String) v) 74 | .sorted() // sort multiple records alphabetically 75 | .collect(Collectors.toList()); 76 | } catch (NameNotFoundException e) { 77 | throw e; 78 | } catch (NamingException e) { 79 | throw new RuntimeException("Unable to look up domain name " + domainName, e); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/LazyRefreshConnectionInfoCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.cloud.sql.core.RefreshCalculator.DEFAULT_REFRESH_BUFFER; 20 | 21 | import com.google.cloud.sql.CredentialFactory; 22 | import java.security.KeyPair; 23 | 24 | /** 25 | * Implements the lazy refresh cache strategy, which loads the new certificate as needed during a 26 | * request for a new connection. 27 | */ 28 | class LazyRefreshConnectionInfoCache implements ConnectionInfoCache { 29 | private final ConnectionConfig config; 30 | private final CloudSqlInstanceName instanceName; 31 | 32 | private final LazyRefreshStrategy refreshStrategy; 33 | 34 | /** 35 | * Initializes a new Cloud SQL instance based on the given connection name using the lazy refresh 36 | * strategy. 37 | * 38 | * @param config instance connection name in the format "PROJECT_ID:REGION_ID:INSTANCE_ID" 39 | * @param connectionInfoRepository Service class for interacting with the Cloud SQL Admin API 40 | * @param keyPair public/private key pair used to authenticate connections 41 | */ 42 | public LazyRefreshConnectionInfoCache( 43 | ConnectionConfig config, 44 | ConnectionInfoRepository connectionInfoRepository, 45 | CredentialFactory tokenSourceFactory, 46 | KeyPair keyPair) { 47 | 48 | CloudSqlInstanceName instanceName = 49 | new CloudSqlInstanceName(config.getCloudSqlInstance(), config.getDomainName()); 50 | 51 | this.config = config; 52 | this.instanceName = instanceName; 53 | 54 | AccessTokenSupplier accessTokenSupplier = 55 | DefaultAccessTokenSupplier.newInstance(config.getAuthType(), tokenSourceFactory); 56 | 57 | this.refreshStrategy = 58 | new LazyRefreshStrategy( 59 | config.getCloudSqlInstance(), 60 | () -> 61 | connectionInfoRepository.getConnectionInfoSync( 62 | instanceName, accessTokenSupplier, config.getAuthType(), keyPair), 63 | DEFAULT_REFRESH_BUFFER); 64 | } 65 | 66 | @Override 67 | public ConnectionMetadata getConnectionMetadata(long timeoutMs) { 68 | return refreshStrategy.getConnectionInfo(timeoutMs).toConnectionMetadata(config, instanceName); 69 | } 70 | 71 | @Override 72 | public void forceRefresh() { 73 | refreshStrategy.forceRefresh(); 74 | } 75 | 76 | @Override 77 | public void refreshIfExpired() { 78 | refreshStrategy.refreshIfExpired(); 79 | } 80 | 81 | @Override 82 | public void close() { 83 | refreshStrategy.close(); 84 | } 85 | 86 | @Override 87 | public boolean isClosed() { 88 | return refreshStrategy.isClosed(); 89 | } 90 | 91 | @Override 92 | public ConnectionConfig getConfig() { 93 | return config; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/RefreshCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import java.time.Duration; 20 | import java.time.Instant; 21 | 22 | /** 23 | * RefreshCalculator determines the number of seconds until the next refresh operation using the 24 | * same algorithm used by the other Connectors. 25 | */ 26 | class RefreshCalculator { 27 | 28 | // defaultRefreshBuffer is the minimum amount of time for which a 29 | // certificate must be valid to ensure the next refresh attempt has adequate 30 | // time to complete. 31 | static final Duration DEFAULT_REFRESH_BUFFER = Duration.ofMinutes(4); 32 | 33 | long calculateSecondsUntilNextRefresh(Instant now, Instant expiration) { 34 | Duration timeUntilExp = Duration.between(now, expiration); 35 | 36 | if (timeUntilExp.compareTo(Duration.ofHours(1)) < 0) { 37 | if (timeUntilExp.compareTo(DEFAULT_REFRESH_BUFFER) < 0) { 38 | // If the time until the certificate expires is less the refresh buffer, schedule the 39 | // refresh immediately 40 | return 0; 41 | } 42 | // Otherwise schedule a refresh in (timeUntilExp - buffer) seconds 43 | return timeUntilExp.minus(DEFAULT_REFRESH_BUFFER).getSeconds(); 44 | } 45 | 46 | // If the time until the certificate expires is longer than an hour, return timeUntilExp//2 47 | return timeUntilExp.dividedBy(2).getSeconds(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/RefreshStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | /** Provide the refresh strategy to the DefaultConnectionInfoCache. */ 20 | public interface RefreshStrategy { 21 | /** Return the current valid ConnectionInfo, blocking if necessary for up to the timeout. */ 22 | ConnectionInfo getConnectionInfo(long timeoutMs); 23 | 24 | /** Force a refresh of the ConnectionInfo, possibly in the background. */ 25 | void forceRefresh(); 26 | 27 | /** Refresh the ConnectionInfo if it has expired or is near expiration. */ 28 | void refreshIfExpired(); 29 | 30 | /** 31 | * Stop background threads and refresh operations in progress and refuse to start subsequent 32 | * refresh operations. 33 | */ 34 | void close(); 35 | 36 | /** Returns true when the RefreshStrategy instance is closed. */ 37 | boolean isClosed(); 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/ServiceAccountImpersonatingCredentialFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.api.services.sqladmin.SQLAdminScopes; 21 | import com.google.auth.http.HttpCredentialsAdapter; 22 | import com.google.auth.oauth2.GoogleCredentials; 23 | import com.google.auth.oauth2.ImpersonatedCredentials; 24 | import com.google.cloud.sql.CredentialFactory; 25 | import java.util.Arrays; 26 | import java.util.List; 27 | 28 | /** 29 | * Wraps an existing CredentialFactory to impersonate the targetPrincipal, with an optional list of 30 | * delegating service accounts in accordance with the ImpersonatedCredentials API. 31 | * 32 | *

targetPrincipal – the service account to impersonate 33 | * 34 | *

delegates – the chained list of delegates required to grant the final access_token. If set, 35 | * the sequence of identities must have "Service Account Token Creator" capability granted to the 36 | * preceding identity. For example, if set to [serviceAccountB, serviceAccountC], the 37 | * sourceCredential must have the Token Creator role on serviceAccountB. serviceAccountB must have 38 | * the Token Creator on serviceAccountC. Finally, C must have Token Creator on target_principal. If 39 | * unset, sourceCredential must have that role on targetPrincipal. 40 | * 41 | * @see com.google.auth.oauth2.ImpersonatedCredentials 42 | */ 43 | class ServiceAccountImpersonatingCredentialFactory implements CredentialFactory { 44 | 45 | private final CredentialFactory source; 46 | private final List delegates; 47 | private final String targetPrincipal; 48 | 49 | /** 50 | * Creates a new ServiceAccountImpersonatingCredentialFactory. 51 | * 52 | * @param source the source of the original credentials, before they are impersonated. 53 | * @param targetPrincipal The target principal in the form of a service account, must not be null. 54 | * @param delegates The optional list of delegate service accounts, may be null or empty. 55 | */ 56 | ServiceAccountImpersonatingCredentialFactory( 57 | CredentialFactory source, String targetPrincipal, List delegates) { 58 | if (targetPrincipal == null || targetPrincipal.isEmpty()) { 59 | throw new IllegalArgumentException("targetPrincipal must not be empty"); 60 | } 61 | this.source = source; 62 | this.delegates = delegates; 63 | this.targetPrincipal = targetPrincipal; 64 | } 65 | 66 | @Override 67 | public HttpRequestInitializer create() { 68 | GoogleCredentials credentials = getCredentials(); 69 | return new HttpCredentialsAdapter(credentials); 70 | } 71 | 72 | @Override 73 | public GoogleCredentials getCredentials() { 74 | GoogleCredentials credentials = source.getCredentials(); 75 | 76 | credentials = 77 | ImpersonatedCredentials.newBuilder() 78 | .setSourceCredentials(credentials) 79 | .setTargetPrincipal(targetPrincipal) 80 | .setDelegates(this.delegates) 81 | .setScopes( 82 | Arrays.asList(SQLAdminScopes.SQLSERVICE_ADMIN, SQLAdminScopes.CLOUD_PLATFORM)) 83 | .build(); 84 | return credentials; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/SslData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import javax.net.ssl.KeyManagerFactory; 20 | import javax.net.ssl.SSLContext; 21 | import javax.net.ssl.TrustManagerFactory; 22 | 23 | /** This class stores data that can be used to establish Cloud SQL SSL connection. */ 24 | class SslData { 25 | 26 | private final SSLContext sslContext; 27 | private final KeyManagerFactory keyManagerFactory; 28 | private final TrustManagerFactory trustManagerFactory; 29 | 30 | SslData( 31 | SSLContext sslContext, 32 | KeyManagerFactory keyManagerFactory, 33 | TrustManagerFactory trustManagerFactory) { 34 | this.sslContext = sslContext; 35 | this.keyManagerFactory = keyManagerFactory; 36 | this.trustManagerFactory = trustManagerFactory; 37 | } 38 | 39 | SSLContext getSslContext() { 40 | return sslContext; 41 | } 42 | 43 | KeyManagerFactory getKeyManagerFactory() { 44 | return keyManagerFactory; 45 | } 46 | 47 | TrustManagerFactory getTrustManagerFactory() { 48 | return trustManagerFactory; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/SupplierCredentialFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpRequestInitializer; 20 | import com.google.auth.http.HttpCredentialsAdapter; 21 | import com.google.auth.oauth2.GoogleCredentials; 22 | import com.google.cloud.sql.CredentialFactory; 23 | import java.util.function.Supplier; 24 | 25 | class SupplierCredentialFactory implements CredentialFactory { 26 | 27 | private final Supplier supplier; 28 | 29 | public SupplierCredentialFactory(Supplier supplier) { 30 | this.supplier = supplier; 31 | } 32 | 33 | @Override 34 | public HttpRequestInitializer create() { 35 | return new HttpCredentialsAdapter(getCredentials()); 36 | } 37 | 38 | @Override 39 | public GoogleCredentials getCredentials() { 40 | return supplier.get(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/TerminalException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | class TerminalException extends RuntimeException { 20 | public TerminalException() { 21 | super(); 22 | } 23 | 24 | public TerminalException(String message) { 25 | super(message); 26 | } 27 | 28 | public TerminalException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/core/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * WARNING: This package does not contain any stable, public Java API. The class definitions may 19 | * change without notice. 20 | * 21 | *

Package com.google.cloud.sql.core holds internal shared packages that implement logic to 22 | * create a socket to a Cloud SQL database. 23 | */ 24 | package com.google.cloud.sql.core; 25 | -------------------------------------------------------------------------------- /core/src/main/java/com/google/cloud/sql/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Package com.google.cloud.sql holds the stable public java API for creating sockets to Cloud SQL 19 | * database. 20 | */ 21 | package com.google.cloud.sql; 22 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/jni-unix-socket-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "jnr.ffi.provider.LoadedLibrary" 4 | }, 5 | { 6 | "name": "jnr.unixsocket.Native$LibC", 7 | "interfaces": [ 8 | "jnr.unixsocket.Native$LibC", 9 | "jnr.ffi.provider.LoadedLibrary" 10 | ] 11 | }, 12 | { 13 | "name": "jnr.enxio.channels.Native$LibC", 14 | "interfaces": [ 15 | "jnr.enxio.channels.Native$LibC", 16 | "jnr.ffi.provider.LoadedLibrary" 17 | ] 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/native-image.properties: -------------------------------------------------------------------------------- 1 | Args =\ 2 | -H:+AddAllCharsets \ 3 | -H:ReflectionConfigurationResources=META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/jni-unix-socket-config.json \ 4 | -H:ResourceConfigurationResources=META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/resource-config.json \ 5 | -H:DynamicProxyConfigurationResources=META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/proxy-config.json \ 6 | --features=com.google.cloud.sql.nativeimage.CloudSqlFeature 7 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/proxy-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "condition": { 4 | "typeReachable": "jnr.unixsocket.Native$LibC" 5 | }, 6 | "name": "jnr.unixsocket.Native$LibC", 7 | "interfaces": [ 8 | "jnr.unixsocket.Native$LibC", 9 | "jnr.ffi.provider.LoadedLibrary" 10 | ] 11 | }, 12 | { 13 | "condition": { 14 | "typeReachable":"jnr.enxio.channels.Native$LibC" 15 | }, 16 | "name": "jnr.enxio.channels.Native$LibC", 17 | "interfaces": [ 18 | "jnr.enxio.channels.Native$LibC", 19 | "jnr.ffi.provider.LoadedLibrary" 20 | ] 21 | }, 22 | { 23 | "name": "com.sun.jndi.dns.DnsContextFactory", 24 | "interfaces": [ 25 | "javax.naming.spi.InitialContextFactory" 26 | ] 27 | }, 28 | { 29 | "name": "com.sun.jndi.url.dns.dnsURLContextFactory", 30 | "interfaces": [ 31 | "javax.naming.spi.ObjectFactory" 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/native-image/com.google.cloud.sql/cloud-sql-jdbc-socket-factory-parent/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources":[ 3 | {"pattern":"\\Qcom.google.cloud.sql/project.properties\\E"}, 4 | {"pattern":"\\QMETA-INF/services/java.sql.Driver\\E"}, 5 | {"pattern":"\\Qcom/mysql/cj/util/TimeZoneMapping.properties\\E"}, 6 | {"pattern":"jni/.*\\.so"}, 7 | {"pattern":"jni/.*\\.dll"} 8 | ], 9 | "bundles": [ 10 | {"name":"com.mysql.cj.LocalizedErrorMessages"}, 11 | {"name":"com.mysql.jdbc.LocalizedErrorMessages"} 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/resources/com.google.cloud.sql/project.properties: -------------------------------------------------------------------------------- 1 | version=${project.version} -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/ApiClientRetryingCallableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import com.google.api.client.http.HttpHeaders; 22 | import com.google.api.client.http.HttpResponseException; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import org.junit.Assert; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.junit.runners.JUnit4; 28 | 29 | @RunWith(JUnit4.class) 30 | public class ApiClientRetryingCallableTest { 31 | @Test 32 | public void testApiClientRetriesOn500ErrorAndSucceeds() throws Exception { 33 | AtomicInteger counter = new AtomicInteger(0); 34 | ApiClientRetryingCallable c = 35 | new ApiClientRetryingCallable<>( 36 | () -> { 37 | int attempt = counter.incrementAndGet(); 38 | if (attempt < 3) { 39 | throw new HttpResponseException.Builder( 40 | 503, "service unavailable", new HttpHeaders()) 41 | .build(); 42 | } 43 | return attempt; 44 | }); 45 | 46 | Integer v = c.call(); 47 | assertThat(counter.get()).isEqualTo(3); 48 | assertThat(v).isEqualTo(3); 49 | } 50 | 51 | @Test 52 | public void testApiClientRetriesOn500ErrorAndFailsAfter5Attempts() throws Exception { 53 | AtomicInteger counter = new AtomicInteger(0); 54 | ApiClientRetryingCallable c = 55 | new ApiClientRetryingCallable<>( 56 | () -> { 57 | counter.incrementAndGet(); 58 | throw new HttpResponseException.Builder(503, "service unavailable", new HttpHeaders()) 59 | .build(); 60 | }); 61 | 62 | try { 63 | c.call(); 64 | Assert.fail("got no exception, wants an exception to be thrown"); 65 | } catch (Exception e) { 66 | // Expected to throw an exception 67 | } 68 | assertThat(counter.get()).isEqualTo(5); 69 | } 70 | 71 | @Test 72 | public void testRetryStopsAfterFatalException() throws Exception { 73 | final AtomicInteger counter = new AtomicInteger(); 74 | RetryingCallable r = 75 | new RetryingCallable( 76 | () -> { 77 | counter.incrementAndGet(); 78 | throw new Exception("nope"); 79 | }) { 80 | @Override 81 | protected boolean isFatalException(Exception e) { 82 | return true; 83 | } 84 | }; 85 | 86 | try { 87 | r.call(); 88 | Assert.fail("got no exception, wants an exception to be thrown"); 89 | } catch (Exception e) { 90 | // Expected to throw an exception 91 | } 92 | assertThat(counter.get()).isEqualTo(1); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/BadConnectionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.http.HttpTransport; 20 | import com.google.api.client.http.LowLevelHttpRequest; 21 | import com.google.api.client.http.LowLevelHttpResponse; 22 | import java.io.IOException; 23 | import java.net.SocketTimeoutException; 24 | 25 | public class BadConnectionFactory extends HttpTransport { 26 | 27 | @Override 28 | protected LowLevelHttpRequest buildRequest(String method, String url) throws IOException { 29 | return new FailToConnectRequest(); 30 | } 31 | 32 | private static class FailToConnectRequest extends LowLevelHttpRequest { 33 | 34 | @Override 35 | public void addHeader(String name, String value) throws IOException { 36 | // do nothing. 37 | } 38 | 39 | @Override 40 | public LowLevelHttpResponse execute() throws IOException { 41 | try { 42 | Thread.sleep(100); 43 | } catch (InterruptedException e) { 44 | // Ignore the interruption 45 | } 46 | throw new SocketTimeoutException("Fake connect timeout"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/CloudSqlInstanceNameTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.assertThrows; 21 | 22 | import org.junit.Assert; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.junit.runners.JUnit4; 26 | 27 | @RunWith(JUnit4.class) 28 | public class CloudSqlInstanceNameTest { 29 | 30 | @Test 31 | public void parseStandardConnectionName() { 32 | String connectionName = "my-project:my-region:my-instance"; 33 | 34 | CloudSqlInstanceName instanceName = new CloudSqlInstanceName(connectionName); 35 | 36 | Assert.assertEquals(connectionName, instanceName.getConnectionName()); 37 | Assert.assertEquals("my-project", instanceName.getProjectId()); 38 | Assert.assertEquals("my-region", instanceName.getRegionId()); 39 | Assert.assertEquals("my-instance", instanceName.getInstanceId()); 40 | } 41 | 42 | @Test 43 | public void parseLegacyConnectionName() { 44 | String connectionName = "google.com:my-project:my-region:my-instance"; 45 | 46 | CloudSqlInstanceName instanceName = new CloudSqlInstanceName(connectionName); 47 | 48 | Assert.assertEquals(instanceName.getConnectionName(), connectionName); 49 | Assert.assertEquals("google.com:my-project", instanceName.getProjectId()); 50 | Assert.assertEquals("my-region", instanceName.getRegionId()); 51 | Assert.assertEquals("my-instance", instanceName.getInstanceId()); 52 | } 53 | 54 | @Test 55 | public void parseBadConnectionName() { 56 | IllegalArgumentException ex = 57 | assertThrows( 58 | IllegalArgumentException.class, 59 | () -> new CloudSqlInstanceName("my-project:my-instance")); 60 | 61 | assertThat(ex).hasMessageThat().contains("Cloud SQL connection name is invalid"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/ConstantCredentialsFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import com.google.auth.oauth2.GoogleCredentials; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.junit.runners.JUnit4; 25 | 26 | @RunWith(JUnit4.class) 27 | public class ConstantCredentialsFactoryTest { 28 | 29 | @Test 30 | public void testConstantCredentials() { 31 | GoogleCredentials c = GoogleCredentials.create(null); 32 | ConstantCredentialFactory f = new ConstantCredentialFactory(c); 33 | assertThat(f.getCredentials()).isSameInstanceAs(c); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/DefaultConnectionInfoRepositoryIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.cloud.sql.ConnectorConfig; 23 | import com.google.cloud.sql.CredentialFactory; 24 | import com.google.common.collect.ImmutableList; 25 | import java.util.concurrent.TimeUnit; 26 | import org.junit.BeforeClass; 27 | import org.junit.Rule; 28 | import org.junit.Test; 29 | import org.junit.rules.Timeout; 30 | import org.junit.runner.RunWith; 31 | import org.junit.runners.JUnit4; 32 | 33 | @RunWith(JUnit4.class) 34 | public class DefaultConnectionInfoRepositoryIntegrationTests { 35 | private static final String QUOTA_PROJECT = System.getenv("QUOTA_PROJECT"); 36 | private static final String CONNECTION_NAME = System.getenv("MYSQL_CONNECTION_NAME"); 37 | 38 | private static final ImmutableList requiredEnvVars = 39 | ImmutableList.of("QUOTA_PROJECT", "MYSQL_CONNECTION_NAME"); 40 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 41 | 42 | @BeforeClass 43 | public static void checkEnvVars() { 44 | // Check that required env vars are set 45 | requiredEnvVars.forEach( 46 | (varName) -> 47 | assertWithMessage( 48 | String.format( 49 | "Environment variable '%s' must be set to perform these tests.", varName)) 50 | .that(System.getenv(varName)) 51 | .isNotEmpty()); 52 | } 53 | 54 | @Test 55 | public void testQuotaProjectIsSetOnAdminApiRequest() { 56 | ConnectorConfig config = 57 | new ConnectorConfig.Builder().withAdminQuotaProject(QUOTA_PROJECT).build(); 58 | 59 | CredentialFactoryProvider credentialFactoryProvider = new CredentialFactoryProvider(); 60 | CredentialFactory instanceCredentialFactory = 61 | credentialFactoryProvider.getInstanceCredentialFactory(config); 62 | DefaultConnectionInfoRepository repo = 63 | new DefaultConnectionInfoRepositoryFactory("cloud-sql-connector-connector-core") 64 | .create(instanceCredentialFactory.create(), config); 65 | 66 | assertThat(repo.getQuotaProject(CONNECTION_NAME)).isEqualTo(QUOTA_PROJECT); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/FileCredentialFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.*; 21 | 22 | import com.google.auth.oauth2.GoogleCredentials; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.junit.runners.JUnit4; 26 | 27 | @RunWith(JUnit4.class) 28 | public class FileCredentialFactoryTest { 29 | 30 | @Test 31 | public void getCredentials_failsWhenNoFileExists() { 32 | FileCredentialFactory f = new FileCredentialFactory("nope"); 33 | assertThrows(IllegalStateException.class, f::getCredentials); 34 | } 35 | 36 | @Test 37 | public void getCredentials_loadsFromFilePath() { 38 | String path = FileCredentialFactoryTest.class.getResource("/sample-credentials.json").getFile(); 39 | FileCredentialFactory f = new FileCredentialFactory(path); 40 | GoogleCredentials c = f.getCredentials(); 41 | assertThat(c.getQuotaProjectId()).isEqualTo("sample"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/LazyRefreshConnectionInfoCacheTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.cloud.sql.core; 17 | 18 | import static com.google.common.truth.Truth.assertThat; 19 | 20 | import com.google.common.util.concurrent.Futures; 21 | import com.google.common.util.concurrent.ListenableFuture; 22 | import java.security.KeyPair; 23 | import java.util.concurrent.ExecutionException; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.junit.runners.JUnit4; 28 | 29 | @RunWith(JUnit4.class) 30 | public class LazyRefreshConnectionInfoCacheTest { 31 | private ListenableFuture keyPairFuture; 32 | private final StubCredentialFactory stubCredentialFactory = 33 | new StubCredentialFactory("my-token", System.currentTimeMillis() + 3600L); 34 | 35 | @Before 36 | public void setup() throws Exception { 37 | MockAdminApi mockAdminApi = new MockAdminApi(); 38 | this.keyPairFuture = Futures.immediateFuture(mockAdminApi.getClientKeyPair()); 39 | } 40 | 41 | @Test 42 | public void testCloudSqlInstanceDataLazyStrategyRetrievedSuccessfully() 43 | throws ExecutionException, InterruptedException { 44 | KeyPair kp = keyPairFuture.get(); 45 | TestDataSupplier instanceDataSupplier = new TestDataSupplier(false); 46 | 47 | // initialize connectionInfoCache after mocks are set up 48 | LazyRefreshConnectionInfoCache connectionInfoCache = 49 | new LazyRefreshConnectionInfoCache( 50 | new ConnectionConfig.Builder().withCloudSqlInstance("project:region:instance").build(), 51 | instanceDataSupplier, 52 | stubCredentialFactory, 53 | kp); 54 | 55 | ConnectionMetadata gotMetadata = connectionInfoCache.getConnectionMetadata(300); 56 | ConnectionMetadata gotMetadata2 = connectionInfoCache.getConnectionMetadata(300); 57 | 58 | // Assert that the underlying ConnectionInfo was retrieved exactly once. 59 | assertThat(instanceDataSupplier.counter.get()).isEqualTo(1); 60 | 61 | // Assert that the ConnectionInfo fields are added to ConnectionMetadata 62 | assertThat(gotMetadata.getKeyManagerFactory()) 63 | .isSameInstanceAs(instanceDataSupplier.response.getSslData().getKeyManagerFactory()); 64 | assertThat(gotMetadata.getKeyManagerFactory()) 65 | .isSameInstanceAs(gotMetadata2.getKeyManagerFactory()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/RefreshCalculatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.cloud.sql.core; 17 | 18 | import static com.google.common.truth.Truth.assertThat; 19 | import static java.time.temporal.ChronoUnit.SECONDS; 20 | 21 | import java.time.Duration; 22 | import java.time.Instant; 23 | import java.util.Arrays; 24 | import java.util.Collection; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.junit.runners.Parameterized; 28 | import org.junit.runners.Parameterized.Parameters; 29 | 30 | @RunWith(Parameterized.class) 31 | public class RefreshCalculatorTest { 32 | 33 | private final Duration input; 34 | private final Duration want; 35 | 36 | @Parameters(name = "Test {0}: calculateSecondsUntilNextRefresh({1})={2}") 37 | public static Collection data() { 38 | return Arrays.asList( 39 | new Object[][] { 40 | {"when expiration is greater than 1 hour", Duration.ofHours(4), Duration.ofHours(2)}, 41 | {"when expiration is equal to 1 hour", Duration.ofHours(1), Duration.ofMinutes(30)}, 42 | { 43 | "when expiration is less than 1 hour, but greater than 4 minutes", 44 | Duration.ofMinutes(5), 45 | Duration.ofMinutes(1) 46 | }, 47 | {"when expiration is less than 4 minutes", Duration.ofMinutes(3), Duration.ofMinutes(0)}, 48 | {"when expiration is now", Duration.ofMinutes(0), Duration.ofMinutes(0)}, 49 | {"when expiration is 62 minutes", Duration.ofMinutes(62), Duration.ofMinutes(31)}, 50 | {"when expiration is 58 minutes", Duration.ofMinutes(58), Duration.ofMinutes(54)}, 51 | }); 52 | } 53 | 54 | public RefreshCalculatorTest(String name, Duration input, Duration want) { 55 | this.input = input; 56 | this.want = want; 57 | this.refreshCalculator = new RefreshCalculator(); 58 | } 59 | 60 | private static final Instant NOW = Instant.now().truncatedTo(SECONDS); 61 | private final RefreshCalculator refreshCalculator; 62 | 63 | @Test 64 | public void testDuration() { 65 | Duration nextRefresh = 66 | Duration.ofSeconds( 67 | refreshCalculator.calculateSecondsUntilNextRefresh(NOW, NOW.plus(input))); 68 | assertThat(nextRefresh).isEqualTo(want); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/RetryingCallableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | import org.junit.Assert; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.junit.runners.JUnit4; 26 | 27 | @RunWith(JUnit4.class) 28 | public class RetryingCallableTest { 29 | @Test 30 | public void testConstructorIllegalArguments() throws Exception { 31 | // Callable must not be null 32 | Assert.assertThrows(IllegalArgumentException.class, () -> new RetryingCallable<>(null)); 33 | } 34 | 35 | @Test 36 | public void testNoRetryRequired() throws Exception { 37 | RetryingCallable r = new RetryingCallable<>(() -> 1); 38 | int v = r.call(); 39 | assertThat(v).isEqualTo(1); 40 | } 41 | 42 | @Test 43 | public void testAlwaysFails() { 44 | final AtomicInteger counter = new AtomicInteger(); 45 | RetryingCallable r = 46 | new RetryingCallable<>( 47 | () -> { 48 | counter.incrementAndGet(); 49 | throw new Exception("nope"); 50 | }); 51 | 52 | try { 53 | r.call(); 54 | Assert.fail("got no exception, wants an exception to be thrown"); 55 | } catch (Exception e) { 56 | // Expected to throw an exception 57 | } 58 | 59 | assertThat(counter.get()).isEqualTo(5); 60 | } 61 | 62 | @Test 63 | public void testRetrySucceedsAfterFailures() throws Exception { 64 | final AtomicInteger counter = new AtomicInteger(); 65 | RetryingCallable r = 66 | new RetryingCallable<>( 67 | () -> { 68 | int i = counter.incrementAndGet(); 69 | if (i < 3) { 70 | throw new Exception("nope"); 71 | } 72 | return i; 73 | }); 74 | 75 | int v = r.call(); 76 | assertThat(counter.get()).isEqualTo(3); 77 | assertThat(v).isEqualTo(3); 78 | } 79 | 80 | @Test 81 | public void testRetryStopsAfterFatalException() throws Exception { 82 | final AtomicInteger counter = new AtomicInteger(); 83 | RetryingCallable r = 84 | new RetryingCallable( 85 | () -> { 86 | int i = counter.incrementAndGet(); 87 | if (i < 3) { 88 | throw new Exception("nope"); 89 | } 90 | return i; 91 | }) { 92 | @Override 93 | protected boolean isFatalException(Exception e) { 94 | return true; 95 | } 96 | }; 97 | 98 | try { 99 | r.call(); 100 | Assert.fail("got no exception, wants an exception to be thrown"); 101 | } catch (Exception e) { 102 | // Expected to throw an exception 103 | } 104 | assertThat(counter.get()).isEqualTo(1); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/StubConnectionInfoRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.cloud.sql.AuthType; 20 | import com.google.cloud.sql.IpType; 21 | import com.google.common.util.concurrent.Futures; 22 | import com.google.common.util.concurrent.ListenableFuture; 23 | import com.google.common.util.concurrent.ListeningScheduledExecutorService; 24 | import java.security.KeyPair; 25 | import java.security.NoSuchAlgorithmException; 26 | import java.time.Instant; 27 | import java.time.temporal.ChronoUnit; 28 | import java.util.Collections; 29 | import java.util.Map; 30 | import java.util.concurrent.atomic.AtomicInteger; 31 | import javax.net.ssl.KeyManagerFactory; 32 | 33 | class StubConnectionInfoRepository implements ConnectionInfoRepository { 34 | private final AtomicInteger refreshCount = new AtomicInteger(); 35 | 36 | int getRefreshCount() { 37 | return refreshCount.get(); 38 | } 39 | 40 | private ConnectionInfo newConnectionInfo() { 41 | Map ips = Collections.singletonMap(IpType.PUBLIC, "10.1.1.1"); 42 | try { 43 | return new ConnectionInfo( 44 | new InstanceMetadata( 45 | new CloudSqlInstanceName("project:region:instance"), ips, null, false, "", false), 46 | new SslData( 47 | null, KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()), null), 48 | Instant.now().plus(1, ChronoUnit.HOURS)); 49 | } catch (NoSuchAlgorithmException e) { 50 | throw new RuntimeException(e); 51 | } 52 | } 53 | 54 | @Override 55 | public ListenableFuture getConnectionInfo( 56 | CloudSqlInstanceName instanceName, 57 | AccessTokenSupplier accessTokenSupplier, 58 | AuthType authType, 59 | ListeningScheduledExecutorService executor, 60 | ListenableFuture keyPair) { 61 | refreshCount.incrementAndGet(); 62 | ConnectionInfo connectionInfo = newConnectionInfo(); 63 | return Futures.immediateFuture(connectionInfo); 64 | } 65 | 66 | @Override 67 | public ConnectionInfo getConnectionInfoSync( 68 | CloudSqlInstanceName instanceName, 69 | AccessTokenSupplier accessTokenSupplier, 70 | AuthType authType, 71 | KeyPair keyPair) { 72 | refreshCount.incrementAndGet(); 73 | return newConnectionInfo(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/StubConnectionInfoRepositoryFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer; 20 | import com.google.api.client.googleapis.services.GoogleClientRequestInitializer; 21 | import com.google.api.client.http.HttpRequestInitializer; 22 | import com.google.api.client.http.HttpTransport; 23 | import com.google.api.client.json.gson.GsonFactory; 24 | import com.google.api.client.testing.http.MockHttpTransport; 25 | import com.google.api.services.sqladmin.SQLAdmin; 26 | import com.google.cloud.sql.ConnectorConfig; 27 | 28 | public class StubConnectionInfoRepositoryFactory implements ConnectionInfoRepositoryFactory { 29 | 30 | HttpTransport httpTransport; 31 | ConnectionInfoRepository connectionInfoRepository; 32 | 33 | StubConnectionInfoRepositoryFactory(HttpTransport transport) { 34 | this.httpTransport = transport; 35 | } 36 | 37 | StubConnectionInfoRepositoryFactory(ConnectionInfoRepository connectionInfoRepository) { 38 | this.connectionInfoRepository = connectionInfoRepository; 39 | } 40 | 41 | @Override 42 | public ConnectionInfoRepository create( 43 | HttpRequestInitializer credentials, ConnectorConfig config) { 44 | if (connectionInfoRepository != null) { 45 | return connectionInfoRepository; 46 | } 47 | 48 | SQLAdmin.Builder adminApiBuilder = 49 | new SQLAdmin.Builder( 50 | httpTransport != null ? httpTransport : new MockHttpTransport(), 51 | GsonFactory.getDefaultInstance(), 52 | credentials) 53 | .setApplicationName("Mock SQL Admin"); 54 | 55 | if (config.getAdminRootUrl() != null) { 56 | adminApiBuilder.setRootUrl(config.getAdminRootUrl()); 57 | } 58 | if (config.getAdminServicePath() != null) { 59 | adminApiBuilder.setServicePath(config.getAdminServicePath()); 60 | } 61 | if (config.getAdminQuotaProject() != null) { 62 | GoogleClientRequestInitializer clientRequestInitializer = 63 | CommonGoogleClientRequestInitializer.newBuilder() 64 | .setUserProject(config.getAdminQuotaProject()) 65 | .build(); 66 | adminApiBuilder.setGoogleClientRequestInitializer(clientRequestInitializer); 67 | } 68 | return new DefaultConnectionInfoRepository(adminApiBuilder.build()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/test/java/com/google/cloud/sql/core/SupplierCredentialFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import com.google.auth.oauth2.GoogleCredentials; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.junit.runners.JUnit4; 25 | 26 | @RunWith(JUnit4.class) 27 | public class SupplierCredentialFactoryTest { 28 | 29 | @Test 30 | public void getCredentials() { 31 | GoogleCredentials c = GoogleCredentials.create(null); 32 | SupplierCredentialFactory f = new SupplierCredentialFactory(() -> c); 33 | assertThat(f.getCredentials()).isSameInstanceAs(c); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /core/src/test/resources/sample-credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "client_id": "sample.apps.googleusercontent.com", 3 | "client_secret": "sample", 4 | "quota_project_id": "sample", 5 | "refresh_token": "sample", 6 | "access_token": "sample", 7 | "type": "authorized_user", 8 | "universe_domain": "googleapis.com" 9 | } 10 | -------------------------------------------------------------------------------- /java.header: -------------------------------------------------------------------------------- 1 | ^/\*$ 2 | ^ \* Copyright \d\d\d\d,? Google (Inc\.|LLC)$ 3 | ^ \*$ 4 | ^ \* Licensed under the Apache License, Version 2\.0 \(the "License"\);$ 5 | ^ \* you may not use this file except in compliance with the License\.$ 6 | ^ \* You may obtain a copy of the License at$ 7 | ^ \*$ 8 | ^ \*[ ]+https?://www.apache.org/licenses/LICENSE-2\.0$ 9 | ^ \*$ 10 | ^ \* Unless required by applicable law or agreed to in writing, software$ 11 | ^ \* distributed under the License is distributed on an "AS IS" BASIS,$ 12 | ^ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.$ 13 | ^ \* See the License for the specific language governing permissions and$ 14 | ^ \* limitations under the License\.$ 15 | ^ \*/$ 16 | -------------------------------------------------------------------------------- /jdbc/mariadb/src/main/java/com/google/cloud/sql/mariadb/SocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.mariadb; 18 | 19 | import com.google.cloud.sql.core.ConnectionConfig; 20 | import com.google.cloud.sql.core.InternalConnectorRegistry; 21 | import java.io.IOException; 22 | import java.net.InetAddress; 23 | import java.net.Socket; 24 | import org.mariadb.jdbc.Configuration; 25 | import org.mariadb.jdbc.util.ConfigurableSocketFactory; 26 | 27 | /** 28 | * A MariaDB {@link SocketFactory} that establishes a secure connection to a Cloud SQL instance 29 | * using ephemeral certificates. 30 | * 31 | *

The heavy lifting is done by the singleton {@link InternalConnectorRegistry} class. 32 | */ 33 | public class SocketFactory extends ConfigurableSocketFactory { 34 | 35 | static { 36 | InternalConnectorRegistry.addArtifactId("mariadb-socket-factory"); 37 | } 38 | 39 | private Configuration conf; 40 | private String host; 41 | 42 | /** Instantiate a socket factory. */ 43 | public SocketFactory() {} 44 | 45 | @Override 46 | public void setConfiguration(Configuration conf, String host) { 47 | // Ignore the hostname 48 | this.conf = conf; 49 | this.host = host; 50 | } 51 | 52 | @Override 53 | public Socket createSocket() throws IOException { 54 | try { 55 | return InternalConnectorRegistry.getInstance() 56 | .connect(ConnectionConfig.fromConnectionProperties(conf.nonMappedOptions(), host)); 57 | } catch (InterruptedException e) { 58 | throw new RuntimeException(e); 59 | } 60 | } 61 | 62 | @Override 63 | public Socket createSocket(String s, int i) { 64 | throw new UnsupportedOperationException(); 65 | } 66 | 67 | @Override 68 | public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) { 69 | throw new UnsupportedOperationException(); 70 | } 71 | 72 | @Override 73 | public Socket createSocket(InetAddress inetAddress, int i) { 74 | throw new UnsupportedOperationException(); 75 | } 76 | 77 | @Override 78 | public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) { 79 | throw new UnsupportedOperationException(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /jdbc/mysql-j-8/src/main/java/com/google/cloud/sql/mysql/SocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.mysql; 18 | 19 | import com.google.cloud.sql.core.ConnectionConfig; 20 | import com.google.cloud.sql.core.InternalConnectorRegistry; 21 | import com.mysql.cj.conf.PropertySet; 22 | import com.mysql.cj.protocol.ServerSession; 23 | import com.mysql.cj.protocol.SocketConnection; 24 | import java.io.Closeable; 25 | import java.io.IOException; 26 | import java.util.Properties; 27 | 28 | /** 29 | * A MySQL {@link SocketFactory} that establishes a secure connection to a Cloud SQL instance using 30 | * ephemeral certificates. 31 | * 32 | *

The heavy lifting is done by the singleton {@link InternalConnectorRegistry} class. 33 | */ 34 | public class SocketFactory implements com.mysql.cj.protocol.SocketFactory { 35 | 36 | static { 37 | InternalConnectorRegistry.addArtifactId("mysql-socket-factory-connector-j-8"); 38 | } 39 | 40 | @Override 41 | @SuppressWarnings("TypeParameterUnusedInFormals") 42 | public T connect( 43 | String host, int portNumber, PropertySet props, int loginTimeout) throws IOException { 44 | try { 45 | return connect(host, portNumber, props.exposeAsProperties(), loginTimeout); 46 | } catch (InterruptedException e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | 51 | /** 52 | * Implements the interface for com.mysql.cj.protocol.SocketFactory for mysql-connector-java prior 53 | * to version 8.0.13. This change is required for backwards compatibility. 54 | */ 55 | @SuppressWarnings("TypeParameterUnusedInFormals") 56 | public T connect( 57 | String host, int portNumber, Properties props, int loginTimeout) 58 | throws IOException, InterruptedException { 59 | @SuppressWarnings("unchecked") 60 | T socket = 61 | (T) 62 | InternalConnectorRegistry.getInstance() 63 | .connect(ConnectionConfig.fromConnectionProperties(props, host)); 64 | return socket; 65 | } 66 | 67 | // Cloud SQL sockets always use TLS and the socket returned by connect above is already TLS-ready. 68 | // It is fine to implement these as no-ops. 69 | @Override 70 | public void beforeHandshake() {} 71 | 72 | @Override 73 | @SuppressWarnings("TypeParameterUnusedInFormals") 74 | public T performTlsHandshake( 75 | SocketConnection socketConnection, ServerSession serverSession) throws IOException { 76 | @SuppressWarnings("unchecked") 77 | T socket = (T) socketConnection.getMysqlSocket(); 78 | return socket; 79 | } 80 | 81 | @Override 82 | public void afterHandshake() {} 83 | } 84 | -------------------------------------------------------------------------------- /license-checks.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /owlbot.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """This script is used to synthesize generated parts of this library.""" 16 | 17 | import synthtool.languages.java as java 18 | 19 | java.common_templates(excludes=[ 20 | "README.md", 21 | "CONTRIBUTING.md", 22 | ".github/auto-label.yaml", 23 | ".github/blunderbuss.yml", 24 | ".github/CODEOWNERS", 25 | ".github/ISSUE_TEMPLATE/bug_report.md", 26 | ".github/ISSUE_TEMPLATE/feature_request.md", 27 | ".github/ISSUE_TEMPLATE/support_request.md", 28 | ".github/snippet-bot.yml", 29 | ]) 30 | -------------------------------------------------------------------------------- /r2dbc/core/src/main/java/com/google/cloud/sql/core/CloudSqlConnectionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static io.r2dbc.spi.ConnectionFactoryOptions.HOST; 20 | import static io.r2dbc.spi.ConnectionFactoryOptions.PORT; 21 | 22 | import io.r2dbc.spi.Connection; 23 | import io.r2dbc.spi.ConnectionFactory; 24 | import io.r2dbc.spi.ConnectionFactoryMetadata; 25 | import io.r2dbc.spi.ConnectionFactoryOptions; 26 | import io.r2dbc.spi.ConnectionFactoryProvider; 27 | import java.util.function.Supplier; 28 | import org.reactivestreams.Publisher; 29 | import reactor.core.publisher.Mono; 30 | import reactor.util.annotation.NonNull; 31 | 32 | /** {@link ConnectionFactory} for accessing Cloud SQL instances via R2DBC protocol. */ 33 | public class CloudSqlConnectionFactory implements ConnectionFactory { 34 | 35 | public static final int SERVER_PROXY_PORT = 3307; 36 | private final Supplier supplier; 37 | private final ConnectionFactoryOptions.Builder builder; 38 | private final ConnectionConfig config; 39 | 40 | /** Creates an instance of ConnectionFactory that pulls and sets host ip before delegating. */ 41 | public CloudSqlConnectionFactory( 42 | ConnectionConfig config, 43 | Supplier supplier, 44 | ConnectionFactoryOptions.Builder builder) { 45 | this.config = config; 46 | this.supplier = supplier; 47 | this.builder = builder; 48 | } 49 | 50 | @Override 51 | @NonNull 52 | public Publisher create() { 53 | String hostIp = 54 | InternalConnectorRegistry.getInstance() 55 | .getConnectionMetadata(config) 56 | .getPreferredIpAddress(); 57 | builder.option(HOST, hostIp).option(PORT, SERVER_PROXY_PORT); 58 | 59 | return Mono.from(supplier.get().create(builder.build()).create()) 60 | .map(c -> new CloudSqlConnection(config, c)); 61 | } 62 | 63 | @Override 64 | @NonNull 65 | public ConnectionFactoryMetadata getMetadata() { 66 | String hostIp = 67 | InternalConnectorRegistry.getInstance() 68 | .getConnectionMetadata(config) 69 | .getPreferredIpAddress(); 70 | builder.option(HOST, hostIp).option(PORT, SERVER_PROXY_PORT); 71 | return supplier.get().create(builder.build()).getMetadata(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /r2dbc/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline 2 | -------------------------------------------------------------------------------- /r2dbc/mariadb/src/main/java/com/google/cloud/sql/core/GcpConnectionFactoryProviderMariadb.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static io.r2dbc.spi.ConnectionFactoryOptions.Builder; 20 | import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER; 21 | import static io.r2dbc.spi.ConnectionFactoryOptions.PROTOCOL; 22 | import static org.mariadb.r2dbc.MariadbConnectionFactoryProvider.MARIADB_DRIVER; 23 | 24 | import io.netty.handler.ssl.SslContextBuilder; 25 | import io.r2dbc.spi.ConnectionFactory; 26 | import io.r2dbc.spi.ConnectionFactoryOptions; 27 | import io.r2dbc.spi.ConnectionFactoryProvider; 28 | import java.util.function.Function; 29 | import java.util.function.UnaryOperator; 30 | import org.mariadb.r2dbc.MariadbConnectionFactoryProvider; 31 | 32 | /** {@link ConnectionFactoryProvider} for proxied access to GCP MySQL instances. */ 33 | public class GcpConnectionFactoryProviderMariadb extends GcpConnectionFactoryProvider { 34 | 35 | static { 36 | InternalConnectorRegistry.addArtifactId("cloud-sql-connector-r2dbc-mariadb"); 37 | } 38 | 39 | @Override 40 | boolean supportedProtocol(String protocol) { 41 | return protocol.equals(MARIADB_DRIVER); 42 | } 43 | 44 | @Override 45 | ConnectionFactory tcpSocketConnectionFactory( 46 | ConnectionConfig config, 47 | Builder builder, 48 | Function customizer) { 49 | 50 | // The MariaDB driver accepts the UnaryOperator interface so we need to adapt the customizer 51 | // function passed in 52 | UnaryOperator unaryCustomizer = 53 | (sslContextBuilder) -> customizer.apply(sslContextBuilder); 54 | 55 | builder 56 | .option(MariadbConnectionFactoryProvider.SSL_TUNNEL_DISABLE_HOST_VERIFICATION, true) 57 | .option(MariadbConnectionFactoryProvider.SSL_CONTEXT_BUILDER_CUSTOMIZER, unaryCustomizer) 58 | .option(MariadbConnectionFactoryProvider.TCP_KEEP_ALIVE, true) 59 | .option(MariadbConnectionFactoryProvider.SSL_MODE, "tunnel"); 60 | 61 | return new CloudSqlConnectionFactory(config, MariadbConnectionFactoryProvider::new, builder); 62 | } 63 | 64 | @Override 65 | ConnectionFactory unixSocketConnectionFactory(Builder optionBuilder, String socket) { 66 | optionBuilder.option(MariadbConnectionFactoryProvider.SOCKET, socket); 67 | return new MariadbConnectionFactoryProvider().create(optionBuilder.build()); 68 | } 69 | 70 | @Override 71 | Builder createBuilder(ConnectionFactoryOptions connectionFactoryOptions) { 72 | return connectionFactoryOptions 73 | .mutate() 74 | .option(DRIVER, MARIADB_DRIVER) 75 | .option(PROTOCOL, "none"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /r2dbc/mariadb/src/main/resources/META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider: -------------------------------------------------------------------------------- 1 | com.google.cloud.sql.core.GcpConnectionFactoryProviderMariadb 2 | -------------------------------------------------------------------------------- /r2dbc/mariadb/src/test/java/com/google/cloud/sql/core/R2dbcMariadbIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import io.r2dbc.pool.ConnectionPool; 24 | import io.r2dbc.pool.ConnectionPoolConfiguration; 25 | import io.r2dbc.spi.ConnectionFactories; 26 | import io.r2dbc.spi.ConnectionFactory; 27 | import java.time.LocalTime; 28 | import java.util.List; 29 | import java.util.concurrent.TimeUnit; 30 | import org.junit.Before; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | import org.junit.rules.Timeout; 34 | import org.junit.runner.RunWith; 35 | import org.junit.runners.JUnit4; 36 | import reactor.core.publisher.Mono; 37 | 38 | @RunWith(JUnit4.class) 39 | public class R2dbcMariadbIntegrationTests { 40 | 41 | private static final ImmutableList requiredEnvVars = 42 | ImmutableList.of("MYSQL_USER", "MYSQL_PASS", "MYSQL_DB", "MYSQL_CONNECTION_NAME"); 43 | 44 | private static final String CONNECTION_NAME = System.getenv("MYSQL_CONNECTION_NAME"); 45 | private static final String DB_NAME = System.getenv("MYSQL_DB"); 46 | private static final String DB_USER = System.getenv("MYSQL_USER"); 47 | private static final String DB_PASSWORD = System.getenv("MYSQL_PASS"); 48 | private static final String IP_TYPE = 49 | System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE"); 50 | 51 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 52 | 53 | private ConnectionPool connectionPool; 54 | 55 | @Before 56 | public void setUpPool() { 57 | // Check that required env vars are set 58 | requiredEnvVars.forEach( 59 | (varName) -> 60 | assertWithMessage( 61 | String.format( 62 | "Environment variable '%s' must be set to perform these tests.", varName)) 63 | .that(System.getenv(varName)) 64 | .isNotEmpty()); 65 | 66 | // Set up URL parameters 67 | String r2dbcURL = 68 | String.format( 69 | "r2dbc:gcp:mariadb://%s:%s@%s/%s?ipTypes=%s", 70 | DB_USER, DB_PASSWORD, CONNECTION_NAME, DB_NAME, IP_TYPE); 71 | 72 | // Initialize connection pool 73 | ConnectionFactory connectionFactory = ConnectionFactories.get(r2dbcURL); 74 | ConnectionPoolConfiguration configuration = 75 | ConnectionPoolConfiguration.builder(connectionFactory).build(); 76 | 77 | this.connectionPool = new ConnectionPool(configuration); 78 | } 79 | 80 | @Test 81 | public void pooledConnectionTest() { 82 | List rows = 83 | Mono.from(this.connectionPool.create()) 84 | .flatMapMany(connection -> connection.createStatement("SELECT NOW() as TS").execute()) 85 | .flatMap(result -> result.map((r, meta) -> r.get("TS", LocalTime.class))) 86 | .collectList() 87 | .block(); 88 | 89 | assertThat(rows.size()).isEqualTo(1); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /r2dbc/mysql/src/main/java/com/google/cloud/sql/core/GcpConnectionFactoryProviderMysql.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static io.r2dbc.spi.ConnectionFactoryOptions.Builder; 20 | import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER; 21 | 22 | import io.asyncer.r2dbc.mysql.MySqlConnectionFactoryProvider; 23 | import io.asyncer.r2dbc.mysql.constant.SslMode; 24 | import io.netty.handler.ssl.SslContextBuilder; 25 | import io.r2dbc.spi.ConnectionFactory; 26 | import io.r2dbc.spi.ConnectionFactoryOptions; 27 | import io.r2dbc.spi.ConnectionFactoryProvider; 28 | import java.util.function.Function; 29 | 30 | /** {@link ConnectionFactoryProvider} for proxied access to GCP MySQL instances. */ 31 | public class GcpConnectionFactoryProviderMysql extends GcpConnectionFactoryProvider { 32 | 33 | /** MySQL driver option value. */ 34 | private static final String MYSQL_DRIVER = "mysql"; 35 | 36 | static { 37 | InternalConnectorRegistry.addArtifactId("cloud-sql-connector-r2dbc-mysql"); 38 | } 39 | 40 | @Override 41 | boolean supportedProtocol(String protocol) { 42 | return protocol.equals(MYSQL_DRIVER); 43 | } 44 | 45 | @Override 46 | ConnectionFactory tcpSocketConnectionFactory( 47 | ConnectionConfig config, 48 | Builder builder, 49 | Function customizer) { 50 | builder 51 | .option(MySqlConnectionFactoryProvider.SSL_CONTEXT_BUILDER_CUSTOMIZER, customizer) 52 | .option(MySqlConnectionFactoryProvider.SSL_MODE, SslMode.TUNNEL) 53 | .option(MySqlConnectionFactoryProvider.TCP_NO_DELAY, true) 54 | .option(MySqlConnectionFactoryProvider.TCP_KEEP_ALIVE, true); 55 | 56 | return new CloudSqlConnectionFactory(config, MySqlConnectionFactoryProvider::new, builder); 57 | } 58 | 59 | @Override 60 | ConnectionFactory unixSocketConnectionFactory(Builder optionBuilder, String socket) { 61 | optionBuilder.option(MySqlConnectionFactoryProvider.UNIX_SOCKET, socket); 62 | return new MySqlConnectionFactoryProvider().create(optionBuilder.build()); 63 | } 64 | 65 | @Override 66 | Builder createBuilder(ConnectionFactoryOptions connectionFactoryOptions) { 67 | return connectionFactoryOptions.mutate().option(DRIVER, MYSQL_DRIVER); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /r2dbc/mysql/src/main/resources/META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider: -------------------------------------------------------------------------------- 1 | com.google.cloud.sql.core.GcpConnectionFactoryProviderMysql 2 | -------------------------------------------------------------------------------- /r2dbc/mysql/src/test/java/com/google/cloud/sql/core/R2dbcMysqlIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import io.r2dbc.pool.ConnectionPool; 24 | import io.r2dbc.pool.ConnectionPoolConfiguration; 25 | import io.r2dbc.spi.ConnectionFactories; 26 | import io.r2dbc.spi.ConnectionFactory; 27 | import java.time.Instant; 28 | import java.util.List; 29 | import java.util.concurrent.TimeUnit; 30 | import org.junit.Before; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | import org.junit.rules.Timeout; 34 | import org.junit.runner.RunWith; 35 | import org.junit.runners.JUnit4; 36 | import reactor.core.publisher.Mono; 37 | 38 | @RunWith(JUnit4.class) 39 | public class R2dbcMysqlIntegrationTests { 40 | 41 | private static final ImmutableList requiredEnvVars = 42 | ImmutableList.of("MYSQL_USER", "MYSQL_PASS", "MYSQL_DB", "MYSQL_CONNECTION_NAME"); 43 | 44 | private static final String CONNECTION_NAME = System.getenv("MYSQL_CONNECTION_NAME"); 45 | private static final String DB_NAME = System.getenv("MYSQL_DB"); 46 | private static final String DB_USER = System.getenv("MYSQL_USER"); 47 | private static final String DB_PASSWORD = System.getenv("MYSQL_PASS"); 48 | private static final String IP_TYPE = 49 | System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE"); 50 | 51 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 52 | 53 | private ConnectionPool connectionPool; 54 | 55 | @Before 56 | public void setUpPool() { 57 | // Check that required env vars are set 58 | requiredEnvVars.forEach( 59 | (varName) -> 60 | assertWithMessage( 61 | String.format( 62 | "Environment variable '%s' must be set to perform these tests.", varName)) 63 | .that(System.getenv(varName)) 64 | .isNotEmpty()); 65 | 66 | // Set up URL parameters 67 | String r2dbcURL = 68 | String.format( 69 | "r2dbc:gcp:mysql://%s:%s@%s/%s?ipTypes=%s", 70 | DB_USER, DB_PASSWORD, CONNECTION_NAME, DB_NAME, IP_TYPE); 71 | 72 | // Initialize connection pool 73 | ConnectionFactory connectionFactory = ConnectionFactories.get(r2dbcURL); 74 | ConnectionPoolConfiguration configuration = 75 | ConnectionPoolConfiguration.builder(connectionFactory).build(); 76 | 77 | this.connectionPool = new ConnectionPool(configuration); 78 | } 79 | 80 | @Test 81 | public void pooledConnectionTest() { 82 | List rows = 83 | Mono.from(this.connectionPool.create()) 84 | .flatMapMany(connection -> connection.createStatement("SELECT NOW() as TS").execute()) 85 | .flatMap(result -> result.map((r, meta) -> r.get("TS", Instant.class))) 86 | .collectList() 87 | .block(); 88 | 89 | assertThat(rows.size()).isEqualTo(1); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /r2dbc/postgres/src/main/java/com/google/cloud/sql/core/GcpConnectionFactoryProviderPostgres.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static io.r2dbc.spi.ConnectionFactoryOptions.Builder; 20 | import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER; 21 | 22 | import io.netty.handler.ssl.SslContextBuilder; 23 | import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider; 24 | import io.r2dbc.postgresql.client.SSLMode; 25 | import io.r2dbc.spi.ConnectionFactory; 26 | import io.r2dbc.spi.ConnectionFactoryOptions; 27 | import io.r2dbc.spi.ConnectionFactoryProvider; 28 | import java.util.function.Function; 29 | 30 | /** {@link ConnectionFactoryProvider} for proxied access to GCP Postgres instances. */ 31 | public class GcpConnectionFactoryProviderPostgres extends GcpConnectionFactoryProvider { 32 | 33 | /** Postgres driver option value. */ 34 | private static final String POSTGRESQL_DRIVER = "postgresql"; 35 | /** Legacy postgres driver option value. */ 36 | private static final String LEGACY_POSTGRESQL_DRIVER = "postgres"; 37 | 38 | static { 39 | InternalConnectorRegistry.addArtifactId("cloud-sql-connector-r2dbc-postgres"); 40 | } 41 | 42 | @Override 43 | boolean supportedProtocol(String protocol) { 44 | return protocol.equals(POSTGRESQL_DRIVER) || protocol.equals(LEGACY_POSTGRESQL_DRIVER); 45 | } 46 | 47 | @Override 48 | ConnectionFactory tcpSocketConnectionFactory( 49 | ConnectionConfig config, 50 | Builder builder, 51 | Function customizer) { 52 | builder 53 | .option(PostgresqlConnectionFactoryProvider.SSL_CONTEXT_BUILDER_CUSTOMIZER, customizer) 54 | .option(PostgresqlConnectionFactoryProvider.SSL_MODE, SSLMode.TUNNEL) 55 | .option(PostgresqlConnectionFactoryProvider.TCP_NODELAY, true) 56 | .option(PostgresqlConnectionFactoryProvider.TCP_KEEPALIVE, true); 57 | 58 | return new CloudSqlConnectionFactory(config, PostgresqlConnectionFactoryProvider::new, builder); 59 | } 60 | 61 | @Override 62 | ConnectionFactory unixSocketConnectionFactory(Builder optionBuilder, String socket) { 63 | optionBuilder.option(PostgresqlConnectionFactoryProvider.SOCKET, socket); 64 | return new PostgresqlConnectionFactoryProvider().create(optionBuilder.build()); 65 | } 66 | 67 | @Override 68 | Builder createBuilder(ConnectionFactoryOptions connectionFactoryOptions) { 69 | return connectionFactoryOptions.mutate().option(DRIVER, POSTGRESQL_DRIVER); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /r2dbc/postgres/src/main/resources/META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider: -------------------------------------------------------------------------------- 1 | com.google.cloud.sql.core.GcpConnectionFactoryProviderPostgres 2 | -------------------------------------------------------------------------------- /r2dbc/postgres/src/test/java/com/google/cloud/sql/core/R2dbcPostgresIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import io.r2dbc.pool.ConnectionPool; 24 | import io.r2dbc.pool.ConnectionPoolConfiguration; 25 | import io.r2dbc.spi.ConnectionFactories; 26 | import io.r2dbc.spi.ConnectionFactory; 27 | import java.time.Instant; 28 | import java.util.List; 29 | import java.util.concurrent.TimeUnit; 30 | import org.junit.Before; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | import org.junit.rules.Timeout; 34 | import org.junit.runner.RunWith; 35 | import org.junit.runners.JUnit4; 36 | import reactor.core.publisher.Mono; 37 | 38 | @RunWith(JUnit4.class) 39 | public class R2dbcPostgresIntegrationTests { 40 | 41 | private static final String CONNECTION_NAME = System.getenv("POSTGRES_CONNECTION_NAME"); 42 | private static final String DB_NAME = System.getenv("POSTGRES_DB"); 43 | private static final String DB_USER = System.getenv("POSTGRES_USER"); 44 | private static final String DB_PASSWORD = System.getenv("POSTGRES_PASS"); 45 | private static final String IP_TYPE = 46 | System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE"); 47 | private static final ImmutableList requiredEnvVars = 48 | ImmutableList.of("POSTGRES_USER", "POSTGRES_PASS", "POSTGRES_DB", "POSTGRES_CONNECTION_NAME"); 49 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 50 | 51 | private ConnectionFactory connectionPool; 52 | 53 | @Before 54 | public void setUpPool() { 55 | // Check that required env vars are set 56 | requiredEnvVars.forEach( 57 | (varName) -> 58 | assertWithMessage( 59 | String.format( 60 | "Environment variable '%s' must be set to perform these tests.", varName)) 61 | .that(System.getenv(varName)) 62 | .isNotEmpty()); 63 | 64 | // Set up URL parameters 65 | String r2dbcURL = 66 | String.format( 67 | "r2dbc:gcp:postgres://%s:%s@%s/%s?ipTypes=%s", 68 | DB_USER, DB_PASSWORD, CONNECTION_NAME, DB_NAME, IP_TYPE); 69 | 70 | // Initialize connection pool 71 | ConnectionFactory connectionFactory = ConnectionFactories.get(r2dbcURL); 72 | ConnectionPoolConfiguration configuration = 73 | ConnectionPoolConfiguration.builder(connectionFactory).build(); 74 | 75 | this.connectionPool = new ConnectionPool(configuration); 76 | } 77 | 78 | @Test 79 | public void pooledConnectionTest() { 80 | List rows = 81 | Mono.from(this.connectionPool.create()) 82 | .flatMapMany(connection -> connection.createStatement("SELECT NOW() as TS").execute()) 83 | .flatMap(result -> result.map((r, meta) -> r.get("TS", Instant.class))) 84 | .collectList() 85 | .block(); 86 | 87 | assertThat(rows.size()).isEqualTo(1); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /r2dbc/postgres/src/test/java/com/google/cloud/sql/core/R2dbcPostgresPoolRemoteValidationIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import io.r2dbc.pool.ConnectionPool; 24 | import io.r2dbc.pool.ConnectionPoolConfiguration; 25 | import io.r2dbc.spi.ConnectionFactories; 26 | import io.r2dbc.spi.ConnectionFactory; 27 | import io.r2dbc.spi.ValidationDepth; 28 | import java.time.Instant; 29 | import java.util.List; 30 | import java.util.concurrent.TimeUnit; 31 | import org.junit.Before; 32 | import org.junit.Rule; 33 | import org.junit.Test; 34 | import org.junit.rules.Timeout; 35 | import org.junit.runner.RunWith; 36 | import org.junit.runners.JUnit4; 37 | import reactor.core.publisher.Mono; 38 | 39 | @RunWith(JUnit4.class) 40 | public class R2dbcPostgresPoolRemoteValidationIntegrationTests { 41 | 42 | private static final String CONNECTION_NAME = System.getenv("POSTGRES_CONNECTION_NAME"); 43 | private static final String DB_NAME = System.getenv("POSTGRES_DB"); 44 | private static final String DB_USER = System.getenv("POSTGRES_USER"); 45 | private static final String DB_PASSWORD = System.getenv("POSTGRES_PASS"); 46 | private static final String IP_TYPE = 47 | System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE"); 48 | private static final ImmutableList requiredEnvVars = 49 | ImmutableList.of("POSTGRES_USER", "POSTGRES_PASS", "POSTGRES_DB", "POSTGRES_CONNECTION_NAME"); 50 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 51 | 52 | private ConnectionFactory connectionPool; 53 | 54 | @Before 55 | public void setUpPool() { 56 | // Check that required env vars are set 57 | requiredEnvVars.forEach( 58 | (varName) -> 59 | assertWithMessage( 60 | String.format( 61 | "Environment variable '%s' must be set to perform these tests.", varName)) 62 | .that(System.getenv(varName)) 63 | .isNotEmpty()); 64 | 65 | // Set up URL parameters 66 | String r2dbcURL = 67 | String.format( 68 | "r2dbc:gcp:postgres://%s:%s@%s/%s?ipTypes=%s", 69 | DB_USER, DB_PASSWORD, CONNECTION_NAME, DB_NAME, IP_TYPE); 70 | 71 | // Initialize connection pool with REMOTE validation 72 | ConnectionFactory connectionFactory = ConnectionFactories.get(r2dbcURL); 73 | ConnectionPoolConfiguration configuration = 74 | ConnectionPoolConfiguration.builder(connectionFactory) 75 | .validationDepth(ValidationDepth.REMOTE) 76 | .build(); 77 | 78 | this.connectionPool = new ConnectionPool(configuration); 79 | } 80 | 81 | @Test 82 | public void pooledConnectionTest() { 83 | List rows = 84 | Mono.from(this.connectionPool.create()) 85 | .flatMapMany(connection -> connection.createStatement("SELECT NOW() as TS").execute()) 86 | .flatMap(result -> result.map((r, meta) -> r.get("TS", Instant.class))) 87 | .collectList() 88 | .block(); 89 | 90 | assertThat(rows.size()).isEqualTo(1); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /r2dbc/sqlserver/src/main/java/com/google/cloud/sql/core/GcpConnectionFactoryProviderMssql.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static io.r2dbc.spi.ConnectionFactoryOptions.Builder; 20 | import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER; 21 | 22 | import io.netty.handler.ssl.SslContextBuilder; 23 | import io.r2dbc.mssql.MssqlConnectionFactoryProvider; 24 | import io.r2dbc.spi.ConnectionFactory; 25 | import io.r2dbc.spi.ConnectionFactoryOptions; 26 | import io.r2dbc.spi.ConnectionFactoryProvider; 27 | import java.util.function.Function; 28 | 29 | /** {@link ConnectionFactoryProvider} for proxied access to GCP MsSQL instances. */ 30 | public class GcpConnectionFactoryProviderMssql extends GcpConnectionFactoryProvider { 31 | 32 | static { 33 | InternalConnectorRegistry.addArtifactId("cloud-sql-connector-r2dbc-mssql"); 34 | } 35 | 36 | /** MsSQL driver option value. */ 37 | private static final String MSSQL_DRIVER = "mssql"; 38 | 39 | @Override 40 | boolean supportedProtocol(String protocol) { 41 | return protocol.equals(MSSQL_DRIVER); 42 | } 43 | 44 | @Override 45 | ConnectionFactory tcpSocketConnectionFactory( 46 | ConnectionConfig config, 47 | Builder builder, 48 | Function customizer) { 49 | builder 50 | .option(MssqlConnectionFactoryProvider.SSL_TUNNEL, customizer) 51 | .option(MssqlConnectionFactoryProvider.TCP_NODELAY, true) 52 | .option(MssqlConnectionFactoryProvider.TCP_KEEPALIVE, true); 53 | 54 | return new CloudSqlConnectionFactory(config, MssqlConnectionFactoryProvider::new, builder); 55 | } 56 | 57 | @Override 58 | ConnectionFactory unixSocketConnectionFactory(Builder optionBuilder, String socket) { 59 | throw new RuntimeException("UNIX socket connections are not supported"); 60 | } 61 | 62 | @Override 63 | Builder createBuilder(ConnectionFactoryOptions connectionFactoryOptions) { 64 | return connectionFactoryOptions.mutate().option(DRIVER, MSSQL_DRIVER); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /r2dbc/sqlserver/src/main/resources/META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider: -------------------------------------------------------------------------------- 1 | com.google.cloud.sql.core.GcpConnectionFactoryProviderMssql 2 | -------------------------------------------------------------------------------- /r2dbc/sqlserver/src/test/java/com/google/cloud/sql/core/R2dbcSqlserverIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.sql.core; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static com.google.common.truth.Truth.assertWithMessage; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import io.r2dbc.pool.ConnectionPool; 24 | import io.r2dbc.pool.ConnectionPoolConfiguration; 25 | import io.r2dbc.spi.ConnectionFactories; 26 | import io.r2dbc.spi.ConnectionFactory; 27 | import java.util.List; 28 | import java.util.concurrent.TimeUnit; 29 | import org.junit.Before; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.junit.rules.Timeout; 33 | import org.junit.runner.RunWith; 34 | import org.junit.runners.JUnit4; 35 | import reactor.core.publisher.Mono; 36 | 37 | @RunWith(JUnit4.class) 38 | public class R2dbcSqlserverIntegrationTests { 39 | 40 | private static final ImmutableList requiredEnvVars = 41 | ImmutableList.of( 42 | "SQLSERVER_USER", "SQLSERVER_PASS", "SQLSERVER_DB", "SQLSERVER_CONNECTION_NAME"); 43 | 44 | private static final String CONNECTION_NAME = System.getenv("SQLSERVER_CONNECTION_NAME"); 45 | private static final String DB_NAME = System.getenv("SQLSERVER_DB"); 46 | private static final String DB_USER = System.getenv("SQLSERVER_USER"); 47 | private static final String DB_PASSWORD = System.getenv("SQLSERVER_PASS"); 48 | private static final String IP_TYPE = 49 | System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE"); 50 | 51 | @Rule public Timeout globalTimeout = new Timeout(80, TimeUnit.SECONDS); 52 | 53 | private ConnectionPool connectionPool; 54 | 55 | @Before 56 | public void setUpPool() { 57 | // Check that required env vars are set 58 | requiredEnvVars.forEach( 59 | (varName) -> 60 | assertWithMessage( 61 | String.format( 62 | "Environment variable '%s' must be set to perform these tests.", varName)) 63 | .that(System.getenv(varName)) 64 | .isNotEmpty()); 65 | 66 | // Set up URL parameters 67 | String r2dbcURL = 68 | String.format( 69 | "r2dbc:gcp:mssql://%s:%s@%s/%s?ipTypes=%s", 70 | DB_USER, DB_PASSWORD, CONNECTION_NAME, DB_NAME, IP_TYPE); 71 | 72 | // Initialize connection pool 73 | ConnectionFactory connectionFactory = ConnectionFactories.get(r2dbcURL); 74 | ConnectionPoolConfiguration configuration = 75 | ConnectionPoolConfiguration.builder(connectionFactory).build(); 76 | 77 | this.connectionPool = new ConnectionPool(configuration); 78 | } 79 | 80 | @Test 81 | public void pooledConnectionTest() { 82 | List rows = 83 | Mono.from(this.connectionPool.create()) 84 | .flatMapMany(connection -> connection.createStatement("SELECT 1 as TS").execute()) 85 | .flatMap(result -> result.map((r, meta) -> r.get("TS", Integer.class))) 86 | .collectList() 87 | .block(); 88 | 89 | assertThat(rows.size()).isEqualTo(1); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /versions.txt: -------------------------------------------------------------------------------- 1 | # Format: 2 | # module:released-version:current-version 3 | 4 | jdbc-socket-factory-parent:1.25.1:1.25.2-SNAPSHOT 5 | jdbc-socket-factory-core:1.25.1:1.25.2-SNAPSHOT 6 | mariadb-socket-factory:1.25.1:1.25.2-SNAPSHOT 7 | mysql-socket-factory:1.25.1:1.25.2-SNAPSHOT 8 | mysql-socket-factory-connector-j-8:1.25.1:1.25.2-SNAPSHOT 9 | postgres-socket-factory:1.25.1:1.25.2-SNAPSHOT 10 | cloud-sql-connector-jdbc-sqlserver:1.25.1:1.25.2-SNAPSHOT 11 | cloud-sql-connector-r2dbc-core:1.25.1:1.25.2-SNAPSHOT 12 | cloud-sql-connector-r2dbc-mariadb:1.25.1:1.25.2-SNAPSHOT 13 | cloud-sql-connector-r2dbc-mysql:1.25.1:1.25.2-SNAPSHOT 14 | cloud-sql-connector-r2dbc-postgres:1.25.1:1.25.2-SNAPSHOT 15 | cloud-sql-connector-r2dbc-sqlserver:1.25.1:1.25.2-SNAPSHOT 16 | --------------------------------------------------------------------------------