Skip to content

Commit

Permalink
Merge pull request #686 from modelix/feat/add-endpoint-to-show-server…
Browse files Browse the repository at this point in the history
…-version

feat(model-server): add endpoint /about
  • Loading branch information
odzhychko authored Jul 10, 2024
2 parents fcd176c + 77e45d3 commit 2579fb9
Show file tree
Hide file tree
Showing 19 changed files with 283 additions and 36 deletions.
26 changes: 26 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
plugins {
`kotlin-dsl`
}

dependencies {
// This should ideally be `compileOnly` and not `implementation`.
// The compiled `build-logic` should not bundle the plugin code.
// The project applying code from "build-logic" should add the plugins themselves.
//
// But using `compileOnly` we run into https://github.com/gradle/gradle/issues/23709
// This is indirectly related to applying any settings plugin in our root "settings.gradle.kts".
// ```
// plugins {
// id("modelix-repositories")
// }
// ```
// Applying any settings plugin causes an `InstrumentingVisitableURLClassLoader` to be added as class loader.
// It results in throwing "java.lang.NoClassDefFoundError: org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper`.
//
// We therefore use `implementation` as a workaround and bundle the plugin code with "build-logic".
//
// Because we use `implementation` and not `compileOnly` only,
// they must not add any of the Kotlin Gradle plugins again in the applying projects.
// This means we must not call `alias(libs.plugins.kotlin.multiplatform)`
// and `alias(libs.plugins.kotlin.jvm), which tries to add them again as plugins.
// We just have to call `kotlin("multiplatform")` and `kotlin("jvm")` which just enables the plugins,
// but uses the plugin code bundled with `build-logic`.
implementation(libs.kotlin.gradlePlugin)
}
79 changes: 79 additions & 0 deletions build-logic/src/main/kotlin/org/modelix/GenerateVersion.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.modelix

import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper

