395 lines
13 KiB
JavaScript
395 lines
13 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, apiDelete, apiGet, apiPost, apiPut, parseParams, setupHeader } from "/global.js";
|
||
|
|
||
|
(function()
|
||
|
{
|
||
|
// Element names specific to this page
|
||
|
elements.algorithm = "algorithm";
|
||
|
elements.centerCell = "center-cell";
|
||
|
elements.checkAttempts = "check-attempts";
|
||
|
elements.checkBody = "check-body";
|
||
|
elements.checkInterval = "check-interval";
|
||
|
elements.checkPath = "check-path";
|
||
|
elements.checkShow = "check-show";
|
||
|
elements.checkTimeout = "check-timeout";
|
||
|
elements.checkType = "check-type";
|
||
|
elements.cipherSuite = "cipher-suite";
|
||
|
elements.commonName = "common-name";
|
||
|
elements.configLabel = "config-label";
|
||
|
elements.fingerprint = "fingerprint";
|
||
|
elements.lmcRow = "lmc-tr1";
|
||
|
elements.lmcRowAlt = "lmc-tr2";
|
||
|
elements.nodebalancerLabel = "nodebalancer-label";
|
||
|
elements.nodebalancerTag = "nodebalancer-tag";
|
||
|
elements.nodebalancerTagLink = "nodebalancer-tag-link";
|
||
|
elements.nodesTable = "nodes-table";
|
||
|
elements.nonzero = "nonzero";
|
||
|
elements.passive = "passive";
|
||
|
elements.port = "port";
|
||
|
elements.protocol = "protocol";
|
||
|
elements.protocolShow = "protocol-show";
|
||
|
elements.proxyProtocol = "proxy-protocol";
|
||
|
elements.removePrefix = "remove-node-";
|
||
|
elements.replaceCert = "replace-cert";
|
||
|
elements.replaceCertOnly = "replace-cert-only";
|
||
|
elements.replaceLink = "replace-link";
|
||
|
elements.saveButton = "save-button";
|
||
|
elements.sslCert = "ssl-cert";
|
||
|
elements.sslKey = "ssl-key";
|
||
|
elements.stickiness = "stickiness";
|
||
|
|
||
|
// Data recieved from API calls
|
||
|
var data = {};
|
||
|
data.config = {};
|
||
|
data.nodebalancer = {};
|
||
|
data.nodes = [];
|
||
|
|
||
|
// Static references to UI elements
|
||
|
var ui = {};
|
||
|
ui.algorithm = {};
|
||
|
ui.checkAttempts = {};
|
||
|
ui.checkBody = {};
|
||
|
ui.checkInterval = {};
|
||
|
ui.checkPath = {};
|
||
|
ui.checkShow = [];
|
||
|
ui.checkTimeout = {};
|
||
|
ui.checkType = {};
|
||
|
ui.cipherSuite = {};
|
||
|
ui.commonName = {};
|
||
|
ui.configLabel = {};
|
||
|
ui.fingerprint = {};
|
||
|
ui.nodebalancerLabel = {};
|
||
|
ui.nodebalancerTag = {};
|
||
|
ui.nodebalancerTagLink = {};
|
||
|
ui.nodesTable = {};
|
||
|
ui.passive = {};
|
||
|
ui.port = {};
|
||
|
ui.protocol = {};
|
||
|
ui.protocolShow = [];
|
||
|
ui.proxyProtocol = {};
|
||
|
ui.saveButton = {};
|
||
|
ui.replaceLink = {};
|
||
|
ui.sslCert = {};
|
||
|
ui.sslKey = {};
|
||
|
ui.stickiness = {};
|
||
|
|
||
|
// Temporary State
|
||
|
var state = {};
|
||
|
state.replaceCert = true;
|
||
|
|
||
|
// Create a row for the nodes table
|
||
|
var createNodeRow = function(node, alt)
|
||
|
{
|
||
|
var row = document.createElement("tr");
|
||
|
if (alt)
|
||
|
row.className = elements.lmcRowAlt;
|
||
|
else
|
||
|
row.className = elements.lmcRow;
|
||
|
|
||
|
var label = document.createElement("td");
|
||
|
label.innerHTML = node.label;
|
||
|
row.appendChild(label);
|
||
|
|
||
|
var address = document.createElement("td");
|
||
|
var lastColon = node.address.lastIndexOf(":");
|
||
|
address.innerHTML = node.address.slice(0, lastColon);
|
||
|
row.appendChild(address);
|
||
|
|
||
|
var port = document.createElement("td");
|
||
|
port.innerHTML = node.address.slice(lastColon + 1);
|
||
|
row.appendChild(port);
|
||
|
|
||
|
var weight = document.createElement("td");
|
||
|
weight.innerHTML = node.weight;
|
||
|
row.appendChild(weight);
|
||
|
|
||
|
var mode = document.createElement("td");
|
||
|
mode.innerHTML = node.mode.charAt(0).toUpperCase() + node.mode.slice(1);
|
||
|
row.appendChild(mode);
|
||
|
|
||
|
var status = document.createElement("td");
|
||
|
status.innerHTML = node.status;
|
||
|
row.appendChild(status);
|
||
|
|
||
|
var options = document.createElement("td");
|
||
|
options.className = elements.centerCell;
|
||
|
var editLink = document.createElement("a");
|
||
|
editLink.href = "/nodebalancers/node?nbid=" + data.params.nbid + "&nbcid=" + data.params.nbcid + "&nbnid=" + node.id;
|
||
|
editLink.innerHTML = "Edit";
|
||
|
var separator = document.createElement("span");
|
||
|
separator.innerHTML = " | ";
|
||
|
var removeLink = document.createElement("a");
|
||
|
removeLink.id = elements.removePrefix + node.id;
|
||
|
removeLink.href = "#";
|
||
|
removeLink.innerHTML = "Remove";
|
||
|
removeLink.addEventListener("click", handleRemoveNode);
|
||
|
options.appendChild(editLink);
|
||
|
options.appendChild(separator);
|
||
|
options.appendChild(removeLink);
|
||
|
row.appendChild(options);
|
||
|
|
||
|
return row;
|
||
|
};
|
||
|
|
||
|
// Callback for config API call
|
||
|
var displayConfig = function(response)
|
||
|
{
|
||
|
data.config = response;
|
||
|
|
||
|
ui.configLabel.innerHTML = "Port " + data.config.port;
|
||
|
ui.port.value = data.config.port;
|
||
|
ui.protocol.value = data.config.protocol;
|
||
|
ui.proxyProtocol.value = data.config.proxy_protocol;
|
||
|
ui.algorithm.value = data.config.algorithm;
|
||
|
ui.stickiness.value = data.config.stickiness;
|
||
|
ui.commonName.innerHTML = data.config.ssl_commonname;
|
||
|
ui.fingerprint.innerHTML = data.config.ssl_fingerprint;
|
||
|
ui.cipherSuite.value = data.config.cipher_suite;
|
||
|
ui.checkType.value = data.config.check;
|
||
|
ui.checkInterval.value = data.config.check_interval;
|
||
|
ui.checkTimeout.value = data.config.check_timeout;
|
||
|
ui.checkAttempts.value = data.config.check_attempts;
|
||
|
ui.checkPath.value = data.config.check_path;
|
||
|
ui.checkBody.value = data.config.check_body;
|
||
|
ui.passive.checked = data.config.check_passive;
|
||
|
state.replaceCert = (!data.config.ssl_key || data.config.ssl_key.indexOf("<REDACTED>") == -1);
|
||
|
|
||
|
ui.saveButton.disabled = false;
|
||
|
|
||
|
showHideChecks();
|
||
|
showHideProtocol();
|
||
|
};
|
||
|
|
||
|
// Callback for nodebalancer API call
|
||
|
var displayNodebalancer = function(response)
|
||
|
{
|
||
|
data.nodebalancer = response;
|
||
|
|
||
|
// Set page title and header stuff
|
||
|
if (document.title.indexOf("//") == -1)
|
||
|
document.title += " // Edit " + data.nodebalancer.label;
|
||
|
ui.nodebalancerLabel.innerHTML = data.nodebalancer.label;
|
||
|
if (data.nodebalancer.tags.length == 1) {
|
||
|
ui.nodebalancerTagLink.href = "/nodebalancers?tag=" + data.nodebalancer.tags[0];
|
||
|
ui.nodebalancerTagLink.innerHTML = "(" + data.nodebalancer.tags[0] + ")";
|
||
|
ui.nodebalancerTag.style.display = "inline";
|
||
|
} else {
|
||
|
ui.nodebalancerTag.style.display = "none";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Callback for nodes API call
|
||
|
var displayNodes = function(response)
|
||
|
{
|
||
|
data.nodes = data.nodes.concat(response.data);
|
||
|
|
||
|
// Request the next page if there are more pages
|
||
|
if (response.page != response.pages) {
|
||
|
apiGet("/nodebalancers/" + data.params.nbid + "/configs/" + data.params.nbcid + "/nodes?page=" + (response.page + 1), displayNodes, null);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Insert nodes into table
|
||
|
for (var i = 0; i < data.nodes.length; i++)
|
||
|
ui.nodesTable.appendChild(createNodeRow(data.nodes[i], i % 2));
|
||
|
};
|
||
|
|
||
|
// Remove node handler
|
||
|
var handleRemoveNode = function(event)
|
||
|
{
|
||
|
if (!confirm("Are you sure you want to remove this node?"))
|
||
|
return;
|
||
|
|
||
|
var nbnid = event.currentTarget.id.substring(elements.removePrefix.length);
|
||
|
apiDelete("/nodebalancers/" + data.params.nbid + "/configs/" + data.params.nbcid + "/nodes/" + nbnid, function()
|
||
|
{
|
||
|
location.reload();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// Replace link handler
|
||
|
var handleReplace = function(event)
|
||
|
{
|
||
|
state.replaceCert = true;
|
||
|
showHideProtocol();
|
||
|
};
|
||
|
|
||
|
// Save button handler
|
||
|
var handleSave = function(event)
|
||
|
{
|
||
|
if (event.currentTarget.disabled)
|
||
|
return;
|
||
|
|
||
|
var req = {
|
||
|
"port": parseInt(ui.port.value),
|
||
|
"protocol": ui.protocol.value,
|
||
|
"algorithm": ui.algorithm.value,
|
||
|
"stickiness": ui.stickiness.value,
|
||
|
"check": ui.checkType.value,
|
||
|
"check_passive": ui.passive.checked
|
||
|
};
|
||
|
|
||
|
if (ui.protocol.value == "tcp") {
|
||
|
req.proxy_protocol = ui.proxyProtocol.value;
|
||
|
} else if (ui.protocol.value == "https") {
|
||
|
req.cipher_suite = ui.cipherSuite.value;
|
||
|
if (state.replaceCert) {
|
||
|
req.ssl_cert = ui.sslCert.value;
|
||
|
req.ssl_key = ui.sslKey.value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (ui.checkType.value) {
|
||
|
case "http_body":
|
||
|
req.check_body = ui.checkBody.value;
|
||
|
case "http":
|
||
|
req.check_path = ui.checkPath.value;
|
||
|
case "connection":
|
||
|
req.check_interval = parseInt(ui.checkInterval.value);
|
||
|
req.check_timeout = parseInt(ui.checkTimeout.value);
|
||
|
req.check_attempts = parseInt(ui.checkAttempts.value);
|
||
|
}
|
||
|
|
||
|
if (data.params.nbcid == 0) {
|
||
|
apiPost("/nodebalancers/" + data.params.nbid + "/configs", req, function(response)
|
||
|
{
|
||
|
location.href = "/nodebalancers/config?nbid=" + data.params.nbid + "&nbcid=" + response.id;
|
||
|
});
|
||
|
} else {
|
||
|
apiPut("/nodebalancers/" + data.params.nbid + "/configs/" + data.params.nbcid, req, function(response)
|
||
|
{
|
||
|
location.href = "/nodebalancers/balancer?nbid=" + data.params.nbid;
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Initial setup
|
||
|
var setup = function()
|
||
|
{
|
||
|
// Parse URL parameters
|
||
|
data.params = parseParams();
|
||
|
|
||
|
// We need a NodeBalancer ID, so die if we don't have it
|
||
|
if (!data.params.nbid) {
|
||
|
alert("No NodeBalancer ID supplied!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// We also need a config ID
|
||
|
if (!data.params.nbcid) {
|
||
|
alert("No config ID supplied!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
setupHeader();
|
||
|
|
||
|
// Update links on page to include proper Linode ID
|
||
|
var anchors = document.getElementsByTagName("a");
|
||
|
for (var i = 0; i < anchors.length; i++) {
|
||
|
anchors[i].href = anchors[i].href.replace("nbid=0", "nbid=" + data.params.nbid);
|
||
|
anchors[i].href = anchors[i].href.replace("nbcid=0", "nbcid=" + data.params.nbcid);
|
||
|
}
|
||
|
|
||
|
// Get element references
|
||
|
ui.algorithm = document.getElementById(elements.algorithm);
|
||
|
ui.checkAttempts = document.getElementById(elements.checkAttempts);
|
||
|
ui.checkBody = document.getElementById(elements.checkBody);
|
||
|
ui.checkInterval = document.getElementById(elements.checkInterval);
|
||
|
ui.checkPath = document.getElementById(elements.checkPath);
|
||
|
ui.checkShow = document.getElementsByClassName(elements.checkShow);
|
||
|
ui.checkTimeout = document.getElementById(elements.checkTimeout);
|
||
|
ui.checkType = document.getElementById(elements.checkType);
|
||
|
ui.cipherSuite = document.getElementById(elements.cipherSuite);
|
||
|
ui.commonName = document.getElementById(elements.commonName);
|
||
|
ui.configLabel = document.getElementById(elements.configLabel);
|
||
|
ui.fingerprint = document.getElementById(elements.fingerprint);
|
||
|
ui.nodebalancerLabel = document.getElementById(elements.nodebalancerLabel);
|
||
|
ui.nodebalancerTag = document.getElementById(elements.nodebalancerTag);
|
||
|
ui.nodebalancerTagLink = document.getElementById(elements.nodebalancerTagLink);
|
||
|
ui.nodesTable = document.getElementById(elements.nodesTable);
|
||
|
ui.passive = document.getElementById(elements.passive);
|
||
|
ui.port = document.getElementById(elements.port);
|
||
|
ui.protocol = document.getElementById(elements.protocol);
|
||
|
ui.protocolShow = document.getElementsByClassName(elements.protocolShow);
|
||
|
ui.proxyProtocol = document.getElementById(elements.proxyProtocol);
|
||
|
ui.replaceLink = document.getElementById(elements.replaceLink);
|
||
|
ui.saveButton = document.getElementById(elements.saveButton);
|
||
|
ui.sslCert = document.getElementById(elements.sslCert);
|
||
|
ui.sslKey = document.getElementById(elements.sslKey);
|
||
|
ui.stickiness = document.getElementById(elements.stickiness);
|
||
|
|
||
|
// Register event handlers
|
||
|
ui.checkType.addEventListener("input", showHideChecks);
|
||
|
ui.protocol.addEventListener("input", showHideProtocol);
|
||
|
ui.replaceLink.addEventListener("click", handleReplace);
|
||
|
ui.saveButton.addEventListener("click", handleSave);
|
||
|
|
||
|
// Get data from API
|
||
|
apiGet("/nodebalancers/" + data.params.nbid, displayNodebalancer, null);
|
||
|
if (parseInt(data.params.nbcid)) {
|
||
|
apiGet("/nodebalancers/" + data.params.nbid + "/configs/" + data.params.nbcid, displayConfig, null);
|
||
|
apiGet("/nodebalancers/" + data.params.nbid + "/configs/" + data.params.nbcid + "/nodes", displayNodes, null);
|
||
|
} else {
|
||
|
ui.configLabel.innerHTML = "Create Configuration";
|
||
|
ui.saveButton.disabled = false;
|
||
|
var hideElements = document.getElementsByClassName(elements.nonzero);
|
||
|
for (var i = 0; i < hideElements.length; i++)
|
||
|
hideElements[i].style.display = "none";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Show/hide check rows
|
||
|
var showHideChecks = function(event)
|
||
|
{
|
||
|
for (var i = 0; i < ui.checkShow.length; i++) {
|
||
|
if (ui.checkShow[i].classList.contains(elements.checkShow + "-" + ui.checkType.value))
|
||
|
ui.checkShow[i].style.display = "table-row";
|
||
|
else
|
||
|
ui.checkShow[i].style.display = "none";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Show/hide protocol stuff
|
||
|
var showHideProtocol = function(event)
|
||
|
{
|
||
|
for (var i = 0; i < ui.protocolShow.length; i++) {
|
||
|
if (ui.protocolShow[i].classList.contains(elements.protocolShow + "-" + ui.protocol.value)) {
|
||
|
if (ui.protocolShow[i].classList.contains(elements.replaceCert)) {
|
||
|
if (ui.protocolShow[i].classList.contains(elements.replaceCertOnly) == state.replaceCert)
|
||
|
ui.protocolShow[i].style.display = "table-row";
|
||
|
else
|
||
|
ui.protocolShow[i].style.display = "none";
|
||
|
} else {
|
||
|
ui.protocolShow[i].style.display = "table-row";
|
||
|
}
|
||
|
} else {
|
||
|
ui.protocolShow[i].style.display = "none";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (data.params.nbcid == 0 && ui.protocol.value == "http")
|
||
|
ui.port.value = 80;
|
||
|
if (data.params.nbcid == 0 && ui.protocol.value == "https")
|
||
|
ui.port.value = 443;
|
||
|
};
|
||
|
|
||
|
// Attach onload handler
|
||
|
window.addEventListener("load", setup);
|
||
|
})();
|