Sfoglia il codice sorgente

Added server report usecase

Tim Jones 5 mesi fa
parent
commit
ad4aa7e0ac

+ 50 - 0
RackPeek/Commands/ServerReportCommand.cs

@@ -0,0 +1,50 @@
+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 ServerReportCommand(ILogger<ServerReportCommand> logger, IServiceProvider serviceProvider)
+    : AsyncCommand
+{
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
+    {
+        using var scope = serviceProvider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<ServerHardwareReportUseCase>();
+
+        var report = await useCase.ExecuteAsync();
+
+        if (report.Servers.Count == 0)
+        {
+            AnsiConsole.MarkupLine("[yellow]No servers found.[/]");
+            return 0;
+        }
+
+        var table = new Table()
+            .Border(TableBorder.Rounded)
+            .AddColumn("Name")
+            .AddColumn("CPU")
+            .AddColumn("C/T")
+            .AddColumn("RAM")
+            .AddColumn("Storage")
+            .AddColumn("NICs")
+            .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.Ipmi ? "[green]yes[/]" : "[red]no[/]"
+            );
+        }
+
+        AnsiConsole.Write(table);
+        return 0;
+    }
+}

+ 105 - 4
RackPeek/Program.cs

@@ -1,9 +1,110 @@
-namespace RackPeek;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using RackPeek.Domain.Resources.Hardware;
+using Spectre.Console;
+using Spectre.Console.Cli;
+using Microsoft.Extensions.Logging;
+using RackPeek.Domain.Resources.Hardware.Reports;
 
-class Program
+namespace RackPeek;
+
+public static class Program
+{
+    public static async Task<int> Main(string[] args)
+    {
+        // Configuration
+        var configuration = new ConfigurationBuilder()
+            .SetBasePath(Directory.GetCurrentDirectory())
+            .AddJsonFile("appsettings.json", optional: true)
+            .Build();
+
+        // DI
+        var services = new ServiceCollection();
+
+        services.AddSingleton<IConfiguration>(configuration);
+
+        // Application
+        services.AddScoped<ServerHardwareReportUseCase>();
+        services.AddScoped<ServerReportCommand>();
+
+        // Infrastructure
+        services.AddScoped<IHardwareRepository>(_ =>
+        {
+            var path = configuration["HardwareFile"] ?? "hardware.yaml";
+
+            var collection = new YamlResourceCollection();
+            collection.Load([File.ReadAllText(path)]);
+
+            return new YamlHardwareRepository(collection);
+        });
+        
+        services.AddLogging(configure =>
+            configure
+                .AddSimpleConsole(opts => { opts.TimestampFormat = "yyyy-MM-dd HH:mm:ss "; }));
+
+
+        // Spectre bootstrap
+        var registrar = new TypeRegistrar(services);
+        var app = new CommandApp(registrar);
+
+        app.Configure(config =>
+        {
+            config.SetApplicationName("rackpeek");
+
+            config.AddCommand<ServerReportCommand>("servers")
+                .WithDescription("Show server hardware report");
+
+            config.ValidateExamples();
+        });
+
+        return await app.RunAsync(args);
+    }
+}
+
+public class SpectreConsoleLoggerProvider : ILoggerProvider
 {
-    static void Main(string[] args)
+    public ILogger CreateLogger(string categoryName)
+    {
+        return new SpectreConsoleLogger();
+    }
+
+    public void Dispose()
+    {
+    }
+}
+
+public class SpectreConsoleLogger : ILogger
+{
+    public IDisposable BeginScope<T>(T state)
+    {
+        return null!;
+    }
+
+    public bool IsEnabled(LogLevel logLevel)
+    {
+        return true;
+    }
+
+    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
+        Func<TState, Exception, string> formatter)
+    {
+        var message = formatter(state, exception);
+        var style = GetStyle(logLevel);
+
+        AnsiConsole.MarkupLine($"[{style}] {message}[/]");
+    }
+
+    private Style GetStyle(LogLevel logLevel)
     {
-        Console.WriteLine("RackPeek");
+        return logLevel switch
+        {
+            LogLevel.Trace => new Style(Color.Grey),
+            LogLevel.Debug => new Style(Color.Grey),
+            LogLevel.Information => new Style(Color.Green),
+            LogLevel.Warning => new Style(Color.Yellow),
+            LogLevel.Error => new Style(Color.Red),
+            LogLevel.Critical => new Style(Color.Red),
+            _ => new Style(Color.White)
+        };
     }
 }

