From f362dc9e3ad4a3b933867b357f2fe36e2a6ebe5e Mon Sep 17 00:00:00 2001 From: daniel-hbn Date: Sun, 15 Jun 2025 13:00:19 +0200 Subject: [PATCH] stuff --- Dockerfile | 25 +- Watcher/Controllers/HeartbeatController.cs | 43 +++ ...20250615102649_ServerAnpassung.Designer.cs | 293 ++++++++++++++++++ .../20250615102649_ServerAnpassung.cs | 30 ++ .../Migrations/AppDbContextModelSnapshot.cs | 3 + Watcher/Models/Server.cs | 2 + Watcher/Views/Server/overview.cshtml | 2 +- Watcher/Views/Shared/_Layout.cshtml | 4 +- Watcher/appsettings.json | 2 +- 9 files changed, 389 insertions(+), 15 deletions(-) create mode 100644 Watcher/Controllers/HeartbeatController.cs create mode 100644 Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs create mode 100644 Watcher/Migrations/20250615102649_ServerAnpassung.cs diff --git a/Dockerfile b/Dockerfile index 100b962..fad3ec9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,25 @@ -# Build-Stage +# 1. Build-Phase: SDK-Image FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /app # Projektdateien kopieren und Abhängigkeiten wiederherstellen -COPY *.csproj ./ +COPY *.sln . +COPY Watcher/*.csproj ./Watcher/ RUN dotnet restore -# Restlichen Code kopieren und veröffentlichen -COPY . ./ -RUN dotnet publish -c Release -o out +# Restliche Dateien kopieren und Build ausführen +COPY Watcher/. ./Watcher/ +WORKDIR /app/Watcher +RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false -# Runtime-Stage -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +# 2. Laufzeit-Phase: ASP.NET Core Runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 WORKDIR /app +COPY --from=build /app/publish . -COPY --from=build /app/out ./ - -EXPOSE 5000 -EXPOSE 5001 +# Exponiere Port 80 und 443 (HTTP + HTTPS) +EXPOSE 80 +EXPOSE 443 +# Anwendung starten ENTRYPOINT ["dotnet", "Watcher.dll"] diff --git a/Watcher/Controllers/HeartbeatController.cs b/Watcher/Controllers/HeartbeatController.cs new file mode 100644 index 0000000..0a362e3 --- /dev/null +++ b/Watcher/Controllers/HeartbeatController.cs @@ -0,0 +1,43 @@ +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; + +[ApiController] +[Route("[controller]")] +public class HeartbeatController : Controller +{ + + private readonly AppDbContext _context; + + public HeartbeatController(AppDbContext context) + { + _context = context; + } + + [HttpPost("receive")] + public async Task Receive([FromForm] int serverId) + { + var server = await _context.Servers.FirstOrDefaultAsync(s => s.Id == serverId); + + // Je nachdem, ob dier Datenbankeintrag für einen neuen Server vorher oder nacher passiert, ist das hier überflüssig + if (server != null) + { + server.LastSeen = DateTime.UtcNow; + + await _context.SaveChangesAsync(); + return Ok(); + + } + else + { + return BadRequest(); + } + + } +} diff --git a/Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs b/Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs new file mode 100644 index 0000000..acd59d2 --- /dev/null +++ b/Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs @@ -0,0 +1,293 @@ +// +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("20250615102649_ServerAnpassung")] + partial class ServerAnpassung + { + /// + 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("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Hostname") + .IsRequired() + .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("Status") + .IsRequired() + .HasColumnType("longtext"); + + 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/20250615102649_ServerAnpassung.cs b/Watcher/Migrations/20250615102649_ServerAnpassung.cs new file mode 100644 index 0000000..c8e9931 --- /dev/null +++ b/Watcher/Migrations/20250615102649_ServerAnpassung.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Watcher.Migrations +{ + /// + public partial class ServerAnpassung : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastSeen", + table: "Servers", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastSeen", + table: "Servers"); + } + } +} diff --git a/Watcher/Migrations/AppDbContextModelSnapshot.cs b/Watcher/Migrations/AppDbContextModelSnapshot.cs index f444135..5d75aee 100644 --- a/Watcher/Migrations/AppDbContextModelSnapshot.cs +++ b/Watcher/Migrations/AppDbContextModelSnapshot.cs @@ -159,6 +159,9 @@ namespace Watcher.Migrations b.Property("IsOnline") .HasColumnType("tinyint(1)"); + b.Property("LastSeen") + .HasColumnType("datetime(6)"); + b.Property("Name") .IsRequired() .HasColumnType("longtext"); diff --git a/Watcher/Models/Server.cs b/Watcher/Models/Server.cs index ac10a8d..de454a7 100644 --- a/Watcher/Models/Server.cs +++ b/Watcher/Models/Server.cs @@ -18,4 +18,6 @@ public class Server public string Type { get; set; } = "VPS"; public Boolean IsOnline { get; set; } = false; + + public DateTime LastSeen { get; set; } } diff --git a/Watcher/Views/Server/overview.cshtml b/Watcher/Views/Server/overview.cshtml index 5b42554..bc39a41 100644 --- a/Watcher/Views/Server/overview.cshtml +++ b/Watcher/Views/Server/overview.cshtml @@ -5,7 +5,7 @@

Serverübersicht

- + + Server hinzufügen
diff --git a/Watcher/Views/Shared/_Layout.cshtml b/Watcher/Views/Shared/_Layout.cshtml index 1911a3f..945167a 100644 --- a/Watcher/Views/Shared/_Layout.cshtml +++ b/Watcher/Views/Shared/_Layout.cshtml @@ -68,10 +68,10 @@ Uptime diff --git a/Watcher/appsettings.json b/Watcher/appsettings.json index c59c356..81748ed 100644 --- a/Watcher/appsettings.json +++ b/Watcher/appsettings.json @@ -7,7 +7,7 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DefaultConnection": "server=192.168.178.68;port=3306;database=watcher;user=monitoringuser;password=ssp123;" + "DefaultConnection": "server=100.64.0.5;port=3306;database=watcher;user=monitoringuser;password=ssp123;" }, "Authentication": { "PocketID": {