Add files via upload

This commit is contained in:
lllllllillllllillll 2023-10-31 21:21:31 -07:00 committed by GitHub
parent 0626792b0d
commit 9597df2524
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 405 additions and 51 deletions

30
app.js
View file

@ -4,7 +4,7 @@ const redis = require('connect-redis');
const app = express();
const routes = require("./routes");
const { serverStats, containerList, containerStats, containerAction } = require('./functions/systeminformation');
const { serverStats, containerList, containerStats, containerAction } = require('./functions/system_information');
let sent_list, clicked;
@ -43,8 +43,6 @@ const io = require('socket.io')(server);
io.engine.use(sessionMiddleware);
io.on('connection', (socket) => {
// set user session
const user_session = socket.request.session;
@ -54,22 +52,16 @@ io.on('connection', (socket) => {
if (sent_list != null) { socket.emit('cards', sent_list); }
// check if an install card has to be sent
if((app.locals.install != '') && (app.locals.install != null)){
socket.emit('install', app.locals.install);
}
if((app.locals.install != '') && (app.locals.install != null)){ socket.emit('install', app.locals.install); }
// send server metrics
let ServerStats = setInterval(async () => {
socket.emit('metrics', await serverStats());
}, 1000);
// send container metrics
// send container list
let ContainerList = setInterval(async () => {
let card_list = await containerList();
if (sent_list !== card_list) {
sent_list = card_list;
app.locals.install = '';
@ -80,20 +72,14 @@ io.on('connection', (socket) => {
// send container metrics
let ContainerStats = setInterval(async () => {
let container_stats = await containerStats();
//split up the array to display the name and stats
for (let i = 0; i < container_stats.length; i++) {
socket.emit('container_stats', container_stats[i]);
}
}, 1000);
// play/pause/stop/restart container
socket.on('clicked', (data) => {
// Prevent multiple clicks
if (clicked == true) { return; } clicked = true;
let buttonPress = {
user: socket.request.session.user,
role: socket.request.session.role,
@ -101,22 +87,14 @@ io.on('connection', (socket) => {
container: data.container,
state: data.state
}
console.log(buttonPress)
containerAction(buttonPress);
clicked = false;
});
socket.on('disconnect', () => {
clearInterval(ServerStats);
clearInterval(ContainerList);
clearInterval(ContainerStats);
});
});

View file

@ -1,5 +1,12 @@
const User = require('../database/UserModel');
const { appCard } = require('../components/appCard')
const { exec, execSync } = require("child_process");
const { dashCard } = require('../components/dashCard');
const yaml = require('js-yaml');
const { install } = require('../functions/package_manager');
const templates_json = require('../templates.json');
let templates = templates_json.templates;
@ -60,7 +67,7 @@ exports.Apps = async function(req, res) {
exports.processApps = async function(req, res) {
exports.searchApps = async function(req, res) {
if (req.session.role == "admin") {
// Get the user.
@ -127,4 +134,63 @@ exports.processApps = async function(req, res) {
// Redirect to the login page
res.redirect("/login");
}
}
exports.Install = async function (req, res) {
if (req.session.role == "admin") {
install(req.body);
let container_info = {
name: req.body.name,
service: req.body.service_name,
state: 'installing',
image: req.body.image,
restart_policy: req.body.restart_policy
}
let installCard = dashCard(container_info);
req.app.locals.install = installCard;
// Redirect to the home page
res.redirect("/");
} else {
// Redirect to the login page
res.redirect("/login");
}
}
exports.Uninstall = async function (req, res) {
if (req.session.role == "admin") {
if (req.body.confirm == 'Yes') {
exec(`docker compose -f ./appdata/${req.body.service_name}/docker-compose.yml down`, (error, stdout, stderr) => {
if (error) { console.error(`error: ${error.message}`); return; }
if (stderr) { console.error(`stderr: ${stderr}`); return; }
console.log(`stdout:\n${stdout}`);
});
}
// Redirect to the home page
res.redirect("/");
} else {
// Redirect to the login page
res.redirect("/login");
}
}

View file

@ -0,0 +1,161 @@
const { writeFileSync, mkdirSync, readFileSync } = require("fs");
const { exec, execSync } = require("child_process");
const { dashCard } = require('../components/dashCard');
const yaml = require('js-yaml');
module.exports.install = async function (data) {
let { service_name, name, image, command_check, command, net_mode, restart_policy } = data;
let { port0, port1, port2, port3, port4, port5 } = data;
let { volume0, volume1, volume2, volume3, volume4, volume5 } = data;
let { env0, env1, env2, env3, env4, env5, env6, env7, env8, env9, env10, env11 } = data;
let { label0, label1, label2, label3, label4, label5, label6, label7, label8, label9, label10, label11 } = data;
if (image.startsWith('https://')){
mkdirSync(`./appdata/${name}`, { recursive: true });
execSync(`curl -o ./appdata/${name}/${name}_stack.yml -L ${image}`);
console.log(`Downloaded stackfile: ${image}`);
let stackfile = yaml.load(readFileSync(`./appdata/${name}/${name}_stack.yml`, 'utf8'));
let services = Object.keys(stackfile.services);
for ( let i = 0; i < services.length; i++ ) {
try {
console.log(stackfile.services[Object.keys(stackfile.services)[i]].environment);
} catch { console.log('no env') }
}
} else {
let compose_file = `version: '3'`;
compose_file += `\nservices:`
compose_file += `\n ${service_name}:`
compose_file += `\n container_name: ${name}`;
compose_file += `\n image: ${image}`;
// Command
if (command_check == 'on') {
compose_file += `\n command: ${command}`
}
// Network mode
if (net_mode == 'host') {
compose_file += `\n network_mode: 'host'`
}
else if (net_mode != 'host' && net_mode != 'docker') {
compose_file += `\n network_mode: '${net_mode}'`
}
// Restart policy
if (restart_policy != '') {
compose_file += `\n restart: ${restart_policy}`
}
// Ports
if ((port0 == 'on' || port1 == 'on' || port2 == 'on' || port3 == 'on' || port4 == 'on' || port5 == 'on') && (net_mode != 'host')) {
compose_file += `\n ports:`
for (let i = 0; i < 6; i++) {
if (data[`port${i}`] == 'on') {
compose_file += `\n - ${data[`port_${i}_external`]}:${data[`port_${i}_internal`]}/${data[`port_${i}_protocol`]}`
}
}
}
// Volumes
if (volume0 == 'on' || volume1 == 'on' || volume2 == 'on' || volume3 == 'on' || volume4 == 'on' || volume5 == 'on') {
compose_file += `\n volumes:`
for (let i = 0; i < 6; i++) {
if (data[`volume${i}`] == 'on') {
compose_file += `\n - ${data[`volume_${i}_bind`]}:${data[`volume_${i}_container`]}:${data[`volume_${i}_readwrite`]}`
}
}
}
// Environment variables
if (env0 == 'on' || env1 == 'on' || env2 == 'on' || env3 == 'on' || env4 == 'on' || env5 == 'on' || env6 == 'on' || env7 == 'on' || env8 == 'on' || env9 == 'on' || env10 == 'on' || env11 == 'on') {
compose_file += `\n environment:`
}
for (let i = 0; i < 12; i++) {
if (data[`env${i}`] == 'on') {
compose_file += `\n - ${data[`env_${i}_name`]}=${data[`env_${i}_default`]}`
}
}
// Add labels
if (label0 == 'on' || label1 == 'on' || label2 == 'on' || label3 == 'on' || label4 == 'on' || label5 == 'on' || label6 == 'on' || label7 == 'on' || label8 == 'on' || label9 == 'on' || label10 == 'on' || label11 == 'on') {
compose_file += `\n labels:`
}
for (let i = 0; i < 12; i++) {
if (data[`label${i}`] == 'on') {
compose_file += `\n - ${data[`label_${i}_name`]}=${data[`label_${i}_value`]}`
}
}
// Add privileged mode
if (data.privileged == 'on') {
compose_file += `\n privileged: true`
}
// Add hardware acceleration to the docker-compose file if one of the environment variables has the label DRINODE
if (env0 == 'on' || env1 == 'on' || env2 == 'on' || env3 == 'on' || env4 == 'on' || env5 == 'on' || env6 == 'on' || env7 == 'on' || env8 == 'on' || env9 == 'on' || env10 == 'on' || env11 == 'on') {
for (let i = 0; i < 12; i++) {
if (data[`env${i}`] == 'on') {
if (data[`env_${i}_name`] == 'DRINODE') {
compose_file += `\n deploy:`
compose_file += `\n resources:`
compose_file += `\n reservations:`
compose_file += `\n devices:`
compose_file += `\n - driver: nvidia`
compose_file += `\n count: 1`
compose_file += `\n capabilities: [gpu]`
}
}
}
}
try {
mkdirSync(`./appdata/${name}`, { recursive: true });
writeFileSync(`./appdata/${name}/docker-compose.yml`, compose_file, function (err) { console.log(err) });
exec(`docker compose -f ./appdata/${name}/docker-compose.yml up -d`, (error, stdout, stderr) => {
if (error) { console.error(`error: ${error.message}`); return; }
if (stderr) { console.error(`stderr: ${stderr}`); return; }
console.log(`stdout:\n${stdout}`);
});
} catch { console.log('error creating directory or compose file') }
}
}
module.exports.uninstall = async function (data) {
if (req.session.role == "admin") {
if (data.confirm == 'Yes') {
exec(`docker compose -f ./appdata/${data.service_name}/docker-compose.yml down`, (error, stdout, stderr) => {
if (error) { console.error(`error: ${error.message}`); return; }
if (stderr) { console.error(`stderr: ${stderr}`); return; }
console.log(`stdout:\n${stdout}`);
});
}
// Redirect to the home page
res.redirect("/");
} else {
// Redirect to the login page
res.redirect("/login");
}
}

View file

@ -0,0 +1,150 @@
const { currentLoad, mem, networkStats, fsSize, dockerContainerStats } = require('systeminformation');
var Docker = require('dockerode');
var docker = new Docker({ socketPath: '/var/run/docker.sock' });
const { dashCard } = require('../components/dashCard');
module.exports.serverStats = async function () {
const cpuUsage = await currentLoad();
const ramUsage = await mem();
const netUsage = await networkStats();
const diskUsage = await fsSize();
const info = {
cpu: Math.round(cpuUsage.currentLoad),
ram: Math.round((ramUsage.active / ramUsage.total) * 100),
tx: netUsage[0].tx_bytes,
rx: netUsage[0].rx_bytes,
disk: diskUsage[0].use,
};
return info;
}
module.exports.containerList = async function () {
let card_list = '';
const data = await docker.listContainers({ all: true });
for (const container of data) {
let imageVersion = container.Image.split('/');
let service = imageVersion[imageVersion.length - 1].split(':')[0];
let containerId = docker.getContainer(container.Id);
let containerInfo = await containerId.inspect();
let open_ports = [];
let external_port = 0;
let internal_port = 0;
for (const [key, value] of Object.entries(containerInfo.HostConfig.PortBindings)) {
open_ports.push(`${value[0].HostPort}`);
external_port = value[0].HostPort;
internal_port = key;
if ((external_port == undefined) || (internal_port == undefined)) {
external_port = 0;
internal_port = 0;
}
}
let volumes = [];
for (const [key, value] of Object.entries(containerInfo.Mounts)) {
volumes.push(`${value.Source}: ${value.Destination}: ${value.RW}`);
}
let environment_variables = [];
for (const [key, value] of Object.entries(containerInfo.Config.Env)) {
environment_variables.push(`${key}: ${value}`);
}
let labels = [];
for (const [key, value] of Object.entries(containerInfo.Config.Labels)) {
labels.push(`${key}: ${value}`);
}
let container_info = {
name: container.Names[0].slice(1),
service: service,
id: container.Id,
state: container.State,
image: container.Image,
external_port: external_port,
internal_port: internal_port
}
let dockerCard = dashCard(container_info);
card_list += dockerCard;
}
return card_list;
}
module.exports.containerStats = async function () {
let container_stats = [];
const data = await docker.listContainers({ all: true });
for (const container of data) {
const stats = await dockerContainerStats(container.Id);
let container_stat = {
name: container.Names[0].slice(1),
cpu: Math.round(stats[0].cpuPercent),
ram: Math.round(stats[0].memPercent)
}
//push stats to an array
container_stats.push(container_stat);
}
return container_stats;
}
module.exports.containerAction = async function (data) {
let { user, role, action, container, state } = data;
console.log(`${user} wants to: ${action} ${container}`);
if (role == 'admin') {
var containerName = docker.getContainer(container);
if ((action == 'start') && (state == 'stopped')) {
containerName.start();
} else if ((action == 'start') && (state == 'paused')) {
containerName.unpause();
} else if ((action == 'stop') && (state != 'stopped')) {
containerName.stop();
} else if ((action == 'pause') && (state == 'running')) {
containerName.pause();
} else if ((action == 'pause') && (state == 'paused')) {
containerName.unpause();
} else if (action == 'restart') {
containerName.restart();
}
} else {
console.log('User is not an admin');
}
}

View file

@ -4,15 +4,14 @@ const router = express.Router();
const { Dashboard } = require("../controllers/dashboard");
const { AddSite, RemoveSite, RefreshSites, DisableSite, EnableSite } = require("../controllers/site_actions");
const { Install, Uninstall } = require("../controllers/app_actions");
const {Apps, processApps} = require("../controllers/apps");
const { Apps, searchApps, Install, Uninstall } = require("../controllers/apps");
const { Users } = require("../controllers/users");
const {Account} = require("../controllers/account");
const {Settings} = require("../controllers/settings");
const {Logout} = require("../controllers/logout");
const {Login, processLogin} = require("../controllers/login");
const {Register, processRegister} = require("../controllers/register");
const { Account } = require("../controllers/account");
const { Settings } = require("../controllers/settings");
const { Logout } = require("../controllers/logout");
const { Login, processLogin } = require("../controllers/login");
const { Register, processRegister } = require("../controllers/register");
@ -31,7 +30,7 @@ router.post("/enablesite", EnableSite)
router.get("/users", Users);
router.get("/apps", Apps);
router.post("/apps", processApps);
router.post("/apps", searchApps);
router.get("/settings", Settings);
router.get("/account", Account);

View file

@ -2196,20 +2196,20 @@
],
"volumes": [
{
"container": "/opt",
"bind": "/home/docker/kasm/opt"
"bind": "/home/docker/kasm/opt",
"container": "/opt"
},
{
"container": "/profiles",
"bind": "/home/docker/kasm/profiles"
"bind": "/home/docker/kasm/profiles",
"container": "/profiles"
},
{
"container": "/dev/input",
"bind": "/dev/input"
"bind": "/dev/input",
"container": "/dev/input"
},
{
"container": "/run/udev/data",
"bind": "/run/udev/data"
"bind": "/run/udev/data",
"container": "/run/udev/data"
}
],
"restart_policy": "unless-stopped"
@ -2225,7 +2225,7 @@
"Tools"
],
"platform": "linux",
"logo": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/libreoffice-logo.png",
"logo": "https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/libreoffice.png",
"image": "linuxserver/libreoffice:latest",
"env": [
{
@ -2511,7 +2511,7 @@
"Tools"
],
"platform": "linux",
"logo": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/phpmyadmin-logo.png",
"logo": "https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/phpmyadmin.png",
"image": "linuxserver/phpmyadmin:latest",
"env": [
{
@ -2561,9 +2561,9 @@
"title": "Pidgin",
"name": "pidgin",
"note": "",
"description": "Pidgin (https://pidgin.im/) is a chat program which lets you log into accounts on multiple chat networks simultaneously. This means that you can be chatting with friends on XMPP and sitting in an IRC channel at the same time.",
"description": "Pidgin is a chat program which lets you log into accounts on multiple chat networks simultaneously. This means that you can be chatting with friends on XMPP and sitting in an IRC channel at the same time.",
"platform": "linux",
"logo": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/pidgin-logo.png",
"logo": "https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/pidgin.png",
"image": "linuxserver/pidgin:latest",
"env": [
{
@ -2591,8 +2591,8 @@
],
"volumes": [
{
"container": "/config",
"bind": "/home/docker/pidgin/config"
"bind": "/home/docker/pidgin",
"container": "/config"
}
],
"restart_policy": "unless-stopped"
@ -2602,9 +2602,9 @@
"title": "Remmina",
"name": "remmina",
"note": "",
"description": "[Remmina](https://remmina.org/) is a remote desktop client written in GTK, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large or tiny screens. Remmina supports multiple network protocols, in an integrated and consistent user interface. Currently RDP, VNC, SPICE, NX, XDMCP, SSH and EXEC are supported.",
"description": "Remmina is a remote desktop client written in GTK, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large or tiny screens. Remmina supports multiple network protocols, in an integrated and consistent user interface. Currently RDP, VNC, SPICE, NX, XDMCP, SSH and EXEC are supported.",
"platform": "linux",
"logo": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/remmina-icon.png",
"logo": "https://raw.githubusercontent.com/lllllllillllllillll/DweebUI-Icons/main/remmina.png",
"image": "linuxserver/remmina:latest",
"env": [
{