Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- 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>
190 lines
7.2 KiB
JavaScript
Executable File
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);
|
|
});
|