Increment now working, tests redacted, Currently configuring CI/CD
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
parent
798fbe9347
commit
83836d13f6
@ -0,0 +1,31 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: Deployment
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- production
|
||||||
|
- dev
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 'Unit Tests'
|
||||||
|
image: ubuntu:latest
|
||||||
|
commands:
|
||||||
|
- apt update && apt install openjdk-11-jdk -y
|
||||||
|
- ./gradlew :test
|
||||||
|
|
||||||
|
- name: deploy to server
|
||||||
|
image: ubuntu:latest
|
||||||
|
depends_on:
|
||||||
|
- 'Unit Tests'
|
||||||
|
environment:
|
||||||
|
SSH_PRIVATE_KEY:
|
||||||
|
from_secret: ???
|
||||||
|
SSH_PUBLIC_KEY:
|
||||||
|
from_secret: ???
|
||||||
|
USER:
|
||||||
|
from_secret: ???
|
||||||
|
IP:
|
||||||
|
from_secret: ???
|
||||||
|
commands:
|
||||||
|
- drone/deliver.sh $DRONE_BRANCH
|
@ -1,36 +1,58 @@
|
|||||||
package org.tbasket.api
|
package org.tbasket.api
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.tbasket.api.Endpoint.LOG
|
||||||
import org.tbasket.api.compute.APIRequestHandler
|
import org.tbasket.api.compute.APIRequestHandler
|
||||||
import zio._
|
import zio._
|
||||||
import zio.http.ServerConfig.LeakDetectionLevel
|
import zio.http.ServerConfig.LeakDetectionLevel
|
||||||
import zio.http._
|
import zio.http._
|
||||||
|
import zio.http.model.Method.{GET, POST}
|
||||||
|
import zio.http.model.Status
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class Endpoint(hostname: String, port: Int, rootPath: Option[String]) extends ZIOAppDefault {
|
class Endpoint(hostname: String, port: Int) extends ZIOAppDefault {
|
||||||
|
|
||||||
|
|
||||||
private val Root: Path = rootPath.map(Path.decode).getOrElse(Path.root)
|
|
||||||
private val handlers = mutable.HashMap.empty[String, APIRequestHandler]
|
private val handlers = mutable.HashMap.empty[String, APIRequestHandler]
|
||||||
|
|
||||||
def bind(path: String)(handler: APIRequestHandler): Unit = {
|
def bind(path: String)(handler: APIRequestHandler): Unit = {
|
||||||
handlers.put(path, handler)
|
handlers.put(path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val app = Http.collectZIO[Request] {
|
//set generic required headers
|
||||||
case r@_ -> Root / path if handlers.contains(path) =>
|
private def transform(response: Response): Response = {
|
||||||
handlers(path).handle.provideEnvironment(ZEnvironment(r))
|
response.withAccessControlAllowOrigin("*")
|
||||||
case _ -> path =>
|
|
||||||
ZIO.fail(new APIException(s"Unable to find a handler for page '$path'"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val app = Http.collect[Request] {
|
||||||
|
case r@GET -> _ / path if handlers.contains(path) =>
|
||||||
|
transform(handlers(path).get(r))
|
||||||
|
case r@POST -> _ / path if handlers.contains(path) =>
|
||||||
|
transform(handlers(path).post(r))
|
||||||
|
case r@method -> path =>
|
||||||
|
val ipInsights = r.remoteAddress
|
||||||
|
.map(ip => s": request received from $ip.")
|
||||||
|
.getOrElse("")
|
||||||
|
LOG.error(s"Was unable to find a handler for request '$path' with method $method ${ipInsights}")
|
||||||
|
Response(Status.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
val run = {
|
val run = {
|
||||||
val config = ServerConfig.default
|
val config = ServerConfig.default
|
||||||
.port(port)
|
.port(port)
|
||||||
.leakDetection(LeakDetectionLevel.PARANOID)
|
.leakDetection(LeakDetectionLevel.PARANOID)
|
||||||
|
|
||||||
val configLayer = ServerConfig.live(config)
|
val configLayer = ServerConfig.live(config)
|
||||||
(Server.install(app).flatMap { port =>
|
Server.install(app).flatMap { port =>
|
||||||
Console.printLine(s"Listening API entries on $hostname:$port$rootPath")
|
LOG.info(s"Listening API entries on $hostname:$port")
|
||||||
} *> ZIO.never).provide(configLayer, Server.live)
|
ZIO.never
|
||||||
|
}.provide(configLayer, Server.live)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Endpoint {
|
||||||
|
final val LOG = LogManager.getLogger("API")
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package org.tbasket.api.compute
|
package org.tbasket.api.compute
|
||||||
|
|
||||||
import org.tbasket.api.APIException
|
import zio.http.model.Status
|
||||||
import zio.ZIO
|
|
||||||
import zio.http.{Request, Response}
|
import zio.http.{Request, Response}
|
||||||
|
|
||||||
trait APIRequestHandler {
|
trait APIRequestHandler {
|
||||||
|
|
||||||
def handle: ZIO[Request, APIException, Response]
|
def get(request: Request): Response = Response(Status.MethodNotAllowed)
|
||||||
|
|
||||||
|
def post(request: Request): Response = Response(Status.MethodNotAllowed)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
apt update && apt install openjdk-11-jdk sftp -y
|
||||||
|
|
||||||
|
PATH="$PATH:."
|
||||||
|
|
||||||
|
gradlew :shadowJar
|
||||||
|
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
|
||||||
|
echo "$SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub
|
||||||
|
sftp "$USER@$IP:tbasket/" <<< $'put build/libs/server-all.jar drone/deploy.sh'
|
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
|
||||||
|
SERVER_JAR_NAME="server-all.jar"
|
||||||
|
|
||||||
|
OLD_PID=$(ps -aux | grep "-jar $SERVER_JAR_NAME" | tr -s " " | cut -d " " -f2)
|
||||||
|
|
||||||
|
#if $OLD_PID is not empty but isn't a number, something went wrong
|
||||||
|
if [ "$OLD_PID" ] && ! grep -E -q "^[0-9]+$"; then
|
||||||
|
echo "error, unable to retrieve old server pid: $OLD_PID" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$OLD_PID" ]; then
|
||||||
|
#will cause the old server to gracefully shutdown
|
||||||
|
echo "shutting down old server version ..."
|
||||||
|
kill SIGQUIT "$OLD_PID"
|
||||||
|
wait "$OLD_PID"
|
||||||
|
fi
|
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="WARN">
|
||||||
|
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout disableAnsi="false"
|
||||||
|
pattern="%style{[%d{HH:mm:ss,SSS}]}{magenta} [%highlight{%-5p}{FATAL=red, ERROR=red, WARN=yellow, INFO=blue, DEBUG=green, TRACE=normal} _ %-6logger] %style{-}{normal} %highlight{%m%n}{FATAL=red, ERROR=red, WARN=yellow, INFO=blue, DEBUG=green, TRACE=normal}"/>
|
||||||
|
</Console>
|
||||||
|
<RollingFile name="LogFile"
|
||||||
|
fileName="log/server-current.log"
|
||||||
|
filePattern="log/archives/server-%d{yyyy-MM-dd}.log"
|
||||||
|
append="true">
|
||||||
|
<PatternLayout disableAnsi="false"
|
||||||
|
pattern="[%d{HH:mm:ss,SSS}] [%-5p _ %-6logger] - %m%n"/>
|
||||||
|
<Policies>
|
||||||
|
<TimeBasedTriggeringPolicy/>
|
||||||
|
</Policies>
|
||||||
|
</RollingFile>
|
||||||
|
</Appenders>
|
||||||
|
|
||||||
|
<Loggers>
|
||||||
|
<Logger name="Database" additivity="false" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Logger>
|
||||||
|
<Logger name="API" additivity="false" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Logger>
|
||||||
|
<Logger name="Core" additivity="false" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Logger>
|
||||||
|
<Root level="ALL" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
|
||||||
|
</Configuration>
|
@ -1,23 +1,21 @@
|
|||||||
package org.tbasket.compute
|
package org.tbasket.compute
|
||||||
|
|
||||||
import org.tbasket.api.APIException
|
|
||||||
import org.tbasket.api.compute.APIRequestHandler
|
import org.tbasket.api.compute.APIRequestHandler
|
||||||
import zio.ZIO
|
|
||||||
import zio.http.model.Method._
|
|
||||||
import zio.http.{Request, Response}
|
import zio.http.{Request, Response}
|
||||||
|
|
||||||
object IncrementHandler extends APIRequestHandler {
|
object IncrementHandler extends APIRequestHandler {
|
||||||
|
|
||||||
private var i = 0
|
@volatile private var i = 0
|
||||||
|
|
||||||
|
def getCounter: Int = i
|
||||||
|
|
||||||
override def handle: ZIO[Request, APIException, Response] = {r: Request =>
|
override def get(request: Request): Response = {
|
||||||
r match {
|
Response.json(s"{\"value\": $i}")
|
||||||
case Request(_, _, GET, _, _, _) =>
|
|
||||||
ZIO.succeed(Response.json(s"value: $i"))
|
|
||||||
case Request(_, _, POST, _, _, _) =>
|
|
||||||
i += 1
|
|
||||||
ZIO.succeed(Response.ok)
|
|
||||||
Console
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def post(request: Request): Response = {
|
||||||
|
i += 1
|
||||||
|
println(s"Counter is now $i")
|
||||||
|
Response.ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package org.tbasket.test
|
||||||
|
|
||||||
|
import io.circe.parser._
|
||||||
|
import org.junit.jupiter.api.{Assertions, Test}
|
||||||
|
import org.tbasket.compute.IncrementHandler
|
||||||
|
import zio.http.model.Status
|
||||||
|
import zio.http.{Body, Path, Request, URL}
|
||||||
|
|
||||||
|
class IncrementRequestHandler {
|
||||||
|
|
||||||
|
private val url = URL(Path.decode("counter"))
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def testMakeIncrement(): Unit = {
|
||||||
|
val last = IncrementHandler.getCounter
|
||||||
|
val response = IncrementHandler.post(Request.post(Body.empty, url))
|
||||||
|
Assertions.assertEquals(response.status, Status.Ok)
|
||||||
|
Assertions.assertEquals(last + 1, IncrementHandler.getCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def testGetIncrement(): Unit = {
|
||||||
|
val counter = IncrementHandler.getCounter
|
||||||
|
val response = IncrementHandler.get(Request.post(Body.empty, url))
|
||||||
|
for {
|
||||||
|
json <- response.body.asString
|
||||||
|
} yield parse(json) match {
|
||||||
|
case Left(failure) => Assertions.fail(s"returned json is invalid ($failure)")
|
||||||
|
case Right(json) =>
|
||||||
|
val valueJsons = json.findAllByKey("value")
|
||||||
|
Assertions.assertEquals(1, valueJsons.size)
|
||||||
|
val valueCounter = valueJsons.head.asNumber.get.toInt.get
|
||||||
|
Assertions.assertEquals(counter, valueCounter)
|
||||||
|
}
|
||||||
|
Assertions.assertEquals(response.status, Status.Ok)
|
||||||
|
Assertions.assertEquals(counter, IncrementHandler.getCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in new issue