feat: VaultWarden service
This commit is contained in:
		| @@ -36,6 +36,7 @@ | ||||
| 	import Wordpress from '$lib/components/svg/services/Wordpress.svelte'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { post } from '$lib/api'; | ||||
| 	import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte'; | ||||
|  | ||||
| 	const { id } = $page.params; | ||||
| 	const from = $page.url.searchParams.get('from'); | ||||
| @@ -71,6 +72,8 @@ | ||||
| 						<VsCodeServer isAbsolute /> | ||||
| 					{:else if type.name === 'wordpress'} | ||||
| 						<Wordpress isAbsolute /> | ||||
| 					{:else if type.name === 'vaultwarden'} | ||||
| 						<VaultWarden isAbsolute /> | ||||
| 					{/if}{type.fancyName} | ||||
| 				</button> | ||||
| 			</form> | ||||
|   | ||||
| @@ -36,6 +36,7 @@ | ||||
| 	import Wordpress from '$lib/components/svg/services/Wordpress.svelte'; | ||||
| 	import Services from './_Services/_Services.svelte'; | ||||
| 	import { getDomain } from '$lib/components/common'; | ||||
| 	import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte'; | ||||
|  | ||||
| 	export let service; | ||||
| 	export let isRunning; | ||||
| @@ -94,6 +95,10 @@ | ||||
| 			<a href="https://wordpress.org" target="_blank"> | ||||
| 				<Wordpress /> | ||||
| 			</a> | ||||
| 		{:else if service.type === 'vaultwarden'} | ||||
| 			<a href="https://github.com/dani-garcia/vaultwarden" target="_blank"> | ||||
| 				<VaultWarden /> | ||||
| 			</a> | ||||
| 		{/if} | ||||
| 	</div> | ||||
| </div> | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/routes/services/[id]/vaultwarden/index.json.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/routes/services/[id]/vaultwarden/index.json.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| import { getUserDetails } from '$lib/common'; | ||||
| import * as db from '$lib/database'; | ||||
| import { PrismaErrorHandler } from '$lib/database'; | ||||
| import type { RequestHandler } from '@sveltejs/kit'; | ||||
|  | ||||
| export const post: RequestHandler = async (event) => { | ||||
| 	const { status, body } = await getUserDetails(event); | ||||
| 	if (status === 401) return { status, body }; | ||||
| 	const { id } = event.params; | ||||
|  | ||||
| 	let { name, fqdn } = await event.request.json(); | ||||
| 	if (fqdn) fqdn = fqdn.toLowerCase(); | ||||
|  | ||||
| 	try { | ||||
| 		await db.updateVaultWardenService({ id, fqdn, name }); | ||||
| 		return { status: 201 }; | ||||
| 	} catch (error) { | ||||
| 		return PrismaErrorHandler(error); | ||||
| 	} | ||||
| }; | ||||
							
								
								
									
										83
									
								
								src/routes/services/[id]/vaultwarden/start.json.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/routes/services/[id]/vaultwarden/start.json.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| import { asyncExecShell, createDirectories, getEngine, getUserDetails } from '$lib/common'; | ||||
