diff --git a/src/db.js b/src/db.js index 0326d6e..295f682 100644 --- a/src/db.js +++ b/src/db.js @@ -6,7 +6,7 @@ class LocalDB { #data = null; constructor () { try { - this.load(this.#filename); + this.load(); } catch { console.log("Error: localdb.json was not found. Please follow the directions in the README to initialize localdb.json."); @@ -14,18 +14,33 @@ class LocalDB { } } - load (path) { - this.#data = JSON.parse(readFileSync(path)); + /** + * Load db from local file system. Reads from file path store in filename. + */ + load () { + this.#data = JSON.parse(readFileSync(this.#filename)); } - save (path) { - writeFileSync(path, JSON.stringify(this.#data)); + /** + * Save db to local file system. Saves to file path stored in filename. + */ + save () { + writeFileSync(this.#filename, JSON.stringify(this.#data)); } + /** + * Gets the global config object from db. + * @returns {Object} global config data. + */ getGlobalConfig () { return this.#data.global; } + /** + * Gets a specific user's config from db. + * @param {string} username of user to get config. + * @returns {Object} specific user config data. + */ getUserConfig (username) { return this.#data.users[username]; } diff --git a/src/main.js b/src/main.js index ae4583e..0f6d044 100644 --- a/src/main.js +++ b/src/main.js @@ -755,9 +755,9 @@ app.get(`/api/:node(${nodeRegexP})/pci`, async (req, res) => { if (!auth) { return; } - let userNodes = db.getUserConfig(req.cookies.username).nodes; - if (!userNodes.includes(params.node)){ - res.status(401).send({auth: false, path: params.node}); + const userNodes = db.getUserConfig(req.cookies.username).nodes; + if (!userNodes.includes(params.node)) { + res.status(401).send({ auth: false, path: params.node }); res.end(); return; } diff --git a/src/pve.js b/src/pve.js index 9ec6fee..369a1f1 100644 --- a/src/pve.js +++ b/src/pve.js @@ -1,6 +1,15 @@ import axios from "axios"; import { pveAPI, pveAPIToken } from "./db.js"; +/** + * Send HTTP request to proxmox API. Allows requests to be made with user cookie credentials or an API token for controlled priviledge elevation. + * @param {string} path HTTP path, prepended with the proxmox API base path. + * @param {string} method HTTP method. + * @param {Object} cookies user cookies for authorization if an API token is not used. Safest option for authentication. + * @param {string} body body parameters and data to be sent. Optional. + * @param {string} token proxmox API token to be used for controled priviledge elevation, allows user requests to perform admin actions safely. Optional + * @returns {Obejct} HTTP response object or HTTP error object + */ export async function requestPVE (path, method, cookies, body = null, token = null) { const url = `${pveAPI}${path}`; const content = { @@ -33,6 +42,14 @@ export async function requestPVE (path, method, cookies, body = null, token = nu } } +/** + * Handle various proxmox API responses. Handles sync and async responses. + * In sync responses, responses are completed when the response arrives. Method returns the response directly. + * In async responses, proxmox sends responses with a UPID to track process completion. Method returns the status of the proxmox process once it completes. + * @param {string} node response originates from. + * @param {Object} result response from proxmox. + * @param {Object} res response object of ProxmoxAAS API call. + */ export async function handleResponse (node, result, res) { const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay)); if (result.data.data && typeof (result.data.data) === "string" && result.data.data.startsWith("UPID:")) { @@ -63,6 +80,12 @@ export async function handleResponse (node, result, res) { } } +/** + * Get the amount of resources used by specified user. + * @param {Object} req ProxmoxAAS API request object. + * @param {Object} resourceMeta data about application resources, to indicate which resources are tracked. + * @returns {Object} k-v pairs of resource name and used amounts + */ export async function getUsedResources (req, resourceMeta) { const response = await requestPVE("/cluster/resources", "GET", req.cookies); const used = {}; @@ -110,6 +133,14 @@ export async function getUsedResources (req, resourceMeta) { return used; } +/** + * Get meta data for a specific disk. Adds info that is not normally available in a instance's config. + * @param {string} node containing the query disk. + * @param {string} type of instance with query disk. + * @param {string} vmid of instance with query disk + * @param {string} disk name of the query disk, ie. sata0. + * @returns {Objetc} k-v pairs of specific disk data, including storage and size of unused disks. + */ export async function getDiskInfo (node, type, vmid, disk) { try { const config = await requestPVE(`/nodes/${node}/${type}/${vmid}/config`, "GET", null, null, pveAPIToken); @@ -124,6 +155,14 @@ export async function getDiskInfo (node, type, vmid, disk) { } } +/** + * Get meta data for a specific pci device. Adds info that is not normally available in a instance's config. + * @param {string} node containing the query device. + * @param {string} type of instance with query device. + * @param {string} vmid of instance with query device. + * @param {string} qid pci bus id number of the query device, ie. 89ab:cd:ef.0. + * @returns {Object} k-v pairs of specific device data, including device name and manufacturer. + */ export async function getDeviceInfo (node, type, vmid, qid) { try { const result = (await requestPVE(`/nodes/${node}/hardware/pci`, "GET", null, null, pveAPIToken)).data.data; @@ -145,6 +184,12 @@ export async function getDeviceInfo (node, type, vmid, qid) { } } +/** + * Get available devices on specific node. + * @param {string} node to get devices from. + * @param {Object} cookies user authentication, unused since the API token is required. + * @returns {Array.} array of k-v pairs of specific device data, including device name and manufacturer, which are available on the specified node. + */ export async function getNodeAvailDevices (node, cookies) { // get node pci devices let nodeAvailPci = (await requestPVE(`/nodes/${node}/hardware/pci`, "GET", cookies, null, pveAPIToken)).data.data; diff --git a/src/utils.js b/src/utils.js index dd92b40..c9861b4 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,6 +1,13 @@ import { getUsedResources, requestPVE } from "./pve.js"; import { db } from "./db.js"; +/** + * Check if a user is authorized to access a specified vm, or the cluster in general. + * @param {Object} cookies user auth cookies. + * @param {Object} res ProxmoxAAS API response object, used to send auth error responses. + * @param {string} vmpath vm path to check. Optional, if null then the general /version path is used. + * @returns {boolean} true if the user is authorized to access the specific vm or cluster in general, false otheriwse. + */ export async function checkAuth (cookies, res, vmpath = null) { let auth = false; @@ -27,6 +34,12 @@ export async function checkAuth (cookies, res, vmpath = null) { return auth; } +/** + * Get user resource data including used, available, and maximum resources. + * @param {Object} req ProxmoxAAS API request object. + * @param {string} username of user to get resource data. + * @returns {{used: Object, avail: Object, max: Object, resources: Object}} used, available, maximum, and resource metadata for the specified user. + */ export async function getUserResources (req, username) { const dbResources = db.getGlobalConfig().resources; const used = await getUsedResources(req, dbResources); @@ -47,6 +60,13 @@ export async function getUserResources (req, username) { return { used, max, avail, resources: dbResources }; } +/** + * Check approval for user requesting additional resources. Generally, subtracts the request from available resources and ensures request can be fulfilled by the available resources. + * @param {Object} req ProxmoxAAS API request object. + * @param {string} username 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. + */ export async function approveResources (req, username, request) { const user = await getUserResources(req, username); const avail = user.avail;