implement resource checking all config paths

Signed-off-by: Arthur Lu <learthurgo@gmail.com>
This commit is contained in:
Arthur Lu 2023-03-01 00:38:09 +00:00
parent 22e12da060
commit 1f25cc1cd1
3 changed files with 103 additions and 12 deletions

1
db.js
View File

@ -42,6 +42,7 @@ function allocateResources (user, resources) {
let newdb = {}; let newdb = {};
Object.assign(newdb, db); Object.assign(newdb, db);
Object.keys(resources).forEach((element) => { Object.keys(resources).forEach((element) => {
console.log(newdb[user][element] + "-" + resources[element])
newdb[user][element] -= resources[element]; newdb[user][element] -= resources[element];
}); });
try { try {

97
main.js
View File

@ -53,6 +53,11 @@ app.post("/api/disk/detach", async (req, res) => {
return; return;
} }
if (req.body.disk.includes("unused")) {
res.status(500).send({auth: auth, data:{error: `Requested disk ${req.body.disk} cannot be unused. Use /disk/delete to permanently delete unused disks.`}});
return;
}
let action = JSON.stringify({delete: req.body.disk}); let action = JSON.stringify({delete: req.body.disk});
let method = req.body.type === "qemu" ? "POST" : "PUT"; let method = req.body.type === "qemu" ? "POST" : "PUT";
let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken);
@ -90,24 +95,28 @@ app.post("/api/disk/resize", async (req, res) => {
} }
// check resource allocation // check resource allocation
let diskConfig = await getDiskConfig(req.body.node, req.body.type, req.body.vmid, req.body.disk); let diskConfig = await getDiskConfig(req.body.node, req.body.type, req.body.vmid, req.body.disk); // get target disk
if (!diskConfig) { if (!diskConfig) { // exit if disk does not exist
res.status(500).send({auth: auth, data:{error: `requested disk ${req.body.disk} does not exist`}}); res.status(500).send({auth: auth, data:{error: `requested disk ${req.body.disk} does not exist`}});
return;
} }
let storage = diskConfig.split(":")[0]; let storage = diskConfig.split(":")[0]; // get the storage
let request = {}; let request = {};
request[storage] = req.body.size; request[storage] = req.body.size; // setup request object
if (!requestResources(req.cookies.username, request)) { if (!requestResources(req.cookies.username, request)) { // check request approval
res.status(500).send({auth: auth, data:{request: request, error: `${storage} could not fulfill request`}}); res.status(500).send({auth: auth, data:{request: request, error: `Storage ${storage} could not fulfill request of size ${req.body.size}G.`}});
return; return;
} }
let action = JSON.stringify({disk: req.body.disk, size: `+${req.body.size}G`}); let action = JSON.stringify({disk: req.body.disk, size: `+${req.body.size}G`});
let result = await requestPVE(`${vmpath}/resize`, "PUT", req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/resize`, "PUT", req.cookies, action, pveAPIToken);
result = await handleResponse(req.body.node, result); result = await handleResponse(req.body.node, result);
// update resources
if (result.status === 200) { if (result.status === 200) {
allocateResources(req.cookies.username, request); allocateResources(req.cookies.username, request);
} }
res.status(result.status).send({auth: auth, data: result.data}); res.status(result.status).send({auth: auth, data: result.data});
}); });
@ -122,6 +131,25 @@ app.post("/api/disk/move", async (req, res) => {
return; return;
} }
// check resource allocation
let diskConfig = await getDiskConfig(req.body.node, req.body.type, req.body.vmid, req.body.disk); // get source disk
if (!diskConfig) { // exit if source disk does not exist
res.status(500).send({auth: auth, data:{error: `Requested disk ${req.body.disk} does not exist`}});
}
let size = parseInt(diskConfig.split("size=")[1].split("G")[0]); // get source disk size
let srcStorage = diskConfig.split(":")[0]; // get source storage
let dstStorage = req.body.storage; // get destination storage
let request = {};
let release = {};
if (req.body.delete) { // if delete is true, increase resource used by the source storage
release[srcStorage] = size;
}
request[dstStorage] = size; // always decrease destination storage by size
if (!requestResources(req.cookies.username, request)) { // check resource approval
res.status(500).send({auth: auth, data:{request: request, release: release, error: `Storage ${dstStorage} could not fulfill request of size ${size}G.`}});
return;
}
let action = {storage: req.body.storage, delete: req.body.delete}; let action = {storage: req.body.storage, delete: req.body.delete};
if (req.body.type === "qemu") { if (req.body.type === "qemu") {
action.disk = req.body.disk action.disk = req.body.disk
@ -132,6 +160,13 @@ app.post("/api/disk/move", async (req, res) => {
action = JSON.stringify(action); action = JSON.stringify(action);
let result = await requestPVE(`${vmpath}/${route}`, "POST", req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/${route}`, "POST", req.cookies, action, pveAPIToken);
result = await handleResponse(req.body.node, result); result = await handleResponse(req.body.node, result);
// update resources
if (result.status === 200) {
allocateResources(req.cookies.username, request);
releaseResources(req.cookies.username, release);
}
res.status(result.status).send({auth: auth, data: result.data}); res.status(result.status).send({auth: auth, data: result.data});
}); });
@ -145,10 +180,30 @@ app.post("/api/disk/delete", async (req, res) => {
return; return;
} }
if (!req.body.disk.includes("unused") && !req.body.disk.includes("ide")) { // must be ide or unused
res.status(500).send({auth: auth, data:{error: `Requested disk ${req.body.disk} must be unused or ide. Use /disk/detach to detach disks in use.`}});
return;
}
// setup release
let release = {};
if (!req.body.disk.includes("ide")) { // if disk type is ide, then dont bother checking for resources
let diskConfig = await getUnusedDiskData(req.body.node, req.body.type, req.body.vmid, req.body.disk); // get disk config of unused disk
let storage = diskConfig.storage; // get disk storage
let size = diskConfig.size / (1024**3); // get disk size
release[storage] = size;
}
let action = JSON.stringify({delete: req.body.disk}); let action = JSON.stringify({delete: req.body.disk});
let method = req.body.type === "qemu" ? "POST" : "PUT"; let method = req.body.type === "qemu" ? "POST" : "PUT";
let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken);
result = await handleResponse(req.body.node, result); result = await handleResponse(req.body.node, result);
// update resources
if (result.status === 200) {
releaseResources(req.cookies.username, release);
}
res.status(result.status).send({auth: auth, data: result.data}); res.status(result.status).send({auth: auth, data: result.data});
}); });
@ -162,6 +217,16 @@ app.post("/api/disk/create", async (req, res) => {
return; return;
} }
// check resource allocation
let request = {};
if (!req.body.disk.includes("ide")) {
request[req.body.storage] = req.body.size; // setup request object
if (!requestResources(req.cookies.username, request)) { // check request approval
res.status(500).send({auth: auth, data:{request: request, error: `Storage ${storage} could not fulfill request of size ${req.body.size}G.`}});
return;
}
}
let action = {}; let action = {};
if (req.body.disk.includes("ide") && req.body.iso) { if (req.body.disk.includes("ide") && req.body.iso) {
action[req.body.disk] = `${req.body.iso},media=cdrom`; action[req.body.disk] = `${req.body.iso},media=cdrom`;
@ -176,6 +241,13 @@ app.post("/api/disk/create", async (req, res) => {
let method = req.body.type === "qemu" ? "POST" : "PUT"; let method = req.body.type === "qemu" ? "POST" : "PUT";
let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken);
result = await handleResponse(req.body.node, result); result = await handleResponse(req.body.node, result);
// update resources
// update resources
if (result.status === 200) {
allocateResources(req.cookies.username, request);
}
res.status(result.status).send({auth: auth, data: result.data}); res.status(result.status).send({auth: auth, data: result.data});
}); });
@ -189,10 +261,23 @@ app.post("/api/resources", async (req, res) => {
return; return;
} }
let currentConfig = await requestPVE(`${vmpath}/config`, "GET", null, null, pveAPIToken);
let request = {cores: req.body.cores - currentConfig.data.data.cores, memory: req.body.memory - currentConfig.data.data.memory};
if (!requestResources(req.cookies.username, request)) { // check resource approval
res.status(500).send({auth: auth, data:{request: request, error: `Not enough resources to satisfy request.`}});
return;
}
let action = JSON.stringify({cores: req.body.cores, memory: req.body.memory}); let action = JSON.stringify({cores: req.body.cores, memory: req.body.memory});
let method = req.body.type === "qemu" ? "POST" : "PUT"; let method = req.body.type === "qemu" ? "POST" : "PUT";
let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken); let result = await requestPVE(`${vmpath}/config`, method, req.cookies, action, pveAPIToken);
result = await handleResponse(req.body.node, result); result = await handleResponse(req.body.node, result);
if (result.status === 200) {
allocateResources(req.cookies.username, request);
}
res.status(result.status).send({auth: auth, data: result.data}); res.status(result.status).send({auth: auth, data: result.data});
}); });

View File

@ -66,15 +66,20 @@ async function handleResponse (node, response) {
} }
} }
async function getUnusedDiskData (node, disk) { async function getUnusedDiskData (node, type, vmid, disk) {
let storageID = disk.split(":")[0]; let diskDataConfig = await getDiskConfig(node, type, vmid, disk);
let storageID = diskDataConfig.split(":")[0];
let storageData = await requestPVE(`/nodes/${node}/storage/${storageID}/content`, "GET", null, null, pveAPIToken); let storageData = await requestPVE(`/nodes/${node}/storage/${storageID}/content`, "GET", null, null, pveAPIToken);
storageData.data.forEach((element) => { let diskDataStorage = null;
if (element.volid === disk) { storageData.data.data.forEach((element) => {
return element; console.log(element)
if (element.volid === diskDataConfig) {
console.log("match!!!")
element.storage = storageID;
diskDataStorage = element;
} }
}); });
return null; return diskDataStorage;
} }
async function getDiskConfig (node, type, vmid, disk) { async function getDiskConfig (node, type, vmid, disk) {