Browse Source

Added reports

Tim Jones 2 months ago
parent
commit
7a64878897

+ 32 - 0
RackPeek.Domain/Resources/Hardware/Reports/AccessPointHardwareReport.cs

@@ -0,0 +1,32 @@
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace RackPeek.Domain.Resources.Hardware.Reports;
+public record AccessPointHardwareReport(
+    IReadOnlyList<AccessPointHardwareRow> AccessPoints
+);
+
+public record AccessPointHardwareRow(
+    string Name,
+    string Model,
+    int SpeedGb
+);
+
+public class AccessPointHardwareReportUseCase(IHardwareRepository repository)
+{
+    public async Task<AccessPointHardwareReport> ExecuteAsync()
+    {
+        var hardware = await repository.GetAllAsync();
+        var aps = hardware.OfType<AccessPoint>();
+
+        var rows = aps.Select(ap =>
+        {
+            return new AccessPointHardwareRow(
+                Name: ap.Name,
+                Model: ap.Model ?? "Unknown",
+                SpeedGb: ap.Speed ?? 0
+            );
+        }).ToList();
+
+        return new AccessPointHardwareReport(rows);
+    }
+}

+ 85 - 0
RackPeek.Domain/Resources/Hardware/Reports/DesktopHardwareReport.cs

@@ -0,0 +1,85 @@
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace RackPeek.Domain.Resources.Hardware.Reports;
+public record DesktopHardwareReport(
+    IReadOnlyList<DesktopHardwareRow> Desktops
+);
+
+public record DesktopHardwareRow(
+    string Name,
+    string CpuSummary,
+    int TotalCores,
+    int TotalThreads,
+    int RamGb,
+    int TotalStorageGb,
+    int SsdStorageGb,
+    int HddStorageGb,
+    string NicSummary,
+    string GpuSummary
+);
+
+public class DesktopHardwareReportUseCase(IHardwareRepository repository)
+{
+    public async Task<DesktopHardwareReport> ExecuteAsync()
+    {
+        var hardware = await repository.GetAllAsync();
+        var desktops = hardware.OfType<Desktop>();
+
+        var rows = desktops.Select(desktop =>
+        {
+            var totalCores = desktop.Cpus?.Sum(c => c.Cores) ?? 0;
+            var totalThreads = desktop.Cpus?.Sum(c => c.Threads) ?? 0;
+
+            var cpuSummary = desktop.Cpus == null
+                ? "Unknown"
+                : string.Join(", ",
+                    desktop.Cpus
+                        .GroupBy(c => c.Model)
+                        .Select(g => $"{g.Count()}× {g.Key}"));
+
+            var ramGb = desktop.Ram?.Size ?? 0;
+
+            var totalStorage = desktop.Drives?.Sum(d => d.Size) ?? 0;
+            var ssdStorage = desktop.Drives?
+                .Where(d => d.Type == "ssd")
+                .Sum(d => d.Size) ?? 0;
+            var hddStorage = desktop.Drives?
+                .Where(d => d.Type == "hdd")
+                .Sum(d => d.Size) ?? 0;
+
+            var nicSummary = desktop.Nics == null
+                ? "Unknown"
+                : string.Join(", ",
+                    desktop.Nics
+                        .GroupBy(n => n.Speed ?? 0)
+                        .OrderBy(g => g.Key)
+                        .Select(g =>
+                        {
+                            var count = g.Sum(n => n.Ports ?? 0);
+                            return $"{count}×{g.Key}G";
+                        }));
+
+            var gpuSummary = desktop.Gpus == null
+                ? "None"
+                : string.Join(", ",
+                    desktop.Gpus
+                        .GroupBy(g => g.Model)
+                        .Select(g => $"{g.Count()}× {g.Key}"));
+
+            return new DesktopHardwareRow(
+                Name: desktop.Name,
+                CpuSummary: cpuSummary,
+                TotalCores: totalCores,
+                TotalThreads: totalThreads,
+                RamGb: ramGb,
+                TotalStorageGb: totalStorage,
+                SsdStorageGb: ssdStorage,
+                HddStorageGb: hddStorage,
+                NicSummary: nicSummary,
+                GpuSummary: gpuSummary
+            );
+        }).ToList();
+
+        return new DesktopHardwareReport(rows);
+    }
+}

