code cleanup,

disk paths now under instance

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
This commit is contained in:
Arthur Lu 2023-04-24 21:28:58 +00:00
parent eeb96a9164
commit 02dbd0dec7
4 changed files with 60 additions and 72 deletions

12
db.js
View File

@ -4,18 +4,12 @@ template = "localdb.json.template"
filename = "localdb.json"; filename = "localdb.json";
let db = JSON.parse(fs.readFileSync(template)); let db = JSON.parse(fs.readFileSync(template));
/**
* called at app startup, can be used to initialize any variables needed for database access
*/
function init () {
try { try {
load(); load();
} }
catch { catch {
save(); save();
} }
}
function load () { function load () {
db = JSON.parse(fs.readFileSync(filename)); db = JSON.parse(fs.readFileSync(filename));
@ -25,12 +19,12 @@ function save () {
fs.writeFileSync(filename, JSON.stringify(db)); fs.writeFileSync(filename, JSON.stringify(db));
} }
function getResources() { function getResourceConfig() {
return db.resources; return db.resources;
} }
function getUser (username) { function getUserConfig (username) {
return db.users[username]; return db.users[username];
} }
module.exports = {init, getUser, getResources}; module.exports = {getUserConfig, getResourceConfig};

73
main.js
View File

@ -7,8 +7,8 @@ const morgan = require("morgan");
var api = require("./package.json"); var api = require("./package.json");
const {pveAPIToken, listenPort, domain} = require("./vars.js"); const {pveAPIToken, listenPort, domain} = require("./vars.js");
const {checkAuth, requestPVE, handleResponse, getUsedResources, getDiskInfo} = require("./pveutils.js"); const {checkAuth, requestPVE, handleResponse, getDiskInfo} = require("./pve.js");
const {init, getUser, getResources} = require("./db.js"); const {getUserData, approveResources} = require("./utils.js")
const app = express(); const app = express();
app.use(helmet()); app.use(helmet());
@ -43,47 +43,15 @@ app.post("/api/proxmox/*", async (req, res) => { // proxy endpoint for POST prox
res.status(result.status).send(result.data); res.status(result.status).send(result.data);
}); });
async function getUserResources (req, username) { app.get("/api/user", async(req, res) => {
let dbResources = getResources();
let used = await getUsedResources(req, dbResources);
let max = getUser(username).resources.max;
avail = {};
Object.keys(max).forEach((k) => {
avail[k] = max[k] - used[k];
});
return {used: used, max: max, avail: avail, units: dbResources};
}
async function approveResources (request, avail) {
let approved = true;
Object.keys(request).forEach((key) => {
if (!(key in avail)) {
approved = false;
}
else if (avail[key] - request[key] < 0) {
approved = false;
}
});
return approved;
}
app.get("/api/user/resources", async(req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
let userResources = await getUserResources(req, req.cookies.username); res.status(200).send(await getUserData(req, req.body.username));
res.status(200).send({resources: userResources});
res.end(); res.end();
return; return;
}); });
app.get("/api/user/instances", async(req, res) => { app.post("/api/instance/disk/detach", async (req, res) => {
await checkAuth(req.cookies, res);
res.status(200).send({instances: getUser(req.cookies.username).instances})
res.end();
return;
});
app.post("/api/disk/detach", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
if (req.body.disk.includes("unused")) { if (req.body.disk.includes("unused")) {
@ -97,7 +65,7 @@ app.post("/api/disk/detach", async (req, res) => {
await handleResponse(req.body.node, result, res); await handleResponse(req.body.node, result, res);
}); });
app.post("/api/disk/attach", async (req, res) => { app.post("/api/instance/disk/attach", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
let action = {}; let action = {};
@ -108,7 +76,7 @@ app.post("/api/disk/attach", async (req, res) => {
await handleResponse(req.body.node, result, res); await handleResponse(req.body.node, result, res);
}); });
app.post("/api/disk/resize", async (req, res) => { app.post("/api/instance/disk/resize", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// check disk existence // check disk existence
@ -118,14 +86,12 @@ app.post("/api/disk/resize", async (req, res) => {
res.end(); res.end();
return; return;
} }
// get used resources
let userResources = await getUserResources(req, req.cookies.username);
// setup request // setup request
let storage = diskConfig.storage; // get the storage let storage = diskConfig.storage; // get the storage
let request = {}; let request = {};
request[storage] = Number(req.body.size * 1024 ** 3); // setup request object request[storage] = Number(req.body.size * 1024 ** 3); // setup request object
// check request approval // check request approval
if (!await approveResources(request, userResources.avail)) { if (!await approveResources(req, req.body.username, request)) {
res.status(500).send({request: request, error: `Storage ${storage} could not fulfill request of size ${req.body.size}G.`}); res.status(500).send({request: request, error: `Storage ${storage} could not fulfill request of size ${req.body.size}G.`});
res.end(); res.end();
return; return;
@ -136,7 +102,7 @@ app.post("/api/disk/resize", async (req, res) => {
await handleResponse(req.body.node, result, res); await handleResponse(req.body.node, result, res);
}); });
app.post("/api/disk/move", async (req, res) => { app.post("/api/instance/disk/move", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// check disk existence // check disk existence
@ -146,8 +112,6 @@ app.post("/api/disk/move", async (req, res) => {
res.end(); res.end();
return; return;
} }
// get used resources
let userResources = await getUserResources(req, req.cookies.username);
// setup request // setup request
let size = parseInt(diskConfig.size); // get source disk size let size = parseInt(diskConfig.size); // get source disk size
let srcStorage = diskConfig.storage; // get source storage let srcStorage = diskConfig.storage; // get source storage
@ -159,7 +123,7 @@ app.post("/api/disk/move", async (req, res) => {
} }
request[dstStorage] = Number(size); // always decrease destination storage by size request[dstStorage] = Number(size); // always decrease destination storage by size
// check request approval // check request approval
if (!await approveResources(request, userResources.avail)) { if (!await approveResources(req, req.body.username, request)) {
res.status(500).send({request: request, error: `Storage ${req.body.storage} could not fulfill request of size ${req.body.size}G.`}); res.status(500).send({request: request, error: `Storage ${req.body.storage} could not fulfill request of size ${req.body.size}G.`});
res.end(); res.end();
return; return;
@ -178,7 +142,7 @@ app.post("/api/disk/move", async (req, res) => {
await handleResponse(req.body.node, result, res); await handleResponse(req.body.node, result, res);
}); });
app.post("/api/disk/delete", async (req, res) => { app.post("/api/instance/disk/delete", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// only ide or unused are allowed to be deleted // only ide or unused are allowed to be deleted
@ -194,17 +158,15 @@ app.post("/api/disk/delete", async (req, res) => {
await handleResponse(req.body.node, result, res); await handleResponse(req.body.node, result, res);
}); });
app.post("/api/disk/create", async (req, res) => { app.post("/api/instance/disk/create", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// get used resources
let userResources = await getUserResources(req, req.cookies.username);
// setup request // setup request
let request = {}; let request = {};
if (!req.body.disk.includes("ide")) { if (!req.body.disk.includes("ide")) {
request[req.body.storage] = Number(req.body.size * 1024 ** 3); // setup request object request[req.body.storage] = Number(req.body.size * 1024 ** 3); // setup request object
// check request approval // check request approval
if (!await approveResources(request, userResources.avail)) { if (!await approveResources(req, req.body.username, request)) {
res.status(500).send({request: request, error: `Storage ${req.body.storage} could not fulfill request of size ${req.body.size}G.`}); res.status(500).send({request: request, error: `Storage ${req.body.storage} could not fulfill request of size ${req.body.size}G.`});
res.end(); res.end();
return; return;
@ -230,8 +192,6 @@ app.post("/api/disk/create", async (req, res) => {
app.post("/api/resources", async (req, res) => { app.post("/api/resources", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// get used resources
let userResources = await getUserResources(req, req.cookies.username);
// get current config // get current config
let currentConfig = await requestPVE(`/nodes/${req.body.node}/${req.body.type}/${req.body.vmid}/config`, "GET", null, null, pveAPIToken); let currentConfig = await requestPVE(`/nodes/${req.body.node}/${req.body.type}/${req.body.vmid}/config`, "GET", null, null, pveAPIToken);
let request = { let request = {
@ -239,7 +199,7 @@ app.post("/api/resources", async (req, res) => {
memory: Number(req.body.memory) - Number(currentConfig.data.data.memory) memory: Number(req.body.memory) - Number(currentConfig.data.data.memory)
}; };
// check resource approval // check resource approval
if (!await approveResources(request, userResources.avail)) { if (!await approveResources(req, req.body.username, request)) {
res.status(500).send({request: request, error: `Could not fulfil request`}); res.status(500).send({request: request, error: `Could not fulfil request`});
res.end(); res.end();
return; return;
@ -254,8 +214,6 @@ app.post("/api/resources", async (req, res) => {
app.post("/api/instance", async (req, res) => { app.post("/api/instance", async (req, res) => {
// check auth // check auth
await checkAuth(req.cookies, res); await checkAuth(req.cookies, res);
// get used resources
let userResources = await getUserResources(req, req.cookies.username);
// setup request // setup request
let request = { let request = {
cores: Number(req.body.cores), cores: Number(req.body.cores),
@ -294,7 +252,7 @@ app.post("/api/instance", async (req, res) => {
action.name = req.body.name; action.name = req.body.name;
} }
// check resource approval // check resource approval
if (!approveResources(request, userResources.avail)) { // check resource approval if (!await approveResources(req, req.body.username, request)) { // check resource approval
res.status(500).send({request: request, error: `Not enough resources to satisfy request.`}); res.status(500).send({request: request, error: `Not enough resources to satisfy request.`});
res.end(); res.end();
return; return;
@ -314,6 +272,5 @@ app.delete("/api/instance", async (req, res) => {
}); });
app.listen(listenPort, () => { app.listen(listenPort, () => {
init();
console.log(`proxmoxaas-api v${api.version} listening on port ${listenPort}`); console.log(`proxmoxaas-api v${api.version} listening on port ${listenPort}`);
}); });

View File

37
utils.js Normal file
View File

@ -0,0 +1,37 @@
const {getUsedResources} = require("./pve.js");
const {getUserConfig, getResourceConfig} = require("./db.js");
async function getUserData (req, username) {
let resources = await getAllocatedResources(req, username);
let instances = getUserConfig(req.cookies.username).instances;
return {resources: resources, instances: instances};
}
async function getAllocatedResources (req, username) {
let dbResources = getResourceConfig();
let used = await getUsedResources(req, dbResources);
let max = getUserConfig(username).resources.max;
avail = {};
Object.keys(max).forEach((k) => {
avail[k] = max[k] - used[k];
});
return {used: used, max: max, avail: avail, units: dbResources};
}
async function approveResources (req, username, request) {
let avail = (await getAllocatedResources(req, username)).avail;
let approved = true;
Object.keys(request).forEach((key) => {
if (!(key in avail)) {
approved = false;
}
else if (avail[key] - request[key] < 0) {
approved = false;
}
});
return approved;
}
module.exports = {getUserData, approveResources}