Files
Datacenter-Control-Complete/scripts/init-topology-vlans.ts
2026-02-09 21:51:31 -08:00

233 lines
6.6 KiB
TypeScript
Executable File

#!/usr/bin/env ts-node
/**
* Script to initialize the four topology VLANs for the datacenter network
*
* VLANs to create:
* - VLAN 10: MGMT (10.10.10.0/24, gateway 10.10.10.1)
* - VLAN 20: VM-LAN (10.20.0.0/22, gateway 10.20.0.1)
* - VLAN 30: CEPH-PUBLIC (10.30.0.0/24, gateway 10.30.0.1)
* - VLAN 99: OOB-MGMT (10.99.99.0/24, gateway 10.99.99.1)
*
* Usage:
* ts-node scripts/init-topology-vlans.ts <siteId>
* or
* node dist/scripts/init-topology-vlans.js <siteId>
*/
import { createVlan } from '../src/services/vlanService';
import prisma from '../src/lib/db';
import logger from '../src/lib/logger';
import { OmadaVlanCreate } from '../src/types/omada';
interface TopologyVlan {
name: string;
vlanId: number;
subnet: string;
gateway: string;
description: string;
}
const TOPOLOGY_VLANS: TopologyVlan[] = [
{
name: 'MGMT',
vlanId: 10,
subnet: '10.10.10.0/24',
gateway: '10.10.10.1',
description: 'Proxmox host management, SSH, APIs',
},
{
name: 'VM-LAN',
vlanId: 20,
subnet: '10.20.0.0/22',
gateway: '10.20.0.1',
description: 'Default VM / container network',
},
{
name: 'CEPH-PUBLIC',
vlanId: 30,
subnet: '10.30.0.0/24',
gateway: '10.30.0.1',
description: 'Ceph "public" network (client/public side)',
},
{
name: 'OOB-MGMT',
vlanId: 99,
subnet: '10.99.99.0/24',
gateway: '10.99.99.1',
description: 'iDRAC/IPMI, PDUs, router mgmt, console',
},
];
async function initializeTopologyVlans(siteIdOrName: string): Promise<void> {
try {
logger.info('Starting topology VLAN initialization', { siteIdOrName });
// Find site in database
const site = await prisma.site.findFirst({
where: {
OR: [
{ id: siteIdOrName },
{ omadaSiteId: siteIdOrName },
{ name: siteIdOrName },
],
},
});
if (!site) {
throw new Error(`Site not found: ${siteIdOrName}`);
}
logger.info('Found site', { siteId: site.id, siteName: site.name, omadaSiteId: site.omadaSiteId });
const results = [];
for (const vlanConfig of TOPOLOGY_VLANS) {
try {
// Check if VLAN already exists in database
const existingVlan = await prisma.vlan.findFirst({
where: {
siteId: site.id,
vlanId: vlanConfig.vlanId,
},
});
if (existingVlan) {
logger.warn('VLAN already exists in database, skipping', {
vlanId: vlanConfig.vlanId,
vlanName: vlanConfig.name,
existingVlanId: existingVlan.id,
});
results.push({
vlan: vlanConfig.name,
status: 'skipped',
reason: 'Already exists in database',
});
continue;
}
// Create VLAN via Omada API
const omadaVlanConfig: OmadaVlanCreate = {
name: vlanConfig.name,
vlanId: vlanConfig.vlanId,
subnet: vlanConfig.subnet,
gateway: vlanConfig.gateway,
dhcpEnabled: false, // Disable DHCP by default, can be enabled later if needed
description: vlanConfig.description,
enabled: true,
};
logger.info('Creating VLAN', {
siteId: site.omadaSiteId,
vlanConfig: omadaVlanConfig,
});
const omadaVlan = await createVlan(site.omadaSiteId, omadaVlanConfig);
// Store in database
const dbVlan = await prisma.vlan.create({
data: {
omadaVlanId: omadaVlan.id,
siteId: site.id,
name: omadaVlan.name,
vlanId: vlanConfig.vlanId,
subnet: vlanConfig.subnet,
gateway: vlanConfig.gateway,
dhcpEnabled: false,
description: vlanConfig.description,
},
});
logger.info('VLAN created successfully', {
vlanId: vlanConfig.vlanId,
vlanName: vlanConfig.name,
dbVlanId: dbVlan.id,
});
results.push({
vlan: vlanConfig.name,
status: 'created',
vlanId: vlanConfig.vlanId,
dbVlanId: dbVlan.id,
});
// Log audit
await prisma.auditLog.create({
data: {
action: 'create_vlan',
targetType: 'site',
targetId: site.id,
details: {
siteName: site.name,
vlanName: vlanConfig.name,
vlanId: vlanConfig.vlanId,
script: 'init-topology-vlans',
},
},
});
} catch (error) {
logger.error('Error creating VLAN', {
vlanName: vlanConfig.name,
vlanId: vlanConfig.vlanId,
error: error instanceof Error ? error.message : String(error),
});
results.push({
vlan: vlanConfig.name,
status: 'error',
error: error instanceof Error ? error.message : String(error),
});
}
}
// Print summary
console.log('\n=== Topology VLAN Initialization Summary ===');
console.log(`Site: ${site.name} (${site.omadaSiteId})`);
console.log('\nResults:');
results.forEach((result) => {
if (result.status === 'created') {
console.log(`${result.vlan} (VLAN ${result.vlanId}) - Created`);
} else if (result.status === 'skipped') {
console.log(`${result.vlan} - Skipped (${result.reason})`);
} else {
console.log(`${result.vlan} - Error: ${result.error}`);
}
});
const successCount = results.filter((r) => r.status === 'created').length;
const skippedCount = results.filter((r) => r.status === 'skipped').length;
const errorCount = results.filter((r) => r.status === 'error').length;
console.log(`\nSummary: ${successCount} created, ${skippedCount} skipped, ${errorCount} errors`);
if (errorCount > 0) {
process.exit(1);
}
} catch (error) {
logger.error('Fatal error initializing topology VLANs', {
error: error instanceof Error ? error.message : String(error),
});
console.error('Error:', error instanceof Error ? error.message : String(error));
process.exit(1);
} finally {
await prisma.$disconnect();
}
}
// Main execution
const siteIdOrName = process.argv[2];
if (!siteIdOrName) {
console.error('Usage: ts-node scripts/init-topology-vlans.ts <siteId|siteName>');
console.error('\nExample:');
console.error(' ts-node scripts/init-topology-vlans.ts "Default"');
console.error(' ts-node scripts/init-topology-vlans.ts <omada-site-id>');
process.exit(1);
}
initializeTopologyVlans(siteIdOrName).catch((error) => {
console.error('Unhandled error:', error);
process.exit(1);
});