From ad09771f54d50f45be97c72b451439250bbdc6d8 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sun, 23 Apr 2023 13:32:01 +0100 Subject: [PATCH] Extracts docker conversion logic to own file, plus some other stuff --- src/Types.ts | 20 ++++++ src/lib/Header.svelte | 2 +- src/utils/template-to-docker-parser.ts | 88 ++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/utils/template-to-docker-parser.ts diff --git a/src/Types.ts b/src/Types.ts index 283fa26..9bbaf3a 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -80,3 +80,23 @@ export interface DockerHubResponse { content_types: string[]; // An array of supported content types for the repository } +export interface DockerCompose { + version: string; + services: { + [serviceName: string]: { + image: string; + ports?: string[]; + environment?: { [envVar: string]: string }; + volumes?: string[]; + restart?: string; + command?: string; + build?: string | { context: string; dockerfile?: string }; + networks?: string[] | { [networkName: string]: { aliases?: string[] } }; + depends_on?: string[]; + labels?: { [labelName: string]: string }; + }; + }; + networks?: { [networkName: string]: {} }; + volumes?: { [volumeName: string]: {} }; +} + diff --git a/src/lib/Header.svelte b/src/lib/Header.svelte index 1291f3e..e6b654a 100644 --- a/src/lib/Header.svelte +++ b/src/lib/Header.svelte @@ -9,7 +9,7 @@

Portainer Templates

diff --git a/src/utils/template-to-docker-parser.ts b/src/utils/template-to-docker-parser.ts new file mode 100644 index 0000000..2ed423a --- /dev/null +++ b/src/utils/template-to-docker-parser.ts @@ -0,0 +1,88 @@ + +import yaml from 'js-yaml'; +import type { Template, Volume, Service, DockerCompose } from '$src/Types'; + +export const generateDockerRunCommand = (template: Template) => { + let command = `docker run -d \\ \n`; + if (template.ports) { + template.ports.forEach((port) => { + command += ` -p ${port} \\\n`; + }); + } + if (template.env) { + template.env.forEach((env) => { + command += ` -e ${env.name}=\${${env.name}} \\\n`; + }); + } + if (template.volumes) { + template.volumes.forEach((volume: Volume) => { + const readOnly = volume.readonly ? ":ro" : ""; + command += ` -v ${volume.bind}:${volume.container}${readOnly} \\\n`; + }); + } + if (template.restart_policy) { + command += ` --restart=${template.restart_policy} \\\n`; + } + command += ` ${template.image}`; + return command; +}; + +export const generateDockerRunCommands = (stack: Service[]) => { + const commands = stack.map((service) => { + let cmd = `docker run --name ${service.name} -d \\\n`; + if (service.command) { + cmd += ` ${service.command} \\\n`; + } + if (service.env) { + service.env.forEach((envVar) => { + cmd += ` -e "${envVar.value}" \\\n`; + }); + } + if (service.ports) { + service.ports.forEach((port) => { + cmd += ` -p ${port} \\\n`; + }); + } + if (service.volumes) { + service.volumes.forEach((volume) => { + cmd += ` -v ${volume.bind}:${volume.container} \\\n`; + }); + } + if (service.restart_policy) { + cmd += ` --restart=${service.restart_policy} \\\n`; + } + cmd += ` ${service.image}`; + return cmd; + }); + return commands; +} + +export const convertToDockerCompose = (template: Template) => { + const serviceName = template.title.toLowerCase().replace(/[^a-z0-9]+/g, "-"); + const dockerCompose: DockerCompose = { + version: "3.8", + services: { [serviceName]: { image: template.image } }, + }; + if (template.ports && template.ports.length > 0) { + dockerCompose.services[serviceName].ports = template.ports.map((port) => port.replace('/', ':')); + } + if (template.env && template.env.length > 0) { + dockerCompose.services[serviceName].environment = template.env.reduce((envVars, envVar) => { + envVars[envVar.name] = envVar.set || ""; + return envVars; + }, {}); + } + if (template.volumes && template.volumes.length > 0) { + dockerCompose.services[serviceName].volumes = template.volumes.map( + (volume) => `${volume.bind || ""}:${volume.container}` + ); + } + + return yaml.dump(dockerCompose); +}; + +export const convertPortainerStackToDockerCompose = (stack: Service[]) => { + const composeStack = stack.map(({ dockerStats, ...s }) => s); + return yaml.dump(composeStack); +}; +