storage.drivers.cassandra.CassandraDataStores.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otoroshi_2.12 Show documentation
Show all versions of otoroshi_2.12 Show documentation
Lightweight api management on top of a modern http reverse proxy
The newest version!
package otoroshi.storage.drivers.cassandra
import akka.NotUsed
import akka.actor.ActorSystem
import akka.http.scaladsl.util.FastFuture
import akka.stream.Materializer
import akka.stream.scaladsl.{Sink, Source}
import akka.util.ByteString
import com.typesafe.config.ConfigFactory
import otoroshi.auth.AuthConfigsDataStore
import otoroshi.cluster.{Cluster, ClusterStateDataStore, KvClusterStateDataStore}
import otoroshi.env.Env
import otoroshi.events.{AlertDataStore, AuditDataStore, HealthCheckDataStore}
import otoroshi.gateway.{InMemoryRequestsDataStore, RequestsDataStore}
import otoroshi.models._
import otoroshi.next.models._
import otoroshi.script.{KvScriptDataStore, ScriptDataStore}
import otoroshi.ssl.{CertificateDataStore, ClientCertificateValidationDataStore, KvClientCertificateValidationDataStore}
import otoroshi.storage._
import otoroshi.storage.stores._
import otoroshi.tcp.{KvTcpServiceDataStoreDataStore, TcpServiceDataStore}
import otoroshi.utils.syntax.implicits._
import play.api.inject.ApplicationLifecycle
import play.api.libs.json._
import play.api.{Configuration, Environment, Logger}
import scala.concurrent.{ExecutionContext, Future}
class CassandraDataStores(
naive: Boolean,
configuration: Configuration,
environment: Environment,
lifecycle: ApplicationLifecycle,
env: Env
) extends DataStores {
lazy val logger = Logger("otoroshi-cassandra-datastores")
lazy val redisStatsItems: Int =
configuration.getOptionalWithFileSupport[Int]("app.cassandra.windowSize").getOrElse(99)
lazy val actorSystem =
ActorSystem(
"otoroshi-cassandra-system",
configuration
.getOptionalWithFileSupport[Configuration]("app.actorsystems.datastore")
.map(_.underlying)
.getOrElse(ConfigFactory.empty)
)
lazy val mat = Materializer(actorSystem)
lazy val redis: RedisLike with RawGetRedis = new NewCassandraRedis(
actorSystem,
configuration
)(actorSystem.dispatcher, mat, env)
override def before(
configuration: Configuration,
environment: Environment,
lifecycle: ApplicationLifecycle
): Future[Unit] = {
logger.info("Now using Cassandra DataStores")
redis.start()
_serviceDescriptorDataStore.startCleanup(env)
_certificateDataStore.startSync()
FastFuture.successful(())
}
override def after(
configuration: Configuration,
environment: Environment,
lifecycle: ApplicationLifecycle
): Future[Unit] = {
_serviceDescriptorDataStore.stopCleanup()
_certificateDataStore.stopSync()
redis.stop()
actorSystem.terminate()
FastFuture.successful(())
}
private lazy val _privateAppsUserDataStore = new KvPrivateAppsUserDataStore(redis, env)
private lazy val _backOfficeUserDataStore = new KvBackOfficeUserDataStore(redis, env)
private lazy val _serviceGroupDataStore = new KvServiceGroupDataStore(redis, env)
private lazy val _globalConfigDataStore = new KvGlobalConfigDataStore(redis, env)
private lazy val _apiKeyDataStore = new KvApiKeyDataStore(redis, env)
private lazy val _serviceDescriptorDataStore = new KvServiceDescriptorDataStore(redis, redisStatsItems, env)
private lazy val _simpleAdminDataStore = new KvSimpleAdminDataStore(redis, env)
private lazy val _alertDataStore = new KvAlertDataStore(redis)
private lazy val _auditDataStore = new KvAuditDataStore(redis)
private lazy val _healthCheckDataStore = new KvHealthCheckDataStore(redis, env)
private lazy val _errorTemplateDataStore = new KvErrorTemplateDataStore(redis, env)
private lazy val _requestsDataStore = new InMemoryRequestsDataStore()
private lazy val _canaryDataStore = new KvCanaryDataStore(redis, env)
private lazy val _chaosDataStore = new KvChaosDataStore(redis, env)
private lazy val _jwtVerifDataStore = new KvGlobalJwtVerifierDataStore(redis, env)
private lazy val _globalOAuth2ConfigDataStore = new KvAuthConfigsDataStore(redis, env)
private lazy val _certificateDataStore = new KvCertificateDataStore(redis, env)
private lazy val _clusterStateDataStore = new KvClusterStateDataStore(redis, env)
override def clusterStateDataStore: ClusterStateDataStore = _clusterStateDataStore
private lazy val _clientCertificateValidationDataStore = new KvClientCertificateValidationDataStore(redis, env)
override def clientCertificateValidationDataStore: ClientCertificateValidationDataStore =
_clientCertificateValidationDataStore
private lazy val _scriptDataStore = new KvScriptDataStore(redis, env)
override def scriptDataStore: ScriptDataStore = _scriptDataStore
private lazy val _tcpServiceDataStore = new KvTcpServiceDataStoreDataStore(redis, env)
override def tcpServiceDataStore: TcpServiceDataStore = _tcpServiceDataStore
private lazy val _rawDataStore = new KvRawDataStore(redis)
override def rawDataStore: RawDataStore = _rawDataStore
private lazy val _webAuthnAdminDataStore = new KvWebAuthnAdminDataStore()
override def webAuthnAdminDataStore: WebAuthnAdminDataStore = _webAuthnAdminDataStore
private lazy val _webAuthnRegistrationsDataStore = new WebAuthnRegistrationsDataStore()
override def webAuthnRegistrationsDataStore: WebAuthnRegistrationsDataStore = _webAuthnRegistrationsDataStore
private lazy val _tenantDataStore = new TenantDataStore(redis, env)
override def tenantDataStore: TenantDataStore = _tenantDataStore
private lazy val _teamDataStore = new TeamDataStore(redis, env)
override def teamDataStore: TeamDataStore = _teamDataStore
private lazy val _dataExporterConfigDataStore = new DataExporterConfigDataStore(redis, env)
override def dataExporterConfigDataStore: DataExporterConfigDataStore = _dataExporterConfigDataStore
private lazy val _routeDataStore = new KvNgRouteDataStore(redis, env)
override def routeDataStore: NgRouteDataStore = _routeDataStore
private lazy val _routesCompositionDataStore = new KvNgRouteCompositionDataStore(redis, env)
override def routeCompositionDataStore: NgRouteCompositionDataStore = _routesCompositionDataStore
private lazy val _backendsDataStore = new KvStoredNgBackendDataStore(redis, env)
override def backendsDataStore: StoredNgBackendDataStore = _backendsDataStore
private lazy val _wasmPluginDataStore = new KvWasmPluginDataStore(redis, env)
override def wasmPluginsDataStore: WasmPluginDataStore = _wasmPluginDataStore
private lazy val _draftDataStore = new KvDraftDataStore(redis, env)
override def draftsDataStore: DraftDataStore = _draftDataStore
private lazy val _adminPreferencesDatastore = new AdminPreferencesDatastore(env)
def adminPreferencesDatastore: AdminPreferencesDatastore = _adminPreferencesDatastore
override def privateAppsUserDataStore: PrivateAppsUserDataStore = _privateAppsUserDataStore
override def backOfficeUserDataStore: BackOfficeUserDataStore = _backOfficeUserDataStore
override def serviceGroupDataStore: ServiceGroupDataStore = _serviceGroupDataStore
override def globalConfigDataStore: GlobalConfigDataStore = _globalConfigDataStore
override def apiKeyDataStore: ApiKeyDataStore = _apiKeyDataStore
override def serviceDescriptorDataStore: ServiceDescriptorDataStore = _serviceDescriptorDataStore
override def simpleAdminDataStore: SimpleAdminDataStore = _simpleAdminDataStore
override def alertDataStore: AlertDataStore = _alertDataStore
override def auditDataStore: AuditDataStore = _auditDataStore
override def healthCheckDataStore: HealthCheckDataStore = _healthCheckDataStore
override def errorTemplateDataStore: ErrorTemplateDataStore = _errorTemplateDataStore
override def requestsDataStore: RequestsDataStore = _requestsDataStore
override def canaryDataStore: CanaryDataStore = _canaryDataStore
override def health()(implicit ec: ExecutionContext): Future[DataStoreHealth] = redis.health()(ec)
override def chaosDataStore: ChaosDataStore = _chaosDataStore
override def globalJwtVerifierDataStore: GlobalJwtVerifierDataStore = _jwtVerifDataStore
override def certificatesDataStore: CertificateDataStore = _certificateDataStore
override def authConfigsDataStore: AuthConfigsDataStore = _globalOAuth2ConfigDataStore
override def rawExport(
group: Int
)(implicit ec: ExecutionContext, mat: Materializer, env: Env): Source[JsValue, NotUsed] = {
Source
.future(
redis.keys(s"${env.storageRoot}:*")
)
.mapConcat(_.toList)
.grouped(group)
.mapAsync(1) {
case keys if keys.isEmpty => FastFuture.successful(Seq.empty[JsValue])
case keys => {
Future.sequence(
keys
.filterNot { key =>
Cluster.filteredKey(key, env)
// key == s"${env.storageRoot}:cluster:" ||
// key == s"${env.storageRoot}:events:audit" ||
// key == s"${env.storageRoot}:events:alerts" ||
// key.startsWith(s"${env.storageRoot}:users:backoffice") ||
// key.startsWith(s"${env.storageRoot}:admins:") ||
// key.startsWith(s"${env.storageRoot}:u2f:users:") ||
// // key.startsWith(s"${env.storageRoot}:users:") ||
// key.startsWith(s"${env.storageRoot}:webauthn:admins:") ||
// key.startsWith(s"${env.storageRoot}:deschealthcheck:") ||
// key.startsWith(s"${env.storageRoot}:scall:stats:") ||
// key.startsWith(s"${env.storageRoot}:scalldur:stats:") ||
// key.startsWith(s"${env.storageRoot}:scallover:stats:") ||
// (key.startsWith(s"${env.storageRoot}:data:") && key.endsWith(":stats:in")) ||
// (key.startsWith(s"${env.storageRoot}:data:") && key.endsWith(":stats:out"))
}
.map { key =>
redis.rawGet(key).flatMap {
case None => FastFuture.successful(JsNull)
case Some((typ, ttl, value)) => {
fetchValueForType(key, typ, value).map {
case JsNull => JsNull
case value =>
Json.obj(
"k" -> key,
"v" -> value,
"t" -> (if (ttl == -1) -1 else (System.currentTimeMillis() + ttl)),
"w" -> typ
)
}
}
}
}
)
}
}
.map(_.filterNot(_ == JsNull))
.mapConcat(_.toList)
}
override def fullNdJsonExport(group: Int, groupWorkers: Int, keyWorkers: Int): Future[Source[JsValue, _]] = {
implicit val ev = env
implicit val ecc = env.otoroshiExecutionContext
implicit val mat = env.otoroshiMaterializer
FastFuture.successful(
Source
.future(redis.keys(s"${env.storageRoot}:*"))
.mapConcat(_.toList)
.grouped(10)
.mapAsync(1) {
case keys if keys.isEmpty => FastFuture.successful(Seq.empty[JsValue])
case keys => {
Source(keys.toList)
.mapAsync(1) { key =>
redis.rawGet(key).flatMap {
case None => FastFuture.successful(JsNull)
case Some((typ, ttl, value)) => {
fetchValueForType(key, typ, value).map {
case JsNull => JsNull
case value =>
Json.obj(
"k" -> key,
"v" -> value,
"t" -> (if (ttl == -1) -1 else (System.currentTimeMillis() + ttl)),
"w" -> typ
)
}
}
}
}
.runWith(Sink.seq)
.map(_.filterNot(_ == JsNull))
}
}
.mapConcat(_.toList)
)
}
override def fullNdJsonImport(exportSource: Source[JsValue, _]): Future[Unit] = {
implicit val ev = env
implicit val ecc = env.otoroshiExecutionContext
implicit val mat = env.otoroshiMaterializer
redis
.keys(s"${env.storageRoot}:*")
.flatMap(keys => if (keys.nonEmpty) redis.del(keys: _*) else FastFuture.successful(0L))
.flatMap { _ =>
exportSource
.mapAsync(1) { json =>
val key = (json \ "k").as[String]
val value = (json \ "v").as[JsValue]
val pttl = (json \ "t").as[Long]
val what = (json \ "w").as[String]
(what match {
case "counter" => redis.set(key, value.as[Long].toString)
case "string" => redis.set(key, value.as[String])
case "hash" =>
Source(value.as[JsObject].value.toList)
.mapAsync(1)(v => redis.hset(key, v._1, Json.stringify(v._2)))
.runWith(Sink.ignore)
case "list" => redis.lpush(key, value.as[JsArray].value.map(Json.stringify): _*)
case "set" => redis.sadd(key, value.as[JsArray].value.map(Json.stringify): _*)
case _ => FastFuture.successful(0L)
}).flatMap { _ =>
if (pttl > -1L) {
redis.pexpire(key, pttl)
} else {
FastFuture.successful(true)
}
}
}
.runWith(Sink.ignore)
.map(_ => ())
}
}
private def fetchValueForType(key: String, typ: String, value: Any)(implicit
ec: ExecutionContext
): Future[JsValue] = {
(typ, value) match {
case ("hash", v: Map[String, ByteString]) =>
FastFuture.successful(JsObject(v.map(t => (t._1, JsString(t._2.utf8String)))))
case ("list", v: Seq[ByteString]) => FastFuture.successful(JsArray(v.map(s => JsString(s.utf8String))))
case ("set", v: Set[ByteString]) => FastFuture.successful(JsArray(v.toSeq.map(s => JsString(s.utf8String))))
case ("string", v: ByteString) =>
Option(v) match {
case None => FastFuture.successful(JsNull)
case Some(a) => FastFuture.successful(JsString(a.utf8String))
}
case _ => FastFuture.successful(JsNull)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy