Merge pull request 'feature/Monitoring-Dashboard' (#7) from feature/Monitoring-Dashboard into development
Reviewed-on: daniel-hbn/Watcher#7
This commit is contained in:
25
Dockerfile
25
Dockerfile
@@ -1,22 +1,25 @@
|
|||||||
# Build-Stage
|
# 1. Build-Phase: SDK-Image
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Projektdateien kopieren und Abhängigkeiten wiederherstellen
|
# Projektdateien kopieren und Abhängigkeiten wiederherstellen
|
||||||
COPY *.csproj ./
|
COPY *.sln .
|
||||||
|
COPY Watcher/*.csproj ./Watcher/
|
||||||
RUN dotnet restore
|
RUN dotnet restore
|
||||||
|
|
||||||
# Restlichen Code kopieren und veröffentlichen
|
# Restliche Dateien kopieren und Build ausführen
|
||||||
COPY . ./
|
COPY Watcher/. ./Watcher/
|
||||||
RUN dotnet publish -c Release -o out
|
WORKDIR /app/Watcher
|
||||||
|
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
# Runtime-Stage
|
# 2. Laufzeit-Phase: ASP.NET Core Runtime
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
COPY --from=build /app/out ./
|
# Exponiere Port 80 und 443 (HTTP + HTTPS)
|
||||||
|
EXPOSE 80
|
||||||
EXPOSE 5000
|
EXPOSE 443
|
||||||
EXPOSE 5001
|
|
||||||
|
|
||||||
|
# Anwendung starten
|
||||||
ENTRYPOINT ["dotnet", "Watcher.dll"]
|
ENTRYPOINT ["dotnet", "Watcher.dll"]
|
||||||
|
60
Watcher/Controllers/ContainerController.cs
Normal file
60
Watcher/Controllers/ContainerController.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Watcher.Data;
|
||||||
|
using Watcher.Models;
|
||||||
|
using Watcher.ViewModels;
|
||||||
|
|
||||||
|
namespace Watcher.Controllers;
|
||||||
|
|
||||||
|
|
||||||
|
public class ContainerController : Controller
|
||||||
|
{
|
||||||
|
private readonly AppDbContext _context;
|
||||||
|
|
||||||
|
public ContainerController(AppDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Overview()
|
||||||
|
{
|
||||||
|
var containers = await _context.Containers.ToListAsync();
|
||||||
|
|
||||||
|
var viewModel = new ContainerOverviewViewModel
|
||||||
|
{
|
||||||
|
Containers = containers
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult AddContainer()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> AddContainer(AddContainerViewModel vm)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return View(vm);
|
||||||
|
|
||||||
|
var container = new Container
|
||||||
|
{
|
||||||
|
Name = vm.Name,
|
||||||
|
Image = vm.Image,
|
||||||
|
Status = vm.Status,
|
||||||
|
Hostname = vm.Hostname,
|
||||||
|
IsRunning = vm.IsRunning,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Containers.Add(container);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
|
}
|
43
Watcher/Controllers/HeartbeatController.cs
Normal file
43
Watcher/Controllers/HeartbeatController.cs
Normal file
@@ -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<IActionResult> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,33 +1,41 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Watcher.Data;
|
||||||
using Watcher.Models;
|
using Watcher.Models;
|
||||||
|
using Watcher.ViewModels;
|
||||||
|
|
||||||
namespace Watcher.Controllers;
|
namespace Watcher.Controllers
|
||||||
|
{
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class HomeController : Controller
|
public class HomeController : Controller
|
||||||
{
|
{
|
||||||
private readonly ILogger<HomeController> _logger;
|
private readonly AppDbContext _context;
|
||||||
|
|
||||||
public HomeController(ILogger<HomeController> logger)
|
public HomeController(AppDbContext context)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Index()
|
public async Task<IActionResult> Index()
|
||||||
{
|
{
|
||||||
return View();
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
}
|
|
||||||
|
|
||||||
public IActionResult Privacy()
|
var user = await _context.Users
|
||||||
{
|
.Where(u => u.PocketId == userId)
|
||||||
return View();
|
.FirstOrDefaultAsync();
|
||||||
}
|
|
||||||
|
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
var viewModel = new DashboardViewModel
|
||||||
public IActionResult Error()
|
|
||||||
{
|
{
|
||||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
ActiveServers = await _context.Servers.CountAsync(s => s.IsOnline),
|
||||||
|
OfflineServers = await _context.Servers.CountAsync(s => !s.IsOnline),
|
||||||
|
RunningContainers = await _context.Containers.CountAsync(c => c.IsRunning),
|
||||||
|
FailedContainers = await _context.Containers.CountAsync(c => !c.IsRunning),
|
||||||
|
LastLogin = user?.LastLogin ?? DateTime.MinValue
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
Watcher/Controllers/ServerController.cs
Normal file
106
Watcher/Controllers/ServerController.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Watcher.Data;
|
||||||
|
using Watcher.Models;
|
||||||
|
using Watcher.ViewModels;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public class ServerController : Controller
|
||||||
|
{
|
||||||
|
private readonly AppDbContext _context;
|
||||||
|
|
||||||
|
public ServerController(AppDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Overview()
|
||||||
|
{
|
||||||
|
var vm = new ServerOverviewViewModel
|
||||||
|
{
|
||||||
|
Servers = await _context.Servers.OrderBy(s => s.Id).ToListAsync()
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult AddServer()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> AddServer(AddServerViewModel vm)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return View(vm);
|
||||||
|
|
||||||
|
var server = new Server
|
||||||
|
{
|
||||||
|
Name = vm.Name,
|
||||||
|
IPAddress = vm.IPAddress,
|
||||||
|
Type = vm.Type,
|
||||||
|
IsOnline = vm.IsOnline,
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Servers.Add(server);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RedirectToAction("Overview");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Delete(int id)
|
||||||
|
{
|
||||||
|
var server = await _context.Servers.FindAsync(id);
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Servers.Remove(server);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return RedirectToAction(nameof(Overview));
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: Server/Edit/5
|
||||||
|
public async Task<IActionResult> EditServer(int id)
|
||||||
|
{
|
||||||
|
var server = await _context.Servers.FindAsync(id);
|
||||||
|
if (server == null) return NotFound();
|
||||||
|
|
||||||
|
var vm = new EditServerViewModel
|
||||||
|
{
|
||||||
|
Name = server.Name,
|
||||||
|
IPAddress = server.IPAddress,
|
||||||
|
Type = server.Type
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: Server/Edit/5
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> EditServer(int id, EditServerViewModel vm)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var server = await _context.Servers.FindAsync(id);
|
||||||
|
if (server == null) return NotFound();
|
||||||
|
|
||||||
|
server.Name = vm.Name;
|
||||||
|
server.IPAddress = vm.IPAddress;
|
||||||
|
server.Type = vm.Type;
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return RedirectToAction(nameof(Overview));
|
||||||
|
}
|
||||||
|
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
284
Watcher/Migrations/20250614183243_Server-Container-IsRunning-Value.Designer.cs
generated
Normal file
284
Watcher/Migrations/20250614183243_Server-Container-IsRunning-Value.Designer.cs
generated
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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("20250614183243_Server-Container-IsRunning-Value")]
|
||||||
|
partial class ServerContainerIsRunningValue
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRunning")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Containers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Tag")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Level")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("LogEvents");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("double");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("Metrics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOnline")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Tags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLogin")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PocketId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PreferredUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
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.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Watcher.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ServerContainerIsRunningValue : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsOnline",
|
||||||
|
table: "Servers",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsRunning",
|
||||||
|
table: "Containers",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsOnline",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsRunning",
|
||||||
|
table: "Containers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
290
Watcher/Migrations/20250614224113_Container-Server-Update.Designer.cs
generated
Normal file
290
Watcher/Migrations/20250614224113_Container-Server-Update.Designer.cs
generated
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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("20250614224113_Container-Server-Update")]
|
||||||
|
partial class ContainerServerUpdate
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRunning")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Containers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Tag")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Level")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("LogEvents");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("double");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("Metrics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IPAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOnline")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Tags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLogin")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PocketId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
Watcher/Migrations/20250614224113_Container-Server-Update.cs
Normal file
29
Watcher/Migrations/20250614224113_Container-Server-Update.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Watcher.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ContainerServerUpdate : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "IPAddress",
|
||||||
|
table: "Servers",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IPAddress",
|
||||||
|
table: "Servers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
293
Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs
generated
Normal file
293
Watcher/Migrations/20250615102649_ServerAnpassung.Designer.cs
generated
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRunning")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Containers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Tag")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Level")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("LogEvents");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("double");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("Metrics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IPAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOnline")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeen")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Tags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLogin")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PocketId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Watcher/Migrations/20250615102649_ServerAnpassung.cs
Normal file
30
Watcher/Migrations/20250615102649_ServerAnpassung.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Watcher.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ServerAnpassung : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastSeen",
|
||||||
|
table: "Servers",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastSeen",
|
||||||
|
table: "Servers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
288
Watcher/Migrations/20250615114821_ServerCleanUp.Designer.cs
generated
Normal file
288
Watcher/Migrations/20250615114821_ServerCleanUp.Designer.cs
generated
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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("20250615114821_ServerCleanUp")]
|
||||||
|
partial class ServerCleanUp
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Hostname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRunning")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Containers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Tag")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Level")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("LogEvents");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ContainerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("double");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ContainerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("Metrics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IPAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOnline")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeen")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("TagId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Tags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLogin")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PocketId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Watcher/Migrations/20250615114821_ServerCleanUp.cs
Normal file
51
Watcher/Migrations/20250615114821_ServerCleanUp.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Watcher.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ServerCleanUp : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Hostname",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Status",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Description",
|
||||||
|
table: "Servers",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Description",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Hostname",
|
||||||
|
table: "Servers",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Status",
|
||||||
|
table: "Servers",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -35,6 +35,9 @@ namespace Watcher.Migrations
|
|||||||
b.Property<int?>("ImageId")
|
b.Property<int?>("ImageId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRunning")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
@@ -145,18 +148,23 @@ namespace Watcher.Migrations
|
|||||||
b.Property<DateTime>("CreatedAt")
|
b.Property<DateTime>("CreatedAt")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<string>("Hostname")
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IPAddress")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOnline")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeen")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<int?>("TagId")
|
b.Property<int?>("TagId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
@@ -212,13 +220,15 @@ namespace Watcher.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Watcher.Models.Image", null)
|
b.HasOne("Watcher.Models.Image", "Image")
|
||||||
.WithMany("Containers")
|
.WithMany("Containers")
|
||||||
.HasForeignKey("ImageId");
|
.HasForeignKey("ImageId");
|
||||||
|
|
||||||
b.HasOne("Watcher.Models.Tag", null)
|
b.HasOne("Watcher.Models.Tag", null)
|
||||||
.WithMany("Containers")
|
.WithMany("Containers")
|
||||||
.HasForeignKey("TagId");
|
.HasForeignKey("TagId");
|
||||||
|
|
||||||
|
b.Navigation("Image");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||||
|
@@ -8,9 +8,13 @@ public class Container
|
|||||||
|
|
||||||
public string Status { get; set; } = string.Empty;
|
public string Status { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public Image? Image { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
public string Hostname { get; set; } = string.Empty;
|
public string Hostname { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Type { get; set; } = "docker"; // z.B. "docker", "vm", "lxc", etc.
|
public string Type { get; set; } = "docker"; // z.B. "docker", "vm", "lxc", etc.
|
||||||
|
|
||||||
|
public Boolean IsRunning { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
@@ -6,12 +6,18 @@ public class Server
|
|||||||
|
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Status { get; set; } = string.Empty;
|
public string IPAddress { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
public string Hostname { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
// z.B. "VPS", "standalone", "VM", etc.
|
// z.B. "VPS", "standalone", "VM", etc.
|
||||||
public string Type { get; set; } = "VPS";
|
public string Type { get; set; } = "VPS";
|
||||||
|
|
||||||
|
public Boolean IsOnline { get; set; } = false;
|
||||||
|
|
||||||
|
public DateTime LastSeen { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
13
Watcher/ViewModels/AddContainerViewModel.cs
Normal file
13
Watcher/ViewModels/AddContainerViewModel.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Watcher.Models;
|
||||||
|
|
||||||
|
namespace Watcher.ViewModels;
|
||||||
|
public class AddContainerViewModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public Image? Image { get; set; }
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
public string Hostname { get; set; } = string.Empty;
|
||||||
|
public string IPAddress { get; set; } = string.Empty;
|
||||||
|
public string ServerName { get; set; } = string.Empty; // oder ID, je nach Relation
|
||||||
|
public bool IsRunning { get; set; } = false;
|
||||||
|
}
|
12
Watcher/ViewModels/AddServerViewModel.cs
Normal file
12
Watcher/ViewModels/AddServerViewModel.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
namespace Watcher.ViewModels;
|
||||||
|
|
||||||
|
public class AddServerViewModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string IPAddress { get; set; } = string.Empty;
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
public string Hostname { get; set; } = string.Empty;
|
||||||
|
public string Type { get; set; } = "VPS";
|
||||||
|
public bool IsOnline { get; set; } = false;
|
||||||
|
}
|
10
Watcher/ViewModels/ContainerOverviewViewModel.cs
Normal file
10
Watcher/ViewModels/ContainerOverviewViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Watcher.Models;
|
||||||
|
|
||||||
|
namespace Watcher.ViewModels
|
||||||
|
{
|
||||||
|
public class ContainerOverviewViewModel
|
||||||
|
{
|
||||||
|
public List<Container> Containers { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
Watcher/ViewModels/DashboardViewModel.cs
Normal file
11
Watcher/ViewModels/DashboardViewModel.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Watcher.ViewModels
|
||||||
|
{
|
||||||
|
public class DashboardViewModel
|
||||||
|
{
|
||||||
|
public int ActiveServers { get; set; }
|
||||||
|
public int OfflineServers { get; set; }
|
||||||
|
public int RunningContainers { get; set; }
|
||||||
|
public int FailedContainers { get; set; }
|
||||||
|
public DateTime LastLogin { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
Watcher/ViewModels/EditServerViewModel.cs
Normal file
10
Watcher/ViewModels/EditServerViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Watcher.ViewModels;
|
||||||
|
|
||||||
|
public class EditServerViewModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string IPAddress { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string Type { get; set; } = "VPS";
|
||||||
|
}
|
10
Watcher/ViewModels/ServerOverviewViewModel.cs
Normal file
10
Watcher/ViewModels/ServerOverviewViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Watcher.Models;
|
||||||
|
|
||||||
|
namespace Watcher.ViewModels
|
||||||
|
|
||||||
|
{
|
||||||
|
public class ServerOverviewViewModel
|
||||||
|
{
|
||||||
|
public List<Server> Servers { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
22
Watcher/Views/Container/AddContainer.cshtml
Normal file
22
Watcher/Views/Container/AddContainer.cshtml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@model Watcher.ViewModels.AddContainerViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Neuen Container hinzufügen";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Neuen Container hinzufügen</h1>
|
||||||
|
|
||||||
|
<form asp-action="Add" method="post" class="space-y-4 max-w-xl">
|
||||||
|
<div>
|
||||||
|
<label asp-for="Name" class="block font-medium">Name</label>
|
||||||
|
<input asp-for="Name" class="w-full border rounded px-3 py-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label asp-for="Image" class="block font-medium">Image</label>
|
||||||
|
<input asp-for="Image" class="w-full border rounded px-3 py-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label asp-for="ServerName" class="block font-medium">Server</label>
|
||||||
|
<input asp-for="ServerName" class="w-full border rounded px-3 py-2" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Speichern</button>
|
||||||
|
</form>
|
36
Watcher/Views/Container/Overview.cshtml
Normal file
36
Watcher/Views/Container/Overview.cshtml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
@model Watcher.ViewModels.ContainerOverviewViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Containerübersicht";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h1 class="text-3xl font-bold">Containerübersicht</h1>
|
||||||
|
<a asp-action="AddContainer" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||||
|
+ Container hinzufügen
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
@foreach (var container in Model.Containers)
|
||||||
|
{
|
||||||
|
<div class="bg-white shadow-md rounded-xl p-5 border border-gray-200 hover:shadow-lg transition duration-200">
|
||||||
|
<h2 class="text-xl font-semibold mb-1">@container.Name</h2>
|
||||||
|
<p class="text-sm text-gray-600 mb-2"><strong>Image:</strong> @container.Image</p>
|
||||||
|
<p class="text-sm text-gray-600"><strong>Hostname:</strong> @container.Hostname</p>
|
||||||
|
<p class="text-sm text-gray-600"><strong>Status:</strong> @container.Status</p>
|
||||||
|
<p class="text-sm text-gray-600 mb-3">
|
||||||
|
<strong>Läuft:</strong>
|
||||||
|
<span class="@(container.IsRunning ? "text-green-600" : "text-red-600")">
|
||||||
|
@(container.IsRunning ? "Ja" : "Nein")
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<a asp-action="Edit" asp-route-id="@container.Id"
|
||||||
|
class="text-blue-600 hover:underline text-sm">Bearbeiten</a>
|
||||||
|
<a asp-action="Delete" asp-route-id="@container.Id"
|
||||||
|
class="text-red-600 hover:underline text-sm">Löschen</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
@@ -1,6 +1,36 @@
|
|||||||
@{
|
@model Watcher.ViewModels.DashboardViewModel
|
||||||
|
@{
|
||||||
ViewData["Title"] = "Dashboard";
|
ViewData["Title"] = "Dashboard";
|
||||||
}
|
}
|
||||||
|
|
||||||
<h1>Dashboard</h1>
|
<h1 class="text-2xl font-bold mb-4">Dashboard</h1>
|
||||||
<p>Willkommen im Watcher Monitoring Interface!</p>
|
|
||||||
|
<div class="grid grid-cols-2 gap-6">
|
||||||
|
<div class="bg-white shadow rounded-2xl p-4">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">Server</h2>
|
||||||
|
<p>🟢 Online: <strong>@Model.ActiveServers</strong></p>
|
||||||
|
<p>🔴 Offline: <strong>@Model.OfflineServers</strong></p>
|
||||||
|
<a href="/Server/Overview" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Servern</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white shadow rounded-2xl p-4">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">Container</h2>
|
||||||
|
<p>🟢 Laufend: <strong>@Model.RunningContainers</strong></p>
|
||||||
|
<p>🔴 Fehlerhaft: <strong>@Model.FailedContainers</strong></p>
|
||||||
|
<a href="/Container/Overview" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Containern</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-2 bg-white shadow rounded-2xl p-4">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">Uptime letzte 24h</h2>
|
||||||
|
<div class="bg-gray-100 h-32 rounded-lg flex items-center justify-center text-gray-500">
|
||||||
|
(Diagramm folgt hier)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-2 bg-white shadow rounded-2xl p-4">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">Systeminfo</h2>
|
||||||
|
<p>Benutzer: <strong>@User.FindFirst("preferred_username")?.Value</strong></p>
|
||||||
|
<p>Letzter Login: <strong>@Model.LastLogin.ToString("g")</strong></p>
|
||||||
|
<a href="/Auth/Info" class="text-blue-500 hover:underline mt-2 inline-block">→ Account-Verwaltung</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
42
Watcher/Views/Server/AddServer.cshtml
Normal file
42
Watcher/Views/Server/AddServer.cshtml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
@model Watcher.ViewModels.AddServerViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Neuen Server hinzufügen";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="max-w-2xl mx-auto mt-10 bg-white rounded-2xl shadow-md p-8">
|
||||||
|
<h1 class="text-2xl font-bold text-gray-800 mb-6">Neuen Server hinzufügen</h1>
|
||||||
|
|
||||||
|
<form asp-action="AddServer" method="post" class="space-y-5">
|
||||||
|
<div>
|
||||||
|
<label asp-for="Name" class="block text-sm font-medium text-gray-700">Name</label>
|
||||||
|
<input asp-for="Name" class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500" />
|
||||||
|
<span asp-validation-for="Name" class="text-red-500 text-sm" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label asp-for="IPAddress" class="block text-sm font-medium text-gray-700">IP-Adresse</label>
|
||||||
|
<input asp-for="IPAddress" class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500" />
|
||||||
|
<span asp-validation-for="IPAddress" class="text-red-500 text-sm" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label asp-for="Type" class="block text-sm font-medium text-gray-700">Typ</label>
|
||||||
|
<select asp-for="Type" class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||||||
|
<option>VPS</option>
|
||||||
|
<option>VM</option>
|
||||||
|
<option>Standalone</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<a asp-action="Overview" class="mr-3 inline-block px-4 py-2 text-gray-600 hover:text-blue-600">Abbrechen</a>
|
||||||
|
<button type="submit" class="px-5 py-2 bg-blue-600 text-white font-semibold rounded hover:bg-blue-700">
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
31
Watcher/Views/Server/EditServer.cshtml
Normal file
31
Watcher/Views/Server/EditServer.cshtml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
@model Watcher.ViewModels.EditServerViewModel;
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Server bearbeiten";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>Server bearbeiten</h2>
|
||||||
|
|
||||||
|
<form asp-action="EditServer" method="post">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label asp-for="Name"></label>
|
||||||
|
<input asp-for="Name" class="form-control" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label asp-for="IPAddress"></label>
|
||||||
|
<input asp-for="IPAddress" class="form-control" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label asp-for="Type"></label>
|
||||||
|
<input asp-for="Type" class="form-control" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary mt-3">Speichern</button>
|
||||||
|
<a asp-action="Overview" class="btn btn-secondary mt-3">Abbrechen</a>
|
||||||
|
</form>
|
48
Watcher/Views/Server/overview.cshtml
Normal file
48
Watcher/Views/Server/overview.cshtml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
@model Watcher.ViewModels.ServerOverviewViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Serverübersicht";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h1 class="text-2xl font-bold">Serverübersicht</h1>
|
||||||
|
<a asp-controller="Server" asp-action="AddServer"
|
||||||
|
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||||
|
+ Server hinzufügen
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
@foreach (var s in Model.Servers)
|
||||||
|
{
|
||||||
|
<div class="bg-white rounded-xl shadow p-4 border border-gray-200">
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-lg font-semibold">(#@s.Id) @s.Name</h2>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm px-2 py-1 rounded
|
||||||
|
@(s.IsOnline ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700")">
|
||||||
|
@(s.IsOnline ? "Online" : "Offline")
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 text-sm space-y-1 text-gray-700">
|
||||||
|
<div><strong>IP:</strong> @s.IPAddress</div>
|
||||||
|
<div><strong>Typ:</strong> @s.Type</div>
|
||||||
|
<div><strong>Status:</strong> @((s.IsOnline) ? "Online" : "Offline")</div>
|
||||||
|
<div><strong>Erstellt:</strong> @s.CreatedAt.ToLocalTime().ToString("dd.MM.yyyy HH:mm")</div>
|
||||||
|
<div><strong>Last-Seen:</strong> @(s.LastSeen.ToLocalTime().ToString("dd.MM.yyyy HH:mm") ?? "Never")</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex justify-end gap-2">
|
||||||
|
<a asp-action="EditServer" asp-route-id="@s.Id" class="btn btn-sm btn-primary">Bearbeiten</a>
|
||||||
|
|
||||||
|
<form asp-action="Delete" asp-route-id="@s.Id" method="post"
|
||||||
|
onsubmit="return confirm('Diesen Server wirklich löschen?');">
|
||||||
|
<button type="submit" class="text-red-600 hover:text-red-800 font-semibold">Löschen</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
@@ -68,10 +68,10 @@
|
|||||||
<a class="nav-link" href="/Uptime">Uptime</a>
|
<a class="nav-link" href="/Uptime">Uptime</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/Monitoring/Servers">Servers</a>
|
<a class="nav-link" href="/Server/Overview">Servers</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/Container">Container</a>
|
<a class="nav-link" href="/Container/Overview">Container</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,6 +103,9 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
|
@RenderSection("Scripts", required: false)
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"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": {
|
"Authentication": {
|
||||||
"PocketID": {
|
"PocketID": {
|
||||||
|
Reference in New Issue
Block a user