import type { Context } from "../context.ts"; import { Resource } from "../resource.ts"; import { DockerApi } from "./api.ts"; /** * Properties for creating a Docker network */ export interface NetworkProps { /** * Network name * * @default ${app}-${stage}-${id} */ name?: string; /** * Network driver to use * @default "bridge" */ driver?: "bridge" | "host" | "none" | "overlay" | "macvlan" | (string & {}); /** * Enable IPv6 on the network * @default false */ enableIPv6?: boolean; /** * Network-scoped alias for containers */ labels?: Record; } /** * Docker Network resource */ export interface Network extends NetworkProps { /** * Network ID */ id: string; /** * Network name */ name: string; /** * Time when the network was created */ createdAt: number; } /** * Create and manage a Docker Network * * @see https://docs.docker.com/engine/network/ * * @example * // Create a simple bridge network * const appNetwork = await Network("app-network", { * name: "app-network" * }); * * @example * // Create a custom network with driver * const overlayNetwork = await Network("overlay-network", { * name: "overlay-network", * driver: "overlay", * enableIPv6: true, * labels: { * "com.example.description": "Network for application services" * } * }); */ export const Network = Resource( "docker::Network", async function ( this: Context, id: string, props: NetworkProps, ): Promise { // Initialize Docker API client const api = new DockerApi(); const networkName = props.name ?? this.output?.name ?? this.scope.createPhysicalName(id); if (this.phase === "update" && this.output.name !== networkName) { this.replace(); } // Handle delete phase if (this.phase === "delete") { if (this.output?.id) { // Remove network await api.removeNetwork(this.output.id); } // Return destroyed state return this.destroy(); } else { // Create the network props.driver = props.driver || "bridge"; try { const networkId = await api.createNetwork(networkName, props.driver); return { ...props, id: networkId, name: networkName, createdAt: Date.now(), }; } catch (error: any) { const errorMessage = error.message || String(error); if ( errorMessage.includes( `network with name ${networkName} already exists`, ) ) { const [details] = await api.inspectNetwork(networkName); if (details) { return { ...props, id: details.Id, name: networkName, createdAt: Date.parse(details.Created) || Date.now(), }; } } throw error; } } }, );