Просмотр исходного кода

Added basic server / tree view to webui

Tim Jones 2 месяцев назад
Родитель
Сommit
9448db2bbe

+ 14 - 0
RackPeek.Domain/Resources/Hardware/IHardwareRepository.cs

@@ -7,4 +7,18 @@ public interface IHardwareRepository
     Task UpdateAsync(Models.Hardware hardware);
     Task DeleteAsync(string name);
     Task<Models.Hardware?> GetByNameAsync(string name);
+    public Task<List<HardwareTree>> GetTreeAsync();
+}
+
+public class HardwareTree
+{
+    public required string HardwareName { get; set; }
+    public required string Kind { get; set; }
+    public required List<SystemTree> Systems {get; set;}
+}
+
+public class SystemTree
+{
+    public required string SystemName { get; set; }
+    public required List<string> Services {get; set;}
 }

BIN
RackPeek.Web/.DS_Store


+ 2 - 1
RackPeek.Web/Components/App.razor

@@ -8,9 +8,10 @@
     <ResourcePreloader/>
     <ImportMap/>
     <HeadOutlet @rendermode="InteractiveServer"/>
+    <script src="tailwind.js"></script>
 </head>
 
-<body>
+<body class="bg-black">
 <Routes @rendermode="InteractiveServer"/>
 <ReconnectModal/>
 <script src="@Assets["_framework/blazor.web.js"]"></script>

+ 83 - 0
RackPeek.Web/Components/Components/HardwareTreeComponent.razor

@@ -0,0 +1,83 @@
+@page "/tree"
+@using RackPeek.Domain.Resources.Hardware
+@inject IHardwareRepository HardwareRepository
+
+<PageTitle>Tree View</PageTitle>
+
+<div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6">
+    <h1 class="text-lg text-zinc-100 mb-6">
+        Tree View
+    </h1>
+
+    @if (_tree is null)
+    {
+        <div class="text-zinc-500">loading tree…</div>
+    }
+    else if (_tree.Count == 0)
+    {
+        <div class="text-zinc-500">no resources found</div>
+    }
+    else
+    {
+        @foreach (var group in _tree
+            .OrderBy(h => h.Kind)
+            .ThenBy(h => h.HardwareName)
+            .GroupBy(h => h.Kind))
+        {
+            <!-- Hardware Kind Header -->
+            <div class="mb-6">
+                <div class="text-xs text-zinc-500 uppercase tracking-wider mb-3">
+                    @group.Key
+                </div>
+
+                <ul class="space-y-4">
+                    @foreach (var hardware in group)
+                    {
+                        <li>
+                            <!-- Hardware -->
+                            <div class="text-zinc-100">
+                                @hardware.HardwareName
+                            </div>
+
+                            @if (hardware.Systems.Any())
+                            {
+                                <ul class="ml-4 mt-2 border-l border-zinc-800 pl-4 space-y-2">
+                                    @foreach (var system in hardware.Systems.OrderBy(s => s.SystemName))
+                                    {
+                                        <li>
+                                            <!-- System -->
+                                            <div class="text-zinc-300">
+                                                └─ @system.SystemName
+                                            </div>
+
+                                            @if (system.Services.Any())
+                                            {
+                                                <ul class="ml-4 mt-1 space-y-1">
+                                                    @foreach (var service in system.Services.OrderBy(s => s))
+                                                    {
+                                                        <li class="text-zinc-500">
+                                                            > @service
+                                                        </li>
+                                                    }
+                                                </ul>
+                                            }
+                                        </li>
+                                    }
+                                </ul>
+                            }
+                        </li>
+                    }
+                </ul>
+            </div>
+        }
+    }
+</div>
+
+@code {
+    private List<HardwareTree>? _tree;
+
+    protected override async Task OnInitializedAsync()
+    {
+        _tree = await HardwareRepository.GetTreeAsync();
+    }
+}

+ 115 - 0
RackPeek.Web/Components/Components/ServersListComponent.razor

