Files
proxmox/scripts/unifi/configure-vlans-node.js
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

190 lines
7.2 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Configure all VLANs on UDM Pro via Private API
* Node.js version for better password handling
*/
import { readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { UnifiClient, ApiMode } from '../../unifi-api/dist/index.js';
import { NetworksService } from '../../unifi-api/dist/index.js';
// Load environment variables
const envPath = join(homedir(), '.env');
function loadEnvFile(filePath) {
try {
const envFile = readFileSync(filePath, 'utf8');
const envVars = envFile.split('\n').filter(
(line) => line.includes('=') && !line.trim().startsWith('#')
);
for (const line of envVars) {
const [key, ...values] = line.split('=');
if (key && values.length > 0 && /^[A-Z_][A-Z0-9_]*$/.test(key.trim())) {
let value = values.join('=').trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
process.env[key.trim()] = value;
}
}
return true;
} catch {
return false;
}
}
loadEnvFile(envPath);
const baseUrl = process.env.UNIFI_UDM_URL || 'https://192.168.0.1';
const username = process.env.UNIFI_USERNAME || 'unifi_api';
const password = process.env.UNIFI_PASSWORD;
const siteId = process.env.UNIFI_SITE_ID || 'default';
if (!password) {
console.error('❌ UNIFI_PASSWORD not set in environment');
process.exit(1);
}
console.log('UDM Pro VLAN Configuration Script');
console.log('==================================');
console.log('');
console.log(`UDM URL: ${baseUrl}`);
console.log(`Site ID: ${siteId}`);
console.log(`Username: ${username}`);
console.log('');
// Create client
const client = new UnifiClient({
baseUrl,
apiMode: ApiMode.PRIVATE,
username,
password,
siteId,
verifySSL: false,
});
const networksService = new NetworksService(client);
// VLAN configurations
const vlanConfigs = [
{ id: 11, name: 'MGMT-LAN', subnet: '192.168.11.0/24', gateway: '192.168.11.1', dhcpStart: '192.168.11.100', dhcpStop: '192.168.11.200' },
{ id: 110, name: 'BESU-VAL', subnet: '10.110.0.0/24', gateway: '10.110.0.1', dhcpStart: '10.110.0.10', dhcpStop: '10.110.0.250' },
{ id: 111, name: 'BESU-SEN', subnet: '10.111.0.0/24', gateway: '10.111.0.1', dhcpStart: '10.111.0.10', dhcpStop: '10.111.0.250' },
{ id: 112, name: 'BESU-RPC', subnet: '10.112.0.0/24', gateway: '10.112.0.1', dhcpStart: '10.112.0.10', dhcpStop: '10.112.0.250' },
{ id: 120, name: 'BLOCKSCOUT', subnet: '10.120.0.0/24', gateway: '10.120.0.1', dhcpStart: '10.120.0.10', dhcpStop: '10.120.0.250' },
{ id: 121, name: 'CACTI', subnet: '10.121.0.0/24', gateway: '10.121.0.1', dhcpStart: '10.121.0.10', dhcpStop: '10.121.0.250' },
{ id: 130, name: 'CCIP-OPS', subnet: '10.130.0.0/24', gateway: '10.130.0.1', dhcpStart: '10.130.0.10', dhcpStop: '10.130.0.250' },
{ id: 132, name: 'CCIP-COMMIT', subnet: '10.132.0.0/24', gateway: '10.132.0.1', dhcpStart: '10.132.0.10', dhcpStop: '10.132.0.250' },
{ id: 133, name: 'CCIP-EXEC', subnet: '10.133.0.0/24', gateway: '10.133.0.1', dhcpStart: '10.133.0.10', dhcpStop: '10.133.0.250' },
{ id: 134, name: 'CCIP-RMN', subnet: '10.134.0.0/24', gateway: '10.134.0.1', dhcpStart: '10.134.0.10', dhcpStop: '10.134.0.250' },
{ id: 140, name: 'FABRIC', subnet: '10.140.0.0/24', gateway: '10.140.0.1', dhcpStart: '10.140.0.10', dhcpStop: '10.140.0.250' },
{ id: 141, name: 'FIREFLY', subnet: '10.141.0.0/24', gateway: '10.141.0.1', dhcpStart: '10.141.0.10', dhcpStop: '10.141.0.250' },
{ id: 150, name: 'INDY', subnet: '10.150.0.0/24', gateway: '10.150.0.1', dhcpStart: '10.150.0.10', dhcpStop: '10.150.0.250' },
{ id: 160, name: 'SANKOFA-SVC', subnet: '10.160.0.0/22', gateway: '10.160.0.1', dhcpStart: '10.160.0.10', dhcpStop: '10.160.0.254' },
{ id: 200, name: 'PHX-SOV-SMOM', subnet: '10.200.0.0/20', gateway: '10.200.0.1', dhcpStart: '10.200.0.10', dhcpStop: '10.200.15.250' },
{ id: 201, name: 'PHX-SOV-ICCC', subnet: '10.201.0.0/20', gateway: '10.201.0.1', dhcpStart: '10.201.0.10', dhcpStop: '10.201.15.250' },
{ id: 202, name: 'PHX-SOV-DBIS', subnet: '10.202.0.0/20', gateway: '10.202.0.1', dhcpStart: '10.202.0.10', dhcpStop: '10.202.15.250' },
{ id: 203, name: 'PHX-SOV-AR', subnet: '10.203.0.0/20', gateway: '10.203.0.1', dhcpStart: '10.203.0.10', dhcpStop: '10.203.15.250' },
];
// Helper function to sleep
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function createVlan(config, networksService) {
try {
console.log(`Creating VLAN ${config.id}: ${config.name} (${config.subnet})...`);
const networkConfig = {
name: config.name,
purpose: 'corporate',
vlan: config.id,
ip_subnet: config.subnet,
ipv6_interface_type: 'none',
dhcpd_enabled: true,
dhcpd_start: config.dhcpStart,
dhcpd_stop: config.dhcpStop,
dhcpd_leasetime: 86400,
domain_name: 'localdomain',
is_nat: true,
networkgroup: 'LAN',
};
await networksService.createNetwork(networkConfig);
console.log(` ✅ VLAN ${config.id} created successfully`);
return true;
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
if (errorMsg.includes('already exists') || errorMsg.includes('duplicate')) {
console.log(` ⚠️ VLAN ${config.id} already exists (skipping)`);
return true;
} else {
console.log(` ❌ Failed to create VLAN ${config.id}: ${errorMsg}`);
return false;
}
}
}
async function main() {
console.log('Authenticating...');
// Force authentication by making a test request
try {
await networksService.listNetworks();
console.log('✅ Authentication successful');
} catch (error) {
console.error('❌ Authentication failed:', error);
process.exit(1);
}
console.log('');
console.log('Creating VLANs...');
console.log('');
// Create VLANs sequentially to avoid rate limiting
const results = [];
for (const config of vlanConfigs) {
const result = await createVlan(config, networksService);
results.push({ status: result ? 'fulfilled' : 'rejected', value: result });
// Small delay between requests to avoid rate limiting
if (config !== vlanConfigs[vlanConfigs.length - 1]) {
await sleep(500);
}
}
console.log('');
console.log('Verifying created networks...');
try {
const networks = await networksService.listNetworks();
const vlanNetworks = networks.filter(n => n.vlan && n.vlan > 0);
console.log('');
console.log(`✅ Found ${vlanNetworks.length} VLAN networks:`);
vlanNetworks.forEach(network => {
console.log(` VLAN ${network.vlan}: ${network.name} (${network.ip_subnet || 'N/A'})`);
});
} catch (error) {
console.error('Error listing networks:', error);
}
const successCount = results.filter(r => r.status === 'fulfilled' && r.value).length;
const failCount = results.length - successCount;
console.log('');
console.log('==================================');
console.log(`✅ Successfully created: ${successCount}/${vlanConfigs.length} VLANs`);
if (failCount > 0) {
console.log(`❌ Failed: ${failCount} VLANs`);
}
console.log('');
}
main().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});