diff --git a/Watcher/Controllers/MonitoringController.cs b/Watcher/Controllers/MonitoringController.cs new file mode 100644 index 0000000..eb13256 --- /dev/null +++ b/Watcher/Controllers/MonitoringController.cs @@ -0,0 +1,131 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.CodeAnalysis; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Watcher.Data; +using Watcher.Models; +using Watcher.ViewModels; + +namespace Watcher.Controllers; + +public class RegistrationDto +{ + // Server Identity + [Required] + public int Id { get; set; } + + [Required] + public string? IpAddress { get; set; } + + // Hardware Info + [Required] + public string? CpuType { get; set; } + + [Required] + public int CpuCores { get; set; } + + [Required] + public string? GpuType { get; set; } + + [Required] + public double RamSize { get; set; } + +} + +public class MetricDto +{ + // Server Identity + [Required] + public int Id { get; set; } + + [Required] + public string? IpAddress { get; set; } + + // Metrics + // CPU Auslastung, CPU Temperatur + // GPU Auslastung, GPU Temperatur + // RAM Auslastung + // Disks? +} + +[ApiController] +[Route("[monitoring]")] +public class MonitoringController : Controller +{ + private readonly AppDbContext _context; + + public MonitoringController(AppDbContext context) + { + _context = context; + } + + [HttpPost("register")] + public async Task Register([FromBody] RegistrationDto dto) + { + // Gültigkeit des Payloads prüfen + if (!ModelState.IsValid) + { + var errors = ModelState.Values + .SelectMany(v => v.Errors) + .Select(e => e.ErrorMessage) + .ToList(); + + return BadRequest(new { error = "Ungültiger Payload", details = errors }); + } + + // Server in Datenbank finden + var server = await _context.Servers + .FirstOrDefaultAsync(s => s.IPAddress == dto.IpAddress); + + if (server != null) + { + // Serverdaten in Datenbank eintragen + server.CpuType = dto.CpuType; + server.CpuCores = dto.CpuCores; + server.GpuType = dto.GpuType; + server.RamSize = dto.RamSize; + + // Änderungen in Datenbank speichern + await _context.SaveChangesAsync(); + + // Success + return Ok(); + } + + return NotFound("No Matching Server found."); + + } + + [HttpPost("metric")] + public async Task Receive([FromBody] MetricDto dto) + { + // Gültigkeit des Payloads prüfen + if (!ModelState.IsValid) + { + var errors = ModelState.Values + .SelectMany(v => v.Errors) + .Select(e => e.ErrorMessage) + .ToList(); + + return BadRequest(new { error = "Ungültiger Payload", details = errors }); + } + + // Server in Datenbank finden + var server = await _context.Servers + .FirstOrDefaultAsync(s => s.IPAddress == dto.IpAddress); + + if (server != null) + { + // Serverdaten in Datenbank eintragen + + // Success + return Ok(); + } + + return NotFound("No Matching Server found."); + + } +} \ No newline at end of file diff --git a/Watcher/Migrations/20250616181808_Server-Hardware-Infos.Designer.cs b/Watcher/Migrations/20250616181808_Server-Hardware-Infos.Designer.cs new file mode 100644 index 0000000..f3b3e9a --- /dev/null +++ b/Watcher/Migrations/20250616181808_Server-Hardware-Infos.Designer.cs @@ -0,0 +1,300 @@ +// +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("20250616181808_Server-Hardware-Infos")] + partial class ServerHardwareInfos + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Watcher.Models.Container", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Hostname") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("IsRunning") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TagId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("TagId"); + + b.ToTable("Containers"); + }); + + modelBuilder.Entity("Watcher.Models.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("Tag") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Watcher.Models.LogEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ContainerId") + .HasColumnType("int"); + + b.Property("Level") + .HasColumnType("longtext"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ServerId"); + + b.ToTable("LogEvents"); + }); + + modelBuilder.Entity("Watcher.Models.Metric", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ContainerId") + .HasColumnType("int"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("longtext"); + + b.Property("Value") + .HasColumnType("double"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ServerId"); + + b.ToTable("Metrics"); + }); + + modelBuilder.Entity("Watcher.Models.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CpuCores") + .HasColumnType("int"); + + b.Property("CpuType") + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("GpuType") + .HasColumnType("longtext"); + + b.Property("IPAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsOnline") + .HasColumnType("tinyint(1)"); + + b.Property("LastSeen") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RamSize") + .HasColumnType("double"); + + b.Property("TagId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.ToTable("Servers"); + }); + + modelBuilder.Entity("Watcher.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("Watcher.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("LastLogin") + .HasColumnType("datetime(6)"); + + b.Property("PocketId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PreferredUsername") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Watcher.Models.Container", b => + { + b.HasOne("Watcher.Models.Image", "Image") + .WithMany("Containers") + .HasForeignKey("ImageId"); + + b.HasOne("Watcher.Models.Tag", null) + .WithMany("Containers") + .HasForeignKey("TagId"); + + b.Navigation("Image"); + }); + + 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.Metric", 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/20250616181808_Server-Hardware-Infos.cs b/Watcher/Migrations/20250616181808_Server-Hardware-Infos.cs new file mode 100644 index 0000000..da270ee --- /dev/null +++ b/Watcher/Migrations/20250616181808_Server-Hardware-Infos.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Watcher.Migrations +{ + /// + public partial class ServerHardwareInfos : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CpuCores", + table: "Servers", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "CpuType", + table: "Servers", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "GpuType", + table: "Servers", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "RamSize", + table: "Servers", + type: "double", + nullable: false, + defaultValue: 0.0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CpuCores", + table: "Servers"); + + migrationBuilder.DropColumn( + name: "CpuType", + table: "Servers"); + + migrationBuilder.DropColumn( + name: "GpuType", + table: "Servers"); + + migrationBuilder.DropColumn( + name: "RamSize", + table: "Servers"); + } + } +} diff --git a/Watcher/Migrations/AppDbContextModelSnapshot.cs b/Watcher/Migrations/AppDbContextModelSnapshot.cs index 1117443..f34eaed 100644 --- a/Watcher/Migrations/AppDbContextModelSnapshot.cs +++ b/Watcher/Migrations/AppDbContextModelSnapshot.cs @@ -145,12 +145,21 @@ namespace Watcher.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + b.Property("CpuCores") + .HasColumnType("int"); + + b.Property("CpuType") + .HasColumnType("longtext"); + b.Property("CreatedAt") .HasColumnType("datetime(6)"); b.Property("Description") .HasColumnType("longtext"); + b.Property("GpuType") + .HasColumnType("longtext"); + b.Property("IPAddress") .IsRequired() .HasColumnType("longtext"); @@ -165,6 +174,9 @@ namespace Watcher.Migrations .IsRequired() .HasColumnType("longtext"); + b.Property("RamSize") + .HasColumnType("double"); + b.Property("TagId") .HasColumnType("int"); diff --git a/Watcher/Models/Server.cs b/Watcher/Models/Server.cs index 84a2f9d..8c0cacd 100644 --- a/Watcher/Models/Server.cs +++ b/Watcher/Models/Server.cs @@ -19,5 +19,13 @@ public class Server public string? Description { get; set; } + // Hardware Infos + public string? CpuType { get; set; } = string.Empty; + public int CpuCores { get; set; } + public string? GpuType { get; set; } = string.Empty; + public double RamSize { get; set; } + + + }