@@ -0,0 +1,115 @@
+@using RackPeek.Domain.Resources.Hardware.Models
+@using RackPeek.Domain.Resources.Hardware.Servers
+@inject GetServersUseCase GetServers
+
+<PageTitle>CLI Monitor</PageTitle>
+
+<div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6">
+    <h1 class="text-lg text-zinc-100 mb-6">
+        CLI Hardware Monitor
+    </h1>
+
+    @if (_servers is null)
+    {
+        <div class="text-zinc-500">loading servers…</div>
+    }
+    else if (_servers.Count == 0)
+    {
+        <div class="text-zinc-500">no servers found</div>
+    }
+    else
+    {
+        <div class="space-y-4">
+            @foreach (var server in _servers)
+            {
+                <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
+                    <div class="flex justify-between items-center mb-3">
+                        <div class="text-zinc-100">
+                            @server.Name
+                        </div>
+
+                        @if (server.Ipmi == true)
+                        {
+                            <span class="text-xs text-emerald-400">IPMI</span>
+                        }
+                    </div>
+
+                    <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
+
+                        @if (server.Cpus?.Any() == true)
+                        {
+                            <div>
+                                <div class="text-zinc-400 mb-1">CPU</div>
+                                @foreach (var cpu in server.Cpus)
+                                {
+                                    <div class="text-zinc-300">
+                                        @cpu.Model — @cpu.Cores cores / @cpu.Threads threads
+                                    </div>
+                                }
+                            </div>
+                        }
+
+                        @if (server.Ram is not null)
+                        {
+                            <div>
+                                <div class="text-zinc-400 mb-1">RAM</div>
+                                <div class="text-zinc-300">
+                                    @server.Ram.Size GB @server.Ram.Mts MT/s
+                                </div>
+                            </div>
+                        }
+
+                        @if (server.Drives?.Any() == true)
+                        {
+                            <div>
+                                <div class="text-zinc-400 mb-1">Drives</div>
+                                @foreach (var drive in server.Drives)
+                                {
+                                    <div class="text-zinc-300">
+                                        @drive.Type — @drive.Size GB
+                                    </div>
+                                }
+                            </div>
+                        }
+
+                        @if (server.Nics?.Any() == true)
+                        {
+                            <div>
+                                <div class="text-zinc-400 mb-1">NICs</div>
+                                @foreach (var nic in server.Nics)
+                                {
+                                    <div class="text-zinc-300">
+                                        @nic.Type — @nic.Speed Gbps (@nic.Ports ports)
+                                    </div>
+                                }
+                            </div>
+                        }
+
+                        @if (server.Gpus?.Any() == true)
+                        {
+                            <div>
+                                <div class="text-zinc-400 mb-1">GPU</div>
+                                @foreach (var gpu in server.Gpus)
+                                {
+                                    <div class="text-zinc-300">
+                                        @gpu.Model — @gpu.Vram GB VRAM
+                                    </div>
+                                }
+                            </div>
+                        }
+
+                    </div>
+                </div>
+            }
+        </div>
+    }
+</div>
+
+@code {
+    private IReadOnlyList<Server>? _servers;
+
+    protected override async Task OnInitializedAsync()
+    {
+        _servers = await GetServers.ExecuteAsync();
+    }
+}

+ 3 - 2
RackPeek.Web/Components/Pages/Home.razor

@@ -1,5 +1,6 @@
 @page "/"
+@using RackPeek.Web.Components.Components
 
-<PageTitle>Home</PageTitle>
+<PageTitle>CLI Monitor</PageTitle>
 
-Hello, World!
+<ServersListComponent/>

+ 35 - 0
RackPeek.Web/Program.cs

@@ -1,5 +1,10 @@
 using Microsoft.AspNetCore.Hosting.StaticWebAssets;
+using RackPeek.Domain;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Services;
+using RackPeek.Domain.Resources.SystemResources;
 using RackPeek.Web.Components;
+using RackPeek.Yaml;
 
 namespace RackPeek.Web;
 
@@ -13,7 +18,37 @@ public class Program
             builder.Environment,
             builder.Configuration
         );
+
+        var yamlDir = "./config";
+        
+        var collection = new YamlResourceCollection();
+        var basePath = Directory.GetCurrentDirectory();
+
+        // Resolve yamlDir as relative to basePath
+        var yamlPath = Path.IsPathRooted(yamlDir)
+            ? yamlDir
+            : Path.Combine(basePath, yamlDir);
+
+        if (!Directory.Exists(yamlPath))
+            throw new DirectoryNotFoundException(
+                $"YAML directory not found: {yamlPath}"
+            );
+
+        // Load all .yml and .yaml files
+        var yamlFiles = Directory.EnumerateFiles(yamlPath, "*.yml")
+            .Concat(Directory.EnumerateFiles(yamlPath, "*.yaml"))
+            .ToArray();
         
