Next.js+React web interface for controlling HAProxy clusters (groups of servers), in conjunction with with https://gitgud.io/fatchan/haproxy-protection.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

126 lines
3.5 KiB

const db = require('../db.js');
const { validClustersString, makeArrayIfSingle, extractMap } = require('../util.js');
exports.clustersPage = async (app, req, res, next) => {
return app.render(req, res, '/clusters', {
csrf: req.csrfToken(),
});
};
exports.clustersJson = async (req, res, next) => {
return res.json({
csrf: req.csrfToken(),
user: res.locals.user,
});
}
/**
* POST /global/toggle
* toggle global ACL
*/
exports.globalToggle = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
res.status(403).send('only admin can toggle global');
}
let globalIndex;
try {
await res.locals.haproxy
.showAcl()
.then(list => {
const hdrCntAcl = list.find(x => x.includes("acl 'hdr_cnt'"));
if (hdrCntAcl != null) {
globalIndex = hdrCntAcl.split(' ')[0];
}
});
const globalAcl = await res.locals.haproxy
.showAcl(globalIndex);
if (globalAcl.length === 1 && globalAcl[0].endsWith(0)) {
await res.locals.haproxy
.clearAcl(globalIndex);
} else {
await res.locals.haproxy
.addAcl(globalIndex, '0');
}
} catch (e) {
return next(e);
}
return res.redirect('/account');
};
/**
* POST /cluster
* set active cluster
*/
exports.setCluster = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return res.status(403).send('only admin can change cluster');
}
if (req.body == null || req.body.cluster == null) {
return res.status(400).send('invalid cluster');
}
req.body.cluster = parseInt(req.body.cluster, 10) || 0;
if (!Number.isSafeInteger(req.body.cluster)
|| req.body.cluster > res.locals.user.clusters.length-1) {
return res.status(404).send('invalid cluster');
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$set: {activeCluster: req.body.cluster }});
} catch (e) {
return next(e);
}
return res.redirect('/account');
};
/**
* POST /cluster/add
* add cluster
*/
exports.addCluster = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return res.status(403).send('only admin can add cluster');
}
if (!req.body || !req.body.cluster
|| typeof req.body.cluster !== 'string'
|| !validClustersString(req.body.cluster)) {
return res.status(400).send('invalid cluster');
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$addToSet: {clusters: req.body.cluster }});
} catch (e) {
return next(e);
}
return res.redirect('/clusters');
};
/**
* POST /cluster/delete
* delete cluster
*/
exports.deleteClusters = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return res.status(403).send('only admin can delete cluster');
}
const existingClusters = new Set(res.locals.user.clusters);
req.body.cluster = makeArrayIfSingle(req.body.cluster);
if (!req.body || !req.body.cluster
|| !req.body.cluster.some(c => existingClusters.has(c))) {
return res.status(400).send('invalid cluster');
}
const filteredClusters = res.locals.user.clusters.filter(c => !req.body.cluster.includes(c));
if (filteredClusters.length === 0) {
return res.status(400).send('cant delete last cluster');
}
let newActiveCluster = res.locals.user.activeCluster;
if (res.locals.user.activeCluster > filteredClusters.length-1) {
newActiveCluster = 0;
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$set: {clusters: filteredClusters, activeCluster: newActiveCluster }});
} catch (e) {
return next(e);
}
return res.redirect('/clusters');
};