improve return message when requests do not pass resource approval
This commit is contained in:
@@ -98,7 +98,7 @@ router.get(`/:node(${nodeRegexP})/pci`, async (req, res) => {
|
||||
|
||||
// get remaining user resources
|
||||
const userAvailPci = (await getUserResources(req, userObj)).pci.nodes[params.node]; // we assume that the node list is used. TODO support global lists
|
||||
if (userAvailPci === undefined) { // user has no avaliable devices on this node, so send an empty list
|
||||
if (userAvailPci === undefined) { // user has no available devices on this node, so send an empty list
|
||||
res.status(200).send([]);
|
||||
res.end();
|
||||
}
|
||||
@@ -164,8 +164,8 @@ router.get(`${basePath}`, async (req, res) => {
|
||||
* - swap: number, optional - new amount of swap for instance
|
||||
* responses:
|
||||
* - 200: PVE Task Object
|
||||
* - 400: {request; Object, error: string, reason: Object}
|
||||
* - 401: {auth: false, path: string}
|
||||
* - 500: {request: Object, error: string}
|
||||
* - 500: PVE Task Object
|
||||
*/
|
||||
router.post(`${basePath}/resources`, async (req, res) => {
|
||||
@@ -201,8 +201,9 @@ router.post(`${basePath}/resources`, async (req, res) => {
|
||||
request.cpu = params.proctype;
|
||||
}
|
||||
// check resource approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
res.status(500).send({ request, error: "Could not fulfil request." });
|
||||
const { approved, reason } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(400).send({ request, error: "Not enough resources to satisfy request.", reason });
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@@ -239,9 +240,9 @@ router.post(`${basePath}/resources`, async (req, res) => {
|
||||
* - rootfssize: number, optional, - size of lxc instance rootfs
|
||||
* responses:
|
||||
* - 200: PVE Task Object
|
||||
* - 400: {request: Object, error: string, reason: Object}
|
||||
* - 401: {auth: false, path: string}
|
||||
* - 500: {error: string}
|
||||
* - 500: {request: Object, error: string}
|
||||
* - 500: PVE Task Object
|
||||
*/
|
||||
router.post(`${basePath}/create`, async (req, res) => {
|
||||
@@ -312,8 +313,9 @@ router.post(`${basePath}/create`, async (req, res) => {
|
||||
}
|
||||
}
|
||||
// check resource approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) { // check resource approval
|
||||
res.status(500).send({ request, error: "Not enough resources to satisfy request." });
|
||||
const { approved, reason } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(400).send({ request, error: "Not enough resources to satisfy request.", reason });
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
@@ -157,7 +157,8 @@ router.post("/:disk/resize", async (req, res) => {
|
||||
const request = {};
|
||||
request[storage] = Number(params.size * 1024 ** 3); // setup request object
|
||||
// check request approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Storage ${storage} could not fulfill request of size ${params.size}G.` });
|
||||
res.end();
|
||||
return;
|
||||
@@ -219,7 +220,8 @@ router.post("/:disk/move", async (req, res) => {
|
||||
request[dstStorage] = Number(size); // always decrease destination storage by size
|
||||
}
|
||||
// check request approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Storage ${params.storage} could not fulfill request of size ${params.size}G.` });
|
||||
res.end();
|
||||
return;
|
||||
@@ -335,7 +337,8 @@ router.post("/:disk/create", async (req, res) => {
|
||||
// setup request
|
||||
request[params.storage] = Number(params.size * 1024 ** 3);
|
||||
// check request approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Storage ${params.storage} could not fulfill request of size ${params.size}G.` });
|
||||
res.end();
|
||||
return;
|
||||
|
@@ -53,7 +53,8 @@ router.post("/:netid/create", async (req, res) => {
|
||||
};
|
||||
// check resource approval
|
||||
const userObj = global.utils.getUserObjFromUsername(req.cookies.username);
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Could not fulfil network request of ${params.rate}MB/s.` });
|
||||
res.end();
|
||||
return;
|
||||
@@ -116,7 +117,8 @@ router.post("/:netid/modify", async (req, res) => {
|
||||
};
|
||||
// check resource approval
|
||||
const userObj = global.utils.getUserObjFromUsername(req.cookies.username);
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Could not fulfil network request of ${params.rate}MB/s.` });
|
||||
res.end();
|
||||
return;
|
||||
|
@@ -100,7 +100,8 @@ router.post("/:hostpci/modify", async (req, res) => {
|
||||
return;
|
||||
}
|
||||
// check resource approval
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Could not fulfil request for ${requestedDevice.device_name}.` });
|
||||
res.end();
|
||||
return;
|
||||
@@ -172,7 +173,8 @@ router.post("/:hostpci/create", async (req, res) => {
|
||||
const request = { pci: requestedDevice.device_name };
|
||||
// check resource approval
|
||||
const userObj = global.utils.getUserObjFromUsername(req.cookies.username);
|
||||
if (!await approveResources(req, userObj, request, params.node)) {
|
||||
const { approved } = await approveResources(req, userObj, request, params.node);
|
||||
if (!approved) {
|
||||
res.status(500).send({ request, error: `Could not fulfil request for ${requestedDevice.device_name}.` });
|
||||
res.end();
|
||||
return;
|
||||
|
41
src/utils.js
41
src/utils.js
@@ -222,19 +222,24 @@ export async function getUserResources (req, user) {
|
||||
* @param {Object} req ProxmoxAAS API request object.
|
||||
* @param {{id: string, realm: string}} user object of user requesting additional resources.
|
||||
* @param {Object} request k-v pairs of resources and requested amounts
|
||||
* @returns {boolean} true if the available resources can fullfill the requested resources, false otherwise.
|
||||
* @returns {boolean, Object} true if the available resources can fullfill the requested resources, false otherwise.
|
||||
*/
|
||||
export async function approveResources (req, user, request, node) {
|
||||
const dbResources = global.config.resources;
|
||||
const userResources = await getUserResources(req, user);
|
||||
let approved = true;
|
||||
Object.keys(request).every((key) => {
|
||||
// let approved = true;
|
||||
const reason = {};
|
||||
|
||||
for (const key in request) {
|
||||
// if requested resource is not specified in user resources, assume it's not allowed
|
||||
if (!(key in userResources)) {
|
||||
approved = false;
|
||||
return false;
|
||||
// approved = false;
|
||||
reason[key] = { approved: false, reason: `${key} not allowed` };
|
||||
continue;
|
||||
// return;
|
||||
}
|
||||
|
||||
// use node specific quota if there is one available, otherwise use the global resource quota
|
||||
const inNode = node in userResources[key].nodes;
|
||||
const resourceData = inNode ? userResources[key].nodes[node] : userResources[key].global;
|
||||
|
||||
@@ -244,24 +249,34 @@ export async function approveResources (req, user, request, node) {
|
||||
// if no matching resource when index == -1, then remaining is -1 otherwise use the remaining value
|
||||
const avail = index === -1 ? false : resourceData[index].avail > 0;
|
||||
if (avail !== dbResources[key].whitelist) {
|
||||
approved = false;
|
||||
return false;
|
||||
// approved = false;
|
||||
reason[key] = { approved: false, reason: `${key} ${dbResources[key].whitelist ? "not in whitelist" : "in blacklist"}` };
|
||||
// return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// if either the requested or avail resource is not strictly a number, block
|
||||
else if (typeof (resourceData.avail) !== "number" || typeof (request[key]) !== "number") {
|
||||
approved = false;
|
||||
return false;
|
||||
// approved = false;
|
||||
reason[key] = { approved: false, reason: `expected ${key} to be a number but got ${request[key]}` };
|
||||
continue;
|
||||
// return;
|
||||
}
|
||||
// if the avail resources is less than the requested resources, block
|
||||
else if (resourceData.avail - request[key] < 0) {
|
||||
approved = false;
|
||||
return false;
|
||||
// approved = false;
|
||||
reason[key] = { approved: false, reason: `${key} requested ${request[key]} which is more than ${resourceData.avail} available` };
|
||||
continue;
|
||||
// return;
|
||||
}
|
||||
|
||||
return true;
|
||||
reason[key] = { approved: true, reason: "ok" };
|
||||
}
|
||||
|
||||
const approved = Object.values(reason).every((element) => {
|
||||
return element.approved === true;
|
||||
});
|
||||
return approved; // if all requested resources pass, allow
|
||||
return { approved, reason }; // if all requested resources pass, allow
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user