first commit
This commit is contained in:
14
Config/AppConfig.cs
Normal file
14
Config/AppConfig.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class AppConfig
|
||||
{
|
||||
public HanaConfig Hana { get; set; } = new();
|
||||
public BackupConfig Backup { get; set; } = new();
|
||||
public CleanerConfig Cleaner { get; set; } = new();
|
||||
public MonitorConfig Monitor { get; set; } = new();
|
||||
public FirewallConfig Firewall { get; set; } = new();
|
||||
public AuroraConfig Aurora { get; set; } = new();
|
||||
public NtfyConfig Ntfy { get; set; } = new();
|
||||
}
|
||||
26
Config/AppConfigJsonContext.cs
Normal file
26
Config/AppConfigJsonContext.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
/// <summary>
|
||||
/// AOT-compatible JSON source generation context.
|
||||
/// All config types serialized by the app must be listed here.
|
||||
/// </summary>
|
||||
[JsonSerializable(typeof(AppConfig))]
|
||||
[JsonSerializable(typeof(HanaConfig))]
|
||||
[JsonSerializable(typeof(BackupConfig))]
|
||||
[JsonSerializable(typeof(CleanerConfig))]
|
||||
[JsonSerializable(typeof(MonitorConfig))]
|
||||
[JsonSerializable(typeof(FirewallConfig))]
|
||||
[JsonSerializable(typeof(FirewallServiceEntry))]
|
||||
[JsonSerializable(typeof(AuroraConfig))]
|
||||
[JsonSerializable(typeof(NtfyConfig))]
|
||||
[JsonSerializable(typeof(List<string>))]
|
||||
[JsonSerializable(typeof(List<FirewallServiceEntry>))]
|
||||
[JsonSourceGenerationOptions(
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||
UseStringEnumConverter = true)]
|
||||
internal partial class AppConfigJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
23
Config/AuroraConfig.cs
Normal file
23
Config/AuroraConfig.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class AuroraConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public int ScheduleHour { get; set; } = 5;
|
||||
public int ScheduleMinute { get; set; } = 0;
|
||||
|
||||
/// <summary>hdbuserstore key with admin rights (DROP SCHEMA, EXPORT, IMPORT, GRANT).</summary>
|
||||
public string AdminUserKey { get; set; } = "CRONKEY";
|
||||
|
||||
/// <summary>Source schema to export and re-import as <SourceSchema>_AURORA.</summary>
|
||||
public string SourceSchema { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>DB user that receives ALL PRIVILEGES on the Aurora schema.</summary>
|
||||
public string AuroraUser { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Directory used for temporary export files during the Aurora refresh.</summary>
|
||||
public string BackupBasePath { get; set; } = "/hana/backup/aurora";
|
||||
|
||||
/// <summary>Thread count for export/import. 0 = auto (nproc/2).</summary>
|
||||
public int Threads { get; set; } = 0;
|
||||
}
|
||||
35
Config/BackupConfig.cs
Normal file
35
Config/BackupConfig.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public enum BackupType { Tenant, Schema, All }
|
||||
|
||||
public sealed class BackupConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public int ScheduleHour { get; set; } = 2;
|
||||
public int ScheduleMinute { get; set; } = 0;
|
||||
|
||||
/// <summary>What to back up: Tenant, Schema, or All.</summary>
|
||||
public BackupType Type { get; set; } = BackupType.All;
|
||||
|
||||
/// <summary>hdbuserstore key for the tenant DB.</summary>
|
||||
public string UserKey { get; set; } = "CRONKEY";
|
||||
|
||||
/// <summary>Base directory for tenant backup files.</summary>
|
||||
public string BackupBasePath { get; set; } = "/hana/backup/tenant";
|
||||
|
||||
public bool Compress { get; set; } = true;
|
||||
|
||||
public bool BackupSystemDb { get; set; } = false;
|
||||
public string SystemDbUserKey { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Schema names to export when Type is Schema or All.</summary>
|
||||
public List<string> SchemaNames { get; set; } = [];
|
||||
|
||||
/// <summary>Base directory for schema export files.</summary>
|
||||
public string SchemaBackupPath { get; set; } = "/hana/backup/schema";
|
||||
|
||||
public bool CompressSchema { get; set; } = true;
|
||||
|
||||
/// <summary>Thread count for export/import. 0 = auto (nproc/2).</summary>
|
||||
public int Threads { get; set; } = 0;
|
||||
}
|
||||
15
Config/CleanerConfig.cs
Normal file
15
Config/CleanerConfig.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class CleanerConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public int ScheduleHour { get; set; } = 3;
|
||||
public int ScheduleMinute { get; set; } = 0;
|
||||
|
||||
public string TenantBackupPath { get; set; } = "/hana/backup/tenant";
|
||||
public int TenantRetentionDays { get; set; } = 7;
|
||||
|
||||
/// <summary>One or more log backup directories. Each is cleaned with LogRetentionDays.</summary>
|
||||
public List<string> LogBackupPaths { get; set; } = [];
|
||||
public int LogRetentionDays { get; set; } = 1;
|
||||
}
|
||||
40
Config/ConfigService.cs
Normal file
40
Config/ConfigService.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class ConfigService
|
||||
{
|
||||
private const string ConfigDir = "/etc/hanatoolbox";
|
||||
private const string ConfigFile = "/etc/hanatoolbox/hanatoolbox.json";
|
||||
|
||||
public static AppConfig Load()
|
||||
{
|
||||
if (!File.Exists(ConfigFile))
|
||||
return new AppConfig();
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(ConfigFile);
|
||||
return JsonSerializer.Deserialize(json, AppConfigJsonContext.Default.AppConfig)
|
||||
?? new AppConfig();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Failed to load config from {ConfigFile}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save(AppConfig config)
|
||||
{
|
||||
Directory.CreateDirectory(ConfigDir);
|
||||
Directory.CreateDirectory(StateDirectory);
|
||||
|
||||
var json = JsonSerializer.Serialize(config, AppConfigJsonContext.Default.AppConfig);
|
||||
File.WriteAllText(ConfigFile, json);
|
||||
}
|
||||
|
||||
public static bool Exists() => File.Exists(ConfigFile);
|
||||
|
||||
public static string StateDirectory => "/etc/hanatoolbox/state";
|
||||
}
|
||||
36
Config/FirewallConfig.cs
Normal file
36
Config/FirewallConfig.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<FirewallDecision>))]
|
||||
public enum FirewallDecision { Skip, All, Ip }
|
||||
|
||||
public sealed class FirewallServiceEntry
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public List<string> Ports { get; set; } = [];
|
||||
public FirewallDecision Decision { get; set; } = FirewallDecision.Skip;
|
||||
public List<string> AllowedIps { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class FirewallConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public int ScheduleHour { get; set; } = 4;
|
||||
public int ScheduleMinute { get; set; } = 0;
|
||||
|
||||
/// <summary>Whether to flush all existing rules before applying. Saved in config.</summary>
|
||||
public bool FlushBeforeApply { get; set; } = false;
|
||||
|
||||
public List<FirewallServiceEntry> Services { get; set; } =
|
||||
[
|
||||
new() { Name = "SAP Web Client", Ports = ["443"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SAP HANA Database (System & Company DB)", Ports = ["30013","30015"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SAP Business One SLD", Ports = ["40000"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SAP Business One Auth", Ports = ["40020"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SAP Business One Service Layer/Cockpit", Ports = ["50000","4300"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SAP Host Agent", Ports = ["1128","1129"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SSH Remote Access", Ports = ["22"], Decision = FirewallDecision.Skip },
|
||||
new() { Name = "SMB / B1_SHR (File Sharing)", Ports = ["139","445"], Decision = FirewallDecision.Skip },
|
||||
];
|
||||
}
|
||||
14
Config/HanaConfig.cs
Normal file
14
Config/HanaConfig.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class HanaConfig
|
||||
{
|
||||
/// <summary>HANA System ID, e.g. NDB. Used to build the OS user <sid>adm.</summary>
|
||||
public string Sid { get; set; } = "NDB";
|
||||
public string InstanceNumber { get; set; } = "00";
|
||||
|
||||
/// <summary>Optional override for hdbsql binary path. Null = auto-detect.</summary>
|
||||
public string? HdbsqlPath { get; set; }
|
||||
|
||||
/// <summary>Optional override for hdbuserstore binary path. Null = auto-detect.</summary>
|
||||
public string? HdbuserstorePath { get; set; }
|
||||
}
|
||||
38
Config/MonitorConfig.cs
Normal file
38
Config/MonitorConfig.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class MonitorConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
/// <summary>hdbuserstore key used for all monitoring SQL queries.</summary>
|
||||
public string HanaUserKey { get; set; } = "CRONKEY";
|
||||
|
||||
public string HanaInstanceNumber { get; set; } = "00";
|
||||
|
||||
/// <summary>Full path to sapcontrol binary.</summary>
|
||||
public string SapcontrolPath { get; set; } = "/usr/sap/NDB/HDB00/exe/sapcontrol";
|
||||
|
||||
/// <summary>Company name included in ntfy alert messages.</summary>
|
||||
public string CompanyName { get; set; } = "MyCompany";
|
||||
|
||||
/// <summary>Disk usage alert threshold in percent.</summary>
|
||||
public int DiskUsageThresholdPercent { get; set; } = 85;
|
||||
|
||||
/// <summary>Alert if truncated log segments exceed this percent of total.</summary>
|
||||
public int TruncatedSegmentThresholdPercent { get; set; } = 80;
|
||||
|
||||
/// <summary>Alert if free log segments fall below this percent of total.</summary>
|
||||
public int FreeSegmentThresholdPercent { get; set; } = 10;
|
||||
|
||||
/// <summary>Statement queue length above which a breach is counted.</summary>
|
||||
public int StatementQueueThreshold { get; set; } = 10;
|
||||
|
||||
/// <summary>How many consecutive cron ticks above threshold before alerting.</summary>
|
||||
public int StatementQueueConsecutiveRuns { get; set; } = 3;
|
||||
|
||||
/// <summary>Alert if the last successful backup is older than this many hours.</summary>
|
||||
public int BackupThresholdHours { get; set; } = 26;
|
||||
|
||||
/// <summary>Directories checked for disk usage.</summary>
|
||||
public List<string> DirectoriesToMonitor { get; set; } = ["/hana/data", "/hana/log"];
|
||||
}
|
||||
7
Config/NtfyConfig.cs
Normal file
7
Config/NtfyConfig.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace HanaToolbox.Config;
|
||||
|
||||
public sealed class NtfyConfig
|
||||
{
|
||||
public string Url { get; set; } = "https://ntfy.sh/your-topic";
|
||||
public string Token { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user