fix: show restarting application & logs

This commit is contained in:
Andras Bacsai 2022-09-09 15:14:58 +02:00
parent 871d1e2440
commit c5bcff0e10
12 changed files with 102 additions and 33 deletions

View File

@ -537,7 +537,7 @@ export async function executeDockerCmd({ debug, buildId, applicationId, dockerId
} }
export async function startTraefikProxy(id: string): Promise<void> { export async function startTraefikProxy(id: string): Promise<void> {
const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } }) const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } })
const found = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true }); const { found } = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true });
const { id: settingsId, ipv4, ipv6 } = await listSettings(); const { id: settingsId, ipv4, ipv6 } = await listSettings();
if (!found) { if (!found) {
@ -621,7 +621,7 @@ export async function configureNetworkTraefikProxy(destination: any): Promise<vo
export async function stopTraefikProxy( export async function stopTraefikProxy(
id: string id: string
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const found = await checkContainer({ dockerId: id, container: 'coolify-proxy' }); const { found } = await checkContainer({ dockerId: id, container: 'coolify-proxy' });
await prisma.destinationDocker.update({ await prisma.destinationDocker.update({
where: { id }, where: { id },
data: { isCoolifyProxyUsed: false } data: { isCoolifyProxyUsed: false }
@ -1062,7 +1062,7 @@ export async function stopTcpHttpProxy(
const { id: dockerId } = destinationDocker; const { id: dockerId } = destinationDocker;
let container = `${id}-${publicPort}`; let container = `${id}-${publicPort}`;
if (forceName) container = forceName; if (forceName) container = forceName;
const found = await checkContainer({ dockerId, container }); const { found } = await checkContainer({ dockerId, container });
try { try {
if (found) { if (found) {
return await executeDockerCmd({ return await executeDockerCmd({
@ -1284,7 +1284,7 @@ export async function startTraefikTCPProxy(
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const { network, id: dockerId, remoteEngine } = destinationDocker; const { network, id: dockerId, remoteEngine } = destinationDocker;
const container = `${id}-${publicPort}`; const container = `${id}-${publicPort}`;
const found = await checkContainer({ dockerId, container, remove: true }); const { found } = await checkContainer({ dockerId, container, remove: true });
const { ipv4, ipv6 } = await listSettings(); const { ipv4, ipv6 } = await listSettings();
let dependentId = id; let dependentId = id;

View File

@ -13,7 +13,7 @@ export function formatLabelsOnDocker(data) {
return container return container
}) })
} }
export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<boolean> { export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> {
let containerFound = false; let containerFound = false;
try { try {
const { stdout } = await executeDockerCmd({ const { stdout } = await executeDockerCmd({
@ -21,9 +21,12 @@ export async function checkContainer({ dockerId, container, remove = false }: {
command: command:
`docker inspect --format '{{json .State}}' ${container}` `docker inspect --format '{{json .State}}' ${container}`
}); });
containerFound = true
const parsedStdout = JSON.parse(stdout); const parsedStdout = JSON.parse(stdout);
const status = parsedStdout.Status; const status = parsedStdout.Status;
const isRunning = status === 'running' || status === 'restarting'; const isRunning = status === 'running';
const isRestarting = status === 'restarting'
const isExited = status === 'exited'
if (status === 'created') { if (status === 'created') {
await executeDockerCmd({ await executeDockerCmd({
dockerId, dockerId,
@ -38,13 +41,23 @@ export async function checkContainer({ dockerId, container, remove = false }: {
`docker rm ${container}` `docker rm ${container}`
}); });
} }
if (isRunning) {
containerFound = true; return {
} found: containerFound,
status: {
isRunning,
isRestarting,
isExited
}
};
} catch (err) { } catch (err) {
// Container not found // Container not found
} }
return containerFound; return {
found: false
};
} }
export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> { export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> {

View File

@ -10,7 +10,8 @@ export default async function ({
branch, branch,
buildId, buildId,
privateSshKey, privateSshKey,
customPort customPort,
forPublic
}: { }: {
applicationId: string; applicationId: string;
workdir: string; workdir: string;
@ -21,11 +22,15 @@ export default async function ({
repodir: string; repodir: string;
privateSshKey: string; privateSshKey: string;
customPort: number; customPort: number;
forPublic: boolean;
}): Promise<string> { }): Promise<string> {
const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, ''); const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, '');
await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId }); await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId });
await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`);
await asyncExecShell(`chmod 600 ${repodir}/id.rsa`); if (!forPublic) {
await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`);
await asyncExecShell(`chmod 600 ${repodir}/id.rsa`);
}
await saveBuildLog({ await saveBuildLog({
line: `Cloning ${repository}:${branch} branch.`, line: `Cloning ${repository}:${branch} branch.`,
@ -33,9 +38,16 @@ export default async function ({
applicationId applicationId
}); });
await asyncExecShell( if (forPublic) {
`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. ` await asyncExecShell(
); `git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. `
);
} else {
await asyncExecShell(
`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. `
);
}
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
return commit.replace('\n', ''); return commit.replace('\n', '');
} }

View File

@ -1116,7 +1116,6 @@ async function startUmamiService(request: FastifyRequest<ServiceStartStop>) {
}, },
volumes: volumeMounts volumes: volumeMounts
}; };
console.log(composeFile)
const composeFileDestination = `${workdir}/docker-compose.yaml`; const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
await startServiceContainers(destinationDocker.id, composeFileDestination) await startServiceContainers(destinationDocker.id, composeFileDestination)

View File

@ -74,14 +74,21 @@ export async function getApplicationStatus(request: FastifyRequest<OnlyId>) {
const { teamId } = request.user const { teamId } = request.user
let isRunning = false; let isRunning = false;
let isExited = false; let isExited = false;
let isRestarting = false;
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
isRunning = await checkContainer({ dockerId: application.destinationDocker.id, container: id }); const status = await checkContainer({ dockerId: application.destinationDocker.id, container: id });
isExited = await isContainerExited(application.destinationDocker.id, id); if (status?.found) {
isRunning = status.status.isRunning;
isExited = status.status.isExited;
isRestarting = status.status.isRestarting
}
// isExited = await isContainerExited(application.destinationDocker.id, id);
} }
return { return {
isRunning, isRunning,
isRestarting,
isExited, isExited,
}; };
} catch ({ status, message }) { } catch ({ status, message }) {
@ -339,7 +346,7 @@ export async function stopPreviewApplication(request: FastifyRequest<StopPreview
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
const container = `${id}-${pullmergeRequestId}` const container = `${id}-${pullmergeRequestId}`
const { id: dockerId } = application.destinationDocker; const { id: dockerId } = application.destinationDocker;
const found = await checkContainer({ dockerId, container }); const { found } = await checkContainer({ dockerId, container });
if (found) { if (found) {
await removeContainer({ id: container, dockerId: application.destinationDocker.id }); await removeContainer({ id: container, dockerId: application.destinationDocker.id });
} }
@ -463,7 +470,7 @@ export async function stopApplication(request: FastifyRequest<OnlyId>, reply: Fa
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
const { id: dockerId } = application.destinationDocker; const { id: dockerId } = application.destinationDocker;
const found = await checkContainer({ dockerId, container: id }); const { found } = await checkContainer({ dockerId, container: id });
if (found) { if (found) {
await removeContainer({ id, dockerId: application.destinationDocker.id }); await removeContainer({ id, dockerId: application.destinationDocker.id });
} }

View File

@ -229,7 +229,7 @@ export async function getDestinationStatus(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params
const destination = await prisma.destinationDocker.findUnique({ where: { id } }) const destination = await prisma.destinationDocker.findUnique({ where: { id } })
const isRunning = await checkContainer({ dockerId: destination.id, container: 'coolify-proxy', remove: true }) const { found: isRunning } = await checkContainer({ dockerId: destination.id, container: 'coolify-proxy', remove: true })
return { return {
isRunning isRunning
} }

View File

@ -43,13 +43,17 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
let isRunning = false; let isRunning = false;
let isExited = false let isExited = false
let isRestarting = false;
const service = await getServiceFromDB({ id, teamId }); const service = await getServiceFromDB({ id, teamId });
const { destinationDockerId, settings } = service; const { destinationDockerId, settings } = service;
if (destinationDockerId) { if (destinationDockerId) {
isRunning = await checkContainer({ dockerId: service.destinationDocker.id, container: id }); const status = await checkContainer({ dockerId: service.destinationDocker.id, container: id });
isExited = await isContainerExited(service.destinationDocker.id, id); if (status?.found) {
isRunning = status.status.isRunning;
isExited = status.status.isExited;
isRestarting = status.status.isRestarting
}
} }
return { return {
isRunning, isRunning,
@ -554,7 +558,7 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp
}); });
try { try {
const isRunning = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` }); const { found: isRunning } = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` });
if (isRunning) { if (isRunning) {
await executeDockerCmd({ await executeDockerCmd({
dockerId: destinationDocker.id, dockerId: destinationDocker.id,

View File

@ -154,7 +154,7 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
if (application.settings.previews) { if (application.settings.previews) {
if (application.destinationDockerId) { if (application.destinationDockerId) {
const isRunning = await checkContainer( const { found: isRunning } = await checkContainer(
{ {
dockerId: application.destinationDocker.id, dockerId: application.destinationDocker.id,
container: application.id container: application.id

View File

@ -107,7 +107,7 @@ export async function gitLabEvents(request: FastifyRequest<GitLabEvents>) {
const buildId = cuid(); const buildId = cuid();
if (application.settings.previews) { if (application.settings.previews) {
if (application.destinationDockerId) { if (application.destinationDockerId) {
const isRunning = await checkContainer( const { found: isRunning } = await checkContainer(
{ {
dockerId: application.destinationDocker.id, dockerId: application.destinationDocker.id,
container: application.id container: application.id

View File

@ -73,6 +73,7 @@ export const status: Writable<any> = writable({
application: { application: {
isRunning: false, isRunning: false,
isExited: false, isExited: false,
isRestarting: false,
loading: false, loading: false,
initialLoading: true initialLoading: true
}, },

View File

@ -154,6 +154,7 @@
const data = await get(`/applications/${id}/status`); const data = await get(`/applications/${id}/status`);
$status.application.isRunning = data.isRunning; $status.application.isRunning = data.isRunning;
$status.application.isExited = data.isExited; $status.application.isExited = data.isExited;
$status.application.isRestarting = data.isRestarting;
$status.application.loading = false; $status.application.loading = false;
$status.application.initialLoading = false; $status.application.initialLoading = false;
} }
@ -162,6 +163,7 @@
$status.application.initialLoading = true; $status.application.initialLoading = true;
$status.application.isRunning = false; $status.application.isRunning = false;
$status.application.isExited = false; $status.application.isExited = false;
$status.application.isRestarting = false;
$status.application.loading = false; $status.application.loading = false;
$location = null; $location = null;
$isDeploymentEnabled = false; $isDeploymentEnabled = false;
@ -171,6 +173,7 @@
setLocation(application, settings); setLocation(application, settings);
$status.application.isRunning = false; $status.application.isRunning = false;
$status.application.isExited = false; $status.application.isExited = false;
$status.application.isRestarting = false;
$status.application.loading = false; $status.application.loading = false;
if ( if (
application.gitSourceId && application.gitSourceId &&
@ -215,7 +218,7 @@
<div class="border border-coolgray-500 h-8" /> <div class="border border-coolgray-500 h-8" />
{/if} {/if}
{#if $status.application.isExited} {#if $status.application.isExited || $status.application.isRestarting}
<a <a
id="applicationerror" id="applicationerror"
href={$isDeploymentEnabled ? `/applications/${id}/logs` : null} href={$isDeploymentEnabled ? `/applications/${id}/logs` : null}
@ -240,7 +243,30 @@
<line x1="12" y1="16" x2="12.01" y2="16" /> <line x1="12" y1="16" x2="12.01" y2="16" />
</svg> </svg>
</a> </a>
<Tooltip triggeredBy="#applicationerror">Application exited with an error!</Tooltip> <Tooltip triggeredBy="#applicationerror">Application exited or restarting!</Tooltip>
<button
id="stop"
on:click={stopApplication}
type="submit"
disabled={!$isDeploymentEnabled}
class="icons bg-transparent text-sm flex items-center space-x-2 text-error"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<rect x="6" y="5" width="4" height="14" rx="1" />
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<Tooltip triggeredBy="#stop">Stop</Tooltip>
{/if} {/if}
{#if $status.application.initialLoading} {#if $status.application.initialLoading}
<button <button

View File

@ -6,7 +6,8 @@
import LoadingLogs from '$lib/components/LoadingLogs.svelte'; import LoadingLogs from '$lib/components/LoadingLogs.svelte';
import { onMount, onDestroy } from 'svelte'; import { onMount, onDestroy } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
import { status } from '$lib/store';
import { goto } from '$app/navigation';
let application: any = {}; let application: any = {};
let logsLoading = false; let logsLoading = false;
let loadLogsInterval: any = null; let loadLogsInterval: any = null;
@ -16,7 +17,13 @@
let followingLogs: any; let followingLogs: any;
let logsEl: any; let logsEl: any;
let position = 0; let position = 0;
if (
!$status.application.isExited &&
!$status.application.isRestarting &&
!$status.application.isRunning
) {
goto(`/applications/${$page.params.id}/`, { replaceState: true });
}
const { id } = $page.params; const { id } = $page.params;
onMount(async () => { onMount(async () => {
const response = await get(`/applications/${id}`); const response = await get(`/applications/${id}`);