+ 56 - 0
RackPeek.Domain/Resources/Hardware/Reports/FirewallHardwareReport.cs

@@ -0,0 +1,56 @@
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace RackPeek.Domain.Resources.Hardware.Reports;
+public record FirewallHardwareReport(
+    IReadOnlyList<FirewallHardwareRow> Firewalls
+);
+
+public record FirewallHardwareRow(
+    string Name,
+    string Model,
+    bool Managed,
+    bool Poe,
+    int TotalPorts,
+    int MaxPortSpeedGb,
+    string PortSummary
+);
+public class FirewallHardwareReportUseCase(IHardwareRepository repository)
+{
+    public async Task<FirewallHardwareReport> ExecuteAsync()
+    {
+        var hardware = await repository.GetAllAsync();
+        var firewalls = hardware.OfType<Firewall>();
+
+        var rows = firewalls.Select(sw =>
+        {
+            var totalPorts = sw.Ports?.Sum(p => p.Count ?? 0) ?? 0;
+
+            var maxSpeed = sw.Ports?
+                .Max(p => p.Speed ?? 0) ?? 0;
+
+            var portSummary = sw.Ports == null
+                ? "Unknown"
+                : string.Join(", ",
+                    sw.Ports
+                        .GroupBy(p => p.Speed ?? 0)
+                        .OrderBy(g => g.Key)
+                        .Select(g =>
+                        {
+                            var count = g.Sum(p => p.Count ?? 0);
+                            return $"{count}×{g.Key}G";
+                        }));
+
+            return new FirewallHardwareRow(
+                Name: sw.Name,
+                Model: sw.Model ?? "Unknown",
+                Managed: sw.Managed ?? false,
+                Poe: sw.Poe ?? false,
+                TotalPorts: totalPorts,
+                MaxPortSpeedGb: maxSpeed,
+                PortSummary: portSummary
+            );
+        }).ToList();
+
+        return new FirewallHardwareReport(rows);
+    }
+}

+ 56 - 0
RackPeek.Domain/Resources/Hardware/Reports/SwitchHardwareReport.cs

@@ -0,0 +1,56 @@
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace RackPeek.Domain.Resources.Hardware.Reports;
+public record SwitchHardwareReport(
+    IReadOnlyList<SwitchHardwareRow> Switches
+);
+
+public record SwitchHardwareRow(
+    string Name,
+    string Model,
+    bool Managed,
+    bool Poe,
+    int TotalPorts,
+    int MaxPortSpeedGb,
+    string PortSummary
+);
+public class SwitchHardwareReportUseCase(IHardwareRepository repository)
+{
+    public async Task<SwitchHardwareReport> ExecuteAsync()
+    {
+        var hardware = await repository.GetAllAsync();
+        var switches = hardware.OfType<Switch>();
+
+        var rows = switches.Select(sw =>
+        {
+            var totalPorts = sw.Ports?.Sum(p => p.Count ?? 0) ?? 0;
+
+            var maxSpeed = sw.Ports?
+                .Max(p => p.Speed ?? 0) ?? 0;
+
+            var portSummary = sw.Ports == null
+                ? "Unknown"
+                : string.Join(", ",
+                    sw.Ports
+                        .GroupBy(p => p.Speed ?? 0)
+                        .OrderBy(g => g.Key)
+                        .Select(g =>
+                        {
+                            var count = g.Sum(p => p.Count ?? 0);
+                            return $"{count}×{g.Key}G";
+                        }));
+
+            return new SwitchHardwareRow(
+                Name: sw.Name,
+                Model: sw.Model ?? "Unknown",
+                Managed: sw.Managed ?? false,
+                Poe: sw.Poe ?? false,
+                TotalPorts: totalPorts,
+                MaxPortSpeedGb: maxSpeed,
+                PortSummary: portSummary
+            );
+        }).ToList();
+
+        return new SwitchHardwareReport(rows);
+    }
+}

