Files
slashroot-cc/src/pages/hardware.astro
2026-04-01 00:19:49 +01:00

332 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
import BaseLayout from '../layouts/BaseLayout.astro';
// ── Hardware data — edit this as your inventory grows ──────────
const hardware = {
compute: [
{
name: 'Proxmox Node 01',
model: 'Dell PowerEdge R730',
specs: ['2× Intel Xeon E5-2680v4 (28C/56T total)', '256GB DDR4 ECC LRDIMM', '2× 10GbE SFP+', 'iDRAC8 Enterprise', 'H730 RAID (passthrough)'],
role: 'Primary Proxmox hypervisor · VM host',
status: 'online',
location: 'homelab rack · U4',
},
{
name: 'Proxmox Node 02',
model: 'Dell PowerEdge R720',
specs: ['2× Intel Xeon E5-2670 (16C/32T total)', '128GB DDR3 ECC RDIMM', '2× 1GbE', 'iDRAC7 Enterprise'],
role: 'Secondary Proxmox node · backup workloads',
status: 'online',
location: 'homelab rack · U6',
},
{
name: 'Raspberry Pi 4 (8GB)',
model: 'Raspberry Pi 4 Model B',
specs: ['Broadcom BCM2711 (4× Cortex-A72)', '8GB LPDDR4', '2× USB 3.0, Gigabit Ethernet', '64GB Samsung Pro Endurance microSD'],
role: 'PXE boot server · ISC26 cluster deployment',
status: 'online',
location: 'desk · USB-C powered',
},
],
storage: [
{
name: 'ZFS NAS — zfs-oporto',
model: 'Custom Proxmox VM → ZFS passthrough',
specs: ['4× Seagate IronWolf 8TB (RAIDZ2)', '2× Samsung 870 EVO 1TB (SSD special class vdev)', 'ZFS 2.2 — RAIDZ expansion capable', '~20TB usable raw (RAIDZ2 overhead)'],
role: 'Primary NAS · NFS exports to K8s · Immich storage',
status: 'online',
location: 'pve-01 · RAIDZ2',
},
{
name: 'Longhorn Cluster Storage',
model: 'Distributed across k8s-worker1/2',
specs: ['2× 500GB NVMe (worker1)', '2× 500GB NVMe (worker2)', '3-replica default policy'],
role: 'Kubernetes persistent volumes · Longhorn CSI',
status: 'online',
location: 'k8s-worker1 / k8s-worker2',
},
],
networking: [
{
name: 'OPNsense Firewall',
model: 'Protectli VP2420',
specs: ['Intel Celeron J6413', '8GB DDR4', '4× 2.5GbE Intel i226', '64GB eMMC', 'OPNsense 26.1'],
role: 'Edge router · Firewall · WireGuard VPN · Unbound DNS · GeoIP blocks',
status: 'online',
location: 'homelab rack · U1',
},
{
name: 'Core Switch',
model: 'Cisco SG300-28PP',
specs: ['24× PoE+ 1GbE', '2× 1GbE combo SFP', 'Layer 3 managed', '375W PoE budget'],
role: 'Core VLAN switch · LAG to hypervisors',
status: 'online',
location: 'homelab rack · U2',
},
{
name: 'AP',
model: 'Ubiquiti U6-Lite',
specs: ['WiFi 6 (802.11ax)', '2.4 + 5GHz', 'PoE powered'],
role: 'Wireless · separate IoT SSID on VLAN50',
status: 'online',
location: 'ceiling mount',
},
],
work_hpc: [
{
name: 'ARCHER2 (EPCC)',
model: 'HPE Cray EX — AMD EPYC 7742',
specs: ['5,860 compute nodes', '2× AMD EPYC 7742 (128C/node)', '256GB DDR4 ECC/node', 'HPE Slingshot 11 100Gb/s HSN', '14.1 PiB Lustre storage'],
role: 'UK National HPC facility · sysadmin',
status: 'production',
location: 'EPCC · Edinburgh',
},
{
name: 'Cirrus (EPCC)',
model: 'SGI ICE XA / HPE ProLiant XL230a',
specs: ['280 compute nodes', '2× Intel Xeon E5-2695v4 (36C/node)', '256GB DDR4/node', 'Intel OmniPath HSN', 'Cirrus EX GPU partition: HPE Cray EX235n'],
role: 'EPCC Tier-2 HPC · sysadmin · GPU partition admin',
status: 'production',
location: 'EPCC · Edinburgh',
},
{
name: 'ISC26 Competition Cluster',
model: 'Atos BullSequana XH2000',
specs: ['1× BullSequana XD670 GPU node (4× NVIDIA H100 80GB)', '8× BullSequana XD2000 CPU nodes', 'NDR 400Gb/s InfiniBand fabric (Cornelis)', 'Raspberry Pi 4 PXE deployment server'],
role: 'ISC26 Student Cluster Competition — Hamburg 2026',
status: 'building',
location: 'EPCC · Edinburgh',
},
],
peripherals: [
{
name: 'Main Monitor',
model: 'LG 27UK850-W',
specs: ['27" 4K IPS', 'USB-C 60W PD', 'HDR400', 'USB-C + HDMI + DP'],
role: 'Primary display',
status: 'online',
},
{
name: '3D Printer',
model: 'Anycubic Kobra S1',
specs: ['FDM · 220×220×250mm build volume', 'Auto-levelling', 'Direct drive'],
role: 'Printing rack accessories, cable guides, custom mounts',
status: 'idle',
},
{
name: 'Laser Printer',
model: 'Kyocera ECOSYS M2135dn',
specs: ['A4 mono laser MFP', 'Duplex · LAN · ADF', '35ppm'],
role: 'Documents · printing homelab diagrams',
status: 'idle',
},
],
};
const categories = [
{ key: 'compute', label: 'Compute', icon: '▣' },
{ key: 'storage', label: 'Storage', icon: '◈' },
{ key: 'networking', label: 'Networking', icon: '⇅' },
{ key: 'work_hpc', label: 'Work / HPC', icon: '⬡' },
{ key: 'peripherals',label: 'Peripherals & Misc', icon: '◎' },
];
---
<BaseLayout title="Hardware" description="Full hardware inventory — homelab and work HPC systems">
<div class="hardware-page">
<!-- Hero -->
<div class="page-hero container">
<div class="accent-line"></div>
<h1>Hardware <span class="text-accent">Inventory</span></h1>
<p class="text-muted font-mono" style="font-size:0.88rem;margin-top:0.5rem">
Everything physical I touch, rack and bench · last updated 2025
</p>
</div>
<!-- Jump nav -->
<div class="container jump-nav">
{categories.map(cat => (
<a href={`#${cat.key}`} class="jump-chip">
<span class="text-accent">{cat.icon}</span>
<span>{cat.label}</span>
</a>
))}
</div>
<!-- Category sections -->
{categories.map(cat => (
<section class="section container hw-section" id={cat.key}>
<div class="hw-section-header">
<span class="hw-icon text-accent">{cat.icon}</span>
<h2>{cat.label}</h2>
</div>
<div class="hw-grid">
{(hardware as any)[cat.key].map((item: any) => (
<div class="card hw-card">
<div class="hw-card-header">
<div>
<div class="hw-name font-display">{item.name}</div>
<div class="hw-model font-mono">{item.model}</div>
</div>
<span
class="hw-status tag"
style={
item.status === 'online' ? '' :
item.status === 'production' ? 'color:#00D2BE;border-color:#00D2BE;background:rgba(0,210,190,0.08)' :
item.status === 'building' ? 'color:#FFB800;border-color:#FFB800;background:rgba(255,184,0,0.08)' :
'color:var(--text-muted);border-color:var(--border-subtle);background:transparent'
}
>{item.status}</span>
</div>
<ul class="hw-specs">
{item.specs.map((s: string) => (
<li class="hw-spec">
<span class="spec-bullet text-accent">▸</span>
<span>{s}</span>
</li>
))}
</ul>
<div class="hw-footer">
<span class="hw-role text-muted">{item.role}</span>
{item.location && (
<span class="hw-location font-mono">{item.location}</span>
)}
</div>
</div>
))}
</div>
</section>
))}
<!-- Total count footer -->
<div class="container hw-totals">
<div class="card" style="padding:1.5rem;text-align:center">
<p class="font-mono text-muted" style="font-size:0.8rem">
{Object.values(hardware).flat().length} items catalogued ·
<span class="text-accent">rack::log hardware registry</span>
</p>
</div>
</div>
</div>
</BaseLayout>
<style>
.hardware-page { padding-top: 8rem; padding-bottom: 4rem; }
.page-hero { margin-bottom: 2.5rem; }
/* Jump nav */
.jump-nav {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 4rem;
}
.jump-chip {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.35rem 0.9rem;
border: 1px solid var(--border-subtle);
border-radius: 20px;
font-family: var(--font-mono);
font-size: 0.78rem;
color: var(--text-muted);
background: var(--bg-surface);
transition: all var(--transition-fast);
}
.jump-chip:hover {
border-color: var(--border-glow);
color: var(--petronas-teal);
background: var(--petronas-glow);
}
/* Section header */
.hw-section { padding-top: 3rem; padding-bottom: 1rem; }
.hw-section-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.75rem;
}
.hw-icon { font-size: 1.4rem; }
/* Cards */
.hw-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.25rem;
}
.hw-card { display: flex; flex-direction: column; gap: 1rem; }
.hw-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
}
.hw-name {
font-size: 1.05rem;
font-weight: 700;
color: var(--text-primary);
}
.hw-model {
font-size: 0.72rem;
color: var(--petronas-teal);
margin-top: 0.2rem;
}
.hw-status { white-space: nowrap; flex-shrink: 0; }
/* Specs list */
.hw-specs {
list-style: none;
display: flex;
flex-direction: column;
gap: 0.35rem;
flex: 1;
}
.hw-spec {
display: flex;
align-items: baseline;
gap: 0.5rem;
font-size: 0.83rem;
color: var(--text-secondary);
line-height: 1.4;
}
.spec-bullet { font-size: 0.6rem; flex-shrink: 0; margin-top: 0.15rem; }
/* Footer */
.hw-footer {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding-top: 0.75rem;
border-top: 1px solid var(--border-subtle);
}
.hw-role { font-size: 0.8rem; }
.hw-location { font-size: 0.68rem; color: var(--text-muted); }
/* Totals */
.hw-totals { margin-top: 4rem; }
@media (max-width: 600px) {
.hw-grid { grid-template-columns: 1fr; }
}
</style>