import { hostSchema, vcenterConnectionSchema, vcenterImportSchema, vcenterPreviewSchema } from '../forms/schemas.js'; import { createHost, deleteHost, findVisibleHostByIdentity, listHosts, updateHost } from '../models/hostModel.js'; import { createHostGroup, deleteHostGroup, getVisibleHostGroup, listHostGroups, syncHostGroup, syncDynamicHostGroups, updateHostGroup } from '../models/hostGroupModel.js'; import { createVCenterConnection, deleteVCenterConnection, getVCenterConnection, listVCenterConnections, recordVCenterConnectionTest, updateVCenterConnection } from '../models/vcenterConnectionModel.js'; import { buildHostPayloadFromVm, previewVCenterHosts, testVCenterConnection, vcenterStatus } from '../services/vcenterService.js'; export function index(req, res) { res.json(listHosts(req.user.id)); } export function create(req, res) { const parsed = hostSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid host payload' }); res.status(201).json(createHost(parsed.data, req.user.id)); } export function update(req, res) { const host = updateHost(req.params.id, req.body, req.user.id); if (!host) return res.status(404).json({ error: 'Host not found' }); res.json(host); } export function destroy(req, res) { deleteHost(req.params.id, req.user.id); res.status(204).end(); } export function listGroups(req, res) { res.json(listHostGroups(req.user.id)); } export function createGroup(req, res) { try { res.status(201).json(createHostGroup(req.body, req.user.id)); } catch (error) { res.status(400).json({ error: error.message }); } } export function updateGroup(req, res) { try { const group = updateHostGroup(req.params.groupId, req.body, req.user.id); if (!group) return res.status(404).json({ error: 'Host group not found' }); res.json(group); } catch (error) { res.status(400).json({ error: error.message }); } } export function deleteGroup(req, res) { deleteHostGroup(req.params.groupId, req.user.id); res.status(204).end(); } export function syncGroup(req, res) { const group = getVisibleHostGroup(req.params.groupId, req.user.id); if (!group) return res.status(404).json({ error: 'Host group not found' }); if (group.mode !== 'dynamic') return res.status(400).json({ error: 'Only dynamic host groups can be synced.' }); res.json(syncHostGroup(group.id)); } export function syncGroups(req, res) { res.json(syncDynamicHostGroups()); } export function vcenterImportStatus(req, res) { res.json({ defaultConnection: vcenterStatus(), connections: listVCenterConnections(req.user.id) }); } export async function previewVCenterImport(req, res) { const parsed = vcenterPreviewSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid vCenter preview payload' }); try { const connection = parsed.data.connectionId ? getVCenterConnection(parsed.data.connectionId, req.user.id, true) : null; if (parsed.data.connectionId && !connection) return res.status(404).json({ error: 'vCenter connection not found' }); res.json(await previewVCenterHosts({ ...parsed.data, connection })); } catch (err) { res.status(err.statusCode || 502).json({ error: err.message, trace: err.trace || [] }); } } export async function importVCenterHosts(req, res) { const parsed = vcenterImportSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid vCenter import payload' }); try { const connection = parsed.data.connectionId ? getVCenterConnection(parsed.data.connectionId, req.user.id, true) : null; if (parsed.data.connectionId && !connection) return res.status(404).json({ error: 'vCenter connection not found' }); const preview = await previewVCenterHosts({ ...parsed.data, connection }); const selected = new Set(parsed.data.vmIds || []); const candidates = selected.size ? preview.candidates.filter((candidate) => selected.has(candidate.id)) : preview.candidates; const imported = []; const skipped = []; for (const candidate of candidates) { const hostPayload = buildHostPayloadFromVm(candidate, parsed.data); const existing = findVisibleHostByIdentity(hostPayload, req.user.id); if (existing) { skipped.push({ vm: candidate, reason: `Existing host matched ${existing.name}` }); continue; } imported.push(createHost(hostPayload, req.user.id)); } res.status(201).json({ imported, skipped, scanned: preview.count, trace: preview.trace || [] }); } catch (err) { res.status(err.statusCode || 502).json({ error: err.message, trace: err.trace || [] }); } } export function listVCenterConnectionRecords(req, res) { res.json(listVCenterConnections(req.user.id)); } export function createVCenterConnectionRecord(req, res) { const parsed = vcenterConnectionSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid vCenter connection payload' }); if (!parsed.data.password) return res.status(400).json({ error: 'A vCenter password is required when creating a connection' }); res.status(201).json(createVCenterConnection(parsed.data, req.user.id)); } export function updateVCenterConnectionRecord(req, res) { const parsed = vcenterConnectionSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid vCenter connection payload' }); const connection = updateVCenterConnection(req.params.connectionId, parsed.data, req.user.id); if (!connection) return res.status(404).json({ error: 'vCenter connection not found' }); res.json(connection); } export function deleteVCenterConnectionRecord(req, res) { deleteVCenterConnection(req.params.connectionId, req.user.id); res.status(204).end(); } export async function testVCenterConnectionRecord(req, res) { const connection = getVCenterConnection(req.params.connectionId, req.user.id, true); if (!connection) return res.status(404).json({ error: 'vCenter connection not found' }); try { const result = await testVCenterConnection(connection); recordVCenterConnectionTest(req.params.connectionId, 'success', result.message); res.json(result); } catch (err) { recordVCenterConnectionTest(req.params.connectionId, 'failed', err.message); res.status(err.statusCode || 502).json({ error: err.message, trace: err.trace || [] }); } }