+ 32 - 0
RackPeek.Domain/Resources/Hardware/Reports/UpsHardwareReport.cs

@@ -0,0 +1,32 @@
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace RackPeek.Domain.Resources.Hardware.Reports;
+public record UpsHardwareReport(
+    IReadOnlyList<UpsHardwareRow> UpsUnits
+);
+
+public record UpsHardwareRow(
+    string Name,
+    string Model,
+    int Va
+);
+
+public class UpsHardwareReportUseCase(IHardwareRepository repository)
+{
+    public async Task<UpsHardwareReport> ExecuteAsync()
+    {
+        var hardware = await repository.GetAllAsync();
+        var upsUnits = hardware.OfType<Ups>();
+
+        var rows = upsUnits.Select(ups =>
+        {
+            return new UpsHardwareRow(
+                Name: ups.Name,
+                Model: ups.Model ?? "Unknown",
+                Va: ups.Va ?? 0
+            );
+        }).ToList();
+
+        return new UpsHardwareReport(rows);
+    }
+}

+ 45 - 0
RackPeek/Commands/AccessPointReportCommand.cs

@@ -0,0 +1,45 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using RackPeek.Domain.Resources.Hardware.Reports;
+using Spectre.Console;
+using Spectre.Console.Cli;
+
+namespace RackPeek;
+
+public class AccessPointReportCommand(
+    ILogger<AccessPointReportCommand> logger,
+    IServiceProvider serviceProvider
+) : AsyncCommand
+{
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
+    {
+        using var scope = serviceProvider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<AccessPointHardwareReportUseCase>();
+
+        var report = await useCase.ExecuteAsync();
+
+        if (report.AccessPoints.Count == 0)
+        {
+            AnsiConsole.MarkupLine("[yellow]No access points found.[/]");
+            return 0;
+        }
+
+        var table = new Table()
+            .Border(TableBorder.Rounded)
+            .AddColumn("Name")
+            .AddColumn("Model")
+            .AddColumn("Speed (Gb)");
+
+        foreach (var ap in report.AccessPoints)
+        {
+            table.AddRow(
+                ap.Name,
+                ap.Model,
+                $"{ap.SpeedGb}G"
+            );
+        }
+
+        AnsiConsole.Write(table);
+        return 0;
+    }
+}

+ 53 - 0
RackPeek/Commands/DesktopReportCommand.cs

@@ -0,0 +1,53 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using RackPeek.Domain.Resources.Hardware.Reports;
+using Spectre.Console;
+using Spectre.Console.Cli;
+
+namespace RackPeek;
+
+public class DesktopReportCommand(
+    ILogger<DesktopReportCommand> logger,
+    IServiceProvider serviceProvider
+) : AsyncCommand
+{
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
+    {
+        using var scope = serviceProvider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<DesktopHardwareReportUseCase>();
+
+        var report = await useCase.ExecuteAsync();
+
+        if (report.Desktops.Count == 0)
+        {
+            AnsiConsole.MarkupLine("[yellow]No desktops found.[/]");
+            return 0;
+        }
+
+        var table = new Table()
+            .Border(TableBorder.Rounded)
+            .AddColumn("Name")
+            .AddColumn("CPU")
+            .AddColumn("C/T")
+            .AddColumn("RAM")
+            .AddColumn("Storage")
+            .AddColumn("NICs")
+            .AddColumn("GPU");
+
+        foreach (var d in report.Desktops)
+        {
+            table.AddRow(
+                d.Name,
+                d.CpuSummary,
+                $"{d.TotalCores}/{d.TotalThreads}",
+                $"{d.RamGb} GB",
+                $"{d.TotalStorageGb} GB (SSD {d.SsdStorageGb} / HDD {d.HddStorageGb})",
+                d.NicSummary,
+                d.GpuSummary
+            );
+        }
+
+        AnsiConsole.Write(table);
+        return 0;
+    }
+}