+        collection.LoadFiles(yamlFiles.Select(f => Path.Combine(basePath, f)));
+
+        // Infrastructure
+        builder.Services.AddScoped<IHardwareRepository>(_ => new YamlHardwareRepository(collection));
+        builder.Services.AddScoped<ISystemRepository>(_ => new YamlSystemRepository(collection));
+        builder.Services.AddScoped<IServiceRepository>(_ => new YamlServiceRepository(collection));
+
+        
+        builder.Services.AddUseCases();
+
         // Add services to the container.
         builder.Services.AddRazorComponents()
             .AddInteractiveServerComponents();

+ 4 - 0
RackPeek.Web/RackPeek.Web.csproj

@@ -7,4 +7,8 @@
         <BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
     </PropertyGroup>
 
+    <ItemGroup>
+      <ProjectReference Include="..\RackPeek\RackPeek.csproj" />
+    </ItemGroup>
+
 </Project>

+ 585 - 0
RackPeek.Web/config/Services.yaml

@@ -0,0 +1,585 @@
+resources:
+  - kind: Service
+    name: immich
+    network:
+      ip: 192.168.0.4
+      port: 8080
+      protocol: TCP
+      url: http://immich.lan:8080
+    runsOn: proxmox-host
+
+  - kind: Service
+    name: jellyfin
+    network:
+      ip: 192.168.0.10
+      port: 8096
+      protocol: TCP
+      url: http://jellyfin.lan:8096
+    runsOn: docker-host
+
+  - kind: Service
+    name: plex
+    network:
+      ip: 192.168.0.11
+      port: 32400
+      protocol: TCP
+      url: http://plex.lan:32400
+    runsOn: proxmox-host
+
+  - kind: Service
+    name: home-assistant
+    network:
+      ip: 192.168.1.20
+      port: 8123
+      protocol: TCP
+      url: http://ha.lan:8123
+    runsOn: k8s-node-1
+
+  - kind: Service
+    name: pihole
+    network:
+      ip: 192.168.1.2
+      port: 53
+      protocol: UDP
+      url: http://pihole.lan/admin
+    runsOn: baremetal-rpi4
+
+  - kind: Service
+    name: unifi-controller
+    network:
+      ip: 192.168.1.5
+      port: 8443
+      protocol: TCP
+      url: https://unifi.lan:8443
+    runsOn: vm-cluster-1
+
+  - kind: Service
+    name: syncthing
+    network:
+      ip: 10.0.0.15
+      port: 8384
+      protocol: TCP
+      url: http://sync.internal:8384
+    runsOn: docker-host
+
+  - kind: Service
+    name: grafana
+    network:
+      ip: 10.0.0.20
+      port: 3000
+      protocol: TCP
+      url: http://grafana.internal:3000
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: prometheus
+    network:
+      ip: 10.0.0.21
+      port: 9090
+      protocol: TCP
+      url: http://prometheus.internal:9090
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: loki
+    network:
+      ip: 10.0.0.22
+      port: 3100
+      protocol: TCP
+      url: http://loki.internal:3100
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: minio
+    network:
+      ip: 172.16.0.10
+      port: 9000
+      protocol: TCP
+      url: http://minio.storage:9000
+    runsOn: storage-node-1
+
+  - kind: Service
+    name: nextcloud
+    network:
+      ip: 172.16.0.11
+      port: 443
+      protocol: TCP
+      url: https://nextcloud.storage
+    runsOn: storage-node-2
+
+  - kind: Service
+    name: vaultwarden
+    network:
+      ip: 192.168.0.30
+      port: 8081
+      protocol: TCP
+      url: http://vault.lan:8081
+    runsOn: docker-host
+
+  - kind: Service
+    name: traefik
+    network:
+      ip: 192.168.0.2
+      port: 80
+      protocol: TCP
+      url: http://traefik.lan
+    runsOn: k8s-node-1
+
+  - kind: Service
+    name: nginx-reverse-proxy
+    network:
+      ip: 192.168.0.3
+      port: 443
+      protocol: TCP
+      url: https://proxy.lan
+    runsOn: docker-host
+
+  - kind: Service
+    name: qbittorrent
+    network:
+      ip: 192.168.0.40
+      port: 8080
+      protocol: TCP
+      url: http://torrent.lan:8080
+    runsOn: proxmox-host
+
+  - kind: Service
+    name: radarr
+    network:
+      ip: 192.168.0.41
+      port: 7878
+      protocol: TCP
+      url: http://radarr.lan:7878
+    runsOn: docker-host
+
+  - kind: Service
+    name: sonarr
+    network:
+      ip: 192.168.0.42
+      port: 8989
+      protocol: TCP
+      url: http://sonarr.lan:8989
+    runsOn: docker-host
+
+  - kind: Service
+    name: prowlarr
+    network:
+      ip: 192.168.0.43
+      port: 9696
+      protocol: TCP
+      url: http://prowlarr.lan:9696
+    runsOn: docker-host
+
+  - kind: Service
+    name: sabnzbd
+    network:
+      ip: 192.168.0.44
+      port: 8085
+      protocol: TCP
+      url: http://sabnzbd.lan:8085
+    runsOn: docker-host
+
+  - kind: Service
+    name: frigate
+    network:
+      ip: 192.168.1.30
+      port: 5000
+      protocol: TCP
+      url: http://frigate.lan:5000
+    runsOn: k8s-node-2
+
+  - kind: Service
+    name: mosquitto-mqtt
+    network:
+      ip: 192.168.1.31
+      port: 1883
+      protocol: TCP
+      url: mqtt://mqtt.lan:1883
+    runsOn: docker-host
+
+  - kind: Service
+    name: zigbee2mqtt
+    network:
+      ip: 192.168.1.32
+      port: 8080
+      protocol: TCP
+      url: http://z2m.lan:8080
+    runsOn: docker-host
+
+  - kind: Service
+    name: postgres-main
+    network:
+      ip: 10.0.1.10
+      port: 5432
+      protocol: TCP
+      url: postgres://db.internal:5432
+    runsOn: db-node-1
+
+  - kind: Service
+    name: mariadb
+    network:
+      ip: 10.0.1.11
+      port: 3306
+      protocol: TCP
+      url: mysql://mariadb.internal:3306
+    runsOn: db-node-2
+
+  - kind: Service
+    name: redis-cache
+    network:
+      ip: 10.0.1.12
+      port: 6379
+      protocol: TCP
+      url: redis://redis.internal:6379
+    runsOn: cache-node
+
+  - kind: Service
+    name: elasticsearch
+    network:
+      ip: 10.0.2.10
+      port: 9200
+      protocol: TCP
+      url: http://es.internal:9200
+    runsOn: search-node
+
+  - kind: Service
+    name: kibana
+    network:
+      ip: 10.0.2.11
+      port: 5601
+      protocol: TCP
+      url: http://kibana.internal:5601
+    runsOn: search-node
+
+  - kind: Service
+    name: uptime-kuma
+    network:
+      ip: 192.168.0.50
+      port: 3001
+      protocol: TCP
+      url: http://uptime.lan:3001
+    runsOn: docker-host
+
+  - kind: Service
+    name: wireguard-vpn
+    network:
+      ip: 192.168.1.100
+      port: 51820
+      protocol: UDP
+      url: wg://vpn.lan
+    runsOn: baremetal-rpi4
+
+  - kind: Service
+    name: openvpn
+    network:
+      ip: 192.168.1.101
+      port: 1194
+      protocol: UDP
+      url: ovpn://openvpn.lan
+    runsOn: vm-cluster-2
+
+  - kind: Service
+    name: adguard-home
+    network:
+      ip: 192.168.1.3
+      port: 3000
+      protocol: TCP
+      url: http://adguard.lan:3000
+    runsOn: docker-host
+
+  - kind: Service
+    name: gitlab
+    network:
+      ip: 10.0.3.10
+      port: 443
+      protocol: TCP
+      url: https://gitlab.internal
+    runsOn: dev-node-1
+
+  - kind: Service
+    name: gitea
+    network:
+      ip: 10.0.3.11
+      port: 3000
+      protocol: TCP
+      url: http://gitea.internal:3000
+    runsOn: dev-node-2
+
+  - kind: Service
+    name: drone-ci
+    network:
+      ip: 10.0.3.12
+      port: 8080
+      protocol: TCP
+      url: http://drone.internal:8080
+    runsOn: dev-node-2
+
+  - kind: Service
+    name: harbor-registry
+    network:
+      ip: 10.0.3.13
+      port: 5000
+      protocol: TCP
+      url: http://harbor.internal:5000
+    runsOn: dev-node-3
+
+  - kind: Service
+    name: kubernetes-api
+    network:
+      ip: 10.0.4.1
+      port: 6443
+      protocol: TCP
+      url: https://k8s-api.internal:6443
+    runsOn: k8s-control-plane
+
+  - kind: Service
+    name: longhorn-ui
+    network:
+      ip: 10.0.4.20
+      port: 9500
+      protocol: TCP
+      url: http://longhorn.internal:9500
+    runsOn: k8s-node-3
+
+  - kind: Service
+    name: rook-ceph-dashboard
+    network:
+      ip: 10.0.4.21
+      port: 8443
+      protocol: TCP
+      url: https://ceph.internal:8443
+    runsOn: k8s-node-3
+
+  - kind: Service
+    name: samba-fileserver
+    network:
+      ip: 192.168.0.60
+      port: 445
+      protocol: TCP
+      url: smb://fileserver.lan
+    runsOn: storage-node-1
+
+  - kind: Service
+    name: nfs-server
+    network:
+      ip: 192.168.0.61
+      port: 2049
+      protocol: TCP
+      url: nfs://nfs.lan
+    runsOn: dell-c6400-node01
+
+  - kind: Service
+    name: iscsi-target
+    network:
+      ip: 172.16.1.10
+      port: 3260
+      protocol: TCP
+      url: iscsi://iscsi.storage
+    runsOn: storage-node-3
+
+  - kind: Service
+    name: calibre-web
+    network:
+      ip: 192.168.0.70
+      port: 8083
+      protocol: TCP
+      url: http://books.lan:8083
+    runsOn: docker-host
+
+  - kind: Service
+    name: paperless-ngx
+    network:
+      ip: 192.168.0.71
+      port: 8000
+      protocol: TCP
+      url: http://docs.lan:8000
+    runsOn: dell-c6400-node01
+
+  - kind: Service
+    name: openldap
+    network:
+      ip: 10.0.5.10
+      port: 389
+      protocol: TCP
+      url: ldap://ldap.internal:389
+    runsOn: dell-c6400-node01
+
+  - kind: Service
+    name: keycloak
+    network:
+      ip: 10.0.5.11
+      port: 8080
+      protocol: TCP
+      url: http://keycloak.internal:8080
+    runsOn: dell-c6400-node01
+
+  - kind: Service
+    name: ntp-server
+    network:
+      ip: 192.168.1.50
+      port: 123
+      protocol: UDP
+      url: ntp://ntp.lan
+    runsOn: baremetal-rpi3
+
+  - kind: Service
+    name: syslog-server
+    network:
+      ip: 10.0.6.10
+      port: 514
+      protocol: UDP
+      url: syslog://syslog.internal
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: dhcp-server
+    network:
+      ip: 192.168.1.1
+      port: 67
+      protocol: UDP
+      url: dhcp://dhcp.lan
+    runsOn: router-appliance
+
+  - kind: Service
+    name: bind-dns
+    network:
+      ip: 10.0.7.10
+      port: 53
+      protocol: UDP
+      url: dns://dns.internal
+    runsOn: infra-node
+
+  - kind: Service
+    name: vault
+    network:
+      ip: 10.0.7.11
+      port: 8200
+      protocol: TCP
+      url: http://vault.internal:8200
+    runsOn: infra-node
+
+  - kind: Service
+    name: consul
+    network:
+      ip: 10.0.7.12
+      port: 8500
+      protocol: TCP
+      url: http://consul.internal:8500
+    runsOn: infra-node
+
+  - kind: Service
+    name: nomad
+    network:
+      ip: 10.0.7.13
+      port: 4646
+      protocol: TCP
+      url: http://nomad.internal:4646
+    runsOn: infra-node
+
+  - kind: Service
+    name: openhab
+    network:
+      ip: 192.168.1.40
+      port: 8080
+      protocol: TCP
+      url: http://openhab.lan:8080
+    runsOn: k8s-node-2
+
+  - kind: Service
+    name: mqtt-explorer
+    network:
+      ip: 192.168.1.41
+      port: 4000
+      protocol: TCP
+      url: http://mqtt-explorer.lan:4000
+    runsOn: docker-host
+
+  - kind: Service
+    name: influxdb
+    network:
+      ip: 10.0.8.10
+      port: 8086
+      protocol: TCP
+      url: http://influx.internal:8086
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: telegraf
+    network:
+      ip: 10.0.8.11
+      port: 8125
+      protocol: UDP
+      url: statsd://telegraf.internal
+    runsOn: monitoring-node
+
+  - kind: Service
+    name: speedtest-tracker
+    network:
+      ip: 192.168.0.80
+      port: 8080
+      protocol: TCP
+      url: http://speedtest.lan:8080
+    runsOn: docker-host
+
+  - kind: Service
+    name: navidrome
+    network:
+      ip: 192.168.0.81
+      port: 4533
+      protocol: TCP
+      url: http://music.lan:4533
+    runsOn: docker-host
+
+  - kind: Service
+    name: photoprism
+    network:
+      ip: 192.168.0.82
+      port: 2342
+      protocol: TCP
+      url: http://photos.lan:2342
+    runsOn: docker-host
+
+  - kind: Service
+    name: dnsdist
+    network:
+      ip: 10.0.9.10
+      port: 53
+      protocol: UDP
+      url: dns://dnsdist.internal
+    runsOn: infra-node
+
+  - kind: Service
+    name: powerdns
+    network:
+      ip: 10.0.9.11
+      port: 8081
+      protocol: TCP
+      url: http://pdns.internal:8081
+    runsOn: infra-node
+
+  - kind: Service
+    name: openproject
+    network:
+      ip: 10.0.10.10
+      port: 8080
+      protocol: TCP
+      url: http://openproject.internal:8080
+    runsOn: dev-node-3
+
+  - kind: Service
+    name: mattermost
+    network:
+      ip: 10.0.10.11
+      port: 8065
+      protocol: TCP
+      url: http://chat.internal:8065
+    runsOn: dev-node-3
+
+  - kind: Service
+    name: rocket-chat
+    network:
+      ip: 10.0.10.12
+      port: 3000
+      protocol: TCP
+      url: http://rocket.internal:3000
+    runsOn: dev-node-3