+ 8 - 0
RackPeek/RackPeek.csproj

@@ -8,6 +8,14 @@
     </PropertyGroup>
 
     <ItemGroup>
+      <PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.2" />
+      <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.2" />
+      <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.2" />
+      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
+      <PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
+      <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.2" />
+      <PackageReference Include="Spectre.Console" Version="0.54.0" />
+      <PackageReference Include="Spectre.Console.Cli" Version="0.53.1" />
       <PackageReference Include="YamlDotNet" Version="16.3.0" />
     </ItemGroup>
 

+ 40 - 0
RackPeek/TypeRegistrar.cs

@@ -0,0 +1,40 @@
+using Microsoft.Extensions.DependencyInjection;
+using Spectre.Console.Cli;
+
+namespace RackPeek;
+
+public sealed class TypeRegistrar(IServiceCollection services) : ITypeRegistrar
+{
+    public void Register(Type service, Type implementation)
+    {
+        services.AddSingleton(service, implementation);
+    }
+
+    public void RegisterInstance(Type service, object implementation)
+    {
+        services.AddSingleton(service, implementation);
+    }
+
+    public void RegisterLazy(Type service, Func<object> factory)
+    {
+        services.AddSingleton(service, _ => factory());
+    }
+
+    public ITypeResolver Build()
+    {
+        return new TypeResolver(services.BuildServiceProvider());
+    }
+}
+
+public sealed class TypeResolver(ServiceProvider provider) : ITypeResolver, IDisposable
+{
+    public object? Resolve(Type? type)
+    {
+        return type == null ? null : provider.GetService(type);
+    }
+
+    public void Dispose()
+    {
+        provider.Dispose();
+    }
+}

+ 0 - 4
RackPeek/Converters.cs → RackPeek/Yaml/Converters.cs

@@ -1,12 +1,8 @@
 using YamlDotNet.Core;
 using YamlDotNet.Core.Events;
 using YamlDotNet.Serialization;
-using System;
 using System.Globalization;
 using System.Text.RegularExpressions;
-using YamlDotNet.Core;
-using YamlDotNet.Core.Events;
-using YamlDotNet.Serialization;
 
 namespace RackPeek;
 

+ 0 - 0
RackPeek/YamlHardwareRepository.cs → RackPeek/Yaml/YamlHardwareRepository.cs


+ 0 - 0
RackPeek/YamlResourceCollection.cs → RackPeek/Yaml/YamlResourceCollection.cs


+ 0 - 0
RackPeek/YamlSystemRepository.cs → RackPeek/Yaml/YamlSystemRepository.cs


+ 128 - 0
RackPeek/hardware.yaml

@@ -0,0 +1,128 @@
+resources:
+  - kind: Server
+    name: dell-c6400-node01
+    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-node02
+    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:
+      - model: Intel(R) Xeon(R) E5-2620 v4
+        cores: 8
+        threads: 16
+    ram:
+      size: 64gb
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 8tb
+      - type: hdd
+        size: 8tb
+      - type: hdd
+        size: 8tb
+      - type: hdd
+        size: 8tb
+      - type: ssd
+        size: 120gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 1
+      - type: sfp+
+        speed: 10gb
+        ports: 1
+    ipmi: true
+
+  - kind: Server
+    name: proxmox-edge01
+    cpus:
+      - model: Intel(R) Core(TM) i5-8500
+        cores: 6
+        threads: 6
+    ram:
+      size: 32gb
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 512gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 4
+    ipmi: false
+
+  - kind: Server
+    name: opnsense-fw01
+    cpus:
+      - model: Intel(R) Celeron(R) J4125
+        cores: 4
+        threads: 4
+    ram:
+      size: 8gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 64gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 4
+    ipmi: false
+
+  - kind: Server
+    name: mgmt-bastion01
+    cpus:
+      - model: Intel(R) Xeon(R) E3-1270 v6
+        cores: 4
+        threads: 8
+    ram:
+      size: 16gb
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 256gb
+    nics:
+      - type: rj45
+        speed: 1gb
+        ports: 1
+    ipmi: true
+