diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a37d1b49..16711b02 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ variables: PROD_NAME_NEXT_RUN: "parr/parr-next-run" PROD_TEMPLATE_DISTRIBOTOR: "parr/parr-template-distributor" PROD_TEMPLATE_ACTIVATOR: "parr/parr-template-activator" + PROD_TEMPLATE_GENERATOR: "parr/parr-template-generator" PROD_JOB_AUTO_CONTROL: "parr/parr-job-auto-control" stages: @@ -659,6 +660,54 @@ prod_template_activator_deploy: - ${RUNNER} +### TEMPLATE GENERATOR PROD ### +prod_template_generator_build: + stage: build + only: + - /^tg[0-9]+\.[0-9]+\.[0-9]+$/ + except: + - branches + services: + - name: docker:20.10.21-dind + command: [ + "--insecure-registry=10.99.253.167:8090", + "--registry-mirror=http://10.99.253.167:8090", + "--insecure-registry=harbor.dvgd.rzd", + "--tls=false" + ] + variables: + DOCKER_HOST: tcp://docker:2375 + DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" + script: + - APP_VERSION=$(echo $CI_COMMIT_TAG | tr -d tg) + - IMAGE_VERSION=$(echo $CI_COMMIT_TAG | sed 's/tg/v/g') + - docker build -t $REPO/$PROD_TEMPLATE_GENERATOR:$IMAGE_VERSION -t $REPO/$PROD_TEMPLATE_GENERATORR:latest -t $PROD_TEMPLATE_GENERATOR:$IMAGE_VERSION -t $PROD_TEMPLATE_GENERATOR:latest --build-arg app_version=$APP_VERSION -f PARR.TemplateGeneratorWorker/Dockerfile . + - docker login -u $HARBOR_PUSH_USER -p $HARBOR_PUSH_PASS $REPO + - docker push --all-tags $REPO/$PROD_TEMPLATE_GENERATOR + tags: + - docker + + +prod_template_generator_deploy: + stage: deploy + environment: + name: parr-template-generator + only: + - /^tg[0-9]+\.[0-9]+\.[0-9]+$/ + except: + - branches + script: + - IMAGE_VERSION=$(echo $CI_COMMIT_TAG | sed 's/tg/v/g') + - docker login -u $HARBOR_PULL_USER -p $HARBOR_PULL_PASS $REPO + - tag=$IMAGE_VERSION docker stack deploy -c docker-compose.template-generator.yml parr-template-generator --with-registry-auth + parallel: + matrix: + - RUNNER: shell-api-swarm-01 + tags: + - ${RUNNER} + + ### JOB AUTO CONTROL PROD ### prod_job_auto_control_build: stage: build diff --git a/PARR.TemplateGeneratorWorker/Dockerfile b/PARR.TemplateGeneratorWorker/Dockerfile deleted file mode 100644 index 4b3d1ba6..00000000 --- a/PARR.TemplateGeneratorWorker/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. - -# This stage is used when running from VS in fast mode (Default for Debug configuration) -FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base -WORKDIR /app - - -# This stage is used to build the service project -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build -ARG BUILD_CONFIGURATION=Release -WORKDIR /src -COPY ["NuGet.config", "."] -COPY ["PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj", "PARR.TemplateGeneratorWorker/"] -RUN dotnet restore "./PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj" -COPY . . -WORKDIR "/src/PARR.TemplateGeneratorWorker" -RUN dotnet build "./PARR.TemplateGeneratorWorker.csproj" -c $BUILD_CONFIGURATION -o /app/build - -# This stage is used to publish the service project to be copied to the final stage -FROM build AS publish -ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "./PARR.TemplateGeneratorWorker.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false - -# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "PARR.TemplateGeneratorWorker.dll"] \ No newline at end of file diff --git a/PARR.TemplateGeneratorWorker/ITemplateGenerator.cs b/PARR.TemplateGeneratorWorker/ITemplateGenerator.cs new file mode 100644 index 00000000..a75efada --- /dev/null +++ b/PARR.TemplateGeneratorWorker/ITemplateGenerator.cs @@ -0,0 +1,7 @@ +namespace PARR.TemplateGeneratorWorker +{ + public interface ITemplateGenerator + { + Task GenerateTemplateAsync(string msg); + } +} diff --git a/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs b/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs index 88077c40..a0bb92e4 100644 --- a/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs +++ b/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs @@ -6,57 +6,46 @@ namespace PARR.TemplateGeneratorWorker.Services { internal class ValidatorService : IValidatorService { - private readonly IServiceProvider serviceProvider; private readonly ILogger logger; + private readonly IJobService jobService; + private readonly IUnitService unitService; public ValidatorService( - IServiceProvider serviceProvider, - ILogger logger + ILogger logger, + IJobService jobService, + IUnitService unitService ) { - this.serviceProvider = serviceProvider; this.logger = logger; + this.jobService = jobService; + this.unitService = unitService; } public async Task IsValidAsync(Guid jobId, Guid unitId) { - using (var scope = serviceProvider.CreateScope()) + + var job = await jobService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == jobId); + + if (job == null) { - var jobService = GetServiceInScope(scope); - var job = await jobService - .Get().AsNoTracking() - .FirstOrDefaultAsync(t => t.Id == jobId); - - if (job == null) - { - logger.LogError($"Не найдена регалментная работа {nameof(jobId)}: {jobId}"); - return false; - } - - var unitService = GetServiceInScope(scope); - var unit = await unitService - .Get().AsNoTracking() - .FirstOrDefaultAsync(t => t.Id == unitId); - - if (unit == null) - { - logger.LogError($"Не найден элемент конфигурации {nameof(unitId)}: {unitId}"); - return false; - } - - return true; + logger.LogError($"Не найдена регалментная работа {nameof(jobId)}: {jobId}"); + return false; } - } + var unit = await unitService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == unitId); - private Service GetServiceInScope(IServiceScope scope) - { - var service = scope.ServiceProvider.GetService(); - if (service == null) - throw new Exception($"Не найден сервис: {nameof(Service)}"); + if (unit == null) + { + logger.LogError($"Не найден элемент конфигурации {nameof(unitId)}: {unitId}"); + return false; + } - return service; + return true; } } } diff --git a/PARR.TemplateGeneratorWorker/TemplateGenerator.cs b/PARR.TemplateGeneratorWorker/TemplateGenerator.cs new file mode 100644 index 00000000..e3256814 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/TemplateGenerator.cs @@ -0,0 +1,86 @@ + +using Microsoft.EntityFrameworkCore; +using PARR.BLL.Domain.Mq; +using PARR.BLL.Services.Interfaces; +using PARR.Common.Domain; +using PARR.Constants; +using PARR.DAL.DomainServices.Interfaces; +using PARR.DAL.Models; +using PARR.DAL.Models.Job; +using PARR.DAL.Models.Unit; +using PARR.DAL.Services.Interfaces; +using PARR.DAL.Services.Interfaces.Job; +using PARR.TemplateGeneratorWorker.Services; + +namespace PARR.TemplateGeneratorWorker +{ + internal class TemplateGenerator : ITemplateGenerator + { + private readonly ILogger logger; + private readonly ITransformService transformService; + private readonly IValidatorService validatorService; + private readonly IJobService jobService; + private readonly IShortcodesService shortcodesService; + private readonly ITemplateService templateService; + + public TemplateGenerator( + ILogger logger, + ITransformService transformService, + IValidatorService validatorService, + IJobService jobService, + IShortcodesService shortcodesService, + ITemplateService templateService + ) + { + this.logger = logger; + this.transformService = transformService; + this.validatorService = validatorService; + this.jobService = jobService; + this.shortcodesService = shortcodesService; + this.templateService = templateService; + } + public async Task GenerateTemplateAsync(string msg) + { + logger.LogInformation($"Получили запрос: {msg}"); + + var query = transformService.GetModelFromJson(msg); + + if (query == null) + return; + + if (!await validatorService.IsValidAsync(query.JobId, query.UnitId)) + { + logger.LogError($"Некорректные параметры регламентной работы или Unit {nameof(Job)}: {query.JobId}, {nameof(Unit)}: {query.UnitId}"); + return; + } + + var job = await jobService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == query.JobId); + + var templateName = await shortcodesService.ApplyShortcodesAsync(job!.TemplateNameMask!, query.UnitId, query.JobId); + + var template = new Template + { + Id = Guid.NewGuid(), + Name = templateName, + UnitId = query.UnitId, + JobId = query.JobId, + IsActiveTemplate = query.IsActiveTemplate ?? false, + IsActiveSchedule = query.IsActiveSchedule ?? false, + InitiatorComment = query.HistoryInitiator?.InitiatorComment, + InitiatorParrComponentId = query.HistoryInitiator?.InitiatorParrComponentId + }; + + if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Запрос на генерацию с тестового шаблона", InitiatorParrComponentId = ParrComponentsEnum.TemplateGenerator })) + { + logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, {nameof(template.Job)}: {template.Job}, {nameof(template.Unit)}: {template.UnitId}"); + } + else + { + logger.LogInformation($"Создан шаблон: Name: {template.Name}, {nameof(template.Job)}: {template.JobId}, {nameof(template.Unit)}: {template.UnitId}"); + } + } + + } +} diff --git a/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs b/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs index 708189e8..d6c769c5 100644 --- a/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs +++ b/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs @@ -16,8 +16,7 @@ namespace PARR.TemplateGeneratorWorker configuration.GetSection(nameof(MqSettings)).Bind(mqSettings); services.AddSingleton(mqSettings); - //services.AddTransient(); - //services.AddTransient(); + services.AddTransient(); services.AddTransient(); } diff --git a/PARR.TemplateGeneratorWorker/Worker.cs b/PARR.TemplateGeneratorWorker/Worker.cs index f3be9a1e..9372ddb4 100644 --- a/PARR.TemplateGeneratorWorker/Worker.cs +++ b/PARR.TemplateGeneratorWorker/Worker.cs @@ -1,11 +1,6 @@ -using Microsoft.EntityFrameworkCore; using PARR.BLL.Contracts.Interfaces; -using PARR.BLL.Domain.Mq; using PARR.BLL.Services.Interfaces; -using PARR.Common.Domain; -using PARR.Constants; using PARR.DAL.DomainServices.Interfaces; -using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; using PARR.TemplateGeneratorWorker.Services; @@ -18,24 +13,23 @@ namespace PARR.TemplateGeneratorWorker private readonly ILogger logger; private readonly IMqSettings mqSettings; private readonly IMqService mqService; + private readonly IServiceProvider serviceProvider; private readonly ITransformService transformService; private readonly IValidatorService validatorService; - private readonly IServiceProvider serviceProvider; + private readonly IJobService jobService; + private readonly IShortcodesService shortcodesService; + private readonly ITemplateService templateService; public Worker( ILogger logger, MqSettings mqSettings, IMqService mqService, - ITransformService transformService, - IValidatorService validatorService, IServiceProvider serviceProvider ) { this.logger = logger; this.mqSettings = mqSettings; this.mqService = mqService; - this.transformService = transformService; - this.validatorService = validatorService; this.serviceProvider = serviceProvider; } @@ -61,61 +55,14 @@ namespace PARR.TemplateGeneratorWorker private async Task GenerateTemplateAsync(string msg) { - logger.LogInformation($"{this.GetType().Name}. : {msg}"); - - var query = transformService.GetModelFromJson(msg); - if (query == null) - return; - - if (!await validatorService.IsValidAsync(query.JobId, query.UnitId)) - { - logger.LogError($" {nameof(query.JobId)}: {query.JobId}"); - return; - } - using (var scope = serviceProvider.CreateScope()) { - var jobService = GetServiceInScope(scope); - - var job = await jobService - .Get().AsNoTracking() - .FirstOrDefaultAsync(t => t.Id == query.JobId); - - var shortcodesService = GetServiceInScope(scope); - var templateName = await shortcodesService.ApplyShortcodesAsync(job!.TemplateNameMask!, query.UnitId, query.JobId); - - var template = new Template - { - Id = Guid.NewGuid(), - Name = templateName, - UnitId = query.UnitId, - JobId = query.JobId, - IsActiveTemplate = query.IsActiveTemplate ?? false, - IsActiveSchedule = query.IsActiveSchedule ?? false, - InitiatorComment = query.HistoryInitiator?.InitiatorComment, - InitiatorParrComponentId = query.HistoryInitiator?.InitiatorParrComponentId - }; - var templateService = GetServiceInScope(scope); - - if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = " ", InitiatorParrComponentId = ParrComponentsEnum.TemplateGenerator })) - { - logger.LogError($" : Name: {template.Name}, {nameof(template.Job)}: {template.JobId}, {nameof(template.Unit)}: {template.UnitId}"); - } - else - { - logger.LogInformation($" : Name: {template.Name}, {nameof(template.Job)}: {template.JobId}, {nameof(template.Unit)}: {template.UnitId}"); - } - + var templateGenerator = scope.ServiceProvider.GetService(); + if (templateGenerator == null) + throw new Exception($" : {nameof(ITemplateGenerator)}"); + await templateGenerator.GenerateTemplateAsync(msg); } } - - private Service GetServiceInScope(IServiceScope scope) - { - var service = scope.ServiceProvider.GetService(); - if (service == null) - throw new Exception($" : {nameof(Service)}"); - - return service; - } } } + diff --git a/docker-compose.dcproj b/docker-compose.dcproj index 40e5b9bd..556b079f 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -9,6 +9,7 @@ parr.api + diff --git a/docker-compose.template-generator.yml b/docker-compose.template-generator.yml new file mode 100644 index 00000000..e7d877d0 --- /dev/null +++ b/docker-compose.template-generator.yml @@ -0,0 +1,25 @@ +version: '3.4' + +#PARR TEMPLATE ACTIVATOR +services: + parr-template-activator: + image: harbor.dvgd.rzd/parr/parr-template-generator:${tag-latest} + environment: + - ASPNETCORE_ENVIRONMENT=Production + - TZ=Europe/Moscow + logging: + driver: fluentd + options: + fluentd-address: dvgd-efk-01.dvgd.oao.rzd:24224 + fluentd-retry-wait: '30s' + fluentd-max-retries: '30' + tag: parr.template-generator.serilog + deploy: + replicas: 4 + networks: + parr-network: + +networks: + parr-network: + driver: overlay + external: true \ No newline at end of file