feat: add host path to any container

This commit is contained in:
Andras Bacsai 2023-03-07 11:15:05 +01:00
parent 3e81d7e9cb
commit 1c237affb4
8 changed files with 60 additions and 18 deletions

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "ApplicationPersistentStorage" ADD COLUMN "hostPath" TEXT;

View File

@ -195,6 +195,7 @@ model ApplicationSettings {
model ApplicationPersistentStorage {
id String @id @default(cuid())
applicationId String
hostPath String?
path String
oldPath Boolean @default(false)
createdAt DateTime @default(now())

View File

@ -110,6 +110,9 @@ import * as buildpacks from '../lib/buildPacks';
.replace(/\//gi, '-')
.replace('-app', '')}:${storage.path}`;
}
if (storage.hostPath) {
return `${storage.hostPath}:${storage.path}`
}
return `${applicationId}${storage.path.replace(/\//gi, '-')}:${storage.path}`;
}) || [];
@ -160,7 +163,11 @@ import * as buildpacks from '../lib/buildPacks';
port: exposePort ? `${exposePort}:${port}` : port
});
try {
const composeVolumes = volumes.map((volume) => {
const composeVolumes = volumes.filter(v => {
if (!v.startsWith('.') && !v.startsWith('..') && !v.startsWith('/') && !v.startsWith('~')) {
return v;
}
}).map((volume) => {
return {
[`${volume.split(':')[0]}`]: {
name: volume.split(':')[0]
@ -381,6 +388,9 @@ import * as buildpacks from '../lib/buildPacks';
.replace(/\//gi, '-')
.replace('-app', '')}:${storage.path}`;
}
if (storage.hostPath) {
return `${storage.hostPath}:${storage.path}`
}
return `${applicationId}${storage.path.replace(/\//gi, '-')}:${storage.path}`;
}) || [];
@ -691,7 +701,11 @@ import * as buildpacks from '../lib/buildPacks';
await saveDockerRegistryCredentials({ url, username, password, workdir });
}
try {
const composeVolumes = volumes.map((volume) => {
const composeVolumes = volumes.filter(v => {
if (!v.startsWith('.') && !v.startsWith('..') && !v.startsWith('/') && !v.startsWith('~')) {
return v;
}
}).map((volume) => {
return {
[`${volume.split(':')[0]}`]: {
name: volume.split(':')[0]

View File

@ -36,12 +36,13 @@ export default async function (data) {
if (volumes.length > 0) {
for (const volume of volumes) {
let [v, path] = volume.split(':');
composeVolumes[v] = {
name: v
};
if (!v.startsWith('.') && !v.startsWith('..') && !v.startsWith('/') && !v.startsWith('~')) {
composeVolumes[v] = {
name: v
};
}
}
}
let networks = {};
for (let [key, value] of Object.entries(dockerComposeYaml.services)) {
value['container_name'] = `${applicationId}-${key}`;
@ -78,6 +79,7 @@ export default async function (data) {
if (value['volumes']?.length > 0) {
value['volumes'] = value['volumes'].map((volume) => {
let [v, path, permission] = volume.split(':');
console.log(v, path, permission)
if (
v.startsWith('.') ||
v.startsWith('..') ||
@ -106,6 +108,7 @@ export default async function (data) {
value['volumes'].push(volume);
}
}
console.log({ volumes, composeVolumes })
if (dockerComposeConfiguration[key]?.port) {
value['expose'] = [dockerComposeConfiguration[key].port];
}

View File

@ -1633,6 +1633,9 @@ export function errorHandler({
type?: string | null;
}) {
if (message.message) message = message.message;
if (message.includes('Unique constraint failed')) {
message = 'This data is unique and already exists. Please try again with a different value.';
}
if (type === 'normal') {
Sentry.captureException(message);
}

View File

@ -1340,16 +1340,16 @@ export async function getStorages(request: FastifyRequest<OnlyId>) {
export async function saveStorage(request: FastifyRequest<SaveStorage>, reply: FastifyReply) {
try {
const { id } = request.params;
const { path, newStorage, storageId } = request.body;
const { hostPath, path, newStorage, storageId } = request.body;
if (newStorage) {
await prisma.applicationPersistentStorage.create({
data: { path, application: { connect: { id } } }
data: { hostPath, path, application: { connect: { id } } }
});
} else {
await prisma.applicationPersistentStorage.update({
where: { id: storageId },
data: { path }
data: { hostPath, path }
});
}
return reply.code(201).send();

View File

@ -96,6 +96,7 @@ export interface DeleteSecret extends OnlyId {
}
export interface SaveStorage extends OnlyId {
Body: {
hostPath?: string;
path: string;
newStorage: boolean;
storageId: string;

View File

@ -12,6 +12,7 @@
import { errorNotification } from '$lib/common';
import { addToast } from '$lib/store';
import CopyVolumeField from '$lib/components/CopyVolumeField.svelte';
import SimpleExplainer from '$lib/components/SimpleExplainer.svelte';
const { id } = $page.params;
let isHttps = browser && window.location.protocol === 'https:';
export let value: string;
@ -33,11 +34,13 @@
storage.path.replace(/\/\//g, '/');
await post(`/applications/${id}/storages`, {
path: storage.path,
hostPath: storage.hostPath,
storageId: storage.id,
newStorage
});
dispatch('refresh');
if (isNew) {
storage.hostPath = null;
storage.path = null;
storage.id = null;
}
@ -80,27 +83,42 @@
<div class="flex gap-4 pb-2" class:pt-8={isNew}>
{#if storage.applicationId}
{#if storage.oldPath}
<CopyVolumeField
<CopyVolumeField
value="{storage.applicationId}{storage.path.replace(/\//gi, '-').replace('-app', '')}"
/>
{:else if !storage.hostPath}
<CopyVolumeField
value="{storage.applicationId}{storage.path.replace(/\//gi, '-').replace('-app', '')}"
/>
{:else}
<CopyVolumeField
value="{storage.applicationId}{storage.path.replace(/\//gi, '-').replace('-app', '')}"
/>
{/if}
{/if}
{#if isNew}
<div class="w-full">
<input
disabled={!isNew}
readonly={!isNew}
bind:value={storage.hostPath}
placeholder="Host path, example: ~/.directory"
/>
<SimpleExplainer
text="You can mount <span class='text-yellow-400 font-bold'>host paths</span> from the operating system.<br>Leave it empty to define a volume based volume."
/>
</div>
{:else if storage.hostPath}
<input disabled readonly value={storage.hostPath} />
{/if}
<input
disabled={!isNew}
readonly={!isNew}
class="w-full"
bind:value={storage.path}
required
placeholder="eg: /data"
placeholder="Mount point inside the container, example: /data"
/>
<div class="flex items-center justify-center">
<div class="flex items-start justify-center">
{#if isNew}
<div class="w-full lg:w-64">
<button class="btn btn-sm btn-primary w-full" on:click={() => saveStorage(true)}