Initial
This commit is contained in:
185
server/models/hostGroupModel.js
Normal file
185
server/models/hostGroupModel.js
Normal file
@@ -0,0 +1,185 @@
|
||||
import { db, id, json, now, parseJson, visibleClause } from '../db.js';
|
||||
import { hostGroupSchema } from '../forms/schemas.js';
|
||||
import { camelHostGroup } from './mappers.js';
|
||||
import { filterVisibleHostIds } from './hostModel.js';
|
||||
|
||||
function scopedGroupId(payload) {
|
||||
return payload.visibility === 'group' ? payload.groupId || null : null;
|
||||
}
|
||||
|
||||
function normalizeHostGroup(body) {
|
||||
const parsed = hostGroupSchema.parse(body || {});
|
||||
return {
|
||||
...parsed,
|
||||
groupId: scopedGroupId(parsed),
|
||||
rules: parsed.mode === 'dynamic' ? parsed.rules : [],
|
||||
hostIds: parsed.mode === 'manual' ? parsed.hostIds : []
|
||||
};
|
||||
}
|
||||
|
||||
export function listHostGroups(userId) {
|
||||
return db.prepare(`
|
||||
SELECT hg.*, g.name AS group_name,
|
||||
COALESCE((SELECT COUNT(*) FROM host_group_members hgm WHERE hgm.host_group_id = hg.id), 0) AS member_count,
|
||||
COALESCE((SELECT json_group_array(host_id) FROM host_group_members hgm WHERE hgm.host_group_id = hg.id), '[]') AS host_ids
|
||||
FROM host_groups hg
|
||||
LEFT JOIN groups g ON g.id = hg.group_id
|
||||
WHERE ${visibleClause('hg')}
|
||||
ORDER BY hg.name
|
||||
`).all(userId, userId).map(camelHostGroup);
|
||||
}
|
||||
|
||||
export function getVisibleHostGroup(groupId, userId) {
|
||||
const row = db.prepare(`
|
||||
SELECT hg.*, g.name AS group_name,
|
||||
COALESCE((SELECT COUNT(*) FROM host_group_members hgm WHERE hgm.host_group_id = hg.id), 0) AS member_count,
|
||||
COALESCE((SELECT json_group_array(host_id) FROM host_group_members hgm WHERE hgm.host_group_id = hg.id), '[]') AS host_ids
|
||||
FROM host_groups hg
|
||||
LEFT JOIN groups g ON g.id = hg.group_id
|
||||
WHERE hg.id = ? AND ${visibleClause('hg')}
|
||||
`).get(groupId, userId, userId);
|
||||
return row ? camelHostGroup(row) : null;
|
||||
}
|
||||
|
||||
export function createHostGroup(body, userId) {
|
||||
const payload = normalizeHostGroup(body);
|
||||
if (payload.mode === 'dynamic' && !payload.rules.length) throw new Error('Dynamic host groups require at least one rule.');
|
||||
const groupId = id('hgrp');
|
||||
db.prepare(`
|
||||
INSERT INTO host_groups (
|
||||
id, name, description, mode, match_mode, rules, visibility, owner_user_id,
|
||||
group_id, created_by, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
groupId,
|
||||
payload.name,
|
||||
payload.description,
|
||||
payload.mode,
|
||||
payload.matchMode,
|
||||
json(payload.rules),
|
||||
payload.visibility,
|
||||
userId,
|
||||
payload.groupId,
|
||||
userId,
|
||||
now(),
|
||||
now()
|
||||
);
|
||||
if (payload.mode === 'manual') replaceHostGroupMembers(groupId, filterVisibleHostIds(payload.hostIds, userId), 'manual');
|
||||
else syncHostGroup(groupId);
|
||||
return getVisibleHostGroup(groupId, userId);
|
||||
}
|
||||
|
||||
export function updateHostGroup(groupId, body, userId) {
|
||||
const existing = db.prepare(`SELECT * FROM host_groups WHERE id = ? AND ${visibleClause()}`).get(groupId, userId, userId);
|
||||
if (!existing) return null;
|
||||
const payload = normalizeHostGroup({
|
||||
name: existing.name,
|
||||
description: existing.description || '',
|
||||
mode: existing.mode,
|
||||
matchMode: existing.match_mode,
|
||||
rules: parseJson(existing.rules, []),
|
||||
visibility: existing.visibility,
|
||||
groupId: existing.group_id,
|
||||
...body
|
||||
});
|
||||
if (payload.mode === 'dynamic' && !payload.rules.length) throw new Error('Dynamic host groups require at least one rule.');
|
||||
db.prepare(`
|
||||
UPDATE host_groups
|
||||
SET name = ?, description = ?, mode = ?, match_mode = ?, rules = ?,
|
||||
visibility = ?, group_id = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
payload.name,
|
||||
payload.description,
|
||||
payload.mode,
|
||||
payload.matchMode,
|
||||
json(payload.rules),
|
||||
payload.visibility,
|
||||
payload.groupId,
|
||||
now(),
|
||||
groupId
|
||||
);
|
||||
if (payload.mode === 'manual') replaceHostGroupMembers(groupId, filterVisibleHostIds(payload.hostIds, userId), 'manual');
|
||||
else syncHostGroup(groupId);
|
||||
return getVisibleHostGroup(groupId, userId);
|
||||
}
|
||||
|
||||
export function deleteHostGroup(groupId, userId) {
|
||||
db.prepare(`DELETE FROM host_groups WHERE id = ? AND ${visibleClause()}`).run(groupId, userId, userId);
|
||||
}
|
||||
|
||||
export function filterVisibleHostGroupIds(groupIds = [], userId) {
|
||||
if (!groupIds.length) return [];
|
||||
const visible = new Set(
|
||||
db.prepare(`SELECT id FROM host_groups WHERE ${visibleClause()}`).all(userId, userId).map((row) => row.id)
|
||||
);
|
||||
return groupIds.filter((groupId) => visible.has(groupId));
|
||||
}
|
||||
|
||||
export function syncHostGroup(groupId) {
|
||||
const group = db.prepare('SELECT * FROM host_groups WHERE id = ?').get(groupId);
|
||||
if (!group || group.mode !== 'dynamic') return { groupId, matched: 0, skipped: true };
|
||||
const ownerId = group.owner_user_id || group.created_by;
|
||||
const hosts = ownerId
|
||||
? db.prepare(`SELECT * FROM hosts WHERE ${visibleClause()} ORDER BY name`).all(ownerId, ownerId)
|
||||
: db.prepare("SELECT * FROM hosts WHERE visibility = 'shared' ORDER BY name").all();
|
||||
const rules = parseJson(group.rules, []);
|
||||
const matched = hosts.filter((host) => hostMatchesRules(host, rules, group.match_mode)).map((host) => host.id);
|
||||
replaceHostGroupMembers(groupId, matched, 'rule');
|
||||
db.prepare('UPDATE host_groups SET last_synced_at = ?, updated_at = ? WHERE id = ?').run(now(), now(), groupId);
|
||||
return { groupId, matched: matched.length, skipped: false };
|
||||
}
|
||||
|
||||
export function syncDynamicHostGroups() {
|
||||
const groups = db.prepare("SELECT id FROM host_groups WHERE mode = 'dynamic'").all();
|
||||
const summary = { evaluated: 0, synced: 0, matched: 0, errors: 0 };
|
||||
for (const group of groups) {
|
||||
summary.evaluated += 1;
|
||||
try {
|
||||
const result = syncHostGroup(group.id);
|
||||
if (!result.skipped) {
|
||||
summary.synced += 1;
|
||||
summary.matched += result.matched;
|
||||
}
|
||||
} catch {
|
||||
summary.errors += 1;
|
||||
}
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
function replaceHostGroupMembers(groupId, hostIds, source) {
|
||||
db.prepare('DELETE FROM host_group_members WHERE host_group_id = ?').run(groupId);
|
||||
const stmt = db.prepare(`
|
||||
INSERT OR IGNORE INTO host_group_members (host_group_id, host_id, source, created_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
`);
|
||||
for (const hostId of [...new Set(hostIds)]) stmt.run(groupId, hostId, source, now());
|
||||
}
|
||||
|
||||
export function hostMatchesRules(host, rules = [], matchMode = 'all') {
|
||||
if (!rules.length) return false;
|
||||
const results = rules.map((rule) => hostMatchesRule(host, rule));
|
||||
return matchMode === 'any' ? results.some(Boolean) : results.every(Boolean);
|
||||
}
|
||||
|
||||
function hostMatchesRule(host, rule) {
|
||||
const values = hostRuleValues(host, rule.field);
|
||||
const needle = String(rule.value || '').toLowerCase();
|
||||
return values.some((value) => compareRuleValue(String(value || '').toLowerCase(), needle, rule.operator));
|
||||
}
|
||||
|
||||
function hostRuleValues(host, field) {
|
||||
if (field === 'tags') return parseJson(host.tags, []);
|
||||
if (field === 'sourceType') return [host.source_type || 'manual'];
|
||||
if (field === 'osFamily') return [host.os_family || ''];
|
||||
return [host[field] || ''];
|
||||
}
|
||||
|
||||
function compareRuleValue(value, needle, operator = 'contains') {
|
||||
if (operator === 'equals') return value === needle;
|
||||
if (operator === 'startsWith') return value.startsWith(needle);
|
||||
if (operator === 'endsWith') return value.endsWith(needle);
|
||||
return value.includes(needle);
|
||||
}
|
||||
@@ -3,10 +3,11 @@ import { camelHost } from './mappers.js';
|
||||
|
||||
export function listHosts(userId) {
|
||||
return db.prepare(`
|
||||
SELECT h.*, c.name AS credential_name, g.name AS group_name
|
||||
SELECT h.*, c.name AS credential_name, g.name AS group_name, vc.name AS source_connection_name
|
||||
FROM hosts h
|
||||
LEFT JOIN credentials c ON c.id = h.credential_id
|
||||
LEFT JOIN groups g ON g.id = h.group_id
|
||||
LEFT JOIN vcenter_connections vc ON vc.id = h.source_connection_id
|
||||
WHERE ${visibleClause('h')}
|
||||
ORDER BY h.name
|
||||
`).all(userId, userId).map(camelHost);
|
||||
@@ -20,8 +21,9 @@ export function createHost(payload, userId) {
|
||||
const hostId = id('hst');
|
||||
db.prepare(`
|
||||
INSERT INTO hosts (id, name, fqdn, address, os_family, transport, port, credential_id, tags, notes,
|
||||
visibility, owner_user_id, group_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
visibility, owner_user_id, group_id, source_type, source_connection_id, source_ref,
|
||||
created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
hostId,
|
||||
payload.name,
|
||||
@@ -36,6 +38,9 @@ export function createHost(payload, userId) {
|
||||
payload.visibility || 'shared',
|
||||
userId,
|
||||
scopedGroupId(payload),
|
||||
payload.sourceType || 'manual',
|
||||
payload.sourceConnectionId || null,
|
||||
payload.sourceRef || '',
|
||||
now(),
|
||||
now()
|
||||
);
|
||||
@@ -69,7 +74,7 @@ export function updateHost(hostId, payload, userId) {
|
||||
db.prepare(`
|
||||
UPDATE hosts
|
||||
SET name = ?, fqdn = ?, address = ?, os_family = ?, transport = ?, port = ?, credential_id = ?,
|
||||
tags = ?, notes = ?, visibility = ?, group_id = ?, updated_at = ?
|
||||
tags = ?, notes = ?, visibility = ?, group_id = ?, source_type = ?, source_connection_id = ?, source_ref = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
payload.name || existing.name,
|
||||
@@ -83,6 +88,9 @@ export function updateHost(hostId, payload, userId) {
|
||||
payload.notes ?? existing.notes,
|
||||
visibility,
|
||||
visibility === 'group' ? (payload.groupId ?? existing.group_id) : null,
|
||||
payload.sourceType ?? existing.source_type ?? 'manual',
|
||||
payload.sourceConnectionId ?? existing.source_connection_id,
|
||||
payload.sourceRef ?? existing.source_ref ?? '',
|
||||
now(),
|
||||
hostId
|
||||
);
|
||||
|
||||
@@ -37,6 +37,53 @@ export function camelHost(row) {
|
||||
ownerUserId: row.owner_user_id || null,
|
||||
groupId: row.group_id || null,
|
||||
groupName: row.group_name || null,
|
||||
sourceType: row.source_type || 'manual',
|
||||
sourceConnectionId: row.source_connection_id || null,
|
||||
sourceConnectionName: row.source_connection_name || null,
|
||||
sourceRef: row.source_ref || '',
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
}
|
||||
|
||||
export function camelVCenterConnection(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
baseUrl: row.base_url,
|
||||
username: row.username,
|
||||
hasPassword: Boolean(row.secret_cipher),
|
||||
apiMode: row.api_mode || 'auto',
|
||||
requestTimeoutMs: row.request_timeout_ms || 20000,
|
||||
allowUntrustedTls: Boolean(row.allow_untrusted_tls),
|
||||
enabled: Boolean(row.enabled),
|
||||
lastTestStatus: row.last_test_status || '',
|
||||
lastTestMessage: row.last_test_message || '',
|
||||
lastTestAt: row.last_test_at || '',
|
||||
visibility: row.visibility || 'shared',
|
||||
ownerUserId: row.owner_user_id || null,
|
||||
groupId: row.group_id || null,
|
||||
groupName: row.group_name || null,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
}
|
||||
|
||||
export function camelHostGroup(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
description: row.description || '',
|
||||
mode: row.mode || 'manual',
|
||||
matchMode: row.match_mode || 'all',
|
||||
rules: parseJson(row.rules, []),
|
||||
hostIds: parseJson(row.host_ids, []),
|
||||
memberCount: row.member_count || 0,
|
||||
visibility: row.visibility || 'shared',
|
||||
ownerUserId: row.owner_user_id || null,
|
||||
groupId: row.group_id || null,
|
||||
groupName: row.group_name || null,
|
||||
lastSyncedAt: row.last_synced_at || '',
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
@@ -142,6 +189,7 @@ export function camelRunPlan(row) {
|
||||
groupName: row.group_name || null,
|
||||
parallel: Boolean(row.parallel),
|
||||
hostCount: row.host_count || 0,
|
||||
hostGroupCount: row.host_group_count || 0,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
|
||||
@@ -2,11 +2,20 @@ import { db, id, now, visibleClause } from '../db.js';
|
||||
import { normalizeRunPlanPayload } from '../forms/schemas.js';
|
||||
import { camelRunPlan } from './mappers.js';
|
||||
import { filterVisibleHostIds } from './hostModel.js';
|
||||
import { filterVisibleHostGroupIds } from './hostGroupModel.js';
|
||||
|
||||
export function listRunPlans(userId) {
|
||||
return db.prepare(`
|
||||
SELECT r.*, s.name AS script_name, g.name AS group_name,
|
||||
(SELECT COUNT(*) FROM runplan_hosts rh WHERE rh.runplan_id = r.id) AS host_count
|
||||
(SELECT COUNT(DISTINCT host_id) FROM (
|
||||
SELECT rh.host_id AS host_id FROM runplan_hosts rh WHERE rh.runplan_id = r.id
|
||||
UNION
|
||||
SELECT hgm.host_id AS host_id
|
||||
FROM runplan_host_groups rhg
|
||||
JOIN host_group_members hgm ON hgm.host_group_id = rhg.host_group_id
|
||||
WHERE rhg.runplan_id = r.id
|
||||
)) AS host_count,
|
||||
(SELECT COUNT(*) FROM runplan_host_groups rhg WHERE rhg.runplan_id = r.id) AS host_group_count
|
||||
FROM runplans r
|
||||
JOIN scripts s ON s.id = r.script_id
|
||||
LEFT JOIN groups g ON g.id = r.group_id
|
||||
@@ -23,13 +32,22 @@ export function createRunPlan(body, userId) {
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(runplanId, payload.name, payload.description, payload.scriptId, payload.visibility, userId, payload.groupId, payload.parallel ? 1 : 0, now(), now());
|
||||
replaceRunPlanHosts(runplanId, filterVisibleHostIds(payload.hostIds, userId));
|
||||
replaceRunPlanHostGroups(runplanId, filterVisibleHostGroupIds(payload.hostGroupIds, userId));
|
||||
return loadRunPlan(runplanId);
|
||||
}
|
||||
|
||||
export function loadRunPlan(runplanId) {
|
||||
const runplan = db.prepare(`
|
||||
SELECT r.*, s.name AS script_name, g.name AS group_name,
|
||||
(SELECT COUNT(*) FROM runplan_hosts rh WHERE rh.runplan_id = r.id) AS host_count
|
||||
(SELECT COUNT(DISTINCT host_id) FROM (
|
||||
SELECT rh.host_id AS host_id FROM runplan_hosts rh WHERE rh.runplan_id = r.id
|
||||
UNION
|
||||
SELECT hgm.host_id AS host_id
|
||||
FROM runplan_host_groups rhg
|
||||
JOIN host_group_members hgm ON hgm.host_group_id = rhg.host_group_id
|
||||
WHERE rhg.runplan_id = r.id
|
||||
)) AS host_count,
|
||||
(SELECT COUNT(*) FROM runplan_host_groups rhg WHERE rhg.runplan_id = r.id) AS host_group_count
|
||||
FROM runplans r
|
||||
JOIN scripts s ON s.id = r.script_id
|
||||
LEFT JOIN groups g ON g.id = r.group_id
|
||||
@@ -37,7 +55,8 @@ export function loadRunPlan(runplanId) {
|
||||
`).get(runplanId);
|
||||
if (!runplan) return null;
|
||||
const hostIds = db.prepare('SELECT host_id FROM runplan_hosts WHERE runplan_id = ? ORDER BY host_id').all(runplanId).map((row) => row.host_id);
|
||||
return { ...camelRunPlan(runplan), hostIds };
|
||||
const hostGroupIds = db.prepare('SELECT host_group_id FROM runplan_host_groups WHERE runplan_id = ? ORDER BY host_group_id').all(runplanId).map((row) => row.host_group_id);
|
||||
return { ...camelRunPlan(runplan), hostIds, hostGroupIds };
|
||||
}
|
||||
|
||||
export function loadVisibleRunPlan(runplanId, userId) {
|
||||
@@ -48,12 +67,13 @@ export function loadVisibleRunPlan(runplanId, userId) {
|
||||
export function updateRunPlan(runplanId, body, userId) {
|
||||
const existing = db.prepare(`SELECT * FROM runplans WHERE id = ? AND ${visibleClause()}`).get(runplanId, userId, userId);
|
||||
if (!existing) return null;
|
||||
const payload = normalizeRunPlanPayload({ ...existing, ...body, hostIds: body.hostIds || undefined });
|
||||
const payload = normalizeRunPlanPayload({ ...existing, ...body, hostIds: body.hostIds || undefined, hostGroupIds: body.hostGroupIds || undefined });
|
||||
db.prepare(`
|
||||
UPDATE runplans SET name = ?, description = ?, script_id = ?, visibility = ?, group_id = ?, parallel = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(payload.name, payload.description, payload.scriptId, payload.visibility, payload.groupId, payload.parallel ? 1 : 0, now(), runplanId);
|
||||
if (body.hostIds) replaceRunPlanHosts(runplanId, filterVisibleHostIds(payload.hostIds, userId));
|
||||
if (body.hostGroupIds) replaceRunPlanHostGroups(runplanId, filterVisibleHostGroupIds(payload.hostGroupIds, userId));
|
||||
return loadRunPlan(runplanId);
|
||||
}
|
||||
|
||||
@@ -66,3 +86,9 @@ function replaceRunPlanHosts(runplanId, hostIds) {
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO runplan_hosts (runplan_id, host_id) VALUES (?, ?)');
|
||||
for (const hostId of hostIds) stmt.run(runplanId, hostId);
|
||||
}
|
||||
|
||||
function replaceRunPlanHostGroups(runplanId, hostGroupIds) {
|
||||
db.prepare('DELETE FROM runplan_host_groups WHERE runplan_id = ?').run(runplanId);
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO runplan_host_groups (runplan_id, host_group_id) VALUES (?, ?)');
|
||||
for (const groupId of hostGroupIds) stmt.run(runplanId, groupId);
|
||||
}
|
||||
|
||||
135
server/models/vcenterConnectionModel.js
Normal file
135
server/models/vcenterConnectionModel.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import { db, id, now, visibleClause } from '../db.js';
|
||||
import { vcenterConnectionSchema } from '../forms/schemas.js';
|
||||
import { decryptSecret, encryptSecret } from '../services/cryptoStore.js';
|
||||
import { camelVCenterConnection } from './mappers.js';
|
||||
|
||||
function normalizeConnection(body, existing = {}) {
|
||||
const parsed = vcenterConnectionSchema.parse({
|
||||
...existing,
|
||||
...body,
|
||||
password: body.password || ''
|
||||
});
|
||||
return {
|
||||
...parsed,
|
||||
baseUrl: String(parsed.baseUrl || '').trim().replace(/\/+$/, ''),
|
||||
groupId: parsed.visibility === 'group' ? parsed.groupId || null : null
|
||||
};
|
||||
}
|
||||
|
||||
export function listVCenterConnections(userId) {
|
||||
return db.prepare(`
|
||||
SELECT c.*, g.name AS group_name
|
||||
FROM vcenter_connections c
|
||||
LEFT JOIN groups g ON g.id = c.group_id
|
||||
WHERE ${visibleClause('c')}
|
||||
ORDER BY c.name
|
||||
`).all(userId, userId).map(camelVCenterConnection);
|
||||
}
|
||||
|
||||
export function getVCenterConnection(connectionId, userId, includeSecret = false) {
|
||||
if (!connectionId) return null;
|
||||
const row = db.prepare(`
|
||||
SELECT c.*, g.name AS group_name
|
||||
FROM vcenter_connections c
|
||||
LEFT JOIN groups g ON g.id = c.group_id
|
||||
WHERE c.id = ? AND ${visibleClause('c')}
|
||||
`).get(connectionId, userId, userId);
|
||||
if (!row) return null;
|
||||
return includeSecret ? { ...row, password: decryptSecret(row) } : camelVCenterConnection(row);
|
||||
}
|
||||
|
||||
export function getVCenterConnectionSystem(connectionId, includeSecret = false) {
|
||||
if (!connectionId) return null;
|
||||
const row = db.prepare('SELECT * FROM vcenter_connections WHERE id = ?').get(connectionId);
|
||||
if (!row) return null;
|
||||
return includeSecret ? { ...row, password: decryptSecret(row) } : camelVCenterConnection(row);
|
||||
}
|
||||
|
||||
export function createVCenterConnection(body, userId) {
|
||||
const payload = normalizeConnection(body);
|
||||
const encrypted = encryptSecret(payload.password);
|
||||
const connectionId = id('vc');
|
||||
db.prepare(`
|
||||
INSERT INTO vcenter_connections (
|
||||
id, name, base_url, username, secret_cipher, secret_iv, secret_tag,
|
||||
api_mode, request_timeout_ms, allow_untrusted_tls, enabled,
|
||||
visibility, owner_user_id, group_id, created_by, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
connectionId,
|
||||
payload.name,
|
||||
payload.baseUrl,
|
||||
payload.username,
|
||||
encrypted.cipher,
|
||||
encrypted.iv,
|
||||
encrypted.tag,
|
||||
payload.apiMode,
|
||||
payload.requestTimeoutMs,
|
||||
payload.allowUntrustedTls ? 1 : 0,
|
||||
payload.enabled ? 1 : 0,
|
||||
payload.visibility,
|
||||
userId,
|
||||
payload.groupId,
|
||||
userId,
|
||||
now(),
|
||||
now()
|
||||
);
|
||||
return getVCenterConnection(connectionId, userId);
|
||||
}
|
||||
|
||||
export function updateVCenterConnection(connectionId, body, userId) {
|
||||
const existing = getVCenterConnection(connectionId, userId, true);
|
||||
if (!existing) return null;
|
||||
const payload = normalizeConnection(body, {
|
||||
name: existing.name,
|
||||
baseUrl: existing.base_url,
|
||||
username: existing.username,
|
||||
apiMode: existing.api_mode,
|
||||
requestTimeoutMs: existing.request_timeout_ms,
|
||||
allowUntrustedTls: Boolean(existing.allow_untrusted_tls),
|
||||
enabled: Boolean(existing.enabled),
|
||||
visibility: existing.visibility,
|
||||
groupId: existing.group_id
|
||||
});
|
||||
const encrypted = payload.password ? encryptSecret(payload.password) : {
|
||||
cipher: existing.secret_cipher,
|
||||
iv: existing.secret_iv,
|
||||
tag: existing.secret_tag
|
||||
};
|
||||
db.prepare(`
|
||||
UPDATE vcenter_connections
|
||||
SET name = ?, base_url = ?, username = ?, secret_cipher = ?, secret_iv = ?, secret_tag = ?,
|
||||
api_mode = ?, request_timeout_ms = ?, allow_untrusted_tls = ?, enabled = ?,
|
||||
visibility = ?, group_id = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
payload.name,
|
||||
payload.baseUrl,
|
||||
payload.username,
|
||||
encrypted.cipher,
|
||||
encrypted.iv,
|
||||
encrypted.tag,
|
||||
payload.apiMode,
|
||||
payload.requestTimeoutMs,
|
||||
payload.allowUntrustedTls ? 1 : 0,
|
||||
payload.enabled ? 1 : 0,
|
||||
payload.visibility,
|
||||
payload.groupId,
|
||||
now(),
|
||||
connectionId
|
||||
);
|
||||
return getVCenterConnection(connectionId, userId);
|
||||
}
|
||||
|
||||
export function deleteVCenterConnection(connectionId, userId) {
|
||||
db.prepare(`DELETE FROM vcenter_connections WHERE id = ? AND ${visibleClause()}`).run(connectionId, userId, userId);
|
||||
}
|
||||
|
||||
export function recordVCenterConnectionTest(connectionId, status, message) {
|
||||
db.prepare(`
|
||||
UPDATE vcenter_connections
|
||||
SET last_test_status = ?, last_test_message = ?, last_test_at = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(status, message || '', now(), now(), connectionId);
|
||||
}
|
||||
Reference in New Issue
Block a user