All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
pl.touk.nussknacker.ui.api.AppApiHttpService.scala Maven / Gradle / Ivy
package pl.touk.nussknacker.ui.api
import com.typesafe.config.{Config, ConfigRenderOptions}
import com.typesafe.scalalogging.LazyLogging
import io.circe.parser
import pl.touk.nussknacker.engine.api.deployment.ProcessState
import pl.touk.nussknacker.engine.api.deployment.simple.SimpleStateStatus.ProblemStateStatus
import pl.touk.nussknacker.engine.api.process.{ProcessName, ProcessingType}
import pl.touk.nussknacker.engine.util.Implicits.RichTupleList
import pl.touk.nussknacker.engine.version.BuildInfo
import pl.touk.nussknacker.ui.api.description.AppApiEndpoints
import pl.touk.nussknacker.ui.api.description.AppApiEndpoints.Dtos._
import pl.touk.nussknacker.ui.process.ProcessService.GetScenarioWithDetailsOptions
import pl.touk.nussknacker.ui.process.processingtype.{ProcessingTypeDataProvider, ProcessingTypeDataReload}
import pl.touk.nussknacker.ui.process.{ProcessService, ScenarioQuery}
import pl.touk.nussknacker.ui.security.api.{AuthManager, LoggedUser, NussknackerInternalUser}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal
class AppApiHttpService(
config: Config,
authManager: AuthManager,
processingTypeDataReloader: ProcessingTypeDataReload,
modelBuildInfos: ProcessingTypeDataProvider[Map[String, String], _],
categories: ProcessingTypeDataProvider[String, _],
processService: ProcessService,
shouldExposeConfig: Boolean
)(implicit executionContext: ExecutionContext)
extends BaseHttpService(authManager)
with LazyLogging {
private val appApiEndpoints = new AppApiEndpoints(authManager.authenticationEndpointInput())
expose {
appApiEndpoints.appHealthCheckEndpoint
.serverLogicSuccess { _ =>
Future.successful(HealthCheckProcessSuccessResponseDto())
}
}
expose {
appApiEndpoints.processDeploymentHealthCheckEndpoint
.serverSecurityLogic(authorizeKnownUser[HealthCheckProcessErrorResponseDto])
.serverLogic { implicit loggedUser => _ =>
problemStateByProcessName
.map { set =>
if (set.isEmpty) {
success(HealthCheckProcessSuccessResponseDto())
} else {
if (logger.underlying.isDebugEnabled) {
logger.debug(s"Scenarios with status PROBLEM: $set")
} else {
logger.warn(s"Scenarios with status PROBLEM: ${set.keys}")
}
businessError(
HealthCheckProcessErrorResponseDto(
message = Some("Scenarios with status PROBLEM"),
processes = Some(set.keys.map(_.value).toSet)
)
)
}
}
.recover { case NonFatal(e) =>
logger.error("Failed to get statuses", e)
businessError(
HealthCheckProcessErrorResponseDto(
message = Some("Failed to retrieve job statuses"),
processes = None
)
)
}
}
}
expose {
appApiEndpoints.processValidationHealthCheckEndpoint
.serverSecurityLogic(authorizeKnownUser[HealthCheckProcessErrorResponseDto])
.serverLogic { implicit loggedUser => _ =>
processesWithValidationErrors.map { processes =>
if (processes.isEmpty) {
success(HealthCheckProcessSuccessResponseDto())
} else {
businessError(
HealthCheckProcessErrorResponseDto(
message = Some("Scenarios with validation errors"),
processes = Some(processes.toSet)
)
)
}
}
}
}
expose {
appApiEndpoints.buildInfoEndpoint
.serverLogicSuccess { _ =>
Future {
import net.ceedubs.ficus.Ficus._
val configuredBuildInfo = config.getAs[Map[String, String]]("globalBuildInfo")
// TODO: Warning, here is a little security leak. Everyone can discover configured processing types.
// We should consider adding an authorization of access rights to this data.
val modelBuildInfo: Map[ProcessingType, Map[String, String]] =
modelBuildInfos.all(NussknackerInternalUser.instance)
BuildInfoDto(
BuildInfo.name,
BuildInfo.gitCommit,
BuildInfo.buildTime,
BuildInfo.version,
modelBuildInfo,
configuredBuildInfo
)
}
}
}
expose(when = shouldExposeConfig) {
appApiEndpoints.serverConfigEndpoint
.serverSecurityLogic(authorizeAdminUser[Unit])
.serverLogic { _ => _ =>
Future {
val configJson = parser.parse(config.root().render(ConfigRenderOptions.concise())).left.map(_.message)
configJson match {
case Right(json) =>
success(ServerConfigInfoDto(json))
case Left(errorMessage) =>
logger.error(s"Cannot create JSON from the Nussknacker configuration. Error: $errorMessage")
throw new Exception("Cannot prepare configuration")
}
}
}
}
expose {
// This endpoint is used only by external project
// TODO: We should remove this endpoint after we fully switch to processing modes - see ConfigProcessCategoryService.checkCategoryToProcessingTypeMappingAmbiguity
appApiEndpoints.userCategoriesWithProcessingTypesEndpoint
.serverSecurityLogic(authorizeKnownUser[Unit])
.serverLogicSuccess { loggedUser => _ =>
Future {
val processingTypeByCategory = categories
.all(loggedUser)
.toList
.map { case (processingType, category) =>
category -> processingType
}
.toMapCheckingDuplicates
UserCategoriesWithProcessingTypesDto(processingTypeByCategory)
}
}
}
expose {
appApiEndpoints.processingTypeDataReloadEndpoint
.serverSecurityLogic(authorizeAdminUser[Unit])
.serverLogic { _ => _ =>
Future(
success(processingTypeDataReloader.reloadAll())
)
}
}
private def problemStateByProcessName(implicit user: LoggedUser): Future[Map[ProcessName, ProcessState]] = {
for {
processes <- processService.getLatestProcessesWithDetails(
ScenarioQuery.deployed,
GetScenarioWithDetailsOptions.detailsOnly.copy(fetchState = true)
)
statusMap = processes.flatMap(process => process.state.map(process.name -> _)).toMap
withProblem = statusMap.collect {
case (name, processStatus @ ProcessState(_, _ @ProblemStateStatus(_, _), _, _, _, _, _, _, _, _)) =>
(name, processStatus)
}
} yield withProblem
}
private def processesWithValidationErrors(implicit user: LoggedUser): Future[List[String]] = {
processService
.getLatestProcessesWithDetails(
ScenarioQuery.unarchivedProcesses,
GetScenarioWithDetailsOptions.withsScenarioGraph.withValidation
)
.map { processes =>
processes
.filterNot(_.validationResultUnsafe.errors.isEmpty)
.map(_.name.value)
}
}
}