create servers, docker commands

This commit is contained in:
mbecker20
2022-03-14 01:07:17 -07:00
parent 1bd5e8675a
commit 12ca36f108
16 changed files with 242 additions and 9 deletions
+6
View File
@@ -5,6 +5,7 @@ import {
readJSONFile,
} from "@monitor/util";
export const CORE_SERVER_NAME = getStringFromEnv("CORE_SERVER_NAME", "Monitor Core");
export const SECRETS = readJSONFile("secrets.json");
export const LOG = getBooleanFromEnv("LOG", false);
export const PORT = getNumberFromEnv("PORT", 8000);
@@ -15,3 +16,8 @@ export const MONGO_URL = getStringFromEnv(
);
export const TOKEN_EXPIRES_IN = getNumberFromEnv("TOKEN_EXPIRES_IN", 3000);
export const PASSWORD_SALT_ROUNDS = getNumberFromEnv("PASSWORD_SALT_ROUNDS", 8);
export const SYSROOT = getStringFromEnv("SYSROOT", "/home/ubuntu/"); // the root folder monitor has access to, prepends volumes mounted using useSysroot
export const ROOT = getStringFromEnv("ROOT", "/rootDir/"); // the root folder in the container that SYSROOT is mounted on
export const DEPLOYDATA_ROOT = "deployments/";
export const REPO_PATH = ROOT + "builds/";
export const REGISTRY_URL = getStringFromEnv("REGISTRY_URL", "localhost:5000/");
+3 -1
View File
@@ -4,10 +4,12 @@ import auth from "./util/auth";
import { LOG, PORT } from "./config";
import db from "./util/db";
import ws from "./util/ws";
import docker from "./util/docker";
const app = fastify({ logger: LOG })
.register(fastifyCors)
.register(fastifyCors)
.register(db)
.register(docker)
.register(auth)
.register(ws);
+2 -1
View File
@@ -1,9 +1,10 @@
import { Build } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
const builds = fp((app: FastifyInstance, _: {}, done: () => void) => {
const schema = new Schema({
const schema = new Schema<Build>({
name: { type: String, unique: true, index: true },
/* repo related */
repo: String,
+3 -2
View File
@@ -1,11 +1,13 @@
import { Deployment } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
import { Conversion, EnvironmentVar, Volume } from "./misc";
const deployments = fp((app: FastifyInstance, _: {}, done: () => void) => {
const schema = new Schema({
const schema = new Schema<Deployment>({
name: { type: String, unique: true, index: true },
containerName: { type: String, unique: true, index: true }, // for auto pull of frontend repo as well
owner: { type: String, index: true },
serverID: { type: String, index: true },
buildID: { type: String, index: true }, // if deploying a monitor build
@@ -22,7 +24,6 @@ const deployments = fp((app: FastifyInstance, _: {}, done: () => void) => {
/* to manage repo for static frontend, mounted as a volume */
repo: String,
accessToken: String,
pullName: { type: String, index: true }, // for auto pull of repo
containerMount: String, // the file path to mount repo on inside the container
});
+4 -1
View File
@@ -2,11 +2,12 @@ import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import mongoose, { Model } from "mongoose";
import { MONGO_URL } from "../../config";
import { Build, Deployment, Update, User } from "@monitor/types";
import { Build, Deployment, Server, Update, User } from "@monitor/types";
import users from "./users";
import updates from "./updates";
import deployments from "./deployments";
import builds from "./builds";
import servers from "./servers";
declare module "fastify" {
interface FastifyInstance {
@@ -15,6 +16,7 @@ declare module "fastify" {
deployments: Model<Deployment>;
builds: Model<Build>;
updates: Model<Update>;
servers: Model<Server>;
}
}
@@ -25,6 +27,7 @@ const db = fp((app: FastifyInstance, _: {}, done: () => void) => {
app
.register(users)
.register(servers)
.register(deployments)
.register(builds)
.register(updates);
+22
View File
@@ -0,0 +1,22 @@
import { Server } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
const servers = fp((app: FastifyInstance, _: {}, done: () => void) => {
const schema = new Schema<Server>({
name: { type: String, unique: true },
address: String,
password: String,
port: String,
rootDirectory: String,
enabled: Boolean,
useHTTP: Boolean,
});
app.decorate("servers", app.mongoose.model("Server", schema));
done();
});
export default servers;
+2 -1
View File
@@ -1,10 +1,11 @@
import { Update } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
import { Log } from "./misc";
const updates = fp((app: FastifyInstance, _: {}, done: () => void) => {
const schema = new Schema({
const schema = new Schema<Update>({
buildID: { type: String, index: true },
deploymentID: { type: String, index: true },
serverID: { type: String, index: true },
+2 -1
View File
@@ -1,9 +1,10 @@
import { User } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
const users = fp((app: FastifyInstance, _: {}, done: () => void) => {
const schema = new Schema({
const schema = new Schema<User>({
username: { type: String, index: true, required: true },
permissions: { type: Number, default: 0 },
password: String,
+18
View File
@@ -0,0 +1,18 @@
import { Build } from "@monitor/types";
import { REGISTRY_URL, REPO_PATH } from "../../config";
import { toDashedName } from "../helpers";
export function createDockerBuild({
name,
buildPath,
dockerfilePath,
pullName,
}: Build) {
return `cd ${REPO_PATH}${pullName}${
buildPath ? (buildPath[0] === "/" ? buildPath : "/" + buildPath) : ""
} && docker build -t ${
REGISTRY_URL + toDashedName(name)
} -f ${dockerfilePath} . && docker push ${
REGISTRY_URL + toDashedName(name)
}`;
}
+46
View File
@@ -0,0 +1,46 @@
import { ContainerStatus, Deployment } from "@monitor/types";
import { objFrom2Arrays } from "@monitor/util";
import { FastifyInstance } from "fastify";
export async function allContainerStatusLocal(
app: FastifyInstance,
deploymentsAr: Deployment[]
) {
const statusAr = await app.dockerode.listContainers({ all: true });
const statusNames = statusAr.map((stat) =>
stat.Names[0].slice(1, stat.Names[0].length)
); // they all start with '/'
const status = objFrom2Arrays(
statusNames,
statusAr.map((stat, i) => ({
name: statusNames[i],
Status: stat.Status,
State: stat.State as "running" | "exited",
}))
);
return objFrom2Arrays(
statusNames,
statusNames.map((name) => {
const tryDeployment = getDeployment(status[name], deploymentsAr);
const _id = tryDeployment ? tryDeployment._id : "none";
return {
...status[name],
deploymentID: _id,
};
})
);
}
function getDeployment(
status: ContainerStatus,
deploymentsAr: Deployment[]
) {
for (let i = 0; i < deploymentsAr.length; i++) {
if (deploymentsAr[i].containerName === status.name) {
return deploymentsAr[i];
}
}
return undefined;
}
+16
View File
@@ -0,0 +1,16 @@
import Dockerode from "dockerode";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
declare module "fastify" {
interface FastifyInstance {
dockerode: Dockerode;
}
}
const docker = fp((app: FastifyInstance, _: {}, done: () => void) => {
app.decorate("dockerode", new Dockerode());
done();
});
export default docker;
+87
View File
@@ -0,0 +1,87 @@
import { Build, Conversion, Deployment, EnvironmentVar, Volume } from "@monitor/types";
import { FastifyInstance } from "fastify";
import { DEPLOYDATA_ROOT, REGISTRY_URL, SYSROOT } from "../../config";
export async function createDockerRun(
app: FastifyInstance,
{
buildID,
image,
latest,
ports,
environment,
network,
volumes,
restart,
postImage,
containerName,
containerUser,
}: Deployment,
) {
const _image = buildID
? REGISTRY_URL +
((await app.builds.findById(buildID)) as any as Build).imageName
: image;
return (
`docker pull ${_image}${buildID || latest ? ":latest" : ""} && ` +
`docker run -d --name ${containerName}` +
containerUserString(containerUser) +
portsString(ports) +
volsString(containerName!, volumes) +
envString(environment) +
restartString(restart) +
networkString(network) +
` ${_image}${buildID || latest ? ":latest" : ""}${
postImage ? " " + postImage : ""
}`
);
}
function portsString(ports?: Conversion[]) {
return ports && ports.length > 0
? ports
.map(({ local, container }) => ` -p ${local}:${container}`)
.reduce((prev, curr) => prev + curr)
: "";
}
function volsString(folderName: string, volumes?: Volume[]) {
return volumes && volumes.length > 0
? volumes
.map(({ local, container, useSystemRoot }) => {
const mid = useSystemRoot ? "" : `${DEPLOYDATA_ROOT}${folderName}/`;
const localString =
local.length > 0
? local[0] === "/"
? local.slice(1, local.length)
: local
: "";
return ` -v ${SYSROOT + mid + localString}:${container}`;
})
.reduce((prev, curr) => prev + curr)
: "";
}
function restartString(restart?: string) {
return restart
? ` --restart=${restart}${restart === "on-failure" ? ":10" : ""}`
: "";
}
function envString(environment?: EnvironmentVar[]) {
return environment && environment.length > 0
? environment
.map(({ variable, value }) => ` -e "${variable}=${value}"`)
.reduce((prev, curr) => prev + curr)
: "";
}
function networkString(network?: string) {
return network ? ` --network=${network}` : "";
}
function containerUserString(containerUser?: string) {
return containerUser && containerUser.length > 0
? ` -u ${containerUser}`
: "";
}
+19
View File
@@ -0,0 +1,19 @@
import { Deployment, Server } from "@monitor/types";
import { FastifyInstance } from "fastify";
export function toDashedName(name: string) {
return name.toLowerCase().replaceAll(" ", "-");
}
export async function getDeploymentAndServer(
app: FastifyInstance,
deploymentID: string
) {
const deployment = (await app.deployments.findById(
deploymentID
)) as Deployment;
return {
deployment,
server: (await app.servers.findById(deployment.serverID)) as Server,
};
}
+2 -1
View File
@@ -6,7 +6,8 @@
"es2019",
"es2020.promise",
"es2020.bigint",
"es2020.string"
"es2020.string",
"ESNext"
],
"module": "commonjs",
"target": "es2019",
+1 -1
View File
@@ -86,7 +86,7 @@ export type Deployment = {
/* to manage repo for static frontend, mounted as a volume */
repo?: string;
accessToken?: string;
pullName?: string; // for auto pull of repo
containerName?: string; // also for auto pull of frontend repo
containerMount?: string; // the file path to mount repo on inside the container
};
+9
View File
@@ -1,3 +1,4 @@
import { Collection } from "@monitor/types";
import { readFileSync } from "fs";
export function readJSONFile<T = any>(path: string): T {
@@ -19,3 +20,11 @@ export function getBooleanFromEnv(varName: string, defaultValue: boolean) {
else if (variable === "false") return false;
else return defaultValue;
}
export function objFrom2Arrays<T>(keys: string[], entries: T[]): Collection<T> {
return Object.fromEntries(
keys.map((id, index) => {
return [id, entries[index]];
})
);
}