feat(dns): Enhance DNS management with auto-generated entries and service activation
This commit is contained in:
@@ -181,8 +181,16 @@ export class DeploymentManager {
|
|||||||
throw new Error('Deployment not found');
|
throw new Error('Deployment not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const serviceId = deployment.serviceId;
|
||||||
await deployment.delete();
|
await deployment.delete();
|
||||||
|
|
||||||
|
// Check if this was the last deployment for the service
|
||||||
|
const remainingDeployments = await this.getDeploymentsForService(serviceId);
|
||||||
|
if (remainingDeployments.length === 0) {
|
||||||
|
// Deactivate DNS entries if no more deployments exist
|
||||||
|
await this.cloudlyRef.dnsManager.deactivateServiceDnsEntries(serviceId);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
@@ -281,7 +289,7 @@ export class DeploymentManager {
|
|||||||
nodeId: string,
|
nodeId: string,
|
||||||
version: string = 'latest'
|
version: string = 'latest'
|
||||||
): Promise<Deployment> {
|
): Promise<Deployment> {
|
||||||
return await Deployment.createDeployment({
|
const deployment = await Deployment.createDeployment({
|
||||||
serviceId,
|
serviceId,
|
||||||
nodeId,
|
nodeId,
|
||||||
version,
|
version,
|
||||||
@@ -289,6 +297,19 @@ export class DeploymentManager {
|
|||||||
deployedAt: Date.now(),
|
deployedAt: Date.now(),
|
||||||
deploymentLog: [`Deployment created at ${new Date().toISOString()}`],
|
deploymentLog: [`Deployment created at ${new Date().toISOString()}`],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Activate DNS entries for the service
|
||||||
|
await this.cloudlyRef.dnsManager.activateServiceDnsEntries(serviceId);
|
||||||
|
|
||||||
|
// Get the node's IP address and update DNS entries
|
||||||
|
const node = await this.cloudlyRef.nodeManager.CClusterNode.getInstance({
|
||||||
|
id: nodeId,
|
||||||
|
});
|
||||||
|
if (node && node.data.publicIp) {
|
||||||
|
await this.cloudlyRef.dnsManager.updateServiceDnsEntriesIp(serviceId, node.data.publicIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deployment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
|
@@ -156,6 +156,95 @@ export class DnsManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Initialize the DNS manager
|
||||||
*/
|
*/
|
||||||
|
@@ -25,6 +25,12 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
|
|||||||
service.id = await Service.getNewId();
|
service.id = await Service.getNewId();
|
||||||
Object.assign(service, serviceDataArg);
|
Object.assign(service, serviceDataArg);
|
||||||
await service.save();
|
await service.save();
|
||||||
|
|
||||||
|
// Create DNS entries if service has web port and domains configured
|
||||||
|
if (service.data.ports?.web && service.data.domains?.length > 0) {
|
||||||
|
await service.createDnsEntries();
|
||||||
|
}
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,4 +60,40 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
|
|||||||
}
|
}
|
||||||
return finalFlatObject;
|
return finalFlatObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates DNS entries for this service (in inactive state)
|
||||||
|
* These will be activated when the service is deployed
|
||||||
|
*/
|
||||||
|
public async createDnsEntries() {
|
||||||
|
const dnsManager = this.manager.cloudlyRef.dnsManager;
|
||||||
|
|
||||||
|
for (const domain of this.data.domains) {
|
||||||
|
const dnsEntryData: plugins.servezoneInterfaces.data.IDnsEntry['data'] = {
|
||||||
|
type: 'A', // Default to A record, could be made configurable
|
||||||
|
name: domain.name,
|
||||||
|
value: '0.0.0.0', // Placeholder, will be updated on deployment
|
||||||
|
ttl: 3600,
|
||||||
|
zone: '', // Will be set based on domainId
|
||||||
|
domainId: domain.domainId,
|
||||||
|
active: false, // Created as inactive
|
||||||
|
description: `Auto-generated DNS entry for service ${this.data.name}`,
|
||||||
|
createdAt: Date.now(),
|
||||||
|
isAutoGenerated: true,
|
||||||
|
sourceServiceId: this.id,
|
||||||
|
sourceType: 'service',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the DNS entry
|
||||||
|
await dnsManager.createServiceDnsEntry(dnsEntryData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes DNS entries for this service
|
||||||
|
*/
|
||||||
|
public async removeDnsEntries() {
|
||||||
|
const dnsManager = this.manager.cloudlyRef.dnsManager;
|
||||||
|
await dnsManager.removeServiceDnsEntries(this.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -91,6 +91,10 @@ export class ServiceManager {
|
|||||||
const service = await Service.getInstance({
|
const service = await Service.getInstance({
|
||||||
id: dataArg.serviceId,
|
id: dataArg.serviceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove DNS entries before deleting the service
|
||||||
|
await service.removeDnsEntries();
|
||||||
|
|
||||||
await service.delete();
|
await service.delete();
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
@@ -77,5 +77,24 @@ export interface IDnsEntry {
|
|||||||
* Timestamp when the entry was last updated
|
* Timestamp when the entry was last updated
|
||||||
*/
|
*/
|
||||||
updatedAt?: number;
|
updatedAt?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this DNS entry was auto-generated
|
||||||
|
*/
|
||||||
|
isAutoGenerated?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service ID that created this DNS entry (for auto-generated entries)
|
||||||
|
*/
|
||||||
|
sourceServiceId?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source type of this DNS entry
|
||||||
|
* - manual: Created by user through UI/API
|
||||||
|
* - service: Auto-generated from service configuration
|
||||||
|
* - system: Created by system processes
|
||||||
|
* - external: Synced from external DNS providers
|
||||||
|
*/
|
||||||
|
sourceType?: 'manual' | 'service' | 'system' | 'external';
|
||||||
};
|
};
|
||||||
}
|
}
|
@@ -54,8 +54,22 @@ export interface IService {
|
|||||||
};
|
};
|
||||||
resources?: IServiceRessources;
|
resources?: IServiceRessources;
|
||||||
domains: {
|
domains: {
|
||||||
|
/**
|
||||||
|
* Optional domain ID to specify which domain to use
|
||||||
|
* If not specified, will use the default domain or require manual configuration
|
||||||
|
*/
|
||||||
|
domainId?: string;
|
||||||
|
/**
|
||||||
|
* The subdomain name (e.g., 'api', 'www', '@' for root)
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
/**
|
||||||
|
* The port to expose (defaults to ports.web if not specified)
|
||||||
|
*/
|
||||||
port?: number;
|
port?: number;
|
||||||
|
/**
|
||||||
|
* The protocol for this domain entry
|
||||||
|
*/
|
||||||
protocol?: 'http' | 'https' | 'ssh';
|
protocol?: 'http' | 'https' | 'ssh';
|
||||||
}[];
|
}[];
|
||||||
deploymentIds: string[];
|
deploymentIds: string[];
|
||||||
|
Reference in New Issue
Block a user