From c2c3e3affd317508d8a556d3035a273ac78677d3 Mon Sep 17 00:00:00 2001 From: beckerinj Date: Thu, 26 May 2022 11:01:35 +0300 Subject: [PATCH] get pm2 commands routed through pipeline --- core/src/routes/index.ts | 2 + core/src/routes/pm2.ts | 117 ++++++++++++++++++++++++++ core/src/routes/servers.ts | 35 ++++---- core/src/util/periphery/pm2.ts | 87 ++++++++++++++++++++ core/src/util/periphery/server.ts | 16 +--- periphery/src/config.ts | 4 +- periphery/src/plugins/pm2.ts | 19 +++-- periphery/src/routes/git.ts | 9 +- periphery/src/routes/pm2.ts | 131 ++++++++++++++++++++++++++++-- 9 files changed, 366 insertions(+), 54 deletions(-) create mode 100644 core/src/routes/pm2.ts create mode 100644 core/src/util/periphery/pm2.ts diff --git a/core/src/routes/index.ts b/core/src/routes/index.ts index 716bb49f6..0d711a2fc 100644 --- a/core/src/routes/index.ts +++ b/core/src/routes/index.ts @@ -10,6 +10,7 @@ import secrets from "./secrets"; import listener from "./listener"; import users from "./users"; import healthCheck from "./healthCheck"; +import pm2 from "./pm2"; const routes = fp((app: FastifyInstance, _: {}, done: () => void) => { app @@ -18,6 +19,7 @@ const routes = fp((app: FastifyInstance, _: {}, done: () => void) => { .register(builds) .register(deployments) .register(servers) + .register(pm2) .register(networks) .register(accounts) .register(secrets) diff --git a/core/src/routes/pm2.ts b/core/src/routes/pm2.ts new file mode 100644 index 000000000..3f83b8d63 --- /dev/null +++ b/core/src/routes/pm2.ts @@ -0,0 +1,117 @@ +import { FastifyInstance } from "fastify"; +import fp from "fastify-plugin"; +import { deletePeripheryPm2, getPeripheryPm2Log, getPeripheryPm2Processes, restartPeripheryPm2, startPeripheryPm2, stopPeripheryPm2 } from "../util/periphery/pm2"; + +const pm2 = fp((app: FastifyInstance, _: {}, done: () => void) => { + app.get("/api/server/:id/pm2/processes", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id } = req.params as { id: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const processes = server.isCore ? [] : await getPeripheryPm2Processes(server); + res.send(processes); + }); + + app.get("/api/server/:id/pm2/log/:name", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id, name } = req.params as { id: string; name: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const log = server.isCore ? {} : await getPeripheryPm2Log(server, name); + res.send(log); + }); + + app.get("/api/server/:id/pm2/start/:name", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id, name } = req.params as { id: string; name: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const log = server.isCore ? {} : await startPeripheryPm2(server, name); + res.send(log); + }); + + app.get("/api/server/:id/pm2/stop/:name", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id, name } = req.params as { id: string; name: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const log = server.isCore ? {} : await stopPeripheryPm2(server, name); + res.send(log); + }); + + app.get("/api/server/:id/pm2/restart/:name", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id, name } = req.params as { id: string; name: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const log = server.isCore ? {} : await restartPeripheryPm2(server, name); + res.send(log); + }); + + app.get("/api/server/:id/pm2/delete/:name", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + const { id, name } = req.params as { id: string; name: string }; + const server = await app.servers.findById(id); + if (!server) { + res.status(400); + res.send("server not found"); + return; + } + const user = (await app.users.findById(req.user.id))!; + if (user.permissions! < 1 && !server.owners.includes(user.username)) { + res.status(403); + res.send("inadequate permissions"); + return; + } + const log = server.isCore ? {} : await deletePeripheryPm2(server, name); + res.send(log); + }); + + done(); +}); + +export default pm2; \ No newline at end of file diff --git a/core/src/routes/servers.ts b/core/src/routes/servers.ts index 34b07b8b9..e30cb5a31 100644 --- a/core/src/routes/servers.ts +++ b/core/src/routes/servers.ts @@ -7,7 +7,6 @@ import { FastifyInstance } from "fastify"; import fp from "fastify-plugin"; import { getPeripheryDockerStats, - getPeripheryPm2Processes, getPeripherySystemStats, } from "../util/periphery/server"; import { serverStatusPeriphery } from "../util/periphery/status"; @@ -123,23 +122,23 @@ const servers = fp((app: FastifyInstance, _: {}, done: () => void) => { } ); - app.get("/api/server/:id/pm2", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { - const { id } = req.params as { id: string }; - const server = await app.servers.findById(id); - if (!server) { - res.status(400); - res.send("server not found"); - return; - } - const sender = (await app.users.findById(req.user.id))!; - if (sender.permissions! < 1 && !server.owners.includes(sender.username)) { - res.status(403); - res.send("inadequate permissions"); - return; - } - const processes = server.isCore ? [] : await getPeripheryPm2Processes(server); - res.send(processes); - }); + // app.get("/api/server/:id/pm2", { onRequest: [app.auth, app.userEnabled] }, async (req, res) => { + // const { id } = req.params as { id: string }; + // const server = await app.servers.findById(id); + // if (!server) { + // res.status(400); + // res.send("server not found"); + // return; + // } + // const sender = (await app.users.findById(req.user.id))!; + // if (sender.permissions! < 1 && !server.owners.includes(sender.username)) { + // res.status(403); + // res.send("inadequate permissions"); + // return; + // } + // const processes = server.isCore ? [] : await getPeripheryPm2Processes(server); + // res.send(processes); + // }); app.post( "/api/server/:id/:owner", diff --git a/core/src/util/periphery/pm2.ts b/core/src/util/periphery/pm2.ts new file mode 100644 index 000000000..aba9fbc54 --- /dev/null +++ b/core/src/util/periphery/pm2.ts @@ -0,0 +1,87 @@ +import { Log, PM2Process, Server } from "@monitor/types"; +import axios from "axios"; +import { SECRETS } from "../../config"; + +export async function getPeripheryPm2Processes({ address, passkey }: Server) { + try { + return await axios + .get(`${address}/pm2/processes`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return [] + } +} + +export async function getPeripheryPm2Log({ address, passkey }: Server, name: string) { + try { + return await axios + .get(`${address}/pm2/log/${name}`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return { stderr: "could not reach pm2 client" } + } +} + +export async function startPeripheryPm2({ address, passkey }: Server, name: string) { + try { + return await axios + .get(`${address}/pm2/start/${name}`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return { stderr: "could not reach pm2 client" } + } +} + +export async function stopPeripheryPm2({ address, passkey }: Server, name: string) { + try { + return await axios + .get(`${address}/pm2/stop/${name}`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return { stderr: "could not reach pm2 client" } + } +} + +export async function restartPeripheryPm2({ address, passkey }: Server, name: string) { + try { + return await axios + .get(`${address}/pm2/restart/${name}`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return { stderr: "could not reach pm2 client" } + } +} + +export async function deletePeripheryPm2({ address, passkey }: Server, name: string) { + try { + return await axios + .get(`${address}/pm2/delete/${name}`, { + headers: { + Authorization: passkey || SECRETS.PASSKEY, + }, + }) + .then(({ data }) => data); + } catch (error) { + return { stderr: "could not reach pm2 client" } + } +} \ No newline at end of file diff --git a/core/src/util/periphery/server.ts b/core/src/util/periphery/server.ts index 2b5129518..97ca75f46 100644 --- a/core/src/util/periphery/server.ts +++ b/core/src/util/periphery/server.ts @@ -30,18 +30,4 @@ export async function getPeripherySystemStats({ address, passkey }: Server) { }, }) .then(({ data }) => data); -} - -export async function getPeripheryPm2Processes({ address, passkey }: Server) { - try { - return await axios - .get(`${address}/pm2List`, { - headers: { - Authorization: passkey || SECRETS.PASSKEY, - }, - }) - .then(({ data }) => data); - } catch (error) { - return [] - } -} +} \ No newline at end of file diff --git a/periphery/src/config.ts b/periphery/src/config.ts index 1c32b1481..2f36cb87c 100644 --- a/periphery/src/config.ts +++ b/periphery/src/config.ts @@ -9,4 +9,6 @@ export const PORT = getNumberFromEnv("PORT", 8000); export const SYSROOT = getStringFromEnv("SYSROOT", "/home/ubuntu/"); export const ROOT = "/monitor-root/"; export const CONTAINER_REPO_ROOT = join(ROOT, "repos"); -export const SYS_REPO_ROOT = join(SYSROOT, "repos"); \ No newline at end of file +export const SYS_REPO_ROOT = join(SYSROOT, "repos"); + +export const PM2_CLIENT_PORT = getNumberFromEnv("PM2_CLIENT_PORT", 4000); \ No newline at end of file diff --git a/periphery/src/plugins/pm2.ts b/periphery/src/plugins/pm2.ts index bfd0cd8b1..2368ff719 100644 --- a/periphery/src/plugins/pm2.ts +++ b/periphery/src/plugins/pm2.ts @@ -1,5 +1,7 @@ import { FastifyInstance } from "fastify"; import fp from "fastify-plugin"; +import axios from "axios"; +import { PM2_CLIENT_PORT } from "../config"; declare module "fastify" { interface FastifyInstance { @@ -17,13 +19,18 @@ const pm2 = fp((app: FastifyInstance, _: {}, done: () => void) => { set: (enabled: boolean) => { pm2Enabled = enabled; } - }) - // PM2.connect((err) => { - // if (err) { - // app.pm2Enabled.set(false) - // } - // }) + }); + checkEnabled(app); done(); }); +async function checkEnabled(app: FastifyInstance) { + try { + await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/enabled`); + app.pm2Enabled.set(true); + } catch { + app.pm2Enabled.set(false); + } +} + export default pm2; \ No newline at end of file diff --git a/periphery/src/routes/git.ts b/periphery/src/routes/git.ts index 4c4bd0d04..8408d96b2 100644 --- a/periphery/src/routes/git.ts +++ b/periphery/src/routes/git.ts @@ -67,12 +67,11 @@ const git = fp((app: FastifyInstance, _: {}, done: () => void) => { deployment.onPull.path || "" )} && ${deployment.onPull.command}` )); - res.send( - mergeCommandLogError( - { name: "pull", cle: pullCle }, - { name: "post", cle: onPullCle } - ) + const log = mergeCommandLogError( + { name: "pull", cle: pullCle }, + { name: "post", cle: onPullCle } ); + res.send(log); }); app.post("/repo/delete", { onRequest: [app.auth] }, async (req, res) => { diff --git a/periphery/src/routes/pm2.ts b/periphery/src/routes/pm2.ts index 9a3a5a286..a68d54690 100644 --- a/periphery/src/routes/pm2.ts +++ b/periphery/src/routes/pm2.ts @@ -1,17 +1,130 @@ import { FastifyInstance } from "fastify"; import fp from "fastify-plugin"; +import axios from "axios"; +import { PM2_CLIENT_PORT } from "../config"; const pm2 = fp((app: FastifyInstance, _: {}, done: () => void) => { - app.get("/pm2List", { onRequest: [app.auth] }, async (_, res) => { - // if (app.pm2Enabled.get()) { - // const processes = await listPm2Processes(); - // res.send(processes); - // } else { - // res.send([]); - // } + app.get("/pm2/processes", { onRequest: [app.auth] }, async (_, res) => { + try { + const processes = await getPm2Processes(); + res.send(processes); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } }); - + + app.get("/pm2/log/:name", { onRequest: [app.auth] }, async (req, res) => { + const { name } = req.params as { name: string } + if (name) { + try { + const log = await getPm2Log(name); + res.send(log); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } + } else { + res.status(400); + res.send("no name specified"); + } + }); + + app.get("/pm2/start/:name", { onRequest: [app.auth] }, async (req, res) => { + const { name } = req.params as { name: string }; + if (name) { + try { + const log = await startPm2(name); + res.send(log); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } + } else { + res.status(400); + res.send("no name specified"); + } + }); + + app.get("/pm2/stop/:name", { onRequest: [app.auth] }, async (req, res) => { + const { name } = req.params as { name: string }; + if (name) { + try { + const log = await stopPm2(name); + res.send(log); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } + } else { + res.status(400); + res.send("no name specified"); + } + }); + + app.get("/pm2/restart/:name", { onRequest: [app.auth] }, async (req, res) => { + const { name } = req.params as { name: string }; + if (name) { + try { + const log = await restartPm2(name); + res.send(log); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } + } else { + res.status(400); + res.send("no name specified"); + } + }); + + app.get("/pm2/delete/:name", { onRequest: [app.auth] }, async (req, res) => { + const { name } = req.params as { name: string }; + if (name) { + try { + const log = await deletePm2(name); + res.send(log); + } catch { + res.status(400); + res.send("could not reach pm2 client"); + } + } else { + res.status(400); + res.send("no name specified"); + } + }); + done(); }); -export default pm2; \ No newline at end of file +export default pm2; + +async function getPm2Processes() { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/processes`) + .then(({ data }) => data); +} + +async function getPm2Log(name: string) { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/log/${name}`) + .then(({ data }) => data); +} + +async function startPm2(name: string) { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/start/${name}`) + .then(({ data }) => data); +} + +async function stopPm2(name: string) { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/stop/${name}`) + .then(({ data }) => data); +} + +async function restartPm2(name: string) { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/restart/${name}`) + .then(({ data }) => data); +} + +async function deletePm2(name: string) { + return await axios.get(`http://127.0.0.1:${PM2_CLIENT_PORT}/delete/${name}`) + .then(({ data }) => data); +} \ No newline at end of file