+ 53 - 0
RackPeek/Commands/SwitchReportCommand.cs

@@ -0,0 +1,53 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using RackPeek.Domain.Resources.Hardware.Reports;
+using Spectre.Console;
+using Spectre.Console.Cli;
+
+namespace RackPeek;
+
+public class SwitchReportCommand(
+    ILogger<SwitchReportCommand> logger,
+    IServiceProvider serviceProvider
+) : AsyncCommand
+{
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
+    {
+        using var scope = serviceProvider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<SwitchHardwareReportUseCase>();
+
+        var report = await useCase.ExecuteAsync();
+
+        if (report.Switches.Count == 0)
+        {
+            AnsiConsole.MarkupLine("[yellow]No switches found.[/]");
+            return 0;
+        }
+
+        var table = new Table()
+            .Border(TableBorder.Rounded)
+            .AddColumn("Name")
+            .AddColumn("Model")
+            .AddColumn("Managed")
+            .AddColumn("PoE")
+            .AddColumn("Ports")
+            .AddColumn("Max Speed")
+            .AddColumn("Port Summary");
+
+        foreach (var s in report.Switches)
+        {
+            table.AddRow(
+                s.Name,
+                s.Model,
+                s.Managed ? "[green]yes[/]" : "[red]no[/]",
+                s.Poe ? "[green]yes[/]" : "[red]no[/]",
+                s.TotalPorts.ToString(),
+                $"{s.MaxPortSpeedGb}G",
+                s.PortSummary
+            );
+        }
+
+        AnsiConsole.Write(table);
+        return 0;
+    }
+}

+ 45 - 0
RackPeek/Commands/UpsReportCommand.cs

@@ -0,0 +1,45 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using RackPeek.Domain.Resources.Hardware.Reports;
+using Spectre.Console;
+using Spectre.Console.Cli;
+
+namespace RackPeek;
+
+public class UpsReportCommand(
+    ILogger<UpsReportCommand> logger,
+    IServiceProvider serviceProvider
+) : AsyncCommand
+{
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
+    {
+        using var scope = serviceProvider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<UpsHardwareReportUseCase>();
+
+        var report = await useCase.ExecuteAsync();
+
+        if (report.UpsUnits.Count == 0)
+        {
+            AnsiConsole.MarkupLine("[yellow]No UPS units found.[/]");
+            return 0;
+        }
+
+        var table = new Table()
+            .Border(TableBorder.Rounded)
+            .AddColumn("Name")
+            .AddColumn("Model")
+            .AddColumn("VA");
+
+        foreach (var u in report.UpsUnits)
+        {
+            table.AddRow(
+                u.Name,
+                u.Model,
+                u.Va.ToString()
+            );
+        }
+
+        AnsiConsole.Write(table);
+        return 0;
+    }
+}

+ 30 - 2
RackPeek/Program.cs

@@ -26,14 +26,30 @@ public static class Program
         // Application
         services.AddScoped<ServerHardwareReportUseCase>();
         services.AddScoped<ServerReportCommand>();
