From d28a270e7b0388d0a2b36e81da4160761541cc88 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Fri, 31 Jan 2025 15:37:31 +0530 Subject: [PATCH] Implement functionality to store DNS deployment --- packages/backend/src/entity/Deployment.ts | 12 +- packages/backend/src/registry.ts | 4 +- packages/backend/src/service.ts | 147 +++++++++++++--------- 3 files changed, 92 insertions(+), 71 deletions(-) diff --git a/packages/backend/src/entity/Deployment.ts b/packages/backend/src/entity/Deployment.ts index f1477f1a..8a5aa6b8 100644 --- a/packages/backend/src/entity/Deployment.ts +++ b/packages/backend/src/entity/Deployment.ts @@ -105,24 +105,15 @@ export class Deployment { @Column('varchar', { nullable: true }) applicationDeploymentRequestId!: string | null; - @Column('varchar', { nullable: true }) - dnsDeploymentRequestId!: string | null; - @Column('simple-json', { nullable: true }) applicationDeploymentRequestData!: ApplicationDeploymentRequest | null; @Column('varchar', { nullable: true }) applicationDeploymentRecordId!: string | null; - @Column('varchar', { nullable: true }) - dnsDeploymentRecordId!: string | null; - @Column('simple-json', { nullable: true }) applicationDeploymentRecordData!: AppDeploymentRecordAttributes | null; - @Column('simple-json', { nullable: true }) - dnsDeploymentRecordData!: AppDeploymentRecordAttributes | null; - @Column('varchar', { nullable: true }) applicationDeploymentRemovalRequestId!: string | null; @@ -150,6 +141,9 @@ export class Deployment { @Column('boolean', { default: false }) isCurrent!: boolean; + @Column('boolean', { default: false }) + isDNS!: boolean; + @Column({ enum: DeploymentStatus }) diff --git a/packages/backend/src/registry.ts b/packages/backend/src/registry.ts index ffd531c5..894792b5 100644 --- a/packages/backend/src/registry.ts +++ b/packages/backend/src/registry.ts @@ -376,8 +376,8 @@ export class Registry { return records.filter((record: AppDeploymentRecord) => deployments.some( (deployment) => - deployment.applicationDeploymentRequestId === record.attributes.request || - deployment.dnsDeploymentRequestId === record.attributes.request + deployment.applicationDeploymentRequestId === record.attributes.request && + record.attributes.url.includes(deployment.id) ) ); } diff --git a/packages/backend/src/service.ts b/packages/backend/src/service.ts index d1270aaa..22449b63 100644 --- a/packages/backend/src/service.ts +++ b/packages/backend/src/service.ts @@ -185,28 +185,23 @@ export class Service { }, }); - const requestIdToRecordsMap = records.reduce( - (acc: { [key: string]: AppDeploymentRecord }, record) => { - acc[record.attributes.request] = record; + const recordToDeploymentsMap = deployments.reduce( + (acc: { [key: string]: Deployment }, deployment) => { + acc[deployment.applicationDeploymentRequestId!] = deployment; return acc; }, {}, ); // Update deployment data for ApplicationDeploymentRecords - const deploymentUpdatePromises = deployments.map(async (deployment) => { - const applicationDeploymentRecord = requestIdToRecordsMap[deployment.applicationDeploymentRequestId!] - const dnsDeploymentRecord = requestIdToRecordsMap[deployment.dnsDeploymentRequestId!] - - if (!applicationDeploymentRecord || !dnsDeploymentRecord) { - return; - } + const deploymentUpdatePromises = records.map(async (record) => { + const deployment = recordToDeploymentsMap[record.attributes.request]; if (!deployment.project) { log(`Project ${deployment.projectId} not found`); return; } else { - const dnsRecords = await this.laconicRegistry.getDNSRecordById(applicationDeploymentRecord.attributes.dns); + const dnsRecords = await this.laconicRegistry.getDNSRecordById(record.attributes.dns); const dnsRecordData: DNSRecordAttributes = { name: dnsRecords[0].attributes.name, @@ -216,15 +211,29 @@ export class Service { version: dnsRecords[0].attributes.version, } - deployment.applicationDeploymentRecordId = applicationDeploymentRecord.id; - deployment.dnsDeploymentRecordId = dnsDeploymentRecord.id; - deployment.applicationDeploymentRecordData = applicationDeploymentRecord.attributes; - deployment.dnsDeploymentRecordData = dnsDeploymentRecord.attributes; - deployment.url = applicationDeploymentRecord.attributes.url; + deployment.applicationDeploymentRecordId = record.id; + deployment.applicationDeploymentRecordData = record.attributes; + deployment.url = record.attributes.url; deployment.status = DeploymentStatus.Ready; deployment.isCurrent = deployment.environment === Environment.Production; deployment.dnsRecordData = dnsRecordData; + if (deployment.isDNS) { + // Delete previous DNS deployment + const oldDNSDeployment = await this.db.getDeployment({ + where: { + projectId: deployment.project.id, + deployer: deployment.deployer, + isDNS: true, + isCurrent: true, + } + }); + + if (oldDNSDeployment) { + await this.db.deleteDeploymentById(oldDNSDeployment.id); + } + } + await this.db.updateDeploymentById(deployment.id, deployment); // Release deployer funds on successful deployment @@ -240,25 +249,27 @@ export class Service { } log( - `Updated deployment ${deployment.id} with URL ${applicationDeploymentRecord.attributes.url}`, + `Updated deployment ${deployment.id} with URL ${record.attributes.url}`, ); } - - // Set the isCurrent state to false for the old deployments - if (deployment.isCurrent) { - const projectDeployments = await this.db.getDeploymentsByProjectId(deployment.projectId); - const oldDeployments = projectDeployments - .filter(projectDeployment => projectDeployment.deployer.deployerLrn === deployment.deployer.deployerLrn && projectDeployment.id !== deployment.id); - for (const oldDeployment of oldDeployments) { - await this.db.updateDeployment( - { id: oldDeployment.id }, - { isCurrent: false } - ); - } - } }); await Promise.all(deploymentUpdatePromises); + + // Get deployments that are in production environment + const prodDeployments = Object.values(recordToDeploymentsMap).filter(deployment => deployment.isCurrent); + // Set the isCurrent state to false for the old deployments + for (const deployment of prodDeployments) { + const projectDeployments = await this.db.getDeploymentsByProjectId(deployment.projectId); + const oldDeployments = projectDeployments + .filter(projectDeployment => projectDeployment.deployer.deployerLrn === deployment.deployer.deployerLrn && projectDeployment.id !== deployment.id); + for (const oldDeployment of oldDeployments) { + await this.db.updateDeployment( + { id: oldDeployment.id }, + { isCurrent: false } + ); + } + }; } /** @@ -658,7 +669,8 @@ export class Service { deployer = data.deployer; } - const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData); + const deployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData, false); + const dnsDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData, true); const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash); const environmentVariablesObj = await this.getEnvVariables(data.project!.id!); @@ -667,43 +679,47 @@ export class Service { const domain = await this.db.getOldestDomainByProjectId(data.project!.id!); // To set project DNS - let dnsDeploymentRequestId = null; if (data.environment === Environment.Production) { // On deleting deployment later, project DNS deployment is also deleted // So publish project DNS deployment first so that ApplicationDeploymentRecord for the same is available when deleting deployment later - const dnsRequest = await this.laconicRegistry.createApplicationDeploymentRequest({ - deployment: newDeployment, - appName: repo, - repository: repoUrl, - environmentVariables: environmentVariablesObj, - dns: domain?.name ?? `${newDeployment.project.name}`, - lrn: deployer!.deployerLrn!, - payment: data.project.txHash, - auctionId: data.project.auctionId + const { applicationDeploymentRequestData, applicationDeploymentRequestId } = + await this.laconicRegistry.createApplicationDeploymentRequest({ + deployment: dnsDeployment, + appName: repo, + repository: repoUrl, + environmentVariables: environmentVariablesObj, + dns: domain?.name ?? `${dnsDeployment.project.name}`, + lrn: deployer!.deployerLrn!, + payment: data.project.txHash, + auctionId: data.project.auctionId + }); + + await this.db.updateDeploymentById(dnsDeployment.id, { + applicationDeploymentRequestId, + applicationDeploymentRequestData, + domainId: domain?.id ?? null }); - dnsDeploymentRequestId = dnsRequest.applicationDeploymentRequestId; } const { applicationDeploymentRequestId, applicationDeploymentRequestData } = await this.laconicRegistry.createApplicationDeploymentRequest({ - deployment: newDeployment, + deployment: deployment, appName: repo, repository: repoUrl, lrn: deployer!.deployerLrn!, environmentVariables: environmentVariablesObj, - dns: `${newDeployment.project.name}-${newDeployment.id}`, + dns: `${deployment.project.name}-${deployment.id}`, payment: data.project.txHash, auctionId: data.project.auctionId }); - await this.db.updateDeploymentById(newDeployment.id, { + await this.db.updateDeploymentById(deployment.id, { applicationDeploymentRequestId, applicationDeploymentRequestData, - dnsDeploymentRequestId, domainId: domain?.id ?? null }); - return newDeployment; + return deployment; } async createDeploymentFromAuction( @@ -746,42 +762,49 @@ export class Service { commitMessage: latestCommit.commit.message, }; - const newDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData); + const deployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData, false); + const dnsDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData, true); const environmentVariablesObj = await this.getEnvVariables(project!.id!); // To set project DNS if (deploymentData.environment === Environment.Production) { // On deleting deployment later, project DNS deployment is also deleted // So publish project DNS deployment first so that ApplicationDeploymentRecord for the same is available when deleting deployment later - await this.laconicRegistry.createApplicationDeploymentRequest({ - deployment: newDeployment, - appName: repo, - repository: repoUrl, - environmentVariables: environmentVariablesObj, - dns: `${newDeployment.project.name}`, - auctionId: project.auctionId!, - lrn: deployerLrn, + const { applicationDeploymentRequestId, applicationDeploymentRequestData } = + await this.laconicRegistry.createApplicationDeploymentRequest({ + deployment: dnsDeployment, + appName: repo, + repository: repoUrl, + environmentVariables: environmentVariablesObj, + dns: `${dnsDeployment.project.name}`, + auctionId: project.auctionId!, + lrn: deployerLrn, + }); + + await this.db.updateDeploymentById(dnsDeployment.id, { + applicationDeploymentRequestId, + applicationDeploymentRequestData, }); } const { applicationDeploymentRequestId, applicationDeploymentRequestData } = // Create requests for all the deployers await this.laconicRegistry.createApplicationDeploymentRequest({ - deployment: newDeployment, + deployment: deployment, appName: repo, repository: repoUrl, auctionId: project.auctionId!, lrn: deployerLrn, environmentVariables: environmentVariablesObj, - dns: `${newDeployment.project.name}-${newDeployment.id}`, + dns: `${deployment.project.name}-${deployment.id}`, }); - await this.db.updateDeploymentById(newDeployment.id, { + await this.db.updateDeploymentById(deployment.id, { applicationDeploymentRequestId, applicationDeploymentRequestData, }); - return newDeployment; + return deployment; } async createDeploymentFromData( @@ -790,6 +813,7 @@ export class Service { deployerLrn: string, applicationRecordId: string, applicationRecordData: ApplicationRecord, + isDNS: boolean, ): Promise { const newDeployment = await this.db.addDeployment({ project: data.project, @@ -807,6 +831,7 @@ export class Service { deployer: Object.assign(new Deployer(), { deployerLrn, }), + isDNS }); log(`Created deployment ${newDeployment.id}`); @@ -1183,6 +1208,8 @@ export class Service { }, }); + // Compare deployer in DNS while deleting + if (deployment && deployment.applicationDeploymentRecordId) { // If deployment is current, remove deployment for project subdomain as well if (deployment.isCurrent) {