From 8ee42a1a81e442de35c262d82ab1f4070f6e835d Mon Sep 17 00:00:00 2001 From: Omer Mecitoglu Date: Wed, 8 Jan 2025 15:01:21 +0700 Subject: [PATCH] fix: network issue in buildtime Fixes #33 --- src/actions/service.ts | 2 +- src/core/build.ts | 16 +++++++++++++--- src/core/docker.ts | 8 ++++---- src/models/service.ts | 1 + src/operations/getService.ts | 1 + src/operations/getServiceByRepo.ts | 1 + 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/actions/service.ts b/src/actions/service.ts index 63fa2db..67aee5e 100644 --- a/src/actions/service.ts +++ b/src/actions/service.ts @@ -90,7 +90,7 @@ export async function update(id: string, _: unknown, formData: FormData): Promis export async function destroy(id: string, _: FormData) { const service = await getService(db, id); if (service) { - await Promise.all(service.networkIds.map(destroyNetwork)); + await Promise.all(service.networkIds.map(networkId => destroyNetwork(networkId))); } await deleteService(db, id); redirect("/services"); diff --git a/src/core/build.ts b/src/core/build.ts index 724d205..c233859 100644 --- a/src/core/build.ts +++ b/src/core/build.ts @@ -2,23 +2,31 @@ import "server-only"; import { kebabCase } from "change-case"; import { after } from "next/server"; import { GitError } from "simple-git"; -import { buildImage, createContainer, removeContainer } from "~/core/docker"; +import { buildImage, createContainer, createNetwork, destroyNetwork, removeContainer } from "~/core/docker"; import { cloneRepo, deleteRepo } from "~/core/git"; import db from "~/database"; import type { ServiceDTO } from "~/models/service"; import createBuildImage from "~/operations/createBuildImage"; import updateBuildImage from "~/operations/updateBuildImage"; import updateService from "~/operations/updateService"; +import { pluck } from "~/utils/object"; import env from "./env"; import { getProviderVariables } from "./provider"; export async function startBuilding(service: ServiceDTO) { const image = await createBuildImage(db, { serviceId: service.id }); after(async () => { + const providerContainerIds = pluck(service.providers, "containerId").filter(c => c !== null); + const buildNetwork = await createNetwork(`build-${image.id}`, providerContainerIds); try { const repoPath = await cloneRepo(service.repo, service.id); - const networkId = service.providers.at(0)?.networkIds.at(0); - const success = await buildImage(image.id, repoPath, service.environmentVariables, networkId, env.DEBUG_MODE === "yes"); + const success = await buildImage( + image.id, + repoPath, + service.environmentVariables, + buildNetwork.id, + env.DEBUG_MODE === "yes", + ); await deleteRepo(service.id); if (success) { await updateBuildImage(db, image.id, { status: "ready" }); @@ -49,6 +57,8 @@ export async function startBuilding(service: ServiceDTO) { } else { await updateBuildImage(db, image.id, { status: "failed" }); } + } finally { + await destroyNetwork(buildNetwork.id, providerContainerIds); } }); return image; diff --git a/src/core/docker.ts b/src/core/docker.ts index e846f8d..74bb9c9 100644 --- a/src/core/docker.ts +++ b/src/core/docker.ts @@ -160,7 +160,7 @@ export async function createVolume(name: string) { }); } -export async function createNetwork(networkId: string) { +export async function createNetwork(networkId: string, containerIds: string[] = []) { const network = await docker.createNetwork({ Name: networkId, Driver: "bridge", @@ -168,11 +168,13 @@ export async function createNetwork(networkId: string) { Internal: false, Attachable: true, }); + await Promise.all(containerIds.map(containerId => connectContainerToNetwork(containerId, network.id))); return network; } -export async function destroyNetwork(networkId: string) { +export async function destroyNetwork(networkId: string, containerIds: string[] = []) { const network = docker.getNetwork(networkId); + await Promise.all(containerIds.map(containerId => disconnectContainerFromNetwork(containerId, network.id))); await network.remove(); } @@ -183,7 +185,6 @@ async function connectContainerToNetwork(containerId: string, networkId: string) }); } -/* async function disconnectContainerFromNetwork(containerId: string, networkId: string) { const network = docker.getNetwork(networkId); await network.disconnect({ @@ -191,4 +192,3 @@ async function disconnectContainerFromNetwork(containerId: string, networkId: st // Force: true, // is this necessary? }); } -*/ diff --git a/src/models/service.ts b/src/models/service.ts index 3d86823..cc03736 100644 --- a/src/models/service.ts +++ b/src/models/service.ts @@ -16,6 +16,7 @@ const baseSchema = createInsertSchema(services, { id: z.string(), name: z.string(), repo: z.string(), + containerId: z.string().nullable(), networkIds: z.string().array(), variables: z.record(z.string(), z.string()), }).array(), diff --git a/src/operations/getService.ts b/src/operations/getService.ts index d4d243e..59001e2 100644 --- a/src/operations/getService.ts +++ b/src/operations/getService.ts @@ -37,6 +37,7 @@ export default async function getService(db: typeof database, serviceId: string) id: true, name: true, repo: true, + containerId: true, }, with: { networks: { diff --git a/src/operations/getServiceByRepo.ts b/src/operations/getServiceByRepo.ts index d2c0715..be0c30c 100644 --- a/src/operations/getServiceByRepo.ts +++ b/src/operations/getServiceByRepo.ts @@ -36,6 +36,7 @@ export default async function getServiceByRepo(db: typeof database, repo: string id: true, name: true, repo: true, + containerId: true, }, with: { networks: {