diff --git a/.ci/dbm/buildContainerImage.js b/.ci/dbm/buildContainerImage.js new file mode 100755 index 0000000000..f962b2ba8f --- /dev/null +++ b/.ci/dbm/buildContainerImage.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +import { $ } from "zx"; +import { getRequiredEnvVar } from "../lib.js"; + +const tag = getRequiredEnvVar("TAG"); + +const platforms = process.env.PLATFORMS ?? "linux/amd64,linux/arm64"; +const push = process.env.PUSH === "1" ? ["--push", "--provenance=true", "--sbom=true"] : ""; + +await $`docker buildx build --file ./DatabaseMigrator/Dockerfile --tag ghcr.io/nmshd/backbone-database-migrator:${tag} --platform ${platforms} ${push} .`; diff --git a/.ci/docker-compose.test.postgres.yml b/.ci/docker-compose.test.postgres.yml index 67ce0ffaf7..96da41adae 100644 --- a/.ci/docker-compose.test.postgres.yml +++ b/.ci/docker-compose.test.postgres.yml @@ -21,20 +21,20 @@ services: seed-database: image: postgres - volumes: - - ../setup-db:/app/setup-db environment: - PGPASSWORD=Passw0rd command: psql -h postgres -U postgres -d enmeshed -f /app/setup-db/setup-postgres.sql - depends_on: - database: - condition: service_healthy seed-client: environment: Database__Provider: Postgres Database__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432" + database-migrator: + environment: + Infrastructure__SqlDatabase__Provider: Postgres + Infrastructure__SqlDatabase__ConnectionString: "Server=postgres;Database=enmeshed;User Id=postgres;Password=Passw0rd;Port=5432" + configs: Config: file: appsettings.override.postgres.json diff --git a/.ci/docker-compose.test.sqlserver.yml b/.ci/docker-compose.test.sqlserver.yml index b2d032b350..2e71f260b9 100644 --- a/.ci/docker-compose.test.sqlserver.yml +++ b/.ci/docker-compose.test.sqlserver.yml @@ -10,6 +10,11 @@ services: - MSSQL_SA_PASSWORD=Passw0rd - ACCEPT_EULA=Y - MSSQL_PID=Express + healthcheck: + test: ["CMD", "echo"] + interval: 1s + timeout: 1s + retries: 1 ports: - 1433:1433 @@ -17,17 +22,18 @@ services: seed-database: image: mcr.microsoft.com/mssql-tools - volumes: - - ../setup-db:/app/setup-db command: bash -c " sleep 20 && /opt/mssql-tools/bin/sqlcmd -S sqlserver -U SA -P Passw0rd -i /app/setup-db/setup-sqlserver.sql " - depends_on: - - database seed-client: environment: Database__Provider: SqlServer Database__ConnectionString: "Server=sqlserver;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True" + database-migrator: + environment: + Infrastructure__SqlDatabase__Provider: SqlServer + Infrastructure__SqlDatabase__ConnectionString: "Server=sqlserver;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" + configs: Config: file: appsettings.override.sqlserver.json diff --git a/.ci/docker-compose.test.yml b/.ci/docker-compose.test.yml index ae822013af..84a994b46c 100644 --- a/.ci/docker-compose.test.yml +++ b/.ci/docker-compose.test.yml @@ -11,12 +11,10 @@ services: ports: - "5000:8080" depends_on: - database: - condition: service_started + database-migrator: + condition: service_completed_successfully rabbitmq: condition: service_started - seed-database: - condition: service_completed_successfully azure-storage-emulator: condition: service_started configs: @@ -34,12 +32,10 @@ services: ports: - "5173:8080" depends_on: - database: - condition: service_started + database-migrator: + condition: service_completed_successfully rabbitmq: condition: service_started - consumer-api: - condition: service_healthy configs: - source: Config target: app/appsettings.override.json @@ -52,14 +48,28 @@ services: environment: - ASPNETCORE_ENVIRONMENT=Development depends_on: - database: - condition: service_started + database-migrator: + condition: service_completed_successfully rabbitmq: condition: service_started configs: - source: Config target: app/appsettings.override.json + database-migrator: + container_name: database-migrator-test + build: + context: .. + dockerfile: DatabaseMigrator/Dockerfile + depends_on: + seed-database: + condition: service_completed_successfully + environment: + - ASPNETCORE_ENVIRONMENT=Development + configs: + - source: Config + target: app/appsettings.override.json + ### infrastructure ### azure-storage-emulator: @@ -79,6 +89,13 @@ services: ### seeds ### + seed-database: + volumes: + - ../setup-db:/app/setup-db + depends_on: + database: + condition: service_healthy + seed-client: container_name: seed-client-test build: diff --git a/.ci/helm/buildChart.js b/.ci/helm/buildChart.js index 2a93da2ca8..dbe390960a 100755 --- a/.ci/helm/buildChart.js +++ b/.ci/helm/buildChart.js @@ -7,4 +7,4 @@ const version = getRequiredEnvVar("VERSION"); await $`helm dependency update helm`; -await $`helm package --version ${version} --app-version ${version} helm`; +await $`helm package --version ${version} --app-version ${version} helm`; diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eef6319349..adcca3bc9e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -161,6 +161,45 @@ jobs: TAG: ${{ steps.extract-version-from-git-tag.outputs.VERSION }} PUSH: 1 + publish-database-migrator: + name: Publish Database Migrator Container Image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install script dependencies + run: npm install --prefix ./.ci + - name: Docker Login + uses: docker/login-action@v3.0.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract version from git tag + id: extract-version-from-git-tag + run: echo "VERSION=$(./.ci/extractVersionFromGitTag.js)" >> $GITHUB_OUTPUT + env: + GIT_TAG: ${{ github.ref_name }} + - name: Log in to Docker Hub for accessing the cloud builder + uses: docker/login-action@v3 + with: + username: ${{ secrets.CLOUD_BUILDER_USERNAME }} + password: ${{ secrets.CLOUD_BUILDER_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: "lab:latest" + driver: cloud + endpoint: "jssoft/js-soft" + - name: Build and Push Container Image + run: ./.ci/dbm/buildContainerImage.js + env: + TAG: ${{ steps.extract-version-from-git-tag.outputs.VERSION }} + PUSH: 1 + publish-helm-chart: name: Publish Helm Chart runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fe5a80906c..f6526c8821 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -221,6 +221,22 @@ jobs: TAG: test PLATFORMS: linux/amd64 + build-dbm-container-image: + name: Build Database Migrator Container Image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install script dependencies + run: npm install --prefix ./.ci + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build image + run: ./.ci/dbm/buildContainerImage.js + env: + TAG: test + PLATFORMS: linux/amd64 + build-aui-container-image: name: Build Admin UI Container Image runs-on: ubuntu-latest diff --git a/.run/Backbone.run.xml b/.run/Backbone.run.xml new file mode 100644 index 0000000000..9d3047566d --- /dev/null +++ b/.run/Backbone.run.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/AdminApi/src/AdminApi/Program.cs b/AdminApi/src/AdminApi/Program.cs index b7582799cc..b77bb14770 100644 --- a/AdminApi/src/AdminApi/Program.cs +++ b/AdminApi/src/AdminApi/Program.cs @@ -15,6 +15,7 @@ using Backbone.Tooling.Extensions; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Logging; using Serilog; using Serilog.Exceptions; using Serilog.Exceptions.Core; @@ -79,7 +80,8 @@ static WebApplication CreateApp(string[] args) var app = builder.Build(); Configure(app); - app.MigrateDbContext(); + if ((app.Environment.IsLocal() || app.Environment.IsDevelopment()) && app.Configuration.GetValue("RunMigrations")) + app.MigrateDbContext(); return app; } @@ -175,7 +177,7 @@ static void Configure(WebApplication app) app.UseSwagger().UseSwaggerUI(); if (app.Environment.IsDevelopment()) - Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; + IdentityModelEventSource.ShowPII = true; app.UseCors(); diff --git a/AdminApi/src/AdminApi/appsettings.override.json b/AdminApi/src/AdminApi/appsettings.override.json index 655cbc153c..fac7faae2a 100644 --- a/AdminApi/src/AdminApi/appsettings.override.json +++ b/AdminApi/src/AdminApi/appsettings.override.json @@ -1,4 +1,5 @@ { + "RunMigrations": true, "Authentication": { "ApiKey": "test" }, @@ -24,8 +25,8 @@ }, "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=adminUi;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - //"ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=adminUi;Password=Passw0rd;TrustServerCertificate=True" + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" } }, "Modules": { @@ -40,8 +41,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=devices;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - //"ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True" + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" }, "PushNotifications": { "Provider": "Dummy" @@ -58,8 +59,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=quotas;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - //"ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=quotas;Password=Passw0rd;TrustServerCertificate=True" + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" } } } diff --git a/Backbone.sln b/Backbone.sln index 79075c4d6c..d9245ade7a 100644 --- a/Backbone.sln +++ b/Backbone.sln @@ -297,6 +297,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHandlerService", "Even EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHandlerService.Tests", "EventHandlerService\test\EventHandlerService.Tests\EventHandlerService.Tests.csproj", "{D47E0FE1-23A0-4A96-AF57-E3CE71A132AD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseMigrator", "DatabaseMigrator\DatabaseMigrator.csproj", "{143EAC38-A2D0-4F74-88F1-3EF27413A8C6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -715,6 +717,10 @@ Global {D47E0FE1-23A0-4A96-AF57-E3CE71A132AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {D47E0FE1-23A0-4A96-AF57-E3CE71A132AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {D47E0FE1-23A0-4A96-AF57-E3CE71A132AD}.Release|Any CPU.Build.0 = Release|Any CPU + {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BuildingBlocks/src/BuildingBlocks.API/Extensions/HostExtensions.cs b/BuildingBlocks/src/BuildingBlocks.API/Extensions/HostExtensions.cs index 896869d690..87b0c4d78e 100644 --- a/BuildingBlocks/src/BuildingBlocks.API/Extensions/HostExtensions.cs +++ b/BuildingBlocks/src/BuildingBlocks.API/Extensions/HostExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging; using Npgsql; using Polly; -using Polly.Retry; namespace Backbone.BuildingBlocks.API.Extensions; diff --git a/ConsumerApi/Program.cs b/ConsumerApi/Program.cs index cad2de10e4..3ebc9804d7 100644 --- a/ConsumerApi/Program.cs +++ b/ConsumerApi/Program.cs @@ -98,16 +98,19 @@ static WebApplication CreateApp(string[] args) var app = builder.Build(); Configure(app); - app - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext() - .MigrateDbContext(); + if ((app.Environment.IsLocal() || app.Environment.IsDevelopment()) && app.Configuration.GetValue("RunMigrations")) + { + app + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext() + .MigrateDbContext(); + } app .SeedDbContext() diff --git a/ConsumerApi/appsettings.override.json b/ConsumerApi/appsettings.override.json index 367cdb9cc1..057fcb9f23 100644 --- a/ConsumerApi/appsettings.override.json +++ b/ConsumerApi/appsettings.override.json @@ -1,4 +1,5 @@ { + "RunMigrations": true, "Authentication": { "JwtSigningCertificate": "", // can be empty to use an auto generated development certificate; however, in production scenarios this should definitely be set! Vertical scaling will not work without a fix signing certificate, because each instance would generate its own certificate "JwtLifetimeInSeconds": 300 @@ -29,8 +30,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=challenges;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=challenges;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -38,8 +39,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=quotas;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=quotas;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -47,8 +48,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=devices;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver }, "PushNotifications": { "Provider": "Dummy" @@ -59,8 +60,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=files;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=files;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver }, "BlobStorage": { "CloudProvider": "Azure", @@ -73,8 +74,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=messages;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=messages;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -82,8 +83,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=relationships;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=relationships;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -91,8 +92,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=synchronization;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=synchronization;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -100,8 +101,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=tokens;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=ms-sql-server;Database=enmeshed;User Id=tokens;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } } diff --git a/DatabaseMigrator/Configuration.cs b/DatabaseMigrator/Configuration.cs new file mode 100644 index 0000000000..5075043b4d --- /dev/null +++ b/DatabaseMigrator/Configuration.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; + +namespace Backbone.DatabaseMigrator; + +public class Configuration +{ + [Required] + public InfrastructureConfiguration Infrastructure { get; set; } = null!; +} + +public class InfrastructureConfiguration +{ + [Required] + public SqlDatabaseConfiguration SqlDatabase { get; set; } = null!; +} + +public class SqlDatabaseConfiguration +{ + [Required] + public string Provider { get; set; } = null!; + + [Required] + public string ConnectionString { get; set; } = null!; +} diff --git a/DatabaseMigrator/DatabaseMigrator.csproj b/DatabaseMigrator/DatabaseMigrator.csproj new file mode 100644 index 0000000000..e35173675b --- /dev/null +++ b/DatabaseMigrator/DatabaseMigrator.csproj @@ -0,0 +1,56 @@ + + + + Exe + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DatabaseMigrator/Dockerfile b/DatabaseMigrator/Dockerfile new file mode 100644 index 0000000000..c5a6dcddfb --- /dev/null +++ b/DatabaseMigrator/Dockerfile @@ -0,0 +1,83 @@ +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.18 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src + +COPY ["Directory.Build.props", "."] +COPY ["Modules/Directory.Build.props", "Modules/"] +COPY ["DatabaseMigrator/DatabaseMigrator.csproj", "DatabaseMigrator/"] +COPY ["AdminApi/src/AdminApi.Infrastructure/AdminApi.Infrastructure.csproj", "AdminApi/src/AdminApi.Infrastructure/"] +COPY ["AdminApi/src/AdminApi.Infrastructure.Database.Postgres/AdminApi.Infrastructure.Database.Postgres.csproj", "AdminApi/src/AdminApi.Infrastructure.Database.Postgres/"] +COPY ["AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/AdminApi.Infrastructure.Database.SqlServer.csproj", "AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/"] +COPY ["BuildingBlocks/src/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj", "BuildingBlocks/src/BuildingBlocks.Infrastructure/"] +COPY ["BuildingBlocks/src/BuildingBlocks.Application.Abstractions/BuildingBlocks.Application.Abstractions.csproj", "BuildingBlocks/src/BuildingBlocks.Application.Abstractions/"] +COPY ["BuildingBlocks/src/DevelopmentKit.Identity/DevelopmentKit.Identity.csproj", "BuildingBlocks/src/DevelopmentKit.Identity/"] +COPY ["BuildingBlocks/src/BuildingBlocks.Domain/BuildingBlocks.Domain.csproj", "BuildingBlocks/src/BuildingBlocks.Domain/"] +COPY ["BuildingBlocks/src/Tooling/Tooling.csproj", "BuildingBlocks/src/Tooling/"] +COPY ["Modules/Tokens/src/Tokens.Infrastructure.Database.SqlServer/Tokens.Infrastructure.Database.SqlServer.csproj", "Modules/Tokens/src/Tokens.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Tokens/src/Tokens.Infrastructure/Tokens.Infrastructure.csproj", "Modules/Tokens/src/Tokens.Infrastructure/"] +COPY ["Modules/Tokens/src/Tokens.Application/Tokens.Application.csproj", "Modules/Tokens/src/Tokens.Application/"] +COPY ["BuildingBlocks/src/BuildingBlocks.Application/BuildingBlocks.Application.csproj", "BuildingBlocks/src/BuildingBlocks.Application/"] +COPY ["Common/src/Common.Infrastructure/Common.Infrastructure.csproj", "Common/src/Common.Infrastructure/"] +COPY ["Modules/Tokens/src/Tokens.Domain/Tokens.Domain.csproj", "Modules/Tokens/src/Tokens.Domain/"] +COPY ["Modules/Tokens/src/Tokens.Infrastructure.Database.Postgres/Tokens.Infrastructure.Database.Postgres.csproj", "Modules/Tokens/src/Tokens.Infrastructure.Database.Postgres/"] +COPY ["Modules/Synchronization/src/Synchronization.Infrastructure.Database.SqlServer/Synchronization.Infrastructure.Database.SqlServer.csproj", "Modules/Synchronization/src/Synchronization.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Synchronization/src/Synchronization.Infrastructure/Synchronization.Infrastructure.csproj", "Modules/Synchronization/src/Synchronization.Infrastructure/"] +COPY ["Modules/Synchronization/src/Synchronization.Application/Synchronization.Application.csproj", "Modules/Synchronization/src/Synchronization.Application/"] +COPY ["Modules/Synchronization/src/Synchronization.Domain/Synchronization.Domain.csproj", "Modules/Synchronization/src/Synchronization.Domain/"] +COPY ["Modules/Synchronization/src/Synchronization.Infrastructure.Database.Postgres/Synchronization.Infrastructure.Database.Postgres.csproj", "Modules/Synchronization/src/Synchronization.Infrastructure.Database.Postgres/"] +COPY ["Modules/Challenges/src/Challenges.Infrastructure/Challenges.Infrastructure.csproj", "Modules/Challenges/src/Challenges.Infrastructure/"] +COPY ["Modules/Challenges/src/Challenges.Application/Challenges.Application.csproj", "Modules/Challenges/src/Challenges.Application/"] +COPY ["Modules/Challenges/src/Challenges.Domain/Challenges.Domain.csproj", "Modules/Challenges/src/Challenges.Domain/"] +COPY ["Modules/Devices/src/Devices.Infrastructure/Devices.Infrastructure.csproj", "Modules/Devices/src/Devices.Infrastructure/"] +COPY ["Modules/Devices/src/Devices.Application/Devices.Application.csproj", "Modules/Devices/src/Devices.Application/"] +COPY ["BuildingBlocks/src/Crypto/Crypto.csproj", "BuildingBlocks/src/Crypto/"] +COPY ["Modules/Devices/src/Devices.Domain/Devices.Domain.csproj", "Modules/Devices/src/Devices.Domain/"] +COPY ["Modules/Files/src/Files.Infrastructure/Files.Infrastructure.csproj", "Modules/Files/src/Files.Infrastructure/"] +COPY ["Modules/Files/src/Files.Application/Files.Application.csproj", "Modules/Files/src/Files.Application/"] +COPY ["Modules/Files/src/Files.Domain/Files.Domain.csproj", "Modules/Files/src/Files.Domain/"] +COPY ["Modules/Messages/src/Messages.Infrastructure/Messages.Infrastructure.csproj", "Modules/Messages/src/Messages.Infrastructure/"] +COPY ["Modules/Messages/src/Messages.Application/Messages.Application.csproj", "Modules/Messages/src/Messages.Application/"] +COPY ["Modules/Messages/src/Messages.Domain/Messages.Domain.csproj", "Modules/Messages/src/Messages.Domain/"] +COPY ["Modules/Quotas/src/Quotas.Infrastructure/Quotas.Infrastructure.csproj", "Modules/Quotas/src/Quotas.Infrastructure/"] +COPY ["Modules/Quotas/src/Quotas.Application/Quotas.Application.csproj", "Modules/Quotas/src/Quotas.Application/"] +COPY ["Modules/Quotas/src/Quotas.Domain/Quotas.Domain.csproj", "Modules/Quotas/src/Quotas.Domain/"] +COPY ["Modules/Relationships/src/Relationships.Infrastructure/Relationships.Infrastructure.csproj", "Modules/Relationships/src/Relationships.Infrastructure/"] +COPY ["Modules/Relationships/src/Relationships.Application/Relationships.Application.csproj", "Modules/Relationships/src/Relationships.Application/"] +COPY ["Modules/Relationships/src/Relationships.Common/Relationships.Common.csproj", "Modules/Relationships/src/Relationships.Common/"] +COPY ["Modules/Relationships/src/Relationships.Domain/Relationships.Domain.csproj", "Modules/Relationships/src/Relationships.Domain/"] +COPY ["Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Relationships.Infrastructure.Database.SqlServer.csproj", "Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Relationships.Infrastructure.Database.Postgres.csproj", "Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/"] +COPY ["Modules/Quotas/src/Quotas.Infrastructure.Database.SqlServer/Quotas.Infrastructure.Database.SqlServer.csproj", "Modules/Quotas/src/Quotas.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Quotas/src/Quotas.Infrastructure.Database.Postgres/Quotas.Infrastructure.Database.Postgres.csproj", "Modules/Quotas/src/Quotas.Infrastructure.Database.Postgres/"] +COPY ["Modules/Messages/src/Messages.Infrastructure.Database.SqlServer/Messages.Infrastructure.Database.SqlServer.csproj", "Modules/Messages/src/Messages.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Messages/src/Messages.Infrastructure.Database.Postgres/Messages.Infrastructure.Database.Postgres.csproj", "Modules/Messages/src/Messages.Infrastructure.Database.Postgres/"] +COPY ["Modules/Files/src/Files.Infrastructure.Database.SqlServer/Files.Infrastructure.Database.SqlServer.csproj", "Modules/Files/src/Files.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Files/src/Files.Infrastructure.Database.Postgres/Files.Infrastructure.Database.Postgres.csproj", "Modules/Files/src/Files.Infrastructure.Database.Postgres/"] +COPY ["Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/Devices.Infrastructure.Database.SqlServer.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Devices/src/Devices.Infrastructure.Database.Postgres/Devices.Infrastructure.Database.Postgres.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.Postgres/"] +COPY ["Modules/Challenges/src/Challenges.Infrastructure.Database.SqlServer/Challenges.Infrastructure.Database.SqlServer.csproj", "Modules/Challenges/src/Challenges.Infrastructure.Database.SqlServer/"] +COPY ["Modules/Challenges/src/Challenges.Infrastructure.Database.Postgres/Challenges.Infrastructure.Database.Postgres.csproj", "Modules/Challenges/src/Challenges.Infrastructure.Database.Postgres/"] +COPY ["AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/AdminApi.Infrastructure.Database.SqlServer.csproj", "AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/"] +COPY ["AdminApi/src/AdminApi.Infrastructure.Database.Postgres/AdminApi.Infrastructure.Database.Postgres.csproj", "AdminApi/src/AdminApi.Infrastructure.Database.Postgres/"] + +RUN dotnet restore "DatabaseMigrator/DatabaseMigrator.csproj" + +COPY . . + +WORKDIR "/src/DatabaseMigrator" +RUN dotnet build "DatabaseMigrator.csproj" -c Release --output /app/build --no-restore + +FROM build AS publish + +RUN dotnet publish -c Release --output /app/publish --no-restore "DatabaseMigrator.csproj" + +FROM base AS final + +RUN apk add icu-libs +ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=0 + +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Backbone.DatabaseMigrator.dll"] diff --git a/DatabaseMigrator/Executor.cs b/DatabaseMigrator/Executor.cs new file mode 100644 index 0000000000..2bc8366ed7 --- /dev/null +++ b/DatabaseMigrator/Executor.cs @@ -0,0 +1,246 @@ +using System.Data.SqlClient; +using Backbone.AdminApi.Infrastructure.Persistence.Database; +using Backbone.Modules.Challenges.Infrastructure.Persistence.Database; +using Backbone.Modules.Devices.Infrastructure.Persistence.Database; +using Backbone.Modules.Files.Infrastructure.Persistence.Database; +using Backbone.Modules.Messages.Infrastructure.Persistence.Database; +using Backbone.Modules.Quotas.Infrastructure.Persistence.Database; +using Backbone.Modules.Relationships.Infrastructure.Persistence.Database; +using Backbone.Modules.Synchronization.Infrastructure.Persistence.Database; +using Backbone.Modules.Tokens.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql; +using Polly; +using Polly.Retry; + +namespace Backbone.DatabaseMigrator; + +public class Executor +{ + private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; + + private readonly Stack<(Type dbContextType, string? migrationBeforeChanges)> _migratedDbContexts = new(); + private readonly RetryPolicy _retryPolicy; + + public Executor(IServiceProvider serviceProvider, ILogger logger) + { + _serviceProvider = serviceProvider; + _logger = logger; + + _retryPolicy = Policy.Handle().Or() + .WaitAndRetry([ + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(10), + TimeSpan.FromSeconds(15) + ]); + } + + public async Task Execute() + { + _logger.StartApplyingMigrations(); + + try + { + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + await MigrateDbContext(); + } + catch (Exception ex) + { + _logger.ErrorWhileApplyingMigrations(ex); + await RollbackAlreadyMigratedDbContexts(); + Environment.Exit(1); + } + + _logger.SuccessfullyAppliedMigrations(); + } + + private async Task MigrateDbContext(string? targetMigration = null) where TContext : DbContext + { + await using var context = _serviceProvider.GetDbContext(); + + if (targetMigration == null) + _logger.MigratingDbContextToLatestMigration(typeof(TContext).Name); + else + _logger.MigratingDbContextToTargetMigration(typeof(TContext).Name, targetMigration); + + var pendingMigrations = await context.Database.GetPendingMigrationsAsync(); + if (!pendingMigrations.Any()) + return; + + var migrationBeforeChanges = await context.GetLastAppliedMigration(); + + try + { + await _retryPolicy.Execute(() => context.MigrateTo(targetMigration)); + } + catch (Exception ex) + { + if (targetMigration == null) + _logger.ErrorWhileApplyingMigrationToLatestMigration(ex, typeof(TContext).Name); + else + _logger.ErrorWhileApplyingMigrationToTargetMigration(ex, typeof(TContext).Name, targetMigration); + throw; + } + finally + { + _migratedDbContexts.Push((context.GetType(), migrationBeforeChanges)); + } + + if (targetMigration == null) + _logger.SuccessfullyMigratedDbContextToLatestMigration(typeof(TContext).Name); + else + _logger.SuccessfullyMigratedDbContextToTargetMigration(typeof(TContext).Name, targetMigration); + } + + private async Task RollbackAlreadyMigratedDbContexts() + { + while (_migratedDbContexts.Count != 0) + { + var (contextType, migrationBeforeChanges) = _migratedDbContexts.Peek(); + + await using var context = _serviceProvider.GetDbContext(contextType); + + // if the migrationBeforeChanges is null, this means that it was the first migration; EF Core doesn't allow unapplying the first migration. But it's no problem because + // if there is only one migration, it means that in case of a rollback of the application version, there will be nothing that needs the tables from the first migration. + if (migrationBeforeChanges == null) + continue; + + _logger.RollingBackDbContext(contextType.Name, migrationBeforeChanges); + + try + { + await context.MigrateTo(migrationBeforeChanges); + } + catch (Exception ex) + { + var remainingDbContexts = string.Join(", ", _migratedDbContexts.Select(c => c.dbContextType.Name)); + + _logger.ErrorOnRollback(ex, context.GetType().Name, migrationBeforeChanges, remainingDbContexts); + } + + _migratedDbContexts.Pop(); + } + } +} + +file static class Extensions +{ + public static async Task MigrateTo(this DbContext dbContext, string? targetMigration = null) + { + var migrator = dbContext.GetInfrastructure().GetRequiredService(); + await migrator.MigrateAsync(targetMigration); + } + + public static async Task GetLastAppliedMigration(this DbContext dbContext) + { + var stateBeforeMigration = await dbContext.Database.GetAppliedMigrationsAsync(); + var migrationBeforeChanges = stateBeforeMigration.LastOrDefault(); + return migrationBeforeChanges; + } + + public static DbContext GetDbContext(this IServiceProvider serviceProvider) where T : DbContext + { + return serviceProvider.GetDbContext(typeof(T)); + } + + public static DbContext GetDbContext(this IServiceProvider serviceProvider, Type type) + { + var scope = serviceProvider.CreateScope(); + var context = (DbContext)scope.ServiceProvider.GetRequiredService(type); + return context; + } +} + +internal static partial class ExecutorLogs +{ + [LoggerMessage( + EventId = 561100, + EventName = "DatabaseMigrator.Executor.StartApplyingMigrations", + Level = LogLevel.Information, + Message = "Start applying migrations...")] + public static partial void StartApplyingMigrations(this ILogger logger); + + [LoggerMessage( + EventId = 561101, + EventName = "DatabaseMigrator.Executor.SuccessfullyAppliedMigrations", + Level = LogLevel.Information, + Message = "All migrations were successfully applied")] + public static partial void SuccessfullyAppliedMigrations(this ILogger logger); + + [LoggerMessage( + EventId = 561102, + EventName = "DatabaseMigrator.Executor.ErrorWhileApplyingMigrations", + Level = LogLevel.Critical, + Message = "An error occurred while migrating the database. Rolling back already migrated DbContexts...")] + public static partial void ErrorWhileApplyingMigrations(this ILogger logger, Exception ex); + + [LoggerMessage( + EventId = 561103, + EventName = "DatabaseMigrator.Executor.MigratingDbContextToLatestMigration", + Level = LogLevel.Information, + Message = "Migrating database associated with context '{context}' to the latest migration...")] + public static partial void MigratingDbContextToLatestMigration(this ILogger logger, string context); + + [LoggerMessage( + EventId = 561104, + EventName = "DatabaseMigrator.Executor.MigratingDbContextToTargetMigration", + Level = LogLevel.Information, + Message = "Migrating database associated with context '{context}' to target migration '{targetMigration}'...")] + public static partial void MigratingDbContextToTargetMigration(this ILogger logger, string context, string targetMigration); + + [LoggerMessage( + EventId = 561105, + EventName = "DatabaseMigrator.Executor.SuccessfullyMigratedDbContextToLatestMigration", + Level = LogLevel.Information, + Message = "Migrating database associated with context '{context}' to the latest migration...")] + public static partial void SuccessfullyMigratedDbContextToLatestMigration(this ILogger logger, string context); + + [LoggerMessage( + EventId = 561106, + EventName = "DatabaseMigrator.Executor.SuccessfullyMigratedDbContextToTargetMigration", + Level = LogLevel.Information, + Message = "Migrating database associated with context '{context}' to target migration '{targetMigration}'...")] + public static partial void SuccessfullyMigratedDbContextToTargetMigration(this ILogger logger, string context, string targetMigration); + + [LoggerMessage( + EventId = 561108, + EventName = "DatabaseMigrator.Executor.ErrorWhileApplyingMigrationToLatestMigration", + Level = LogLevel.Critical, + Message = + "An error occurred while migrating the database associated with context '{context}' to the latest migration'")] + public static partial void ErrorWhileApplyingMigrationToLatestMigration(this ILogger logger, Exception ex, string context); + + [LoggerMessage( + EventId = 561107, + EventName = "DatabaseMigrator.Executor.ErrorWhileApplyingMigrationToTargetMigration", + Level = LogLevel.Critical, + Message = + "An error occurred while migrating the database associated with context '{context}' to target migration '{targetMigration}'")] + public static partial void ErrorWhileApplyingMigrationToTargetMigration(this ILogger logger, Exception ex, string context, string targetMigration); + + [LoggerMessage( + EventId = 561109, + EventName = "DatabaseMigrator.Executor.RollingBackDbContext", + Level = LogLevel.Information, + Message = + "Rolling back context '{context}' to migration '{migrationBeforeChanges}'....")] + public static partial void RollingBackDbContext(this ILogger logger, string context, string migrationBeforeChanges); + + [LoggerMessage( + EventId = 561110, + EventName = "DatabaseMigrator.Executor.ErrorOnRollback", + Level = LogLevel.Critical, + Message = + "There was an error while rolling back the migration of context '{context}' to migration '{migrationBeforeChanges}'. The following DbContexts couldn't be rolled back: {remainingDbContexts}")] + public static partial void ErrorOnRollback(this ILogger logger, Exception ex, string context, string migrationBeforeChanges, string remainingDbContexts); +} diff --git a/DatabaseMigrator/Program.cs b/DatabaseMigrator/Program.cs new file mode 100644 index 0000000000..56e7c5f7c5 --- /dev/null +++ b/DatabaseMigrator/Program.cs @@ -0,0 +1,137 @@ +using System.Reflection; +using Autofac.Extensions.DependencyInjection; +using Backbone.DatabaseMigrator; +using Microsoft.Extensions.Options; +using Serilog; +using Serilog.Exceptions; +using Serilog.Exceptions.Core; +using Serilog.Exceptions.EntityFrameworkCore.Destructurers; +using Serilog.Settings.Configuration; +using IServiceCollectionExtensions = Backbone.Modules.Challenges.Infrastructure.Persistence.IServiceCollectionExtensions; + +Log.Logger = new LoggerConfiguration() + .WriteTo.Console() + .CreateBootstrapLogger(); + +try +{ + var app = CreateHostBuilder(args).Build(); + + var executor = app.Services.GetRequiredService(); + + await executor.Execute(); + + return 0; +} +catch (Exception ex) +{ + Log.Fatal(ex, "Host terminated unexpectedly"); + return 1; +} +finally +{ + await Log.CloseAndFlushAsync(); +} + + +static IHostBuilder CreateHostBuilder(string[] args) +{ + return Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((hostContext, configuration) => + { + configuration.Sources.Clear(); + var env = hostContext.HostingEnvironment; + + configuration + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true) + .AddJsonFile("appsettings.override.json", optional: true, reloadOnChange: true); + + if (env.IsDevelopment()) + { + var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); + configuration.AddUserSecrets(appAssembly, optional: true); + } + + configuration.AddEnvironmentVariables(); + configuration.AddCommandLine(args); + }) + .ConfigureServices((hostContext, services) => + { + var configuration = hostContext.Configuration; + + services.ConfigureAndValidate(configuration.Bind); + var parsedConfiguration = services.BuildServiceProvider().GetRequiredService>().Value; + + services.AddSingleton(); + + # region Add db contexts + + IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Devices.Infrastructure.Persistence.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.ConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Files.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Messages.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Quotas.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Relationships.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Synchronization.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.Modules.Tokens.Infrastructure.Persistence.Database.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + Backbone.AdminApi.Infrastructure.Persistence.IServiceCollectionExtensions.AddDatabase(services, options => + { + options.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider; + options.ConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString; + }); + + #endregion + }) + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .UseSerilog((context, configuration) => configuration + .ReadFrom.Configuration(context.Configuration, new ConfigurationReaderOptions { SectionName = "Logging" }) + .Enrich.WithDemystifiedStackTraces() + .Enrich.FromLogContext() + .Enrich.WithProperty("service", "databasemigrator") + .Enrich.WithExceptionDetails(new DestructuringOptionsBuilder() + .WithDefaultDestructurers() + .WithDestructurers(new[] { new DbUpdateExceptionDestructurer() }) + ) + ); +} diff --git a/DatabaseMigrator/appsettings.json b/DatabaseMigrator/appsettings.json new file mode 100644 index 0000000000..ee2039925d --- /dev/null +++ b/DatabaseMigrator/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "MinimumLevel": { + "Default": "Information", + }, + "WriteTo": { + "Console": { + "Name": "Console", + "Args": { + "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" + } + } + } + } +} diff --git a/DatabaseMigrator/appsettings.override.json b/DatabaseMigrator/appsettings.override.json new file mode 100644 index 0000000000..f9955cd341 --- /dev/null +++ b/DatabaseMigrator/appsettings.override.json @@ -0,0 +1,28 @@ +{ + "Infrastructure": { + "SqlDatabase": { + "Provider": "Postgres", + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres, +// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + } + }, + "Logging": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Backbone": "Debug" + } + }, + "WriteTo": { + "Seq": { + "Name": "Seq", + "Args": { + "ServerUrl": "http://localhost:5341" + } + }, + "Debug": { + "Name": "Debug" + } + } + } +} diff --git a/EventHandlerService/src/EventHandlerService/EventHandlerService.csproj b/EventHandlerService/src/EventHandlerService/EventHandlerService.csproj index c511107aa1..43d6c8b872 100644 --- a/EventHandlerService/src/EventHandlerService/EventHandlerService.csproj +++ b/EventHandlerService/src/EventHandlerService/EventHandlerService.csproj @@ -1,7 +1,7 @@  - Exe + Exe Linux ..\..\.. diff --git a/EventHandlerService/src/EventHandlerService/appsettings.override.json b/EventHandlerService/src/EventHandlerService/appsettings.override.json index 40cf03c8d0..7bef826456 100644 --- a/EventHandlerService/src/EventHandlerService/appsettings.override.json +++ b/EventHandlerService/src/EventHandlerService/appsettings.override.json @@ -17,8 +17,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=challenges;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=challenges;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -26,8 +26,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=quotas;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=quotas;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -35,8 +35,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=devices;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver }, "PushNotifications": { "Provider": "Dummy" @@ -47,8 +47,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=files;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=files;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver }, "BlobStorage": { "CloudProvider": "Azure", @@ -61,8 +61,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=messages;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=messages;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -70,8 +70,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=relationships;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=relationships;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -79,8 +79,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=synchronization;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=synchronization;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } }, @@ -88,8 +88,8 @@ "Infrastructure": { "SqlDatabase": { "Provider": "Postgres", - "ConnectionString": "User ID=tokens;Password=Passw0rd;Server=localhost;Port=5432;Database=enmeshed;" // postgres - // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=tokens;Password=Passw0rd;TrustServerCertificate=True" // sqlserver + "ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres + // "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver } } } diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index b4bb341a09..7480bc5ac8 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -34,7 +34,7 @@ services: - postgres-volume:/var/lib/postgresql/data ports: - 5432:5432 - + rabbitmq: container_name: bkb-rabbitmq hostname: rabbitmq diff --git a/helm/templates/admincli/templates/deployment.yaml b/helm/templates/admincli/deployment.yaml similarity index 89% rename from helm/templates/admincli/templates/deployment.yaml rename to helm/templates/admincli/deployment.yaml index 5b872db345..b913d78906 100644 --- a/helm/templates/admincli/templates/deployment.yaml +++ b/helm/templates/admincli/deployment.yaml @@ -1,15 +1,15 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "global.name" . }} + name: {{ .Values.admincli.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.admincli.name }} spec: replicas: 1 selector: matchLabels: - app: {{ include "global.name" . }} + app: {{ .Values.admincli.name }} template: metadata: {{- with .Values.admincli.podAnnotations }} @@ -17,7 +17,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - app: {{ include "global.name" . }} + app: {{ .Values.admincli.name }} spec: {{- with .Values.admincli.podSecurityContext }} securityContext: @@ -28,7 +28,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} containers: - - name: {{ include "global.name" . }} + - name: {{ .Values.admincli.name }} {{- with .Values.admincli.securityContext }} securityContext: {{- toYaml .Values.admincli.securityContext | nindent 8 }} diff --git a/helm/templates/adminui/templates/deployment.yaml b/helm/templates/adminui/deployment.yaml similarity index 94% rename from helm/templates/adminui/templates/deployment.yaml rename to helm/templates/adminui/deployment.yaml index 43aba0b988..40a64bb5f9 100644 --- a/helm/templates/adminui/templates/deployment.yaml +++ b/helm/templates/adminui/deployment.yaml @@ -1,10 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "global.name" . }} + name: {{ .Values.adminui.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.adminui.name }} spec: replicas: {{ .Values.adminui.replicas }} strategy: @@ -14,7 +14,7 @@ spec: maxUnavailable: {{ .Values.adminui.maxUnavailable }} selector: matchLabels: - app: {{ include "global.name" . }} + app: {{ .Values.adminui.name }} template: metadata: annotations: @@ -24,7 +24,7 @@ spec: {{- end }} labels: {{- include "global.labels" . | nindent 8 }} - app: {{ include "global.name" . }} + app: {{ .Values.adminui.name }} spec: {{- with .Values.global.serviceAccount.name}} serviceAccountName: {{ . }} @@ -46,7 +46,7 @@ spec: configMap: name: configuration containers: - - name: {{ include "global.name" . }} + - name: {{ .Values.adminui.name }} {{- with .Values.adminui.securityContext }} securityContext: {{- toYaml .Values.adminui.securityContext | nindent 8 }} diff --git a/helm/templates/adminui/templates/hpa.yaml b/helm/templates/adminui/hpa.yaml similarity index 91% rename from helm/templates/adminui/templates/hpa.yaml rename to helm/templates/adminui/hpa.yaml index a58f4203c3..badb60579e 100644 --- a/helm/templates/adminui/templates/hpa.yaml +++ b/helm/templates/adminui/hpa.yaml @@ -2,14 +2,14 @@ apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: - name: {{ include "global.name" . }} + name: {{ .Values.adminui.name }} labels: {{- include "global.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment - name: {{ include "global.name" . }} + name: {{ .Values.adminui.name }} minReplicas: {{ .Values.adminui.autoscaling.minReplicas }} maxReplicas: {{ .Values.adminui.autoscaling.maxReplicas }} metrics: diff --git a/helm/templates/adminui/templates/service.yaml b/helm/templates/adminui/service.yaml similarity index 59% rename from helm/templates/adminui/templates/service.yaml rename to helm/templates/adminui/service.yaml index 4ef1b52b64..2bc84f5ef7 100644 --- a/helm/templates/adminui/templates/service.yaml +++ b/helm/templates/adminui/service.yaml @@ -1,13 +1,13 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "global.name" . }} + name: {{ .Values.adminui.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.adminui.name }} {{- if eq .Values.global.provider "GoogleCloud" }} annotations: - cloud.google.com/backend-config: '{"default": "{{ include "global.name" . }}"}' + cloud.google.com/backend-config: '{"default": "{{ .Values.adminui.name }}"}' {{- end }} spec: type: {{ .Values.adminui.service.type }} @@ -15,4 +15,4 @@ spec: - port: 8080 targetPort: 8080 selector: - app: {{ include "global.name" . }} + app: {{ .Values.adminui.name }} diff --git a/helm/templates/consumerapi/templates/backendconfig.yaml b/helm/templates/consumerapi/backendconfig.yaml similarity index 94% rename from helm/templates/consumerapi/templates/backendconfig.yaml rename to helm/templates/consumerapi/backendconfig.yaml index 05c998b615..fb416b9389 100644 --- a/helm/templates/consumerapi/templates/backendconfig.yaml +++ b/helm/templates/consumerapi/backendconfig.yaml @@ -4,7 +4,7 @@ kind: BackendConfig metadata: labels: {{- include "global.labels" . | nindent 4 }} - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} spec: healthCheck: checkIntervalSec: {{ .Values.consumerapi.backendConfig.healthCheck.checkIntervalSec }} diff --git a/helm/templates/consumerapi/templates/deployment.yaml b/helm/templates/consumerapi/deployment.yaml similarity index 94% rename from helm/templates/consumerapi/templates/deployment.yaml rename to helm/templates/consumerapi/deployment.yaml index eeb699c772..bdd1d2fd9f 100644 --- a/helm/templates/consumerapi/templates/deployment.yaml +++ b/helm/templates/consumerapi/deployment.yaml @@ -1,10 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} spec: replicas: {{ .Values.consumerapi.replicas }} strategy: @@ -14,7 +14,7 @@ spec: maxUnavailable: {{ .Values.consumerapi.maxUnavailable }} selector: matchLabels: - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} template: metadata: annotations: @@ -24,7 +24,7 @@ spec: {{- end }} labels: {{- include "global.labels" . | nindent 8 }} - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} spec: {{- with .Values.global.serviceAccount.name}} serviceAccountName: {{ . }} @@ -46,7 +46,7 @@ spec: configMap: name: configuration containers: - - name: {{ include "global.name" . }} + - name: {{ .Values.consumerapi.name }} {{- with .Values.consumerapi.securityContext }} securityContext: {{- toYaml .Values.consumerapi.securityContext | nindent 8 }} diff --git a/helm/templates/consumerapi/templates/hpa.yaml b/helm/templates/consumerapi/hpa.yaml similarity index 91% rename from helm/templates/consumerapi/templates/hpa.yaml rename to helm/templates/consumerapi/hpa.yaml index 816ad94b62..18c00417d9 100644 --- a/helm/templates/consumerapi/templates/hpa.yaml +++ b/helm/templates/consumerapi/hpa.yaml @@ -2,14 +2,14 @@ apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} labels: {{- include "global.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} minReplicas: {{ .Values.consumerapi.autoscaling.minReplicas }} maxReplicas: {{ .Values.consumerapi.autoscaling.maxReplicas }} metrics: diff --git a/helm/templates/consumerapi/templates/httproute.yaml b/helm/templates/consumerapi/httproute.yaml similarity index 88% rename from helm/templates/consumerapi/templates/httproute.yaml rename to helm/templates/consumerapi/httproute.yaml index c1c7a7c46d..d59b0da7c2 100644 --- a/helm/templates/consumerapi/templates/httproute.yaml +++ b/helm/templates/consumerapi/httproute.yaml @@ -2,7 +2,7 @@ apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} labels: {{- include "global.labels" . | nindent 4 }} spec: @@ -20,6 +20,6 @@ spec: type: PathPrefix value: / backendRefs: - - name: {{ include "global.name" . }} + - name: {{ .Values.consumerapi.name }} port: 8080 {{- end }} diff --git a/helm/templates/consumerapi/templates/ingress.yaml b/helm/templates/consumerapi/ingress.yaml similarity index 84% rename from helm/templates/consumerapi/templates/ingress.yaml rename to helm/templates/consumerapi/ingress.yaml index ed39cf7cca..6df847853e 100644 --- a/helm/templates/consumerapi/templates/ingress.yaml +++ b/helm/templates/consumerapi/ingress.yaml @@ -2,10 +2,10 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} annotations: kubernetes.io/ingress.class: azure/application-gateway appgw.ingress.kubernetes.io/appgw-ssl-certificate: {{ .Values.consumerapi.ingress.certName }} @@ -20,7 +20,7 @@ spec: pathType: Prefix backend: service: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} port: number: 8080 {{- end }} diff --git a/helm/templates/consumerapi/templates/service.yaml b/helm/templates/consumerapi/service.yaml similarity index 76% rename from helm/templates/consumerapi/templates/service.yaml rename to helm/templates/consumerapi/service.yaml index b1de961c48..dcf5524d85 100644 --- a/helm/templates/consumerapi/templates/service.yaml +++ b/helm/templates/consumerapi/service.yaml @@ -1,13 +1,13 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "global.name" . }} + name: {{ .Values.consumerapi.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} {{- if eq .Values.global.provider "GoogleCloud" }} annotations: - cloud.google.com/backend-config: '{"default": "{{ include "global.name" . }}"}' + cloud.google.com/backend-config: '{"default": "{{ .Values.consumerapi.name }}"}' {{- end }} {{- if eq .Values.consumerapi.service.type "LoadBalancer" }} annotations: @@ -22,4 +22,4 @@ spec: - port: 8080 targetPort: 8080 selector: - app: {{ include "global.name" . }} + app: {{ .Values.consumerapi.name }} diff --git a/helm/templates/databasemigrator/configmap.yaml b/helm/templates/databasemigrator/configmap.yaml new file mode 100644 index 0000000000..1ab3cb282b --- /dev/null +++ b/helm/templates/databasemigrator/configmap.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: configuration-for-databasemigrator + labels: {{- include "global.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "0" + "helm.sh/hook-delete-policy": before-hook-creation +data: + appsettings.override.json: |- + {{- mustToPrettyJson .Values.global.configuration | toString | nindent 4 }} diff --git a/helm/templates/databasemigrator/job.yaml b/helm/templates/databasemigrator/job.yaml new file mode 100644 index 0000000000..0ef615e075 --- /dev/null +++ b/helm/templates/databasemigrator/job.yaml @@ -0,0 +1,65 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Values.databasemigrator.name }} + labels: + {{- include "global.labels" . | nindent 4 }} + app: {{ .Values.databasemigrator.name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + template: + metadata: + {{- with .Values.databasemigrator.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app: {{ .Values.databasemigrator.name }} + spec: + restartPolicy: Never + {{- with .Values.databasemigrator.podSecurityContext }} + securityContext: + {{- toYaml .Values.databasemigrator.podSecurityContext | nindent 8 }} + {{- end }} + {{- with .Values.databasemigrator.image.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: settings-override + configMap: + name: configuration-for-databasemigrator + containers: + - name: {{ .Values.databasemigrator.name }} + {{- with .Values.databasemigrator.securityContext }} + securityContext: + {{- toYaml .Values.databasemigrator.securityContext | nindent 8 }} + {{- end }} + resources: + {{- toYaml .Values.databasemigrator.resources | nindent 12 }} + image: "{{ .Values.databasemigrator.image.repository }}:{{- default .Chart.AppVersion .Values.databasemigrator.image.tagOverride }}" + imagePullPolicy: {{ .Values.databasemigrator.image.pullPolicy }} + volumeMounts: + - name: settings-override + mountPath: /app/appsettings.override.json + subPath: appsettings.override.json + readOnly: true + env: + {{- with .Values.databasemigrator.env }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.databasemigrator.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.databasemigrator.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.databasemigrator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/templates/eventhandler/templates/deployment.yaml b/helm/templates/eventhandler/deployment.yaml similarity index 87% rename from helm/templates/eventhandler/templates/deployment.yaml rename to helm/templates/eventhandler/deployment.yaml index 536c66ff82..2ede81542d 100644 --- a/helm/templates/eventhandler/templates/deployment.yaml +++ b/helm/templates/eventhandler/deployment.yaml @@ -1,15 +1,20 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "global.name" . }} + name: {{ .Values.eventhandler.name }} labels: {{- include "global.labels" . | nindent 4 }} - app: {{ include "global.name" . }} + app: {{ .Values.eventhandler.name }} spec: replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: {{ .Values.maxSurge }} + maxUnavailable: {{ .Values.maxUnavailable }} selector: matchLabels: - app: {{ include "global.name" . }} + app: {{ .Values.eventhandler.name }} template: metadata: {{- with .Values.eventhandler.podAnnotations }} @@ -17,7 +22,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - app: {{ include "global.name" . }} + app: {{ .Values.eventhandler.name }} spec: {{- with .Values.eventhandler.podSecurityContext }} securityContext: @@ -32,7 +37,7 @@ spec: configMap: name: configuration containers: - - name: {{ include "global.name" . }} + - name: {{ .Values.eventhandler.name }} {{- with .Values.eventhandler.securityContext }} securityContext: {{- toYaml .Values.eventhandler.securityContext | nindent 8 }} diff --git a/helm/values.yaml b/helm/values.yaml index b60b707fce..f46b6d3b24 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,5 +1,5 @@ consumerapi: - nameOverride: "" + name: "consumerapi" replicas: 1 maxSurge: 2 maxUnavailable: 0 @@ -99,7 +99,7 @@ consumerapi: unhealthyThreshold: 2 adminui: - nameOverride: "" + name: "adminui" replicas: 1 maxSurge: 2 maxUnavailable: 0 @@ -189,7 +189,7 @@ adminui: unhealthyThreshold: 2 eventhandler: - nameOverride: "" + name: "eventhandler" replicas: 1 maxSurge: 2 maxUnavailable: 0 @@ -236,8 +236,46 @@ eventhandler: targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: "" +databasemigrator: + name: "databasemigrator" + + image: + repository: "ghcr.io/nmshd/backbone-database-migrator" + tagOverride: "" + pullPolicy: "IfNotPresent" + imagePullSecrets: [] + + # resources - the resources for the Event Handler container (see https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources) + resources: + requests: + cpu: "50m" + memory: "64Mi" + limits: + cpu: "200m" + memory: "512Mi" + + # securityContext - securityContext for the Consumer API container (see https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1) + securityContext: {} + + # podSecurityContext - securityContext for the pods deployed by the Deployment (see https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) + podSecurityContext: {} + + podAnnotations: {} + + # env - environment variables for the Event Handler container (see https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) + env: [] + + # the nodeSelector for the pods deployed by the Deployment (see https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) + nodeSelector: {} + + # the tolerations for the pods deployed by the Deployment (see https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) + tolerations: [] + + # the affinity for the pods deployed by the Deployment (see https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#NodeAffinity) + affinity: {} + admincli: - nameOverride: "" + name: "admincli" configuration: Database: diff --git a/setup-db/setup-postgres.sql b/setup-db/setup-postgres.sql index 3a7f87ff03..47dae177a0 100644 --- a/setup-db/setup-postgres.sql +++ b/setup-db/setup-postgres.sql @@ -130,73 +130,81 @@ $$; /*+++++++++++++++++++++++++++++++++++++++++++++++++ Authorizations +++++++++++++++++++++++++++++++++++++++++++++++++*/ -/*GRANT CREATE ON SCHEMA Challenges, Devices, Messages, Synchronization, Tokens, Relationships, Files TO challenges, devices, messages, synchronization, tokens, relationships, files, Quotas; -GRANT CREATE ON SCHEMA Relationships TO relationships;*/ - -REVOKE USAGE, CREATE ON SCHEMA "Challenges" FROM synchronization, devices, messages, tokens, relationships, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Synchronization" FROM challenges, devices, messages, tokens, relationships, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Messages" FROM challenges, synchronization, devices, tokens, relationships, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Devices" FROM challenges, synchronization, messages, tokens, relationships, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Tokens" FROM challenges, synchronization, devices, messages, relationships, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Relationships" FROM challenges, synchronization, devices, messages, tokens, files, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Files" FROM challenges, synchronization, devices, messages, tokens, relationships, quotas; -REVOKE USAGE, CREATE ON SCHEMA "Quotas" FROM challenges, synchronization, devices, messages, tokens, relationships, files; +GRANT USAGE ON SCHEMA "Challenges" TO challenges; +GRANT USAGE ON SCHEMA "Devices" TO devices; +GRANT USAGE ON SCHEMA "Files" TO files; +GRANT USAGE ON SCHEMA "Messages" TO messages; +GRANT USAGE ON SCHEMA "Quotas" TO quotas; +GRANT USAGE ON SCHEMA "Relationships" TO relationships; +GRANT USAGE ON SCHEMA "Synchronization" TO synchronization; +GRANT USAGE ON SCHEMA "Tokens" TO tokens; +GRANT USAGE ON SCHEMA "AdminUi" TO "adminUi"; + +ALTER DEFAULT PRIVILEGES IN SCHEMA "Challenges" GRANT ALL ON TABLES TO challenges; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Devices" GRANT ALL ON TABLES TO devices; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Files" GRANT ALL ON TABLES TO files; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Messages" GRANT ALL ON TABLES TO messages; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Quotas" GRANT ALL ON TABLES TO quotas; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Relationships" GRANT ALL ON TABLES TO relationships; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Synchronization" GRANT ALL ON TABLES TO synchronization; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Tokens" GRANT ALL ON TABLES TO tokens; +ALTER DEFAULT PRIVILEGES IN SCHEMA "AdminUi" GRANT ALL ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Relationships" TO messages; GRANT SELECT, REFERENCES, TRIGGER, TRUNCATE ON ALL TABLES IN SCHEMA "Relationships" TO messages; -ALTER DEFAULT PRIVILEGES FOR ROLE relationships IN SCHEMA "Relationships" GRANT SELECT, REFERENCES, TRIGGER, TRUNCATE ON TABLES TO messages; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Relationships" GRANT SELECT, REFERENCES, TRIGGER, TRUNCATE ON TABLES TO messages; GRANT USAGE ON SCHEMA "Challenges" TO devices; GRANT SELECT ON ALL TABLES IN SCHEMA "Challenges" TO devices; -ALTER DEFAULT PRIVILEGES FOR ROLE challenges IN SCHEMA "Challenges" GRANT SELECT ON TABLES TO devices; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Challenges" GRANT SELECT ON TABLES TO devices; GRANT USAGE ON SCHEMA "Messages" TO quotas; GRANT SELECT ON ALL TABLES IN SCHEMA "Messages" TO quotas; -ALTER DEFAULT PRIVILEGES FOR ROLE messages IN SCHEMA "Messages" GRANT SELECT ON TABLES TO quotas; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Messages" GRANT SELECT ON TABLES TO quotas; GRANT USAGE ON SCHEMA "Files" TO quotas; GRANT SELECT ON ALL TABLES IN SCHEMA "Files" TO quotas; -ALTER DEFAULT PRIVILEGES FOR ROLE files IN SCHEMA "Files" GRANT SELECT ON TABLES TO quotas; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Files" GRANT SELECT ON TABLES TO quotas; GRANT USAGE ON SCHEMA "Relationships" TO quotas; GRANT SELECT ON ALL TABLES IN SCHEMA "Relationships" TO quotas; -ALTER DEFAULT PRIVILEGES FOR ROLE relationships IN SCHEMA "Relationships" GRANT SELECT ON TABLES TO quotas; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Relationships" GRANT SELECT ON TABLES TO quotas; GRANT USAGE ON SCHEMA "Challenges" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Challenges" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE challenges IN SCHEMA "Challenges" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Challenges" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Synchronization" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Synchronization" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE synchronization IN SCHEMA "Synchronization" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Synchronization" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Messages" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Messages" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE messages IN SCHEMA "Messages" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Messages" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Devices" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Devices" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE devices IN SCHEMA "Devices" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Devices" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Tokens" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Tokens" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE tokens IN SCHEMA "Tokens" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Tokens" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Relationships" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Relationships" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE relationships IN SCHEMA "Relationships" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Relationships" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Files" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Files" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE files IN SCHEMA "Files" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Files" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Quotas" TO "adminUi"; GRANT SELECT ON ALL TABLES IN SCHEMA "Quotas" TO "adminUi"; -ALTER DEFAULT PRIVILEGES FOR ROLE quotas IN SCHEMA "Quotas" GRANT SELECT ON TABLES TO "adminUi"; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Quotas" GRANT SELECT ON TABLES TO "adminUi"; GRANT USAGE ON SCHEMA "Tokens" TO quotas; GRANT SELECT ON ALL TABLES IN SCHEMA "Tokens" TO quotas; -ALTER DEFAULT PRIVILEGES FOR ROLE tokens IN SCHEMA "Tokens" GRANT SELECT ON TABLES TO quotas; +ALTER DEFAULT PRIVILEGES IN SCHEMA "Tokens" GRANT SELECT ON TABLES TO quotas; CREATE TABLE IF NOT EXISTS "Challenges"."__EFMigrationsHistory" @@ -282,13 +290,3 @@ GRANT relationships TO "nmshdAdmin"; GRANT files TO "nmshdAdmin"; GRANT quotas TO "nmshdAdmin"; GRANT "adminUi" TO "nmshdAdmin"; - -ALTER SCHEMA "Challenges" OWNER TO challenges; -ALTER SCHEMA "Devices" OWNER TO devices; -ALTER SCHEMA "Messages" OWNER TO messages; -ALTER SCHEMA "Synchronization" OWNER TO synchronization; -ALTER SCHEMA "Tokens" OWNER TO tokens; -ALTER SCHEMA "Relationships" OWNER TO relationships; -ALTER SCHEMA "Files" OWNER TO files; -ALTER SCHEMA "Quotas" OWNER TO quotas; -ALTER SCHEMA "AdminUi" OWNER TO "adminUi"; diff --git a/setup-db/setup-sqlserver.sql b/setup-db/setup-sqlserver.sql index 3e75712272..f9ad347520 100644 --- a/setup-db/setup-sqlserver.sql +++ b/setup-db/setup-sqlserver.sql @@ -226,35 +226,18 @@ END GO -/*+++++++++++++++++++++++++++++++++++++++++++++++++ Schema Owners ++++++++++++++++++++++++++++++++++++++++++++++++++*/ -PRINT 'Start changing schema owners' ; -ALTER AUTHORIZATION ON SCHEMA::Challenges TO challenges -ALTER AUTHORIZATION ON SCHEMA::Devices TO devices -ALTER AUTHORIZATION ON SCHEMA::Messages TO messages -ALTER AUTHORIZATION ON SCHEMA::Synchronization TO synchronization -ALTER AUTHORIZATION ON SCHEMA::Tokens TO tokens -ALTER AUTHORIZATION ON SCHEMA::Relationships TO relationships -ALTER AUTHORIZATION ON SCHEMA::Files TO files -ALTER AUTHORIZATION ON SCHEMA::Quotas TO quotas -ALTER AUTHORIZATION ON SCHEMA::AdminUi TO adminUi -PRINT 'Finished changing schema owners' ; -GO - /*+++++++++++++++++++++++++++++++++++++++++++++++++ Authorizations +++++++++++++++++++++++++++++++++++++++++++++++++*/ PRINT 'Start changing authorizations' ; -GRANT CREATE TABLE TO challenges, devices, messages, synchronization, tokens, relationships, files, quotas, adminUi -GRANT CREATE FUNCTION TO relationships -GO - -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Challenges TO synchronization, devices, messages, tokens, relationships, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Synchronization TO challenges, devices, messages, tokens, relationships, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Messages TO challenges, synchronization, devices, tokens, relationships, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Devices TO challenges, synchronization, messages, tokens, relationships, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Tokens TO challenges, synchronization, devices, messages, relationships, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Relationships TO challenges, synchronization, devices, messages, tokens, files, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Files TO challenges, synchronization, devices, messages, tokens, relationships, quotas -DENY SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Quotas TO challenges, synchronization, devices, messages, tokens, relationships, files +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Challenges TO challenges; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Devices TO devices; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Files TO files; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Messages TO messages; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Quotas TO quotas; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Relationships TO relationships; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Synchronization TO synchronization; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::Tokens TO tokens; +GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, REFERENCES, VIEW DEFINITION ON SCHEMA::AdminUi TO adminUi; GRANT SELECT, REFERENCES ON SCHEMA::Relationships TO messages GRANT SELECT, REFERENCES ON SCHEMA::Challenges TO devices