| import * as db from '$lib/database'; | ||||
| import { promises as fs } from 'fs'; | ||||
| import yaml from 'js-yaml'; | ||||
| import type { RequestHandler } from '@sveltejs/kit'; | ||||
| import { letsEncrypt } from '$lib/letsencrypt'; | ||||
| import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; | ||||
| import { getDomain } from '$lib/components/common'; | ||||
| import { getServiceImage, PrismaErrorHandler } from '$lib/database'; | ||||
|  | ||||
| export const post: RequestHandler = async (event) => { | ||||
| 	const { teamId, status, body } = await getUserDetails(event); | ||||
| 	if (status === 401) return { status, body }; | ||||
|  | ||||
| 	const { id } = event.params; | ||||
|  | ||||
| 	try { | ||||
| 		const service = await db.getService({ id, teamId }); | ||||
| 		const { type, version, fqdn, destinationDockerId, destinationDocker } = service; | ||||
|  | ||||
| 		const domain = getDomain(fqdn); | ||||
| 		const isHttps = fqdn.startsWith('https://'); | ||||
|  | ||||
| 		const network = destinationDockerId && destinationDocker.network; | ||||
| 		const host = getEngine(destinationDocker.engine); | ||||
|  | ||||
| 		const { workdir } = await createDirectories({ repository: type, buildId: id }); | ||||
| 		const baseImage = getServiceImage(type); | ||||
|  | ||||
| 		const config = { | ||||
| 			image: `${baseImage}:${version}`, | ||||
| 			volume: `${id}-vaultwarden-data:/data/` | ||||
| 		}; | ||||
|  | ||||
| 		const composeFile = { | ||||
| 			version: '3.8', | ||||
| 			services: { | ||||
| 				[id]: { | ||||
| 					container_name: id, | ||||
| 					image: config.image, | ||||
| 					networks: [network], | ||||
| 					volumes: [config.volume], | ||||
| 					restart: 'always' | ||||
| 				} | ||||
| 			}, | ||||
| 			networks: { | ||||
| 				[network]: { | ||||
| 					external: true | ||||
| 				} | ||||
| 			}, | ||||
| 			volumes: { | ||||
| 				[config.volume.split(':')[0]]: { | ||||
| 					external: true | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 		const composeFileDestination = `${workdir}/docker-compose.yaml`; | ||||
| 		await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); | ||||
| 		try { | ||||
| 			await asyncExecShell( | ||||
| 				`DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}` | ||||
| 			); | ||||
| 		} catch (error) { | ||||
| 			console.log(error); | ||||
| 		} | ||||
| 		try { | ||||
| 			await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); | ||||
| 			await configureSimpleServiceProxyOn({ id, domain, port: 80 }); | ||||
|  | ||||
| 			if (isHttps) { | ||||
| 				await letsEncrypt({ domain, id }); | ||||
| 			} | ||||
| 			await reloadHaproxy(destinationDocker.engine); | ||||
| 			return { | ||||
| 				status: 200 | ||||
| 			}; | ||||
| 		} catch (error) { | ||||
| 			return PrismaErrorHandler(error); | ||||
| 		} | ||||
| 	} catch (error) { | ||||
| 		return PrismaErrorHandler(error); | ||||
| 	} | ||||
| }; | ||||
							
								
								
									
										39
									
								
								src/routes/services/[id]/vaultwarden/stop.json.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/routes/services/[id]/vaultwarden/stop.json.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import { getUserDetails, removeDestinationDocker } from '$lib/common'; | ||||
| import { getDomain } from '$lib/components/common'; | ||||
| import * as db from '$lib/database'; | ||||
| import { PrismaErrorHandler } from '$lib/database'; | ||||
| import { dockerInstance } from '$lib/docker'; | ||||
| import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy'; | ||||
| import type { RequestHandler } from '@sveltejs/kit'; | ||||
|  | ||||
| export const post: RequestHandler = async (event) => { | ||||
| 	const { teamId, status, body } = await getUserDetails(event); | ||||
| 	if (status === 401) return { status, body }; | ||||
|  | ||||
| 	const { id } = event.params; | ||||
|  | ||||
| 	try { | ||||
| 		const service = await db.getService({ id, teamId }); | ||||
| 		const { destinationDockerId, destinationDocker, fqdn } = service; | ||||
| 		const domain = getDomain(fqdn); | ||||
| 		if (destinationDockerId) { | ||||
| 			const engine = destinationDocker.engine; | ||||
|  | ||||
| 			try { | ||||
| 				const found = await checkContainer(engine, id); | ||||
| 				if (found) { | ||||
| 					await removeDestinationDocker({ id, engine }); | ||||
| 				} | ||||
| 			} catch (error) { | ||||
| 				console.error(error); | ||||
| 			} | ||||
| 			await configureSimpleServiceProxyOff({ domain }); | ||||
| 		} | ||||
|  | ||||
| 		return { | ||||
| 			status: 200 | ||||
| 		}; | ||||
| 	} catch (error) { | ||||
| 		return PrismaErrorHandler(error); | ||||
| 	} | ||||
| }; | ||||
| @@ -25,6 +25,7 @@ | ||||
| 	import MinIo from '$lib/components/svg/services/MinIO.svelte'; | ||||
| 	import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte'; | ||||
| 	import Wordpress from '$lib/components/svg/services/Wordpress.svelte'; | ||||
| 	import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte'; | ||||
|  | ||||
| 	export let services; | ||||
| </script> | ||||
| @@ -67,6 +68,8 @@ | ||||
| 						<VsCodeServer isAbsolute /> | ||||
| 					{:else if service.type === 'wordpress'} | ||||
| 						<Wordpress isAbsolute /> | ||||
| 					{:else if service.type === 'vaultwarden'} | ||||
| 						<VaultWarden isAbsolute /> | ||||
| 					{/if} | ||||
| 					<div class="font-bold text-xl text-center truncate"> | ||||
| 						{service.name} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai