Initial commit: add .gitignore and README
This commit is contained in:
82
scripts/add-omada-env.sh
Executable file
82
scripts/add-omada-env.sh
Executable file
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to add Omada environment variables to existing .env file
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
ENV_FILE="$PROJECT_ROOT/.env"
|
||||
ENV_EXAMPLE="$PROJECT_ROOT/env.example"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ .env file not found. Creating from template..."
|
||||
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
||||
echo "✅ Created .env file. Please edit it with your credentials."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Adding Omada environment variables to existing .env file..."
|
||||
|
||||
# Check if variables already exist
|
||||
OMADA_VARS=(
|
||||
"OMADA_USERNAME"
|
||||
"OMADA_PASSWORD"
|
||||
"OMADA_ID"
|
||||
"OMADA_CONTROLLER_BASE"
|
||||
"OMADA_NORTHBOUND_BASE"
|
||||
"DATABASE_URL"
|
||||
"JWT_SECRET"
|
||||
"PORT"
|
||||
"NODE_ENV"
|
||||
"LOG_LEVEL"
|
||||
"SYNC_JOB_SCHEDULE"
|
||||
"LICENSE_JOB_SCHEDULE"
|
||||
)
|
||||
|
||||
# Read existing .env and check what's missing
|
||||
MISSING_VARS=()
|
||||
for var in "${OMADA_VARS[@]}"; do
|
||||
if ! grep -q "^${var}=" "$ENV_FILE" 2>/dev/null; then
|
||||
MISSING_VARS+=("$var")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#MISSING_VARS[@]} -eq 0 ]; then
|
||||
echo "✅ All Omada environment variables are already present in .env"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Found ${#MISSING_VARS[@]} missing variable(s): ${MISSING_VARS[*]}"
|
||||
echo ""
|
||||
|
||||
# Append missing variables from template
|
||||
echo "" >> "$ENV_FILE"
|
||||
echo "# ============================================" >> "$ENV_FILE"
|
||||
echo "# Omada Cloud Integration Variables" >> "$ENV_FILE"
|
||||
echo "# ============================================" >> "$ENV_FILE"
|
||||
|
||||
# Extract and add missing variables from env.example
|
||||
while IFS= read -r line; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "${line// }" ]] && continue
|
||||
|
||||
# Extract variable name
|
||||
var_name=$(echo "$line" | cut -d'=' -f1)
|
||||
|
||||
# Check if this variable is missing
|
||||
if [[ " ${MISSING_VARS[@]} " =~ " ${var_name} " ]]; then
|
||||
echo "$line" >> "$ENV_FILE"
|
||||
fi
|
||||
done < "$ENV_EXAMPLE"
|
||||
|
||||
echo "✅ Added missing Omada environment variables to .env"
|
||||
echo ""
|
||||
echo "📝 Please edit .env and fill in the actual values for:"
|
||||
for var in "${MISSING_VARS[@]}"; do
|
||||
echo " - $var"
|
||||
done
|
||||
echo ""
|
||||
|
||||
232
scripts/init-topology-vlans.ts
Executable file
232
scripts/init-topology-vlans.ts
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/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);
|
||||
});
|
||||
|
||||
54
scripts/setup-database.sh
Executable file
54
scripts/setup-database.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# Database setup script for Omada Cloud Integration
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Database Setup Script ==="
|
||||
echo ""
|
||||
|
||||
# Check if PostgreSQL is running
|
||||
if ! pg_isready -h localhost -p 5432 >/dev/null 2>&1; then
|
||||
echo "⚠️ PostgreSQL is not running on localhost:5432"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo "1. Start PostgreSQL with Docker:"
|
||||
echo " docker run -d --name omada-postgres \\"
|
||||
echo " -e POSTGRES_USER=omada_user \\"
|
||||
echo " -e POSTGRES_PASSWORD=omada_password \\"
|
||||
echo " -e POSTGRES_DB=omada_db \\"
|
||||
echo " -p 5433:5432 postgres:15-alpine"
|
||||
echo ""
|
||||
echo " Then update DATABASE_URL in .env to use port 5433"
|
||||
echo ""
|
||||
echo "2. Use existing PostgreSQL (you'll need admin credentials)"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ PostgreSQL is running"
|
||||
echo ""
|
||||
|
||||
# Try to create database with different methods
|
||||
echo "Attempting to create database..."
|
||||
|
||||
# Method 1: Try with default postgres user
|
||||
if psql -h localhost -U postgres -lqt 2>/dev/null | cut -d \| -f 1 | grep -qw omada_db; then
|
||||
echo "✅ Database 'omada_db' already exists"
|
||||
else
|
||||
echo "Creating database 'omada_db'..."
|
||||
echo "You may need to enter PostgreSQL admin password"
|
||||
createdb -h localhost -U postgres omada_db 2>/dev/null || \
|
||||
psql -h localhost -U postgres -c "CREATE DATABASE omada_db;" 2>/dev/null || \
|
||||
echo "⚠️ Could not create database automatically. Please create it manually:"
|
||||
echo " CREATE DATABASE omada_db;"
|
||||
echo " CREATE USER omada_user WITH PASSWORD 'omada_password';"
|
||||
echo " GRANT ALL PRIVILEGES ON DATABASE omada_db TO omada_user;"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Database setup complete!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Run: pnpm run prisma:migrate"
|
||||
echo "2. Verify: pnpm run prisma:studio"
|
||||
|
||||
54
scripts/setup-env.sh
Executable file
54
scripts/setup-env.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Setup script to create .env file from template
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
ENV_EXAMPLE="$PROJECT_ROOT/env.example"
|
||||
ENV_FILE="$PROJECT_ROOT/.env"
|
||||
|
||||
echo "Setting up environment variables..."
|
||||
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "⚠️ .env file already exists!"
|
||||
read -p "Do you want to overwrite it? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Aborted. Keeping existing .env file."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_EXAMPLE" ]; then
|
||||
echo "❌ Error: env.example file not found at $ENV_EXAMPLE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Copy template to .env
|
||||
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
||||
|
||||
echo "✅ Created .env file from env.example"
|
||||
echo ""
|
||||
echo "📝 Next steps:"
|
||||
echo " 1. Edit .env file and fill in your Omada credentials:"
|
||||
echo " - OMADA_USERNAME"
|
||||
echo " - OMADA_PASSWORD"
|
||||
echo " - OMADA_ID"
|
||||
echo " - OMADA_CONTROLLER_BASE"
|
||||
echo " - OMADA_NORTHBOUND_BASE"
|
||||
echo ""
|
||||
echo " 2. Configure your database:"
|
||||
echo " - DATABASE_URL"
|
||||
echo ""
|
||||
echo " 3. Set a strong JWT_SECRET (generate with: openssl rand -base64 32)"
|
||||
echo ""
|
||||
echo " 4. Adjust optional settings as needed:"
|
||||
echo " - PORT"
|
||||
echo " - LOG_LEVEL"
|
||||
echo " - SYNC_JOB_SCHEDULE"
|
||||
echo " - LICENSE_JOB_SCHEDULE"
|
||||
echo ""
|
||||
|
||||
46
scripts/test-auth.ts
Executable file
46
scripts/test-auth.ts
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env ts-node
|
||||
/**
|
||||
* Test script to verify Omada authentication
|
||||
* Usage: npx ts-node scripts/test-auth.ts
|
||||
*/
|
||||
|
||||
import { login } from '../src/services/authService';
|
||||
import { listSites } from '../src/services/siteService';
|
||||
|
||||
async function testAuthentication() {
|
||||
try {
|
||||
console.log('Testing Omada Cloud authentication...\n');
|
||||
|
||||
// Test login
|
||||
console.log('1. Testing login...');
|
||||
const token = await login();
|
||||
console.log('✅ Login successful!');
|
||||
console.log(` Token: ${token.substring(0, 20)}...\n`);
|
||||
|
||||
// Test API call
|
||||
console.log('2. Testing API call (fetching sites)...');
|
||||
const sites = await listSites();
|
||||
console.log(`✅ API call successful!`);
|
||||
console.log(` Found ${sites.length} site(s):`);
|
||||
sites.forEach((site, index) => {
|
||||
console.log(` ${index + 1}. ${site.name} (ID: ${site.id || site.siteId})`);
|
||||
});
|
||||
|
||||
console.log('\n✅ All tests passed!');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('\n❌ Test failed:');
|
||||
if (error instanceof Error) {
|
||||
console.error(` ${error.message}`);
|
||||
if (error.stack) {
|
||||
console.error(`\n Stack trace:\n ${error.stack.split('\n').slice(1).join('\n ')}`);
|
||||
}
|
||||
} else {
|
||||
console.error(' Unknown error:', error);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
testAuthentication();
|
||||
|
||||
Reference in New Issue
Block a user