feat(domains): enhance domain management with activation states and sync options
This commit is contained in:
@@ -69,12 +69,15 @@ export class DnsManager {
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
// Validate domain exists if domainId is provided
|
||||
// Validate domain exists and is activated if domainId is provided
|
||||
if (reqArg.dnsEntryData.domainId) {
|
||||
const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId);
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`);
|
||||
}
|
||||
if ((domain.data as any).activationState !== 'activated') {
|
||||
throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`);
|
||||
}
|
||||
// Set the zone from the domain name
|
||||
reqArg.dnsEntryData.zone = domain.data.name;
|
||||
}
|
||||
@@ -97,12 +100,15 @@ export class DnsManager {
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
// Validate domain exists if domainId is provided
|
||||
// Validate domain exists and is activated if domainId is provided
|
||||
if (reqArg.dnsEntryData.domainId) {
|
||||
const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId);
|
||||
if (!domain) {
|
||||
throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`);
|
||||
}
|
||||
if ((domain.data as any).activationState !== 'activated') {
|
||||
throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`);
|
||||
}
|
||||
// Set the zone from the domain name
|
||||
reqArg.dnsEntryData.zone = domain.data.name;
|
||||
}
|
||||
@@ -258,4 +264,4 @@ export class DnsManager {
|
||||
public async stop() {
|
||||
console.log('DNS Manager stopped');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,9 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc<
|
||||
verificationStatus: domainDataArg.verificationStatus || 'pending',
|
||||
nameservers: domainDataArg.nameservers || [],
|
||||
autoRenew: domainDataArg.autoRenew !== false,
|
||||
activationState: domainDataArg.activationState || 'available',
|
||||
syncSource: domainDataArg.syncSource ?? null,
|
||||
lastSyncAt: domainDataArg.lastSyncAt,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
@@ -55,6 +58,7 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc<
|
||||
}
|
||||
Object.assign(domain.data, domainDataArg, {
|
||||
updatedAt: Date.now(),
|
||||
activationState: domain.data.activationState || 'available',
|
||||
});
|
||||
await domain.save();
|
||||
return domain;
|
||||
@@ -201,4 +205,4 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc<
|
||||
});
|
||||
return dnsEntries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,86 @@ import { logger } from '../logger.js';
|
||||
*/
|
||||
export function createPredefinedTasks(taskManager: CloudlyTaskManager) {
|
||||
|
||||
// Cloudflare Domain Sync Task
|
||||
const cfDomainSync = new plugins.taskbuffer.Task({
|
||||
name: 'cloudflare-domain-sync',
|
||||
taskFunction: async () => {
|
||||
const execution = taskManager.getCurrentExecution('cloudflare-domain-sync');
|
||||
try {
|
||||
await execution?.addLog('Starting Cloudflare domain sync…', 'info');
|
||||
const cf = taskManager.cloudlyRef.cloudflareConnector?.cloudflare;
|
||||
if (!cf) {
|
||||
await execution?.addLog('Cloudflare not configured; skipping sync.', 'warning');
|
||||
return { created: 0, updated: 0, totalZones: 0 };
|
||||
}
|
||||
|
||||
const zones = await cf.convenience.listZones();
|
||||
await execution?.setMetric('totalZones', zones.length);
|
||||
await execution?.addLog(`Fetched ${zones.length} zones from Cloudflare`, 'info');
|
||||
|
||||
let created = 0;
|
||||
let updated = 0;
|
||||
const now = Date.now();
|
||||
|
||||
for (const zone of zones) {
|
||||
// zone fields from Cloudflare typings
|
||||
const zoneName = (zone as any).name as string;
|
||||
const zoneId = (zone as any).id as string;
|
||||
const zoneStatus = ((zone as any).status || 'active') as 'active'|'pending'|'suspended'|'transferred'|'expired';
|
||||
const nameServers: string[] = (zone as any).name_servers || [];
|
||||
|
||||
const existing = await taskManager.cloudlyRef.domainManager.CDomain.getDomainByName(zoneName);
|
||||
if (existing) {
|
||||
if (execution && (taskManager.isCancellationRequested(execution.id) || existing.data == null)) {
|
||||
await execution?.addLog('Cancellation requested. Stopping CF sync…', 'warning');
|
||||
break;
|
||||
}
|
||||
await execution?.addLog(`Updating domain: ${zoneName}`, 'info');
|
||||
await taskManager.cloudlyRef.domainManager.CDomain.updateDomain(existing.id, {
|
||||
status: zoneStatus as any,
|
||||
nameservers: nameServers,
|
||||
cloudflareZoneId: zoneId,
|
||||
syncSource: 'cloudflare',
|
||||
lastSyncAt: now,
|
||||
activationState: existing.data.activationState || 'available',
|
||||
});
|
||||
updated++;
|
||||
} else {
|
||||
await execution?.addLog(`Creating domain: ${zoneName}`, 'info');
|
||||
await taskManager.cloudlyRef.domainManager.CDomain.createDomain({
|
||||
name: zoneName,
|
||||
description: `Synced from Cloudflare zone ${zoneId}`,
|
||||
status: zoneStatus as any,
|
||||
verificationStatus: 'pending',
|
||||
nameservers: nameServers,
|
||||
autoRenew: true,
|
||||
cloudflareZoneId: zoneId,
|
||||
activationState: 'available',
|
||||
syncSource: 'cloudflare',
|
||||
lastSyncAt: now,
|
||||
} as any);
|
||||
created++;
|
||||
}
|
||||
}
|
||||
|
||||
await execution?.setMetric('created', created);
|
||||
await execution?.setMetric('updated', updated);
|
||||
await execution?.addLog(`Cloudflare sync done: ${created} created, ${updated} updated`, 'success');
|
||||
return { created, updated, totalZones: zones.length };
|
||||
} catch (error) {
|
||||
await execution?.addLog(`Cloudflare sync error: ${error.message}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
taskManager.registerTask('cloudflare-domain-sync', cfDomainSync, {
|
||||
description: 'Import and update domains from Cloudflare zones',
|
||||
category: 'system',
|
||||
schedule: '0 3 * * *', // Daily at 3 AM
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
// DNS Sync Task
|
||||
const dnsSync = new plugins.taskbuffer.Task({
|
||||
name: 'dns-sync',
|
||||
@@ -79,8 +159,10 @@ export function createPredefinedTasks(taskManager: CloudlyTaskManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all domains
|
||||
const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({});
|
||||
// Get all domains (only activated ones are considered for renewal)
|
||||
const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({
|
||||
'data.activationState': 'activated',
|
||||
} as any);
|
||||
await execution?.setMetric('totalDomains', domains.length);
|
||||
|
||||
let renewedCount = 0;
|
||||
|
Reference in New Issue
Block a user