mirror of
https://github.com/moghtech/komodo.git
synced 2026-10-30 00:07:14 +00:00
start on deployments
This commit is contained in:
@@ -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;
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user