Browse Source

Merge pull request #1 from Timmoth/Server-Hardware-GPU

Deserialization test + adding GPU to report
Tim Jones 2 months ago
parent
commit
3fb0547e0a

+ 0 - 1
.idea/.idea.RackPeek/.idea/.name

@@ -1 +0,0 @@
-RackPeek

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Models/AccessPoint.cs

@@ -3,5 +3,5 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 public class AccessPoint : Hardware
 {
     public string? Model { get; set; }
-    public int? Speed { get; set; }
+    public double? Speed { get; set; }
 }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Reports/AccessPointHardwareReport.cs

@@ -8,7 +8,7 @@ public record AccessPointHardwareReport(
 public record AccessPointHardwareRow(
     string Name,
     string Model,
-    int SpeedGb
+    double SpeedGb
 );
 
 public class AccessPointHardwareReportUseCase(IHardwareRepository repository)

+ 20 - 0
RackPeek.Domain/Resources/Hardware/Reports/ServerHardwareReport.cs

@@ -17,7 +17,11 @@ public record ServerHardwareRow(
     int HddStorageGb,
     int TotalNicPorts,
     int MaxNicSpeedGb,
+    int GpuCount,
+    int TotalGpuVramGb,
+    string GpuSummary,
     bool Ipmi
+    
 );
 
 public class ServerHardwareReportUseCase(IHardwareRepository repository)
@@ -51,6 +55,19 @@ public class ServerHardwareReportUseCase(IHardwareRepository repository)
 
             var totalNicPorts = server.Nics?.Sum(n => n.Ports) ?? 0;
             var maxNicSpeed = server.Nics?.Max(n => n.Speed) ?? 0;
+            
+            var gpuCount = server.Gpus?.Count ?? 0;
+
+            var totalGpuVram = server.Gpus?
+                .Sum(g => g.Vram) ?? 0;
+
+            var gpuSummary = server.Gpus == null || server.Gpus.Count == 0
+                ? "None"
+                : string.Join(", ",
+                    server.Gpus
+                        .GroupBy(g => g.Model)
+                        .Select(g => $"{g.Count()}× {g.Key}"));
+
 
             return new ServerHardwareRow(
                 Name: server.Name,
@@ -63,6 +80,9 @@ public class ServerHardwareReportUseCase(IHardwareRepository repository)
                 HddStorageGb: hddStorage,
                 TotalNicPorts: totalNicPorts,
                 MaxNicSpeedGb: maxNicSpeed,
+                GpuCount: gpuCount,
+                TotalGpuVramGb: totalGpuVram,
+                GpuSummary: gpuSummary,
                 Ipmi: server.Ipmi ?? false
             );
         }).ToList();

+ 10 - 6
RackPeek/Commands/ServerReportCommand.cs

