2025-09-09 15:08:28 +00:00
|
|
|
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<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsEntries>(
|
|
|
|
'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<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsEntryById>(
|
|
|
|
'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<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_CreateDnsEntry>(
|
|
|
|
'createDnsEntry',
|
|
|
|
async (reqArg) => {
|
|
|
|
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
|
|
|
this.cloudlyRef.authManager.validIdentityGuard,
|
|
|
|
]);
|
|
|
|
|
2025-09-09 15:13:44 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2025-09-09 15:08:28 +00:00
|
|
|
const dnsEntry = await this.CDnsEntry.createDnsEntry(reqArg.dnsEntryData);
|
|
|
|
|
|
|
|
return {
|
|
|
|
dnsEntry: await dnsEntry.createSavableObject(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Update DNS entry
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_UpdateDnsEntry>(
|
|
|
|
'updateDnsEntry',
|
|
|
|
async (reqArg) => {
|
|
|
|
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
|
|
|
this.cloudlyRef.authManager.validIdentityGuard,
|
|
|
|
]);
|
|
|
|
|
2025-09-09 15:13:44 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2025-09-09 15:08:28 +00:00
|
|
|
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<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_DeleteDnsEntry>(
|
|
|
|
'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<plugins.servezoneInterfaces.requests.dns.IRequest_Any_Cloudly_GetDnsZones>(
|
|
|
|
'getDnsZones',
|
|
|
|
async (reqArg) => {
|
|
|
|
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
|
|
|
this.cloudlyRef.authManager.validIdentityGuard,
|
|
|
|
]);
|
|
|
|
|
|
|
|
const zones = await this.CDnsEntry.getDnsZones();
|
|
|
|
|
|
|
|
return {
|
|
|
|
zones,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2025-09-10 15:38:42 +00:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-09-09 15:08:28 +00:00
|
|
|
/**
|
|
|
|
* Initialize the DNS manager
|
|
|
|
*/
|
|
|
|
public async init() {
|
|
|
|
console.log('DNS Manager initialized');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the DNS manager
|
|
|
|
*/
|
|
|
|
public async stop() {
|
|
|
|
console.log('DNS Manager stopped');
|
|
|
|
}
|
|
|
|
}
|