/* * 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 . */ import { settings, elements, apiDelete, apiGet, apiPut, countSI, drawSeries, parseParams, regionNames, setupHeader } from "/global.js"; (function() { // Element names specific to this page elements.centerCell = "center-cell"; elements.configTable = "config-table"; elements.cxnAvg = "cxn-avg"; elements.cxnGraph = "cxn-graph"; elements.cxnLast = "cxn-last"; elements.cxnMax = "cxn-max"; elements.hostname = "hostname"; elements.inputLabel = "input-label"; elements.ipv4 = "ipv4"; elements.ipv6 = "ipv6"; elements.lmcRow = "lmc-tr1"; elements.lmcRowAlt = "lmc-tr2"; elements.loadingConfigs = "loading-configs"; elements.location = "location"; elements.nodebalancerLabel = "nodebalancer-label"; elements.nodebalancerTag = "nodebalancer-tag"; elements.nodebalancerTagLink = "nodebalancer-tag-link"; elements.removePrefix = "remove-config-"; elements.saveButton = "save-button"; elements.tableLabel = "table-label"; elements.tags = "tags"; elements.throttle = "throttle"; elements.trafficGraph = "traffic-graph"; elements.trafficInAvg = "traffic-in-avg"; elements.trafficInLast = "traffic-in-last"; elements.trafficInMax = "traffic-in-max"; elements.trafficOutAvg = "traffic-out-avg"; elements.trafficOutLast = "traffic-out-last"; elements.trafficOutMax = "traffic-out-max"; elements.transferred = "transferred"; // Data recieved from API calls var data = {}; data.configs = []; data.nodebalancer = {}; data.params = {}; data.regions = []; data.stats = {}; // Static references to UI elements var ui = {}; ui.configTable = {}; ui.cxnAvg = {}; ui.cxnGraph = {}; ui.cxnLast = {}; ui.cxnMax = {}; ui.hostname = {}; ui.inputLabel = {}; ui.ipv4 = {}; ui.ipv6 = {}; ui.loadingConfigs = {}; ui.location = {}; ui.nodebalancerLabel = {}; ui.nodebalancerTag = {}; ui.nodebalancerTagLink = {}; ui.saveButton = {}; ui.tableLabel = {}; ui.tags = {}; ui.throttle = {}; ui.trafficGraph = {}; ui.trafficInAvg = {}; ui.trafficInLast = {}; ui.trafficInMax = {}; ui.trafficOutAvg = {}; ui.trafficOutLast = {}; ui.trafficOutMax = {}; ui.transferred = {}; // Temporary state var state = {}; state.haveNodebalancer = false; state.haveRegions = false; // Generate a configuration table row var createConfigRow = function(config, alt) { var row = document.createElement("tr"); if (alt) row.className = elements.lmcRowAlt; else row.className = elements.lmcRow; var port = document.createElement("td"); var portLink = document.createElement("a"); portLink.href = "/nodebalancers/config?nbid=" + data.params.nbid + "&nbcid=" + config.id; portLink.innerHTML = "Port " + config.port; port.appendChild(portLink); row.appendChild(port); var protocol = document.createElement("td"); protocol.innerHTML = config.protocol.toUpperCase(); row.appendChild(protocol); var algorithmStrings = { "roundrobin": "Round Robin", "leastconn": "Least Connections", "source": "Source IP" }; var algorithm = document.createElement("td"); if (algorithmStrings[config.algorithm]) algorithm.innerHTML = algorithmStrings[config.algorithm]; else algorithm.innerHTML = config.algorithm; row.appendChild(algorithm); var stickinessStrings = { "none": "None", "table": "Table", "http_cookie": "HTTP Cookie" }; var stickiness = document.createElement("td"); if (stickinessStrings[config.stickiness]) stickiness.innerHTML = stickinessStrings[config.stickiness]; else stickiness.innerHTML = config.stickiness; row.appendChild(stickiness); var healthStrings = { "none": "None", "connection": "TCP Connection", "http": "HTTP Valid Status", "http_body": "HTTP Body Regex" }; var healthCheck = document.createElement("td"); if (healthStrings[config.check]) healthCheck.innerHTML = healthStrings[config.check]; else healthCheck.innerHTML = config.check; row.appendChild(healthCheck); var status = document.createElement("td"); status.innerHTML = config.nodes_status.up + " up, " + config.nodes_status.down + " down"; row.appendChild(status); var options = document.createElement("td"); options.className = elements.centerCell; var editLink = document.createElement("a"); editLink.href = "/nodebalancers/config?nbid=" + data.params.nbid + "&nbcid=" + config.id; editLink.innerHTML = "Edit"; var separator = document.createElement("span"); separator.innerHTML = " | "; var removeLink = document.createElement("a"); removeLink.href = "#"; removeLink.id = elements.removePrefix + config.id; removeLink.innerHTML = "Remove"; removeLink.addEventListener("click", handleConfigRemove); options.appendChild(editLink); options.appendChild(separator); options.appendChild(removeLink); row.appendChild(options); return row; }; // Callback for nodebalancer configs API call var displayConfigs = function(response) { // Add configs to array data.configs = data.configs.concat(response.data); // Request the next page if there are more pages if (response.page != response.pages) { apiGet("/nodebalancers/" + data.params.nbid + "/configs?page=" + (response.page + 1), displayConfigs, null); return; } // Remove loading row ui.loadingConfigs.remove(); // Insert configuration rows into table for (var i = 0; i < data.configs.length; i++) ui.configTable.appendChild(createConfigRow(data.configs[i], i % 2)); }; // 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"; } // Populate info ui.tableLabel.innerHTML = data.nodebalancer.label; ui.hostname.innerHTML = data.nodebalancer.hostname; ui.ipv4.innerHTML = data.nodebalancer.ipv4; ui.ipv6.innerHTML = data.nodebalancer.ipv6; ui.transferred.innerHTML = countSI(data.nodebalancer.transfer.in * 1048576) + "B in - " + countSI(data.nodebalancer.transfer.out * 1048576) + "B out (" + countSI(data.nodebalancer.transfer.total * 1048576) + "B total)"; ui.inputLabel.value = data.nodebalancer.label; ui.throttle.value = data.nodebalancer.client_conn_throttle; ui.tags.value = data.nodebalancer.tags.join(","); ui.saveButton.disabled = false; state.haveNodebalancer = true; if (state.haveRegions) insertRegion(); }; // Callback for regions API call 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.haveNodebalancer) insertRegion(); }; // Callback for nodebalancer stats API call var displayStats = function(response) { // Insert dummy points in case of blank data if (!response.data.connections.length) response.data.connections = [[0,0]]; if (!response.data.traffic.in.length) response.data.traffic.in = [[0,0]]; if (!response.data.traffic.out.length) reponse.data.traffic.out = [[0,0]]; data.stats.cxn = [{ "color": "#906", "fill": true, "points": response.data.connections }]; data.stats.traffic = [ { "color": "#32CD32", "fill": true, "points": response.data.traffic.out }, { "color": "#03C", "fill": false, "points": response.data.traffic.in } ]; // Draw graphs drawSeries(data.stats.cxn, ui.cxnGraph); drawSeries(data.stats.traffic, ui.trafficGraph); // Update tables ui.cxnMax.innerHTML = data.stats.cxn[0].max; ui.cxnAvg.innerHTML = data.stats.cxn[0].avg.toFixed(2); ui.cxnLast.innerHTML = data.stats.cxn[0].points[data.stats.cxn[0].points.length - 1][1]; ui.trafficOutMax.innerHTML = countSI(data.stats.traffic[1].max) + "b/s"; ui.trafficOutAvg.innerHTML = countSI(data.stats.traffic[1].avg) + "b/s"; ui.trafficOutLast.innerHTML = countSI(data.stats.traffic[1].points[data.stats.traffic[1].points.length - 1][1]) + "b/s"; ui.trafficInMax.innerHTML = countSI(data.stats.traffic[0].max) + "b/s"; ui.trafficInAvg.innerHTML = countSI(data.stats.traffic[0].avg) + "b/s"; ui.trafficInLast.innerHTML = countSI(data.stats.traffic[0].points[data.stats.traffic[0].points.length - 1][1]) + "b/s"; }; // Click handler for config remove link var handleConfigRemove = function(event) { if (!confirm("Are you sure you want to delete this config?")) return; var nbcid = event.currentTarget.id.substring(elements.removePrefix.length); apiDelete("/nodebalancers/" + data.params.nbid + "/configs/" + nbcid, function() { location.reload(); }); }; // Click handler for save button var handleSave = function(event) { if (event.currentTarget.disabled) return; var req = { "label": ui.inputLabel.value, "client_conn_throttle": parseInt(ui.throttle.value), "tags": [] }; if (ui.tags.value.length) req.tags = ui.tags.value.split(","); apiPut("/nodebalancers/" + data.params.nbid, req, function(response) { location.reload(); }); }; // Display region info var insertRegion = function() { var regionData = null; for (var i = 0; i < data.regions.length; i++) { if (data.regions[i].id == data.nodebalancer.region) { regionData = data.regions[i]; break; } } if (regionData && regionData.label && regionData.label.length) ui.location.innerHTML = regionData.label; else if (regionNames[data.nodebalancer.region]) ui.location.innerHTML = regionNames[data.nodebalancer.region]; else ui.location.innerHTML = data.nodebalancer.region; }; // 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; } 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); // Get element references ui.configTable = document.getElementById(elements.configTable); ui.cxnAvg = document.getElementById(elements.cxnAvg); ui.cxnGraph = document.getElementById(elements.cxnGraph); ui.cxnLast = document.getElementById(elements.cxnLast); ui.cxnMax = document.getElementById(elements.cxnMax); ui.hostname = document.getElementById(elements.hostname); ui.inputLabel = document.getElementById(elements.inputLabel); ui.ipv4 = document.getElementById(elements.ipv4); ui.ipv6 = document.getElementById(elements.ipv6); ui.loadingConfigs = document.getElementById(elements.loadingConfigs); ui.location = document.getElementById(elements.location); ui.nodebalancerLabel = document.getElementById(elements.nodebalancerLabel); ui.nodebalancerTag = document.getElementById(elements.nodebalancerTag); ui.nodebalancerTagLink = document.getElementById(elements.nodebalancerTagLink); ui.saveButton = document.getElementById(elements.saveButton); ui.tableLabel = document.getElementById(elements.tableLabel); ui.tags = document.getElementById(elements.tags); ui.throttle = document.getElementById(elements.throttle); ui.trafficGraph = document.getElementById(elements.trafficGraph); ui.trafficInAvg = document.getElementById(elements.trafficInAvg); ui.trafficInLast = document.getElementById(elements.trafficInLast); ui.trafficInMax = document.getElementById(elements.trafficInMax); ui.trafficOutAvg = document.getElementById(elements.trafficOutAvg); ui.trafficOutLast = document.getElementById(elements.trafficOutLast); ui.trafficOutMax = document.getElementById(elements.trafficOutMax); ui.transferred = document.getElementById(elements.transferred); // Attach event handlers ui.saveButton.addEventListener("click", handleSave); // Set graph resolutions ui.cxnGraph.height = ui.cxnGraph.clientHeight; ui.cxnGraph.width = ui.cxnGraph.clientWidth; ui.trafficGraph.height = ui.trafficGraph.clientHeight; ui.trafficGraph.width = ui.trafficGraph.clientWidth; // Get data from the API apiGet("/nodebalancers/" + data.params.nbid, displayNodebalancer, null); apiGet("/regions", displayRegions, null); apiGet("/nodebalancers/" + data.params.nbid + "/configs", displayConfigs, null); apiGet("/nodebalancers/" + data.params.nbid + "/stats", displayStats, null); }; // Attach onload handler window.addEventListener("load", setup); })();