Merge pull request #3599 from Dokploy/copilot/fix-postgres-deployment-port-conflict

fix: add port conflict validation for database external ports
This commit is contained in:
Mauricio Siu
2026-02-05 02:31:20 -06:00
committed by GitHub
10 changed files with 94 additions and 19 deletions
@@ -73,8 +73,8 @@ export const ShowExternalMariadbCredentials = ({ mariadbId }: Props) => {
toast.success("External Port updated"); toast.success("External Port updated");
await refetch(); await refetch();
}) })
.catch(() => { .catch((error: Error) => {
toast.error("Error saving the external port"); toast.error(error?.message || "Error saving the external port");
}); });
}; };
@@ -73,8 +73,8 @@ export const ShowExternalMongoCredentials = ({ mongoId }: Props) => {
toast.success("External Port updated"); toast.success("External Port updated");
await refetch(); await refetch();
}) })
.catch(() => { .catch((error: Error) => {
toast.error("Error saving the external port"); toast.error(error?.message || "Error saving the external port");
}); });
}; };
@@ -73,8 +73,8 @@ export const ShowExternalMysqlCredentials = ({ mysqlId }: Props) => {
toast.success("External Port updated"); toast.success("External Port updated");
await refetch(); await refetch();
}) })
.catch(() => { .catch((error: Error) => {
toast.error("Error saving the external port"); toast.error(error?.message || "Error saving the external port");
}); });
}; };
@@ -75,8 +75,8 @@ export const ShowExternalPostgresCredentials = ({ postgresId }: Props) => {
toast.success("External Port updated"); toast.success("External Port updated");
await refetch(); await refetch();
}) })
.catch(() => { .catch((error: Error) => {
toast.error("Error saving the external port"); toast.error(error?.message || "Error saving the external port");
}); });
}; };
@@ -74,8 +74,8 @@ export const ShowExternalRedisCredentials = ({ redisId }: Props) => {
toast.success("External Port updated"); toast.success("External Port updated");
await refetch(); await refetch();
}) })
.catch(() => { .catch((error: Error) => {
toast.error("Error saving the external port"); toast.error(error?.message || "Error saving the external port");
}); });
}; };
+18 -3
View File
@@ -1,5 +1,6 @@
import { import {
addNewService, addNewService,
checkPortInUse,
checkServiceAccess, checkServiceAccess,
createMariadb, createMariadb,
createMount, createMount,
@@ -162,9 +163,9 @@ export const mariadbRouter = createTRPCRouter({
saveExternalPort: protectedProcedure saveExternalPort: protectedProcedure
.input(apiSaveExternalPortMariaDB) .input(apiSaveExternalPortMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if ( if (
mongo.environment.project.organizationId !== mariadb.environment.project.organizationId !==
ctx.session.activeOrganizationId ctx.session.activeOrganizationId
) { ) {
throw new TRPCError({ throw new TRPCError({
@@ -172,11 +173,25 @@ export const mariadbRouter = createTRPCRouter({
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
}); });
} }
if (input.externalPort) {
const portCheck = await checkPortInUse(
input.externalPort,
mariadb.serverId || undefined,
);
if (portCheck.isInUse) {
throw new TRPCError({
code: "CONFLICT",
message: `Port ${input.externalPort} is already in use by ${portCheck.conflictingContainer}`,
});
}
}
await updateMariadbById(input.mariadbId, { await updateMariadbById(input.mariadbId, {
externalPort: input.externalPort, externalPort: input.externalPort,
}); });
await deployMariadb(input.mariadbId); await deployMariadb(input.mariadbId);
return mongo; return mariadb;
}), }),
deploy: protectedProcedure deploy: protectedProcedure
.input(apiDeployMariaDB) .input(apiDeployMariaDB)
+15
View File
@@ -1,5 +1,6 @@
import { import {
addNewService, addNewService,
checkPortInUse,
checkServiceAccess, checkServiceAccess,
createMongo, createMongo,
createMount, createMount,
@@ -189,6 +190,20 @@ export const mongoRouter = createTRPCRouter({
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
}); });
} }
if (input.externalPort) {
const portCheck = await checkPortInUse(
input.externalPort,
mongo.serverId || undefined,
);
if (portCheck.isInUse) {
throw new TRPCError({
code: "CONFLICT",
message: `Port ${input.externalPort} is already in use by ${portCheck.conflictingContainer}`,
});
}
}
await updateMongoById(input.mongoId, { await updateMongoById(input.mongoId, {
externalPort: input.externalPort, externalPort: input.externalPort,
}); });
+18 -3
View File
@@ -1,5 +1,6 @@
import { import {
addNewService, addNewService,
checkPortInUse,
checkServiceAccess, checkServiceAccess,
createMount, createMount,
createMysql, createMysql,
@@ -177,9 +178,9 @@ export const mysqlRouter = createTRPCRouter({
saveExternalPort: protectedProcedure saveExternalPort: protectedProcedure
.input(apiSaveExternalPortMySql) .input(apiSaveExternalPortMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if ( if (
mongo.environment.project.organizationId !== mysql.environment.project.organizationId !==
ctx.session.activeOrganizationId ctx.session.activeOrganizationId
) { ) {
throw new TRPCError({ throw new TRPCError({
@@ -187,11 +188,25 @@ export const mysqlRouter = createTRPCRouter({
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
}); });
} }
if (input.externalPort) {
const portCheck = await checkPortInUse(
input.externalPort,
mysql.serverId || undefined,
);
if (portCheck.isInUse) {
throw new TRPCError({
code: "CONFLICT",
message: `Port ${input.externalPort} is already in use by ${portCheck.conflictingContainer}`,
});
}
}
await updateMySqlById(input.mysqlId, { await updateMySqlById(input.mysqlId, {
externalPort: input.externalPort, externalPort: input.externalPort,
}); });
await deployMySql(input.mysqlId); await deployMySql(input.mysqlId);
return mongo; return mysql;
}), }),
deploy: protectedProcedure deploy: protectedProcedure
.input(apiDeployMySql) .input(apiDeployMySql)
@@ -1,5 +1,6 @@
import { import {
addNewService, addNewService,
checkPortInUse,
checkServiceAccess, checkServiceAccess,
createMount, createMount,
createPostgres, createPostgres,
@@ -192,6 +193,20 @@ export const postgresRouter = createTRPCRouter({
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
}); });
} }
if (input.externalPort) {
const portCheck = await checkPortInUse(
input.externalPort,
postgres.serverId || undefined,
);
if (portCheck.isInUse) {
throw new TRPCError({
code: "CONFLICT",
message: `Port ${input.externalPort} is already in use by ${portCheck.conflictingContainer}`,
});
}
}
await updatePostgresById(input.postgresId, { await updatePostgresById(input.postgresId, {
externalPort: input.externalPort, externalPort: input.externalPort,
}); });
+18 -3
View File
@@ -1,5 +1,6 @@
import { import {
addNewService, addNewService,
checkPortInUse,
checkServiceAccess, checkServiceAccess,
createMount, createMount,
createRedis, createRedis,
@@ -201,9 +202,9 @@ export const redisRouter = createTRPCRouter({
saveExternalPort: protectedProcedure saveExternalPort: protectedProcedure
.input(apiSaveExternalPortRedis) .input(apiSaveExternalPortRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if ( if (
mongo.environment.project.organizationId !== redis.environment.project.organizationId !==
ctx.session.activeOrganizationId ctx.session.activeOrganizationId
) { ) {
throw new TRPCError({ throw new TRPCError({
@@ -211,11 +212,25 @@ export const redisRouter = createTRPCRouter({
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
}); });
} }
if (input.externalPort) {
const portCheck = await checkPortInUse(
input.externalPort,
redis.serverId || undefined,
);
if (portCheck.isInUse) {
throw new TRPCError({
code: "CONFLICT",
message: `Port ${input.externalPort} is already in use by ${portCheck.conflictingContainer}`,
});
}
}
await updateRedisById(input.redisId, { await updateRedisById(input.redisId, {
externalPort: input.externalPort, externalPort: input.externalPort,
}); });
await deployRedis(input.redisId); await deployRedis(input.redisId);
return mongo; return redis;
}), }),
deploy: protectedProcedure deploy: protectedProcedure
.input(apiDeployRedis) .input(apiDeployRedis)