+ 184 - 0
RackPeek.Web/config/Systems.yaml

@@ -0,0 +1,184 @@
+resources:
+  - kind: System
+    type: Hypervisor
+    name: proxmox-host
+    os: proxmox
+    cores: 16
+    ram: 64gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: ContainerHost
+    name: docker-host
+    os: ubuntu
+    cores: 12
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: KubernetesNode
+    name: k8s-node-1
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: KubernetesNode
+    name: k8s-node-2
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: KubernetesNode
+    name: k8s-node-3
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: KubernetesControlPlane
+    name: k8s-control-plane
+    os: ubuntu
+    cores: 4
+    ram: 16gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Monitoring
+    name: monitoring-node
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Storage
+    name: storage-node-1
+    os: truenas
+    cores: 8
+    ram: 64gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Storage
+    name: storage-node-2
+    os: truenas
+    cores: 8
+    ram: 64gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Storage
+    name: storage-node-3
+    os: truenas
+    cores: 8
+    ram: 64gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Database
+    name: db-node-1
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Database
+    name: db-node-2
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Cache
+    name: cache-node
+    os: ubuntu
+    cores: 4
+    ram: 16gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Search
+    name: search-node
+    os: ubuntu
+    cores: 8
+    ram: 32gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Development
+    name: dev-node-1
+    os: ubuntu
+    cores: 4
+    ram: 16gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Development
+    name: dev-node-2
+    os: ubuntu
+    cores: 4
+    ram: 16gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: Development
+    name: dev-node-3
+    os: ubuntu
+    cores: 6
+    ram: 24gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: VirtualMachineCluster
+    name: vm-cluster-1
+    os: proxmox
+    cores: 12
+    ram: 48gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: VirtualMachineCluster
+    name: vm-cluster-2
+    os: proxmox
+    cores: 12
+    ram: 48gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: BareMetal
+    name: baremetal-rpi4
+    os: raspbian
+    cores: 4
+    ram: 8gb
+    runsOn: rack-edge
+
+  - kind: System
+    type: BareMetal
+    name: baremetal-rpi3
+    os: raspbian
+    cores: 4
+    ram: 4gb
+    runsOn: rack-edge
+
+  - kind: System
+    type: Infrastructure
+    name: infra-node
+    os: ubuntu
+    cores: 4
+    ram: 16gb
+    runsOn: dell-c6400-node01
+
+  - kind: System
+    type: NetworkAppliance
+    name: router-appliance
+    os: openwrt
+    cores: 2
+    ram: 2gb
+    runsOn: network-rack

