From f8961320c56812d1b6cd251722a331a4433c3627 Mon Sep 17 00:00:00 2001 From: triggermeelmo Date: Mon, 17 Nov 2025 15:37:28 +0100 Subject: [PATCH] DB startet Server bei ID 0 --- Watcher/Controllers/ApiController.cs | 2 +- Watcher/Controllers/MonitoringController.cs | 56 ++- Watcher/Data/AppDbContext.cs | 14 + ...117142850_StartServerIdsAtZero.Designer.cs | 395 ++++++++++++++++++ .../20251117142850_StartServerIdsAtZero.cs | 35 ++ .../Migrations/AppDbContextModelSnapshot.cs | 5 +- 6 files changed, 490 insertions(+), 17 deletions(-) create mode 100644 Watcher/Migrations/20251117142850_StartServerIdsAtZero.Designer.cs create mode 100644 Watcher/Migrations/20251117142850_StartServerIdsAtZero.cs diff --git a/Watcher/Controllers/ApiController.cs b/Watcher/Controllers/ApiController.cs index 56385a8..ab13813 100644 --- a/Watcher/Controllers/ApiController.cs +++ b/Watcher/Controllers/ApiController.cs @@ -27,6 +27,6 @@ public class ApiController : Controller public async Task GetAllServers() { var Servers = await _context.Servers.OrderBy(s => s.Id).ToListAsync(); - return Ok(); + return Ok(Servers); } } \ No newline at end of file diff --git a/Watcher/Controllers/MonitoringController.cs b/Watcher/Controllers/MonitoringController.cs index 547fe44..7e7c649 100644 --- a/Watcher/Controllers/MonitoringController.cs +++ b/Watcher/Controllers/MonitoringController.cs @@ -83,7 +83,8 @@ public class MetricDto public class DockerServiceDto { - public required int Server_id { get; set; } // Vom Watcher-Server zugewiesene ID des Hosts + public int Server_id { get; set; } // Vom Watcher-Server zugewiesene ID des Hosts (optional, falls der Agent diese bereits kennt) + public string? IpAddress { get; set; } // IP-Adresse des Servers (wird verwendet, falls Server_id nicht gesetzt oder 0 ist) public required JsonElement Containers { get; set; } } @@ -138,9 +139,13 @@ public class MonitoringController : Controller // Änderungen in Datenbank speichern await _context.SaveChangesAsync(); - // Success + // Success - Server-ID und IP-Adresse zurückgeben _logger.LogInformation("Agent für '{server}' erfolgreich registriert.", server.Name); - return Ok(); + return Ok(new + { + id = server.Id, + ipAddress = server.IPAddress + }); } _logger.LogError("Kein Server für Registrierung gefunden"); return NotFound("No Matching Server found."); @@ -182,7 +187,7 @@ public class MonitoringController : Controller // Server in Datenbank finden var server = await _context.Servers - .FirstOrDefaultAsync(s => s.IPAddress == dto.IpAddress); + .FirstOrDefaultAsync(s => s.Id == dto.ServerId); if (server != null) { @@ -244,13 +249,32 @@ public class MonitoringController : Controller return BadRequest(new { error = "Invalid Payload", details = errors }); } - // Prüfen, ob der Server existiert - var serverExists = await _context.Servers.AnyAsync(s => s.Id == dto.Server_id); - if (!serverExists) + // Debug-Logging für eingehende Requests + _logger.LogDebug("Service-Discovery Request empfangen: Server_id={ServerId}, IpAddress={IpAddress}", + dto.Server_id, dto.IpAddress ?? "null"); + + // Server anhand IP-Adresse oder ID finden + Server? server = null; + + // Zuerst versuchen, Server anhand der IP-Adresse zu finden (bevorzugte Methode) + if (!string.IsNullOrEmpty(dto.IpAddress)) { - _logger.LogError($"Server with ID {dto.Server_id} does not exist."); - return BadRequest(new { error = "Server not found", details = $"Server with ID {dto.Server_id} does not exist. Please register the server first." }); + server = await _context.Servers.FirstOrDefaultAsync(s => s.IPAddress == dto.IpAddress); } + // Falls keine IP-Adresse übergeben wurde oder Server nicht gefunden, versuche es mit der ID + else if (dto.Server_id > 0) + { + server = await _context.Servers.FirstOrDefaultAsync(s => s.Id == dto.Server_id); + } + + if (server == null) + { + _logger.LogError("Server with IP '{IpAddress}' or ID {ServerId} does not exist.", dto.IpAddress, dto.Server_id); + return BadRequest(new { error = "Server not found", details = $"Server with IP '{dto.IpAddress}' or ID {dto.Server_id} does not exist. Please register the server first." }); + } + + // Server ID für die weitere Verarbeitung setzen + int serverId = server.Id; List newContainers = JsonSerializer.Deserialize>(dto.Containers.GetRawText()) @@ -258,7 +282,7 @@ public class MonitoringController : Controller foreach (Container container in newContainers) { - container.ServerId = dto.Server_id; + container.ServerId = serverId; // Debug Logs // TODO entfernen wenn fertig getestet Console.WriteLine("---------"); @@ -272,7 +296,7 @@ public class MonitoringController : Controller // Liste aller Container, die bereits der übergebenen ServerId zugewiesen sind List existingContainers = _context.Containers - .Where(c => c.ServerId == dto.Server_id) + .Where(c => c.ServerId == serverId) .ToList(); @@ -291,7 +315,7 @@ public class MonitoringController : Controller existingContainer.Image = container.Image; existingContainer.IsRunning = true; - _logger.LogInformation("Container '{containerName}' (ID: {containerId}) already exists for Server {serverId}, updated.", container.Name, container.ContainerId, dto.Server_id); + _logger.LogInformation("Container '{containerName}' (ID: {containerId}) already exists for Server {serverId}, updated.", container.Name, container.ContainerId, serverId); } // Container auf einen Host/Server registrieren else @@ -393,6 +417,7 @@ public class MonitoringController : Controller return NotFound(); } + [Authorize] [HttpGet("cpu-usage")] public async Task GetCpuUsageData(int serverId, int hours = 1) { @@ -413,6 +438,7 @@ public class MonitoringController : Controller return Ok(data); } + [Authorize] [HttpGet("ram-usage")] public async Task GetRamUsageData(int serverId, int hours = 1) { @@ -433,6 +459,7 @@ public class MonitoringController : Controller return Ok(data); } + [Authorize] [HttpGet("gpu-usage")] public async Task GetGpuUsageData(int serverId, int hours = 1) { @@ -453,6 +480,7 @@ public class MonitoringController : Controller return Ok(data); } + [Authorize] [HttpGet("current-metrics/{serverId}")] public async Task GetCurrentMetrics(int serverId) { @@ -509,9 +537,7 @@ public class MonitoringController : Controller // Degree Input auf zwei Nachkommastellen runden public static double SanitizeInput(double metricInput) { - Math.Round(metricInput, 2); - - return metricInput; + return Math.Round(metricInput, 2); } private List ParseServiceDiscoveryInput(int serverId, List containers) diff --git a/Watcher/Data/AppDbContext.cs b/Watcher/Data/AppDbContext.cs index 36030f1..c9538bc 100644 --- a/Watcher/Data/AppDbContext.cs +++ b/Watcher/Data/AppDbContext.cs @@ -41,5 +41,19 @@ public class AppDbContext : DbContext optionsBuilder.UseSqlite(connStr); } } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // Server IDs bei 0 starten lassen (statt Standard 1) + modelBuilder.Entity() + .Property(s => s.Id) + .ValueGeneratedOnAdd(); + + // SQLite-spezifische Konfiguration: AUTOINCREMENT startet bei 0 + modelBuilder.Entity() + .ToTable(tb => tb.HasCheckConstraint("CK_Server_Id", "Id >= 0")); + } } diff --git a/Watcher/Migrations/20251117142850_StartServerIdsAtZero.Designer.cs b/Watcher/Migrations/20251117142850_StartServerIdsAtZero.Designer.cs new file mode 100644 index 0000000..4beca61 --- /dev/null +++ b/Watcher/Migrations/20251117142850_StartServerIdsAtZero.Designer.cs @@ -0,0 +1,395 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Watcher.Data; + +#nullable disable + +namespace Watcher.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20251117142850_StartServerIdsAtZero")] + partial class StartServerIdsAtZero + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); + + modelBuilder.Entity("Watcher.Models.Container", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ContainerId") + .HasColumnType("TEXT") + .HasAnnotation("Relational:JsonPropertyName", "id"); + + b.Property("Image") + .HasColumnType("TEXT") + .HasAnnotation("Relational:JsonPropertyName", "image"); + + b.Property("ImageId") + .HasColumnType("INTEGER"); + + b.Property("IsRunning") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT") + .HasAnnotation("Relational:JsonPropertyName", "name"); + + b.Property("ServerId") + .HasColumnType("INTEGER") + .HasAnnotation("Relational:JsonPropertyName", "Server_id"); + + b.Property("TagId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("ServerId"); + + b.HasIndex("TagId"); + + b.ToTable("Containers"); + }); + + modelBuilder.Entity("Watcher.Models.ContainerMetric", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CPU_Load") + .HasColumnType("REAL"); + + b.Property("CPU_Temp") + .HasColumnType("REAL"); + + b.Property("ContainerId") + .HasColumnType("INTEGER"); + + b.Property("RAM_Load") + .HasColumnType("REAL"); + + b.Property("RAM_Size") + .HasColumnType("REAL"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ContainerMetrics"); + }); + + modelBuilder.Entity("Watcher.Models.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Tag") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Watcher.Models.LogEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ContainerId") + .HasColumnType("INTEGER"); + + b.Property("Level") + .HasColumnType("TEXT"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ServerId"); + + b.ToTable("LogEvents"); + }); + + modelBuilder.Entity("Watcher.Models.Metric", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CPU_Load") + .HasColumnType("REAL"); + + b.Property("CPU_Temp") + .HasColumnType("REAL"); + + b.Property("DISK_Size") + .HasColumnType("REAL"); + + b.Property("DISK_Temp") + .HasColumnType("REAL"); + + b.Property("DISK_Usage") + .HasColumnType("REAL"); + + b.Property("GPU_Load") + .HasColumnType("REAL"); + + b.Property("GPU_Temp") + .HasColumnType("REAL"); + + b.Property("GPU_Vram_Size") + .HasColumnType("REAL"); + + b.Property("GPU_Vram_Usage") + .HasColumnType("REAL"); + + b.Property("NET_In") + .HasColumnType("REAL"); + + b.Property("NET_Out") + .HasColumnType("REAL"); + + b.Property("RAM_Load") + .HasColumnType("REAL"); + + b.Property("RAM_Size") + .HasColumnType("REAL"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Metrics"); + }); + + modelBuilder.Entity("Watcher.Models.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CpuCores") + .HasColumnType("INTEGER"); + + b.Property("CpuLoadCritical") + .HasColumnType("REAL"); + + b.Property("CpuLoadWarning") + .HasColumnType("REAL"); + + b.Property("CpuTempCritical") + .HasColumnType("REAL"); + + b.Property("CpuTempWarning") + .HasColumnType("REAL"); + + b.Property("CpuType") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DiskSpace") + .HasColumnType("TEXT"); + + b.Property("DiskTempCritical") + .HasColumnType("REAL"); + + b.Property("DiskTempWarning") + .HasColumnType("REAL"); + + b.Property("DiskUsageCritical") + .HasColumnType("REAL"); + + b.Property("DiskUsageWarning") + .HasColumnType("REAL"); + + b.Property("GpuLoadCritical") + .HasColumnType("REAL"); + + b.Property("GpuLoadWarning") + .HasColumnType("REAL"); + + b.Property("GpuTempCritical") + .HasColumnType("REAL"); + + b.Property("GpuTempWarning") + .HasColumnType("REAL"); + + b.Property("GpuType") + .HasColumnType("TEXT"); + + b.Property("IPAddress") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsOnline") + .HasColumnType("INTEGER"); + + b.Property("IsVerified") + .HasColumnType("INTEGER"); + + b.Property("LastSeen") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RamLoadCritical") + .HasColumnType("REAL"); + + b.Property("RamLoadWarning") + .HasColumnType("REAL"); + + b.Property("RamSize") + .HasColumnType("REAL"); + + b.Property("TagId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.ToTable("Servers", t => + { + t.HasCheckConstraint("CK_Server_Id", "Id >= 0"); + }); + }); + + modelBuilder.Entity("Watcher.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("Watcher.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .HasColumnType("TEXT"); + + b.Property("LastLogin") + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Watcher.Models.Container", b => + { + b.HasOne("Watcher.Models.Image", null) + .WithMany("Containers") + .HasForeignKey("ImageId"); + + b.HasOne("Watcher.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Watcher.Models.Tag", null) + .WithMany("Containers") + .HasForeignKey("TagId"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Watcher.Models.LogEvent", b => + { + b.HasOne("Watcher.Models.Container", "Container") + .WithMany() + .HasForeignKey("ContainerId"); + + b.HasOne("Watcher.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId"); + + b.Navigation("Container"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Watcher.Models.Server", b => + { + b.HasOne("Watcher.Models.Tag", null) + .WithMany("Servers") + .HasForeignKey("TagId"); + }); + + modelBuilder.Entity("Watcher.Models.Image", b => + { + b.Navigation("Containers"); + }); + + modelBuilder.Entity("Watcher.Models.Tag", b => + { + b.Navigation("Containers"); + + b.Navigation("Servers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Watcher/Migrations/20251117142850_StartServerIdsAtZero.cs b/Watcher/Migrations/20251117142850_StartServerIdsAtZero.cs new file mode 100644 index 0000000..fd8f8b4 --- /dev/null +++ b/Watcher/Migrations/20251117142850_StartServerIdsAtZero.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Watcher.Migrations +{ + /// + public partial class StartServerIdsAtZero : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddCheckConstraint( + name: "CK_Server_Id", + table: "Servers", + sql: "Id >= 0"); + + // Bestehende Server-IDs um 1 verringern (1 -> 0, 2 -> 1, etc.) + migrationBuilder.Sql(@" + UPDATE Servers SET Id = Id - 1; + UPDATE Metrics SET ServerId = ServerId - 1 WHERE ServerId IS NOT NULL; + UPDATE Containers SET ServerId = ServerId - 1 WHERE ServerId IS NOT NULL; + UPDATE sqlite_sequence SET seq = seq - 1 WHERE name = 'Servers'; + "); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropCheckConstraint( + name: "CK_Server_Id", + table: "Servers"); + } + } +} diff --git a/Watcher/Migrations/AppDbContextModelSnapshot.cs b/Watcher/Migrations/AppDbContextModelSnapshot.cs index bc651b5..f07b2ff 100644 --- a/Watcher/Migrations/AppDbContextModelSnapshot.cs +++ b/Watcher/Migrations/AppDbContextModelSnapshot.cs @@ -288,7 +288,10 @@ namespace Watcher.Migrations b.HasIndex("TagId"); - b.ToTable("Servers"); + b.ToTable("Servers", t => + { + t.HasCheckConstraint("CK_Server_Id", "Id >= 0"); + }); }); modelBuilder.Entity("Watcher.Models.Tag", b =>