aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/core/init/CloudServices.scala
blob: 857dd4c6131908787db11aa22cbd54e1e67d4bee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package xyz.driver.core
package init

import java.nio.file.Paths

import xyz.driver.core.messaging.{CreateOnDemand, GoogleBus, QueueBus, StreamBus}
import xyz.driver.core.reporting._
import xyz.driver.core.rest.DnsDiscovery
import xyz.driver.core.storage.{BlobStorage, FileSystemBlobStorage, GcsBlobStorage}

import scala.collection.JavaConverters._

/** Mixin trait that provides essential cloud utilities. */
trait CloudServices extends AkkaBootable { self =>

  /** The platform that this application is running on.
    * @group config
    */
  def platform: Platform = Platform.current

  /** Service discovery for the current platform.
    * @group utilities
    */
  lazy val discovery: DnsDiscovery = {
    def getOverrides(): Map[String, String] = {
      val block = config.getObject("services.dev-overrides").unwrapped().asScala
      for ((key, value) <- block) yield {
        require(value.isInstanceOf[String], s"Service URL override for '$key' must be a string. Found '$value'.")
        key -> value.toString
      }
    }.toMap
    val overrides = platform match {
      case Platform.Dev => getOverrides()
      // TODO: currently, deployed services must be configured via Kubernetes DNS resolver. Maybe we may want to
      // provide a way to override deployed services as well.
      case _ => Map.empty[String, String]
    }
    new DnsDiscovery(clientTransport, overrides)
  }

  /* TODO: this reporter uses the platform to determine if JSON logging should be enabled.
   * Since the default logger uses slf4j, its settings must be specified before a logger
   * is first accessed. This in turn leads to somewhat convoluted code,
   * since we can't log when the platform being is determined.
   * A potential fix would be to make the log format independent of the platform, and always log
   * as JSON for example.
   */
  override lazy val reporter: Reporter with ScalaLoggingCompat = {
    Console.println("determining platform") // scalastyle:ignore
    val r = platform match {
      case p @ Platform.GoogleCloud(_, _) =>
        new GoogleReporter(p.credentials, p.namespace) with ScalaLoggingCompat with GoogleMdcLogger {
          val logger = ScalaLoggingCompat.defaultScalaLogger(true)
        }
      case Platform.Dev =>
        new NoTraceReporter with ScalaLoggingCompat {
          val logger = ScalaLoggingCompat.defaultScalaLogger(false)
        }
    }
    r.info(s"application started on platform '${platform}'")(SpanContext.fresh())
    r
  }

  /** Object storage.
    *
    * When running on a cloud platform, prepends `$project-` to bucket names, where `$project`
    * is the project ID (for example 'driverinc-production` or `driverinc-sandbox`).
    *
    * @group utilities
    */
  def storage(bucketName: String): BlobStorage =
    platform match {
      case p @ Platform.GoogleCloud(keyfile, _) =>
        GcsBlobStorage.fromKeyfile(keyfile, s"${p.project}-$bucketName")
      case Platform.Dev =>
        new FileSystemBlobStorage(Paths.get(s".data-$bucketName"))
    }

  /** Message bus.
    * @group utilities
    */
  def messageBus: StreamBus = platform match {
    case p @ Platform.GoogleCloud(_, namespace) =>
      new GoogleBus(p.credentials, namespace) with StreamBus with CreateOnDemand
    case Platform.Dev =>
      new QueueBus()(self.system) with StreamBus
  }

}