From a36d7ba9128f3ab63e075cb4aa0e214e91152dbe Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Tue, 15 Mar 2022 04:33:35 -0700 Subject: [PATCH] start on deployments --- core/src/messages/build.ts | 357 ------------------------ core/src/messages/builds/index.ts | 4 - core/src/messages/deployment.ts | 64 ----- core/src/messages/deployments/create.ts | 41 +++ core/src/messages/deployments/delete.ts | 76 +++++ core/src/messages/deployments/index.ts | 78 ++++++ core/src/messages/index.ts | 4 +- util/docker.ts | 18 ++ 8 files changed, 215 insertions(+), 427 deletions(-) delete mode 100644 core/src/messages/build.ts delete mode 100644 core/src/messages/deployment.ts create mode 100644 core/src/messages/deployments/create.ts create mode 100644 core/src/messages/deployments/delete.ts create mode 100644 core/src/messages/deployments/index.ts diff --git a/core/src/messages/build.ts b/core/src/messages/build.ts deleted file mode 100644 index f3b51fa7f..000000000 --- a/core/src/messages/build.ts +++ /dev/null @@ -1,357 +0,0 @@ -import { Build, User } from "@monitor/types"; -import { buildChangelog, clone, dockerBuild, pull } from "@monitor/util"; -import { FastifyInstance } from "fastify"; -import { move, pathExists, remove } from "fs-extra"; -import { WebSocket } from "ws"; -import { PERMISSIONS_DENY_LOG, REGISTRY_URL, REPO_PATH } from "../config"; -import { BUILDING, PULLING } from "../plugins/actionStates"; -import { toDashedName } from "../util/helpers"; -import { addBuildUpdate, addSystemUpdate } from "../util/updates"; - -const CREATE_BUILD = "CREATE_BUILD"; -const DELETE_BUILD = "DELETE_BUILD"; -const UPDATE_BUILD = "UPDATE_BUILD"; -const PULL = "PULL"; -const BUILD = "BUILD"; -const CLONE_REPO = "CLONE_REPO"; - -async function buildMessages( - app: FastifyInstance, - client: WebSocket, - message: any, - user: User -) { - switch (message.type) { - case CREATE_BUILD: - const created = message.build && (await createBuild(app, user, message)); - if (created) { - app.broadcast(CREATE_BUILD, { build: created }); - } - return true; - - case DELETE_BUILD: - const deleted = - message.buildID && (await deleteBuild(app, user, message)); - if (deleted) { - app.broadcast(DELETE_BUILD, { buildID: message.buildID }); - } - return true; - - case UPDATE_BUILD: - const updated = message.build && (await updateBuild(app, user, message)); - if (updated) { - app.broadcast(UPDATE_BUILD, { build: updated }); - } - return true; - - case PULL: - message.buildID && (await pullRepo(app, user, message)); - return true; - - case BUILD: - message.buildID && (await build(app, user, message)); - return true; - - default: - return false; - } -} - -async function createBuild( - app: FastifyInstance, - user: User, - message: { build: Build; note?: string } -) { - if (user.permissions! >= 1) { - try { - const build = await app.builds.create({ - ...message.build, - imageName: toDashedName(message.build.name), - owner: user.username, - }); - app.buildActionStates.add(build._id!); - addBuildUpdate( - app, - build._id!, - CREATE_BUILD, - "Create Build", - { stdout: "Build Created: " + build.name }, - user.username, - message.note - ); - if (build.repo) { - await cloneRepo(app, user, build); - } - return build; - } catch (err) { - addSystemUpdate( - app, - CREATE_BUILD, - "Create Build (ERROR)", - { stderr: JSON.stringify(err) }, - user.username, - message.note, - true - ); - } - } else { - addSystemUpdate( - app, - CREATE_BUILD, - "Create Build (DENIED)", - PERMISSIONS_DENY_LOG, - user.username, - message.note, - true - ); - } -} - -async function deleteBuild( - app: FastifyInstance, - user: User, - { buildID, note }: { buildID: string; note?: string } -) { - const build = await app.builds.findById(buildID).catch(() => {}); - if (!build) return; - if (user.permissions! >= 2 || user.username === build.owner) { - try { - await app.builds.findByIdAndDelete(buildID); - await app.deployments.updateMany( - { buildID: build._id }, - { buildID: undefined } - ); - if (build!.repo) await remove(REPO_PATH + build.imageName); - app.buildActionStates.delete(buildID); - addSystemUpdate( - app, - DELETE_BUILD, - "Delete Build", - {}, - user.username, - note - ); - return true; - } catch (error) { - addSystemUpdate( - app, - DELETE_BUILD, - "Delete Build", - { - stderr: JSON.stringify(error), - }, - user.username, - note, - true - ); - } - } else { - addSystemUpdate( - app, - DELETE_BUILD, - "Delete Build (DENIED)", - PERMISSIONS_DENY_LOG, - user.username, - note, - true - ); - } -} - -async function updateBuild( - app: FastifyInstance, - user: User, - { build, note }: { build: Build; note?: string } -) { - const preBuild = await app.builds.findById(build._id!).catch(() => {}); - if (!preBuild) return; // may want to add some update here - if (user.permissions! >= 2 || user.username === preBuild.owner) { - try { - build.imageName = toDashedName(build.name); - if (build.repo !== preBuild.repo || build.branch !== preBuild.branch) { - // reclone repo if repo is changed - await remove(REPO_PATH + preBuild.imageName).catch(); - if (build.repo) { - await cloneRepo(app, user, build); - } - } else if (build.imageName !== preBuild.imageName) { - if (await pathExists(REPO_PATH + preBuild.imageName)) { - await move( - REPO_PATH + preBuild.imageName, - REPO_PATH + build.imageName - ); - } - // maybe do something more with deployments - } - await app.builds.updateOne({ _id: build._id }, build); - addBuildUpdate( - app, - build._id!, - UPDATE_BUILD, - "Update Build", - { stdout: buildChangelog(preBuild, build) }, - user.username, - note - ); - return build; - } catch (error) { - addBuildUpdate( - app, - build._id!, - UPDATE_BUILD, - "Update Build (ERROR)", - { - stderr: JSON.stringify(error), - }, - user.username, - note, - true - ); - } - } else { - addSystemUpdate( - app, - UPDATE_BUILD, - "Update Build (DENIED)", - PERMISSIONS_DENY_LOG, - user.username, - note, - true - ); - } -} - -async function cloneRepo( - app: FastifyInstance, - user: User, - { imageName, branch, repo, accessToken, _id }: Build -) { - const { command, log, isError } = await clone( - repo!, - imageName!, - branch, - accessToken - ); - addBuildUpdate( - app, - _id!, - CLONE_REPO, - command, - log, - user.username, - "", - !isError - ); -} - -async function pullRepo( - app: FastifyInstance, - user: User, - { buildID, note }: { buildID: string; note?: string } -) { - const build = await app.builds.findById(buildID); - if (!build) return; - if (user.permissions! >= 2 || build.owner === user.username) { - if (!app.buildActionStates.get(buildID, PULLING)) { - app.buildActionStates.set(buildID, PULLING, true); - app.broadcast(PULL, { complete: false, buildID }); - try { - const { imageName, branch } = build; - const { command, log, isError } = await pull( - REPO_PATH + imageName, - branch - ); - addBuildUpdate( - app, - buildID, - PULL, - command, - log, - user.username, - note, - isError - ); - } catch (error) { - addBuildUpdate( - app, - buildID, - PULL, - "Pull (ERROR)", - { stderr: JSON.stringify(error) }, - user.username, - note, - true - ); - } - app.broadcast(PULL, { complete: true, buildID }); - app.buildActionStates.set(buildID, PULLING, false); - } - } else { - addBuildUpdate( - app, - buildID, - PULL, - "Pull (DENIED)", - PERMISSIONS_DENY_LOG, - user.username, - note, - true - ); - } -} - -async function build( - app: FastifyInstance, - user: User, - { buildID, note }: { buildID: string; note?: string } -) { - const build = await app.builds.findById(buildID); - if (!build) return; - if (user.permissions! >= 2 || build.owner === user.username) { - app.buildActionStates.set(buildID, BUILDING, true); - app.broadcast(BUILD, { complete: false, buildID }); - try { - const { command, log, isError } = await dockerBuild( - build, - REPO_PATH, - REGISTRY_URL - ); - addBuildUpdate( - app, - buildID, - BUILD, - command, - log, - user.username, - note, - isError - ); - } catch (error) { - addBuildUpdate( - app, - buildID, - BUILD, - "Build (ERROR)", - { stderr: JSON.stringify(error) }, - user.username, - note, - true - ); - } - app.broadcast(BUILD, { complete: true, buildID }); - app.buildActionStates.set(buildID, BUILDING, false); - } else { - addBuildUpdate( - app, - buildID, - BUILD, - "Build (DENIED)", - PERMISSIONS_DENY_LOG, - user.username, - note, - true - ); - } -} - -export default buildMessages; diff --git a/core/src/messages/builds/index.ts b/core/src/messages/builds/index.ts index 2773a6822..862909f47 100644 --- a/core/src/messages/builds/index.ts +++ b/core/src/messages/builds/index.ts @@ -1,10 +1,6 @@ import { User } from "@monitor/types"; -import { dockerBuild, pull } from "@monitor/util"; import { FastifyInstance } from "fastify"; import { WebSocket } from "ws"; -import { PERMISSIONS_DENY_LOG, REGISTRY_URL, REPO_PATH } from "../../config"; -import { BUILDING, PULLING } from "../../plugins/actionStates"; -import { addBuildUpdate, addSystemUpdate } from "../../util/updates"; import build from "./build"; import createBuild from "./create"; import deleteBuild from "./delete"; diff --git a/core/src/messages/deployment.ts b/core/src/messages/deployment.ts deleted file mode 100644 index 8a10ce644..000000000 --- a/core/src/messages/deployment.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Action, User } from "@monitor/types"; -import { FastifyInstance } from "fastify"; -import { WebSocket } from "ws"; - -const CREATE_DEPLOYMENT = "CREATE_DEPLOYMENT"; -const DELETE_DEPLOYMENT = "DELETE_DEPLOYMENT"; -const UPDATE_DEPLOYMENT = "UPDATE_DEPLOYMENT"; -const DEPLOY = "DEPLOY"; -const REDEPLOY = "REDEPLOY"; -const START_CONTAINER = "START_CONTAINER"; -const STOP_CONTAINER = "STOP_CONTAINER"; -const DELETE_CONTAINER = "DELETE_CONTAINER"; -const REFRESH_CONTAINER_STATUS = "REFRESH_CONTAINER_STATUS"; -const COPY_ENV = "COPY_ENV"; - -const DEPLOY_TIMEOUT = 1000; -const DEPLOY_RECHECK_TIMEOUT = 3000; - -async function deploymentMessages( - app: FastifyInstance, - client: WebSocket, - message: Action & object, - user: User -) { - switch (message.type) { - case CREATE_DEPLOYMENT: - return true; - - case DELETE_DEPLOYMENT: - return true; - - case UPDATE_DEPLOYMENT: - return true; - - case DEPLOY: - return true; - - case REDEPLOY: - return true; - - case START_CONTAINER: - return true; - - case STOP_CONTAINER: - return true; - - case UPDATE_DEPLOYMENT: - return true; - - case DELETE_CONTAINER: - return true; - - case REFRESH_CONTAINER_STATUS: - return true; - - case COPY_ENV: - return true; - - default: - return false; - } -} - -export default deploymentMessages; \ No newline at end of file diff --git a/core/src/messages/deployments/create.ts b/core/src/messages/deployments/create.ts new file mode 100644 index 000000000..3724e6969 --- /dev/null +++ b/core/src/messages/deployments/create.ts @@ -0,0 +1,41 @@ +import { Deployment, User } from "@monitor/types"; +import { FastifyInstance } from "fastify"; +import { CREATE_DEPLOYMENT } from "."; +import { PERMISSIONS_DENY_LOG } from "../../config"; +import { toDashedName } from "../../util/helpers"; +import { addDeploymentUpdate, addSystemUpdate } from "../../util/updates"; + +async function createDeployment( + app: FastifyInstance, + user: User, + { deployment }: { deployment: Deployment } +) { + if (user.permissions! >= 1) { + const created = await app.deployments.create({ + ...deployment, + containerName: toDashedName(deployment.name), + owner: user.username, + }); + app.deployActionStates.add(created._id!); + addDeploymentUpdate( + app, + created._id!, + CREATE_DEPLOYMENT, + "Create Deployment", + { stdout: "Deployment Created: " + deployment.name }, + user.username + ); + } else { + addSystemUpdate( + app, + CREATE_DEPLOYMENT, + "Create Deployment (DENIED)", + PERMISSIONS_DENY_LOG, + user.username, + "", + true + ); + } +} + +export default createDeployment; diff --git a/core/src/messages/deployments/delete.ts b/core/src/messages/deployments/delete.ts new file mode 100644 index 000000000..0ca28bd41 --- /dev/null +++ b/core/src/messages/deployments/delete.ts @@ -0,0 +1,76 @@ +import { User } from "@monitor/types"; +import { FastifyInstance } from "fastify"; +import { DELETE_DEPLOYMENT } from "."; +import { PERMISSIONS_DENY_LOG } from "../../config"; +import { addDeploymentUpdate, addSystemUpdate } from "../../util/updates"; + +const deploymentViewFields = [ + "name", + "image", + "ports", + "volumes", + "environment", + "network", + "logToAWS", + "useServerRoot", + "restart", + "autoDeploy", +]; // the fields shown in the update log + +async function deleteDeployment( + app: FastifyInstance, + user: User, + { deploymentID, note }: { deploymentID: string; note?: string } +) { + const deployment = await app.deployments.findById(deploymentID); + if (!deployment) return; + if (user.permissions! >= 2 || user.username === deployment.owner) { + try { + const stopLog = (deployment.image || deployment.buildID) && ""; // stop container, either locally or remote + if (deployment.image || deployment.buildID) { + // stop container, either locally or remote + } + addSystemUpdate( + app, + DELETE_DEPLOYMENT, + "Delete Deployment", + { + stdout: + "Removed:\n\n" + + deploymentViewFields + .map((field) => { + return `${field}: ${JSON.stringify(deployment[field])}\n`; + }) + .reduce((prev, curr) => prev + curr) + + (stopLog && `\n\nDocker Stop Log:\n\n${JSON.stringify(stopLog)}`), + }, + user.username, + note + ); + return true; + } catch (error) { + addSystemUpdate( + app, + DELETE_DEPLOYMENT, + "Delete Deployment (ERROR)", + { stderr: JSON.stringify(error) }, + user.username, + note, + true + ); + } + } else { + addDeploymentUpdate( + app, + deploymentID, + DELETE_DEPLOYMENT, + "Delete Deployment (DENIED)", + PERMISSIONS_DENY_LOG, + user.username, + note, + true + ); + } +} + +export default deleteDeployment; diff --git a/core/src/messages/deployments/index.ts b/core/src/messages/deployments/index.ts new file mode 100644 index 000000000..edfd7b124 --- /dev/null +++ b/core/src/messages/deployments/index.ts @@ -0,0 +1,78 @@ +import { Action, User } from "@monitor/types"; +import { FastifyInstance } from "fastify"; +import { WebSocket } from "ws"; +import createDeployment from "./create"; +import deleteDeployment from "./delete"; + +export const CREATE_DEPLOYMENT = "CREATE_DEPLOYMENT"; +export const DELETE_DEPLOYMENT = "DELETE_DEPLOYMENT"; +export const UPDATE_DEPLOYMENT = "UPDATE_DEPLOYMENT"; +export const DEPLOY = "DEPLOY"; +export const REDEPLOY = "REDEPLOY"; +export const START_CONTAINER = "START_CONTAINER"; +export const STOP_CONTAINER = "STOP_CONTAINER"; +export const DELETE_CONTAINER = "DELETE_CONTAINER"; +export const REFRESH_CONTAINER_STATUS = "REFRESH_CONTAINER_STATUS"; +export const COPY_ENV = "COPY_ENV"; + +const DEPLOY_TIMEOUT = 1000; +const DEPLOY_RECHECK_TIMEOUT = 3000; + +async function deploymentMessages( + app: FastifyInstance, + client: WebSocket, + message: any, + user: User +) { + switch (message.type) { + case CREATE_DEPLOYMENT: + const created = + message.deployment && (await createDeployment(app, user, message)); + if (created) { + app.broadcast(CREATE_DEPLOYMENT, { deployment: created }); + } + return true; + + case DELETE_DEPLOYMENT: + const deleted = + message.deploymentID && (await deleteDeployment(app, user, message)); + if (deleted) { + app.broadcast(DELETE_DEPLOYMENT, { + deploymentID: message.deploymentID, + }); + } + return true; + + case UPDATE_DEPLOYMENT: + return true; + + case DEPLOY: + return true; + + case REDEPLOY: + return true; + + case START_CONTAINER: + return true; + + case STOP_CONTAINER: + return true; + + case UPDATE_DEPLOYMENT: + return true; + + case DELETE_CONTAINER: + return true; + + case REFRESH_CONTAINER_STATUS: + return true; + + case COPY_ENV: + return true; + + default: + return false; + } +} + +export default deploymentMessages; diff --git a/core/src/messages/index.ts b/core/src/messages/index.ts index 272280026..9800425b1 100644 --- a/core/src/messages/index.ts +++ b/core/src/messages/index.ts @@ -1,8 +1,8 @@ import { Action, User } from "@monitor/types"; import { FastifyInstance } from "fastify"; import { WebSocket } from "ws"; -import buildMessages from "./build"; -import deploymentMessages from "./deployment"; +import buildMessages from "./builds"; +import deploymentMessages from "./deployments"; import serverMessages from "./server"; export default async function handleMessage( diff --git a/util/docker.ts b/util/docker.ts index 250044935..15e6a532b 100644 --- a/util/docker.ts +++ b/util/docker.ts @@ -7,6 +7,24 @@ import { } from "@monitor/types"; import { execute } from "./execute"; +/* Container */ + +export async function startContainer(containerName: string) { + const command = `docker start ${containerName}`; + return { + command, + ...(await execute(command)), + } +} + +export async function deleteContainer(containerName: string) { + const command = `docker stop ${containerName} && docker container rm ${containerName}`; + return { + command, + ...(await execute(command)), + } +} + /* Docker Build */ export async function dockerBuild(