+        services.AddScoped<AccessPointHardwareReportUseCase>();
+        services.AddScoped<AccessPointReportCommand>();
+        services.AddScoped<SwitchHardwareReportUseCase>();
+        services.AddScoped<SwitchReportCommand>();
+        services.AddScoped<UpsHardwareReportUseCase>();
+        services.AddScoped<UpsReportCommand>();
+        services.AddScoped<DesktopHardwareReportUseCase>();
+        services.AddScoped<DesktopReportCommand>();
 
         // Infrastructure
         services.AddScoped<IHardwareRepository>(_ =>
         {
             var path = configuration["HardwareFile"] ?? "hardware.yaml";
-
+            
             var collection = new YamlResourceCollection();
-            collection.Load([File.ReadAllText(path)]);
+            collection.Load([
+                File.ReadAllText("servers.yaml"),
+                File.ReadAllText("aps.yaml"),
+                File.ReadAllText("desktops.yaml"),
+                File.ReadAllText("switches.yaml"),
+                File.ReadAllText("ups.yaml"),
+                File.ReadAllText("firewalls.yaml"),
+                File.ReadAllText("laptops.yaml"),
+                File.ReadAllText("routers.yaml")]);
 
             return new YamlHardwareRepository(collection);
         });
@@ -54,6 +70,18 @@ public static class Program
             config.AddCommand<ServerReportCommand>("servers")
                 .WithDescription("Show server hardware report");
 
+            config.AddCommand<AccessPointReportCommand>("ap")
+                .WithDescription("Show access point hardware report");
+            
+            config.AddCommand<DesktopReportCommand>("desktops")
+                .WithDescription("Show desktop hardware report");
+            
+            config.AddCommand<SwitchReportCommand>("switches")
+                .WithDescription("Show switch hardware report");
+            
+            config.AddCommand<UpsReportCommand>("ups")
+                .WithDescription("Show ups hardware report");
+            
             config.ValidateExamples();
         });
 

+ 5 - 0
RackPeek/aps.yaml

@@ -0,0 +1,5 @@
+resources:
+  - kind: AccessPoint
+    name: lounge-ap
+    model: Unifi-Ap-Pro
+    speed: 1gb

+ 20 - 0
RackPeek/desktops.yaml

@@ -0,0 +1,20 @@
+resources:
+  - kind: Desktop
+    name: dell-optiplex
+    cpus:
+      - model: Intel(R) Core(TM) i5-9500
+        cores: 6
+        threads: 6
+    ram:
+      size: 16gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 512gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 1
+    gpus:
+      - model: RTX 3080
+        vram: 12gb

+ 13 - 0
RackPeek/firewalls.yaml

@@ -0,0 +1,13 @@
+resources:
+  - kind: Firewall
+    name: pfsense
+    model: pfSense-1100
+    ports:
+      - type: rj45
+        speed: 1gb
+        count: 8
+      - type: sfp
+        speed: 10gb
+        count: 2
+    managed: true
+    poe: true

+ 16 - 0
RackPeek/laptops.yaml

@@ -0,0 +1,16 @@
+resources:
+  - kind: Laptop
+    name: thinkpad-x1
+    cpus:
+      - model: Intel(R) Core(TM) i7-10510U
+        cores: 4
+        threads: 8
+    ram:
+      size: 16gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 1tb
+    gpus:
+      - model: RTX 3080
+        vram: 12gb

+ 13 - 0
RackPeek/routers.yaml

@@ -0,0 +1,13 @@
+resources:
+  - kind: Router
+    name: ubiquiti-edge-router
+    model: ER-4
+    ports:
+      - type: rj45
+        speed: 1gb
+        count: 8
+      - type: sfp
+        speed: 10gb
+        count: 2
+    managed: true
+    poe: true

+ 0 - 0
RackPeek/hardware.yaml → RackPeek/servers.yaml


+ 13 - 0
RackPeek/switches.yaml

@@ -0,0 +1,13 @@
+resources:
+  - kind: Switch
+    name: netgear-s24
+    model: GS324
+    ports:
+      - type: rj45
+        speed: 1gb
+        count: 8
+      - type: sfp
+        speed: 10gb
+        count: 2
+    managed: true
+    poe: true

+ 5 - 0
RackPeek/ups.yaml

@@ -0,0 +1,5 @@
+resources:
+  - kind: Ups
+    name: rack-ups
+    model: Volta
+    va: 2200