[backend/startup] Validate configuration on startup (ISH-23)
This commit is contained in:
parent
64e882c0e7
commit
104a2c485d
3 changed files with 64 additions and 30 deletions
|
@ -1,3 +1,4 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
|
||||
|
@ -38,12 +39,12 @@ public sealed class Config
|
|||
|
||||
public string UserAgent => $"Iceshrimp.NET/{Version} (https://{WebDomain})";
|
||||
|
||||
public int ListenPort { get; init; } = 3000;
|
||||
public string ListenHost { get; init; } = "localhost";
|
||||
public string? ListenSocket { get; init; }
|
||||
public string WebDomain { get; init; } = null!;
|
||||
public string AccountDomain { get; init; } = null!;
|
||||
public int CharacterLimit { get; init; } = 8192;
|
||||
[Range(1, 65535)] public int ListenPort { get; init; } = 3000;
|
||||
[Required] public string ListenHost { get; init; } = "localhost";
|
||||
public string? ListenSocket { get; init; }
|
||||
[Required] public string WebDomain { get; init; } = null!;
|
||||
[Required] public string AccountDomain { get; init; } = null!;
|
||||
[Range(1, 100000)] public int CharacterLimit { get; init; } = 8192;
|
||||
}
|
||||
|
||||
public sealed class SecuritySection
|
||||
|
@ -60,22 +61,22 @@ public sealed class Config
|
|||
|
||||
public sealed class DatabaseSection
|
||||
{
|
||||
public string Host { get; init; } = "localhost";
|
||||
public int Port { get; init; } = 5432;
|
||||
public string Database { get; init; } = null!;
|
||||
public string Username { get; init; } = null!;
|
||||
public string? Password { get; init; }
|
||||
[Required] public string Host { get; init; } = "localhost";
|
||||
[Range(1, 65535)] public int Port { get; init; } = 5432;
|
||||
[Required] public string Database { get; init; } = null!;
|
||||
[Required] public string Username { get; init; } = null!;
|
||||
public string? Password { get; init; }
|
||||
}
|
||||
|
||||
public sealed class RedisSection
|
||||
{
|
||||
public string Host { get; init; } = "localhost";
|
||||
public int Port { get; init; } = 6379;
|
||||
public string? UnixDomainSocket { get; init; }
|
||||
public string? Prefix { get; init; }
|
||||
public string? Username { get; init; }
|
||||
public string? Password { get; init; }
|
||||
public int? Database { get; init; }
|
||||
[Required] public string Host { get; init; } = "localhost";
|
||||
[Range(1, 65535)] public int Port { get; init; } = 6379;
|
||||
public string? UnixDomainSocket { get; init; }
|
||||
public string? Prefix { get; init; }
|
||||
public string? Username { get; init; }
|
||||
public string? Password { get; init; }
|
||||
public int? Database { get; init; }
|
||||
|
||||
//TODO: TLS settings
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ using Microsoft.AspNetCore.DataProtection;
|
|||
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
|
||||
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using StackExchange.Redis;
|
||||
using NoteRenderer = Iceshrimp.Backend.Controllers.Renderers.NoteRenderer;
|
||||
|
@ -85,15 +86,36 @@ public static class ServiceExtensions
|
|||
|
||||
public static void ConfigureServices(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//TODO: fail if config doesn't parse correctly / required things are missing
|
||||
services.Configure<Config>(configuration);
|
||||
services.Configure<Config.InstanceSection>(configuration.GetSection("Instance"));
|
||||
services.Configure<Config.SecuritySection>(configuration.GetSection("Security"));
|
||||
services.Configure<Config.DatabaseSection>(configuration.GetSection("Database"));
|
||||
services.Configure<Config.RedisSection>(configuration.GetSection("Redis"));
|
||||
services.Configure<Config.StorageSection>(configuration.GetSection("Storage"));
|
||||
services.Configure<Config.LocalStorageSection>(configuration.GetSection("Storage:Local"));
|
||||
services.Configure<Config.ObjectStorageSection>(configuration.GetSection("Storage:ObjectStorage"));
|
||||
services.ConfigureWithValidation<Config>(configuration)
|
||||
.ConfigureWithValidation<Config.InstanceSection>(configuration, "Instance")
|
||||
.ConfigureWithValidation<Config.SecuritySection>(configuration, "Security")
|
||||
.ConfigureWithValidation<Config.DatabaseSection>(configuration, "Database")
|
||||
.ConfigureWithValidation<Config.RedisSection>(configuration, "Redis")
|
||||
.ConfigureWithValidation<Config.StorageSection>(configuration, "Storage")
|
||||
.ConfigureWithValidation<Config.LocalStorageSection>(configuration, "Storage:Local")
|
||||
.ConfigureWithValidation<Config.ObjectStorageSection>(configuration, "Storage:ObjectStorage");
|
||||
}
|
||||
|
||||
private static IServiceCollection ConfigureWithValidation<T>(
|
||||
this IServiceCollection services, IConfiguration config
|
||||
) where T : class
|
||||
{
|
||||
services.AddOptionsWithValidateOnStart<T>()
|
||||
.Bind(config)
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollection ConfigureWithValidation<T>(
|
||||
this IServiceCollection services, IConfiguration config, string name
|
||||
) where T : class
|
||||
{
|
||||
services.AddOptionsWithValidateOnStart<T>()
|
||||
.Bind(config.GetSection(name))
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static void AddDatabaseContext(this IServiceCollection services, IConfiguration configuration)
|
||||
|
|
|
@ -5,6 +5,7 @@ using Iceshrimp.Backend.Core.Middleware;
|
|||
using Iceshrimp.Backend.Core.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Iceshrimp.Backend.Core.Extensions;
|
||||
|
||||
|
@ -46,11 +47,18 @@ public static class WebApplicationExtensions
|
|||
var instanceConfig = app.Configuration.GetSection("Instance").Get<Config.InstanceSection>() ??
|
||||
throw new Exception("Failed to read Instance config section");
|
||||
|
||||
var storageConfig = app.Configuration.GetSection("Storage").Get<Config.StorageSection>() ??
|
||||
throw new Exception("Failed to read Storage config section");
|
||||
|
||||
app.Logger.LogInformation("Iceshrimp.NET v{version} ({domain})", instanceConfig.Version,
|
||||
instanceConfig.AccountDomain);
|
||||
try
|
||||
{
|
||||
app.Logger.LogInformation("Validating configuration...");
|
||||
app.Services.CreateScope().ServiceProvider.GetRequiredService<IStartupValidator>().Validate();
|
||||
}
|
||||
catch (OptionsValidationException e)
|
||||
{
|
||||
app.Logger.LogCritical("Failed to validate configuration: {error}", e.Message);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
|
@ -115,6 +123,9 @@ public static class WebApplicationExtensions
|
|||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var storageConfig = app.Configuration.GetSection("Storage").Get<Config.StorageSection>() ??
|
||||
throw new Exception("Failed to read Storage config section");
|
||||
|
||||
if (storageConfig.Mode == Enums.FileStorage.Local)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(storageConfig.Local?.Path) ||
|
||||
|
|
Loading…
Add table
Reference in a new issue