367 lines
12 KiB
JavaScript
367 lines
12 KiB
JavaScript
|
/*
|
||
|
* This file is part of Linode Manager Classic.
|
||
|
*
|
||
|
* Linode Manager Classic is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Linode Manager Classic is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Linode Manager Classic. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
import { settings, elements, regionNames, apiGet, countSI, parseParams, setupHeader } from "/global.js";
|
||
|
|
||
|
(function()
|
||
|
{
|
||
|
// Element names specific to this page
|
||
|
elements.barRemaining = "bar-remaining";
|
||
|
elements.barUsed = "bar-used";
|
||
|
elements.centerCell = "center-cell";
|
||
|
elements.info = "info";
|
||
|
elements.lmcRow = "lmc-tr1";
|
||
|
elements.lmcRowAlt = "lmc-tr2";
|
||
|
elements.lmcTable = "lmc-table";
|
||
|
elements.loading = "loading";
|
||
|
elements.nodebalancerPortsPrefix = "nodebalancer-ports-";
|
||
|
elements.nodebalancers = "nodebalancers";
|
||
|
elements.nodebalancerStatusPrefix = "nodebalancer-nodestatus-";
|
||
|
elements.nodebalancerTagPrefix = "nodebalancer-tag-";
|
||
|
elements.subLinks = "sub-links";
|
||
|
elements.transferQuota = "transfer-quota";
|
||
|
elements.transferRemaining = "transfer-remaining";
|
||
|
elements.transferUsed = "transfer-used";
|
||
|
|
||
|
// Data recieved from API calls
|
||
|
var data = {};
|
||
|
data.params = {};
|
||
|
data.nodebalancers = [];
|
||
|
data.nodebalancerTags = [];
|
||
|
data.noTag = false;
|
||
|
data.regions = [];
|
||
|
|
||
|
// Static references to UI elements
|
||
|
var ui = {};
|
||
|
ui.barRemaining = {};
|
||
|
ui.barUsed = {};
|
||
|
ui.loading = {};
|
||
|
ui.nodebalancers = {};
|
||
|
ui.nodebalancerTables = {};
|
||
|
ui.transferQuota = {};
|
||
|
ui.transferRemaining = {};
|
||
|
ui.transferUsed = {};
|
||
|
|
||
|
// Temporary state
|
||
|
var state = {};
|
||
|
state.haveNodebalancers = false;
|
||
|
state.haveRegions = false;
|
||
|
|
||
|
var createNodebalancerRow = function(nodebalancer, alt)
|
||
|
{
|
||
|
var row = document.createElement("tr");
|
||
|
if (alt)
|
||
|
row.className = elements.lmcRowAlt;
|
||
|
else
|
||
|
row.className = elements.lmcRow;
|
||
|
var name = document.createElement("td");
|
||
|
var nameLink = document.createElement("a");
|
||
|
nameLink.href = "/nodebalancers/balancer?nbid=" + nodebalancer.id;
|
||
|
nameLink.innerHTML = nodebalancer.label;
|
||
|
name.appendChild(nameLink);
|
||
|
var regionData = null;
|
||
|
for (var i = 0; i < data.regions.length; i++) {
|
||
|
if (data.regions[i].id == nodebalancer.region) {
|
||
|
regionData = data.regions[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
var region = document.createElement("td");
|
||
|
if (regionData && regionData.label && regionData.label.length)
|
||
|
region.innerHTML = regionData.label;
|
||
|
else if (regionNames[nodebalancer.region])
|
||
|
region.innerHTML = regionNames[nodebalancer.region];
|
||
|
else
|
||
|
region.innerHTML = nodebalancer.region;
|
||
|
var ip = document.createElement("td");
|
||
|
ip.innerHTML = nodebalancer.ipv4;
|
||
|
var ports = document.createElement("td");
|
||
|
ports.id = elements.nodebalancerPortsPrefix + nodebalancer.id;
|
||
|
var nodeStatus = document.createElement("td");
|
||
|
nodeStatus.id = elements.nodebalancerStatusPrefix + nodebalancer.id;
|
||
|
var transferred = document.createElement("td");
|
||
|
transferred.innerHTML = countSI(nodebalancer.transfer.total * 1048576) + "B";
|
||
|
var options = document.createElement("td");
|
||
|
options.className = elements.centerCell;
|
||
|
var editLink = document.createElement("a");
|
||
|
editLink.href = "/nodebalancers/balancer?nbid=" + nodebalancer.id;
|
||
|
editLink.innerHTML = "Edit";
|
||
|
var optionsSeparator = document.createElement("span");
|
||
|
optionsSeparator.innerHTML = " | ";
|
||
|
var removeLink = document.createElement("a");
|
||
|
removeLink.href = "/nodebalancers/remove?nbid=" + nodebalancer.id;
|
||
|
removeLink.innerHTML = "Remove";
|
||
|
options.appendChild(editLink);
|
||
|
options.appendChild(optionsSeparator);
|
||
|
options.appendChild(removeLink);
|
||
|
row.appendChild(name);
|
||
|
row.appendChild(region);
|
||
|
row.appendChild(ip);
|
||
|
row.appendChild(ports);
|
||
|
row.appendChild(nodeStatus);
|
||
|
row.appendChild(transferred);
|
||
|
row.appendChild(options);
|
||
|
|
||
|
return row;
|
||
|
};
|
||
|
|
||
|
var createNodebalancerTable = function(tag)
|
||
|
{
|
||
|
var table = document.createElement("table");
|
||
|
table.id = elements.nodebalancerTagPrefix + tag;
|
||
|
table.className = elements.lmcTable;
|
||
|
var thead = document.createElement("thead");
|
||
|
var headRow1 = document.createElement("tr");
|
||
|
var title = document.createElement("td");
|
||
|
if (tag.length == 0)
|
||
|
title.innerHTML = "NodeBalancers";
|
||
|
else
|
||
|
title.innerHTML = tag;
|
||
|
headRow1.appendChild(title);
|
||
|
var headRow2 = document.createElement("tr");
|
||
|
var cells = ["Label", "Location", "IP", "Ports", "Node Status", "Transferred", "Options"];
|
||
|
title.colSpan = cells.length;
|
||
|
for (var i = 0; i < cells.length; i++) {
|
||
|
var cell = document.createElement("td");
|
||
|
if (cells[i] == "Options")
|
||
|
cell.className = elements.centerCell;
|
||
|
cell.innerHTML = cells[i];
|
||
|
headRow2.appendChild(cell);
|
||
|
}
|
||
|
thead.appendChild(headRow1);
|
||
|
thead.appendChild(headRow2);
|
||
|
var tbody = document.createElement("tbody");
|
||
|
table.appendChild(thead);
|
||
|
table.appendChild(tbody);
|
||
|
ui.nodebalancerTables[tag] = tbody;
|
||
|
|
||
|
var subLinks = document.createElement("p");
|
||
|
subLinks.className = elements.subLinks;
|
||
|
var addNodebalancer = document.createElement("a");
|
||
|
addNodebalancer.href = "/nodebalancers/add";
|
||
|
if (tag.length > 0)
|
||
|
addNodebalancer.href += "?tag=" + tag;
|
||
|
addNodebalancer.innerHTML = "Add a NodeBalancer";
|
||
|
subLinks.appendChild(addNodebalancer);
|
||
|
|
||
|
ui.nodebalancers.appendChild(table);
|
||
|
ui.nodebalancers.appendChild(subLinks);
|
||
|
};
|
||
|
|
||
|
// Callback for NB configs API call
|
||
|
var displayConfigs = function(response)
|
||
|
{
|
||
|
// Find the index of this NB in the array
|
||
|
var nbid = parseInt(response['_endpoint'].split("/")[2]);
|
||
|
var nbindex = -1;
|
||
|
for (var i = 0; i < data.nodebalancers.length; i++) {
|
||
|
if (data.nodebalancers[i].id == nbid) {
|
||
|
nbindex = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (nbindex == -1)
|
||
|
return;
|
||
|
|
||
|
// Add configs to object
|
||
|
data.nodebalancers[nbindex].configs = data.nodebalancers[nbindex].configs.concat(response.data);
|
||
|
|
||
|
// Request the next page if there are more pages
|
||
|
if (response.page != response.pages) {
|
||
|
apiGet("/nodebalancers/" + nbid + "/configs?page=" + (response.page + 1), displayConfigs, null);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var ports = document.getElementById(elements.nodebalancerPortsPrefix + nbid);
|
||
|
var status = document.getElementById(elements.nodebalancerStatusPrefix + nbid);
|
||
|
var upTotal = 0;
|
||
|
var downTotal = 0;
|
||
|
|
||
|
// Count the backend totals and insert port/config links
|
||
|
if (!data.nodebalancers[nbindex].configs.length) {
|
||
|
var addLink = document.createElement("a");
|
||
|
addLink.href = "/nodebalancers/config?nbid=" + nbid + "&nbcid=0";
|
||
|
addLink.innerHTML = "Add...";
|
||
|
ports.appendChild(addLink);
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < data.nodebalancers[nbindex].configs.length; i++) {
|
||
|
upTotal += data.nodebalancers[nbindex].configs[i].nodes_status.up;
|
||
|
downTotal += data.nodebalancers[nbindex].configs[i].nodes_status.down;
|
||
|
|
||
|
if (i > 0) {
|
||
|
var separator = document.createElement("span");
|
||
|
separator.innerHTML = ", ";
|
||
|
ports.appendChild(separator);
|
||
|
}
|
||
|
var port = document.createElement("a");
|
||
|
port.href = "/nodebalancers/config?nbid=" + nbid + "&nbcid=" + data.nodebalancers[nbindex].configs[i].id;
|
||
|
port.innerHTML = data.nodebalancers[nbindex].configs[i].port;
|
||
|
ports.appendChild(port);
|
||
|
}
|
||
|
|
||
|
status.innerHTML = upTotal + " up, " + downTotal + " down";
|
||
|
};
|
||
|
|
||
|
var displayNodebalancers = function(response)
|
||
|
{
|
||
|
// Add linodes to array
|
||
|
data.nodebalancers = data.nodebalancers.concat(response.data);
|
||
|
|
||
|
// Add new tags to array
|
||
|
for (var i = 0; i < response.data.length; i++) {
|
||
|
if (response.data[i].tags.length == 0)
|
||
|
data.noTag = true;
|
||
|
|
||
|
for (var j = 0; j < response.data[i].tags.length; j++) {
|
||
|
if (!data.nodebalancerTags.includes(response.data[i].tags[j]))
|
||
|
data.nodebalancerTags.push(response.data[i].tags[j]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Request the next page if there are more pages
|
||
|
if (response.page != response.pages) {
|
||
|
var progress = (response.page / response.pages) * 100;
|
||
|
progress = progress.toFixed(0);
|
||
|
ui.loading.innerHTML = "Loading " + progress + "%...";
|
||
|
var filters = null;
|
||
|
if (data.params.tag)
|
||
|
filters = {
|
||
|
"tags": data.params.tag
|
||
|
};
|
||
|
apiGet("/nodebalancers?page=" + (response.page + 1), displayNodebalancers, filters);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Remove tag filter if there are no results, otherwise redirect to add page
|
||
|
if (!data.nodebalancers.length) {
|
||
|
if (data.params.tag)
|
||
|
location.href = "/nodebalancers";
|
||
|
else
|
||
|
location.href = "/nodebalancers/add";
|
||
|
}
|
||
|
|
||
|
// Sort
|
||
|
data.nodebalancerTags.sort();
|
||
|
data.nodebalancers.sort(function(a, b)
|
||
|
{
|
||
|
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
|
||
|
});
|
||
|
|
||
|
// Create tables
|
||
|
ui.loading.remove();
|
||
|
if (data.noTag)
|
||
|
createNodebalancerTable("");
|
||
|
for (var i = 0; i < data.nodebalancerTags.length; i++)
|
||
|
createNodebalancerTable(data.nodebalancerTags[i]);
|
||
|
|
||
|
state.haveNodebalancers = true;
|
||
|
|
||
|
// Insert linodes
|
||
|
if (state.haveRegions)
|
||
|
insertNodebalancers();
|
||
|
};
|
||
|
|
||
|
var displayRegions = function(response)
|
||
|
{
|
||
|
// Add regions to array
|
||
|
data.regions = data.regions.concat(response.data);
|
||
|
|
||
|
// Request the next page if there are more pages
|
||
|
if (response.page != response.pages) {
|
||
|
apiGet("/regions?page=" + (response.page + 1), getRegions, null);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
state.haveRegions = true;
|
||
|
if (state.haveNodebalancers)
|
||
|
insertNodebalancers();
|
||
|
};
|
||
|
|
||
|
var displayTransfer = function(response)
|
||
|
{
|
||
|
// Get border width of bar segments from CSS sheet
|
||
|
var remainingBorderWidth = 0;
|
||
|
var usedBorderWidth = 0;
|
||
|
for (var i = 0; i < document.styleSheets[0].cssRules.length; i++) {
|
||
|
if (document.styleSheets[0].cssRules[i].selectorText == "#" + elements.barRemaining)
|
||
|
remainingBorderWidth = Number.parseInt(document.styleSheets[0].cssRules[i].style.borderWidth) * 2;
|
||
|
else if (document.styleSheets[0].cssRules[i].selectorText == "#" + elements.barUsed)
|
||
|
usedBorderWidth = Number.parseInt(document.styleSheets[0].cssRules[i].style.borderWidth) * 2;
|
||
|
}
|
||
|
|
||
|
var usage = (response.used / response.quota) * 100;
|
||
|
usage = usage.toFixed(0);
|
||
|
|
||
|
if (usage != 0) {
|
||
|
ui.barUsed.style = "display: inline-block; width: calc(" + usage + "% - " + usedBorderWidth + "px);";
|
||
|
ui.barUsed.innerHTML = usage + "% Used";
|
||
|
}
|
||
|
if (usage != 100) {
|
||
|
ui.barRemaining.style = "display: inline-block; width: calc(" + (100 - usage) + "% - " + remainingBorderWidth + "px);";
|
||
|
ui.barRemaining.innerHTML = (100 - usage) + "% Remaining";
|
||
|
}
|
||
|
|
||
|
ui.transferUsed.innerHTML = response.used + "GB";
|
||
|
ui.transferRemaining.innerHTML = (response.quota - response.used) + "GB";
|
||
|
ui.transferQuota.innerHTML = response.quota + "GB";
|
||
|
};
|
||
|
|
||
|
var insertNodebalancers = function()
|
||
|
{
|
||
|
// Insert linodes into tables
|
||
|
for (var i = 0; i < data.nodebalancers.length; i++) {
|
||
|
if (data.nodebalancers[i].tags.length == 0)
|
||
|
ui.nodebalancerTables[""].appendChild(createNodebalancerRow(data.nodebalancers[i], ui.nodebalancerTables[""].children.length % 2));
|
||
|
for (var j = 0; j < data.nodebalancers[i].tags.length; j++)
|
||
|
ui.nodebalancerTables[data.nodebalancers[i].tags[j]].appendChild(createNodebalancerRow(data.nodebalancers[i], ui.nodebalancerTables[data.nodebalancers[i].tags[j]].children.length % 2));
|
||
|
|
||
|
data.nodebalancers[i].configs = [];
|
||
|
apiGet("/nodebalancers/" + data.nodebalancers[i].id + "/configs", displayConfigs, null);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var setup = function()
|
||
|
{
|
||
|
// Parse URL parameters
|
||
|
data.params = parseParams();
|
||
|
|
||
|
ui.barRemaining = document.getElementById(elements.barRemaining);
|
||
|
ui.barUsed = document.getElementById(elements.barUsed);
|
||
|
ui.loading = document.getElementById(elements.loading);
|
||
|
ui.nodebalancers = document.getElementById(elements.nodebalancers);
|
||
|
ui.transferQuota = document.getElementById(elements.transferQuota);
|
||
|
ui.transferRemaining = document.getElementById(elements.transferRemaining);
|
||
|
ui.transferUsed = document.getElementById(elements.transferUsed);
|
||
|
|
||
|
setupHeader();
|
||
|
|
||
|
// Get linode and transfer info
|
||
|
apiGet("/regions", displayRegions, null);
|
||
|
apiGet("/account/transfer", displayTransfer, null);
|
||
|
var filters = null;
|
||
|
if (data.params.tag)
|
||
|
filters = {
|
||
|
"tags": data.params.tag
|
||
|
};
|
||
|
apiGet("/nodebalancers", displayNodebalancers, filters);
|
||
|
};
|
||
|
|
||
|
// Attach onload handler
|
||
|
window.addEventListener("load", setup);
|
||
|
})();
|