+ 31 - 0
RackPeek.Web/config/accesspoints.yaml

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

+ 21 - 0
RackPeek.Web/config/desktops.yaml

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

+ 14 - 0
RackPeek.Web/config/firewalls.yaml

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

+ 17 - 0
RackPeek.Web/config/laptops.yaml

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

+ 14 - 0
RackPeek.Web/config/routers.yaml

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

+ 397 - 0
RackPeek.Web/config/servers.yaml

@@ -0,0 +1,397 @@
+resources:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 64
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 480
+      - type: ssd
+        size: 480
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+    ipmi: true
+    name: dell-c6400-node01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 128
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 960
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+    ipmi: true
+    name: dell-c6400-node02
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 64
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 480
+      - type: ssd
+        size: 480
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+    ipmi: true
+    name: dell-c6400-node03
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4110
+        cores: 8
+        threads: 16
+    ram:
+      size: 128
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 960
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+    ipmi: true
+    name: dell-c6400-node04
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E5-2620 v4
+        cores: 8
+        threads: 16
+    ram:
+      size: 64
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 8192
+      - type: hdd
+        size: 8192
+      - type: hdd
+        size: 8192
+      - type: hdd
+        size: 8192
+      - type: ssd
+        size: 120
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 1
+      - type: sfp+
+        speed: 10
+        ports: 1
+    gpus:
+    ipmi: true
+    name: truenas-storage01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Core(TM) i5-8500
+        cores: 6
+        threads: 6
+    ram:
+      size: 32
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 512
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 4
+    gpus:
+    ipmi: false
+    name: proxmox-edge01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Celeron(R) J4125
+        cores: 4
+        threads: 4
+    ram:
+      size: 8
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 64
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 4
+    gpus:
+    ipmi: false
+    name: opnsense-fw01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E3-1270 v6
+        cores: 4
+        threads: 8
+    ram:
+      size: 16
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 256
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 1
+    gpus:
+    ipmi: true
+    name: mgmt-bastion01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E5-2630 v4
+        cores: 10
+        threads: 20
+    ram:
+      size: 64
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 6144
+      - type: hdd
+        size: 6144
+      - type: hdd
+        size: 6144
+      - type: hdd
+        size: 6144
+      - type: ssd
+        size: 240
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+      - type: sfp+
+        speed: 10
+        ports: 1
+    gpus:
+    ipmi: true
+    name: truenas-backup01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4214
+        cores: 12
+        threads: 24
+    ram:
+      size: 128
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 1024
+    nics:
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+      - model: NVIDIA Tesla P40
+        vram: 24
+      - model: NVIDIA Tesla P40
+        vram: 24
+      - model: NVIDIA Tesla P4
+        vram: 8
+    ipmi: true
+    name: compute-gpu01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E3-1240 v5
+        cores: 4
+        threads: 8
+    ram:
+      size: 32
+      mts: 2133
+    drives:
+      - type: ssd
+        size: 512
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+    gpus:
+    ipmi: true
+    name: proxmox-lab01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E-2224
+        cores: 4
+        threads: 4
+    ram:
+      size: 16
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 256
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+    gpus:
+    ipmi: true
+    name: k8s-control01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E-2224
+        cores: 4
+        threads: 4
+    ram:
+      size: 16
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 256
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+    gpus:
+    ipmi: true
+    name: k8s-control02
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) Silver 4108
+        cores: 8
+        threads: 16
+    ram:
+      size: 64
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 1024
+      - type: ssd
+        size: 1024
+    nics:
+      - type: sfp+
+        speed: 10
+        ports: 1
+    gpus:
+    ipmi: true
+    name: elk-logging01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Core(TM) i3-8100
+        cores: 4
+        threads: 4
+    ram:
+      size: 16
+      mts: 2400
+    drives:
+      - type: ssd
+        size: 256
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 2
+    gpus:
+    ipmi: false
+    name: edge-node01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E5-1650 v3
+        cores: 6
+        threads: 12
+    ram:
+      size: 64
+      mts: 2133
+    drives:
+      - type: ssd
+        size: 480
+      - type: hdd
+        size: 4096
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 4
+    gpus:
+    ipmi: true
+    name: backup-proxmox01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Core(TM) i7-8700
+        cores: 6
+        threads: 12
+    ram:
+      size: 32
+      mts: 2666
+    drives:
+      - type: ssd
+        size: 512
+    nics:
+      - type: rj45
+        speed: 1
+        ports: 1
+    gpus:
+    ipmi: false
+    name: lab-general01
+    tags:
+  - kind: Server
+    cpus:
+      - model: Intel(R) Xeon(R) E5-2650 v3
+        cores: 10
+        threads: 20
+    ram:
+      size: 128
+      mts: 2133
+    drives:
+      - type: hdd
+        size: 4096
+      - type: hdd
+        size: 4096
+      - type: hdd
+        size: 4096
+      - type: hdd
+        size: 4096
+    nics:
+      - type: sfp+
+        speed: 10
+        ports: 2
+    gpus:
+    ipmi: true
+    name: dell-r730-archive01
+    tags: 