/**
* Causes code containing the Modelix version to be generated and used in a Kotlin project.
* The Kotlin project can be a JVM or Multiplatform project.
*/
fun Project.registerVersionGenerationTask(packageName: String) {
val packagePath = packageName.replace('.', '/')

val generateVersionVariable = tasks.register("generateVersionVariable") {
doLast {
val fileContent = buildString {
appendLine("package $packageName")
appendLine()
appendLine("""const val MODELIX_VERSION: String = "$version"""")
if (project.name == "modelql-core") {
appendLine("""@Deprecated("Use the new MODELIX_VERSION", replaceWith = ReplaceWith("MODELIX_VERSION"))""")
appendLine("const val modelqlVersion: String = MODELIX_VERSION")
}
}
val outputDir = layout.buildDirectory.dir("version_gen/$packagePath").get().asFile
outputDir.mkdirs()
outputDir.resolve("Version.kt").writeText(fileContent)
}
}

// Generate version constant for Kotlin JVM projects
plugins.withType<KotlinPluginWrapper> {
extensions.configure<KotlinJvmProjectExtension> {
sourceSets["main"].kotlin.srcDir(layout.buildDirectory.dir("version_gen"))
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
dependsOn(generateVersionVariable)
}
}

// Generate version constant for Kotlin Multiplatform projects
plugins.withType<KotlinMultiplatformPluginWrapper> {
extensions.configure<KotlinMultiplatformExtension> {
sourceSets.commonMain {
kotlin.srcDir(layout.buildDirectory.dir("version_gen"))
}
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
dependsOn(generateVersionVariable)
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon>().all {
dependsOn(generateVersionVariable)
}
}
}
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ buildscript {
plugins {
`maven-publish`
`version-catalog`
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.gitVersion)
alias(libs.plugins.spotless) apply false
Expand Down
2 changes: 1 addition & 1 deletion bulk-model-sync-gradle-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

plugins {
alias(libs.plugins.kotlin.jvm)
kotlin("jvm")
id("org.modelix.bulk-model-sync")
}

Expand Down
2 changes: 1 addition & 1 deletion bulk-model-sync-lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
alias(libs.plugins.kotlin.multiplatform)
kotlin("multiplatform")
}

kotlin {
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ kotlin-serialization-yaml = { group = "com.charleskorn.kaml", name = "kaml", ver
kotlin-logging = { group = "io.github.microutils", name = "kotlin-logging", version = "3.0.5" }
kotlin-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version = "0.3.7" }
kotlin-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version = "0.6.0" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }

kotlin-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinCoroutines" }
kotlin-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinCoroutines" }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
alias(libs.plugins.kotlin.jvm)
kotlin("jvm")
id("org.modelix.model-api-gen") apply false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import org.modelix.model.server.api.SetPropertyOpData
import org.modelix.model.server.api.SetReferenceOpData
import org.modelix.model.server.api.VersionData
import org.modelix.model.server.api.buildModelQuery
import org.modelix.modelql.core.modelqlVersion
import org.modelix.modelql.core.MODELIX_VERSION
import org.modelix.modelql.server.ModelQLServer
import java.time.Duration
import java.util.*
Expand Down Expand Up @@ -202,7 +202,7 @@ class LightModelServer @JvmOverloads constructor(val port: Int, val rootNodeProv
}
}
get("/version") {
call.respondText(modelqlVersion ?: "unknown")
call.respondText(MODELIX_VERSION)
}
get("/health") {
val output = StringBuilder()
Expand Down
26 changes: 26 additions & 0 deletions model-server-openapi/specifications/model-server-operative.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ paths:
default:
$ref: '#/components/responses/GeneralError'

/about:
get:
operationId: getAboutInformation
x-modelix-media-type-handlers:
- v1:
- 'application/x.modelix.about+json;version=1'
tags:
- about
responses:
"200":
description: Response with information about the model server.
content:
'application/x.modelix.about+json;version=1':
schema:
$ref: "#/components/schemas/AboutV1"

components:
responses:
Healthy:
Expand Down Expand Up @@ -110,3 +126,13 @@ components:
e.g. by adding a fragment identifier or sub-path to the problem type.
May be used to locate the root of this problem in the source code.
example: '/some/uri-reference#specific-occurrence-context'

AboutV1:
x-modelix-media-type: 'application/x.modelix.about+json;version=1'
description: Information about the model server
type: object
properties:
version:
type: string
required:
- version
3 changes: 3 additions & 0 deletions model-server/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
import io.gitlab.arturbosch.detekt.Detekt
import org.modelix.registerVersionGenerationTask
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask

plugins {
Expand Down Expand Up @@ -270,3 +271,5 @@ openApiFiles.forEach {
tasks.withType<Detekt> {
exclude("**/org/modelix/api/**")
}

project.registerVersionGenerationTask("org.modelix.model.server")
10 changes: 7 additions & 3 deletions model-server/src/main/kotlin/org/modelix/model/server/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ import kotlinx.serialization.json.Json
import org.apache.commons.io.FileUtils
import org.apache.ignite.Ignition
import org.modelix.api.v1.Problem
import org.modelix.api.v2.Paths.registerJsonTypes
import org.modelix.authorization.ModelixAuthorization
import org.modelix.authorization.NoPermissionException
import org.modelix.authorization.NotLoggedInException
import org.modelix.model.InMemoryModels
import org.modelix.model.server.handlers.AboutApiImpl
import org.modelix.model.server.handlers.HealthApiImpl
import org.modelix.model.server.handlers.HttpException
import org.modelix.model.server.handlers.IdsApiImpl
Expand All @@ -79,6 +79,8 @@ import java.io.IOException
import java.nio.charset.StandardCharsets
import java.time.Duration
import javax.sql.DataSource
import org.modelix.api.operative.Paths.registerJsonTypes as registerJsonTypesOperative
import org.modelix.api.v2.Paths.registerJsonTypes as registerJsonTypesV2

object Main {
private val LOG = LoggerFactory.getLogger(Main::class.java)
Expand All @@ -95,6 +97,7 @@ object Main {
return
}

LOG.info("Version: $MODELIX_VERSION")
LOG.info("Max memory (bytes): ${Runtime.getRuntime().maxMemory()}")
LOG.info("Server process started")
LOG.info("In memory: ${cmdLineArgs.inmemory}")
Expand Down Expand Up @@ -196,7 +199,8 @@ object Main {
}
install(ContentNegotiation) {
json()
registerJsonTypes()
registerJsonTypesV2()
registerJsonTypesOperative()
}
install(CORS) {
anyHost()
Expand All @@ -219,7 +223,7 @@ object Main {

routing {
HealthApiImpl(repositoriesManager, globalStoreClient, inMemoryModels).installRoutes(this)

AboutApiImpl.installRoutes(this)
staticResources("/public", "public")

if (cmdLineArgs.noSwaggerUi) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2024.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.modelix.model.server.handlers

import io.ktor.server.application.ApplicationCall
import io.ktor.server.application.call
import io.ktor.server.response.respond
import io.ktor.util.pipeline.PipelineContext
import org.modelix.api.operative.AboutApi
import org.modelix.api.operative.AboutV1
import org.modelix.model.server.MODELIX_VERSION

/**
* Responding information about the model server.
*/
object AboutApiImpl : AboutApi() {
override suspend fun PipelineContext<Unit, ApplicationCall>.getAboutInformationV1() {
val about = AboutV1(MODELIX_VERSION)
call.respond(about)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class PageWithMenuBar(val activePage: String, val baseUrl: String) : Template<HT
"user" to "JWT token",
"permissions" to "Permissions",
"swagger" to "SwaggerUI",
"about" to "About",
)
var classes = "menuItem"
if (activePage == "root") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import io.ktor.server.routing.IgnoreTrailingSlash
import io.ktor.server.testing.ApplicationTestBuilder
import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.runBlocking
import org.modelix.api.v2.Paths.registerJsonTypes
import org.modelix.authorization.ModelixAuthorization
import org.modelix.authorization.installAuthentication
import org.modelix.model.client2.ModelClientV2
import org.modelix.model.server.Main.installStatusPages
import org.modelix.api.operative.Paths.registerJsonTypes as registerJsonTypesOperative
import org.modelix.api.v2.Paths.registerJsonTypes as registerJsonTypesV2

suspend fun ApplicationTestBuilder.createModelClient(): ModelClientV2 {
val url = "http://localhost/v2"
Expand All @@ -43,7 +44,8 @@ fun Application.installDefaultServerPlugins(unitTestMode: Boolean = true) {
install(WebSockets)
install(ContentNegotiation) {
json()
registerJsonTypes()
registerJsonTypesV2()
registerJsonTypesOperative()
}
install(Resources)
install(IgnoreTrailingSlash)
Expand Down
Loading

0 comments on commit 2579fb9

Please sign in to comment.