mirror of
https://github.com/moghtech/komodo.git
synced 2026-08-02 10:58:59 -05:00
add prune containers functionality
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
CREATE_NETWORK,
|
||||
DELETE_NETWORK,
|
||||
GET_SERVER_STATS,
|
||||
PRUNE_CONTAINERS,
|
||||
PRUNE_IMAGES,
|
||||
PRUNE_NETWORKS,
|
||||
REMOVE_SERVER,
|
||||
@@ -13,7 +14,7 @@ import { FastifyInstance } from "fastify";
|
||||
import { WebSocket } from "ws";
|
||||
import addServer from "./add";
|
||||
import { createServerNetwork, deleteServerNetwork } from "./networks";
|
||||
import { pruneServerImages, pruneServerNetworks } from "./prune";
|
||||
import { pruneServerContainers, pruneServerImages, pruneServerNetworks } from "./prune";
|
||||
import removeServer from "./remove";
|
||||
import updateServer from "./update";
|
||||
|
||||
@@ -27,7 +28,11 @@ async function serverMessages(
|
||||
case ADD_SERVER:
|
||||
const created = message.server && (await addServer(app, user, message));
|
||||
if (created) {
|
||||
app.broadcast(ADD_SERVER, { server: created }, app.serverUserFilter(created._id));
|
||||
app.broadcast(
|
||||
ADD_SERVER,
|
||||
{ server: created },
|
||||
app.serverUserFilter(created._id)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -35,7 +40,11 @@ async function serverMessages(
|
||||
const removed =
|
||||
message.serverID && (await removeServer(app, user, message));
|
||||
if (removed) {
|
||||
app.broadcast(REMOVE_SERVER, { serverID: message.serverID }, app.serverUserFilter(removed._id, removed));
|
||||
app.broadcast(
|
||||
REMOVE_SERVER,
|
||||
{ serverID: message.serverID },
|
||||
app.serverUserFilter(removed._id, removed)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -43,7 +52,11 @@ async function serverMessages(
|
||||
const updated =
|
||||
message.server && (await updateServer(app, user, message));
|
||||
if (updated) {
|
||||
app.broadcast(UPDATE_SERVER, { server: updated }, app.serverUserFilter(updated._id));
|
||||
app.broadcast(
|
||||
UPDATE_SERVER,
|
||||
{ server: updated },
|
||||
app.serverUserFilter(updated._id)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -51,6 +64,10 @@ async function serverMessages(
|
||||
await pruneServerImages(app, client, user, message);
|
||||
return true;
|
||||
|
||||
case PRUNE_CONTAINERS:
|
||||
await pruneServerContainers(app, client, user, message);
|
||||
return true;
|
||||
|
||||
case CREATE_NETWORK:
|
||||
message.serverID &&
|
||||
message.name &&
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { User } from "@monitor/types";
|
||||
import {
|
||||
PRUNE_CONTAINERS,
|
||||
PRUNE_IMAGES,
|
||||
PRUNE_NETWORKS,
|
||||
} from "@monitor/util";
|
||||
import { pruneImages, pruneNetworks } from "@monitor/util-node";
|
||||
import { pruneContainers, pruneImages, pruneNetworks } from "@monitor/util-node";
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { WebSocket } from "ws";
|
||||
import { PERMISSIONS_DENY_LOG } from "../../config";
|
||||
import { sendAlert } from "../../util/helpers";
|
||||
import { prunePeripheryNetworks } from "../../util/periphery/networks";
|
||||
import { prunePeripheryImages } from "../../util/periphery/server";
|
||||
import { prunePeripheryContainers, prunePeripheryImages } from "../../util/periphery/server";
|
||||
import { addServerUpdate } from "../../util/updates";
|
||||
|
||||
export async function pruneServerImages(
|
||||
@@ -60,6 +61,58 @@ export async function pruneServerImages(
|
||||
);
|
||||
}
|
||||
|
||||
export async function pruneServerContainers(
|
||||
app: FastifyInstance,
|
||||
client: WebSocket,
|
||||
user: User,
|
||||
{ serverID, note }: { serverID: string; note?: string }
|
||||
) {
|
||||
if (app.serverActionStates.busy(serverID)) {
|
||||
sendAlert(client, "bad", "server busy, try again in a bit");
|
||||
return;
|
||||
}
|
||||
if (user.permissions! < 2) {
|
||||
addServerUpdate(
|
||||
app,
|
||||
serverID,
|
||||
PRUNE_CONTAINERS,
|
||||
"Prune Containers (DENIED)",
|
||||
PERMISSIONS_DENY_LOG,
|
||||
user.username,
|
||||
note,
|
||||
true
|
||||
);
|
||||
return;
|
||||
}
|
||||
const server = await app.servers.findById(serverID);
|
||||
if (!server) return;
|
||||
app.serverActionStates.set(serverID, "pruningContainers", true);
|
||||
app.broadcast(
|
||||
PRUNE_CONTAINERS,
|
||||
{ complete: false, serverID },
|
||||
app.serverUserFilter(serverID)
|
||||
);
|
||||
const { command, log, isError } = server.isCore
|
||||
? await pruneContainers()
|
||||
: await prunePeripheryContainers(server);
|
||||
addServerUpdate(
|
||||
app,
|
||||
serverID,
|
||||
PRUNE_CONTAINERS,
|
||||
command,
|
||||
log,
|
||||
user.username,
|
||||
note,
|
||||
isError
|
||||
);
|
||||
app.serverActionStates.set(serverID, "pruningContainers", false);
|
||||
app.broadcast(
|
||||
PRUNE_CONTAINERS,
|
||||
{ complete: true, serverID },
|
||||
app.serverUserFilter(serverID)
|
||||
);
|
||||
}
|
||||
|
||||
export async function pruneServerNetworks(
|
||||
app: FastifyInstance,
|
||||
client: WebSocket,
|
||||
|
||||
@@ -138,6 +138,7 @@ const actionStates = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
serverActionStates[serverID] = {
|
||||
pruningImages: false,
|
||||
pruningNetworks: false,
|
||||
pruningContainers: false,
|
||||
deleting: false,
|
||||
};
|
||||
},
|
||||
@@ -157,7 +158,7 @@ const actionStates = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
return false;
|
||||
},
|
||||
busy: (serverID: string) => {
|
||||
for (const type of ["pruningImages", "pruningNetworks", "deleting"]) {
|
||||
for (const type of ["pruningImages", "pruningNetworks", "pruningContainers", "deleting"]) {
|
||||
if (serverActionStates[serverID][type]) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -12,6 +12,16 @@ export async function prunePeripheryImages({ address, passkey }: Server) {
|
||||
.then(({ data }) => data);
|
||||
}
|
||||
|
||||
export async function prunePeripheryContainers({ address, passkey }: Server) {
|
||||
return await axios
|
||||
.get<CommandLogError>(`${address}/containers/prune`, {
|
||||
headers: {
|
||||
Authorization: passkey || SECRETS.PASSKEY,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => data);
|
||||
}
|
||||
|
||||
export async function getPeripheryDockerStats({ address, passkey }: Server) {
|
||||
return await axios
|
||||
.get<DockerStat[]>(`${address}/stats`, {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
useContext,
|
||||
} from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { PRUNE_IMAGES } from "@monitor/util";
|
||||
import { PRUNE_CONTAINERS, PRUNE_IMAGES, PRUNE_NETWORKS } from "@monitor/util";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { getServerActionState } from "../../util/query";
|
||||
|
||||
@@ -20,6 +20,7 @@ export const ActionStateProvider: Component<{}> = (p) => {
|
||||
const [actions, setActions] = createStore<ServerActionState>({
|
||||
pruningImages: false,
|
||||
pruningNetworks: false,
|
||||
pruningContainers: false,
|
||||
deleting: false,
|
||||
});
|
||||
createEffect(() => {
|
||||
@@ -32,6 +33,20 @@ export const ActionStateProvider: Component<{}> = (p) => {
|
||||
}
|
||||
})
|
||||
);
|
||||
onCleanup(
|
||||
ws.subscribe([PRUNE_NETWORKS], ({ complete, serverID }) => {
|
||||
if (serverID === selected.id()) {
|
||||
setActions("pruningNetworks", !complete);
|
||||
}
|
||||
})
|
||||
);
|
||||
onCleanup(
|
||||
ws.subscribe([PRUNE_CONTAINERS], ({ complete, serverID }) => {
|
||||
if (serverID === selected.id()) {
|
||||
setActions("pruningContainers", !complete);
|
||||
}
|
||||
})
|
||||
);
|
||||
return <context.Provider value={actions}>{p.children}</context.Provider>;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { pushNotification } from "../..";
|
||||
import { PRUNE_IMAGES, PRUNE_NETWORKS } from "@monitor/util";
|
||||
import { PRUNE_CONTAINERS, PRUNE_IMAGES, PRUNE_NETWORKS } from "@monitor/util";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import ConfirmButton from "../util/ConfirmButton";
|
||||
@@ -24,6 +24,9 @@ const Actions: Component<{}> = (p) => {
|
||||
<Flex class={combineClasses("action shadow", themeClass())}>
|
||||
prune images <PruneImages />
|
||||
</Flex>
|
||||
<Flex class={combineClasses("action shadow", themeClass())}>
|
||||
prune containers <PruneContainers />
|
||||
</Flex>
|
||||
<Flex class={combineClasses("action shadow", themeClass())}>
|
||||
prune networks{" "}
|
||||
<ConfirmButton
|
||||
@@ -68,3 +71,29 @@ function PruneImages() {
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
|
||||
function PruneContainers() {
|
||||
const { ws, servers, selected } = useAppState();
|
||||
const server = () => servers.get(selected.id())!;
|
||||
const actions = useActionStates();
|
||||
return (
|
||||
<Show
|
||||
when={!actions.pruningContainers}
|
||||
fallback={
|
||||
<button class="blue">
|
||||
<Loading type="spinner" />
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<ConfirmButton
|
||||
color="blue"
|
||||
onConfirm={() => {
|
||||
ws.send(PRUNE_CONTAINERS, { serverID: server()._id });
|
||||
pushNotification("ok", `pruning containers on ${server().name}...`);
|
||||
}}
|
||||
>
|
||||
<Icon type="cut" />
|
||||
</ConfirmButton>
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { pruneImages, getSystemStats, getDockerStatsJson } from "@monitor/util-node";
|
||||
import { pruneImages, getSystemStats, getDockerStatsJson, pruneContainers } from "@monitor/util-node";
|
||||
import { FastifyInstance } from "fastify";
|
||||
import fp from "fastify-plugin";
|
||||
|
||||
@@ -8,6 +8,11 @@ const server = fp((app: FastifyInstance, _: {}, done: () => void) => {
|
||||
res.send(log);
|
||||
});
|
||||
|
||||
app.get("/containers/prune", { onRequest: [app.auth] }, async (req, res) => {
|
||||
const log = await pruneContainers();
|
||||
res.send(log);
|
||||
});
|
||||
|
||||
app.get("/stats", { onRequest: [app.auth] }, async (req, res) => {
|
||||
const stats = await getDockerStatsJson();
|
||||
res.send(stats);
|
||||
|
||||
Vendored
+1
@@ -182,6 +182,7 @@ export type DeployActionState = {
|
||||
export type ServerActionState = {
|
||||
pruningImages: boolean;
|
||||
pruningNetworks: boolean;
|
||||
pruningContainers: boolean;
|
||||
deleting: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ export async function pruneImages() {
|
||||
return await execute("docker image prune -a -f");
|
||||
}
|
||||
|
||||
export async function pruneContainers() {
|
||||
return await execute("docker container prune -f");
|
||||
}
|
||||
|
||||
export async function getNetworks(dockerode: Dockerode): Promise<Network[]> {
|
||||
const networks = await dockerode.listNetworks();
|
||||
return networks.map(({ Name, Driver }) => ({
|
||||
|
||||
@@ -27,6 +27,7 @@ export const ADD_SERVER = "ADD_SERVER";
|
||||
export const REMOVE_SERVER = "REMOVE_SERVER";
|
||||
export const UPDATE_SERVER = "UPDATE_SERVER";
|
||||
export const PRUNE_IMAGES = "PRUNE_IMAGES";
|
||||
export const PRUNE_CONTAINERS = "PRUNE_CONTAINERS";
|
||||
export const GET_SERVER_STATS = "GET_SERVER_STATS";
|
||||
export const CREATE_NETWORK = "CREATE_NETWORK";
|
||||
export const DELETE_NETWORK = "DELETE_NETWORK";
|
||||
|
||||
Reference in New Issue
Block a user