Skip to content

Commit

Permalink
feat(prism-agent): add JVM metrics endpoint, add health/version endpo…
Browse files Browse the repository at this point in the history
…int (#390)

* feat(prism-agent): add JVM metrics endpoint, add health/version endpoint

* feat(prism-agent): add health check e2e test, refactor class names

* fix: scalafmt and remove additional character

---------

Co-authored-by: Yurii Shynbuiev - IOHK <102033808+yshyn-iohk@users.noreply.github.com>
  • Loading branch information
davidpoltorak-io and yshyn-iohk committed Feb 27, 2023
1 parent c95c65f commit 6d3e5a0
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ package-lock.json
**/.docker-volumes/*
target/
**.env.*
project

119 changes: 64 additions & 55 deletions infrastructure/shared/apisix/conf/apisix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,70 @@ plugins:
- name: proxy-rewrite

routes:
- uri: /prism-agent/*
upstream_id: 2
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/(.*)","/$1"]
- uri: /didcomm
upstream_id: 3
plugins:
proxy-rewrite:
uri: "/"
- uri: /prism-agent/schema-registry/*
upstream_id: 4
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/schema-registry/(.*)","/schema-registry/$1"]
- uri: /mediator/*
upstream_id: 1
plugins:
proxy-rewrite:
regex_uri: ["^/mediator/(.*)","/$1"]
- uri: /apidocs/*
upstream_id: 5
plugins:
proxy-rewrite:
regex_uri: ["^/apidocs/(.*)","/$1"]
- uri: /docs/mediator/api/*
upstream_id: 1
plugins:
proxy-rewrite:
regex_uri: ["^/docs/mediator/api/(.*)","/api/$1"]
- uri: /docs/prism-agent/api/*
upstream_id: 2
plugins:
proxy-rewrite:
regex_uri: ["^/docs/prism-agent/api/(.*)","/api/$1"]
- uri: /prism-agent/_system/*
upstream_id: 6
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/_system/(.*)", "/$1"]
- uri: /prism-agent/*
upstream_id: 2
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/(.*)", "/$1"]
- uri: /didcomm
upstream_id: 3
plugins:
proxy-rewrite:
uri: "/"
- uri: /prism-agent/schema-registry/*
upstream_id: 4
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/schema-registry/(.*)", "/schema-registry/$1"]
- uri: /mediator/*
upstream_id: 1
plugins:
proxy-rewrite:
regex_uri: ["^/mediator/(.*)", "/$1"]
- uri: /apidocs/*
upstream_id: 5
plugins:
proxy-rewrite:
regex_uri: ["^/apidocs/(.*)", "/$1"]
- uri: /docs/mediator/api/*
upstream_id: 1
plugins:
proxy-rewrite:
regex_uri: ["^/docs/mediator/api/(.*)", "/api/$1"]
- uri: /docs/prism-agent/api/*
upstream_id: 2
plugins:
proxy-rewrite:
regex_uri: ["^/docs/prism-agent/api/(.*)", "/api/$1"]

upstreams:
- id: 1
nodes:
"mediator:8080": 1
type: roundrobin
- id: 2
nodes:
"prism-agent:8080": 1 #api
type: roundrobin
- id: 3
nodes:
"prism-agent:8090": 1 #didcom
type: roundrobin
- id: 4
nodes:
"prism-agent:8085": 1 #tapir
type: roundrobin
- id: 5
nodes:
"swagger-ui:8080": 1
type: roundrobin
- id: 1
nodes:
"mediator:8080": 1
type: roundrobin
- id: 2
nodes:
"prism-agent:8080": 1 #api
type: roundrobin
- id: 3
nodes:
"prism-agent:8090": 1 #didcom
type: roundrobin
- id: 4
nodes:
"prism-agent:8085": 1 #tapir
type: roundrobin
- id: 5
nodes:
"swagger-ui:8080": 1
type: roundrobin
- id: 6
nodes:
"prism-agent:8082": 1 #_system
type: roundrobin
#END
8 changes: 5 additions & 3 deletions prism-agent/service/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ lazy val server = project
name := "prism-agent",
fork := true,
libraryDependencies ++= serverDependencies,
Compile / mainClass := Some("io.iohk.atala.agent.server.Main"),
Compile / mainClass := Some("io.iohk.atala.agent.server.MainApp"),
// OpenAPI settings
Compile / unmanagedResourceDirectories += apiBaseDirectory.value,
Compile / sourceGenerators += openApiGenerateClasses,
Expand All @@ -68,9 +68,11 @@ lazy val server = project
Docker / githubOwner := "atala-prism-building-blocks",
Docker / dockerRepository := Some("ghcr.io"),
dockerExposedPorts := Seq(8080, 8085, 8090),
dockerBaseImage := "openjdk:11"
dockerBaseImage := "openjdk:11",
buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
buildInfoPackage := "io.iohk.atala.agent.server.buildinfo"
)
.enablePlugins(OpenApiGeneratorPlugin, JavaAppPackaging, DockerPlugin)
.enablePlugins(OpenApiGeneratorPlugin, JavaAppPackaging, DockerPlugin, BuildInfoPlugin)
.dependsOn(`wallet-api`)

releaseProcess := Seq[ReleaseStep](
Expand Down
6 changes: 5 additions & 1 deletion prism-agent/service/project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ object Dependencies {
val zioConfig = "3.0.2"
val zioHttp = "2.0.0-RC11"
val zioInteropCats = "3.3.0" // scala-steward:off
val zioMetrics = "2.0.6"
val akka = "2.6.20"
val akkaHttp = "10.2.9"
val castor = "0.8.1"
Expand Down Expand Up @@ -34,6 +35,8 @@ object Dependencies {

private lazy val zioHttp = "io.d11" %% "zhttp" % Versions.zioHttp

private lazy val zioMetrics = "dev.zio" %% "zio-metrics-connectors" % Versions.zioMetrics

private lazy val akkaTyped = "com.typesafe.akka" %% "akka-actor-typed" % Versions.akka
private lazy val akkaStream = "com.typesafe.akka" %% "akka-stream" % Versions.akka
private lazy val akkaHttp = "com.typesafe.akka" %% "akka-http" % Versions.akkaHttp
Expand Down Expand Up @@ -91,7 +94,8 @@ object Dependencies {
zioConfigTypesafe,
zioJson,
logback,
zioHttp
zioHttp,
zioMetrics
)
private lazy val castorDependencies: Seq[ModuleID] = Seq(castorCore, castorSqlDoobie)
private lazy val polluxDependencies: Seq[ModuleID] = Seq(polluxCore, polluxSqlDoobie)
Expand Down
1 change: 1 addition & 0 deletions prism-agent/service/project/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0")
addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.3")
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.9")
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0")
//addDependencyTreePlugin

libraryDependencies ++= Seq("org.openapitools" % "openapi-generator" % "6.0.1")
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,47 @@ import org.flywaydb.core.extensibility.AppliedMigration
import io.iohk.atala.pollux.service.{JdbcSchemaRegistryService, SchemaRegistryServiceInMemory}
import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage
import io.iohk.atala.pollux.schema.controller.VerificationPolicyControllerInMemory
import zhttp.http.*
import zhttp.service.Server
import zio.metrics.connectors.prometheus.PrometheusPublisher
import zio.metrics.connectors.{MetricsConfig, prometheus}
import zio.metrics.jvm.DefaultJvmMetrics
import io.iohk.atala.agent.server.buildinfo.BuildInfo
import io.circe.*
import io.circe.generic.auto.*
import io.circe.parser.*
import io.circe.syntax.*
import io.iohk.atala.agent.server.health.HealthInfo

object Main extends ZIOAppDefault {
object SystemInfoApp extends ZIOAppDefault {
private val metricsConfig = ZLayer.succeed(MetricsConfig(5.seconds))

def run =
Server
.start(
port = 8082,
http = Http.collectZIO[Request] {
case Method.GET -> !! / "metrics" =>
ZIO.serviceWithZIO[PrometheusPublisher](_.get.map(Response.text))
case Method.GET -> !! / "health" =>
ZIO
.succeed(
Response.json(
HealthInfo(
version = BuildInfo.version
).asJson.toString
)
)
}
)
.provide(
metricsConfig,
prometheus.publisherLayer,
prometheus.prometheusLayer
)
}

object AgentApp extends ZIOAppDefault {

def didCommAgentLayer(didCommServiceUrl: String): ZLayer[ManagedDIDService, Nothing, DidAgent] = {
val aux = for {
Expand Down Expand Up @@ -45,9 +84,10 @@ object Main extends ZIOAppDefault {
} yield ()

override def run: ZIO[Any, Throwable, Unit] = {

val app = for {
_ <- Console
.printLine("""
.printLine(s"""
|██████╗ ██████╗ ██╗███████╗███╗ ███╗
|██╔══██╗██╔══██╗██║██╔════╝████╗ ████║
|██████╔╝██████╔╝██║███████╗██╔████╔██║
Expand All @@ -61,6 +101,9 @@ object Main extends ZIOAppDefault {
|██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║
|██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║
|╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝
|
|version: ${BuildInfo.version}
|
|""".stripMargin)
.ignore

Expand Down Expand Up @@ -111,3 +154,5 @@ object Main extends ZIOAppDefault {
}

}

object MainApp extends ZIOApp.Proxy(SystemInfoApp <> DefaultJvmMetrics.app <> AgentApp)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.iohk.atala.agent.server.health

case class HealthInfo(
version: String
)
4 changes: 4 additions & 0 deletions tests/e2e-tests/src/main/kotlin/api_models/HealthInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package api_models
data class HealthInfo(
var version: String = "",
)
36 changes: 36 additions & 0 deletions tests/e2e-tests/src/test/kotlin/features/system/SystemSteps.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package features.system

import api_models.HealthInfo
import common.Utils.lastResponseObject
import io.cucumber.java.en.Then
import io.cucumber.java.en.When
import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.rest.interactions.Get
import net.serenitybdd.screenplay.rest.questions.ResponseConsequence
import org.apache.http.HttpStatus.SC_OK
import org.assertj.core.api.Assertions.assertThat

class SystemSteps {
@When("{actor} makes a request to the health endpoint")
fun actorRequestsHealthEndpoint(actor: Actor) {
actor.attemptsTo(
Get.resource("/_system/health"),
)
actor.should(
ResponseConsequence.seeThatResponse {
it.statusCode(SC_OK)
},
)
val healthResponse = lastResponseObject("", HealthInfo::class)
assertThat(healthResponse)
.hasFieldOrProperty("version")
.hasNoNullFieldsOrProperties()
actor.remember("version", healthResponse.version)
}

@Then("{actor} knows what version of the service is running")
fun actorUnderstandsVersion(actor: Actor) {
assertThat(actor.recall<String>("version"))
.isNotBlank()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@system @smoke
Feature: Agent Health Endpoint

Scenario: The runtime version can be retrieved from the Health Endpoint
When Acme makes a request to the health endpoint
Then Acme knows what version of the service is running

0 comments on commit 6d3e5a0

Please sign in to comment.