diff --git a/backend/buildSrc/src/main/kotlin/buildlogic.spring-conventions.gradle.kts b/backend/buildSrc/src/main/kotlin/buildlogic.spring-conventions.gradle.kts index e4eb3dd7..d9358876 100644 --- a/backend/buildSrc/src/main/kotlin/buildlogic.spring-conventions.gradle.kts +++ b/backend/buildSrc/src/main/kotlin/buildlogic.spring-conventions.gradle.kts @@ -4,3 +4,9 @@ plugins { id("io.spring.dependency-management") kotlin("plugin.spring") } + +kotlin { + compilerOptions { + freeCompilerArgs.addAll("-Xjsr305=strict") + } +} diff --git a/backend/gradle/libs.versions.toml b/backend/gradle/libs.versions.toml index da310ca1..1698120e 100644 --- a/backend/gradle/libs.versions.toml +++ b/backend/gradle/libs.versions.toml @@ -31,12 +31,15 @@ io-github-numichi-reactive-logger = "6.0.3" io-projectreactor-reactor-test = "3.6.11" junit-junit = "4.13.2" org-testcontainers = "1.20.3" +org-junit-platform = "1.11.4" +org-jetbrains-kotlin = "2.1.0" [libraries] org-springframework-boot-spring-boot = { module = "org.springframework.boot:spring-boot", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-webflux = { module = "org.springframework.boot:spring-boot-starter-webflux", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-data-r2dbc = { module = "org.springframework.boot:spring-boot-starter-data-r2dbc", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "org-springframework-boot-spring-boot" } +org-springframework-boot-spring-boot-starter-web-services = { module = "org.springframework.boot:spring-boot-starter-web-services", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "org-springframework-boot-spring-boot" } org-springframework-boot-spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "org-springframework-boot-spring-boot" } @@ -84,6 +87,8 @@ io-micrometer-micrometer-registry-prometheus = { module = "io.micrometer:microme com-github-loki4j-loki-logback-appender = { module = "com.github.loki4j:loki-logback-appender", version.ref = "com-github-loki4j" } io-github-numichi-reactive-logger = { module = "io.github.numichi:reactive-logger", version.ref = "io-github-numichi-reactive-logger" } +org-jetbrains-kotlin-kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "org-jetbrains-kotlin" } + junit-junit = { module = "junit:junit", version.ref = "junit-junit" } org-testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "org-testcontainers" } org-testcontainers-r2dbc = { module = "org.testcontainers:r2dbc", version.ref = "org-testcontainers" } @@ -91,3 +96,6 @@ org-testcontainers-minio = { module = "org.testcontainers:minio", version.ref = org-testcontainers-vault = { module = "org.testcontainers:vault", version.ref = "org-testcontainers" } org-testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "org-testcontainers" } io-projectreactor-reactor-test = { module = "io.projectreactor:reactor-test", version.ref = "io-projectreactor-reactor-test" } +org-jetbrains-kotlin-kotlin-test-junit5 = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "org-jetbrains-kotlin" } +org-junit-platform-junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "org-junit-platform" } + diff --git a/backend/haproxy/config/haproxy.cfg b/backend/haproxy/config/haproxy.cfg index e122bc60..22bb4155 100644 --- a/backend/haproxy/config/haproxy.cfg +++ b/backend/haproxy/config/haproxy.cfg @@ -28,13 +28,15 @@ frontend internal bind :8455 ssl crt /usr/local/etc/haproxy/itmo-dating-backend.pem bind :8456 ssl crt /usr/local/etc/haproxy/itmo-dating-backend.pem bind :8457 ssl crt /usr/local/etc/haproxy/itmo-dating-backend.pem + bind :8458 ssl crt /usr/local/etc/haproxy/itmo-dating-backend.pem - use_backend vault if { dst_port 8445 } - use_backend consul if { dst_port 8446 } - use_backend grafana if { dst_port 8447 } - use_backend authik if { dst_port 8455 } - use_backend matchmaker if { dst_port 8456 } - use_backend people if { dst_port 8457 } + use_backend vault if { dst_port 8445 } + use_backend consul if { dst_port 8446 } + use_backend grafana if { dst_port 8447 } + use_backend authik if { dst_port 8455 } + use_backend matchmaker if { dst_port 8456 } + use_backend people if { dst_port 8457 } + use_backend matchmaker-soap if { dst_port 8458 } backend vault option httpchk GET /v1/sys/health?standbycode=200&sealedcode=200&uninitcode=200&drsecondarycode=200&performancestandbycode=200 @@ -64,3 +66,6 @@ backend people option httpchk GET /actuator/health server people-0 people-0.dating.se.ifmo.ru:8080 check init-addr last,libc,none ssl verify required ca-file /usr/local/etc/haproxy/itmo-dating-backend-ca.crt server people-1 people-1.dating.se.ifmo.ru:8080 check init-addr last,libc,none ssl verify required ca-file /usr/local/etc/haproxy/itmo-dating-backend-ca.crt + +backend matchmaker-soap + server matchmaker-soap matchmaker-soap.dating.se.ifmo.ru:8080 check init-addr last,libc,none ssl verify required ca-file /usr/local/etc/haproxy/itmo-dating-backend-ca.crt diff --git a/backend/matchmaker-soap/Dockerfile b/backend/matchmaker-soap/Dockerfile new file mode 100644 index 00000000..0bfbcc5c --- /dev/null +++ b/backend/matchmaker-soap/Dockerfile @@ -0,0 +1,9 @@ +FROM eclipse-temurin:23-jdk-alpine + +WORKDIR /matchmaker-soap + +COPY ./build/libs/matchmaker-soap-1.0.0.jar ./matchmaker-soap.jar + +EXPOSE 8080 + +CMD ["java", "-jar", "matchmaker-soap.jar"] \ No newline at end of file diff --git a/backend/matchmaker-soap/build.gradle.kts b/backend/matchmaker-soap/build.gradle.kts new file mode 100644 index 00000000..dbed8e23 --- /dev/null +++ b/backend/matchmaker-soap/build.gradle.kts @@ -0,0 +1,68 @@ +import org.openapitools.generator.gradle.plugin.tasks.GenerateTask as OpenAPIGenerateTask + +plugins { + id("buildlogic.spring-conventions") + id("com.github.bjornvester.wsdl2java") version "2.0.2" +} + +val projectGroup = group + +val matchmaker = "matchmaker" +val matchmakerTitle = matchmaker.replaceFirstChar { it.titlecase() } + +val clientGeneratedDir = layout.buildDirectory + .dir("generated/client/$matchmaker").get().toString() + +tasks.register("openApiGenerate${matchmakerTitle}Client") { + generatorName = "kotlin" + inputSpec = rootProject.layout.projectDirectory.asFile + .let { "$it/$matchmaker/src/main/resources/static/openapi/api.yml" } + outputDir = clientGeneratedDir + packageName = "$projectGroup.$matchmaker.client.generated" + modelPackage = "$projectGroup.$matchmaker.client.model.generated" + modelNameSuffix = "Message" + configOptions = mapOf( + "library" to "jvm-spring-restclient", + "useSpringBoot3" to "true", + "serializationLibrary" to "jackson", + ) +} + +val versionCxf = "4.1.0" + +wsdl2java { + wsdlDir = file("$projectDir/src/main/resources/wsdl") + markGenerated = true + cxfVersion = versionCxf +} + +sourceSets { + main { + kotlin { + srcDir("$clientGeneratedDir/src/main/kotlin") + } + } +} + +tasks.compileKotlin.configure { + dependsOn("openApiGenerate${matchmakerTitle}Client") + dependsOn(tasks.wsdl2java) +} + +dependencies { + api(project(":starter-tls")) + + implementation(libs.org.springframework.boot.spring.boot.starter.web) + implementation(libs.org.springframework.boot.spring.boot.starter.web.services) + + implementation(libs.com.fasterxml.jackson.module.jackson.module.kotlin) + implementation(libs.org.jetbrains.kotlin.kotlin.reflect) + + implementation("org.springframework.ws:spring-ws-core:4.0.11") + implementation("org.apache.cxf:cxf-spring-boot-starter-jaxws:$versionCxf") + + testImplementation(libs.org.springframework.boot.spring.boot.starter.test) + testImplementation(libs.org.jetbrains.kotlin.kotlin.reflect) + testImplementation(libs.org.jetbrains.kotlin.kotlin.test.junit5) + testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) +} diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/Application.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/Application.kt new file mode 100644 index 00000000..2497990a --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/Application.kt @@ -0,0 +1,13 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication +import org.springframework.context.annotation.ComponentScan + +@SpringBootApplication +@ComponentScan(basePackages = ["ru.ifmo.se.dating"]) +class Application + +fun main(args: Array) { + runApplication(args = args) +} diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerMessageMapping.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerMessageMapping.kt new file mode 100644 index 00000000..ac1aa87a --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerMessageMapping.kt @@ -0,0 +1,47 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import ru.ifmo.se.dating.matchmaker.* +import ru.ifmo.se.dating.matchmaker.client.model.generated.AttitudeKindMessage +import ru.ifmo.se.dating.matchmaker.client.model.generated.PersonStatusMessage +import ru.ifmo.se.dating.matchmaker.client.model.generated.PersonUpdateMessage +import ru.ifmo.se.dating.matchmaker.client.model.generated.StatisticsAttitudesGet200ResponseInnerMessage + +fun List.toSuggestionsSoap(): GetSuggestionsResponse = + GetSuggestionsResponse().apply { + personId.addAll(this@toSuggestionsSoap.map { it.toInt() }) + } + +fun AttitudeKind.toRest(): AttitudeKindMessage = + when (this) { + AttitudeKind.LIKE -> AttitudeKindMessage.like + AttitudeKind.SKIP -> AttitudeKindMessage.skip + } + +fun List.toSoap(): GetAttitudesStatisticsResponse = + GetAttitudesStatisticsResponse().apply { + statistics.addAll(this@toSoap.map { it.toSoap() }) + } + +fun StatisticsAttitudesGet200ResponseInnerMessage.toSoap() = + GetAttitudesStatisticsResponse.Statistics().apply { + personId = this@toSoap.personId.toInt() + likes = this@toSoap.likes + skips = this@toSoap.skips + } + +fun List.toMatchesSoap(): GetMatchesResponse = + GetMatchesResponse().apply { + personId.addAll(this@toMatchesSoap.map { it.toInt() }) + } + +fun PersonUpdate.toRest(): PersonUpdateMessage = + PersonUpdateMessage( + status = this.status.toRest(), + version = this.version, + ) + +fun PersonStatus.toRest(): PersonStatusMessage = + when (this) { + PersonStatus.HIDDEN -> PersonStatusMessage.hidden + PersonStatus.ACTIVE -> PersonStatusMessage.active + } diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerRestClient.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerRestClient.kt new file mode 100644 index 00000000..575d008b --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerRestClient.kt @@ -0,0 +1,26 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import org.springframework.web.client.RestClient +import ru.ifmo.se.dating.matchmaker.client.generated.apis.PeopleApi +import ru.ifmo.se.dating.matchmaker.client.generated.apis.StatisticsApi +import ru.ifmo.se.dating.matchmaker.client.generated.apis.SuggestionsApi + +class MatchmakerRestClient(private val client: RestClient) { + fun people(authorization: String? = null) = + PeopleApi(clientWithHeaders(authorization)) + + fun statistics(authorization: String? = null) = + StatisticsApi(clientWithHeaders(authorization)) + + fun suggestions(authorization: String? = null) = + SuggestionsApi(clientWithHeaders(authorization)) + + private fun clientWithHeaders(authorization: String? = null) = + client.mutate() + .apply { client -> + authorization?.let { + client.defaultHeader("Authorization", "Bearer $it") + } + } + .build() +} diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerSoapService.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerSoapService.kt new file mode 100644 index 00000000..8a5d7f1b --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/MatchmakerSoapService.kt @@ -0,0 +1,57 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import org.springframework.stereotype.Controller +import ru.ifmo.se.dating.matchmaker.* + +@Controller +class MatchmakerSoapService( + private val rest: MatchmakerRestClient, +) : ITMODatingMatchmakerPortType { + override fun getSuggestions( + authorization: String, + parameters: GetSuggestionsRequest, + ): GetSuggestionsResponse = + rest.suggestions(authorization = authorization) + .suggestionsGet(limit = parameters.limit.toLong()) + .toSuggestionsSoap() + + override fun likeSkip( + authorization: String, + parameters: LikeSkipRequest, + ): LikeSkipResponse = + rest.suggestions(authorization = authorization) + .peoplePersonIdAttitudesIncomingAttitudeKindPost( + personId = parameters.personId.toLong(), + attitudeKind = parameters.attitudeKind.toRest(), + ) + .let { LikeSkipResponse() } + + override fun getAttitudesStatistics(parameters: Any): GetAttitudesStatisticsResponse = + rest.statistics() + .statisticsAttitudesGet() + .toSoap() + + override fun getMatches( + authorization: String, + parameters: GetMatchesRequest, + ): GetMatchesResponse = + rest.suggestions(authorization) + .peoplePersonIdMatchesGet(personId = parameters.personId.toLong()) + .toMatchesSoap() + + override fun updatePerson(parameters: UpdatePersonRequest): UpdatePersonResponse = + rest.people() + .peoplePersonIdPut( + personId = parameters.personId.toLong(), + personUpdateMessage = parameters.personUpdate.toRest(), + ) + .let { UpdatePersonResponse() } + + override fun resetAttitudes( + authorization: String, + parameters: ResetAttitudesRequest, + ): ResetAttitudesResponse = + rest.suggestions(authorization) + .attitudesDelete(sourceId = parameters.sourceId.toLong()) + .let { ResetAttitudesResponse() } +} diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/RestClientConfiguration.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/RestClientConfiguration.kt new file mode 100644 index 00000000..484266c2 --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/RestClientConfiguration.kt @@ -0,0 +1,24 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.autoconfigure.web.client.RestClientSsl +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.web.client.RestClient + +@Configuration +class RestClientConfiguration { + @Bean + fun matchmakerRestClient( + @Value("\${itmo-dating.matchmaker.url}") + baseUrl: String, + + ssl: RestClientSsl, + ): MatchmakerRestClient = RestClient.builder() + .baseUrl("$baseUrl/api") + .messageConverters { it.add(MappingJackson2HttpMessageConverter()) } + .apply(ssl.fromBundle("internal")) + .build() + .let { MatchmakerRestClient(it) } +} diff --git a/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/WebServiceConfiguration.kt b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/WebServiceConfiguration.kt new file mode 100644 index 00000000..cdf5f409 --- /dev/null +++ b/backend/matchmaker-soap/src/main/kotlin/ru/ifmo/se/dating/matchmaker/soap/WebServiceConfiguration.kt @@ -0,0 +1,26 @@ +package ru.ifmo.se.dating.matchmaker.soap + +import jakarta.xml.ws.Endpoint +import org.apache.cxf.Bus +import org.apache.cxf.bus.spring.SpringBus +import org.apache.cxf.jaxws.EndpointImpl +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import ru.ifmo.se.dating.matchmaker.ITMODatingMatchmakerPortType + +@Configuration +class WebServiceConfiguration { + @Bean(Bus.DEFAULT_BUS_ID) + fun springBus(): SpringBus = + SpringBus() + + @Bean + fun matchmakerEndpoint( + bus: Bus, + service: ITMODatingMatchmakerPortType, + ): Endpoint { + val endpoint = EndpointImpl(bus, service) + endpoint.publish("/matchmaker") + return endpoint + } +} diff --git a/backend/matchmaker-soap/src/main/resources/application.yml b/backend/matchmaker-soap/src/main/resources/application.yml new file mode 100644 index 00000000..3c9ba69d --- /dev/null +++ b/backend/matchmaker-soap/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + config: + import: application-tls.yml + application: + name: matchmaker-soap + ssl: + bundle: + jks: + internal: + keystore: + type: PKCS12 + location: classpath:keystore/itmo-dating-backend.p12 + password: ${ITMO_DATING_KEY_STORE_PASSWORD} + truststore: + type: PKCS12 + location: classpath:keystore/itmo-dating-backend.p12 + password: ${ITMO_DATING_KEY_STORE_PASSWORD} +itmo-dating: + matchmaker: + url: https://matchmaker-0.dating.se.ifmo.ru:8080 diff --git a/backend/matchmaker-soap/src/main/resources/wsdl/matchmaker.wsdl b/backend/matchmaker-soap/src/main/resources/wsdl/matchmaker.wsdl new file mode 100644 index 00000000..0cab0361 --- /dev/null +++ b/backend/matchmaker-soap/src/main/resources/wsdl/matchmaker.wsdl @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/script/crypto/keys.bash b/backend/script/crypto/keys.bash index 000b685b..c5ac7a41 100755 --- a/backend/script/crypto/keys.bash +++ b/backend/script/crypto/keys.bash @@ -9,7 +9,7 @@ ALIAS="itmo-dating" ALIAS_BACKEND="$ALIAS-backend" ALIAS_EXTERNAL="$ALIAS-external" -VALIDITY=1 +VALIDITY=10 PASSWORD="$ITMO_DATING_KEYSTORE_PASSWORD" INTERNAL_INSTALL_PATH="src/main/resources/keystore" diff --git a/backend/settings.gradle.kts b/backend/settings.gradle.kts index 853f7199..a78dd233 100644 --- a/backend/settings.gradle.kts +++ b/backend/settings.gradle.kts @@ -16,3 +16,4 @@ include( ":starter-service-discovery", ":starter-tls", ) +include("matchmaker-soap") diff --git a/compose.yml b/compose.yml index 98d3cdf7..eb88ce2a 100644 --- a/compose.yml +++ b/compose.yml @@ -15,6 +15,7 @@ services: condition: service_started config: condition: service_started + restart: unless-stopped authik-1: extends: service: authik-0 @@ -35,12 +36,21 @@ services: condition: service_healthy consul: condition: service_started + restart: unless-stopped matchmaker-1: extends: service: matchmaker-0 hostname: matchmaker-1.dating.se.ifmo.ru profiles: - reliability + matchmaker-soap: + image: ghcr.io/secs-dev/itmo-dating-matchmaker-soap:latest + build: + context: ./backend/matchmaker-soap + environment: + ITMO_DATING_KEY_STORE_PASSWORD: ${ITMO_DATING_KEYSTORE_PASSWORD?:err} + tty: true + hostname: matchmaker-soap.dating.se.ifmo.ru people-0: image: ghcr.io/secs-dev/itmo-dating-people:latest build: @@ -57,6 +67,7 @@ services: condition: service_started object-storage: condition: service_healthy + restart: unless-stopped people-1: extends: service: people-0 @@ -82,6 +93,7 @@ services: timeout: 5s retries: 5 hostname: object-storage.dating.se.ifmo.ru + restart: unless-stopped database: image: postgres environment: @@ -97,6 +109,7 @@ services: timeout: 1s retries: 16 hostname: database-primary.dating.se.ifmo.ru + restart: unless-stopped postgres-exporter: image: quay.io/prometheuscommunity/postgres-exporter command: '--no-collector.stat_bgwriter' @@ -109,6 +122,7 @@ services: depends_on: database: condition: service_healthy + restart: unless-stopped gateway: image: ghcr.io/secs-dev/itmo-dating-gateway:latest build: @@ -120,6 +134,7 @@ services: hostname: gateway.dating.se.ifmo.ru ports: - "444:8080" + restart: unless-stopped config: image: ghcr.io/secs-dev/itmo-dating-config:latest build: @@ -133,6 +148,7 @@ services: condition: service_started consul: condition: service_started + restart: unless-stopped consul: image: ghcr.io/secs-dev/itmo-dating-consul:latest build: @@ -141,6 +157,7 @@ services: - consul-data:/opt/consul/data tty: true hostname: server.dc1.consul + restart: unless-stopped consul-exporter: image: prom/consul-exporter command: --consul.server=server.dc1.consul:8500 @@ -149,12 +166,14 @@ services: depends_on: consul: condition: service_started + restart: unless-stopped vault: image: ghcr.io/secs-dev/itmo-dating-vault:latest build: context: ./backend/vault tty: true hostname: vault.dating.se.ifmo.ru + restart: unless-stopped haproxy: image: ghcr.io/secs-dev/itmo-dating-haproxy:latest build: @@ -168,6 +187,8 @@ services: - "127.0.0.1:8455:8455" - "127.0.0.1:8456:8456" - "127.0.0.1:8457:8457" + - "127.0.0.1:8458:8458" + restart: unless-stopped node-exporter: image: prom/node-exporter:latest container_name: node_exporter @@ -178,6 +199,7 @@ services: - "/:/host:ro,rslave" tty: true hostname: node-exporter.dating.se.ifmo.ru + restart: unless-stopped prometheus: image: ghcr.io/secs-dev/itmo-dating-prometheus:latest build: @@ -187,6 +209,7 @@ services: - prometheus-data:/prometheus tty: true hostname: prometheus.dating.se.ifmo.ru + restart: unless-stopped loki: image: ghcr.io/secs-dev/itmo-dating-loki:latest build: @@ -196,6 +219,7 @@ services: - loki-data:/loki tty: true hostname: loki.dating.se.ifmo.ru + restart: unless-stopped grafana: image: ghcr.io/secs-dev/itmo-dating-grafana:latest build: @@ -209,6 +233,7 @@ services: - grafana-data:/var/lib/grafana tty: true hostname: grafana.dating.se.ifmo.ru + restart: unless-stopped tg-miniapp: image: ghcr.io/secs-dev/itmo-dating-tg-miniapp:latest build: