diff --git a/6/.gitea/workflows/docker-build-push.yml b/6/.gitea/workflows/docker-build-push.yml new file mode 100644 index 0000000..a819418 --- /dev/null +++ b/6/.gitea/workflows/docker-build-push.yml @@ -0,0 +1,42 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + docker: + runs-on: docker-host + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + env: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + run: + echo "$DOCKERHUB_TOKEN" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin + + - name: Build image + env: + IMAGE_NAME: ${{ vars.DOCKERHUB_REPOSITORY }} + run: + SHORT_SHA="$(git rev-parse --short HEAD)" + docker build \ + --tag "$IMAGE_NAME:latest" \ + --tag "$IMAGE_NAME:$SHORT_SHA" \ + . + + - name: Push image + env: + IMAGE_NAME: ${{ vars.DOCKERHUB_REPOSITORY }} + run: + SHORT_SHA="$(git rev-parse --short HEAD)" + docker push "$IMAGE_NAME:latest" + docker push "$IMAGE_NAME:$SHORT_SHA" diff --git a/6/.gitignore b/6/.gitignore index 33bbf36..722efda 100644 --- a/6/.gitignore +++ b/6/.gitignore @@ -5,6 +5,8 @@ # dotenv files .env +secrets/ +!secrets/.gitkeep # User-specific files *.rsuser diff --git a/6/Program.cs b/6/Program.cs index 57a759a..b6aa9c4 100644 --- a/6/Program.cs +++ b/6/Program.cs @@ -1,13 +1,13 @@ using Example.Data; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using Npgsql; var builder = WebApplication.CreateBuilder(args); -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") - ?? throw new InvalidOperationException("Connection string 'DefaultConnection' was not found."); var configuredProvider = builder.Configuration["Database:Provider"] ?? throw new InvalidOperationException("Database provider configuration 'Database:Provider' was not found."); +var connectionString = ResolveConnectionString(builder, configuredProvider); if (builder.Environment.IsDevelopment()) { @@ -116,3 +116,42 @@ static void ValidateConnectionString(string connectionString, string configuredP throw new InvalidOperationException($"Unsupported database provider '{configuredProvider}'."); } + +static string ResolveConnectionString(WebApplicationBuilder builder, string configuredProvider) +{ + var configuredConnectionString = builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string 'DefaultConnection' was not found."); + + if (builder.Environment.IsDevelopment() || + !string.Equals(configuredProvider, "Postgres", StringComparison.OrdinalIgnoreCase)) + { + return configuredConnectionString; + } + + var passwordFile = builder.Configuration["POSTGRES_PASSWORD_FILE"]; + if (string.IsNullOrWhiteSpace(passwordFile) || !File.Exists(passwordFile)) + { + return configuredConnectionString; + } + + var password = File.ReadAllText(passwordFile).Trim(); + if (string.IsNullOrWhiteSpace(password)) + { + throw new InvalidOperationException($"The PostgreSQL password file '{passwordFile}' is empty."); + } + + var connectionStringBuilder = new NpgsqlConnectionStringBuilder(configuredConnectionString) + { + Host = builder.Configuration["POSTGRES_HOST"] ?? "db", + Database = builder.Configuration["POSTGRES_DB"] ?? "db", + Username = builder.Configuration["POSTGRES_USER"] ?? "user", + Password = password + }; + + if (int.TryParse(builder.Configuration["POSTGRES_PORT"], out var port)) + { + connectionStringBuilder.Port = port; + } + + return connectionStringBuilder.ConnectionString; +} diff --git a/6/appsettings.json b/6/appsettings.json index c872741..23f4a86 100644 --- a/6/appsettings.json +++ b/6/appsettings.json @@ -3,7 +3,7 @@ "Provider": "Postgres" }, "ConnectionStrings": { - "DefaultConnection": "Host=db;Port=5432;Database=db;Username=user;Password=password" + "DefaultConnection": "Host=db;Port=5432;Database=db;Username=user" }, "Logging": { "LogLevel": { diff --git a/6/docker-compose.yml b/6/docker-compose.yml index 72fe03f..6cd7e36 100644 --- a/6/docker-compose.yml +++ b/6/docker-compose.yml @@ -9,11 +9,18 @@ services: - ass5_net environment: ASPNETCORE_ENVIRONMENT: Production + POSTGRES_HOST: db + POSTGRES_PORT: 5432 + POSTGRES_DB: db + POSTGRES_USER: user + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password restart: always depends_on: - db expose: - "8080" + secrets: + - postgres_password db: image: postgres:16 @@ -23,12 +30,14 @@ services: environment: POSTGRES_DB: db POSTGRES_USER: user - POSTGRES_PASSWORD: password + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password volumes: - postgres_data:/var/lib/postgresql/data restart: always expose: - "5432" + secrets: + - postgres_password caddy: image: caddy:2 @@ -44,11 +53,32 @@ services: - caddy_data:/data - caddy_config:/config + runner: # Service for Gitea Actions runner + image: docker.io/gitea/act_runner:latest # Docker-imaget som brukes for act_runner + restart: always # Runneren restartes automatisk hvis den stopper eller maskinen restartes + environment: # Miljøvariabler som konfigurerer runneren + CONFIG_FILE: /config.yaml # Forteller runneren hvor konfigurasjonsfila ligger inne i containeren + GITEA_INSTANCE_URL: "https://git.softsand.it/" # URL-en til Gitea-instansen runneren skal koble seg til + GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN} # Token brukt for å registrere runneren mot Gitea + GITEA_RUNNER_NAME: "docker-host-1" # Navnet runneren får i Gitea-grensesnittet + GITEA_RUNNER_LABEL: "docker:host" # Label workflowen kan bruke i runs-on for å velge denne runneren + volumes: # Mapper nødvendige filer og socketer inn i runner-containeren + - ./config.yaml:/config.yaml # Mapper lokal config-fil til /config.yaml inne i containeren + - ./data:/data # Lagrer runnerdata persistent i lokal mappe ./data + - /var/run/docker.sock:/var/run/docker.sock # Gir runneren tilgang til Docker-daemonen på hosten + networks: # Angir hvilke nettverk runneren kobles til + - ass5_net # Kobler runneren til samme nettverk som Gitea og databasen + + volumes: postgres_data: caddy_data: caddy_config: +secrets: + postgres_password: + file: ./secrets/postgres_password.txt + networks: caddy_shared: external: true