fix: update prisma

feat(beta): database branching
This commit is contained in:
Andras Bacsai
2022-09-05 15:41:32 +02:00
parent c9aecd51f3
commit 5a15e64471
12 changed files with 707 additions and 687 deletions

View File

@@ -156,7 +156,8 @@ export async function getApplicationFromDB(id: string, teamId: string) {
settings: true,
gitSource: { include: { githubApp: true, gitlabApp: true } },
secrets: true,
persistentStorage: true
persistentStorage: true,
connectedDatabase: true
}
});
if (!application) {
@@ -190,7 +191,8 @@ export async function getApplicationFromDBWebhook(projectId: number, branch: str
settings: true,
gitSource: { include: { githubApp: true, gitlabApp: true } },
secrets: true,
persistentStorage: true
persistentStorage: true,
connectedDatabase: true
}
});
if (applications.length === 0) {
@@ -242,7 +244,8 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
denoOptions,
baseImage,
baseBuildImage,
deploymentType
deploymentType,
baseDatabaseBranch
} = request.body
if (port) port = Number(port);
if (exposePort) {
@@ -263,22 +266,43 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
dockerFileLocation,
denoMainFile
});
await prisma.application.update({
where: { id },
data: {
name,
fqdn,
exposePort,
pythonWSGI,
pythonModule,
pythonVariable,
denoOptions,
baseImage,
baseBuildImage,
deploymentType,
...defaultConfiguration
}
});
if (baseDatabaseBranch) {
await prisma.application.update({
where: { id },
data: {
name,
fqdn,
exposePort,
pythonWSGI,
pythonModule,
pythonVariable,
denoOptions,
baseImage,
baseBuildImage,
deploymentType,
...defaultConfiguration,
connectedDatabase: { update: { hostedDatabaseDBName: baseDatabaseBranch } }
}
});
} else {
await prisma.application.update({
where: { id },
data: {
name,
fqdn,
exposePort,
pythonWSGI,
pythonModule,
pythonVariable,
denoOptions,
baseImage,
baseBuildImage,
deploymentType,
...defaultConfiguration
}
});
}
return reply.code(201).send();
} catch ({ status, message }) {
return errorHandler({ status, message })
@@ -289,7 +313,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
export async function saveApplicationSettings(request: FastifyRequest<SaveApplicationSettings>, reply: FastifyReply) {
try {
const { id } = request.params
const { debug, previews, dualCerts, autodeploy, branch, projectId, isBot } = request.body
const { debug, previews, dualCerts, autodeploy, branch, projectId, isBot, isDBBranching } = request.body
// const isDouble = await checkDoubleBranch(branch, projectId);
// if (isDouble && autodeploy) {
// await prisma.applicationSettings.updateMany({ where: { application: { branch, projectId } }, data: { autodeploy: false } })
@@ -297,7 +321,7 @@ export async function saveApplicationSettings(request: FastifyRequest<SaveApplic
// }
await prisma.application.update({
where: { id },
data: { fqdn: isBot ? null : undefined, settings: { update: { debug, previews, dualCerts, autodeploy, isBot } } },
data: { fqdn: isBot ? null : undefined, settings: { update: { debug, previews, dualCerts, autodeploy, isBot, isDBBranching } } },
include: { destinationDocker: true }
});
return reply.code(201).send();
@@ -478,6 +502,7 @@ export async function deleteApplication(request: FastifyRequest<DeleteApplicatio
await prisma.build.deleteMany({ where: { applicationId: id } });
await prisma.secret.deleteMany({ where: { applicationId: id } });
await prisma.applicationPersistentStorage.deleteMany({ where: { applicationId: id } });
await prisma.applicationConnectedDatabase.deleteMany({ where: { applicationId: id } });
if (teamId === '0') {
await prisma.application.deleteMany({ where: { id } });
} else {
@@ -738,6 +763,17 @@ export async function saveBuildPack(request, reply) {
return errorHandler({ status, message })
}
}
export async function saveConnectedDatabase(request, reply) {
try {
const { id } = request.params
const { databaseId, type } = request.body
console.log({ databaseId, type })
await prisma.application.update({ where: { id }, data: { connectedDatabase: { upsert: { create: { database: { connect: { id: databaseId } }, hostedDatabaseType: type }, update: { database: { connect: { id: databaseId } }, hostedDatabaseType: type } } } } })
return reply.code(201).send()
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}
export async function getSecrets(request: FastifyRequest<OnlyId>) {
try {
@@ -986,11 +1022,13 @@ export async function getBuildIdLogs(request: FastifyRequest<GetBuildIdLogs>) {
where: { buildId, time: { gt: sequence } },
orderBy: { time: 'asc' }
});
const data = await prisma.build.findFirst({ where: { id: buildId } });
const createdAt = day(data.createdAt).utc();
return {
logs,
logs: logs.map(log => {
log.time = Number(log.time)
return log
}),
took: day().diff(createdAt) / 1000,
status: data?.status || 'queued'
}
@@ -1067,3 +1105,58 @@ export async function cancelDeployment(request: FastifyRequest<CancelDeployment>
return errorHandler({ status, message })
}
}
export async function createdBranchDatabase(database: any, baseDatabaseBranch: string, pullmergeRequestId: string) {
try {
if (!baseDatabaseBranch) return
const { id, type, destinationDockerId, rootUser, rootUserPassword, dbUser } = database;
if (destinationDockerId) {
if (type === 'postgresql') {
const decryptedRootUserPassword = decrypt(rootUserPassword);
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} pg_dump -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/${baseDatabaseBranch}" --encoding=UTF8 --schema-only -f /tmp/${baseDatabaseBranch}.dump`
})
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "CREATE DATABASE branch_${pullmergeRequestId}"`
})
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} psql -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/branch_${pullmergeRequestId}" -f /tmp/${baseDatabaseBranch}.dump`
})
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "ALTER DATABASE branch_${pullmergeRequestId} OWNER TO ${dbUser}"`
})
}
}
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}
export async function removeBranchDatabase(database: any, pullmergeRequestId: string) {
try {
const { id, type, destinationDockerId, rootUser, rootUserPassword } = database;
if (destinationDockerId) {
if (type === 'postgresql') {
const decryptedRootUserPassword = decrypt(rootUserPassword);
// Terminate all connections to the database
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'branch_${pullmergeRequestId}' AND pid <> pg_backend_pid();"`
})
await executeDockerCmd({
dockerId: destinationDockerId,
command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "DROP DATABASE branch_${pullmergeRequestId}"`
})
}
}
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}

View File

@@ -1,6 +1,6 @@
import { FastifyPluginAsync } from 'fastify';
import { OnlyId } from '../../../../types';
import { cancelDeployment, checkDNS, checkDomain, checkRepository, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildLogs, getBuildPack, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getSecrets, getStorages, getUsage, listApplications, newApplication, restartApplication, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication } from './handlers';
import { cancelDeployment, checkDNS, checkDomain, checkRepository, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildLogs, getBuildPack, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getSecrets, getStorages, getUsage, listApplications, newApplication, restartApplication, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication } from './handlers';
import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuildLogs, GetImages, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types';
@@ -55,6 +55,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.get('/:id/configuration/buildpack', async (request) => await getBuildPack(request));
fastify.post('/:id/configuration/buildpack', async (request, reply) => await saveBuildPack(request, reply));
fastify.post('/:id/configuration/database', async (request, reply) => await saveConnectedDatabase(request, reply));
fastify.get<OnlyId>('/:id/configuration/sshkey', async (request) => await getGitLabSSHKey(request));
fastify.post<OnlyId>('/:id/configuration/sshkey', async (request, reply) => await saveGitLabSSHKey(request, reply));

View File

@@ -20,12 +20,13 @@ export interface SaveApplication extends OnlyId {
denoOptions: string,
baseImage: string,
baseBuildImage: string,
deploymentType: string
deploymentType: string,
baseDatabaseBranch: string
}
}
export interface SaveApplicationSettings extends OnlyId {
Querystring: { domain: string; };
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; isBot: boolean; };
Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; isBot: boolean; isDBBranching: boolean };
}
export interface DeleteApplication extends OnlyId {
Querystring: { domain: string; };

View File

@@ -3,8 +3,7 @@ import cuid from "cuid";
import crypto from "crypto";
import { encrypt, errorHandler, getUIUrl, isDev, prisma } from "../../../lib/common";
import { checkContainer, removeContainer } from "../../../lib/docker";
import { scheduler } from "../../../lib/scheduler";
import { getApplicationFromDBWebhook } from "../../api/v1/applications/handlers";
import { createdBranchDatabase, getApplicationFromDBWebhook, removeBranchDatabase } from "../../api/v1/applications/handlers";
import type { FastifyReply, FastifyRequest } from "fastify";
import type { GitHubEvents, InstallGithub } from "./types";
@@ -67,7 +66,6 @@ export async function configureGitHubApp(request, reply) {
}
export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promise<any> {
try {
const allowedGithubEvents = ['push', 'pull_request'];
const allowedActions = ['opened', 'reopened', 'synchronize', 'closed'];
const githubEvent = request.headers['x-github-event']?.toString().toLowerCase();
@@ -133,8 +131,6 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
where: { id: application.id },
data: { updatedAt: new Date() }
});
console.log(application.id)
await prisma.build.create({
data: {
id: buildId,
@@ -178,6 +174,16 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
where: { id: application.id },
data: { updatedAt: new Date() }
});
if (application.connectedDatabase && pullmergeRequestAction === 'opened' || pullmergeRequestAction === 'reopened') {
// Coolify hosted database
if (application.connectedDatabase.databaseId) {
const databaseId = application.connectedDatabase.databaseId;
const database = await prisma.database.findUnique({ where: { id: databaseId } });
if (database) {
await createdBranchDatabase(database, application.connectedDatabase.hostedDatabaseDBName, pullmergeRequestId);
}
}
}
await prisma.build.create({
data: {
id: buildId,
@@ -197,9 +203,17 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
} else if (pullmergeRequestAction === 'closed') {
if (application.destinationDockerId) {
const id = `${application.id}-${pullmergeRequestId}`;
await removeContainer({ id, dockerId: application.destinationDocker.id });
try {
await removeContainer({ id, dockerId: application.destinationDocker.id });
} catch (error) { }
}
if (application.connectedDatabase.databaseId) {
const databaseId = application.connectedDatabase.databaseId;
const database = await prisma.database.findUnique({ where: { id: databaseId } });
if (database) {
await removeBranchDatabase(database, pullmergeRequestId);
}
}
}
}
}