feat(health-check): add TLS verification option to health check configuration
Introduced a new `verify_tls` boolean option in health check configurations across various services, allowing users to specify whether to validate TLS certificates during health checks. Updated related components and services to accommodate this new option, ensuring proper handling in both the backend and frontend. Enhanced tests to validate the new functionality and ensure correct behavior with different configurations.
This commit is contained in:
1 parent
9783974949
commit
1d497d01c2
123 files changed
+351
-15912
No files matched your search
Vendored
+72
-5
@@ -1,7 +1,7 @@
|
||||
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
||||
import Database from 'better-sqlite3';
|
||||
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
||||
import { AppSwitcherConfig, LbMode, HealthCheckType, IpHealthState, HealthCheckScope, ServiceBinding, Domain, Group, Service, ServiceGroup, Subdomain, DnsRecord, ServiceBindingView, Certificate, GroupWithStats, IpHealthStatus, SyncJob, DomainListItem, HealthCheckTarget } from '@cfdm/shared';
|
||||
import { LbMode, HealthCheckType, IpHealthState, HealthCheckScope, ServiceBinding, Domain, Group, Service, ServiceGroup, Subdomain, DnsRecord, ServiceBindingView, Certificate, GroupWithStats, IpHealthStatus, SyncJob, DomainListItem, HealthCheckTarget } from '@cfdm/shared';
|
||||
|
||||
declare const groups: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
||||
name: "groups";
|
||||
@@ -563,6 +563,23 @@ declare const serviceGroups: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
health_check_verify_tls: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "health_check_verify_tls";
|
||||
tableName: "service_groups";
|
||||
dataType: "boolean";
|
||||
columnType: "SQLiteBoolean";
|
||||
data: boolean;
|
||||
driverParam: number;
|
||||
notNull: true;
|
||||
hasDefault: true;
|
||||
isPrimaryKey: false;
|
||||
isAutoincrement: false;
|
||||
hasRuntimeDefault: false;
|
||||
enumValues: undefined;
|
||||
baseColumn: never;
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "created_at";
|
||||
tableName: "service_groups";
|
||||
@@ -1465,6 +1482,23 @@ declare const serviceBindings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
health_check_verify_tls: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "health_check_verify_tls";
|
||||
tableName: "service_bindings";
|
||||
dataType: "boolean";
|
||||
columnType: "SQLiteBoolean";
|
||||
data: boolean;
|
||||
driverParam: number;
|
||||
notNull: true;
|
||||
hasDefault: true;
|
||||
isPrimaryKey: false;
|
||||
isAutoincrement: false;
|
||||
hasRuntimeDefault: false;
|
||||
enumValues: undefined;
|
||||
baseColumn: never;
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "created_at";
|
||||
tableName: "service_bindings";
|
||||
@@ -3552,6 +3586,23 @@ declare const schema: {
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
health_check_verify_tls: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "health_check_verify_tls";
|
||||
tableName: "service_groups";
|
||||
dataType: "boolean";
|
||||
columnType: "SQLiteBoolean";
|
||||
data: boolean;
|
||||
driverParam: number;
|
||||
notNull: true;
|
||||
hasDefault: true;
|
||||
isPrimaryKey: false;
|
||||
isAutoincrement: false;
|
||||
hasRuntimeDefault: false;
|
||||
enumValues: undefined;
|
||||
baseColumn: never;
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "created_at";
|
||||
tableName: "service_groups";
|
||||
@@ -4454,6 +4505,23 @@ declare const schema: {
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
health_check_verify_tls: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "health_check_verify_tls";
|
||||
tableName: "service_bindings";
|
||||
dataType: "boolean";
|
||||
columnType: "SQLiteBoolean";
|
||||
data: boolean;
|
||||
driverParam: number;
|
||||
notNull: true;
|
||||
hasDefault: true;
|
||||
isPrimaryKey: false;
|
||||
isAutoincrement: false;
|
||||
hasRuntimeDefault: false;
|
||||
enumValues: undefined;
|
||||
baseColumn: never;
|
||||
identity: undefined;
|
||||
generated: undefined;
|
||||
}, {}, {}>;
|
||||
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
|
||||
name: "created_at";
|
||||
tableName: "service_bindings";
|
||||
@@ -6005,7 +6073,6 @@ declare class ConflictError extends Error {
|
||||
|
||||
type AppSettingsDto = {
|
||||
id: string;
|
||||
appSwitcher: AppSwitcherConfig;
|
||||
vpsTrackerUrl: string;
|
||||
vpsTrackerIntegrationTokenSet: boolean;
|
||||
vpsTrackerSyncEnabled: boolean;
|
||||
@@ -6013,7 +6080,6 @@ type AppSettingsDto = {
|
||||
showQuickActions: boolean;
|
||||
};
|
||||
type AppSettingsPatch = {
|
||||
appSwitcher?: AppSwitcherConfig;
|
||||
vpsTrackerUrl?: string;
|
||||
vpsTrackerIntegrationToken?: string;
|
||||
vpsTrackerSyncEnabled?: boolean;
|
||||
@@ -6027,7 +6093,6 @@ declare function getAppSettingsSecrets(db: Db): {
|
||||
};
|
||||
declare function updateAppSettings(db: Db, patch: AppSettingsPatch): AppSettingsDto;
|
||||
declare function touchVpsTrackerSync(db: Db): void;
|
||||
declare function getAppSwitcher(db: Db): AppSwitcherConfig;
|
||||
|
||||
interface DnsListFilter {
|
||||
record_type?: string;
|
||||
@@ -6105,6 +6170,7 @@ interface ServiceGroupLbPatch {
|
||||
health_check_expected_status?: number | null;
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
}
|
||||
declare function createServiceGroup(db: Db, name: string, groupType: string, icon: string | null, domain: string | null, lbPatch?: ServiceGroupLbPatch): ServiceGroup;
|
||||
declare function updateServiceGroup(db: Db, id: number, name: string, groupType: string, icon: string | null, domain: string | null, lbPatch?: ServiceGroupLbPatch): ServiceGroup;
|
||||
@@ -6130,6 +6196,7 @@ interface BindingLbPatch {
|
||||
health_check_expected_status?: number | null;
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
}
|
||||
declare function updateBindingLbConfig(db: Db, bindingId: number, patch: BindingLbPatch): void;
|
||||
declare function setBindingCnameTarget(db: Db, bindingId: number, target: string | null): void;
|
||||
@@ -6362,4 +6429,4 @@ declare namespace repos {
|
||||
export { type repos_BindingIpMeta as BindingIpMeta, type repos_BindingLbPatch as BindingLbPatch, type repos_DnsListFilter as DnsListFilter, type repos_DomainMonitorRow as DomainMonitorRow, type repos_HealthAggregate as HealthAggregate, type repos_ServiceGroupLbPatch as ServiceGroupLbPatch, type repos_UpdateSubdomainPatch as UpdateSubdomainPatch, repos_addDomainTags as addDomainTags, repos_aggregateIpHealthByRefs as aggregateIpHealthByRefs, repos_aggregateIpHealthByServiceIds as aggregateIpHealthByServiceIds, repos_bindingsToRemove as bindingsToRemove, repos_countCertificatesByStatus as countCertificatesByStatus, repos_createDomain as createDomain, repos_createDomainMonitor as createDomainMonitor, repos_createGroup as createGroup, repos_createService as createService, repos_createServiceGroup as createServiceGroup, repos_createSubdomain as createSubdomain, repos_createSyncJob as createSyncJob, repos_deleteBinding as deleteBinding, repos_deleteBindingsExcept as deleteBindingsExcept, repos_deleteCertificatesNotIn as deleteCertificatesNotIn, repos_deleteDnsRecord as deleteDnsRecord, repos_deleteDomain as deleteDomain, repos_deleteDomainMonitor as deleteDomainMonitor, repos_deleteGroup as deleteGroup, repos_deleteIpHealthStatusForIp as deleteIpHealthStatusForIp, repos_deleteIpHealthStatusForRef as deleteIpHealthStatusForRef, repos_deleteService as deleteService, repos_deleteServiceGroup as deleteServiceGroup, repos_deleteSubdomain as deleteSubdomain, repos_findBinding as findBinding, repos_findDnsByCfId as findDnsByCfId, repos_findDomainByZoneName as findDomainByZoneName, repos_findSubdomainByDomainAndName as findSubdomainByDomainAndName, repos_finishSyncJob as finishSyncJob, repos_getBinding as getBinding, repos_getBindingView as getBindingView, repos_getCertificate as getCertificate, repos_getDnsRecord as getDnsRecord, repos_getDomain as getDomain, repos_getDomainMonitor as getDomainMonitor, repos_getGroup as getGroup, repos_getGroupWithStats as getGroupWithStats, repos_getIpHealthStatusRow as getIpHealthStatusRow, repos_getService as getService, repos_getServiceGroup as getServiceGroup, repos_getSubdomain as getSubdomain, repos_getSyncJob as getSyncJob, repos_insertBinding as insertBinding, repos_insertDnsRecord as insertDnsRecord, repos_insertNotificationLog as insertNotificationLog, repos_linkBindingRecord as linkBindingRecord, repos_linkGroupDnsRecord as linkGroupDnsRecord, repos_listAllBindings as listAllBindings, repos_listAllDomains as listAllDomains, repos_listAllSubdomains as listAllSubdomains, repos_listBindingIps as listBindingIps, repos_listBindingIpsWithMeta as listBindingIpsWithMeta, repos_listBindingsByDomain as listBindingsByDomain, repos_listBindingsByService as listBindingsByService, repos_listCertificates as listCertificates, repos_listDnsByDomain as listDnsByDomain, repos_listDnsRecords as listDnsRecords, repos_listDomainMonitorResults as listDomainMonitorResults, repos_listDomainMonitorResultsForDomain as listDomainMonitorResultsForDomain, repos_listDomainMonitors as listDomainMonitors, repos_listDomainTags as listDomainTags, repos_listDomains as listDomains, repos_listDomainsEnriched as listDomainsEnriched, repos_listEnabledDomainMonitors as listEnabledDomainMonitors, repos_listGroupDnsRecords as listGroupDnsRecords, repos_listGroups as listGroups, repos_listHealthCheckTargets as listHealthCheckTargets, repos_listIpHealthStatus as listIpHealthStatus, repos_listNotificationLog as listNotificationLog, repos_listRecordsForBinding as listRecordsForBinding, repos_listServiceGroups as listServiceGroups, repos_listServiceIps as listServiceIps, repos_listServices as listServices, repos_listServicesByGroup as listServicesByGroup, repos_listSubdomainsByDomain as listSubdomainsByDomain, repos_listUngroupedServices as listUngroupedServices, repos_markDnsPendingDelete as markDnsPendingDelete, repos_mergeHealthAggregates as mergeHealthAggregates, repos_pruneStaleIpHealthStatus as pruneStaleIpHealthStatus, repos_reorderServices as reorderServices, repos_replaceBindingIps as replaceBindingIps, repos_replaceBindingIpsWithMeta as replaceBindingIpsWithMeta, repos_replaceServiceIps as replaceServiceIps, repos_setBindingCnameTarget as setBindingCnameTarget, repos_setBindingDnsRecordId as setBindingDnsRecordId, repos_setDnsSyncStatus as setDnsSyncStatus, repos_setDomainLastSynced as setDomainLastSynced, repos_setDomainTags as setDomainTags, repos_setServiceEnabled as setServiceEnabled, repos_setServiceGroup as setServiceGroup, repos_setServiceGroupEnabled as setServiceGroupEnabled, repos_setServiceLb as setServiceLb, repos_unlinkBindingRecord as unlinkBindingRecord, repos_unlinkGroupDnsRecord as unlinkGroupDnsRecord, repos_updateBindingFields as updateBindingFields, repos_updateBindingLbConfig as updateBindingLbConfig, repos_updateDnsFields as updateDnsFields, repos_updateDomain as updateDomain, repos_updateDomainMonitorResult as updateDomainMonitorResult, repos_updateGroup as updateGroup, repos_updateServiLine truncated
|
||||
}
|
||||
|
||||
export { type AppSettingsDto, type AppSettingsPatch, ConflictError, type Db, type DnsListFilter, NotFoundError, type Sqlite, type UpdateSubdomainPatch, appSettings, certificates, createDb, createMemoryDb, dnsRecords, domainMonitorResults, domainMonitors, domainTags, domains, getAppSettings, getAppSettingsSecrets, getAppSwitcher, groups, healthCheck, ipHealthStatus, notificationLog, repos, resolveDatabasePath, runMigrations, schema, serviceBindingIps, serviceBindingRecords, serviceBindings, serviceGroupDnsRecords, serviceGroups, serviceIps, services, subdomains, syncJobs, touchVpsTrackerSync, updateAppSettings };
|
||||
export { type AppSettingsDto, type AppSettingsPatch, ConflictError, type Db, type DnsListFilter, NotFoundError, type Sqlite, type UpdateSubdomainPatch, appSettings, certificates, createDb, createMemoryDb, dnsRecords, domainMonitorResults, domainMonitors, domainTags, domains, getAppSettings, getAppSettingsSecrets, groups, healthCheck, ipHealthStatus, notificationLog, repos, resolveDatabasePath, runMigrations, schema, serviceBindingIps, serviceBindingRecords, serviceBindings, serviceGroupDnsRecords, serviceGroups, serviceIps, services, subdomains, syncJobs, touchVpsTrackerSync, updateAppSettings };
|
||||
Vendored
+26
-52
@@ -50,6 +50,7 @@ var serviceGroups = sqliteTable("service_groups", {
|
||||
health_check_expected_status: integer("health_check_expected_status"),
|
||||
health_check_interval_sec: integer("health_check_interval_sec").notNull().default(30),
|
||||
health_check_timeout_ms: integer("health_check_timeout_ms").notNull().default(3e3),
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" }).notNull().default(false),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
@@ -110,6 +111,7 @@ var serviceBindings = sqliteTable("service_bindings", {
|
||||
health_check_expected_status: integer("health_check_expected_status"),
|
||||
health_check_interval_sec: integer("health_check_interval_sec").notNull().default(30),
|
||||
health_check_timeout_ms: integer("health_check_timeout_ms").notNull().default(3e3),
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" }).notNull().default(false),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
@@ -188,6 +190,7 @@ var ipHealthStatus = sqliteTable(
|
||||
var appSettings = sqliteTable("app_settings", {
|
||||
id: text("id").primaryKey(),
|
||||
app_switcher_json: text("app_switcher_json"),
|
||||
// deprecated: portal is SoT; column kept for migrate compat
|
||||
vps_tracker_url: text("vps_tracker_url"),
|
||||
vps_tracker_integration_token: text("vps_tracker_integration_token"),
|
||||
vps_tracker_sync_enabled: integer("vps_tracker_sync_enabled", {
|
||||
@@ -328,49 +331,10 @@ var ConflictError = class extends Error {
|
||||
|
||||
// src/settings-repo.ts
|
||||
import { eq } from "drizzle-orm";
|
||||
import { appSwitcherConfigSchema } from "@cfdm/shared";
|
||||
var SETTINGS_ID = "settings-main";
|
||||
var DEFAULT_APP_SWITCHER = {
|
||||
menuLabel: "\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F",
|
||||
apps: [
|
||||
{
|
||||
id: "vps-tracker",
|
||||
name: "VPS Tracker",
|
||||
subtitle: "\u0423\u0447\u0451\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043B\u044C\u043D\u044B\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u0432",
|
||||
url: "http://192.168.100.67:3001",
|
||||
icon: "server",
|
||||
shortcut: "\u23181"
|
||||
},
|
||||
{
|
||||
id: "cfdm",
|
||||
name: "CF Domain Manager",
|
||||
subtitle: "\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u043E\u043C\u0435\u043D\u0430\u043C\u0438",
|
||||
url: "http://192.168.100.67:6363",
|
||||
icon: "cloud",
|
||||
shortcut: "\u23182"
|
||||
},
|
||||
{
|
||||
id: "evobgp",
|
||||
name: "EvoBGP",
|
||||
subtitle: "BGP \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044F",
|
||||
url: "http://192.168.100.67:3000",
|
||||
icon: "globe",
|
||||
shortcut: "\u23183"
|
||||
}
|
||||
]
|
||||
};
|
||||
function parseAppSwitcher(raw) {
|
||||
if (!raw?.trim()) return DEFAULT_APP_SWITCHER;
|
||||
try {
|
||||
return appSwitcherConfigSchema.parse(JSON.parse(raw));
|
||||
} catch {
|
||||
return DEFAULT_APP_SWITCHER;
|
||||
}
|
||||
}
|
||||
function toDto(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
appSwitcher: parseAppSwitcher(row.app_switcher_json),
|
||||
vpsTrackerUrl: row.vps_tracker_url?.trim() ?? "",
|
||||
vpsTrackerIntegrationTokenSet: Boolean(
|
||||
row.vps_tracker_integration_token?.trim()
|
||||
@@ -405,7 +369,7 @@ function updateAppSettings(db, patch) {
|
||||
}
|
||||
const current = db.select().from(appSettings).where(eq(appSettings.id, SETTINGS_ID)).get();
|
||||
db.update(appSettings).set({
|
||||
app_switcher_json: patch.appSwitcher !== void 0 ? JSON.stringify(patch.appSwitcher) : current.app_switcher_json,
|
||||
// app_switcher_json: deprecated — source of truth is auth-portal
|
||||
vps_tracker_url: patch.vpsTrackerUrl !== void 0 ? patch.vpsTrackerUrl : current.vps_tracker_url,
|
||||
vps_tracker_integration_token: patch.vpsTrackerIntegrationToken !== void 0 && patch.vpsTrackerIntegrationToken.trim() !== "" ? patch.vpsTrackerIntegrationToken : current.vps_tracker_integration_token,
|
||||
vps_tracker_sync_enabled: patch.vpsTrackerSyncEnabled !== void 0 ? patch.vpsTrackerSyncEnabled : current.vps_tracker_sync_enabled,
|
||||
@@ -420,9 +384,6 @@ function touchVpsTrackerSync(db) {
|
||||
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
||||
}).where(eq(appSettings.id, SETTINGS_ID)).run();
|
||||
}
|
||||
function getAppSwitcher(db) {
|
||||
return getAppSettings(db).appSwitcher;
|
||||
}
|
||||
|
||||
// src/repos.ts
|
||||
var repos_exports = {};
|
||||
@@ -910,6 +871,7 @@ function mapServiceGroup(row) {
|
||||
health_check_expected_status: row.health_check_expected_status,
|
||||
health_check_interval_sec: row.health_check_interval_sec,
|
||||
health_check_timeout_ms: row.health_check_timeout_ms,
|
||||
health_check_verify_tls: row.health_check_verify_tls,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
@@ -935,7 +897,8 @@ function createServiceGroup(db, name, groupType, icon, domain, lbPatch) {
|
||||
health_check_path: lbPatch?.health_check_path ?? null,
|
||||
health_check_expected_status: lbPatch?.health_check_expected_status ?? null,
|
||||
health_check_interval_sec: lbPatch?.health_check_interval_sec ?? 30,
|
||||
health_check_timeout_ms: lbPatch?.health_check_timeout_ms ?? 3e3
|
||||
health_check_timeout_ms: lbPatch?.health_check_timeout_ms ?? 3e3,
|
||||
health_check_verify_tls: lbPatch?.health_check_verify_tls ?? false
|
||||
}).returning({ id: serviceGroups.id }).get().id;
|
||||
return getServiceGroup(db, id);
|
||||
}
|
||||
@@ -963,6 +926,8 @@ function updateServiceGroup(db, id, name, groupType, icon, domain, lbPatch) {
|
||||
update.health_check_interval_sec = lbPatch.health_check_interval_sec;
|
||||
if (lbPatch.health_check_timeout_ms !== void 0)
|
||||
update.health_check_timeout_ms = lbPatch.health_check_timeout_ms;
|
||||
if (lbPatch.health_check_verify_tls !== void 0)
|
||||
update.health_check_verify_tls = lbPatch.health_check_verify_tls;
|
||||
}
|
||||
const result = db.update(serviceGroups).set(update).where(eq2(serviceGroups.id, id)).run();
|
||||
if (result.changes === 0) throw new NotFoundError(`service group ${id}`);
|
||||
@@ -1033,6 +998,8 @@ function updateBindingLbConfig(db, bindingId, patch) {
|
||||
update.health_check_interval_sec = patch.health_check_interval_sec;
|
||||
if (patch.health_check_timeout_ms !== void 0)
|
||||
update.health_check_timeout_ms = patch.health_check_timeout_ms;
|
||||
if (patch.health_check_verify_tls !== void 0)
|
||||
update.health_check_verify_tls = patch.health_check_verify_tls;
|
||||
db.update(serviceBindings).set(update).where(eq2(serviceBindings.id, bindingId)).run();
|
||||
}
|
||||
function setBindingCnameTarget(db, bindingId, target) {
|
||||
@@ -1091,7 +1058,7 @@ function dnsRecordMatchesHostname(recordName, hostname, zoneName) {
|
||||
var SERVICE_BINDING_SELECT_COLUMNS = `sb.id, sb.domain_id, sb.service_id, sb.hostname, sb.dns_record_id,
|
||||
sb.lb_mode, sb.health_check_enabled, sb.health_check_type, sb.health_check_port,
|
||||
sb.health_check_path, sb.health_check_expected_status, sb.health_check_interval_sec,
|
||||
sb.health_check_timeout_ms, sb.cname_target,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.cname_target,
|
||||
d.zone_name, d.group_id, g.name AS group_name,
|
||||
s.name AS service_name, s.slug AS service_slug,
|
||||
dr.content AS target_ip, dr.sync_status,
|
||||
@@ -1492,7 +1459,8 @@ function listHealthCheckTargets(db) {
|
||||
sb.health_check_port AS port,
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -1505,7 +1473,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM services s
|
||||
JOIN service_ips sip ON sip.service_id = s.id
|
||||
JOIN service_groups sg ON sg.id = s.service_group_id
|
||||
@@ -1521,7 +1490,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -1540,7 +1510,8 @@ function listHealthCheckTargets(db) {
|
||||
sb.health_check_port AS port,
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -1556,7 +1527,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -1575,7 +1547,10 @@ function listHealthCheckTargets(db) {
|
||||
...groupInheritedBindingTargets,
|
||||
...cnameBindingTargets,
|
||||
...groupInheritedCnameBindingTargets
|
||||
];
|
||||
].map((t) => ({
|
||||
...t,
|
||||
verify_tls: Boolean(t.verify_tls)
|
||||
}));
|
||||
}
|
||||
function listDomainTags(db, domainId) {
|
||||
return db.select({ tag: domainTags.tag }).from(domainTags).where(eq2(domainTags.domain_id, domainId)).all().map((r) => r.tag);
|
||||
@@ -1700,7 +1675,6 @@ export {
|
||||
domains,
|
||||
getAppSettings,
|
||||
getAppSettingsSecrets,
|
||||
getAppSwitcher,
|
||||
groups,
|
||||
healthCheck,
|
||||
ipHealthStatus,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE service_groups ADD COLUMN health_check_verify_tls INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE service_bindings ADD COLUMN health_check_verify_tls INTEGER NOT NULL DEFAULT 0;
|
||||
@@ -736,6 +736,7 @@ function mapServiceGroup(row: typeof serviceGroups.$inferSelect): ServiceGroup {
|
||||
health_check_expected_status: row.health_check_expected_status,
|
||||
health_check_interval_sec: row.health_check_interval_sec,
|
||||
health_check_timeout_ms: row.health_check_timeout_ms,
|
||||
health_check_verify_tls: row.health_check_verify_tls,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at,
|
||||
};
|
||||
@@ -769,6 +770,7 @@ export interface ServiceGroupLbPatch {
|
||||
health_check_expected_status?: number | null;
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
}
|
||||
|
||||
export function createServiceGroup(
|
||||
@@ -794,6 +796,7 @@ export function createServiceGroup(
|
||||
health_check_expected_status: lbPatch?.health_check_expected_status ?? null,
|
||||
health_check_interval_sec: lbPatch?.health_check_interval_sec ?? 30,
|
||||
health_check_timeout_ms: lbPatch?.health_check_timeout_ms ?? 3000,
|
||||
health_check_verify_tls: lbPatch?.health_check_verify_tls ?? false,
|
||||
})
|
||||
.returning({ id: serviceGroups.id })
|
||||
.get()!.id;
|
||||
@@ -832,6 +835,8 @@ export function updateServiceGroup(
|
||||
update.health_check_interval_sec = lbPatch.health_check_interval_sec;
|
||||
if (lbPatch.health_check_timeout_ms !== undefined)
|
||||
update.health_check_timeout_ms = lbPatch.health_check_timeout_ms;
|
||||
if (lbPatch.health_check_verify_tls !== undefined)
|
||||
update.health_check_verify_tls = lbPatch.health_check_verify_tls;
|
||||
}
|
||||
const result = db
|
||||
.update(serviceGroups)
|
||||
@@ -956,6 +961,7 @@ export interface BindingLbPatch {
|
||||
health_check_expected_status?: number | null;
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
}
|
||||
|
||||
export function updateBindingLbConfig(
|
||||
@@ -981,6 +987,8 @@ export function updateBindingLbConfig(
|
||||
update.health_check_interval_sec = patch.health_check_interval_sec;
|
||||
if (patch.health_check_timeout_ms !== undefined)
|
||||
update.health_check_timeout_ms = patch.health_check_timeout_ms;
|
||||
if (patch.health_check_verify_tls !== undefined)
|
||||
update.health_check_verify_tls = patch.health_check_verify_tls;
|
||||
db.update(serviceBindings)
|
||||
.set(update)
|
||||
.where(eq(serviceBindings.id, bindingId))
|
||||
@@ -1088,7 +1096,7 @@ function dnsRecordMatchesHostname(
|
||||
const SERVICE_BINDING_SELECT_COLUMNS = `sb.id, sb.domain_id, sb.service_id, sb.hostname, sb.dns_record_id,
|
||||
sb.lb_mode, sb.health_check_enabled, sb.health_check_type, sb.health_check_port,
|
||||
sb.health_check_path, sb.health_check_expected_status, sb.health_check_interval_sec,
|
||||
sb.health_check_timeout_ms, sb.cname_target,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.cname_target,
|
||||
d.zone_name, d.group_id, g.name AS group_name,
|
||||
s.name AS service_name, s.slug AS service_slug,
|
||||
dr.content AS target_ip, dr.sync_status,
|
||||
@@ -1734,7 +1742,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sb.health_check_port AS port,
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -1748,7 +1757,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM services s
|
||||
JOIN service_ips sip ON sip.service_id = s.id
|
||||
JOIN service_groups sg ON sg.id = s.service_group_id
|
||||
@@ -1769,7 +1779,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -1790,7 +1801,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sb.health_check_port AS port,
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -1809,7 +1821,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_port AS port,
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -1829,7 +1842,10 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
...groupInheritedBindingTargets,
|
||||
...cnameBindingTargets,
|
||||
...groupInheritedCnameBindingTargets,
|
||||
];
|
||||
].map((t) => ({
|
||||
...t,
|
||||
verify_tls: Boolean(t.verify_tls),
|
||||
}));
|
||||
}
|
||||
|
||||
// --- Domain tags ---
|
||||
|
||||
@@ -60,6 +60,9 @@ export const serviceGroups = sqliteTable("service_groups", {
|
||||
health_check_timeout_ms: integer("health_check_timeout_ms")
|
||||
.notNull()
|
||||
.default(3000),
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
created_at: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
@@ -154,6 +157,9 @@ export const serviceBindings = sqliteTable("service_bindings", {
|
||||
health_check_timeout_ms: integer("health_check_timeout_ms")
|
||||
.notNull()
|
||||
.default(3000),
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
created_at: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
@@ -271,7 +277,7 @@ export const ipHealthStatus = sqliteTable(
|
||||
|
||||
export const appSettings = sqliteTable("app_settings", {
|
||||
id: text("id").primaryKey(),
|
||||
app_switcher_json: text("app_switcher_json"),
|
||||
app_switcher_json: text("app_switcher_json"), // deprecated: portal is SoT; column kept for migrate compat
|
||||
vps_tracker_url: text("vps_tracker_url"),
|
||||
vps_tracker_integration_token: text("vps_tracker_integration_token"),
|
||||
vps_tracker_sync_enabled: integer("vps_tracker_sync_enabled", {
|
||||
|
||||
@@ -1,43 +1,11 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { appSwitcherConfigSchema, type AppSwitcherConfig } from "@cfdm/shared";
|
||||
import type { Db } from "./client.js";
|
||||
import { appSettings } from "./schema.js";
|
||||
|
||||
const SETTINGS_ID = "settings-main";
|
||||
|
||||
const DEFAULT_APP_SWITCHER: AppSwitcherConfig = {
|
||||
menuLabel: "Приложения",
|
||||
apps: [
|
||||
{
|
||||
id: "vps-tracker",
|
||||
name: "VPS Tracker",
|
||||
subtitle: "Учёт виртуальных серверов",
|
||||
url: "http://192.168.100.67:3001",
|
||||
icon: "server",
|
||||
shortcut: "⌘1",
|
||||
},
|
||||
{
|
||||
id: "cfdm",
|
||||
name: "CF Domain Manager",
|
||||
subtitle: "Управление доменами",
|
||||
url: "http://192.168.100.67:6363",
|
||||
icon: "cloud",
|
||||
shortcut: "⌘2",
|
||||
},
|
||||
{
|
||||
id: "evobgp",
|
||||
name: "EvoBGP",
|
||||
subtitle: "BGP маршрутизация",
|
||||
url: "http://192.168.100.67:3000",
|
||||
icon: "globe",
|
||||
shortcut: "⌘3",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export type AppSettingsDto = {
|
||||
id: string;
|
||||
appSwitcher: AppSwitcherConfig;
|
||||
vpsTrackerUrl: string;
|
||||
vpsTrackerIntegrationTokenSet: boolean;
|
||||
vpsTrackerSyncEnabled: boolean;
|
||||
@@ -46,26 +14,15 @@ export type AppSettingsDto = {
|
||||
};
|
||||
|
||||
export type AppSettingsPatch = {
|
||||
appSwitcher?: AppSwitcherConfig;
|
||||
vpsTrackerUrl?: string;
|
||||
vpsTrackerIntegrationToken?: string;
|
||||
vpsTrackerSyncEnabled?: boolean;
|
||||
showQuickActions?: boolean;
|
||||
};
|
||||
|
||||
function parseAppSwitcher(raw: string | null | undefined): AppSwitcherConfig {
|
||||
if (!raw?.trim()) return DEFAULT_APP_SWITCHER;
|
||||
try {
|
||||
return appSwitcherConfigSchema.parse(JSON.parse(raw));
|
||||
} catch {
|
||||
return DEFAULT_APP_SWITCHER;
|
||||
}
|
||||
}
|
||||
|
||||
function toDto(row: typeof appSettings.$inferSelect): AppSettingsDto {
|
||||
return {
|
||||
id: row.id,
|
||||
appSwitcher: parseAppSwitcher(row.app_switcher_json),
|
||||
vpsTrackerUrl: row.vps_tracker_url?.trim() ?? "",
|
||||
vpsTrackerIntegrationTokenSet: Boolean(
|
||||
row.vps_tracker_integration_token?.trim(),
|
||||
@@ -127,10 +84,7 @@ export function updateAppSettings(db: Db, patch: AppSettingsPatch): AppSettingsD
|
||||
|
||||
db.update(appSettings)
|
||||
.set({
|
||||
app_switcher_json:
|
||||
patch.appSwitcher !== undefined
|
||||
? JSON.stringify(patch.appSwitcher)
|
||||
: current.app_switcher_json,
|
||||
// app_switcher_json: deprecated — source of truth is auth-portal
|
||||
vps_tracker_url:
|
||||
patch.vpsTrackerUrl !== undefined
|
||||
? patch.vpsTrackerUrl
|
||||
@@ -165,7 +119,3 @@ export function touchVpsTrackerSync(db: Db): void {
|
||||
.where(eq(appSettings.id, SETTINGS_ID))
|
||||
.run();
|
||||
}
|
||||
|
||||
export function getAppSwitcher(db: Db): AppSwitcherConfig {
|
||||
return getAppSettings(db).appSwitcher;
|
||||
}
|
||||
Reference in new issue
Block a user