import type { Cloudly } from '../classes.cloudly.js'; import * as plugins from '../plugins.js'; import { DnsEntry } from './classes.dnsentry.js'; export class DnsManager { public typedrouter = new plugins.typedrequest.TypedRouter(); public cloudlyRef: Cloudly; get db() { return this.cloudlyRef.mongodbConnector.smartdataDb; } public CDnsEntry = plugins.smartdata.setDefaultManagerForDoc(this, DnsEntry); constructor(cloudlyRef: Cloudly) { this.cloudlyRef = cloudlyRef; this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter); // Get all DNS entries this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getDnsEntries', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); const dnsEntries = await this.CDnsEntry.getDnsEntries( reqArg.zone ? { zone: reqArg.zone } : undefined ); return { dnsEntries: await Promise.all( dnsEntries.map((entry) => entry.createSavableObject()) ), }; } ) ); // Get DNS entry by ID this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getDnsEntryById', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); const dnsEntry = await this.CDnsEntry.getDnsEntryById(reqArg.dnsEntryId); if (!dnsEntry) { throw new Error(`DNS entry with id ${reqArg.dnsEntryId} not found`); } return { dnsEntry: await dnsEntry.createSavableObject(), }; } ) ); // Create DNS entry this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'createDnsEntry', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); // Validate domain exists 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`); } // Set the zone from the domain name reqArg.dnsEntryData.zone = domain.data.name; } const dnsEntry = await this.CDnsEntry.createDnsEntry(reqArg.dnsEntryData); return { dnsEntry: await dnsEntry.createSavableObject(), }; } ) ); // Update DNS entry this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updateDnsEntry', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); // Validate domain exists 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`); } // Set the zone from the domain name reqArg.dnsEntryData.zone = domain.data.name; } const dnsEntry = await this.CDnsEntry.updateDnsEntry( reqArg.dnsEntryId, reqArg.dnsEntryData ); return { dnsEntry: await dnsEntry.createSavableObject(), }; } ) ); // Delete DNS entry this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'deleteDnsEntry', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); const success = await this.CDnsEntry.deleteDnsEntry(reqArg.dnsEntryId); return { success, }; } ) ); // Get DNS zones this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getDnsZones', async (reqArg) => { await plugins.smartguard.passGuardsOrReject(reqArg, [ this.cloudlyRef.authManager.validIdentityGuard, ]); const zones = await this.CDnsEntry.getDnsZones(); return { zones, }; } ) ); } /** * Create a DNS entry for a service * @param dnsEntryData The DNS entry data */ public async createServiceDnsEntry(dnsEntryData: plugins.servezoneInterfaces.data.IDnsEntry['data']) { // If domainId is provided, get the domain and set the zone if (dnsEntryData.domainId) { const domain = await this.cloudlyRef.domainManager.CDomain.getInstance({ id: dnsEntryData.domainId, }); if (domain) { dnsEntryData.zone = domain.data.name; } } // Create the DNS entry const dnsEntry = await this.CDnsEntry.createDnsEntry(dnsEntryData); return dnsEntry; } /** * Activate DNS entries for a service when it's deployed * @param serviceId The service ID */ public async activateServiceDnsEntries(serviceId: string) { const dnsEntries = await this.CDnsEntry.getInstances({ 'data.sourceServiceId': serviceId, 'data.sourceType': 'service', }); for (const entry of dnsEntries) { entry.data.active = true; entry.data.updatedAt = Date.now(); await entry.save(); } } /** * Deactivate DNS entries for a service when it's undeployed * @param serviceId The service ID */ public async deactivateServiceDnsEntries(serviceId: string) { const dnsEntries = await this.CDnsEntry.getInstances({ 'data.sourceServiceId': serviceId, 'data.sourceType': 'service', }); for (const entry of dnsEntries) { entry.data.active = false; entry.data.updatedAt = Date.now(); await entry.save(); } } /** * Remove all DNS entries for a service * @param serviceId The service ID */ public async removeServiceDnsEntries(serviceId: string) { const dnsEntries = await this.CDnsEntry.getInstances({ 'data.sourceServiceId': serviceId, 'data.sourceType': 'service', }); for (const entry of dnsEntries) { await entry.delete(); } } /** * Update DNS entry values when deployment happens * @param serviceId The service ID * @param ipAddress The IP address to set for the DNS entries */ public async updateServiceDnsEntriesIp(serviceId: string, ipAddress: string) { const dnsEntries = await this.CDnsEntry.getInstances({ 'data.sourceServiceId': serviceId, 'data.sourceType': 'service', }); for (const entry of dnsEntries) { if (entry.data.type === 'A' || entry.data.type === 'AAAA') { entry.data.value = ipAddress; entry.data.updatedAt = Date.now(); await entry.save(); } } } /** * Initialize the DNS manager */ public async init() { console.log('DNS Manager initialized'); } /** * Stop the DNS manager */ public async stop() { console.log('DNS Manager stopped'); } }