@celilo/cli 0.3.30-alpha.0 → 0.4.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/drizzle/0005_module_operations.sql +12 -0
- package/drizzle/0006_base_module_aspects.sql +15 -0
- package/drizzle/0007_module_systems.sql +17 -0
- package/drizzle/meta/_journal.json +21 -0
- package/package.json +3 -3
- package/schemas/system_config.json +14 -28
- package/src/ansible/inventory.test.ts +46 -62
- package/src/ansible/inventory.ts +48 -25
- package/src/capabilities/registration.ts +25 -7
- package/src/capabilities/validation.test.ts +30 -0
- package/src/capabilities/validation.ts +8 -0
- package/src/cli/backup-rename.test.ts +95 -0
- package/src/cli/cli.test.ts +17 -23
- package/src/cli/command-registry.ts +199 -0
- package/src/cli/commands/backup-list.ts +1 -1
- package/src/cli/commands/events.ts +96 -0
- package/src/cli/commands/machine-add.ts +103 -59
- package/src/cli/commands/module-import.ts +153 -4
- package/src/cli/commands/module-remove.ts +86 -17
- package/src/cli/commands/module-status.ts +6 -2
- package/src/cli/commands/publish/alpha.test.ts +185 -0
- package/src/cli/commands/publish/alpha.ts +226 -0
- package/src/cli/commands/publish/changesets.test.ts +89 -0
- package/src/cli/commands/publish/changesets.ts +144 -0
- package/src/cli/commands/publish/consumer-pins.test.ts +155 -0
- package/src/cli/commands/publish/consumer-pins.ts +149 -0
- package/src/cli/commands/publish/execute.ts +131 -0
- package/src/cli/commands/publish/global-install.test.ts +154 -0
- package/src/cli/commands/publish/global-install.ts +171 -0
- package/src/cli/commands/publish/helpers.ts +227 -0
- package/src/cli/commands/publish/index.ts +365 -0
- package/src/cli/commands/publish/module-registry.test.ts +40 -0
- package/src/cli/commands/publish/module-registry.ts +64 -0
- package/src/cli/commands/publish/plan.ts +107 -0
- package/src/cli/commands/publish/preflight.ts +238 -0
- package/src/cli/commands/publish/types.ts +264 -0
- package/src/cli/commands/publish/workspace.test.ts +323 -0
- package/src/cli/commands/publish/workspace.ts +596 -0
- package/src/cli/commands/restore.ts +126 -0
- package/src/cli/commands/storage-add-local.ts +1 -1
- package/src/cli/commands/storage-add-s3.ts +1 -1
- package/src/cli/commands/subscribers-add.ts +68 -0
- package/src/cli/commands/subscribers-list.ts +48 -0
- package/src/cli/commands/subscribers-remove.ts +38 -0
- package/src/cli/commands/subscribers-serve.ts +77 -0
- package/src/cli/commands/subscribers-status.ts +33 -0
- package/src/cli/commands/subscribers-test.ts +71 -0
- package/src/cli/commands/system-apply-config-equivalence.test.ts +108 -0
- package/src/cli/commands/system-apply-config.test.ts +70 -0
- package/src/cli/commands/system-apply-config.ts +130 -0
- package/src/cli/commands/system-audit.ts +2 -1
- package/src/cli/commands/system-init-deprecation.test.ts +90 -0
- package/src/cli/commands/system-init.ts +36 -70
- package/src/cli/commands/system-update.ts +3 -2
- package/src/cli/completion.ts +22 -1
- package/src/cli/index.ts +214 -6
- package/src/cli/interactive-config.test.ts +19 -0
- package/src/cli/restore-command.test.ts +131 -0
- package/src/db/client.ts +42 -0
- package/src/db/schema.test.ts +13 -16
- package/src/db/schema.ts +161 -9
- package/src/hooks/capability-loader-firewall.test.ts +6 -15
- package/src/hooks/capability-loader.test.ts +2 -3
- package/src/hooks/capability-loader.ts +36 -2
- package/src/hooks/define-hook.test.ts +4 -0
- package/src/hooks/executor.test.ts +18 -0
- package/src/hooks/executor.ts +21 -2
- package/src/hooks/load-hook-config.test.ts +26 -24
- package/src/hooks/load-hook-config.ts +11 -2
- package/src/hooks/run-named-hook.ts +16 -0
- package/src/hooks/types.ts +9 -1
- package/src/manifest/contracts/v1.ts +70 -0
- package/src/manifest/schema.ts +262 -16
- package/src/manifest/validate-privileged.test.ts +84 -0
- package/src/manifest/validate.test.ts +156 -0
- package/src/manifest/validate.ts +69 -0
- package/src/module/import.ts +12 -0
- package/src/services/aspect-approvals.test.ts +231 -0
- package/src/services/aspect-approvals.ts +120 -0
- package/src/services/aspect-runner.test.ts +493 -0
- package/src/services/aspect-runner.ts +438 -0
- package/src/services/aspect-template-resolver.test.ts +101 -0
- package/src/services/aspect-template-resolver.ts +122 -0
- package/src/services/backup-create.ts +104 -25
- package/src/services/backup-envelope-roundtrip.test.ts +199 -0
- package/src/services/backup-in-flight-refusal.test.ts +163 -0
- package/src/services/backup-manifest.test.ts +115 -0
- package/src/services/backup-manifest.ts +163 -0
- package/src/services/backup-restore.ts +154 -19
- package/src/services/build-bus/delivery-events.ts +92 -0
- package/src/services/build-bus/event-factory.ts +54 -0
- package/src/services/build-bus/fan-out.test.ts +279 -0
- package/src/services/build-bus/fan-out.ts +161 -0
- package/src/services/build-bus/hook-dispatch-mgmt.test.ts +157 -0
- package/src/services/build-bus/hook-dispatch.test.ts +207 -0
- package/src/services/build-bus/hook-dispatch.ts +198 -0
- package/src/services/build-bus/hook-dispatcher.ts +115 -0
- package/src/services/build-bus/index.ts +41 -0
- package/src/services/build-bus/receiver-server.test.ts +179 -0
- package/src/services/build-bus/receiver-server.ts +159 -0
- package/src/services/build-bus/status.test.ts +212 -0
- package/src/services/build-bus/status.ts +213 -0
- package/src/services/build-bus/subscriber-store.ts +113 -0
- package/src/services/celilo-events.test.ts +70 -0
- package/src/services/celilo-events.ts +92 -0
- package/src/services/celilo-mgmt-hooks.test.ts +296 -0
- package/src/services/config-interview.ts +13 -95
- package/src/services/cross-module-data-manager.ts +2 -31
- package/src/services/cross-module-read.test.ts +250 -0
- package/src/services/cross-module-read.ts +232 -0
- package/src/services/deploy-validation.ts +7 -0
- package/src/services/deployed-systems.test.ts +235 -0
- package/src/services/deployed-systems.ts +308 -0
- package/src/services/dns-provider-backfill.ts +75 -0
- package/src/services/health-runner.ts +19 -3
- package/src/services/infrastructure-variable-resolver.test.ts +6 -32
- package/src/services/infrastructure-variable-resolver.ts +3 -13
- package/src/services/machine-detector.ts +104 -48
- package/src/services/machine-pool.ts +145 -2
- package/src/services/module-config.ts +78 -120
- package/src/services/module-deploy.ts +113 -40
- package/src/services/module-operations.test.ts +154 -0
- package/src/services/module-operations.ts +154 -0
- package/src/services/module-subscriptions.test.ts +58 -0
- package/src/services/module-subscriptions.ts +24 -1
- package/src/services/module-types-generator.test.ts +3 -3
- package/src/services/module-types-generator.ts +7 -2
- package/src/services/proxmox-reconcile.test.ts +333 -0
- package/src/services/proxmox-reconcile.ts +156 -0
- package/src/services/proxmox-state-recovery.ts +3 -24
- package/src/services/restore-from-file.test.ts +177 -0
- package/src/services/restore-from-file.ts +355 -0
- package/src/services/restore-preflight.test.ts +127 -0
- package/src/services/restore-preflight.ts +118 -0
- package/src/services/storage-providers/s3.ts +10 -2
- package/src/services/system-identity.ts +30 -0
- package/src/services/system-init.test.ts +64 -21
- package/src/services/system-init.ts +28 -26
- package/src/templates/generator.test.ts +7 -16
- package/src/templates/generator.ts +28 -115
- package/src/test-utils/integration.ts +5 -2
- package/src/types/infrastructure.ts +8 -0
- package/src/variables/computed/computed-integration.test.ts +191 -0
- package/src/variables/computed/computed.test.ts +177 -0
- package/src/variables/computed/evaluate.ts +271 -0
- package/src/variables/computed/marker.ts +53 -0
- package/src/variables/computed/parse.ts +262 -0
- package/src/variables/computed/provider-lookup.ts +130 -0
- package/src/variables/context.test.ts +89 -28
- package/src/variables/context.ts +196 -191
- package/src/variables/parser.ts +3 -3
- package/src/variables/resolver.test.ts +61 -0
- package/src/variables/resolver.ts +81 -0
- package/src/variables/types.ts +23 -1
- package/src/services/dns-auto-register.ts +0 -211
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { evaluateComputed } from './computed/evaluate';
|
|
2
|
+
import { asComputedExpression } from './computed/marker';
|
|
3
|
+
import { buildProviderLookup } from './computed/provider-lookup';
|
|
1
4
|
import { applyIndex, parsePath, parseVariables } from './parser';
|
|
2
5
|
import type {
|
|
3
6
|
ResolutionContext,
|
|
@@ -70,6 +73,40 @@ export async function resolveVariable(
|
|
|
70
73
|
return { success: true, value };
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
case 'infra': {
|
|
77
|
+
// Format: $infra:<system-name>.<field> — references a deployed system by
|
|
78
|
+
// its stable handle (requires.systems[].name). v2/MODULE_SYSTEMS_ADDRESSING.md.
|
|
79
|
+
const dot = variable.path.indexOf('.');
|
|
80
|
+
if (dot === -1) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
variable: variable.raw,
|
|
84
|
+
error: `Infra variable must be '$infra:<system-name>.<field>' (e.g. $infra:main.ipv4_address); got '${variable.path}'`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const systemName = variable.path.slice(0, dot);
|
|
88
|
+
const field = variable.path.slice(dot + 1);
|
|
89
|
+
const systems = context.systems ?? {};
|
|
90
|
+
const system = systems[systemName];
|
|
91
|
+
if (!system) {
|
|
92
|
+
const known = Object.keys(systems);
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
variable: variable.raw,
|
|
96
|
+
error: `No deployed system named '${systemName}' for module ${context.moduleId}${known.length ? ` (known: ${known.join(', ')})` : ' (none recorded yet)'}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const value = (system as unknown as Record<string, unknown>)[field];
|
|
100
|
+
if (value === undefined || value === '') {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
variable: variable.raw,
|
|
104
|
+
error: `Infra field '${field}' not available on system '${systemName}' (fields: name, hostname, ipv4_address, zone, cidr, vmid)`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { success: true, value: value as string };
|
|
108
|
+
}
|
|
109
|
+
|
|
73
110
|
case 'system_secret': {
|
|
74
111
|
const value = context.systemSecrets[variable.path];
|
|
75
112
|
if (value === undefined) {
|
|
@@ -171,6 +208,50 @@ export async function resolveVariable(
|
|
|
171
208
|
};
|
|
172
209
|
}
|
|
173
210
|
|
|
211
|
+
// Computed field (v2/INTERNAL_DNS_DHCP_AND_SPLIT_HORIZON.md D1):
|
|
212
|
+
// evaluate the DSL expression in the PROVIDER's context. Like the
|
|
213
|
+
// lazy $self: block below, we look up the provider module, but here
|
|
214
|
+
// we build a typed lookup over its config/secrets/system data.
|
|
215
|
+
const computedExpr = asComputedExpression(value);
|
|
216
|
+
if (computedExpr !== null) {
|
|
217
|
+
// Find the provider module (raw SQL, matching the lazy $self: block).
|
|
218
|
+
const providerResult = db.$client
|
|
219
|
+
.prepare(
|
|
220
|
+
`SELECT p.id FROM modules p
|
|
221
|
+
JOIN capabilities c ON p.id = c.module_id
|
|
222
|
+
WHERE c.capability_name = ?
|
|
223
|
+
LIMIT 1`,
|
|
224
|
+
)
|
|
225
|
+
.get(capabilityName) as { id: string } | undefined;
|
|
226
|
+
|
|
227
|
+
if (!providerResult) {
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
variable: variable.raw,
|
|
231
|
+
error: `Capability '${capabilityName}' has a computed field '${fieldPath}' but no provider module was found`,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const lookup = await buildProviderLookup(providerResult.id, db);
|
|
237
|
+
const result = evaluateComputed(computedExpr, lookup);
|
|
238
|
+
// Computed results are often arrays/objects (e.g. domain_list).
|
|
239
|
+
// In a string-template context we serialize non-scalars as JSON;
|
|
240
|
+
// structured consumers read the evaluated value directly.
|
|
241
|
+
const serialized =
|
|
242
|
+
typeof result === 'string' || typeof result === 'number' || typeof result === 'boolean'
|
|
243
|
+
? String(result)
|
|
244
|
+
: JSON.stringify(result);
|
|
245
|
+
return { success: true, value: serialized };
|
|
246
|
+
} catch (error) {
|
|
247
|
+
return {
|
|
248
|
+
success: false,
|
|
249
|
+
variable: variable.raw,
|
|
250
|
+
error: `Failed to evaluate computed field '${fieldPath}' of '${capabilityName}': ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
174
255
|
// Check if value contains unresolved $self: variable (lazy resolution)
|
|
175
256
|
if (typeof value === 'string' && value.startsWith('$self:')) {
|
|
176
257
|
// Get provider module's config to resolve the variable.
|
package/src/variables/types.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Example: $self:target_ip -> { type: 'self', path: 'target_ip', raw: '$self:target_ip' }
|
|
8
8
|
*/
|
|
9
9
|
export interface VariableReference {
|
|
10
|
-
type: 'self' | 'system' | 'system_secret' | 'secret' | 'capability';
|
|
10
|
+
type: 'self' | 'system' | 'system_secret' | 'secret' | 'capability' | 'infra';
|
|
11
11
|
path: string;
|
|
12
12
|
raw: string;
|
|
13
13
|
}
|
|
@@ -22,6 +22,28 @@ export interface ResolutionContext {
|
|
|
22
22
|
systemSecrets: Record<string, string>;
|
|
23
23
|
secrets: Record<string, string>;
|
|
24
24
|
capabilities: Record<string, Record<string, unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* The module's deployed systems, keyed by name, for `$infra:<name>.<field>`
|
|
27
|
+
* resolution at generate time (v2/MODULE_SYSTEMS_ADDRESSING.md). Each value
|
|
28
|
+
* exposes the snake_cased fields a template can reference: `ipv4_address`,
|
|
29
|
+
* `hostname`, `zone`, `vmid`, `cidr`. Optional only so the many test-stub
|
|
30
|
+
* `ResolutionContext` literals need no churn — production (buildResolutionContext)
|
|
31
|
+
* always populates it; the resolver treats undefined as the empty map.
|
|
32
|
+
*/
|
|
33
|
+
systems?: Record<string, InfraSystemFields>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The `$infra:<name>.<field>` fields a template can read for one deployed
|
|
38
|
+
* system. `cidr` is derived (ipv4_address + the zone's prefix length).
|
|
39
|
+
*/
|
|
40
|
+
export interface InfraSystemFields {
|
|
41
|
+
name: string;
|
|
42
|
+
hostname: string;
|
|
43
|
+
ipv4_address: string;
|
|
44
|
+
zone: string;
|
|
45
|
+
cidr: string;
|
|
46
|
+
vmid: string;
|
|
25
47
|
}
|
|
26
48
|
|
|
27
49
|
/**
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Automatic DNS registration for deployed modules.
|
|
3
|
-
*
|
|
4
|
-
* After any module deploys successfully, registers its hostname as an
|
|
5
|
-
* A record in the internal DNS server (if dns_internal capability is
|
|
6
|
-
* available). When the dns_internal provider itself deploys, backfills
|
|
7
|
-
* records for all previously-deployed modules.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { HookLogger } from '@celilo/capabilities';
|
|
11
|
-
import type { DnsInternalCapability } from '@celilo/capabilities';
|
|
12
|
-
import { eq } from 'drizzle-orm';
|
|
13
|
-
import type { DbClient } from '../db/client';
|
|
14
|
-
import {
|
|
15
|
-
capabilities as capabilitiesTable,
|
|
16
|
-
moduleConfigs,
|
|
17
|
-
moduleInfrastructure,
|
|
18
|
-
modules,
|
|
19
|
-
systemConfig,
|
|
20
|
-
} from '../db/schema';
|
|
21
|
-
import { loadCapabilityFunctions } from '../hooks/capability-loader';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Get a module's hostname and IP for DNS registration.
|
|
25
|
-
* Returns null if the module doesn't have both.
|
|
26
|
-
*/
|
|
27
|
-
async function getModuleHostAndIp(
|
|
28
|
-
moduleId: string,
|
|
29
|
-
db: DbClient,
|
|
30
|
-
): Promise<{ hostname: string; ip: string } | null> {
|
|
31
|
-
// Get hostname from module config
|
|
32
|
-
const hostnameConfig = db
|
|
33
|
-
.select()
|
|
34
|
-
.from(moduleConfigs)
|
|
35
|
-
.where(eq(moduleConfigs.moduleId, moduleId))
|
|
36
|
-
.all()
|
|
37
|
-
.find((c) => c.key === 'hostname');
|
|
38
|
-
|
|
39
|
-
if (!hostnameConfig?.value) return null;
|
|
40
|
-
|
|
41
|
-
// Get IP: try target_ip first, then machine IP
|
|
42
|
-
const targetIpConfig = db
|
|
43
|
-
.select()
|
|
44
|
-
.from(moduleConfigs)
|
|
45
|
-
.where(eq(moduleConfigs.moduleId, moduleId))
|
|
46
|
-
.all()
|
|
47
|
-
.find((c) => c.key === 'target_ip');
|
|
48
|
-
|
|
49
|
-
let ip = targetIpConfig?.value;
|
|
50
|
-
|
|
51
|
-
if (!ip) {
|
|
52
|
-
// Try machine IP from infrastructure assignment
|
|
53
|
-
const infra = db
|
|
54
|
-
.select()
|
|
55
|
-
.from(moduleInfrastructure)
|
|
56
|
-
.where(eq(moduleInfrastructure.moduleId, moduleId))
|
|
57
|
-
.all();
|
|
58
|
-
|
|
59
|
-
if (infra.length > 0 && infra[0].machineId) {
|
|
60
|
-
const { machines } = await import('../db/schema');
|
|
61
|
-
const machine = db.select().from(machines).where(eq(machines.id, infra[0].machineId)).get();
|
|
62
|
-
if (machine) {
|
|
63
|
-
ip = machine.ipAddress;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!ip) return null;
|
|
69
|
-
|
|
70
|
-
// Strip CIDR notation
|
|
71
|
-
const bareIp = ip.split('/')[0];
|
|
72
|
-
|
|
73
|
-
return { hostname: hostnameConfig.value, ip: bareIp };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get the system's primary domain.
|
|
78
|
-
*/
|
|
79
|
-
function getPrimaryDomain(db: DbClient): string | null {
|
|
80
|
-
const record = db.select().from(systemConfig).where(eq(systemConfig.key, 'primary_domain')).get();
|
|
81
|
-
|
|
82
|
-
return record?.value || null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Load the dns_internal capability if it's available.
|
|
87
|
-
* Returns null if no dns_internal provider is registered.
|
|
88
|
-
*/
|
|
89
|
-
async function loadDnsInternal(
|
|
90
|
-
db: DbClient,
|
|
91
|
-
logger: HookLogger,
|
|
92
|
-
): Promise<DnsInternalCapability | null> {
|
|
93
|
-
const providers = db
|
|
94
|
-
.select()
|
|
95
|
-
.from(capabilitiesTable)
|
|
96
|
-
.where(eq(capabilitiesTable.capabilityName, 'dns_internal'))
|
|
97
|
-
.all();
|
|
98
|
-
|
|
99
|
-
if (providers.length === 0) return null;
|
|
100
|
-
|
|
101
|
-
// Load capability functions using the provider's own module ID as context
|
|
102
|
-
const caps = await loadCapabilityFunctions(providers[0].moduleId, db, logger);
|
|
103
|
-
return (caps.dns_internal as DnsInternalCapability) || null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Auto-register a module's hostname in internal DNS after successful deploy.
|
|
108
|
-
*
|
|
109
|
-
* If the deployed module IS the dns_internal provider, also backfills
|
|
110
|
-
* records for all previously-deployed modules.
|
|
111
|
-
*/
|
|
112
|
-
export async function autoRegisterDns(
|
|
113
|
-
moduleId: string,
|
|
114
|
-
db: DbClient,
|
|
115
|
-
logger: HookLogger,
|
|
116
|
-
): Promise<void> {
|
|
117
|
-
const primaryDomain = getPrimaryDomain(db);
|
|
118
|
-
if (!primaryDomain) {
|
|
119
|
-
return; // No domain configured, skip silently
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const dnsInternal = await loadDnsInternal(db, logger);
|
|
123
|
-
if (!dnsInternal) {
|
|
124
|
-
return; // No dns_internal provider, skip silently
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Check if the module being deployed IS the dns_internal provider
|
|
128
|
-
const providers = db
|
|
129
|
-
.select()
|
|
130
|
-
.from(capabilitiesTable)
|
|
131
|
-
.where(eq(capabilitiesTable.capabilityName, 'dns_internal'))
|
|
132
|
-
.all();
|
|
133
|
-
const isProvider = providers.some((p) => p.moduleId === moduleId);
|
|
134
|
-
|
|
135
|
-
if (isProvider) {
|
|
136
|
-
// Backfill: register all deployed modules
|
|
137
|
-
logger.info('dns_internal provider deployed -- backfilling DNS records for all modules');
|
|
138
|
-
const allModules = db
|
|
139
|
-
.select()
|
|
140
|
-
.from(modules)
|
|
141
|
-
.all()
|
|
142
|
-
.filter((m) => m.id !== moduleId); // Skip self
|
|
143
|
-
|
|
144
|
-
for (const mod of allModules) {
|
|
145
|
-
const hostInfo = await getModuleHostAndIp(mod.id, db);
|
|
146
|
-
if (!hostInfo) continue;
|
|
147
|
-
|
|
148
|
-
const fqdn = `${hostInfo.hostname}.${primaryDomain}`;
|
|
149
|
-
try {
|
|
150
|
-
await dnsInternal.registerRecord({
|
|
151
|
-
host: fqdn,
|
|
152
|
-
type: 'A',
|
|
153
|
-
value: hostInfo.ip,
|
|
154
|
-
});
|
|
155
|
-
} catch (error) {
|
|
156
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
157
|
-
logger.warn(`Failed to register ${fqdn}: ${msg}`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Register the deployed module itself
|
|
163
|
-
const hostInfo = await getModuleHostAndIp(moduleId, db);
|
|
164
|
-
if (!hostInfo) return;
|
|
165
|
-
|
|
166
|
-
const fqdn = `${hostInfo.hostname}.${primaryDomain}`;
|
|
167
|
-
try {
|
|
168
|
-
await dnsInternal.registerRecord({
|
|
169
|
-
host: fqdn,
|
|
170
|
-
type: 'A',
|
|
171
|
-
value: hostInfo.ip,
|
|
172
|
-
});
|
|
173
|
-
logger.success(`Registered DNS: ${fqdn} → ${hostInfo.ip}`);
|
|
174
|
-
} catch (error) {
|
|
175
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
176
|
-
logger.warn(`DNS registration failed for ${fqdn}: ${msg}`);
|
|
177
|
-
// Non-fatal -- deployment still succeeded
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Remove a module's DNS record when the module is removed.
|
|
183
|
-
*/
|
|
184
|
-
export async function autoDeregisterDns(
|
|
185
|
-
moduleId: string,
|
|
186
|
-
db: DbClient,
|
|
187
|
-
logger: HookLogger,
|
|
188
|
-
): Promise<void> {
|
|
189
|
-
const primaryDomain = getPrimaryDomain(db);
|
|
190
|
-
if (!primaryDomain) return;
|
|
191
|
-
|
|
192
|
-
const dnsInternal = await loadDnsInternal(db, logger);
|
|
193
|
-
if (!dnsInternal) return;
|
|
194
|
-
|
|
195
|
-
const hostInfo = await getModuleHostAndIp(moduleId, db);
|
|
196
|
-
if (!hostInfo) return;
|
|
197
|
-
|
|
198
|
-
const fqdn = `${hostInfo.hostname}.${primaryDomain}`;
|
|
199
|
-
try {
|
|
200
|
-
await dnsInternal.deleteRecord({
|
|
201
|
-
host: fqdn,
|
|
202
|
-
type: 'A',
|
|
203
|
-
value: hostInfo.ip,
|
|
204
|
-
});
|
|
205
|
-
logger.success(`Removed DNS: ${fqdn}`);
|
|
206
|
-
} catch (error) {
|
|
207
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
208
|
-
logger.warn(`DNS cleanup failed for ${fqdn}: ${msg}`);
|
|
209
|
-
// Non-fatal
|
|
210
|
-
}
|
|
211
|
-
}
|