@@ -29,17 +29,21 @@ public class ServerReportCommand(ILogger<ServerReportCommand> logger, IServicePr
             .AddColumn("RAM")
             .AddColumn("Storage")
             .AddColumn("NICs")
+            .AddColumn("GPUs")
             .AddColumn("IPMI");
 
         foreach (var s in report.Servers)
         {
             table.AddRow(
-                s.Name,
-                s.CpuSummary,
-                $"{s.TotalCores}/{s.TotalThreads}",
-                $"{s.RamGb} GB",
-                $"{s.TotalStorageGb} GB (SSD {s.SsdStorageGb} / HDD {s.HddStorageGb})",
-                $"{s.TotalNicPorts}×{s.MaxNicSpeedGb}G",
+                    s.Name,
+                    s.CpuSummary,
+                    $"{s.TotalCores}/{s.TotalThreads}",
+                    $"{s.RamGb} GB",
+                    $"{s.TotalStorageGb} GB (SSD {s.SsdStorageGb} / HDD {s.HddStorageGb})",
+                    $"{s.TotalNicPorts}×{s.MaxNicSpeedGb}G",
+                    s.GpuCount == 0
+                        ? "[grey]none[/]"
+                        : $"{s.GpuSummary} ({s.TotalGpuVramGb} GB VRAM)",
                 s.Ipmi ? "[green]yes[/]" : "[red]no[/]"
             );
         }

+ 27 - 21
RackPeek/Yaml/Converters.cs

@@ -1,32 +1,25 @@
+using System.Globalization;
+using System.Text.RegularExpressions;
 using YamlDotNet.Core;
 using YamlDotNet.Core.Events;
 using YamlDotNet.Serialization;
-using System.Globalization;
-using System.Text.RegularExpressions;
 
 namespace RackPeek;
 
 public static class StorageSizeParser
 {
-    private static readonly Regex SizeRegex =
-        new(@"^\s*(\d+(?:\.\d+)?)\s*(gb|tb)?\s*$",
-            RegexOptions.IgnoreCase | RegexOptions.Compiled);
+    private static readonly Regex SizeRegex = new(@"^\s*(\d+(?:\.\d+)?)\s*(gb|tb)?\s*$",
+        RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
-    public static int ParseToGb(string input)
+    public static double ParseToGbDouble(string input)
     {
         var match = SizeRegex.Match(input);
-
-        if (!match.Success)
-            throw new FormatException($"Invalid storage size: '{input}'");
-
+        if (!match.Success) throw new FormatException($"Invalid storage size: '{input}'");
         var value = double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
         var unit = match.Groups[2].Value.ToLowerInvariant();
-
         return unit switch
         {
-            "tb" => (int)Math.Round(value * 1024),
-            "gb" or "" => (int)Math.Round(value),
-            _ => throw new FormatException($"Unknown unit in '{input}'")
+            "tb" => value * 1024, "gb" or "" => value, _ => throw new FormatException($"Unknown unit in '{input}'")
         };
     }
 }
@@ -34,7 +27,10 @@ public static class StorageSizeParser
 public class StorageSizeYamlConverter : IYamlTypeConverter
 {
     public bool Accepts(Type type) =>
-        type == typeof(int) || type == typeof(int?);
+        type == typeof(int) ||
+        type == typeof(int?) ||
+        type == typeof(double) ||
+        type == typeof(double?);
 
     public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
     {
@@ -44,13 +40,23 @@ public class StorageSizeYamlConverter : IYamlTypeConverter
         if (string.IsNullOrWhiteSpace(value))
             return null;
 
-        // If it's already a number, just parse it
-        if (int.TryParse(value, out var numeric))
-            return numeric;
+        // If it's already a number, parse directly
+        if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var numericDouble))
+        {
+            if (type == typeof(double) || type == typeof(double?))
+                return numericDouble;
+
+            if (type == typeof(int) || type == typeof(int?))
+                return (int)numericDouble;
+        }
+
+        // Otherwise parse with size parser
+        var gb = StorageSizeParser.ParseToGbDouble(value);
+
+        if (type == typeof(double) || type == typeof(double?))
+            return gb;
 
-        // Otherwise try size parsing
-        return StorageSizeParser.ParseToGb(value);
-        
+        return (int)Math.Round(gb);
     }
 
     public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)

+ 25 - 1
RackPeek/aps.yaml

@@ -2,4 +2,28 @@ resources:
   - kind: AccessPoint
     name: lounge-ap
     model: Unifi-Ap-Pro
-    speed: 1gb
+    speed: 1gb
+  - kind: AccessPoint
+    name: office-ap
+    model: Unifi-U6-Lite
+    speed: 1gb
+
+  - kind: AccessPoint
+    name: garage-ap
+    model: TP-Link-EAP245
+    speed: 1gb
+
+  - kind: AccessPoint
+    name: upstairs-ap
+    model: Aruba-AP-515
+    speed: 2.5gb
+
+  - kind: AccessPoint
+    name: guest-ap
+    model: Unifi-U6-Mesh
+    speed: 1gb
+
+  - kind: AccessPoint
+    name: warehouse-ap
+    model: Cisco-Aironet-1832i
+    speed: 1gb

+ 252 - 0
RackPeek/servers.yaml

@@ -43,6 +43,50 @@ resources:
         ports: 2
     ipmi: true
 
+  - kind: Server
+    name: dell-c6400-node03
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 64gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 480gb
+      - type: ssd
+        size: 480gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+      - type: sfp+
+        speed: 10gb
+        ports: 2
+    ipmi: true
+
+  - kind: Server
+    name: dell-c6400-node04
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 128gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 960gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+      - type: sfp+
+        speed: 10gb
+        ports: 2
+    ipmi: true
+
   - kind: Server
     name: truenas-storage01
     cpus:
@@ -125,4 +169,212 @@ resources:
         speed: 1gb
         ports: 1
     ipmi: true
