Skip to content

Commit

Permalink
[NU-1979] DeploymentService refactor: extracted ActionService and Sce…
Browse files Browse the repository at this point in the history
…narioStateProvider + BuildInfo as a Map -> ModelInfo as a value class (#7563)
  • Loading branch information
arkadius authored Feb 14, 2025
1 parent 6af265e commit 8f695ea
Show file tree
Hide file tree
Showing 54 changed files with 1,327 additions and 1,915 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package pl.touk.nussknacker.engine.api.modelinfo

import io.circe
import io.circe.parser._
import io.circe.syntax.EncoderOps
import io.circe.{Decoder, Encoder, Printer}

case class ModelInfo private (parameters: Map[String, String]) {

val asJsonString: String = {
val prettyParams = Printer.spaces2.copy(sortKeys = true)
parameters.asJson.printWith(prettyParams)
}

}

object ModelInfo {

val empty = new ModelInfo(Map.empty[String, String])

def fromMap(parameters: Map[String, String]) = new ModelInfo(parameters)

def parseJsonString(json: String): Either[circe.Error, ModelInfo] = {
parse(json)
.flatMap(js => Decoder[Map[String, String]].decodeJson(js))
.map(new ModelInfo(_))
}

implicit val encoder: Encoder[ModelInfo] = Encoder[Map[String, String]].contramap(_.parameters)

implicit val decoder: Decoder[ModelInfo] = Decoder[Map[String, String]].map(ModelInfo.fromMap)

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package pl.touk.nussknacker.defaultmodel

import pl.touk.nussknacker.engine.api.modelinfo.ModelInfo
import pl.touk.nussknacker.engine.api.process.WithCategories.anyCategory
import pl.touk.nussknacker.engine.api.process.{EmptyProcessConfigCreator, _}

Expand All @@ -24,10 +25,12 @@ class DefaultConfigCreator extends EmptyProcessConfigCreator {
)
}

override def buildInfo(): Map[String, String] = {
pl.touk.nussknacker.engine.version.BuildInfo.toMap.map { case (k, v) =>
k -> v.toString
} + ("name" -> "defaultModel")
override def modelInfo(): ModelInfo = {
ModelInfo.fromMap(
pl.touk.nussknacker.engine.version.BuildInfo.toMap.map { case (k, v) =>
k -> v.toString
} + ("name" -> "defaultModel")
)
}

}
3 changes: 2 additions & 1 deletion designer/client/cypress/e2e/process.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ describe("Process", () => {
cy.viewport("macbook-15");
cy.contains(/^deploy$/i).click();
cy.intercept("POST", "/api/processManagement/deploy/*").as("deploy");
cy.contains(/^ok$/i).should("be.enabled").click();
cy.contains(/^ok$/i).should("be.enabled").as("okButton");
cy.get("@okButton").click();
cy.wait("@deploy", { timeout: 20000 }).its("response.statusCode").should("eq", 400);
cy.contains(/^Comment is required.$/i).should("exist");
});
Expand Down
8 changes: 0 additions & 8 deletions designer/client/src/components/Process/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,12 @@ export type ActionName = string;

export type ProcessVersionId = number;

export type BuildInfoType = {
buildTime: string;
gitCommit: string;
name: string;
version: string;
};

export type ProcessActionType = {
performedAt: Instant;
user: string;
actionName: ActionName;
commentId?: number;
comment?: string;
buildInfo?: BuildInfoType;
processVersionId: ProcessVersionId;
};

Expand Down
6 changes: 2 additions & 4 deletions designer/client/src/containers/BuildInfoProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React, { useContext } from "react";
import { createContext, PropsWithChildren, useEffect, useState } from "react";
import { BuildInfoType } from "../components/Process/types";
import React, { createContext, PropsWithChildren, useContext, useEffect, useState } from "react";
import HttpService, { AppBuildInfo } from "../http/HttpService";
import LoaderSpinner from "../components/spinner/Spinner";

const BuildInfoContext = createContext<BuildInfoType>(null);
const BuildInfoContext = createContext<AppBuildInfo>(null);

export const BuildInfoProvider = ({ children }: PropsWithChildren) => {
const [buildInfo, setBuildInfo] = useState<AppBuildInfo>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package pl.touk.nussknacker.restmodel.component

import pl.touk.nussknacker.engine.api.ProcessVersion
import pl.touk.nussknacker.engine.api.component.Component.AllowedProcessingModes
import pl.touk.nussknacker.engine.api.component.{
ComponentGroupName,
Expand All @@ -14,17 +13,18 @@ import pl.touk.nussknacker.engine.api.deployment.{
ProcessActionState,
ScenarioActionName
}
import pl.touk.nussknacker.engine.api.modelinfo.ModelInfo
import pl.touk.nussknacker.engine.api.process.{ProcessId, ProcessName, VersionId}
import pl.touk.nussknacker.restmodel.BaseEndpointDefinitions
import pl.touk.nussknacker.restmodel.BaseEndpointDefinitions.SecuredEndpoint
import pl.touk.nussknacker.restmodel.component.NodeUsageData.ScenarioUsageData
import pl.touk.nussknacker.security.AuthCredentials
import sttp.model.StatusCode.{NotFound, Ok}
import sttp.tapir.Codec.PlainCodec
import sttp.tapir.EndpointIO.Example
import sttp.tapir._
import sttp.tapir.generic.auto.schemaForCaseClass
import sttp.tapir.json.circe.jsonBody
import sttp.tapir.Codec.PlainCodec
import sttp.tapir.EndpointIO.Example

import java.net.URI
import java.time.Instant
Expand All @@ -37,6 +37,7 @@ class ComponentApiEndpoints(auth: EndpointInput[AuthCredentials]) extends BaseEn
implicit val versionIdSchema: Schema[VersionId] = Schema.schemaForLong.as[VersionId]
implicit val actionIdSchema: Schema[ProcessActionId] = Schema.schemaForUUID.as[ProcessActionId]
implicit val componentGroupNameSchema: Schema[ComponentGroupName] = Schema.string[ComponentGroupName]
implicit val modelInfoSchema: Schema[ModelInfo] = Schema.schemaForMap[String].as[ModelInfo]

import ComponentApiEndpoints.ComponentCodec._

Expand Down Expand Up @@ -121,7 +122,7 @@ class ComponentApiEndpoints(auth: EndpointInput[AuthCredentials]) extends BaseEn
failureMessage = None,
commentId = None,
comment = None,
buildInfo = Map.empty
modelInfo = None
)
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "scenario_activities" ALTER COLUMN "build_info" RENAME TO "model_info";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "scenario_activities" RENAME COLUMN "build_info" TO "model_info";
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ object V1_057__MigrateActionsAndCommentsToScenarioActivitiesDefinition extends L
comment.createDate.?, // finishedAt
None: Option[String], // state
None: Option[String], // errorMessage
None: Option[String], // buildInfo - always absent in old actions
None: Option[String], // modelInfo - always absent in old actions
"{}" // additionalProperties always empty in old actions
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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.modelinfo.ModelInfo
import pl.touk.nussknacker.engine.api.process.{ProcessName, ProcessingType}
import pl.touk.nussknacker.engine.util.ExecutionContextWithIORuntime
import pl.touk.nussknacker.engine.util.Implicits.RichTupleList
Expand All @@ -26,7 +27,7 @@ class AppApiHttpService(
config: Config,
authManager: AuthManager,
processingTypeDataReloader: ReloadableProcessingTypeDataProvider,
modelBuildInfos: ProcessingTypeDataProvider[Map[String, String], _],
modelInfos: ProcessingTypeDataProvider[ModelInfo, _],
categories: ProcessingTypeDataProvider[String, _],
processService: ProcessService,
shouldExposeConfig: Boolean
Expand Down Expand Up @@ -106,14 +107,14 @@ class AppApiHttpService(
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)
val modelInfo: Map[ProcessingType, ModelInfo] =
modelInfos.all(NussknackerInternalUser.instance)
BuildInfoDto(
BuildInfo.name,
BuildInfo.gitCommit,
BuildInfo.buildTime,
BuildInfo.version,
modelBuildInfo,
modelInfo,
configuredBuildInfo
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ import pl.touk.nussknacker.ui.process.ProcessService.{
CreateScenarioCommand,
FetchScenarioGraph,
GetScenarioWithDetailsOptions,
SkipAdditionalFields,
UpdateScenarioCommand
}
import pl.touk.nussknacker.ui.process.ScenarioWithDetailsConversions._
import pl.touk.nussknacker.ui.process._
import pl.touk.nussknacker.ui.process.deployment.ScenarioStateProvider
import pl.touk.nussknacker.ui.security.api.LoggedUser
import pl.touk.nussknacker.ui.util._

import scala.concurrent.{ExecutionContext, Future}

class ProcessesResources(
protected val processService: ProcessService,
processStateService: ProcessStateProvider,
scenarioStateProvider: ScenarioStateProvider,
processToolbarService: ScenarioToolbarService,
val processAuthorizer: AuthorizeProcess,
processChangeListener: ProcessChangeListener
Expand Down Expand Up @@ -212,7 +212,9 @@ class ProcessesResources(
currentlyPresentedVersionIdParameter { currentlyPresentedVersionId =>
complete {
implicit val freshnessPolicy: DataFreshnessPolicy = DataFreshnessPolicy.Fresh
processStateService.getProcessState(processId, currentlyPresentedVersionId).map(ToResponseMarshallable(_))
scenarioStateProvider
.getProcessState(processId, currentlyPresentedVersionId)
.map(ToResponseMarshallable(_))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import enumeratum._
import io.circe.syntax.EncoderOps
import io.circe.{Codec => CirceCodec, Decoder, Encoder, Json}
import pl.touk.nussknacker.engine.api.CirceUtil.HCursorExt
import pl.touk.nussknacker.engine.api.modelinfo.ModelInfo
import pl.touk.nussknacker.restmodel.BaseEndpointDefinitions
import pl.touk.nussknacker.restmodel.BaseEndpointDefinitions.SecuredEndpoint
import pl.touk.nussknacker.security.AuthCredentials
Expand Down Expand Up @@ -126,10 +127,12 @@ class AppApiEndpoints(auth: EndpointInput[AuthCredentials]) extends BaseEndpoint
buildTime = "2023-09-25T09:26:30.402299",
version = "1.234.0",
processingType = Map(
"streaming" -> Map(
"process-version" -> "0.1",
"engine-version" -> "0.2",
"generation-time" -> "2023-09-25T09:26:30.402299"
"streaming" -> ModelInfo.fromMap(
Map(
"process-version" -> "0.1",
"engine-version" -> "0.2",
"generation-time" -> "2023-09-25T09:26:30.402299"
)
)
)
)
Expand Down Expand Up @@ -223,6 +226,8 @@ object AppApiEndpoints {

object Dtos {

private implicit val modelInfoSchema: Schema[ModelInfo] = Schema.schemaForMap[String].as[ModelInfo]

@derive(encoder, decoder, schema)
final case class HealthCheckProcessSuccessResponseDto private (
status: HealthCheckProcessSuccessResponseDto.Status,
Expand Down Expand Up @@ -270,7 +275,7 @@ object AppApiEndpoints {
gitCommit: String,
buildTime: String,
version: String,
processingType: Map[String, Map[String, String]],
processingType: Map[String, ModelInfo],
globalBuildInfo: Option[Map[String, String]] = None
)

Expand All @@ -284,7 +289,7 @@ object AppApiEndpoints {
version <- c.downField("version").as[String]
buildTime <- c.downField("buildTime").as[String]
gitCommit <- c.downField("gitCommit").as[String]
processingType <- c.downField("processingType").as[Map[String, Map[String, String]]]
processingType <- c.downField("processingType").as[Map[String, ModelInfo]]
globalBuildInfoOpt <- c.downField("globalBuildInfo").as[Option[Map[String, String]]]
globalBuildInfo <- globalBuildInfoOpt match {
case globalBuildInfo @ Some(_) =>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package pl.touk.nussknacker.ui.db.entity

import com.typesafe.scalalogging.LazyLogging
import pl.touk.nussknacker.engine.api.modelinfo.ModelInfo
import pl.touk.nussknacker.engine.api.deployment.ProcessActionState.ProcessActionState
import pl.touk.nussknacker.engine.api.deployment.{
DeploymentStatusName,
Expand All @@ -13,7 +15,7 @@ import slick.jdbc.JdbcProfile

import java.util.UUID

trait BaseEntityFactory {
trait BaseEntityFactory extends LazyLogging {
protected val profile: JdbcProfile
import profile.api._

Expand Down Expand Up @@ -41,4 +43,18 @@ trait BaseEntityFactory {
implicit def deploymentStatusName: BaseColumnType[DeploymentStatusName] =
MappedColumnType.base[DeploymentStatusName, String](_.value, DeploymentStatusName.apply)

implicit def modelInfoMapper: BaseColumnType[ModelInfo] =
MappedColumnType.base[ModelInfo, String](
_.asJsonString,
ModelInfo
.parseJsonString(_)
.fold(
{ err =>
logger.warn(s"Saved model info is not a json's object: ${err.getMessage}. Empty map will be returned")
ModelInfo.empty
},
identity
)
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import enumeratum.EnumEntry.UpperSnakecase
import enumeratum._
import io.circe.Decoder
import io.circe.syntax.EncoderOps
import pl.touk.nussknacker.engine.api.modelinfo.ModelInfo
import pl.touk.nussknacker.engine.api.deployment.ProcessActionState.ProcessActionState
import pl.touk.nussknacker.engine.api.deployment._
import pl.touk.nussknacker.engine.api.process.ProcessId
Expand Down Expand Up @@ -59,7 +60,7 @@ trait ScenarioActivityEntityFactory extends BaseEntityFactory {

def errorMessage: Rep[Option[String]] = column[Option[String]]("error_message")

def buildInfo: Rep[Option[String]] = column[Option[String]]("build_info")
def modelInfo: Rep[Option[ModelInfo]] = column[Option[ModelInfo]]("model_info")

def additionalProperties: Rep[AdditionalProperties] = column[AdditionalProperties]("additional_properties")

Expand All @@ -82,7 +83,7 @@ trait ScenarioActivityEntityFactory extends BaseEntityFactory {
performedAt,
state,
errorMessage,
buildInfo,
modelInfo,
additionalProperties,
) <> (
ScenarioActivityEntityData.apply _ tupled, ScenarioActivityEntityData.unapply
Expand Down Expand Up @@ -195,6 +196,6 @@ final case class ScenarioActivityEntityData(
finishedAt: Option[Timestamp],
state: Option[ProcessActionState],
errorMessage: Option[String],
buildInfo: Option[String],
modelInfo: Option[ModelInfo],
additionalProperties: AdditionalProperties,
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import pl.touk.nussknacker.ui.NuDesignerError
import pl.touk.nussknacker.ui.api.ProcessesResources.ProcessUnmarshallingError
import pl.touk.nussknacker.ui.process.ProcessService._
import pl.touk.nussknacker.ui.process.ScenarioWithDetailsConversions._
import pl.touk.nussknacker.ui.process.deployment.ScenarioStateProvider
import pl.touk.nussknacker.ui.process.exception.{ProcessIllegalAction, ProcessValidationError}
import pl.touk.nussknacker.ui.process.label.ScenarioLabel
import pl.touk.nussknacker.ui.process.marshall.CanonicalProcessConverter
Expand Down Expand Up @@ -177,7 +178,7 @@ trait ProcessService {
* Each action includes verification based on actual process state and checking process is fragment / archived.
*/
class DBProcessService(
processStateProvider: ProcessStateProvider,
processStateProvider: ScenarioStateProvider,
newProcessPreparers: ProcessingTypeDataProvider[NewProcessPreparer, _],
scenarioParametersServiceProvider: ProcessingTypeDataProvider[_, ScenarioParametersService],
processResolverByProcessingType: ProcessingTypeDataProvider[UIProcessResolver, _],
Expand Down
Loading

0 comments on commit 8f695ea

Please sign in to comment.