+ 14 - 0
RackPeek.Web/config/switches.yaml

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

+ 6 - 0
RackPeek.Web/config/ups.yaml

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

Разница между файлами не показана из-за своего большого размера
+ 6 - 0
RackPeek.Web/wwwroot/tailwind.js


BIN
RackPeek/.DS_Store


+ 52 - 0
RackPeek/Yaml/YamlHardwareRepository.cs

@@ -3,6 +3,7 @@ using RackPeek.Domain.Resources.Hardware.Models;
 
 namespace RackPeek.Yaml;
 
+
 public class YamlHardwareRepository(YamlResourceCollection resources) : IHardwareRepository
 {
     public Task<IReadOnlyList<Hardware>> GetAllAsync()
@@ -14,6 +15,57 @@ public class YamlHardwareRepository(YamlResourceCollection resources) : IHardwar
     {
         return Task.FromResult(resources.GetByName(name) as Hardware);
     }
+    
+    public Task<List<HardwareTree>> GetTreeAsync()
+    {
+        var hardwareTree = new List<HardwareTree>();
+
+        var systemGroups = resources.SystemResources
+            .Where(s => !string.IsNullOrWhiteSpace(s.RunsOn))
+            .GroupBy(s => s.RunsOn!.Trim(), StringComparer.OrdinalIgnoreCase)
+            .ToDictionary(g => g.Key, g => g.ToList(), StringComparer.OrdinalIgnoreCase);
+
+        var serviceGroups = resources.ServiceResources
+            .Where(s => !string.IsNullOrWhiteSpace(s.RunsOn))
+            .GroupBy(s => s.RunsOn!.Trim(), StringComparer.OrdinalIgnoreCase)
+            .ToDictionary(g => g.Key, g => g.ToList(), StringComparer.OrdinalIgnoreCase);
+
+        foreach (var hardware in resources.HardwareResources)
+        {
+            var systems = new List<SystemTree>();
+            var hardwareKey = hardware.Name.Trim();
+
+            if (systemGroups.TryGetValue(hardwareKey, out var systemResources))
+            {
+                foreach (var system in systemResources)
+                {
+                    var services = new List<string>();
+                    var systemKey = system.Name.Trim();
+
+                    if (serviceGroups.TryGetValue(systemKey, out var serviceResources))
+                    {
+                        services.AddRange(serviceResources.Select(s => s.Name));
+                    }
+
+                    systems.Add(new SystemTree
+                    {
+                        SystemName = system.Name,
+                        Services = services
+                    });
+                }
+            }
+
+            hardwareTree.Add(new HardwareTree
+            {
+                Kind = hardware.Kind,
+                HardwareName = hardware.Name,
+                Systems = systems
+            });
+        }
+
+        return Task.FromResult(hardwareTree);
+    }
+
 
     public Task AddAsync(Hardware hardware)
     {

Некоторые файлы не были показаны из-за большого количества измененных файлов