-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
baserer seg i all hovedgrad på defaults på nais-plattformen.
- Loading branch information
1 parent
047802e
commit 42fdc22
Showing
6 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
Naisful Postgres | ||
================ | ||
|
||
Enkel måte å komme kjapt i gang med en databasetilkobling. | ||
|
||
Auto-detecter miljøvariabler og lager JDBC-url for deg. | ||
|
||
## Fra miljøvariabler | ||
```kotlin | ||
|
||
// lager jdbc-url fra env | ||
val jdbcUrl = defaultJdbcUrl() | ||
``` | ||
|
||
Miljøvariabler som slutter på `_HOST`, `_USERNAME` osv. vil bli brukt. | ||
Hvis appen har flere slike miljøvariabler så kan de skilles ved å spesifisere prefix: | ||
```kotlin | ||
ConnectionConfigFactory.Env(envVarPrefix = "DB") | ||
``` | ||
Da vil det søkes etter `DB_HOST`, `DB_USERNAME`, osv. | ||
|
||
## Fra mount path | ||
Hvis du vil laste sql secrets fra mount path så kan de konfigureres slik i nais.yml. | ||
```yml | ||
filesFrom: | ||
- secret: google-sql-APP | ||
mountPath: /var/run/secrets/sql/APP | ||
``` | ||
og så gjøre dette i kotlin: | ||
```kotlin | ||
// lager jdbc-url fra mount path | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.MountPath("/var/run/secrets/sql/APP")) | ||
``` | ||
|
||
## Google SocketFactory | ||
|
||
Det er også en variant som vil konfe opp `com.google.cloud.sql.postgres.SocketFactory` i JDBC-url: | ||
```kotlin | ||
val jdbcUrl = jdbcUrlWithGoogleSocketFactory("dbinstance", ConnectionConfigFactory.Env()) | ||
``` |
Empty file.
92 changes: 92 additions & 0 deletions
92
...-postgres/src/main/kotlin/com/github/navikt/tbd_libs/naisful/postgres/DataSourceConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package com.github.navikt.tbd_libs.naisful.postgres | ||
|
||
import kotlin.collections.component1 | ||
import kotlin.collections.component2 | ||
import kotlin.collections.plus | ||
import kotlin.io.path.Path | ||
import kotlin.io.path.listDirectoryEntries | ||
import kotlin.io.path.name | ||
import kotlin.io.path.readText | ||
|
||
|
||
/** | ||
* bruker _JDBC_URL hvis den er satt, ellers bygges opp en jdbc-url: | ||
* @see <a href="https://doc.nais.io/persistence/postgres/reference/?h=jdbc#database-connnection">nais doc</a> | ||
*/ | ||
fun defaultJdbcUrl(metode: ConnectionConfigFactory = ConnectionConfigFactory.Env(), options: Map<String, String> = emptyMap()): String? { | ||
return metode.buildJdbcUrl(options) | ||
} | ||
|
||
/** | ||
* bruker _JDBC_URL hvis den er satt, ellers bygges opp en jdbc-url med gitte options. | ||
* det betyr at socketFactory kun brukes hvis _JDBC_URL ikke finnes | ||
* | ||
* @see <a href="https://doc.nais.io/persistence/postgres/reference/?h=jdbc#database-connnection">nais doc</a> | ||
*/ | ||
fun jdbcUrlWithGoogleSocketFactory(databaseInstance: String, metode: ConnectionConfigFactory, gcpTeamProjectId: String = System.getenv("GCP_TEAM_PROJECT_ID"), databaseRegion: String = "europe-north1"): String? { | ||
return defaultJdbcUrl(metode, mapOf( | ||
"socketFactory" to "com.google.cloud.sql.postgres.SocketFactory", | ||
"cloudSqlInstance" to "$gcpTeamProjectId:$databaseRegion:$databaseInstance" | ||
)) | ||
} | ||
|
||
sealed class ConnectionConfigFactory { | ||
abstract fun buildJdbcUrl(options: Map<String, String>): String? | ||
|
||
|
||
data class Env(val env: Map<String, String> = System.getenv(), val envVarPrefix: String? = null) : ConnectionConfigFactory() { | ||
override fun buildJdbcUrl(options: Map<String, String>): String? { | ||
return buildJdbcUrl(options) { key -> | ||
env.getKeySuffixOrNull(envVarPrefix, key) | ||
} | ||
} | ||
} | ||
data class MountPath(val path: String) : ConnectionConfigFactory() { | ||
override fun buildJdbcUrl(options: Map<String, String>): String? { | ||
val secretsPath = Path(path).listDirectoryEntries() | ||
return buildJdbcUrl(options) { key -> | ||
secretsPath.firstOrNull { it.name.endsWith(key) }?.readText() | ||
} | ||
} | ||
} | ||
|
||
private companion object { | ||
private fun buildJdbcUrl(options: Map<String, String>, strategi: (String) -> String?): String? { | ||
val jdbcUrlFromPlatform = strategi("_JDBC_URL") | ||
if (jdbcUrlFromPlatform != null) return jdbcUrlFromPlatform | ||
|
||
val hostname = strategi("_HOST") ?: return null | ||
val port = strategi("_PORT")?.toInt() ?: return null | ||
val databaseName = strategi("_DATABASE") ?: return null | ||
val username = strategi("_USERNAME") ?: return null | ||
val password = strategi("_PASSWORD") ?: return null | ||
|
||
val sslOptions = buildMap { | ||
strategi("_SSLCERT")?.also { this["sslcert"] = it } | ||
strategi("_SSLROOTCERT")?.also { this["sslrootcert"] = it } | ||
strategi("_SSLKEY_PK8")?.also { this["sslkey"] = it } | ||
strategi("_SSLMODE")?.also { this["sslmode"] = it } | ||
} | ||
|
||
return buildPostgresCompliantJdbcUrl(hostname, port, databaseName, username, password, options + sslOptions) | ||
} | ||
} | ||
} | ||
|
||
fun Map<String, String>.getKeySuffixOrNull(prefix: String?, suffix: String): String? { | ||
val searchKey = "${prefix ?: ""}$suffix" | ||
return entries.firstOrNull { (k, _) -> k.endsWith(searchKey) }?.value | ||
} | ||
|
||
private fun buildPostgresCompliantJdbcUrl(hostname: String, port: Int, databaseName: String, username: String, password: String, options: Map<String, String> = emptyMap()): String { | ||
val defaultOptions = mapOf( | ||
"user" to username, | ||
"password" to password | ||
) | ||
val optionsString = optionsString(defaultOptions + options) | ||
return "jdbc:postgresql://$hostname:$port/$databaseName?$optionsString" | ||
} | ||
|
||
private fun optionsString(options: Map<String, String>): String { | ||
return (options).entries.joinToString(separator = "&") { (k, v) -> "$k=$v" } | ||
} |
80 changes: 80 additions & 0 deletions
80
...es/src/test/kotlin/com/github/navikt/tbd_libs/naisful/postgres/DataSourceConfigEnvTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.github.navikt.tbd_libs.naisful.postgres | ||
|
||
import org.junit.jupiter.api.Assertions.* | ||
import org.junit.jupiter.api.Test | ||
|
||
class DataSourceConfigEnvTest { | ||
|
||
@Test | ||
fun `default jdbc url`() { | ||
val fakeEnv = mapOf( | ||
"DB_HOST" to "localhost", | ||
"DB_PORT" to "5432", | ||
"DB_DATABASE" to "postgres", | ||
"DB_USERNAME" to "username", | ||
"DB_PASSWORD" to "secret", | ||
) | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.Env(fakeEnv)) | ||
assertEquals("jdbc:postgresql://localhost:5432/postgres?user=username&password=secret", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - jdbc_url set`() { | ||
val fakeEnv = mapOf( | ||
"DB_HOST" to "localhost", | ||
"DB_PORT" to "5432", | ||
"DB_DATABASE" to "postgres", | ||
"DB_USERNAME" to "username", | ||
"DB_PASSWORD" to "secret", | ||
"DB_JDBC_URL" to "jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", | ||
) | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.Env(fakeEnv)) | ||
assertEquals("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - env with prefix`() { | ||
val fakeEnv = mapOf( | ||
"CONFLICTING_HOST" to "remote_ip", | ||
"CONFLICTING_PORT" to "2345", | ||
"CONFLICTING_DATABASE" to "dev-db", | ||
"CONFLICTING_USERNAME" to "willy", | ||
"CONFLICTING_PASSWORD" to "wonka", | ||
|
||
"DB_HOST" to "localhost", | ||
"DB_PORT" to "5432", | ||
"DB_DATABASE" to "postgres", | ||
"DB_USERNAME" to "username", | ||
"DB_PASSWORD" to "secret", | ||
) | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.Env(fakeEnv, envVarPrefix = "DB")) | ||
assertEquals("jdbc:postgresql://localhost:5432/postgres?user=username&password=secret", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - google factory`() { | ||
val fakeEnv = mapOf( | ||
"DB_HOST" to "localhost", | ||
"DB_PORT" to "5432", | ||
"DB_DATABASE" to "postgres", | ||
"DB_USERNAME" to "username", | ||
"DB_PASSWORD" to "secret", | ||
) | ||
val jdbcUrl = jdbcUrlWithGoogleSocketFactory("dbinstance", ConnectionConfigFactory.Env(fakeEnv), gcpTeamProjectId = "project_id") | ||
assertEquals("jdbc:postgresql://localhost:5432/postgres?user=username&password=secret&socketFactory=com.google.cloud.sql.postgres.SocketFactory&cloudSqlInstance=project_id:europe-north1:dbinstance", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - google factory - with jdbc_url set`() { | ||
val fakeEnv = mapOf( | ||
"DB_HOST" to "localhost", | ||
"DB_PORT" to "5432", | ||
"DB_DATABASE" to "postgres", | ||
"DB_USERNAME" to "username", | ||
"DB_PASSWORD" to "secret", | ||
"DB_JDBC_URL" to "jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", | ||
) | ||
val jdbcUrl = jdbcUrlWithGoogleSocketFactory("dbinstance", ConnectionConfigFactory.Env(fakeEnv), gcpTeamProjectId = "project_id") | ||
assertEquals("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", jdbcUrl) | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
.../test/kotlin/com/github/navikt/tbd_libs/naisful/postgres/DataSourceConfigMountPathTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.github.navikt.tbd_libs.naisful.postgres | ||
|
||
import org.junit.jupiter.api.Assertions.* | ||
import org.junit.jupiter.api.Test | ||
import org.junit.jupiter.api.io.TempDir | ||
import java.nio.file.Path | ||
import kotlin.io.path.writeText | ||
|
||
class DataSourceConfigMountPathTest { | ||
|
||
@Test | ||
fun `default jdbc url - env`(@TempDir tempDir: Path) { | ||
tempDir.resolve("DB_HOST").writeText("localhost") | ||
tempDir.resolve("DB_PORT").writeText("5432") | ||
tempDir.resolve("DB_DATABASE").writeText("postgres") | ||
tempDir.resolve("DB_USERNAME").writeText("username") | ||
tempDir.resolve("DB_PASSWORD").writeText("secret") | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.MountPath(tempDir.toString())) | ||
assertEquals("jdbc:postgresql://localhost:5432/postgres?user=username&password=secret", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - jdbc_url set`(@TempDir tempDir: Path) { | ||
tempDir.resolve("DB_HOST").writeText("localhost") | ||
tempDir.resolve("DB_PORT").writeText("5432") | ||
tempDir.resolve("DB_DATABASE").writeText("postgres") | ||
tempDir.resolve("DB_USERNAME").writeText("username") | ||
tempDir.resolve("DB_PASSWORD").writeText("secret") | ||
tempDir.resolve("DB_JDBC_URL").writeText("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar") | ||
val jdbcUrl = defaultJdbcUrl(ConnectionConfigFactory.MountPath(tempDir.toString())) | ||
assertEquals("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - google factory`(@TempDir tempDir: Path) { | ||
tempDir.resolve("DB_HOST").writeText("localhost") | ||
tempDir.resolve("DB_PORT").writeText("5432") | ||
tempDir.resolve("DB_DATABASE").writeText("postgres") | ||
tempDir.resolve("DB_USERNAME").writeText("username") | ||
tempDir.resolve("DB_PASSWORD").writeText("secret") | ||
val jdbcUrl = jdbcUrlWithGoogleSocketFactory("dbinstance", ConnectionConfigFactory.MountPath(tempDir.toString()), gcpTeamProjectId = "project_id") | ||
assertEquals("jdbc:postgresql://localhost:5432/postgres?user=username&password=secret&socketFactory=com.google.cloud.sql.postgres.SocketFactory&cloudSqlInstance=project_id:europe-north1:dbinstance", jdbcUrl) | ||
} | ||
|
||
@Test | ||
fun `default jdbc url - google factory - with jdbc_url set`(@TempDir tempDir: Path) { | ||
tempDir.resolve("DB_HOST").writeText("localhost") | ||
tempDir.resolve("DB_PORT").writeText("5432") | ||
tempDir.resolve("DB_DATABASE").writeText("postgres") | ||
tempDir.resolve("DB_USERNAME").writeText("username") | ||
tempDir.resolve("DB_PASSWORD").writeText("secret") | ||
tempDir.resolve("DB_JDBC_URL").writeText("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar") | ||
val jdbcUrl = jdbcUrlWithGoogleSocketFactory("dbinstance", ConnectionConfigFactory.MountPath(tempDir.toString()), gcpTeamProjectId = "project_id") | ||
assertEquals("jdbc:postgresql://remote_ip:5432/testdb?user=foo&password=bar", jdbcUrl) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters