Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add a GET /config Route #22

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions src/main/kotlin/com/jameskbride/localsns/Main.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.jameskbride.localsns

import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import com.jameskbride.localsns.models.Configuration
import com.typesafe.config.ConfigFactory
import io.vertx.core.AsyncResult
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.core.json.JsonObject
import io.vertx.core.json.jackson.DatabindCodec
import org.apache.camel.impl.DefaultCamelContext
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
Expand All @@ -22,7 +19,12 @@ class Main {
fun main(args: Array<String>) {
configureObjectMappers()
val config = ConfigFactory.load()
logger.info("Starting local-sns-${config.getValue("version").unwrapped()}")
val version = config.getValue("version").unwrapped()
logger.info("Starting local-sns-$version")
val httpInterface = getHttpInterface(config)
val port = getPort(config)
logger.info("Health endpoint: http://$httpInterface:$port/health")
logger.info("Configuration endpoint: http://${httpInterface}:$port/config")
val vertx = Vertx.vertx()
val dbPath = getDbPath(config)
vertx.fileSystem()
Expand Down Expand Up @@ -72,18 +74,10 @@ class Main {

private fun readConfiguration(result: AsyncResult<Buffer>): Configuration {
val configFile = result.result()
val jsonConfig = JsonObject(configFile)
val jsonConfig = toJsonConfig(configFile)
logger.info("Loading configuration: $jsonConfig")

return jsonConfig.mapTo(Configuration::class.java)
}

private fun configureObjectMappers() {
val mapper = DatabindCodec.mapper()
mapper.registerKotlinModule()

val prettyMapper = DatabindCodec.prettyMapper()
prettyMapper.registerKotlinModule()
}
}
}
47 changes: 47 additions & 0 deletions src/main/kotlin/com/jameskbride/localsns/routes/configRoute.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.jameskbride.localsns.routes

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.jameskbride.localsns.getDbOutputPath
import com.jameskbride.localsns.getDbPath
import com.jameskbride.localsns.models.Configuration
import com.jameskbride.localsns.toJsonConfig
import com.typesafe.config.ConfigFactory
import io.vertx.core.Vertx
import io.vertx.core.json.JsonObject
import io.vertx.ext.web.RoutingContext
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.time.LocalDateTime
import java.time.ZoneOffset

val configRoute: (RoutingContext) -> Unit = { ctx: RoutingContext ->
val logger: Logger = LogManager.getLogger("configRoute")
val config = ConfigFactory.load()
val vertx = Vertx.vertx()
val dbPath = if (vertx.fileSystem().existsBlocking(getDbOutputPath(config))) {
getDbOutputPath(config)
} else {
getDbPath(config)
}
val configuration = try {
val dbFile = vertx.fileSystem().readFileBlocking(dbPath)
toJsonConfig(dbFile)
} catch(e: Exception) {
logger.info("Failed to load configuration: $e")
createNewConfig()
}

ctx.request().response()
.setStatusCode(200)
.putHeader("context-type", "application/json")
.end(configuration.toString())
}

fun createNewConfig(): JsonObject {
val mapper = jacksonObjectMapper()
val configuration = Configuration(
version = 1,
timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)
)
return JsonObject(mapper.writeValueAsString(configuration))
}
27 changes: 27 additions & 0 deletions src/main/kotlin/com/jameskbride/localsns/utils.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.jameskbride.localsns

import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import com.jameskbride.localsns.models.Subscription
import com.jameskbride.localsns.models.Topic
import com.typesafe.config.Config
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.core.json.JsonObject
import io.vertx.core.json.jackson.DatabindCodec
import io.vertx.core.shareddata.LocalMap
import io.vertx.ext.web.RoutingContext
import org.apache.logging.log4j.Logger
Expand All @@ -19,12 +23,27 @@ fun getDbPath(config: Config): String? =
fun getDbOutputPath(config: Config): String =
System.getenv("DB_OUTPUT_PATH") ?: config.getString("db.outputPath")

fun toJsonConfig(configFile: Buffer?) = JsonObject(configFile)

fun getAwsAccountId(config: Config): String =
System.getenv("AWS_ACCOUNT_ID") ?: config.getString("aws.accountId")

fun getAwsRegion(config: Config): String =
System.getenv("AWS_DEFAULT_REGION") ?: config.getString("aws.region")

fun getPort(config: Config): Int {
val httpPortEnv = System.getenv("HTTP_PORT")
val port = if (httpPortEnv !== null) {
Integer.parseInt(httpPortEnv)
} else {
config.getInt("http.port")
}
return port
}

fun getHttpInterface(config: Config): String? =
System.getenv("HTTP_INTERFACE") ?: config.getString("http.interface")

fun getTopicsMap(vertx: Vertx): LocalMap<String, Topic>? =
vertx.sharedData().getLocalMap("topics")

Expand All @@ -51,3 +70,11 @@ fun getFormAttribute(
ctx: RoutingContext,
attribute: String
): String? = ctx.request().getFormAttribute(attribute)

fun configureObjectMappers() {
val mapper = DatabindCodec.mapper()
mapper.registerKotlinModule()

val prettyMapper = DatabindCodec.prettyMapper()
prettyMapper.registerKotlinModule()
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class DatabaseVerticle: AbstractVerticle() {
vertx.eventBus().publish("configChangeComplete", "configChangeComplete")
}
.onFailure {
logger.error("Unable to config at: $dbPath", it)
logger.error("Unable to save config to: $dbPath", it)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.jameskbride.localsns.verticles

import com.jameskbride.localsns.getHttpInterface
import com.jameskbride.localsns.getPort
import com.jameskbride.localsns.routes.configRoute
import com.jameskbride.localsns.routes.getRoute
import com.jameskbride.localsns.routes.healthRoute
import com.typesafe.config.ConfigFactory
Expand All @@ -21,13 +24,11 @@ class MainVerticle : AbstractVerticle() {
router.route().handler(BodyHandler.create())
router.route("/").handler(getRoute)
router.route("/health").handler(healthRoute)
router.route("/config").handler(configRoute)

val config = ConfigFactory.load()
val httpInterface = System.getenv("HTTP_INTERFACE") ?: config.getString("http.interface")
val httpPortEnv = System.getenv("HTTP_PORT")
val port = if (httpPortEnv !== null) {
Integer.parseInt(httpPortEnv)
} else { config.getInt("http.port") }
val httpInterface = getHttpInterface(config)
val port = getPort(config)

val socketAddress = inetSocketAddress(port, httpInterface)

Expand Down
6 changes: 6 additions & 0 deletions src/test/kotlin/com/jameskbride/localsns/BaseTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.jameskbride.localsns
import com.jameskbride.localsns.models.Topic
import com.typesafe.config.ConfigFactory
import khttp.post
import khttp.get
import khttp.responses.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
Expand All @@ -23,6 +24,11 @@ open class BaseTest {
}
}

fun getCurrentConfig(): Response {
val baseUrl = getBaseUrl()
return get("$baseUrl/config")
}

protected fun createValidArn(resourceName: String) =
"arn:aws:sns:us-east-1:123456789012:${resourceName}"

Expand Down
39 changes: 39 additions & 0 deletions src/test/kotlin/com/jameskbride/localsns/ConfigRouteTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.jameskbride.localsns;

import com.jameskbride.localsns.models.Configuration
import com.jameskbride.localsns.verticles.MainVerticle
import io.vertx.core.Vertx
import io.vertx.junit5.VertxExtension
import io.vertx.junit5.VertxTestContext
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(VertxExtension::class)
class ConfigRouteTest: BaseTest() {

@BeforeEach
fun setup(vertx:Vertx, testContext:VertxTestContext) {
configureObjectMappers()
vertx.deployVerticle(MainVerticle(), testContext.succeeding { _ -> testContext.completeNow() })
}

@Test
fun `it returns the configuration`(testContext:VertxTestContext) {
val response = getCurrentConfig()

assertEquals(200, response.statusCode)
val text = response.text
val jsonConfig = io.vertx.core.json.JsonObject(text)
assertTrue(jsonConfig.containsKey("topics"))
assertTrue(jsonConfig.containsKey("subscriptions"))
assertTrue(jsonConfig.containsKey("timestamp"))
assertTrue(jsonConfig.containsKey("version"))

jsonConfig.mapTo(Configuration::class.java)

testContext.completeNow()
}
}
Loading