Skip to content

Commit

Permalink
Kubernetes (#9)
Browse files Browse the repository at this point in the history
* Moved to monorepo project structure with separate frontend/backend folders.

* Created Matrix build on Travis CI and using specific badges, currently code coverage is only collected for the frontend

* Initial dockerfiles and kubernetes config for frontend, mongo, and backend.

* Server currently is just a minimal Scala/Finch server from the tutorials, which is enough to prove the build process

* Basic put/get Mongo service created with scala & http4s
  • Loading branch information
RawToast committed Mar 5, 2018
1 parent 177e372 commit e71efe8
Show file tree
Hide file tree
Showing 56 changed files with 524 additions and 51 deletions.
28 changes: 2 additions & 26 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,26 +1,2 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build

# bucklescript
/lib
/types
.merlin

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.vscode
.idea
23 changes: 18 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
language: node_js
node_js:
- "8"
cache: yarn
script: ["yarn add coveralls", "yarn bsb -clean-world -make-world", "yarn ci"]
matrix:
include:
- language: node_js
node_js:
- "8"
cache: yarn
before_script:
- cd dokusho
script: ["yarn add coveralls", "yarn bsb -clean-world -make-world", "yarn ci"]

- language: scala
jdk: oraclejdk8
scala:
- 2.12.4
before_script:
- cd dokusho-server
script:
- sbt test
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# Dokusho
# Dokusho

[![Build Status](https://travis-ci.org/RawToast/dokusho.svg?branch=master)](https://travis-ci.org/RawToast/dokusho)
[![Coverage Status](https://coveralls.io/repos/github/RawToast/dokusho/badge.svg)](https://coveralls.io/github/RawToast/dokusho)
[T1]: https://travis-matrix-badges.herokuapp.com/repos/RawToast/dokusho/branches/master/1
[T2]: https://travis-matrix-badges.herokuapp.com/repos/RawToast/dokusho/branches/master/2
[TR]: https://travis-ci.org/RawToast/dokusho

A Japanese reading page count calculator, using the same page values as the [Tadoku reading contest](http://readmod.com).
[C1]: https://coveralls.io/repos/github/RawToast/dokusho/badge.svg
[CR]: https://coveralls.io/github/RawToast/dokusho

| [Dokusho](dokusho/) | [Dokusho Server](dokusho-server/)|
|-----------------------|---------------------|
| [![Travis][T1]][TR] | [![Travis][T2]][TR] |
| [![Coveralls][C1]][CR]| |


Japanese reading page count calculator, using similar page values as the [Tadoku reading contest](http://readmod.com).

読書 (dokusho)

Expand All @@ -13,19 +23,23 @@ Noun, Suru verb

## Running the project

### Using npm / yarn
This is a multi-module project. See the relevent modules for running instructions.

### Building

As this project is built using ReasonML, it requires the bucklescript platform to compile and run. To start the application on a fresh machine run the following commands to start a server at `localhost:3000`:

* `npm install -g bs-platform`
* `yarn`
* `yarn start`

### Docker
### Minikube

Alternatively, docker can be used to run the project. The service will be available at: `localhost:80`
[Minikube](https://github.com/kubernetes/minikube) can be used to run a local kubernetes cluster with a Mongo instance. The url can be found using: `minikube service web --url`

* `./run-docker.sh`
* `minikube start --vm-driver <hyperkit, xhyve, virtualbox, etc>`
* `./kube/build-image.sh`
* `./kube/run-local.sh`

## Additional Information

Expand All @@ -36,3 +50,9 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
* [Reason React](https://reasonml.github.io/reason-react/)
* [Rationale](https://github.com/jonlaing/rationale)
* [Bs-Jest](https://github.com/glennsl/bs-jest)
* [Scala](http://scala-lang.org)
* [Finch](https://finagle.github.io/finch/)
* [Circe](https://circe.github.io/circe/)
* [Kubernetes](https://kubernetes.io)
* [Minikube](https://github.com/kubernetes/minikube)
* [MongoDB](https://www.mongodb.com)
7 changes: 7 additions & 0 deletions bin/build-images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

eval $(minikube docker-env)

docker build ../dokusho -t dokusho:web

docker build ../dokusho-server -t dokusho:server
7 changes: 7 additions & 0 deletions bin/create-services.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

kubectl create -f ../kube/mongo-service.yaml
kubectl create -f ../kube/web-service.yaml

kubectl create -f ../kube/mongo-controller.yaml
kubectl create -f ../kube/web-controller.yaml
9 changes: 0 additions & 9 deletions dockerfile

This file was deleted.

16 changes: 16 additions & 0 deletions dokusho-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.class
*.log

# sbt specific
.cache
.history
.lib/
dist/*
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/

# Idea
.idea/
24 changes: 24 additions & 0 deletions dokusho-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Dokusho-Server

[![Build Status](https://travis-matrix-badges.herokuapp.com/repos/RawToast/dokusho/branches/master/2)](https://travis-ci.org/RawToast/dokusho)

Backend server for Dokusho. This is a work in progress and is not currently being used by the frontend.

## Running the backend

### Using sbt

`sbt run` will compile and start a server listening on `8080`

### Docker

Currently, no docker configuration has been craeted for this module.

## Additional Information

This project is built using the following:

* [Scala](http://scala-lang.org)
* [Cats](https://typelevel.org/cats)
* [Http4s](http://http4s.org)
* [Circe](https://circe.github.io/circe/)
3 changes: 3 additions & 0 deletions dokusho-server/build-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

docker build ../dokusho-server -t dokusho:server
30 changes: 30 additions & 0 deletions dokusho-server/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name := "dokusho-server"

mainClass in(Compile, run) := Some("Main")

val SCALA_VERSION = "2.12.4"
val CIRCE_VERSION = "0.9.1"
val HTTP4S_VERSION = "0.18.1"
val MONGO_VERSION = "2.2.1"

resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Resolver.sonatypeRepo("snapshots"),
"Bintary JCenter" at "http://jcenter.bintray.com"
)

libraryDependencies ++= Seq(
"org.http4s" %% "http4s-dsl" % HTTP4S_VERSION,
"org.http4s" %% "http4s-blaze-server" % HTTP4S_VERSION,
"org.http4s" %% "http4s-circe" % HTTP4S_VERSION,

"io.circe" %% "circe-generic" % CIRCE_VERSION,
"io.circe" %% "circe-generic-extras" % CIRCE_VERSION,
"io.circe" %% "circe-parser" % CIRCE_VERSION,

"org.mongodb.scala" %% "mongo-scala-driver" % MONGO_VERSION,

"ch.qos.logback" % "logback-classic" % "1.2.3"
)

scalacOptions ++= Seq("-Ypartial-unification")
7 changes: 7 additions & 0 deletions dokusho-server/dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM hseeberger/scala-sbt:8u151-2.12.4-1.1.1

COPY . .

RUN sbt compile

CMD sbt run
1 change: 1 addition & 0 deletions dokusho-server/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version = 1.1.1
14 changes: 14 additions & 0 deletions dokusho-server/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
28 changes: 28 additions & 0 deletions dokusho-server/src/main/scala/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import cats.effect._
import dokusho.{MongoRepository, MongoService}
import org.http4s.dsl.io._
import org.http4s.server.blaze.BlazeBuilder
import fs2.{Stream, StreamApp}
import fs2.StreamApp.ExitCode
import org.http4s.server.ServerBuilder

import scala.concurrent.ExecutionContext.Implicits.global

object Main extends StreamApp[IO] {

//TODO move to .env
lazy val mongo = new MongoRepository(
"mongodb://mongo:27017",
"test",
"dokusho")

val mongoService = new MongoService(mongo)


override def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] =
BlazeBuilder[IO]
.bindHttp(8080, "localhost")
.mountService(mongoService.routes, "/")
.withBanner(ServerBuilder.DefaultBanner)
.serve
}
59 changes: 59 additions & 0 deletions dokusho-server/src/main/scala/dokusho/MongoRepository.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dokusho

import cats.effect._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
import io.circe.{DecodingFailure, Json, ParsingFailure}
import org.bson.Document
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.{MongoClient, MongoCollection, Observable, model}

import scala.concurrent.ExecutionContext

class MongoRepository(connectionString: String, databaseName: String, collectionName: String) {

implicit val executionContext: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global

lazy val collection: MongoCollection[Document] =
MongoClient(connectionString)
.getDatabase(databaseName)
.getCollection(collectionName)

def get(userId: String) = for {
document <- getDocument(userId)
hs <- toUserReadingHistory(document)
} yield hs

def put(g: UserReadingHistory): IO[UserReadingHistory] =
collection.replaceOne(equal("uuid", g.userId.toString), Document.parse(g.asJson.spaces2),
model.UpdateOptions().upsert(true)).asIO
.map(_ => g)


private def getDocument(id: String): IO[Document] = collection.find(equal("userId", id)).asIO

private def toUserReadingHistory(task: Document): IO[UserReadingHistory] = {
for {
json <- parseJson(task.toJson)
readingHistory <- parseReadingHistory(json)
} yield readingHistory
}

private def parseJson(s: String): IO[Json] = parse(s) match {
case Left(err: ParsingFailure) => IO.raiseError(err.underlying)
case Right(json) => IO.pure(json)
}

private def parseReadingHistory(j: Json): IO[UserReadingHistory] = j.as[UserReadingHistory] match {
case Left(err: DecodingFailure) => IO.raiseError(err.getCause)
case Right(json: UserReadingHistory) => IO.pure(json)
}

private implicit class IOSyntax[T](obs: Observable[T]) {
def asIO: IO[T] = IO.fromFuture(IO(obs.head()))

def asSeqIO: IO[Seq[T]] = IO.fromFuture(IO(obs.toFuture()))
}

}
31 changes: 31 additions & 0 deletions dokusho-server/src/main/scala/dokusho/MongoService.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dokusho

import cats.effect.IO
import io.circe.Json
import io.circe.generic.auto._
import io.circe.syntax._
import org.http4s._
import org.http4s.circe._
import org.http4s.dsl.io.{->, /, GET, Ok, Root, _}

class MongoService(mongoRepository: MongoRepository) {

case class SuccessfulPut(userId: String)

val routes: HttpService[IO] = HttpService[IO] {
case GET -> Root / "mongo" / name =>
for {
userReadingHistory <- mongoRepository.get(name)
json: Json = userReadingHistory.asJson
response <- Ok(json)
} yield response
case req@PUT -> Root / "mongo" =>
implicit val userDecoder: EntityDecoder[IO, UserReadingHistory] = jsonOf[IO, UserReadingHistory]
for {
userReadingHistory <- req.as[UserReadingHistory]
storedHistory <- mongoRepository.put(userReadingHistory)
json: Json = SuccessfulPut(storedHistory.userId).asJson
response <- Ok(json)
} yield response
}
}
Loading

0 comments on commit e71efe8

Please sign in to comment.