- Add MorningSummaryService with Zabbix aggregation and adaptive card builder - Add webhook delivery system with Teams incoming webhooks - Add admin UI at /admin/morning-summary for webhook/config management - Add API routes: /send, /test, /webhooks, /webhooks/[id], /config, /history - Register morning-summary cron job in SyncScheduler (Mon-Fri 6:30 AM) - Add outages_only filter (Unavailable triggers only) - Fix host resolution: use getTriggerEnabledHosts to exclude disabled hosts - Fix resolved events: event.get value:1 scoped to window with r_eventid filter - Remove emojis from fact rows and section headers in card - Remove Open Zabbix button (duplicate of View Problems) - Add migrations: morning_summary_config + morning_summaries tables - Add outages_only column to morning_summary_config
126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
/**
|
|
* Manual Zabbix Host Creation API
|
|
* POST /api/zabbix/create-host
|
|
*
|
|
* Creates a Zabbix host with ICMP monitoring using the same logic as the
|
|
* RMM discovery flow, but with a user-supplied IP and site name instead
|
|
* of auto-discovered WAN IPs.
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { ZabbixClient } from '@/lib/services/zabbix-client';
|
|
import { postgresClient } from '@/lib/services/postgres-client';
|
|
import {
|
|
lookupIsp,
|
|
buildHostParams,
|
|
discoverIcmpTemplate,
|
|
} from '@/lib/services/zabbix-wan-utils';
|
|
|
|
interface CreateHostBody {
|
|
ip: string;
|
|
siteName: string;
|
|
companyId?: number;
|
|
dryRun?: boolean;
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body: CreateHostBody = await request.json();
|
|
const { ip, siteName, companyId, dryRun = false } = body;
|
|
|
|
// Validate required fields
|
|
if (!ip || !siteName) {
|
|
return NextResponse.json(
|
|
{ error: 'ip and siteName are required' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Basic IPv4 validation
|
|
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
if (!ipv4Regex.test(ip)) {
|
|
return NextResponse.json(
|
|
{ error: 'Invalid IPv4 address format' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
if (!process.env.ZABBIX_API_URL || !process.env.ZABBIX_API_TOKEN) {
|
|
return NextResponse.json(
|
|
{ error: 'Zabbix is not configured. Add ZABBIX_API_URL and ZABBIX_API_TOKEN to your environment.' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
// Resolve company name if companyId provided
|
|
let companyName: string | undefined;
|
|
if (companyId) {
|
|
const res = await postgresClient.query<{ company_name: string }>(
|
|
'SELECT company_name FROM companies WHERE id = $1 LIMIT 1',
|
|
[companyId]
|
|
);
|
|
companyName = res.rows[0]?.company_name;
|
|
}
|
|
|
|
// ISP lookup
|
|
const ispInfo = await lookupIsp(ip);
|
|
|
|
// Dry-run: return what would happen without writing to Zabbix
|
|
if (dryRun) {
|
|
return NextResponse.json({
|
|
action: 'skipped',
|
|
dryRun: true,
|
|
siteName,
|
|
ip,
|
|
companyId: companyId ?? null,
|
|
companyName: companyName ?? null,
|
|
isp: ispInfo?.isp ?? null,
|
|
asn: ispInfo?.asn ?? null,
|
|
hostId: null,
|
|
});
|
|
}
|
|
|
|
const zabbix = new ZabbixClient({
|
|
apiUrl: process.env.ZABBIX_API_URL!,
|
|
apiToken: process.env.ZABBIX_API_TOKEN!,
|
|
});
|
|
|
|
// Ensure host group + discover ICMP template
|
|
const globalGroupId = await zabbix.ensureHostGroup('Datto RMM Sites');
|
|
const icmpTemplateId = await discoverIcmpTemplate(zabbix);
|
|
|
|
// Build host params using the shared utility
|
|
const hostParams = await buildHostParams({
|
|
siteName,
|
|
wanIp: ip,
|
|
companyId,
|
|
companyName,
|
|
ispInfo,
|
|
source: 'manual',
|
|
icmpTemplateId,
|
|
globalGroupId,
|
|
zabbix,
|
|
});
|
|
|
|
// Create or update the host
|
|
const { action, hostid } = await zabbix.upsertHost(hostParams);
|
|
|
|
return NextResponse.json({
|
|
action,
|
|
dryRun: false,
|
|
siteName,
|
|
ip,
|
|
companyId: companyId ?? null,
|
|
companyName: companyName ?? null,
|
|
isp: ispInfo?.isp ?? null,
|
|
asn: ispInfo?.asn ?? null,
|
|
hostId: hostid,
|
|
});
|
|
} catch (error) {
|
|
console.error('[create-host] error:', error);
|
|
return NextResponse.json(
|
|
{ error: String(error) },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|