+  
+  - kind: Server
+    name: truenas-backup01
+    cpus:
+      - model: Intel(R) Xeon(R) E5-2630 v4
+        cores: 10
+        threads: 20
+    ram:
+      size: 64gb
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 6tb
+      - type: hdd
+        size: 6tb
+      - type: hdd
+        size: 6tb
+      - type: hdd
+        size: 6tb
+      - type: ssd
+        size: 240gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+      - type: sfp+
+        speed: 10gb
+        ports: 1
+    ipmi: true
+
+  - kind: Server
+    name: compute-gpu01
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4214
+        cores: 12
+        threads: 24
+    ram:
+      size: 128gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 1tb
+    gpus:
+      - model: NVIDIA Tesla P40
+        vram: 24gb
+      - model: NVIDIA Tesla P40
+        vram: 24gb  
+      - model: NVIDIA Tesla P4
+        vram: 8Gb  
+    nics:
+      - type: sfp+
+        speed: 10gb
+        ports: 2
+    ipmi: true
+
+  - kind: Server
+    name: proxmox-lab01
+    cpus:
+      - model: Intel(R) Xeon(R) E3-1240 v5
+        cores: 4
+        threads: 8
+    ram:
+      size: 32gb
+      mts: 2133
+    drives:
+      - type: ssd
+        size: 512gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+    ipmi: true
+
+  - kind: Server
+    name: k8s-control01
+    cpus:
+      - model: Intel(R) Xeon(R) E-2224
+        cores: 4
+        threads: 4
+    ram:
+      size: 16gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 256gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+    ipmi: true
+
+  - kind: Server
+    name: k8s-control02
+    cpus:
+      - model: Intel(R) Xeon(R) E-2224
+        cores: 4
+        threads: 4
+    ram:
+      size: 16gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 256gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+    ipmi: true
+
+  - kind: Server
+    name: elk-logging01
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4108
+        cores: 8
+        threads: 16
+    ram:
+      size: 64gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 1tb
+      - type: ssd
+        size: 1tb
+    nics:
+      - type: sfp+
+        speed: 10gb
+        ports: 1
+    ipmi: true
+
+  - kind: Server
+    name: edge-node01
+    cpus:
+      - model: Intel(R) Core(TM) i3-8100
+        cores: 4
+        threads: 4
+    ram:
+      size: 16gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 256gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 2
+    ipmi: false
+
+  - kind: Server
+    name: backup-proxmox01
+    cpus:
+      - model: Intel(R) Xeon(R) E5-1650 v3
+        cores: 6
+        threads: 12
+    ram:
+      size: 64gb
+      mts: 2133
+    drives:
+      - type: ssd
+        size: 480gb
+      - type: hdd
+        size: 4tb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 4
+    ipmi: true
+
+  - kind: Server
+    name: lab-general01
+    cpus:
+      - model: Intel(R) Core(TM) i7-8700
+        cores: 6
+        threads: 12
+    ram:
+      size: 32gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 512gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 1
+    ipmi: false
+
+  - kind: Server
+    name: dell-r730-archive01
+    cpus:
+      - model: Intel(R) Xeon(R) E5-2650 v3
+        cores: 10
+        threads: 20
+    ram:
+      size: 128gb
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 4tb
+      - type: hdd
+        size: 4tb
+      - type: hdd
+        size: 4tb
+      - type: hdd
+        size: 4tb
+    nics:
+      - type: sfp+
+        speed: 10gb
+        ports: 2
+    ipmi: true
 

+ 9 - 0
Tests/Hardware/ServerHardwareReportTests.cs

@@ -29,6 +29,12 @@ public class ServerHardwareReportTests
                 Nics = new()
                 {
                     new Nic { Speed = 10, Ports = 2 }
+                },
+                Gpus = new()
+                {
+                    new Gpu { Model = "NVIDIA Tesla T4", Vram = 16 },
+                    new Gpu { Model = "NVIDIA Tesla T4", Vram = 16 },
+                    new Gpu { Model = "RTX 3080", Vram = 10 }
                 }
             }
         ]);
@@ -41,6 +47,9 @@ public class ServerHardwareReportTests
         Assert.Equal(2304, server.TotalStorageGb);
         Assert.Equal(4, server.TotalCores);
         Assert.Equal(10, server.MaxNicSpeedGb);
+        Assert.Equal(3, server.GpuCount);
+        Assert.Equal(42, server.TotalGpuVramGb);
+        Assert.Equal("2× NVIDIA Tesla T4, 1× RTX 3080", server.GpuSummary);
     }
 
 }

+ 11 - 2
Tests/Yaml/HardwareDeserializationTests.cs

@@ -60,6 +60,9 @@ resources:
           size: 2Tb
         - type: ssd
           size: 256gb
+    gpus:
+        - model: NVIDIA Tesla T4
+          vram: 16gb
     nics:
         - type: rj45
           speed: 1gb
@@ -101,6 +104,12 @@ resources:
         var ssd = server.Drives[1];
         Assert.Equal("ssd", ssd.Type);
         Assert.Equal(256, ssd.Size);
+        
+        //GPUs
+        Assert.NotNull(server.Gpus);
+        var gpu = server.Gpus[0];
+        Assert.Equal("NVIDIA Tesla T4", gpu.Model);
+        Assert.Equal(16, gpu.Vram);
 
         // ipmi
         Assert.True(server.Ipmi);
@@ -394,7 +403,7 @@ resources:
   - kind: AccessPoint
     name: lounge-ap
     model: Unifi-Ap-Pro
-    speed: 1gb
+    speed: 2.5Gb
 ";
 
         var sut = CreateSut(yaml);
@@ -412,7 +421,7 @@ resources:
 
         Assert.Equal("lounge-ap", accessPoint.Name);
         Assert.Equal("Unifi-Ap-Pro", accessPoint.Model);
-        Assert.Equal(1, accessPoint.Speed);
+        Assert.Equal(2.5, accessPoint.Speed);
 
     }