diff --git a/Tests/servicediscovery.py b/Tests/servicediscovery.py index d73ad5f..dcf2df8 100644 --- a/Tests/servicediscovery.py +++ b/Tests/servicediscovery.py @@ -3,10 +3,9 @@ import urllib.request url = "http://localhost:5000/monitoring/service-discovery" payload = { -"ServerId": 1, -"ContainerId": "aaaaaaaaaaaa", -"Name": "test-Name", -"Image": "test-Image" + "server_id": 7, + "containers": ["{\"id\":\"6621c5b67c25\",\"image\":\"git.triggermeelmo.com/donpat1to/watcher-agent:v0.1.26\",\"name\":\"watcher-agent\"}", + "{\"id\":\"b8c86fb260bd\",\"image\":\"git.triggermeelmo.com/watcher/watcher-server:v0.1.10\",\"name\":\"watcher\"}"] } data = json.dumps(payload).encode("utf-8") diff --git a/Watcher/Controllers/ContainerController.cs b/Watcher/Controllers/ContainerController.cs index b18e4dd..f3f5c63 100644 --- a/Watcher/Controllers/ContainerController.cs +++ b/Watcher/Controllers/ContainerController.cs @@ -18,17 +18,17 @@ public class ContainerController : Controller } public async Task Overview() -{ - var containers = await _context.Containers.ToListAsync(); + { + var containers = await _context.Containers.ToListAsync(); var servers = await _context.Servers.ToListAsync(); - var viewModel = new ContainerOverviewViewModel - { - Servers = servers, - Containers = containers - }; + var viewModel = new ContainerOverviewViewModel + { + Servers = servers, + Containers = containers + }; - return View(viewModel); -} + return View(viewModel); + } } diff --git a/Watcher/Controllers/MonitoringController.cs b/Watcher/Controllers/MonitoringController.cs index 0f4e2a3..e956ed0 100644 --- a/Watcher/Controllers/MonitoringController.cs +++ b/Watcher/Controllers/MonitoringController.cs @@ -1,9 +1,12 @@ using System.ComponentModel.DataAnnotations; +using System.Net; using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; @@ -81,8 +84,8 @@ public class MetricDto public class ServiceDto { - public required int Server_id { get; set; } // Vom Watcher-Server zugewiesene ID des Hosts - public required JsonContent Containers { get; set; } + public required int server_id { get; set; } // Vom Watcher-Server zugewiesene ID des Hosts + public required List containers { get; set; } } [ApiController] @@ -238,12 +241,37 @@ public class MonitoringController : Controller } // Json zu was brauchbarem machen - string containersJson = await dto.Containers.ReadAsStringAsync(); - List newContainers = JsonSerializer.Deserialize>(containersJson)?? new List();; + //string containersJson = await dto.containers.ReadAsStringAsync(); + //List newContainers = JsonSerializer.Deserialize>(containersJson)?? new List();; + + List newContainers = new List(); + + foreach (String s in dto.containers) + { + // JSON zu einem JsonDocument parsen + using JsonDocument doc = JsonDocument.Parse(s); + JsonElement root = doc.RootElement; + + // Einzelne Werte extrahieren + string id = root.GetProperty("id").GetString() ?? ""; + string image = root.GetProperty("image").GetString() ?? ""; + string name = root.GetProperty("name").GetString() ?? ""; + + Container newContainer = new Container + { + ServerId = dto.server_id, + ContainerId = id, + Image = image, + Name = name, + }; + + + newContainers.Add(newContainer); + } foreach (Container c in newContainers) { - c.ServerId = dto.Server_id; + c.ServerId = dto.server_id; // Debug Logs // TODO entfernen wenn fertig getestet Console.WriteLine("---------"); @@ -260,7 +288,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 == dto.server_id) .ToList(); @@ -310,6 +338,45 @@ public class MonitoringController : Controller } + // Endpoint, an den der Agent die Metrics der registrierten Container schickt + public async Task ServiceMetrics([FromBody] ServiceMetricDto dto) + { + // Gültigkeit des Payloads prüfen + if (!ModelState.IsValid) + { + var errors = ModelState.Values + .SelectMany(v => v.Errors) + .Select(e => e.ErrorMessage) + .ToList(); + + _logger.LogError("Invalid ServiceDetection-Payload."); + return BadRequest(new { error = "Invalid Payload", details = errors }); + } + + // Liste an Metrics aus der dto erstellen + List metrics = new List(); + + // Metrics in die Datenbank eintragen + try + { + foreach (ContainerMetric m in metrics) + { + _context.ContainerMetrics.Add(m); + await _context.SaveChangesAsync(); + // _logger.LogInformation(m. + " added for Host " + c.ServerId); + return Ok(); + } + } + catch (SqliteException e) + { + _logger.LogError(e.Message); + return StatusCode(500); + } + + return Ok(); + + } + // Durchschnittliche Werte Berechnen public async Task CalculateMedian(string Metric, int HoursToMonitor, int ServerId) { diff --git a/Watcher/Data/AppDbContext.cs b/Watcher/Data/AppDbContext.cs index c88df1b..1affd63 100644 --- a/Watcher/Data/AppDbContext.cs +++ b/Watcher/Data/AppDbContext.cs @@ -26,6 +26,8 @@ public class AppDbContext : DbContext public DbSet Tags { get; set; } + public DbSet ContainerMetrics { get; set; } + public DbSet Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) diff --git a/Watcher/Migrations/20251029105954_container-changed.Designer.cs b/Watcher/Migrations/20251029105954_container-changed.Designer.cs new file mode 100644 index 0000000..4eda82f --- /dev/null +++ b/Watcher/Migrations/20251029105954_container-changed.Designer.cs @@ -0,0 +1,355 @@ +// +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("20251029105954_container-changed")] + partial class containerchanged + { + /// + 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"); + + b.Property("Image") + .HasColumnType("TEXT"); + + b.Property("ImageId") + .HasColumnType("INTEGER"); + + b.Property("IsRunning") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("TagId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("TagId"); + + b.ToTable("Containers"); + }); + + 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("CPU_Load_Critical") + .HasColumnType("REAL"); + + b.Property("CPU_Load_Warning") + .HasColumnType("REAL"); + + b.Property("CPU_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("CPU_Temp_Warning") + .HasColumnType("REAL"); + + b.Property("CpuCores") + .HasColumnType("INTEGER"); + + b.Property("CpuType") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DISK_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("DISK_Temp_Warning") + .HasColumnType("REAL"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DiskSpace") + .HasColumnType("TEXT"); + + b.Property("Disk_Usage_Critical") + .HasColumnType("REAL"); + + b.Property("Disk_Usage_Warning") + .HasColumnType("REAL"); + + b.Property("GPU_Load_Critical") + .HasColumnType("REAL"); + + b.Property("GPU_Load_Warning") + .HasColumnType("REAL"); + + b.Property("GPU_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("GPU_Temp_Warning") + .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("RAM_Load_Critical") + .HasColumnType("REAL"); + + b.Property("RAM_Load_Warning") + .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"); + }); + + 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("IdentityProvider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastLogin") + .HasColumnType("TEXT"); + + b.Property("OIDC_Id") + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .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.Tag", null) + .WithMany("Containers") + .HasForeignKey("TagId"); + }); + + 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/20251029105954_container-changed.cs b/Watcher/Migrations/20251029105954_container-changed.cs new file mode 100644 index 0000000..6f880a4 --- /dev/null +++ b/Watcher/Migrations/20251029105954_container-changed.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Watcher.Migrations +{ + /// + public partial class containerchanged : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/Watcher/Migrations/20251029125404_ContainerMetrics-Added.Designer.cs b/Watcher/Migrations/20251029125404_ContainerMetrics-Added.Designer.cs new file mode 100644 index 0000000..73b5076 --- /dev/null +++ b/Watcher/Migrations/20251029125404_ContainerMetrics-Added.Designer.cs @@ -0,0 +1,355 @@ +// +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("20251029125404_ContainerMetrics-Added")] + partial class ContainerMetricsAdded + { + /// + 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"); + + b.Property("Image") + .HasColumnType("TEXT"); + + b.Property("ImageId") + .HasColumnType("INTEGER"); + + b.Property("IsRunning") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("TagId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("TagId"); + + b.ToTable("Containers"); + }); + + 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("CPU_Load_Critical") + .HasColumnType("REAL"); + + b.Property("CPU_Load_Warning") + .HasColumnType("REAL"); + + b.Property("CPU_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("CPU_Temp_Warning") + .HasColumnType("REAL"); + + b.Property("CpuCores") + .HasColumnType("INTEGER"); + + b.Property("CpuType") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DISK_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("DISK_Temp_Warning") + .HasColumnType("REAL"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DiskSpace") + .HasColumnType("TEXT"); + + b.Property("Disk_Usage_Critical") + .HasColumnType("REAL"); + + b.Property("Disk_Usage_Warning") + .HasColumnType("REAL"); + + b.Property("GPU_Load_Critical") + .HasColumnType("REAL"); + + b.Property("GPU_Load_Warning") + .HasColumnType("REAL"); + + b.Property("GPU_Temp_Critical") + .HasColumnType("REAL"); + + b.Property("GPU_Temp_Warning") + .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("RAM_Load_Critical") + .HasColumnType("REAL"); + + b.Property("RAM_Load_Warning") + .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"); + }); + + 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("IdentityProvider") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastLogin") + .HasColumnType("TEXT"); + + b.Property("OIDC_Id") + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .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.Tag", null) + .WithMany("Containers") + .HasForeignKey("TagId"); + }); + + 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/20251029125404_ContainerMetrics-Added.cs b/Watcher/Migrations/20251029125404_ContainerMetrics-Added.cs new file mode 100644 index 0000000..c084fda --- /dev/null +++ b/Watcher/Migrations/20251029125404_ContainerMetrics-Added.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Watcher.Migrations +{ + /// + public partial class ContainerMetricsAdded : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/Watcher/Models/Container.cs b/Watcher/Models/Container.cs index 2807d80..8dc084f 100644 --- a/Watcher/Models/Container.cs +++ b/Watcher/Models/Container.cs @@ -1,14 +1,23 @@ +using System.Text.Json.Serialization; + namespace Watcher.Models; public class Container { + [JsonPropertyName("id")] public int Id { get; set; } public int ServerId { get; set; } public String? ContainerId { get; set; } + + [JsonPropertyName("image")] public String? Image { get; set; } + + [JsonPropertyName("name")] public String? Name { get; set; } + // keine Variable, die vom Agent übergeben wird. Ein container ist immer Running, die Variable dient nur für die Übersicht + // auf dem Dashboard. public Boolean IsRunning { get; set; } = true; } diff --git a/Watcher/Models/ContainerMetric.cs b/Watcher/Models/ContainerMetric.cs new file mode 100644 index 0000000..5c95d99 --- /dev/null +++ b/Watcher/Models/ContainerMetric.cs @@ -0,0 +1,24 @@ +namespace Watcher.Models; + +public class ContainerMetric +{ + // Metric Metadata + public int Id { get; set; } + public DateTime Timestamp { get; set; } + + + // Zuordnung zu einem Container -- Foreign Key + public int? ContainerId { get; set; } + + + // CPU-Daten + public double CPU_Load { get; set; } = 0.0; // % + + public double CPU_Temp { get; set; } = 0.0; // deg C + + // RAM-Daten + public double RAM_Size { get; set; } = 0.0; // GB + + public double RAM_Load { get; set; } = 0.0; // % + +} diff --git a/Watcher/Views/Container/Overview.cshtml b/Watcher/Views/Container/Overview.cshtml index 07cccb7..e3edfc3 100644 --- a/Watcher/Views/Container/Overview.cshtml +++ b/Watcher/Views/Container/Overview.cshtml @@ -12,20 +12,22 @@
- - - - - + + + + + @foreach (Container container in Model.Containers) { + - - - + + + + }
ServiceHostServerStatusDeploymentContainer-IDNameImageHost-IDAktionen
@container.ContainerId @container.Name@container.ServerIdnicht automatisiertDocker@container.Image@container.ServerIdnicht verfügbar