Initial commit. Implemented OAuth, Linodes, volumes, and images

This commit is contained in:
2020-01-10 00:24:59 -05:00
commit 9915ef3413
121 changed files with 14776 additions and 0 deletions

98
linodes/add/add.css Normal file
View File

@ -0,0 +1,98 @@
/*
* 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 url('/global.css');
#add-button {
display: block;
font-size: 16px;
font-weight: bold;
margin: 0 auto;
padding: 5px;
}
#datacenters {
font-size: 18px;
margin-top: 10px;
}
h2 {
font-size: 18px;
margin: 0;
}
h3 {
font-size: 16px;
}
.instance-category {
padding-top: 10px;
}
.instance-category p {
color: #808080;
font-size: 16px;
}
.instance-type {
background-color: #F7F7F7;
border: 1px solid #DDD;
border-radius: 5px;
cursor: pointer;
display: inline-block;
margin: 10px;
padding: 10px;
text-align: center;
width: 135px;
}
.instance-type h3 {
border-bottom: 1px solid #D4D4D4;
color: #333;
margin: 0;
padding-bottom: 2px;
}
.instance-type p {
color: #666;
font-size: 13px;
margin: 10px 0px 0px 0px;
}
.instance-type-active {
background-color: #5FABFF;
}
.instance-type-active p {
color: #FFF;
}
#instances {
padding: 15px;
}
#location {
padding: 15px;
}
#right-links {
float: right;
}
#submit {
padding: 15px;
}

151
linodes/add/add.js Normal file
View File

@ -0,0 +1,151 @@
/*
* 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, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.addButton = "add-button";
elements.datacenters = "datacenters";
elements.instanceType = "instance-type";
elements.instanceTypeActive = "instance-type-active";
// Data recieved from API calls
var data = {};
data.params = {};
data.linodeTypes = [];
// Static references to UI elements
var ui = {};
ui.datacenters = {};
var createLinodeTypeButton = function(type)
{
var typeButton = document.createElement("div");
typeButton.id = type.id;
typeButton.className = elements.instanceType;
var label = document.createElement("h3");
label.innerHTML = type.label;
var storage = document.createElement("p");
storage.innerHTML = (type.disk / 1024) + "GB Storage";
var cpu = document.createElement("p");
cpu.innerHTML = type.vcpus + " CPU Core";
if (type.vcpus > 1)
cpu.innerHTML = cpu.innerHTML + "s";
var transfer = document.createElement("p");
transfer.innerHTML = type.transfer + "GB XFER";
var cost = document.createElement("p");
cost.innerHTML = "$" + type.price.monthly + "/mo or (" + type.price.hourly + "/hr)";
typeButton.appendChild(label);
typeButton.appendChild(storage);
typeButton.appendChild(cpu);
typeButton.appendChild(transfer);
typeButton.appendChild(cost);
typeButton.addEventListener("click", handleTypeButtonClick);
var list = document.getElementById(type["class"]);
list.appendChild(typeButton);
};
var displayRegions = function(response)
{
for (var i = 0; i < response.data.length; i++) {
var dc = document.createElement("option");
dc.value = response.data[i].id;
if (regionNames[response.data[i].id])
dc.innerHTML = regionNames[response.data[i].id];
else
dc.innerHTML = response.data[i].id;
ui.datacenters.appendChild(dc);
}
// Request the next page if there are more pages
if (response.page != response.pages)
apiGet("/regions?page=" + (response.page + 1), displayRegions, null);
};
var displayTypes = function(response)
{
// Add types to array
data.linodeTypes = data.linodeTypes.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/types?page=" + (response.page + 1), displayTypes, null);
return;
}
// Insert types
for (var i = 0; i < data.linodeTypes.length; i++)
createLinodeTypeButton(data.linodeTypes[i]);
};
var handleAddLinode = function(event)
{
if (event.currentTarget.disabled)
return;
var selectedPlan = document.getElementsByClassName(elements.instanceTypeActive);
if (selectedPlan.length == 0) {
alert("You must select a plan.");
return;
}
var request = {
"type": selectedPlan[0].id,
"region": ui.datacenters.value
};
if (data.params.tag)
request.tags = [data.params.tag];
apiPost("/linode/instances", request, function(response)
{
location.href = "/linodes/dashboard?lid=" + response.id;
});
};
var handleTypeButtonClick = function(event)
{
// Deselect any selected plans
var selected = document.getElementsByClassName(elements.instanceTypeActive);
for (var i = 0; i < selected.length; i++)
selected[i].className = selected[i].className.replace(elements.instanceTypeActive, "");
// Select the clicked plan
event.currentTarget.className += " " + elements.instanceTypeActive;
};
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
ui.datacenters = document.getElementById(elements.datacenters);
// Register add button handler
document.getElementById(elements.addButton).addEventListener("click", handleAddLinode);
setupHeader();
// Get linode types and regions
apiGet("/linode/types", displayTypes, null);
apiGet("/regions", displayRegions, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

70
linodes/add/index.shtml Normal file
View File

@ -0,0 +1,70 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Add a Linode</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="add.css" />
<script src="add.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<div id="main-content" class="wrapper">
<div id="top-links">
<span id="left-links"><a href="/linodes">Linodes</a> » <strong>Add a Linode</strong></span>
<span id="right-links"><a href="/volumes">Manage Volumes</a> | <a href="/images">Manage Images</a> | <a href="/stackscripts">Manage StackScripts</a></span>
</div>
<div id="instances">
<h2>Select an instance type</h2>
<div class="instance-category">
<h3>Nanode Instances</h3>
<p>Nanode instances are good for low-duty workloads, where performance isn't critical.</p>
<div id="nanode"></div>
</div>
<div class="instance-category">
<h3>Standard Instances</h3>
<p>Standard instances are good for medium-duty workloads and are a good mix of performance, resources, and price.</p>
<div id="standard"></div>
</div>
<div class="instance-category">
<h3>Dedicated CPU Instances</h3>
<p>Dedicated CPU instances are good for full-duty workloads where consistent performance is important.</p>
<div id="dedicated"></div>
</div>
<div class="instance-category">
<h3>High Memory Instances</h3>
<p>High Memory instances favor RAM over other resources, and can be good for memory hungry use cases like caching and in-memory databases.</p>
<div id="highmem"></div>
</div>
<div class="instance-category">
<h3>GPU Instances</h3>
<p>Linodes with dedicated GPUs accelerate highly specialized applications such as machine learning, AI, and video transcoding.</p>
<div id="gpu"></div>
</div>
</div>
<div id="location">
<h2>Location</h2>
<select id="datacenters"></select>
</div>
<div id="submit">
<button id="add-button" type="button">Add this Linode!</button>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,49 @@
/*
* 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 url('/global.css');
#backup_details {
padding: 0px 15px 15px;
}
p {
text-align: center;
}
#restore-table td:nth-of-type(5) {
text-align: center;
}
table:first-of-type tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
}
tbody tr:last-of-type {
border: none;
}
td {
white-space: nowrap;
}
ul {
display: inline;
list-style-position: inside;
padding-left: 0;
}

View File

@ -0,0 +1,453 @@
/*
* 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, apiGet, apiPost, parseParams, regionNames, setupHeader, timeString } from "/global.js";
(function()
{
// Element names specific to this page
elements.backupAge = "backup-age";
elements.backupConfigs = "backup-configs";
elements.backupDate = "backup-date";
elements.backupDisks = "backup-disks";
elements.backupLabel = "backup-label";
elements.backupLocation = "backup-location";
elements.backupSize = "backup-size";
elements.backupType = "backup-type";
elements.destLabel = "dest-label";
elements.destLinodes = "dest-linodes";
elements.destLocation = "dest-location";
elements.destPlan = "dest-plan";
elements.destSpace = "dest-space";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.loading = "loading-linodes";
elements.lmcRow = "lmc-tr3";
elements.newLinode = "new-linode";
elements.restorePrefix = "restore-";
elements.selectPrefix = "select-";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
elements.unallocatedPrefix = "unallocated-";
// Data recieved from API calls
var data = {};
data.backup = {};
data.linode = {};
data.linodes = [];
data.types = [];
// Static references to UI elements
var ui = {};
ui.backupAge = {};
ui.backupConfigs = {};
ui.backupDate = {};
ui.backupDisks = {};
ui.backupLabel = {};
ui.backupLocation = {};
ui.backupSize = {};
ui.backupType = {};
ui.destLabel = {};
ui.destLinodes = {};
ui.destLocation = {};
ui.destPlan = {};
ui.destSpace = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.loading = {};
ui.newLinode = {};
// Temporary state
var state = {};
state.haveTypes = false;
// Generate a linode table row
var createLinodeRow = function(linode)
{
var row = document.createElement("tr");
row.className = elements.lmcRow;
var label = document.createElement("td");
label.innerHTML = linode.label;
row.appendChild(label);
var plan = document.createElement("td");
if (linode.type) {
for (var i = 0; i < data.types.length; i++) {
if (data.types[i].id == linode.type) {
plan.innerHTML = data.types[i].label;
break;
}
}
} else {
plan.innerHTML = "Unknown";
}
if (plan.innerHTML == "")
translatePlan(linode.type, plan);
row.appendChild(plan);
var location = document.createElement("td");
if (regionNames[linode.region])
location.innerHTML = regionNames[linode.region];
else
location.innerHTML = linode.region;
row.appendChild(location);
var freeSpace = document.createElement("td");
freeSpace.id = elements.unallocatedPrefix + linode.id;
row.appendChild(freeSpace);
var select = document.createElement("td");
select.id = elements.selectPrefix + linode.id;
row.appendChild(select);
return row;
};
// Callback for backup details API call
var displayBackup = function(response)
{
data.backup = response;
// Populate info table
if (data.backup.label)
ui.backupLabel.innerHTML = data.backup.label;
var now = new Date();
var backupStart = new Date(data.backup.created + "Z");
ui.backupDate.innerHTML = backupStart.toLocaleString();
ui.backupAge.innerHTML = timeString(now - backupStart, true);
ui.backupType.innerHTML = data.backup.type;
for (var i = 0; i < data.backup.configs.length; i++) {
var li = document.createElement("li");
li.innerHTML = data.backup.configs[i];
ui.backupConfigs.appendChild(li);
}
data.backup.totalSize = 0;
for (var i = 0; i < data.backup.disks.length; i++) {
data.backup.totalSize += data.backup.disks[i].size;
var li = document.createElement("li");
li.innerHTML = data.backup.disks[i].label + " (" + data.backup.disks[i].filesystem + ") " + data.backup.disks[i].size + "MB";
ui.backupDisks.appendChild(li);
}
ui.backupSize.innerHTML = data.backup.totalSize + " MB";
if (state.haveTypes && data.linode.id)
insertTypes();
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Display location
if (regionNames[data.linode.region]) {
ui.backupLocation.innerHTML = regionNames[data.linode.region];
ui.destLocation.innerHTML = regionNames[data.linode.region];
} else {
ui.backupLocation.innerHTML = data.linode.region;
ui.destLocation.innerHTML = data.linode.region;
}
if (state.haveTypes && data.backup.id)
insertTypes();
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Find the linode this response is for
var lid = parseInt(response['_endpoint'].split("/")[3]);
var index = -1;
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == lid) {
index = i;
break;
}
}
if (index == -1)
return;
// Add disks to array
data.linodes[index].disks = data.linodes[index].disks.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.linodes[index].id + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Calculate Linode's free space
var free = data.linodes[index].specs.disk;
for (var i = 0; i < data.linodes[index].disks.length; i++)
free -= data.linodes[index].disks[i].size;
// Update table
var freeCell = document.getElementById(elements.unallocatedPrefix + data.linodes[index].id);
var selectCell = document.getElementById(elements.selectPrefix + data.linodes[index].id);
freeCell.innerHTML = free + " MB";
if (free >= data.backup.totalSize) {
var restoreLink = document.createElement("a");
restoreLink.id = elements.restorePrefix + data.linodes[index].id;
restoreLink.href = "#";
restoreLink.innerHTML = "Restore to this Linode";
restoreLink.addEventListener("click", handleRestore);
selectCell.appendChild(restoreLink);
} else {
selectCell.innerHTML = "--- not enough free space ---";
}
};
// Callback for linodes API call
var displayLinodes = function(response)
{
// Add linodes to array
data.linodes = data.linodes.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, filter);
return;
}
ui.loading.remove();
for (var i = 0; i < data.linodes.length; i++) {
// Create row in the table
ui.destLinodes.appendChild(createLinodeRow(data.linodes[i]));
// Get the linode's disks
data.linodes[i].disks = [];
apiGet("/linode/instances/" + data.linodes[i].id + "/disks", displayDisks, null);
}
};
// Callback for linode types API call
var displayTypes = function(response)
{
// Add types to array
data.types = data.types.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/types?page=" + (response.page + 1), displayTypes, null);
return;
}
state.haveTypes = true;
if (data.backup.id && data.linode.id)
insertTypes();
};
// Handler for create linode button
var handleCreate = function(event)
{
if (event.currentTarget.disabled)
return;
// Find the selected type
var index = -1;
for (var i = 0; i < data.types.length; i++) {
if (data.types[i].id == ui.destPlan.value) {
index = i;
break;
}
}
if (index == -1)
return;
if (!confirm("Create a new " + data.types[i].label + " from this backup? This new instance will cost $" + data.types[i].price.monthly.toFixed(2) + " per month and backups will be enabled per your global account setting."))
return;
var req = {
"label": ui.destLabel.value,
"type": ui.destPlan.value,
"region": data.linode.region,
"backup_id": data.backup.id
};
var callback = function(response)
{
location.href = "/linodes/dashboard?lid=" + response.id;
};
apiPost("/linode/instances", req, callback);
};
// Handler for backup restore links
var handleRestore = function(event)
{
// Find the linode associated with this link
var lid = parseInt(event.currentTarget.id.replace(elements.restorePrefix, ""));
var index = -1;
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == lid) {
index = i;
break;
}
}
if (index == -1)
return;
if (!confirm("Restore to Linode " + data.linodes[index].label + "?"))
return;
var req = {
"linode_id": lid,
"overwrite": false
};
var callback = function(response)
{
location.href = "/linodes/dashboard?lid=" + lid;
};
apiPost("/linode/instances/" + data.params.lid + "/backups/" + data.backup.id + "/restore", req, callback);
};
// Insert linode types into selector
var insertTypes = function()
{
for (var i = 0; i < data.types.length; i++) {
if (data.types[i].disk < data.backup.totalSize)
continue;
var option = document.createElement("option");
option.value = data.types[i].id;
option.innerHTML = data.types[i].label;
ui.destPlan.appendChild(option);
}
updatePrice(null);
ui.newLinode.disabled = false;
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances", displayLinodes, filter);
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode ID supplied!");
return;
}
// We also need a backup ID
if (!data.params.bid) {
alert("No Backup 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("lid=0", "lid=" + data.params.lid);
// Highlight the backups subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/backups")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.backupAge = document.getElementById(elements.backupAge);
ui.backupConfigs = document.getElementById(elements.backupConfigs);
ui.backupDate = document.getElementById(elements.backupDate);
ui.backupDisks = document.getElementById(elements.backupDisks);
ui.backupLabel = document.getElementById(elements.backupLabel);
ui.backupLocation = document.getElementById(elements.backupLocation);
ui.backupSize = document.getElementById(elements.backupSize);
ui.backupType = document.getElementById(elements.backupType);
ui.destLabel = document.getElementById(elements.destLabel);
ui.destLinodes = document.getElementById(elements.destLinodes);
ui.destLocation = document.getElementById(elements.destLocation);
ui.destPlan = document.getElementById(elements.destPlan);
ui.destSpace = document.getElementById(elements.destSpace);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.loading = document.getElementById(elements.loading);
ui.newLinode = document.getElementById(elements.newLinode);
// Register event handlers
ui.destPlan.addEventListener("input", updatePrice);
ui.newLinode.addEventListener("click", handleCreate);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/backups/" + data.params.bid, displayBackup, null);
apiGet("/linode/types", displayTypes, null);
};
// Update the given element with the given type's label
var translatePlan = function(type, el)
{
var callback = function(response)
{
el.innerHTML = response.label;
};
apiGet("/linode/types/" + type, callback, null);
};
// Update the price display
var updatePrice = function(event)
{
// Find the selected type
var type = null;
for (var i = 0; i < data.types.length; i++) {
if (data.types[i].id == ui.destPlan.value) {
type = data.types[i];
break;
}
}
if (!type)
return;
ui.destSpace.innerHTML = type.disk;
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,100 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Backups</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="backup_details.css" />
<script src="backup_details.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/backups?lid=0">Backups</a> » <span class="top-links-title">Details</span></div>
<div id="backup_details">
<table class="lmc-table">
<thead>
<tr>
<td colspan="2">Backup Details</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Label</td>
<td id="backup-label"></td>
</tr>
<tr class="lmc-tr3">
<td>Backup Date</td>
<td><span id="backup-date"></span> (<span id="backup-age"></span>)</td>
</tr>
<tr class="lmc-tr3">
<td>Type</td>
<td id="backup-type"></td>
</tr>
<tr class="lmc-tr3">
<td>Location</td>
<td id="backup-location"></td>
</tr>
<tr class="lmc-tr3">
<td>Configuration Profiles</td>
<td>
<ul id="backup-configs"></ul>
</td>
</tr>
<tr class="lmc-tr3">
<td>Disks</td>
<td>
<ul id="backup-disks"></ul>
</td>
</tr>
<tr class="lmc-tr3">
<td>Total size required</td>
<td id="backup-size"></td>
</tr>
</tbody>
</table>
<p>Select a Linode to restore this backup to:</p>
<table id="restore-table" class="lmc-table">
<thead>
<tr>
<td>Linode</td>
<td>Plan</td>
<td>Location</td>
<td>Unallocated/Free Space</td>
<td>Select</td>
</tr>
</thead>
<tbody id="dest-linodes">
<tr class="lmc-tr3">
<td><input id="dest-label" type="text" /></td>
<td><select id="dest-plan"></select></td>
<td id="dest-location"></td>
<td><span id="dest-space"></span> MB</td>
<td><button disabled id="new-linode" type="button">Create Linode from Backup</button></td>
</tr>
<tr id="loading-linodes" class="lmc-tr3">
<td colspan="5">Loading Linodes...</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
/*
* 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 url('/global.css');
#backups {
padding: 0px 15px 15px;
}
#cancel-link {
text-align: center;
}
#in-progress {
display: none;
}
#schedule-updated {
background-color: #ADD370;
display: none;
font-size: 16px;
margin-top: 0;
padding: 7px;
}
table {
margin-bottom: 30px;
}
table:first-of-type tbody:not(.lmc-tbody-head) tr td:first-of-type {
font-weight: bold;
text-align: right;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}

270
linodes/backups/backups.js Normal file
View File

@ -0,0 +1,270 @@
/*
* 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, apiGet, apiPost, apiPut, parseParams, setupHeader, timeString } from "/global.js";
(function()
{
// Element names specific to this page
elements.backupDay = "backup-day";
elements.backupTable = "backup-table";
elements.backupWindow = "backup-window";
elements.inProgress = "in-progress";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr3";
elements.saveButton = "save-button";
elements.scheduleUpdated = "schedule-updated";
elements.snapshotButton = "snapshot-button";
elements.snapshotLabel = "snapshot-label";
elements.timezone = "timezone";
elements.window = "window";
// Data recieved from API calls
var data = {};
data.backups = {};
data.backupsSorted = [];
data.linode = {};
data.profile = {};
// Static references to UI elements
var ui = {};
ui.backupDay = {};
ui.backupTable = {};
ui.backupWindow = {};
ui.inProgress = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.saveButton = {};
ui.scheduleUpdated = {};
ui.snapshotButton = {};
ui.snapshotLabel = {};
ui.timezone = {};
ui.windows = [];
// Generate a backup table row
var createBackupRow = function(backup)
{
var row = document.createElement("tr");
row.className = elements.lmcRow;
var type = document.createElement("td");
type.innerHTML = backup.type;
row.appendChild(type);
var started = document.createElement("td");
var startedDate = new Date(backup.created + "Z");
started.innerHTML = startedDate.toLocaleString();
row.appendChild(started);
var finished = document.createElement("td");
if (backup.finished) {
var finishedDate = new Date(backup.finished + "Z");
finished.innerHTML = finishedDate.toLocaleString();
}
row.appendChild(finished);
var duration = document.createElement("td");
if (backup.finished)
duration.innerHTML = timeString(finishedDate - startedDate, false);
row.appendChild(duration);
var status = document.createElement("td");
status.innerHTML = backup.status;
row.appendChild(status);
var restore = document.createElement("td");
if (backup.status == "successful") {
var restoreLink = document.createElement("a");
restoreLink.href = "/linodes/backup_details?lid=" + data.params.lid + "&bid=" + backup.id;
restoreLink.innerHTML = "Restore to...";
restore.appendChild(restoreLink);
}
row.appendChild(restore);
return row;
};
// Callback for backups API call
var displayBackups = function(response)
{
data.backups = response;
// Enable snapshot button if there's no snapshot in progress
if (!data.backups.snapshot.in_progress) {
ui.snapshotButton.disabled = false;
} else {
ui.snapshotButton.style.display = "none";
ui.snapshotLabel.style.display = "none";
ui.inProgress.style.display = "initial";
ui.backupTable.appendChild(createBackupRow(data.backups.snapshot.in_progress));
}
// Sort backups by date
data.backupsSorted = data.backups.automatic;
if (data.backups.snapshot.current)
data.backupsSorted.push(data.backups.snapshot.current);
data.backupsSorted.sort(function(a, b)
{
var startA = new Date(a.created + "Z");
var startB = new Date(b.created + "Z");
return startB - startA;
});
// Add them to the table
for (var i = 0; i < data.backupsSorted.length; i++)
ui.backupTable.appendChild(createBackupRow(data.backupsSorted[i]));
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Redirect to enable page if backups not enabled
if (!data.linode.backups.enabled)
location.href = "/linodes/backups_enable?lid=" + data.params.lid;
// Set backup settings
ui.backupWindow.value = data.linode.backups.schedule.window;
ui.backupDay.value = data.linode.backups.schedule.day;
ui.saveButton.disabled = false;
};
// Handler for save button
var handleSave = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"backups": {
"schedule": {
"day": ui.backupDay.value,
"window": ui.backupWindow.value
}
}
};
apiPut("/linode/instances/" + data.params.lid, req, function(response)
{
ui.scheduleUpdated.style.display = "block";
});
};
// Handler for snapshot button
var handleSnapshot = function(event)
{
if (event.currentTarget.disabled)
return;
if (!confirm("Taking a snapshot will back up your Linode in its current state, over-writing your previous snapshot. Are you sure?"))
return;
var req = {
"label": ui.snapshotLabel.value
};
apiPost("/linode/instances/" + data.params.lid + "/backups", req, function(response)
{
location.reload();
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.backupDay = document.getElementById(elements.backupDay);
ui.backupTable = document.getElementById(elements.backupTable);
ui.backupWindow = document.getElementById(elements.backupWindow);
ui.inProgress = document.getElementById(elements.inProgress);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.saveButton = document.getElementById(elements.saveButton);
ui.scheduleUpdated = document.getElementById(elements.scheduleUpdated);
ui.snapshotButton = document.getElementById(elements.snapshotButton);
ui.snapshotLabel = document.getElementById(elements.snapshotLabel);
ui.timezone = document.getElementById(elements.timezone);
ui.windows = document.getElementsByClassName(elements.window);
// Display timezone info
var now = new Date();
var offset = now.getTimezoneOffset() / -60;
var offsetHours = Math.floor(offset);
var offsetMins = now.getTimezoneOffset() % 60;
if (offsetMins < 10)
offsetMins = "0" + offsetMins;
ui.timezone.innerHTML = "GMT";
if (offset >= 0)
ui.timezone.innerHTML += "+";
ui.timezone.innerHTML += offset;
for (var i = 0; i < ui.windows.length; i++) {
var windowNum = parseInt(ui.windows[i].value.substring(1));
var startHour = windowNum + offsetHours;
if (startHour < 0)
startHour += 24;
if (startHour < 10)
startHour = "0" + startHour;
var endHour = windowNum + offsetHours + 2;
if (endHour < 0)
endHour += 24;
if (endHour < 10)
endHour = "0" + endHour;
ui.windows[i].innerHTML = startHour + ":" + offsetMins + " - " + endHour + ":" + offsetMins;
}
// Attach button handlers
ui.saveButton.addEventListener("click", handleSave);
ui.snapshotButton.addEventListener("click", handleSnapshot);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/backups", displayBackups, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

122
linodes/backups/index.shtml Normal file
View File

@ -0,0 +1,122 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Backups</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="backups.css" />
<script src="backups.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Backups</span></div>
<div id="backups">
<p id="schedule-updated">Backup schedule updated.</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="2">Backup Settings</td>
</tr>
<tr>
<td colspan="2">Schedule</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Backup Window (<span id="timezone"></span>)</td>
<td>
<select id="backup-window">
<option selected disabled value="Scheduling">Choose a time</option>
<option class="window" value="W0">00:00 - 02:00</option>
<option class="window" value="W2">02:00 - 04:00</option>
<option class="window" value="W4">04:00 - 06:00</option>
<option class="window" value="W6">06:00 - 08:00</option>
<option class="window" value="W8">08:00 - 10:00</option>
<option class="window" value="W10">10:00 - 12:00</option>
<option class="window" value="W12">12:00 - 14:00</option>
<option class="window" value="W14">14:00 - 16:00</option>
<option class="window" value="W16">16:00 - 18:00</option>
<option class="window" value="W18">18:00 - 20:00</option>
<option class="window" value="W20">20:00 - 22:00</option>
<option class="window" value="W22">22:00 - 00:00</option>
</select>
</td>
</tr>
<tr class="lmc-tr3">
<td>Weekly Backup</td>
<td>
<select id="backup-day">
<option selected disabled value="Scheduling">Choose a day</option>
<option value="Sunday">Sunday</option>
<option value="Monday">Monday</option>
<option value="Tuesday">Tuesday</option>
<option value="Wednesday">Wednesday</option>
<option value="Thursday">Thursday</option>
<option value="Friday">Friday</option>
<option value="Saturday">Saturday</option>
</select>
</td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="save-button" type="button">Save Changes</button></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2">Manual Snapshot</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td></td>
<td>
<span id="in-progress">— Snapshot In Progress —<br /></span>
<input id="snapshot-label" type="text" placeholder="My New Snapshot Label" minlength="1" maxlength="255" size="32" />
<button disabled id="snapshot-button" type="button">Take a New Snapshot Now</button>
</td>
</tr>
</tbody>
</table>
<table class="lmc-table">
<thead>
<tr>
<td colspan="6">Available Backups</td>
</tr>
<tr>
<td>Type</td>
<td>Started</td>
<td>Finished</td>
<td>Duration</td>
<td>Status</td>
<td>Restore</td>
</tr>
</thead>
<tbody id="backup-table"></tbody>
</table>
<p id="cancel-link"><a href="/linodes/backups_cancel?lid=0">Cancel Backups</a></p>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,30 @@
/*
* 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 url('/global.css');
#backups_cancel {
padding: 0px 15px 15px;
}
#button-block {
text-align: center;
}
h2 {
margin-top: 0;
}

View File

@ -0,0 +1,107 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.cancelButton = "cancel-button";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.cancelButton = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Redirect to backups page if backups are already enabled
if (!data.linode.backups.enabled)
location.href = "/linodes/backups_enable?lid=" + data.params.lid;
};
// Cancel button handler
var handleCancel = function(event)
{
if (event.currentTarget.disabled)
return;
if (!confirm("Removing Backup Service will irreversibly delete all backup data, are you sure you want to continue?"))
return;
apiPost("/linode/instances/" + data.params.lid + "/backups/cancel", {}, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.cancelButton = document.getElementById(elements.cancelButton);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
// Register rebuild button handler
ui.cancelButton.addEventListener("click", handleCancel);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,42 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Backups Cancel</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="backups_cancel.css" />
<script src="backups_cancel.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/backups?lid=0">Backups</a> » <span class="top-links-title">Cancel</span></div>
<div id="backups_cancel">
<h2>Cancel Backups</h2>
<p>
Warning: Please be aware that all data in your backups will be securely deleted and unrecoverable. Linode does not retain backup data after cancellation. If you would like to enable backups again, you can do so via the manager, but you will not have access to older backups as they will be purged from Linode's system.<br />
<br />
Would you like to continue?
</p>
<div id="button-block"><button id="cancel-button" type="button">Cancel backups for this Linode</button></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,43 @@
/*
* 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 url('/global.css');
#backups_enable {
padding: 0px 15px 15px;
}
#button-block {
text-align: center;
}
h2 {
margin-top: 0;
}
#price {
font-weight: bold;
}
#price-info {
padding-top: 15px;
text-align: center;
}
.top-level {
font-weight: bold;
}

View File

@ -0,0 +1,117 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.enableButton = "enable-button";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.price = "price";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.enableButton = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.price = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Redirect to backups page if backups are already enabled
if (data.linode.backups.enabled)
location.href = "/linodes/backups?lid=" + data.params.lid;
// Get Linode type info for backup pricing
apiGet("/linode/types/" + data.linode.type, displayPricing, null);
};
// Callback for linode type API call
var displayPricing = function(response)
{
ui.price.innerHTML = "$" + response.addons.backups.price.monthly.toFixed(2) + "/mo";
ui.enableButton.disabled = false;
};
// Enable button handler
var handleEnable = function(event)
{
if (event.currentTarget.disabled)
return;
apiPost("/linode/instances/" + data.params.lid + "/backups/enable", {}, function(response)
{
location.href = "/linodes/backups?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.enableButton = document.getElementById(elements.enableButton);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.price = document.getElementById(elements.price);
// Register rebuild button handler
ui.enableButton.addEventListener("click", handleEnable);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,59 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Backups Enable</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="backups_enable.css" />
<script src="backups_enable.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/backups?lid=0">Backups</a> » <span class="top-links-title">Enable</span></div>
<div id="backups_enable">
<h2>Backups</h2>
<p>The Linode Backup System is designed to be an easy to use, reliable and redundant on-site backup solution for your Linode. It performs backups without causing any interruption of your running system. It provides 4 backup slots. Three of the slots are executed and rotated automatically: a daily backup, a 2-7 day old backup, and an 8-14 day old backup. The fouth backup slot is a user-initiated snapshot and remains in place until another user-initiated snapshot is taken.</p>
<ul>
<li>
<span class="top-level">Resiliency:</span>
<ul>
<li>Linode's storage back ends tolerate hard drive failures by utilizing RAID across many drives.</li>
</ul>
</li>
<li>
<span class="top-level">Restoring:</span>
<ul>
<li>You can restore a backup to any of the Linodes attached to this account, even if they do not have backups enabled. Currently only a full restore is possible.</li>
</ul>
</li>
<li>
<span class="top-level">Limitations:</span>
<ul>
<li>The backup system must be able to mount your disks on the host. If you've used fdisk on your disks to create partitions, or created encrypted volumes, or done anything other than use Linode's deployment or disk creation tools, the backup system won't be able to back up the data. The backup system operates on files, not at the block level.</li>
</ul>
</li>
</ul>
<p id="price-info">Backups for this Linode are <span id="price"></span>.</p>
<div id="button-block"><button disabled id="enable-button" type="button">Enable backups for this Linode</button></div>
</div>
</div>
</body>
</html>

84
linodes/clone/clone.css Normal file
View File

@ -0,0 +1,84 @@
/*
* 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 url('/global.css');
#clone {
padding: 0px 15px 15px;
}
#clone-table tbody:last-of-type tr:last-of-type {
font-weight: bold;
}
#clone-table tbody:last-of-type tr:last-of-type td:nth-of-type(2) {
text-align: right;
}
#clone-table td:first-of-type {
width: 100%;
}
#config-table {
margin-bottom: 20px;
text-align: center;
}
#config-table td:nth-of-type(2) {
text-align: left;
width: 100%;
}
#config-table td:nth-of-type(3) {
text-align: left;
}
#dest-table tbody:not(.lmc-tbody-head) td:first-of-type {
font-weight: bold;
padding-left: 100px;
text-align: right;
}
#dest-table tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}
#dest-table td:last-of-type {
width: 100%;
}
#disk-table {
margin-bottom: 20px;
text-align: center;
}
#disk-table td:nth-of-type(2) {
text-align: left;
width: 100%;
}
.lmc-table td {
white-space: nowrap;
}
.lmc-table thead tr:first-of-type {
text-align: left;
}
optgroup {
display: none;
}

558
linodes/clone/clone.js Normal file
View File

@ -0,0 +1,558 @@
/*
* 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, apiGet, apiPost, migrateETA, parseParams, regionNames, setupHeader, translateKernel } from "/global.js";
(function()
{
// Element names specific to this page
elements.cloneButton = "clone-button";
elements.configCloneTable = "config-clone-table";
elements.configDiskRow = "config-disk-row";
elements.configsNone = "configs-none";
elements.configTable = "config-table-body";
elements.destBackups = "dest-backups";
elements.destBackupsPrice = "dest-backups-price";
elements.destLabel = "dest-label";
elements.destLinode = "dest-linode";
elements.destLocation = "dest-location";
elements.destPlan = "dest-plan";
elements.destPlanPrice = "dest-plan-price";
elements.diskCloneTable = "disk-clone-table";
elements.disksNone = "disks-none";
elements.diskTable = "disk-table-body";
elements.etaLocal = "eta-local";
elements.etaRemote = "eta-remote";
elements.etaRow = "eta-row";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr1";
elements.lmcRowAlt = "lmc-tr2";
elements.lmcRowThree = "lmc-tr3";
elements.loadingConfigs = "loading-configs";
elements.loadingDisks = "loading-disks";
elements.newLinode = "new-linode";
elements.sourceLocation = "source-location";
// Data recieved from API calls
var data = {};
data.configs = [];
data.disks = [];
data.linode = {};
data.types = [];
// Static references to UI elements
var ui = {};
ui.cloneButton = {};
ui.configCloneTable = {};
ui.configsNone = {};
ui.configTable = {};
ui.destBackups = {};
ui.destBackupsPrice = {};
ui.destLabel = {};
ui.destLinode = {};
ui.destLocation = {};
ui.destPlan = {};
ui.destPlanPrice = {};
ui.diskCloneTable = {};
ui.disksNone = {};
ui.diskTable = {};
ui.etaLocal = {};
ui.etaRemote = {};
ui.etaRow = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.loadingConfigs = {};
ui.loadingDisks = {};
ui.newLinode = [];
ui.sourceLocation = {};
// Temporary state
var state = {};
state.configs = [];
state.disks = [];
// Generate a config profile table row for clone section
var createCloneConfigRow = function(config)
{
var row = document.createElement("tr");
row.className = elements.lmcRowThree + " " + elements.configDiskRow;
var label = document.createElement("td");
label.colSpan = ui.configsNone.children[0].colSpan;
label.innerHTML = config.label;
row.appendChild(label);
return row;
};
// Create a disk table row for clone section
var createCloneDiskRow = function(disk)
{
var row = document.createElement("tr");
row.className = elements.lmcRowThree + " " + elements.configDiskRow;
// Label
var label = document.createElement("td");
label.innerHTML = disk.label;
row.appendChild(label);
// Size
var size = document.createElement("td");
size.innerHTML = disk.size + " MB";
row.appendChild(size);
// Local copy ETA
var local = document.createElement("td");
local.innerHTML = migrateETA(disk.size, true);
row.appendChild(local);
// Remote copy ETA
var remote = document.createElement("td");
remote.innerHTML = migrateETA(disk.size, false);
row.appendChild(remote);
return row;
};
// Generate a config profile table row
var createConfigRow = function(config, alt)
{
var row = document.createElement("tr");
if (alt)
row.className = elements.lmcRowAlt;
else
row.className = elements.lmcRow;
// Select checkbox
var selectCell = document.createElement("td");
var select = document.createElement("input");
select.id = "config-" + config.id;
select.type = "checkbox";
select.addEventListener("input", handleSelect);
selectCell.appendChild(select);
row.appendChild(selectCell);
// Config profile name
var nameCell = document.createElement("td");
nameCell.innerHTML = config.label;
row.appendChild(nameCell);
// Kernel
var kernel = document.createElement("td");
translateKernel(config.kernel, kernel);
row.appendChild(kernel);
// Number of disks
var disks = document.createElement("td");
var numDisks = 0;
for (var disk in config.devices) {
if (config.devices[disk] && config.devices[disk].disk_id)
numDisks++;
}
disks.innerHTML = numDisks;
row.appendChild(disks);
return row;
};
// Generate a disk table row
var createDiskRow = function(disk, alt)
{
var row = document.createElement("tr");
if (alt)
row.className = elements.lmcRowAlt;
else
row.className = elements.lmcRow;
// Select checkbox
var selectCell = document.createElement("td");
var select = document.createElement("input");
select.id = "disk-" + disk.id;
select.type = "checkbox";
select.addEventListener("input", handleSelect);
selectCell.appendChild(select);
row.appendChild(selectCell);
// Disk name
var nameCell = document.createElement("td");
nameCell.innerHTML = disk.label;
row.appendChild(nameCell);
// Disk type
var typeCell = document.createElement("td");
typeCell.innerHTML = disk.filesystem;
row.appendChild(typeCell);
// Disk size
var sizeCell = document.createElement("td");
sizeCell.innerHTML = disk.size + " MB";
row.appendChild(sizeCell);
return row;
};
// Callback for config profiles 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
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/configs?page=" + (response.page + 1), displayConfigs, null);
return;
}
// Remove loading row
ui.loadingConfigs.remove();
// Insert config profile rows into table
for (var i = 0; i < data.configs.length; i++)
ui.configTable.appendChild(createConfigRow(data.configs[i], i % 2));
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Display the source location
if (regionNames[data.linode.region])
ui.sourceLocation.innerHTML = regionNames[data.linode.region];
else
ui.sourceLocation.innerHTML = data.linode.region;
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Remove loading row
ui.loadingDisks.remove();
// Insert disk rows into table
for (var i = 0; i < data.disks.length; i++)
ui.diskTable.appendChild(createDiskRow(data.disks[i], i % 2));
};
// Callback for linodes API call
var displayLinodes = function(response)
{
// Add linodes to selector
for (var i = 0; i < response.data.length; i++) {
if (response.data[i].id == data.params.lid)
continue;
var linode = document.createElement("option");
linode.value = response.data[i].id;
linode.innerHTML = response.data[i].label;
var optgroup = document.getElementById(response.data[i].region);
optgroup.appendChild(linode);
optgroup.style.display = "initial";
}
// Request the next page if there are more pages
if (response.page != response.pages)
apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, null);
};
// Callback for regions API call
var displayRegions = function(response)
{
for (var i = 0; i < response.data.length; i++) {
// Add regions to selector
var dc = document.createElement("option");
dc.value = response.data[i].id;
if (regionNames[response.data[i].id])
dc.innerHTML = regionNames[response.data[i].id];
else
dc.innerHTML = response.data[i].id;
ui.destLocation.appendChild(dc);
// Add optgroups to linode selector
var optgroup = document.createElement("optgroup");
optgroup.id = response.data[i].id;
if (regionNames[response.data[i].id])
optgroup.label = regionNames[response.data[i].id];
else
optgroup.label = response.data[i].label;
ui.destLinode.appendChild(optgroup);
}
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/regions?page=" + (response.page + 1), displayRegions, null);
return;
}
apiGet("/linode/instances", displayLinodes, null);
};
// Callback for linode types API call
var displayTypes = function(response)
{
// Add types to array
data.types = data.types.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/types?page=" + (response.page + 1), displayTypes, null);
return;
}
// Insert types into selector
for (var i = 0; i < data.types.length; i++) {
var type = document.createElement("option");
type.value = data.types[i].id;
type.innerHTML = data.types[i].label;
ui.destPlan.appendChild(type);
}
updatePrices(null);
};
// Clone button handler
var handleClone = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"configs": state.configs,
"disks": state.disks
};
var destLinode = parseInt(ui.destLinode.value);
if (destLinode == 0) {
req.region = ui.destLocation.value;
req.type = ui.destPlan.value;
if (ui.destLabel.value.length)
req.label = ui.destLabel.value;
req.backups_enabled = ui.destBackups.checked;
} else {
req.linode_id = destLinode;
}
apiPost("/linode/instances/" + data.params.lid + "/clone", req, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Handler for checkbox selections
var handleSelect = function(event)
{
// Determine whether we're working with configs or disks
var arr = state.configs;
if (event.currentTarget.id.split("-")[0] == "disk")
arr = state.disks;
// Get the ID of the thing
var id = parseInt(event.currentTarget.id.split("-")[1]);
var index = arr.indexOf(id);
// If the box is checked, add the ID, otherwise remove it
if (event.currentTarget.checked && index == -1)
arr.push(id);
else if (index != -1)
arr.splice(index, 1);
updateClone();
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.cloneButton = document.getElementById(elements.cloneButton);
ui.configCloneTable = document.getElementById(elements.configCloneTable);
ui.configsNone = document.getElementById(elements.configsNone);
ui.configTable = document.getElementById(elements.configTable);
ui.destBackups = document.getElementById(elements.destBackups);
ui.destBackupsPrice = document.getElementById(elements.destBackupsPrice);
ui.destLabel = document.getElementById(elements.destLabel);
ui.destLinode = document.getElementById(elements.destLinode);
ui.destLocation = document.getElementById(elements.destLocation);
ui.destPlan = document.getElementById(elements.destPlan);
ui.destPlanPrice = document.getElementById(elements.destPlanPrice);
ui.diskCloneTable = document.getElementById(elements.diskCloneTable);
ui.disksNone = document.getElementById(elements.disksNone);
ui.diskTable = document.getElementById(elements.diskTable);
ui.etaLocal = document.getElementById(elements.etaLocal);
ui.etaRemote = document.getElementById(elements.etaRemote);
ui.etaRow = document.getElementById(elements.etaRow);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.loadingConfigs = document.getElementById(elements.loadingConfigs);
ui.loadingDisks = document.getElementById(elements.loadingDisks);
ui.newLinode = document.getElementsByClassName(elements.newLinode);
ui.sourceLocation = document.getElementById(elements.sourceLocation);
// Register event handlers
ui.cloneButton.addEventListener("click", handleClone);
ui.destLinode.addEventListener("input", updateDestination);
ui.destPlan.addEventListener("input", updatePrices);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/configs", displayConfigs, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
apiGet("/linode/types", displayTypes, null);
apiGet("/regions", displayRegions, null);
};
// Update clone config and disk info
var updateClone = function()
{
// Remove all config and disk rows
var configDiskRows = document.getElementsByClassName(elements.configDiskRow);
for (var i = configDiskRows.length - 1; i >= 0; i--)
configDiskRows[i].remove();
var allDisks = [];
// Loop through configs and create rows
for (var i = 0; i < state.configs.length; i++) {
// Find config
var config = null;
for (var j = 0; j < data.configs.length; j++) {
if (state.configs[i] == data.configs[j].id) {
config = data.configs[j];
break;
}
}
if (!config)
continue;
// Add config to table
ui.configCloneTable.appendChild(createCloneConfigRow(config));
// Loop through config's disks and add them to array
for (var disk in config.devices) {
if (config.devices[disk] && config.devices[disk].disk_id && allDisks.indexOf(config.devices[disk].disk_id) == -1)
allDisks.push(config.devices[disk].disk_id);
}
}
// Add independent disks to array
for (var i = 0; i < state.disks.length; i++) {
if (allDisks.indexOf(state.disks[i]) == -1)
allDisks.push(state.disks[i]);
}
// Loop through disks and create rows
var totalSize = 0;
for (var i = 0; i < allDisks.length; i++) {
// Find disk
var disk = null;
for (var j = 0; j < data.disks.length; j++) {
if (allDisks[i] == data.disks[j].id) {
disk = data.disks[j];
break;
}
}
if (!disk)
continue;
totalSize += disk.size;
// Add disk to table
ui.diskCloneTable.insertBefore(createCloneDiskRow(disk), ui.etaRow);
}
// Show/hide the "none" rows
if (state.configs.length > 0)
ui.configsNone.style.display = "none";
else
ui.configsNone.style.display = "table-row";
if (allDisks.length > 0)
ui.disksNone.style.display = "none";
else
ui.disksNone.style.display = "table-row";
// Compute total ETAs
ui.etaLocal.innerHTML = migrateETA(totalSize, true);
ui.etaRemote.innerHTML = migrateETA(totalSize, false);
};
// Update destination form
var updateDestination = function(event)
{
var display = "none";
if (ui.destLinode.value == "0")
display = "table-row";
for (var i = 0; i < ui.newLinode.length; i++)
ui.newLinode[i].style.display = display;
};
// Update price labels
var updatePrices = function(event)
{
// Find the selected type
var type = null;
for (var i = 0; i < data.types.length; i++) {
if (data.types[i].id == ui.destPlan.value) {
type = data.types[i];
break;
}
}
if (!type)
return;
ui.destPlanPrice.innerHTML = type.price.monthly;
ui.destBackupsPrice.innerHTML = type.addons.backups.price.monthly;
};
// Attach onload handler
window.addEventListener("load", setup);
})();

174
linodes/clone/index.shtml Normal file
View File

@ -0,0 +1,174 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Clone</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="clone.css" />
<script src="clone.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Clone</span></div>
<div id="clone">
<table id="config-table" class="lmc-table">
<thead>
<tr>
<td colspan="4">Configuration Profiles</td>
</tr>
<tr>
<td>Select</td>
<td>Configuration Profiles</td>
<td>Kernel</td>
<td>Disks Attached</td>
</tr>
</thead>
<tbody id="config-table-body">
<tr id="loading-configs" class="lmc-tr3">
<td></td>
<td>Loading configuration profiles...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<table id="disk-table" class="lmc-table">
<thead>
<tr>
<td colspan="4">Disks</td>
</tr>
<tr>
<td>Select</td>
<td>Disks</td>
<td>Type</td>
<td>Size</td>
</tr>
</thead>
<tbody id="disk-table-body">
<tr id="loading-disks" class="lmc-tr3">
<td></td>
<td>Loading disks...</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<table id="clone-table" class="lmc-table">
<thead>
<tr>
<td colspan="4">Clone</td>
</tr>
<tr>
<td colspan="4">Config Profiles</td>
</tr>
</thead>
<tbody id="config-clone-table">
<tr id="configs-none" class="lmc-tr3">
<td colspan="4">- None -</td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="4"></td>
</tr>
<tr>
<td>Disks</td>
<td>Size</td>
<td>Time to copy: Local</td>
<td>To another Datacenter</td>
</tr>
</tbody>
<tbody id="disk-clone-table">
<tr id="disks-none" class="lmc-tr3">
<td colspan="4">- None -</td>
</tr>
<tr id="eta-row" class="lmc-tr3">
<td></td>
<td>TOTAL ESTIMATED TIME:</td>
<td id="eta-local">0 minutes</td>
<td id="eta-remote">0 minutes</td>
</tr>
</tbody>
</table>
<table id="dest-table" class="lmc-table">
<thead>
<tr class="noshow">
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2">Source</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Current Datacenter</td>
<td id="source-location"></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="2"></td>
</tr>
<tr>
<td colspan="2">Select Destination</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Destination Linode</td>
<td>
<select id="dest-linode">
<option selected value="0">New Linode</option>
</select>
</td>
</tr>
<tr class="lmc-tr3 new-linode">
<td>Location</td>
<td><select id="dest-location"></select></td>
</tr>
<tr class="lmc-tr3 new-linode">
<td>Plan</td>
<td>
<select id="dest-plan"></select>
$<span id="dest-plan-price"></span> per month
</td>
</tr>
<tr class="lmc-tr3 new-linode">
<td>Label</td>
<td><input id="dest-label" type="text" /></td>
</tr>
<tr class="lmc-tr3 new-linode">
<td>Backups</td>
<td>
<input id="dest-backups" type="checkbox" />
<label for="dest-backups">$<span id="dest-backups-price"></span> per month</label>
</td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button id="clone-button" type="button">Clone</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

31
linodes/config/config.css Normal file
View File

@ -0,0 +1,31 @@
/*
* 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 url('/global.css');
#config {
padding: 0px 15px 15px;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}
tbody:not(.lmc-tbody-head) tr td:first-of-type {
font-weight: bold;
text-align: right;
}

535
linodes/config/config.js Normal file
View File

@ -0,0 +1,535 @@
/*
* 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, apiGet, apiPost, apiPut, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.binbash = "binbash";
elements.bootDeviceCustom = "boot-device-custom";
elements.bootDeviceStandard = "boot-device-standard";
elements.custom = "custom";
elements["default"] = "default";
elements.devtmpfsHelper = "devtmpfs-helper";
elements.devtmpfsHelperNo = "devtmpfs-helper-no";
elements.disks = "disks";
elements.distroHelper = "distro-helper";
elements.distroHelperNo = "distro-helper-no";
elements.fullvirt = "fullvirt";
elements.fullvirtHide = "fullvirt-hide";
elements.initrd = "initrd";
elements.kernel = "kernel";
elements.label = "label";
elements.limit = "limit";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.maxMem = "max-mem";
elements.memLimit = "mem-limit";
elements.modulesHelper = "modules-helper";
elements.modulesHelperNo = "modules-helper-no";
elements.networkHelper = "network-helper";
elements.networkHelperNo = "network-helper-no";
elements.noLimit = "no-limit";
elements.notes = "notes";
elements.paravirt = "paravirt";
elements.saveButton = "save-button";
elements.sda = "sda";
elements.sdb = "sdb";
elements.sdc = "sdc";
elements.sdd = "sdd";
elements.sde = "sde";
elements.sdf = "sdf";
elements.sdg = "sdg";
elements.sdh = "sdh";
elements.single = "single";
elements.standard = "standard";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
elements.updatedbHelper = "updatedb-helper";
elements.updatedbHelperNo = "updatedb-helper-no";
elements.volumes = "volumes";
// Data recieved from API calls
var data = {};
data.config = {};
data.disks = [];
data.kernels = [];
data.linode = {};
data.volumes = [];
// Static references to UI elements
var ui = {};
ui.binbash = {};
ui.bootDeviceCustom = {};
ui.bootDeviceStandard = {};
ui.custom = {};
ui["default"] = {};
ui.devtmpfsHelper = {};
ui.devtmpfsHelperNo = {};
ui.disks = [];
ui.distroHelper = {};
ui.distroHelperNo = {};
ui.fullvirt = {};
ui.fullvirtHide = [];
ui.initrd = {};
ui.kernel = {};
ui.label = {};
ui.limit = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.maxMem = {};
ui.memLimit = {};
ui.modulesHelper = {};
ui.modulesHelperNo = {};
ui.networkHelper = {};
ui.networkHelperNo = {};
ui.noLimit = {};
ui.notes = {};
ui.paravirt = {};
ui.saveButton = {};
ui.sda = {};
ui.sdb = {};
ui.sdc = {};
ui.sdd = {};
ui.sde = {};
ui.sdf = {};
ui.sdg = {};
ui.sdh = {};
ui.single = {};
ui.standard = {};
ui.updatedbHelper = {};
ui.updatedbHelperNo = {};
ui.volumes = [];
// Temporary state
var state = {
"haveDisks": false,
"haveVolumes": false
};
// Callback for config API call
var displayConfig = function(response)
{
data.config = response;
// Label and notes
ui.label.value = data.config.label;
ui.notes.value = data.config.comments;
// Virtualization mode
if (data.config.virt_mode == "paravirt")
ui.paravirt.checked = true;
else if (data.config.virt_mode == "fullvirt")
ui.fullvirt.checked = true;
showHideFullvirt(null);
// Kernel
if (data.kernels.length)
ui.kernel.value = data.config.kernel;
// Run level
if (data.config.run_level == "default")
ui["default"].checked = true;
else if (data.config.run_level == "single")
ui.single.checked = true;
else if (data.config.run_level == "binbash")
ui.binbash.checked = true;
// Memory limit
if (data.config.memory_limit == 0) {
ui.noLimit.checked = true;
} else {
ui.limit.checked = true;
ui.memLimit.value = data.config.memory_limit;
}
// Disk configuration
if (state.haveDisks && state.haveVolumes)
displayDrives();
if (data.config.initrd)
ui.initrd.value = data.config.initrd;
if (/^\/dev\/sd[a-h]$/.test(data.config.root_device)) {
ui.standard.checked = true;
ui.bootDeviceStandard.value = data.config.root_device;
} else {
ui.custom.checked = true;
ui.bootDeviceCustom.value = data.config.root_device;
}
// Helpers
if (data.config.helpers.distro)
ui.distroHelper.checked = true;
else
ui.distroHelperNo.checked = true;
if (data.config.helpers.updatedb_disabled)
ui.updatedbHelper.checked = true;
else
ui.updatedbHelperNo.checked = true;
if (data.config.helpers.modules_dep)
ui.modulesHelper.checked = true;
else
ui.modulesHelperNo.checked = true;
if (data.config.helpers.devtmpfs_automount)
ui.devtmpfsHelper.checked = true;
else
ui.devtmpfsHelperNo.checked = true;
if (data.config.helpers.network)
ui.networkHelper.checked = true;
else
ui.networkHelperNo.checked = true;
ui.saveButton.disabled = false;
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Display memory limits
ui.maxMem.innerHTML = data.linode.specs.memory;
ui.memLimit.max = data.linode.specs.memory;
// Get list of volumes
apiGet("/volumes", displayVolumes, null);
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
state.haveDisks = true;
// Add disks to selectors
for (var i = data.disks.length - 1; i >= 0; i--) {
var disk = document.createElement("option");
disk.value = "disk-" + data.disks[i].id;
disk.innerHTML = data.disks[i].label;
for (var j = 0; j < ui.disks.length; j++)
ui.disks[j].prepend(disk.cloneNode(true));
}
if (data.config.devices && state.haveVolumes)
displayDrives();
};
// Sets the values for the drive selectors
var displayDrives = function()
{
for (var drive in data.config.devices) {
if (!data.config.devices[drive])
continue;
if (data.config.devices[drive].disk_id)
ui[drive].value = "disk-" + data.config.devices[drive].disk_id;
else if (data.config.devices[drive].volume_id)
ui[drive].value = "volume-" + data.config.devices[drive].volume_id;
}
};
// Callback for linode kernels API call
var displayKernels = function(response)
{
// Add kernels to array
data.kernels = data.kernels.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/kernels?page=" + (response.page + 1), displayKernels, null);
return;
}
// Add kernels to selector
for (var i = 0; i < data.kernels.length; i++) {
var kernel = document.createElement("option");
kernel.value = data.kernels[i].id;
kernel.innerHTML = data.kernels[i].label;
ui.kernel.appendChild(kernel);
if (data.params.cid == 0 && data.kernels[i].id == settings.preferredKernel)
ui.kernel.value = data.kernels[i].id;
}
if (data.config.kernel)
ui.kernel.value = data.config.kernel;
};
// Callback for account settings API call
var displaySettings = function(response)
{
if (response.network_helper)
ui.networkHelper.checked = true;
else
ui.networkHelperNo.checked = true;
};
// Callback for volumes API call
var displayVolumes = function(response)
{
// Add volumes to array
data.volumes = data.volumes.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/volumes?page=" + (response.page + 1), displayVolumes, null);
return;
}
state.haveVolumes = true;
// Add volumes from this Linode's region to selectors
for (var i = 0; i < data.volumes.length; i++) {
if (data.volumes[i].region != data.linode.region)
continue;
if (data.volumes[i].linode_id && data.volumes[i].linode_id != data.params.lid)
continue;
var volume = document.createElement("option");
volume.value = "volume-" + data.volumes[i].id;
volume.innerHTML = data.volumes[i].label;
for (var j = 0; j < ui.volumes.length; j++)
ui.volumes[j].appendChild(volume.cloneNode(true));
}
if (data.config.devices && state.haveDisks)
displayDrives();
};
// Save button handler
var handleSave = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"label": ui.label.value,
"comments": ui.notes.value,
"kernel": ui.kernel.value,
"devices": {},
"helpers": {
"distro": ui.distroHelper.checked,
"updatedb_disabled": ui.updatedbHelper.checked,
"modules_dep": ui.modulesHelper.checked,
"devtmpfs_automount": ui.devtmpfsHelper.checked,
"network": ui.networkHelper.checked
}
};
if (ui.paravirt.checked)
req.virt_mode = "paravirt";
else if (ui.fullvirt.checked)
req.virt_mode = "fullvirt";
if (ui["default"].checked)
req.run_level = "default";
else if (ui.single.checked)
req.run_level = "single";
else if (ui.binbash.checked)
req.run_level = "binbash";
if (ui.noLimit.checked)
req.memory_limit = 0;
else
req.memory_limit = parseInt(ui.memLimit.value);
if (ui.sda.value.startsWith("disk-"))
req.devices.sda = { "disk_id": parseInt(ui.sda.value.substring(5)) };
else if (ui.sda.value.startsWith("volume-"))
req.devices.sda = { "volume_id": parseInt(ui.sda.value.substring(7)) };
if (ui.sdb.value.startsWith("disk-"))
req.devices.sdb = { "disk_id": parseInt(ui.sdb.value.substring(5)) };
else if (ui.sdb.value.startsWith("volume-"))
req.devices.sdb = { "volume_id": parseInt(ui.sdb.value.substring(7)) };
if (ui.sdc.value.startsWith("disk-"))
req.devices.sdc = { "disk_id": parseInt(ui.sdc.value.substring(5)) };
else if (ui.sdc.value.startsWith("volume-"))
req.devices.sdc = { "volume_id": parseInt(ui.sdc.value.substring(7)) };
if (ui.sdd.value.startsWith("disk-"))
req.devices.sdd = { "disk_id": parseInt(ui.sdd.value.substring(5)) };
else if (ui.sdd.value.startsWith("volume-"))
req.devices.sdd = { "volume_id": parseInt(ui.sdd.value.substring(7)) };
if (ui.paravirt.checked) {
if (ui.sde.value.startsWith("disk-"))
req.devices.sde = { "disk_id": parseInt(ui.sde.value.substring(5)) };
else if (ui.sde.value.startsWith("volume-"))
req.devices.sde = { "volume_id": parseInt(ui.sde.value.substring(7)) };
if (ui.sdf.value.startsWith("disk-"))
req.devices.sdf = { "disk_id": parseInt(ui.sdf.value.substring(5)) };
else if (ui.sdf.value.startsWith("volume-"))
req.devices.sdf = { "volume_id": parseInt(ui.sdf.value.substring(7)) };
if (ui.sdg.value.startsWith("disk-"))
req.devices.sdg = { "disk_id": parseInt(ui.sdg.value.substring(5)) };
else if (ui.sdg.value.startsWith("volume-"))
req.devices.sdg = { "volume_id": parseInt(ui.sdg.value.substring(7)) };
if (ui.sdh.value.startsWith("disk-"))
req.devices.sdh = { "disk_id": parseInt(ui.sdh.value.substring(5)) };
else if (ui.sdh.value.startsWith("volume-"))
req.devices.sdh = { "volume_id": parseInt(ui.sdh.value.substring(7)) };
}
var initrd = parseInt(ui.initrd.value);
if (initrd == 0)
req.initrd = null;
else
req.initrd = initrd;
if (ui.standard.checked)
req.root_device = ui.bootDeviceStandard.value;
else
req.root_device = ui.bootDeviceCustom.value;
if (data.params.cid == 0) {
apiPost("/linode/instances/" + data.params.lid + "/configs", req, function(response) {
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
} else {
apiPut("/linode/instances/" + data.params.lid + "/configs/" + data.params.cid, req, function(response) {
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
}
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode ID supplied!");
return;
}
// We also need a config ID
if (!data.params.cid) {
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("lid=00", data.params.lid);
anchors[i].href = anchors[i].href.replace("lid=0", "lid=" + data.params.lid);
}
// Highlight the dashboard subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/dashboard")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.binbash = document.getElementById(elements.binbash);
ui.bootDeviceCustom = document.getElementById(elements.bootDeviceCustom);
ui.bootDeviceStandard = document.getElementById(elements.bootDeviceStandard);
ui.custom = document.getElementById(elements.custom);
ui["default"] = document.getElementById(elements["default"]);
ui.devtmpfsHelper = document.getElementById(elements.devtmpfsHelper);
ui.devtmpfsHelperNo = document.getElementById(elements.devtmpfsHelperNo);
ui.disks = document.getElementsByClassName(elements.disks);
ui.distroHelper = document.getElementById(elements.distroHelper);
ui.distroHelperNo = document.getElementById(elements.distroHelperNo);
ui.fullvirt = document.getElementById(elements.fullvirt);
ui.fullvirtHide = document.getElementsByClassName(elements.fullvirtHide);
ui.initrd = document.getElementById(elements.initrd);
ui.kernel = document.getElementById(elements.kernel);
ui.label = document.getElementById(elements.label);
ui.limit = document.getElementById(elements.limit);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.maxMem = document.getElementById(elements.maxMem);
ui.memLimit = document.getElementById(elements.memLimit);
ui.modulesHelper = document.getElementById(elements.modulesHelper);
ui.modulesHelperNo = document.getElementById(elements.modulesHelperNo);
ui.networkHelper = document.getElementById(elements.networkHelper);
ui.networkHelperNo = document.getElementById(elements.networkHelperNo);
ui.noLimit = document.getElementById(elements.noLimit);
ui.notes = document.getElementById(elements.notes);
ui.paravirt = document.getElementById(elements.paravirt);
ui.saveButton = document.getElementById(elements.saveButton);
ui.sda = document.getElementById(elements.sda);
ui.sdb = document.getElementById(elements.sdb);
ui.sdc = document.getElementById(elements.sdc);
ui.sdd = document.getElementById(elements.sdd);
ui.sde = document.getElementById(elements.sde);
ui.sdf = document.getElementById(elements.sdf);
ui.sdg = document.getElementById(elements.sdg);
ui.sdh = document.getElementById(elements.sdh);
ui.single = document.getElementById(elements.single);
ui.standard = document.getElementById(elements.standard);
ui.updatedbHelper = document.getElementById(elements.updatedbHelper);
ui.updatedbHelperNo = document.getElementById(elements.updatedbHelperNo);
ui.volumes = document.getElementsByClassName(elements.volumes);
// Register event handlers
ui.fullvirt.addEventListener("input", showHideFullvirt);
ui.paravirt.addEventListener("input", showHideFullvirt);
ui.saveButton.addEventListener("click", handleSave);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/kernels", displayKernels, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
if (data.params.cid == 0) {
apiGet("/account/settings", displaySettings, null);
ui.saveButton.disabled = false;
} else {
apiGet("/linode/instances/" + data.params.lid + "/configs/" + data.params.cid, displayConfig, null);
}
};
// Show/hide rows for fullvirt
var showHideFullvirt = function(event)
{
var display = "table-row";
if (ui.fullvirt.checked)
display = "none";
for (var i = 0; i < ui.fullvirtHide.length; i++)
ui.fullvirtHide[i].style.display = display;
};
// Attach onload handler
window.addEventListener("load", setup);
})();

326
linodes/config/index.shtml Normal file
View File

@ -0,0 +1,326 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Edit Configuration Profile</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="config.css" />
<script src="config.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Edit Configuration Profile</span></div>
<div id="config">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Configuration Profile</td>
</tr>
<tr>
<td colspan="3">Label and Notes</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Label</td>
<td colspan="2"><input id="label" type="text" value="New Profile" maxlength="48" size="50" /></td>
</tr>
<tr class="lmc-tr3">
<td>Notes</td>
<td colspan="2"><textarea id="notes" rows="3" cols="60"></textarea></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Virtual Machine Mode</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>VM Mode</td>
<td>
<input checked id="paravirt" type="radio" name="vm-mode" />
<label for="paravirt">Paravirtualization</label><br />
<input id="fullvirt" type="radio" name="vm-mode" />
<label for="fullvirt">Full-virtualization</label>
</td>
<td>
<span class="info">
Controls if devices inside your virtual machine are paravirtualized or fully virtualized.<br />
Paravirt is what you want, unless you're doing weird things.
</span>
</td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Boot Settings</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Kernel</td>
<td colspan="2">
<select id="kernel"></select>
</td>
</tr>
<tr class="lmc-tr3">
<td>Run Level</td>
<td colspan="2">
<input checked id="default" type="radio" name="run-level" />
<label for="default">Default Run Level</label><br />
<input id="single" type="radio" name="run-level" />
<label for="single">Single user mode</label><br />
<input id="binbash" type="radio" name="run-level" />
<label for="binbash">init=/bin/bash</label>
</td>
</tr>
<tr class="lmc-tr3">
<td>Memory Limit</td>
<td colspan="2">
<input id="limit" type="radio" name="mem-limit" />
<label for="limit">Limit to</label> <input id="mem-limit" type="number" min="0" value="0" /> MB<br />
<input checked id="no-limit" type="radio" name="mem-limit" />
<label for="no-limit">Maximum (<span id="max-mem"></span> MB)</label>
</td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Block Device Assignment</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>/dev/sda</td>
<td>
<select id="sda" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdb</td>
<td>
<select id="sdb" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdc</td>
<td>
<select id="sdc" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdd</td>
<td>
<select id="sdd" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3 fullvirt-hide">
<td>/dev/sde</td>
<td>
<select id="sde" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3 fullvirt-hide">
<td>/dev/sdf</td>
<td>
<select id="sdf" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3 fullvirt-hide">
<td>/dev/sdg</td>
<td>
<select id="sdg" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3 fullvirt-hide">
<td>/dev/sdh</td>
<td>
<select id="sdh" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks">
<option value="disk-25665">Recovery - Finnix (iso)</option>
</optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>initrd</td>
<td>
<select id="initrd">
<option selected value="0">-- No initrd --</option>
<option value="25669">Recovery - Finnix (initrd)</option>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>root / boot device</td>
<td>
<input checked id="standard" type="radio" name="boot-device" />
<label for="standard">Standard: </label>
<select id="boot-device-standard">
<option value="/dev/sda">/dev/sda</option>
<option value="/dev/sdb">/dev/sdb</option>
<option value="/dev/sdc">/dev/sdc</option>
<option value="/dev/sdd">/dev/sdd</option>
<option value="/dev/sde">/dev/sde</option>
<option value="/dev/sdf">/dev/sdf</option>
<option value="/dev/sdg">/dev/sdg</option>
<option value="/dev/sdh">/dev/sdh</option>
</select><br />
<input id="custom" type="radio" name="boot-device" />
<label for="custom">Custom: </label>
<input id="boot-device-custom" type="text" value="" />
</td>
<td></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Filesystem/Boot Helpers</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Distro Helper</td>
<td>
<input checked id="distro-helper" type="radio" name="distro-helper" />
<label for="distro-helper">Yes</label>
<input id="distro-helper-no" type="radio" name="distro-helper" />
<label for="distro-helper-no">No</label>
</td>
<td><span class="info">Helps maintain correct inittab/upstart console device</span></td>
</tr>
<tr class="lmc-tr3">
<td>Disable updatedb</td>
<td>
<input checked id="updatedb-helper" type="radio" name="updatedb-helper" />
<label for="updatedb-helper">Yes</label>
<input id="updatedb-helper-no" type="radio" name="updatedb-helper" />
<label for="updatedb-helper-no">No</label>
</td>
<td><span class="info">Disables updatedb cron job to avoid disk thrashing</span></td>
</tr>
<tr class="lmc-tr3">
<td>modules.dep Helper</td>
<td>
<input checked id="modules-helper" type="radio" name="modules-helper" />
<label for="modules-helper">Yes</label>
<input id="modules-helper-no" type="radio" name="modules-helper" />
<label for="modules-helper-no">No</label>
</td>
<td><span class="info">Creates a modules dependency file for the kernel you run</span></td>
</tr>
<tr class="lmc-tr3">
<td>Automount devtmpfs</td>
<td>
<input checked id="devtmpfs-helper" type="radio" name="devtmpfs-helper" />
<label for="devtmpfs-helper">Yes</label>
<input id="devtmpfs-helper-no" type="radio" name="devtmpfs-helper" />
<label for="devtmpfs-helper-no">No</label>
</td>
<td><span class="info">Controls if pv_ops kernels automount devtmpfs at boot</span></td>
</tr>
<tr class="lmc-tr3">
<td>Auto-configure Networking</td>
<td>
<input id="network-helper" type="radio" name="network-helper" />
<label for="network-helper">Yes</label>
<input id="network-helper-no" type="radio" name="network-helper" />
<label for="network-helper-no">No</label>
</td>
<td><span class="info">Automatically configure static networking <a href="https://www.linode.com/docs/platform/network-helper" target="_blank">(more info)</a></span></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="save-button" type="button">Save Changes</button></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,199 @@
/*
* 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 url('/global.css');
.backups-enabled {
font-weight: bold;
}
#boot {
margin-top: 5px;
}
.disk-icon {
height: 24px;
width: 26px;
}
.extra-event {
display: none;
}
h3 {
border-bottom: 1px solid #E8E8E8;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 18px;
font-weight: lighter;
margin-bottom: 50px;
}
.job-failed {
background-color: #C13100;
color: #FFF;
display: block;
padding: 5px;
text-align: center;
}
.job-info {
color: #777;
font-size: 10px;
}
.job-notice {
background-color: #3683DC;
color: #FFF;
display: block;
padding: 5px;
text-align: center;
}
#job-progress {
background-color: #A9A9A9;
display: block;
color: #31B96E;
width: calc(100% - 2px);
}
#job-progress::-moz-progress-bar {
background-color: #31B96E;
}
#job-progress::-webkit-progress-bar {
background-color: #A9A9A9;
}
#job-progress::-webkit-progress-value {
background-color: #31B96E;
}
#job-progress-row {
display: none;
}
#job-progress-row td {
padding: 0;
}
.job-running {
text-align: right;
}
.job-success {
background-color: #31B96E;
color: #FFF;
display: block;
padding: 5px;
text-align: center;
}
.job-type {
font-weight: bold;
}
#last-backup {
display: none;
}
#linode-details {
display: inline-block;
padding: 0px 15px 20px;
text-overflow: ellipsis;
width: 75%;
}
#linode-sidebar {
float: right;
margin-right: 15px;
width: calc(25% - 45px);
}
.lmc-table td {
white-space: nowrap;
}
.lmc-table td:nth-child(2) {
width: 100%;
}
#moar-jobs {
font-size: 13px;
font-weight: normal;
}
#notifications {
padding: 0px 15px;
}
#reboot {
display: none;
margin-top: 5px;
}
#server-status {
font-weight: bold;
font-size: 18px;
}
#shut-down {
display: none;
font-size: 14px;
margin: 0 auto 15px;
}
.sidebar-box {
border: 1px dotted #999;
font-size: 12px;
margin-bottom: 15px;
}
.sidebar-box a {
font-weight: bold;
}
.sidebar-box h4 {
background-color: #E5E5E5;
font-size: 15px;
margin: 0;
padding: 2px;
}
.sidebar-box meter {
display: block;
margin: 0 auto 10px;
width: 90%;
}
.sidebar-box p {
margin: 10px;
text-align: center;
}
.sidebar-box ul {
list-style-position: inside;
padding-left: 15px;
}
.sub-links-inline {
display: inline-block;
float: right;
}
#uptime {
display: none;
}

View File

@ -0,0 +1,887 @@
/*
* 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, eventTitles, parseParams, setupHeader, timeString, translateKernel } from "/global.js";
(function()
{
// Element names specific to this page
elements.backups = "backups";
elements.backupsEnabled = "backups-enabled";
elements.boot = "boot";
elements.configRadioName = "config-radio";
elements.configRemovePrefix = "config-remove-";
elements.configTable = "config-table";
elements.diskIcon = "disk-icon";
elements.diskIconImg = "/img/disk.gif";
elements.diskRemovePrefix = "disk-remove-";
elements.diskTable = "disk-table";
elements.diskUsage = "disk-usage";
elements.eventRowPrefix = "event-row-";
elements.eventTable = "event-table";
elements.extraEvent = "extra-event";
elements.info = "info";
elements.jobFailed = "job-failed";
elements.jobInfo = "job-info";
elements.jobNotice = "job-notice";
elements.jobProgress = "job-progress";
elements.jobProgressRow = "job-progress-row";
elements.jobRunning = "job-running";
elements.jobSuccess = "job-success";
elements.jobType = "job-type";
elements.lastBackup = "last-backup";
elements.lastBackupTime = "last-backup-time";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr3";
elements.loadingConfigs = "loading-configs";
elements.loadingDisks = "loading-disks";
elements.loadingJobs = "loading-jobs";
elements.loadingVolumes = "loading-volumes";
elements.moreJobs = "moar-jobs";
elements.netUsage = "net-usage";
elements.notification = "notification";
elements.notifications = "notifications";
elements.reboot = "reboot";
elements.serverStatus = "server-status";
elements.shutDown = "shut-down";
elements.spinnerImg = "/img/spinner-trans.gif";
elements.storageFree = "storage-free";
elements.storageTotal = "storage-total";
elements.storageUsed = "storage-used";
elements.transferMonthly = "transfer-monthly";
elements.transferOverage = "transfer-overage";
elements.transferUsed = "transfer-used";
elements.volumeTable = "volume-table";
// Data recieved from API calls
var data = {};
data.params = {};
data.configs = [];
data.disks = [];
data.events = [];
data.linode = {};
data.linodeTransfer = {};
data.notifications = [];
data.volumes = [];
// Static references to UI elements
var ui = {};
ui.backups = {};
ui.boot = {};
ui.configTable = {};
ui.diskTable = {};
ui.diskUsage = {};
ui.eventTable = {};
ui.jobProgress = {};
ui.jobProgressRow = {};
ui.lastBackup = {};
ui.lastBackupTime = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.loadingConfigs = {};
ui.loadingDisks = {};
ui.loadingJobs = {};
ui.loadingVolumes = {};
ui.moreJobs = {};
ui.netUsage = {};
ui.notifications = {};
ui.reboot = {};
ui.serverStatus = {};
ui.shutDown = {};
ui.storageFree = {};
ui.storageTotal = {};
ui.storageUsed = {};
ui.transferMonthly = {};
ui.transferOverage = {};
ui.transferUsed = {};
ui.volumeTable = {};
// Temporary state
var state = {};
state.diskRefresh = false;
state.eventsComplete = 0;
state.linodeRefresh = false;
state.showExtraEvents = false;
// Button handler for boot button
var bootLinode = function(event)
{
if (!confirm("Boot this Linode?"))
return;
var config = getSelectedConfig();
var request = {};
if (config)
request.config_id = config;
// Reload the page on successful API return
var callback = function()
{
location.reload();
};
apiPost("/linode/instances/" + data.params.lid + "/boot", request, callback);
};
// Convert a byte count into a "friendly" byte string (KB, MB, GB, etc)
var byteString = function(count)
{
var prefix = "KMGTPEZY";
var unit = "";
for (var i = 0; i < prefix.length; i++) {
if (count >= 1024) {
count /= 1024;
unit = prefix.charAt(i);
} else {
break;
}
}
return count.toFixed(2) + " " + unit + "B";
};
// Generate a config profile table row
var createConfigRow = function(config)
{
var row = document.createElement("tr");
row.className = elements.lmcRow;
// Radio button selector
var radioCell = document.createElement("td");
var radioInput = document.createElement("input");
radioInput.name = elements.configRadioName;
radioInput.className = elements.configRadioName;
radioInput.id = elements.configRadioName + "-" + config.id;
radioInput.type = "radio";
radioCell.appendChild(radioInput);
row.appendChild(radioCell);
// Config profile name and kernel
var nameCell = document.createElement("td");
var nameLink = document.createElement("a");
nameLink.href = "/linodes/config?cid=" + config.id + "&lid=" + data.params.lid;
if (config.label.length > 41)
nameLink.innerHTML = config.label.substring(0, 41) + "...";
else
nameLink.innerHTML = config.label;
nameCell.appendChild(nameLink);
var prefix = document.createElement("span");
prefix.className = elements.info;
prefix.innerHTML = " (";
nameCell.appendChild(prefix);
var kernel = document.createElement("span");
kernel.className = elements.info;
translateKernel(config.kernel, kernel);
nameCell.appendChild(kernel);
var suffix = document.createElement("span");
suffix.className = elements.info;
suffix.innerHTML = ")";
nameCell.appendChild(suffix);
row.appendChild(nameCell);
// Option links
var options = document.createElement("td");
var editLink = document.createElement("a");
editLink.href = "/linodes/config?cid=" + config.id + "&lid=" + data.params.lid;
editLink.innerHTML = "Edit";
var separator = document.createElement("span");
separator.innerHTML = " | ";
var removeLink = document.createElement("a");
removeLink.href = "#";
removeLink.id = elements.configRemovePrefix + config.id;
removeLink.innerHTML = "Remove";
removeLink.addEventListener("click", deleteConfig);
options.appendChild(editLink);
options.appendChild(separator);
options.appendChild(removeLink);
row.appendChild(options);
return row;
};
// Generate a disk table row
var createDiskRow = function(disk)
{
var row = document.createElement("tr");
row.className = elements.lmcRow;
// Disk icon
var iconCell = document.createElement("td");
var diskIcon = document.createElement("img");
diskIcon.className = elements.diskIcon;
diskIcon.src = elements.diskIconImg;
iconCell.appendChild(diskIcon);
row.appendChild(iconCell);
// Disk name and size
var nameCell = document.createElement("td");
var nameLink = document.createElement("a");
nameLink.href = "/linodes/disk?did=" + disk.id + "&lid=" + data.params.lid;
nameLink.innerHTML = disk.label;
var size = document.createElement("span");
size.className = elements.info;
size.innerHTML = " (" + disk.size + " MB, " + disk.filesystem + ")";
nameCell.appendChild(nameLink);
nameCell.appendChild(size);
row.appendChild(nameCell);
// Options links
var options = document.createElement("td");
var editLink = document.createElement("a");
editLink.href = "/linodes/disk?did=" + disk.id + "&lid=" + data.params.lid;
editLink.innerHTML = "Edit";
var separator = document.createElement("span");
separator.innerHTML = " | ";
var removeLink = document.createElement("a");
removeLink.href = "#";
removeLink.id = elements.diskRemovePrefix + disk.id;
removeLink.innerHTML = "Remove";
removeLink.addEventListener("click", deleteDisk);
options.appendChild(editLink);
options.appendChild(separator);
options.appendChild(removeLink);
row.appendChild(options);
return row;
};
// Generate an event table row
var createEventRow = function(event, extra)
{
var row = document.createElement("tr");
row.id = elements.eventRowPrefix + event.id;
row.className = elements.lmcRow;
if (extra)
row.className += " " + elements.extraEvent;
// Status cell
var statusCell = document.createElement("td");
if (event.status.match(/scheduled|started/)) {
statusCell.className = elements.jobRunning;
var spinner = document.createElement("img");
spinner.src = elements.spinnerImg;
statusCell.appendChild(spinner);
} else if (event.status == "failed") {
var failed = document.createElement("span");
failed.className = elements.jobFailed;
failed.innerHTML = "Failed";
statusCell.appendChild(failed);
} else if (event.status == "notification") {
var notice = document.createElement("span");
notice.className = elements.jobNotice;
notice.innerHTML = "Notice";
statusCell.appendChild(notice);
} else if (event.status == "finished") {
var success = document.createElement("span");
success.className = elements.jobSuccess;
success.innerHTML = "Success";
statusCell.appendChild(success);
}
row.appendChild(statusCell);
// Details cell
var detailsCell = document.createElement("td");
var jobType = document.createElement("span");
jobType.className = elements.jobType;
if (eventTitles[event.action])
jobType.innerHTML = eventTitles[event.action];
else
jobType.innerHTML = event.action;
var jobDetails = document.createElement("span");
if (event.secondary_entity)
jobDetails.innerHTML = " - " + event.secondary_entity.label;
var br = document.createElement("br");
var jobInfo = document.createElement("span");
jobInfo.className = elements.jobInfo;
var eventDate = new Date(event.created + "Z");
var curDate = new Date();
jobInfo.innerHTML = "Entered: " + timeString(curDate - eventDate, true);
if (event.percent_complete && event.percent_complete != 100)
jobInfo.innerHTML += " - " + event.percent_complete + "%";
if (event.time_remaining) {
var times = event.time_remaining.split(":");
var ms = 0;
ms += parseInt(times[0]) * 3600000;
ms += parseInt(times[1]) * 60000;
ms += parseInt(times[2]) * 1000;
jobInfo.innerHTML += " - " + timeString(ms, false) + " Remaining";
}
detailsCell.appendChild(jobType);
detailsCell.appendChild(jobDetails);
detailsCell.appendChild(br);
detailsCell.appendChild(jobInfo);
row.appendChild(detailsCell);
return row;
};
// Generate a volume table row
var createVolumeRow = function(volume)
{
var row = document.createElement("tr");
row.className = elements.lmcRow;
// Disk icon
var iconCell = document.createElement("td");
var diskIcon = document.createElement("img");
diskIcon.className = elements.diskIcon;
diskIcon.src = elements.diskIconImg;
iconCell.appendChild(diskIcon);
row.appendChild(iconCell);
// Volume name and size
var nameCell = document.createElement("td");
var nameLink = document.createElement("a");
nameLink.href = "/volumes/settings?vid=" + volume.id;
nameLink.innerHTML = volume.label;
var size = document.createElement("span");
size.className = elements.info;
size.innerHTML = " (" + volume.size + " GiB)";
nameCell.appendChild(nameLink);
nameCell.appendChild(size);
row.appendChild(nameCell);
// Options links
var options = document.createElement("td");
var editLink = document.createElement("a");
editLink.href = "/volumes/settings?vid=" + volume.id;
editLink.innerHTML = "Edit";
var separator = document.createElement("span");
separator.innerHTML = " | ";
var cloneLink = document.createElement("a");
cloneLink.href = "/volumes/clone?vid=" + volume.id;
cloneLink.innerHTML = "Clone";
var detachLink = document.createElement("a");
detachLink.href = "/volumes/detach?vid=" + volume.id;
detachLink.innerHTML = "Detach";
var removeLink = document.createElement("a");
removeLink.href = "/volumes/remove?vid=" + volume.id;
removeLink.innerHTML = "Remove";
options.appendChild(editLink);
options.appendChild(separator);
options.appendChild(cloneLink);
options.appendChild(separator.cloneNode(true));
options.appendChild(detachLink);
options.appendChild(separator.cloneNode(true));
options.appendChild(removeLink);
row.appendChild(options);
return row;
};
// Handler for config delete
var deleteConfig = function(event)
{
if (!confirm("Delete this Configuration Profile?"))
return;
var cid = event.currentTarget.id.substring(elements.configRemovePrefix.length);
apiDelete("/linode/instances/" + data.params.lid + "/configs/" + cid, function()
{
location.reload();
});
};
// Handler for disk delete
var deleteDisk = function(event)
{
var did = parseInt(event.currentTarget.id.substring(elements.diskRemovePrefix.length));
var disk = null;
for (var i = 0; i < data.disks.length; i++) {
if (data.disks[i].id == did) {
disk = data.disks[i];
break;
}
}
if (!disk)
return;
if (!confirm("Delete " + disk.label + "?"))
return;
apiDelete("/linode/instances/" + data.params.lid + "/disks/" + did, function()
{
location.reload();
});
};
// Callback for backups API call
var displayBackups = function(response)
{
// Find time of most recent backup
var mostRecent = new Date(0);
for (var i = 0; i < response.automatic.length; i++) {
if (response.automatic[i].status == "successful") {
var time = new Date(response.automatic[i].finished + "Z");
if (time > mostRecent)
mostRecent = time;
}
}
if (response.snapshot.current && response.snapshot.current.status == "successful") {
var time = new Date(response.snapshot.current.finished + "Z");
if (time > mostRecent)
mostRecent = time;
}
// 1970 means no backups happened
if (mostRecent.getUTCFullYear() == 1970)
return;
var curDate = new Date();
ui.lastBackupTime.innerHTML = timeString(curDate - mostRecent, true);
ui.lastBackup.style.display = "block";
};
// Callback for config profile 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
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/configs?page=" + (response.page + 1), displayConfigs, null);
return;
}
// Remove loading row
ui.loadingConfigs.remove();
// Insert config profile rows into table
for (var i = 0; i < data.configs.length; i++)
ui.configTable.appendChild(createConfigRow(data.configs[i]));
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
if (document.title.indexOf("//") == -1)
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
} else {
ui.linodeTag.style.display = "none";
}
// Set running status
ui.serverStatus.innerHTML = data.linode.status.charAt(0).toUpperCase() + data.linode.status.slice(1).replace(/_/g, " ");
if (data.linode.status == "running") {
ui.shutDown.disabled = false;
ui.shutDown.style.display = "block";
} else {
ui.shutDown.style.display = "none";
}
if (data.linode.status.match(/offline|provisioning|migrating|rebuilding|restoring|shutting_down|resizing/)) {
ui.reboot.style.display = "none";
ui.boot.disabled = false;
ui.boot.style.display = "inline";
} else if (data.linode.status != "cloning") {
ui.boot.style.display = "none";
ui.reboot.disabled = false;
ui.reboot.style.display = "inline";
}
// Update storage info
displayStorage();
// Set backup status
if (data.linode.backups.enabled) {
ui.backups.innerHTML = "Enabled!";
ui.backups.className += " " + elements.backupsEnabled;
} else {
ui.backups.innerHTML = "";
var text = document.createElement("span");
text.innerHTML = "No - ";
var backupLink = document.createElement("a");
backupLink.href = "/linodes/backups_enable?lid=" + data.params.lid;
backupLink.innerHTML = "Enable";
backups.appendChild(text);
backups.appendChild(backupLink);
}
state.linodeRefresh = false;
};
// Callback for disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Remove loading row
ui.loadingDisks.remove();
// Update storage info
displayStorage();
// Insert disk rows into table
ui.diskTable.innerHTML = "";
for (var i = 0; i < data.disks.length; i++)
ui.diskTable.appendChild(createDiskRow(data.disks[i]));
state.diskRefresh = false;
};
// Callback for events API call
var displayEvents = function(response)
{
// Only collect a max of 8 finished jobs
for (var i = 0; i < response.data.length && state.eventsComplete < 8; i++) {
if (response.data[i].status.match(/failed|finished|notification/))
state.eventsComplete++;
data.events.push(response.data[i]);
}
// Request the next page if there are more
if (state.eventsComplete < 8 && response.page != response.pages) {
var filter = {
"entity.type": "linode",
"entity.id": parseInt(data.params.lid)
};
apiGet("/account/events?page=" + (response.page + 1), displayEvents, filter);
return;
}
// Remove loading row
ui.loadingJobs.remove();
// Insert events into table and compute total progress
var progress = 0;
var totalProgress = 0;
for (var i = 0; i < data.events.length; i++) {
var extra = (data.events[i].status.match(/failed|finished|notification/) && i >= 4);
ui.eventTable.appendChild(createEventRow(data.events[i], extra));
if (!data.events[i].status.match(/failed|finished|notification/)) {
totalProgress += 100;
progress += data.events[i].percent_complete;
// Set refresh timer for event
window.setTimeout(getEvent, settings.refreshRate, data.events[i].id);
}
}
// If there are ongoing events, show the progress bar
if (totalProgress) {
ui.jobProgress.max = totalProgress;
ui.jobProgress.value = progress;
ui.jobProgress.innerHTML = (progress / totalProgress * 100).toFixed(0) + "%";
ui.jobProgress.title = ui.jobProgress.innerHTML;
ui.jobProgressRow.style.display = "table-row";
}
};
// Callback for notifications API call
var displayNotifications = function(response)
{
// Add notifications to array
data.notifications = data.notifications.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/account/notifications?page=" + (response.page + 1), displayNotifications, null);
return;
}
// Display notifications
for (var i = 0; i < data.notifications.length; i++) {
if (!data.notifications[i].entity || data.notifications[i].entity.type != "linode" || data.notifications[i].entity.id != data.params.lid)
continue;
var notification = document.createElement("div");
notification.className = elements.notification;
var header = document.createElement("h1");
header.innerHTML = data.notifications[i].label;
notification.appendChild(header);
if (data.notifications[i].type == "migration_pending") {
var migrateButton = document.createElement("button");
migrateButton.type = "button";
migrateButton.innerHTML = "Migrate " + data.notifications[i].entity.label + " NOW";
migrateButton.addEventListener("click", initiateMigration);
notification.appendChild(migrateButton);
}
var body = document.createElement("p");
body.innerHTML = data.notifications[i].message;
notification.appendChild(body);
ui.notifications.appendChild(notification);
}
};
// Show storage totals
var displayStorage = function()
{
if (!data.linode.specs)
return;
ui.storageTotal.innerHTML = data.linode.specs.disk + " MB";
var storageUsed = 0;
for (var i = 0; i < data.disks.length; i++)
storageUsed += data.disks[i].size;
ui.storageUsed.innerHTML = storageUsed + " MB";
ui.storageFree.innerHTML = (data.linode.specs.disk - storageUsed) + " MB";
ui.diskUsage.value = (storageUsed / data.linode.specs.disk * 100).toFixed(0);
ui.diskUsage.innerHTML = ui.diskUsage.value + "%";
ui.diskUsage.title = ui.diskUsage.innerHTML;
};
// Callback for network transfer API call
var displayTransfer = function(response)
{
data.linodeTransfer = response;
// Display network transfer info
ui.transferMonthly.innerHTML = data.linodeTransfer.quota + " GB";
ui.transferUsed.innerHTML = byteString(data.linodeTransfer.used);
ui.transferOverage.innerHTML = data.linodeTransfer.billable + " GB";
ui.netUsage.value = ((data.linodeTransfer.used / 1024 / 1024 / 1024) / data.linodeTransfer.quota * 100).toFixed(0);
ui.netUsage.innerHTML = ui.netUsage.value + "%";
ui.netUsage.title = ui.netUsage.innerHTML;
};
// Callback for volumes API call
var displayVolumes = function(response)
{
// Add volumes to array
data.volumes = data.volumes.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/volumes?page=" + (response.page + 1), displayVolumes, null);
return;
}
// Remove loading row
ui.loadingVolumes.remove();
// Insert volume rows into table
for (var i = 0; i < data.volumes.length; i++)
ui.volumeTable.appendChild(createVolumeRow(data.volumes[i]));
};
// Retrieve the given event from the API
var getEvent = function(eventID)
{
apiGet("/account/events/" + eventID, updateEvent, null);
};
// Get selected config profile
var getSelectedConfig = function()
{
var configs = document.getElementsByClassName(elements.configRadioName);
for (var i = 0; i < configs.length; i++) {
if (configs[i].checked)
return parseInt(configs[i].id.replace(elements.configRadioName + "-", ""));
}
return 0;
};
// Button handler to initiate migration
var initiateMigration = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"upgrade": false
};
apiPost("/linode/instances/" + data.params.lid + "/migrate", req, function(response)
{
location.reload();
});
};
// Button handler for reboot button
var rebootLinode = function(event)
{
if (!confirm("Are you sure you want to issue a Reboot?"))
return;
var config = getSelectedConfig();
var request = {};
if (config)
request.config_id = config;
// Reload the page on successful API return
var callback = function()
{
location.reload();
};
apiPost("/linode/instances/" + data.params.lid + "/reboot", request, callback);
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.backups = document.getElementById(elements.backups);
ui.boot = document.getElementById(elements.boot);
ui.configTable = document.getElementById(elements.configTable);
ui.diskTable = document.getElementById(elements.diskTable);
ui.diskUsage = document.getElementById(elements.diskUsage);
ui.eventTable = document.getElementById(elements.eventTable);
ui.jobProgress = document.getElementById(elements.jobProgress);
ui.jobProgressRow = document.getElementById(elements.jobProgressRow);
ui.lastBackup = document.getElementById(elements.lastBackup);
ui.lastBackupTime = document.getElementById(elements.lastBackupTime);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.loadingConfigs = document.getElementById(elements.loadingConfigs);
ui.loadingDisks = document.getElementById(elements.loadingDisks);
ui.loadingJobs = document.getElementById(elements.loadingJobs);
ui.loadingVolumes = document.getElementById(elements.loadingVolumes);
ui.moreJobs = document.getElementById(elements.moreJobs);
ui.netUsage = document.getElementById(elements.netUsage);
ui.notifications = document.getElementById(elements.notifications);
ui.reboot = document.getElementById(elements.reboot);
ui.serverStatus = document.getElementById(elements.serverStatus);
ui.shutDown = document.getElementById(elements.shutDown);
ui.storageFree = document.getElementById(elements.storageFree);
ui.storageTotal = document.getElementById(elements.storageTotal);
ui.storageUsed = document.getElementById(elements.storageUsed);
ui.transferMonthly = document.getElementById(elements.transferMonthly);
ui.transferOverage = document.getElementById(elements.transferOverage);
ui.transferUsed = document.getElementById(elements.transferUsed);
ui.volumeTable = document.getElementById(elements.volumeTable);
// Attach button handlers
ui.boot.addEventListener("click", bootLinode);
ui.moreJobs.addEventListener("click", toggleEvents);
ui.reboot.addEventListener("click", rebootLinode);
ui.shutDown.addEventListener("click", shutDownLinode);
// Get data from the API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/configs", displayConfigs, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
apiGet("/linode/instances/" + data.params.lid + "/volumes", displayVolumes, null);
apiGet("/linode/instances/" + data.params.lid + "/transfer", displayTransfer, null);
apiGet("/linode/instances/" + data.params.lid + "/backups", displayBackups, null);
var filter = {
"entity.type": "linode",
"entity.id": parseInt(data.params.lid)
};
apiGet("/account/events", displayEvents, filter);
apiGet("/account/notifications", displayNotifications, null);
};
// Button handler for shutdown button
var shutDownLinode = function(event)
{
if (!confirm("Are you sure you want to issue a Shutdown?"))
return;
// Reload the page on successful API return
var callback = function()
{
location.reload();
};
apiPost("/linode/instances/" + data.params.lid + "/shutdown", {}, callback);
};
// Toggle visibility of "extra" events
var toggleEvents = function(event)
{
// Flip
state.showExtraEvents = !state.showExtraEvents;
var display = "none";
if (state.showExtraEvents)
display = "table-row";
// Get extra events and show/hide them
var extras = document.getElementsByClassName(elements.extraEvent);
for (var i = 0; i < extras.length; i++)
extras[i].style.display = display;
};
// Update an existing event
var updateEvent = function(event)
{
// Update the local copy of the event
var progress = 0;
for (var i = 0; i < data.events.length; i++) {
if (data.events[i].id == event.id) {
progress = event.percent_complete - data.events[i].percent_complete;
// Refresh details if event status changed
if (event.status != data.events[i].status && !state.linodeRefresh && !state.diskRefresh) {
state.linodeRefresh = true;
state.diskRefresh = true;
data.linode = {};
data.disks = [];
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
}
data.events[i] = event;
continue;
}
}
// Generate a new event row and replace the existing one
var eventRow = document.getElementById(elements.eventRowPrefix + event.id);
var extra = (eventRow.className.indexOf(elements.extraEvent) != -1);
eventRow.replaceWith(createEventRow(event, extra));
// Update progress bar
ui.jobProgress.value += progress;
ui.jobProgress.innerHTML = (ui.jobProgress.value / ui.jobProgress.max * 100).toFixed(0) + "%";
ui.jobProgress.title = ui.jobProgress.innerHTML;
if (ui.jobProgress.value == ui.jobProgress.max)
ui.jobProgressRow.style.display = "none";
// Refresh again if not complete
if (!event.status.match(/failed|finished|notification/))
window.setTimeout(getEvent, settings.refreshRate, event.id);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,142 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Dashboard</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="dashboard.css" />
<script src="dashboard.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><span id="linode-label" class="top-links-title"></span></div>
<div id="notifications"></div>
<div id="linode-details">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Dashboard</td>
</tr>
<tr>
<td>Select</td>
<td>Configuration Profiles</td>
<td>Options</td>
</tr>
</thead>
<tbody id="config-table">
<tr id="loading-configs" class="lmc-tr3">
<td></td>
<td>Loading configuration profiles...</td>
<td></td>
</tr>
</tbody>
</table>
<button id="boot" type="button" disabled>Boot</button>
<button id="reboot" type="button">Reboot</button>
<p class="sub-links sub-links-inline">
<a href="/linodes/rebuild?lid=0">Rebuild</a> | <a href="/linodes/deploy?lid=0">Deploy an Image</a> | <a href="/linodes/config?cid=0&lid=0">Create a new Configuration Profile</a>
</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Disks</td>
</tr>
</thead>
<tbody id="disk-table">
<tr id="loading-disks" class="lmc-tr3">
<td></td>
<td>Loading disks...</td>
<td></td>
</tr>
</tbody>
</table>
<p class="sub-links"><a href="/linodes/disk?did=0&lid=0">Create a new Disk</a></p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Volumes</td>
</tr>
</thead>
<tbody id="volume-table">
<tr id="loading-volumes" class="lmc-tr3">
<td></td>
<td>Loading volumes...</td>
<td></td>
</tr>
</tbody>
</table>
<p class="sub-links">
<a href="/volumes">View all Volumes</a> | <a href="/volumes/add?lid=0">Create a new Volume</a>
</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="2">Host Job Queue <a id="moar-jobs" href="#">(more)</a></td>
</tr>
</thead>
<tbody id="event-table">
<tr id="job-progress-row" class="lmc-tr1">
<td colspan="2"><progress id="job-progress" max="100" value="50">50%</progress></td>
</tr>
<tr id="loading-jobs" class="lmc-tr3">
<td></td>
<td>Loading jobs...</td>
</tr>
</tbody>
</table>
<h3>Graphs</h3>
</div>
<div id="linode-sidebar">
<div class="sidebar-box">
<h4>Server Status</h4>
<p>Your Linode is currently</p>
<p id="server-status"></p>
<button id="shut-down" type="button">Shut down</button>
</div>
<div class="sidebar-box">
<h4>Network</h4>
<ul>
<li>Transfer/mo: <span id="transfer-monthly"></span></li>
<li>Used: <span id="transfer-used"></span></li>
<li>Overage: <span id="transfer-overage"></span></li>
</ul>
<p>Monthly transfer usage:</p>
<meter id="net-usage" max="100" low="50" optimum="30" high="80" value="0"></meter>
</div>
<div class="sidebar-box">
<h4>Storage</h4>
<ul>
<li>Total: <span id="storage-total"></span></li>
<li>Used: <span id="storage-used"></span></li>
<li>Free: <span id="storage-free"></span></li>
</ul>
<p>Storage allocation:</p>
<meter id="disk-usage" max="100" low="50" optimum="30" high="80" value="0"></meter>
</div>
<div class="sidebar-box">
<h4>Backups</h4>
<p id="backups"></p>
<p id="last-backup">Last backup was <span id="last-backup-time"></span></p>
</div>
</div>
</div>
</body>
</html>

35
linodes/deploy/deploy.css Normal file
View File

@ -0,0 +1,35 @@
/*
* 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 url('/global.css');
#deploy {
padding: 0px 15px 15px;
}
#size {
width: 80px;
}
tbody tr:last-of-type {
border: none;
}
tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
}

243
linodes/deploy/deploy.js Normal file
View File

@ -0,0 +1,243 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.currentDistros = "current";
elements.customImages = "custom";
elements.deletedDisks = "deleted";
elements.deployButton = "deploy-button";
elements.deprecatedDistros = "deprecated";
elements.image = "image";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.maxSize = "max";
elements.minSize = "min";
elements.rootPass = "root-pass";
elements.size = "size";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.disks = [];
data.images = [];
data.linode = {};
// Static references to UI elements
var ui = {};
ui.currentDistros = {};
ui.customImages = {};
ui.deletedDisks = {};
ui.deployButton = {};
ui.deprecatedDistros = {};
ui.image = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.rootPass = {};
ui.maxSize = {};
ui.minSize = {};
ui.size = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Get linode's disks
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
};
// Callback for disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Display max size
var free = data.linode.specs.disk;
for (var i = 0; i < data.disks.length; i++)
free -= data.disks[i].size;
ui.maxSize.innerHTML = free;
ui.size.max = free;
ui.size.value = free;
};
// Callback for images API call
var displayImages = function(response)
{
// Add images to array
data.images = data.images.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/images?page=" + (response.page + 1), displayImages, null);
return;
}
// Add images to selector
for (var i = 0; i < data.images.length; i++) {
var image = document.createElement("option");
image.value = data.images[i].id;
image.innerHTML = data.images[i].label;
if (data.images[i].deprecated)
ui.deprecatedDistros.appendChild(image);
else if (data.images[i].type == "automatic")
ui.deletedDisks.appendChild(image);
else if (!data.images[i].vendor)
ui.customImages.appendChild(image);
else
ui.currentDistros.appendChild(image);
if (data.images[i].id == settings.preferredDistro) {
ui.image.value = data.images[i].id;
ui.minSize.innerHTML = data.images[i].size;
ui.size.min = data.images[i].size;
}
}
if (ui.customImages.childNodes.length == 0)
ui.customImages.style.display = "none";
if (ui.deletedDisks.childNodes.length == 0)
ui.deletedDisks.style.display = "none";
ui.deployButton.disabled = false;
};
// Handler for deploy button
var handleDeploy = function(event)
{
if (event.currentTarget.disabled)
return;
var image = null;
for (var i = 0; i < data.images.length; i++) {
if (data.images[i].id == ui.image.value) {
image = data.images[i];
break;
}
}
if (!image)
return;
var req = {
"label": image.label,
"size": parseInt(ui.size.value),
"image": ui.image.value,
"root_pass": ui.rootPass.value
};
if (image.id.startsWith("linode/"))
req.label += " Disk";
apiPost("/linode/instances/" + data.params.lid + "/disks", req, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the dashboard subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/dashboard")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.currentDistros = document.getElementById(elements.currentDistros);
ui.customImages = document.getElementById(elements.customImages);
ui.deletedDisks = document.getElementById(elements.deletedDisks);
ui.deployButton = document.getElementById(elements.deployButton);
ui.deprecatedDistros = document.getElementById(elements.deprecatedDistros);
ui.image = document.getElementById(elements.image);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.maxSize = document.getElementById(elements.maxSize);
ui.minSize = document.getElementById(elements.minSize);
ui.rootPass = document.getElementById(elements.rootPass);
ui.size = document.getElementById(elements.size);
// Register event handlers
ui.deployButton.addEventListener("click", handleDeploy);
ui.image.addEventListener("input", updateMinSize);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/images", displayImages, null);
};
// Update the mininum image size display
var updateMinSize = function()
{
var image = null;
for (var i = 0; i < data.images.length; i++) {
if (data.images[i].id == ui.image.value) {
image = data.images[i];
break;
}
}
if (!image)
return;
ui.minSize.innerHTML = image.size;
ui.size.min = image.size;
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,77 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Deploy</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="deploy.css" />
<script src="deploy.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Deploy</span></div>
<div id="deploy">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Deploy an Image</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Image</td>
<td>
<select id="image">
<optgroup id="current" label="64 bit Distributions - Recommended"></optgroup>
<optgroup id="deprecated" label="Older Distributions"></optgroup>
<optgroup id="custom" label="Images"></optgroup>
<optgroup id="deleted" label="Recently Deleted Disks"></optgroup>
</select>
</td>
<td><span class="info">See also: <a href="/linodes/deploy_stackscript?lid=0">Deploying using StackScripts</a></span></td>
</tr>
<tr class="lmc-tr3">
<td>Deployment Disk Size</td>
<td>
<input id="size" type="number" /> MB<br />
<span class="info"><span id="min"></span> MB min <span id="max"></span> MB max</span>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>Swap Disk</td>
<td>A swap disk must be created separately.</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>Root Password</td>
<td colspan="2"><input id="root-pass" type="password" /></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td colspan="2"><button disabled id="deploy-button" type="button">Deploy</button>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

63
linodes/disk/disk.css Normal file
View File

@ -0,0 +1,63 @@
/*
* 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 url('/global.css');
#disk {
padding: 0px 15px 15px;
}
h3 {
border-bottom: 1px solid #E8E8E8;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 18px;
font-weight: lighter;
margin-bottom: 0px;
}
.resize {
display: none;
}
#space-warning {
display: none;
}
.stats-box {
border-right: 1px solid #E8E8E8;
display: inline-block;
font-size: 11px;
padding: 5px 12px 0;
}
.stats-box:last-of-type {
border-right: none;
}
.stats-box span {
font-size: 13.3px;
font-weight: bold;
}
tbody tr:last-of-type {
border: none;
}
tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
}

297
linodes/disk/disk.js Normal file
View File

@ -0,0 +1,297 @@
/*
* 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, apiGet, apiPost, apiPut, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.currentSize = "current-size";
elements.currentSizeRow = "current-size-row";
elements.currentType = "current-type";
elements.duplicateButton = "duplicate-button";
elements.imageButton = "image-button";
elements.label = "label";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.maxSize = "max-size";
elements.resizeAddl = "resize-addl";
elements.saveButton = "save-button";
elements.size = "size";
elements.spaceAllocated = "space-allocated";
elements.spaceFree = "space-free";
elements.spaceTotal = "space-total";
elements.spaceWarning = "space-warning";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
elements.type = "type";
// Data recieved from API calls
var data = {};
data.disks = [];
data.linode = {};
// Static references to UI elements
var ui = {};
ui.currentSize = {};
ui.currentSizeRow = {};
ui.currentType = {};
ui.duplicateButton = {};
ui.imageButton = {};
ui.label = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.maxSize = {};
ui.resizeAddl = {};
ui.saveButton = {};
ui.size = {};
ui.spaceAllocated = {};
ui.spaceFree = {};
ui.spaceTotal = {};
ui.spaceWarning = {};
ui.type = {};
// Temporary state
var state = {};
state.haveDisks = false;
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
if (state.haveDisks)
displayStorage();
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
for (var i = 0; i < data.disks.length; i++) {
if (data.disks[i].id == data.params.did) {
data.disk = data.disks[i];
break;
}
}
state.haveDisks = true;
if (data.linode.specs)
displayStorage();
if (!data.disk)
return;
// Update form
ui.label.value = data.disk.label;
ui.currentType.innerHTML = data.disk.filesystem;
ui.currentSize.innerHTML = data.disk.size;
ui.size.value = data.disk.size;
if (data.disk.filesystem != "raw" && data.disk.filesystem != "swap")
ui.imageButton.disabled = false;
};
// Show storage totals
var displayStorage = function()
{
var storageUsed = 0;
for (var i = 0; i < data.disks.length; i++)
storageUsed += data.disks[i].size;
var storageFree = data.linode.specs.disk - storageUsed;
ui.spaceAllocated.innerHTML = storageUsed;
ui.spaceFree.innerHTML = storageFree;
ui.spaceTotal.innerHTML = data.linode.specs.disk;
if (data.params.did == 0) {
ui.size.max = storageFree;
ui.maxSize.innerHTML = storageFree;
if (storageFree <= 0)
ui.spaceWarning.style.display = "block";
else
ui.saveButton.disabled = false;
}
if (!data.disk)
return;
ui.size.max = storageFree + data.disk.size;
ui.maxSize.innerHTML = storageFree + data.disk.size;
ui.saveButton.disabled = false;
if (storageFree >= data.disk.size)
ui.duplicateButton.disabled = false;
};
// Duplicate button handler
var handleDuplicate = function(event)
{
if (event.currentTarget.disabled)
return;
apiPost("/linode/instances/" + data.params.lid + "/disks/" + data.params.did + "/clone", {}, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Image button handler
var handleImage = function(event)
{
if (event.currentTarget.disabled)
return;
location.href = "/images/create?lid=" + data.params.lid + "&did=" + data.params.did;
};
// Save button handler
var handleSave = function(event)
{
if (event.currentTarget.disabled)
return;
var diskSize = parseInt(ui.size.value);
var standardCallback = function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
};
if (data.params.did == 0) {
var req = {
"label": ui.label.value,
"size": diskSize,
"filesystem": ui.type.value
};
apiPost("/linode/instances/" + data.params.lid + "/disks", req, standardCallback);
} else {
var labelReq = {
"label": ui.label.value
};
var resizeReq = {
"size": diskSize
};
if (data.disk.size != diskSize) {
if (data.disk.label != ui.label.value) {
apiPut("/linode/instances/" + data.params.lid + "/disks/" + data.params.did, labelReq, function(response)
{
apiPost("/linode/instances/" + data.params.lid + "/disks/" + data.params.did + "/resize", resizeReq, standardCallback);
});
} else {
apiPost("/linode/instances/" + data.params.lid + "/disks/" + data.params.did + "/resize", resizeReq, standardCallback);
}
} else if (data.disk.label != ui.label.value) {
apiPut("/linode/instances/" + data.params.lid + "/disks/" + data.params.did, labelReq, standardCallback);
} else {
location.href = "/linodes/dashboard?lid=" + data.params.lid;
}
}
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode ID supplied!");
return;
}
// We also need a disk ID
if (!data.params.did) {
alert("No disk 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("lid=00", data.params.lid);
anchors[i].href = anchors[i].href.replace("lid=0", "lid=" + data.params.lid);
}
// Highlight the dashboard subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/dashboard")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.currentSize = document.getElementById(elements.currentSize);
ui.currentSizeRow = document.getElementById(elements.currentSizeRow);
ui.currentType = document.getElementById(elements.currentType);
ui.duplicateButton = document.getElementById(elements.duplicateButton);
ui.imageButton = document.getElementById(elements.imageButton);
ui.label = document.getElementById(elements.label);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.maxSize = document.getElementById(elements.maxSize);
ui.resizeAddl = document.getElementById(elements.resizeAddl);
ui.saveButton = document.getElementById(elements.saveButton);
ui.size = document.getElementById(elements.size);
ui.spaceAllocated = document.getElementById(elements.spaceAllocated);
ui.spaceFree = document.getElementById(elements.spaceFree);
ui.spaceTotal = document.getElementById(elements.spaceTotal);
ui.spaceWarning = document.getElementById(elements.spaceWarning);
ui.type = document.getElementById(elements.type);
if (data.params.did != 0) {
ui.currentSizeRow.style.display = "table-row";
ui.duplicateButton.style.display = "initial";
ui.imageButton.style.display = "initial";
ui.type.style.display = "none";
ui.resizeAddl.style.display = "initial";
}
// Register event handlers
ui.duplicateButton.addEventListener("click", handleDuplicate);
ui.imageButton.addEventListener("click", handleImage);
ui.saveButton.addEventListener("click", handleSave);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

92
linodes/disk/index.shtml Normal file
View File

@ -0,0 +1,92 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Edit Disk</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="disk.css" />
<script src="disk.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Edit Disk</span></div>
<div id="disk">
<p id="space-warning" class="warning">Not enough free disk space to create any more disk images</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Edit Disk</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Label</td>
<td colspan="2"><input id="label" type="text" value="New Disk Label" maxlength="48" size="50" /></td>
</tr>
<tr class="lmc-tr3">
<td>Type</td>
<td colspan="2">
<select id="type">
<option selected value="ext4">ext4</option>
<option value="ext3">ext3</option>
<option value="swap">swap</option>
<option value="raw">unformatted / raw</option>
<option value="initrd">initrd (uncompressed initrd, ext2, max: 32 MB)</option>
</select>
<span id="current-type"></span>
</td>
</tr>
<tr id="current-size-row" class="lmc-tr3 resize">
<td>Current Size</td>
<td colspan="2"><span id="current-size"></span> MB</td>
</tr>
<tr class="lmc-tr3">
<td>Size</td>
<td><input id="size" type="number" min="1" value="1" /> MB</td>
<td><span class="info">Enter a size between 1 and <span id="max-size"></span><span id="resize-addl" class="resize"> to resize this disk</span></span></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td colspan="2">
<button disabled id="save-button" type="button">Save Changes</button>
<button disabled id="duplicate-button" class="resize" type="button">Duplicate Disk</button>
<button disabled id="image-button" class="resize" type="button">Create Image</button>
</td>
</tr>
</tbody>
</table>
<h3>Storage Stats</h3>
<div class="stats-box">
<span><span id="space-allocated"></span> MB</span><br />
Allocated
</div>
<div class="stats-box">
<span><span id="space-free"></span> MB</span><br />
Free
</div>
<div class="stats-box">
<span><span id="space-total"></span> MB</span><br />
Total
</div>
</div>
</div>
</body>
</html>

22
linodes/graphs/graphs.css Normal file
View File

@ -0,0 +1,22 @@
/*
* 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 url('/global.css');
#graphs {
padding: 0px 15px 15px;
}

82
linodes/graphs/graphs.js Normal file
View File

@ -0,0 +1,82 @@
/*
* 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, apiGet, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,35 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Graphs</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="graphs.css" />
<script src="graphs.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Graphs</span></div>
<div id="graphs">
</div>
</div>
</body>
</html>

43
linodes/index.shtml Normal file
View File

@ -0,0 +1,43 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Linode Manager Classic</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="linodes.css" />
<script src="linodes.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<div id="main-content" class="wrapper">
<div id="linodes">
<div id="notifications"></div>
<span id="loading">Loading...</span>
</div>
<div id="transfer-pool">
<p id="transfer-header">This Month's Network Transfer Pool</p>
<div id="transfer-bar">
<div id="bar-used"></div><div id="bar-remaining"></div>
</div>
<p id="transfer-details"><span id="transfer-used"></span> Used, <span id="transfer-remaining"></span> Remaining, <span id="transfer-quota"></span> Quota</p>
<p id="transfer-notice">Your transfer is prorated and will reset next month</p>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,52 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - IP Failover</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="ip_failover.css" />
<script src="ip_failover.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/remote_access?lid=0">Remote Access</a> » <span class="top-links-title">IP Failover</span></div>
<div id="ip-failover">
<table class="lmc-table">
<thead>
<tr>
<td colspan="2">IP Failover Configuration</td>
</tr>
</thead>
<tbody id="failover-table">
<tr id="loading" class="lmc-tr3">
<td>Loading...</td>
<td></td>
</tr>
<tr id="save-row" class="lmc-tr3">
<td></td>
<td><button disabled id="save-button" type="button">Save Changes</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,31 @@
/*
* 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 url('/global.css');
#ip-failover {
padding: 0px 15px 15px;
}
tbody tr:last-of-type {
border: none;
}
tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
}

View File

@ -0,0 +1,225 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.failoverTable = "failover-table";
elements.info = "info";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr3";
elements.loading = "loading";
elements.saveButton = "save-button";
elements.saveRow = "save-row";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.linode = {};
data.linodes = [];
// Static references to UI elements
var ui = {};
ui.failoverTable = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.loading = {};
ui.saveButton = {};
ui.saveRow = {};
// Temporary state
var state = {};
state.lidIndex = -1;
state.netInfoCount = 0;
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Get other Linodes in the same DC
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances", displayLinodes, filter);
};
// Callback for linodes API call
var displayLinodes = function(response)
{
// Add linodes to array
data.linodes = data.linodes.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, filter);
return;
}
// Get net info for each linode
for (var i = 0; i < data.linodes.length; i++)
apiGet("/linode/instances/" + data.linodes[i].id + "/ips", displayNetInfo, null);
};
// Callback for net info API call
var displayNetInfo = function(response)
{
// Find the associated linode
var lid = parseInt(response['_endpoint'].split("/")[3]);
var index = -1;
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == lid) {
index = i;
break;
}
}
if (i == -1)
return;
else if (lid == data.linode.id)
state.lidIndex = i;
data.linodes[index].netInfo = response;
state.netInfoCount++;
if (state.netInfoCount < data.linodes.length)
return;
// Populate the table
ui.loading.remove();
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == data.linode.id)
continue;
var ips = data.linodes[i].netInfo.ipv4["public"].concat(data.linodes[i].netInfo.ipv4["private"]);
for (var j = 0; j < ips.length; j++) {
var row = document.createElement("tr");
row.className = elements.lmcRow;
var nameCell = document.createElement("td");
nameCell.innerHTML = data.linodes[i].label;
var ipCell = document.createElement("td");
var box = document.createElement("input");
box.id = ips[j].address;
box.type = "checkbox";
for (var k = 0; k < data.linodes[state.lidIndex].netInfo.ipv4.shared.length; k++) {
if (data.linodes[state.lidIndex].netInfo.ipv4.shared[k].address == ips[j].address)
box.checked = true;
}
ipCell.appendChild(box);
var label = document.createElement("label");
label.htmlFor = box.id;
label.innerHTML = " " + ips[j].address;
ipCell.appendChild(label);
if (ips[j].rdns) {
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = " (" + ips[j].rdns + ")";
ipCell.appendChild(rdns);
}
row.appendChild(nameCell);
row.appendChild(ipCell);
ui.failoverTable.insertBefore(row, ui.saveRow);
}
}
ui.saveButton.disabled = false;
};
// Handler for save button
var handleSave = function(event)
{
if (event.currentTarget.disabled)
return;
var ips = [];
var boxes = document.getElementsByTagName("input");
for (var i = 0; i < boxes.length; i++) {
if (boxes[i].checked)
ips.push(boxes[i].id);
}
var req = {
"ips": ips,
"linode_id": data.linode.id
};
apiPost("/networking/ipv4/share", req, function(response) {
location.href = "/linodes/remote_access?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the remote access subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/remote_access")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.failoverTable = document.getElementById(elements.failoverTable);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.loading = document.getElementById(elements.loading);
ui.saveButton = document.getElementById(elements.saveButton);
ui.saveRow = document.getElementById(elements.saveRow);
// Attach event handlers
ui.saveButton.addEventListener("click", handleSave);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,49 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - IP Remove</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="ip_remove.css" />
<script src="ip_remove.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/remote_access?lid=0">Remote Access</a> » <span class="top-links-title">IP Remove</span></div>
<div id="ip-remove">
<table class="lmc-table">
<thead>
<tr>
<td id="label" colspan="2"></td>
</tr>
<tr>
<td>IP Address</td>
<td>Remove It</td>
</tr>
</thead>
<tbody id="ip-body"></tbody>
</table>
<button disabled id="remove-button" type="button">Remove Selected IPs</button>
<p><strong>Note</strong>: The IP address selected will be immediately removed. This is not reversible.</p>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
/*
* 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 url('/global.css');
button {
display: block;
margin: 10px 0 0 auto;
}
#ip-remove {
padding: 0px 15px 15px;
}
p {
text-align: center;
}
td:nth-of-type(1) {
width: 100%;
}
td:nth-of-type(2) {
text-align: center;
white-space: nowrap;
}

View File

@ -0,0 +1,176 @@
/*
* 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, apiGet, apiDelete, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.info = "info";
elements.ipBody = "ip-body";
elements.label = "label";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr1";
elements.lmcRowAlt = "lmc-tr2";
elements.removeBox = "remove-box";
elements.removeButton = "remove-button";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.ipBody = {};
ui.label = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.removeButton = {};
// Temporary state
var state = {};
state.numReqs = 0;
state.numReturns = 0;
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
ui.label.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
};
// Callback for linode net info API call
var displayNetInfo = function(response)
{
// Insert public IPs into table
for (var i = 0; i < response.ipv4["public"].length; i++) {
var row = document.createElement("tr");
if (i % 2)
row.className = elements.lmcRowAlt;
else
row.className = elements.lmcRow;
var ipCell = document.createElement("td");
var ip = document.createElement("span");
ip.innerHTML = response.ipv4["public"][i].address;
ipCell.appendChild(ip);
if (response.ipv4["public"][i].rdns) {
var br = document.createElement("br");
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = response.ipv4["public"][i].rdns;
ipCell.appendChild(br);
ipCell.appendChild(rdns);
}
var removeCell = document.createElement("td");
var removeBox = document.createElement("input");
removeBox.id = response.ipv4["public"][i].address;
removeBox.className = elements.removeBox;
removeBox.type = "checkbox";
removeCell.appendChild(removeBox);
row.appendChild(ipCell);
row.appendChild(removeCell);
ui.ipBody.appendChild(row);
}
ui.removeButton.disabled = false;
};
// Event handler for remove button
var handleRemove = function(event)
{
if (event.currentTarget.disabled)
return;
var ips = document.getElementsByClassName(elements.removeBox);
state.numReqs = ips.length;
state.numReturns = 0;
// Submit removal request for each IP
for (var i = 0; i < ips.length; i++) {
if (!ips[i].checked)
continue;
apiDelete("/linode/instances/" + data.params.lid + "/ips/" + ips[i].id, function(response) {
state.numReturns++;
if (state.numReturns >= state.numReqs)
location.href = "/linodes/remote_access?lid=" + data.params.lid;
});
}
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the remote access subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/remote_access")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.ipBody = document.getElementById(elements.ipBody);
ui.label = document.getElementById(elements.label);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.removeButton = document.getElementById(elements.removeButton);
// Attach event handlers
ui.removeButton.addEventListener("click", handleRemove);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/ips", displayNetInfo, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,84 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - IP Swap</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="ip_swap.css" />
<script src="ip_swap.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/remote_access?lid=0">Remote Access</a> » <span class="top-links-title">IP Swap</span></div>
<div id="ip-swap">
<table id="select-table" class="lmc-table">
<thead>
<tr>
<td colspan="2">Swap IPs</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>With Linode</td>
<td><select id="linode-select"></select></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="select-button" type="button">Select</button></td>
</tr>
</tbody>
</table>
<table id="swap-table" class="lmc-table">
<thead>
<tr>
<td id="src-linode" colspan="2"></td>
<td></td>
<td id="dest-linode" colspan="2"></td>
</tr>
<tr>
<td>IP Address</td>
<td>Move It</td>
<td></td>
<td>Move It</td>
<td>IP Address</td>
</tr>
</thead>
<tbody id="public-ips"></tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="5"></td>
</tr>
<tr>
<td>Private IP Address</td>
<td>Move It</td>
<td></td>
<td>Move It</td>
<td>Private IP Address</td>
</tr>
</tbody>
<tbody id="private-ips"></tbody>
</table>
<button disabled id="do-it" type="button">Do it.</button>
<p>Note: This IP Address transfer will take effect immediately however there may be a short delay before both addresses become available.</p>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,91 @@
/*
* 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 url('/global.css');
#ip-swap {
padding: 0px 15px 15px;
}
p {
margin-top: 30px;
text-align: center;
}
#select-table tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
width: 200px;
}
#swap-table tr td:nth-of-type(5) {
text-align: right;
}
#swap-table tbody:not(.lmc-tbody-head) td:nth-of-type(2) {
text-align: center;
}
#swap-table tbody:not(.lmc-tbody-head) td:nth-of-type(3) {
font-size: 30px;
padding: 0;
text-align: center;
}
#swap-table tbody:not(.lmc-tbody-head) td:nth-of-type(4) {
text-align: center;
}
#swap-table tbody.lmc-tbody-head tr:nth-of-type(1) td:nth-of-type(2) {
background-color: #FFF;
}
#swap-table tbody.lmc-tbody-head tr:nth-of-type(2) td:nth-of-type(2) {
text-align: center;
}
#swap-table tbody.lmc-tbody-head tr:nth-of-type(2) td:nth-of-type(3) {
background-color: #FFF;
}
#swap-table tbody.lmc-tbody-head tr:nth-of-type(2) td:nth-of-type(4) {
text-align: center;
}
#swap-table thead tr:nth-of-type(1) td:nth-of-type(2) {
background-color: #FFF;
}
#swap-table thead tr:nth-of-type(2) td:nth-of-type(2) {
text-align: center;
}
#swap-table thead tr:nth-of-type(2) td:nth-of-type(3) {
background-color: #FFF;
}
#swap-table thead tr:nth-of-type(2) td:nth-of-type(4) {
text-align: center;
}
table {
margin-bottom: 20px;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}

374
linodes/ip_swap/ip_swap.js Normal file
View File

@ -0,0 +1,374 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.destClass = "dest-ip";
elements.destLinode = "dest-linode";
elements.doIt = "do-it";
elements.info = "info";
elements.linodeLabel = "linode-label";
elements.linodeSelect = "linode-select";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr3";
elements.privateIPs = "private-ips";
elements.publicIPs = "public-ips";
elements.selectButton = "select-button";
elements.srcClass = "src-ip";
elements.srcLinode = "src-linode";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.destNet = {};
data.linode = {};
data.linodes = [];
data.srcNet = {};
// Static references to UI elements
var ui = {};
ui.destLinode = {};
ui.doIt = {};
ui.linodeLabel = {};
ui.linodeSelect = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.privateIPs = {};
ui.publicIPs = {};
ui.selectButton = {};
ui.srcLinode = {};
// Temporary state
var state = {};
state.destIndex = -1;
state.haveDest = false;
state.haveSrc = false;
// Callback for destination linode network details API call
var displayDestNet = function(response)
{
data.destNet = response;
state.haveDest = true;
if (state.haveSrc)
displayIPs();
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
ui.srcLinode.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Get other Linodes in the same DC
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances", displayLinodes, filter);
apiGet("/linode/instances/" + data.params.lid + "/ips", displaySrcNet, null);
};
// Populate swap table with source and dest IPs
var displayIPs = function()
{
// Add public IPs
var numIPs = Math.max(data.srcNet.ipv4["public"].length, data.destNet.ipv4["public"].length);
for (var i = 0; i < numIPs; i++) {
var row = document.createElement("tr");
row.className = elements.lmcRow;
var srcAddr = document.createElement("td");
var srcMove = document.createElement("td");
if (data.srcNet.ipv4["public"][i]) {
var ip = document.createElement("span");
ip.innerHTML = data.srcNet.ipv4["public"][i].address;
var br = document.createElement("br");
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = data.srcNet.ipv4["public"][i].rdns;
srcAddr.appendChild(ip);
srcAddr.appendChild(br);
srcAddr.appendChild(rdns);
var move = document.createElement("input");
move.id = data.srcNet.ipv4["public"][i].address;
move.className = elements.srcClass;
move.type = "checkbox";
srcMove.appendChild(move);
}
row.appendChild(srcAddr);
row.appendChild(srcMove);
var arrow = document.createElement("td");
arrow.innerHTML = "↔";
row.appendChild(arrow);
var destAddr = document.createElement("td");
var destMove = document.createElement("td");
if (data.destNet.ipv4["public"][i]) {
var ip = document.createElement("span");
ip.innerHTML = data.destNet.ipv4["public"][i].address;
var br = document.createElement("br");
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = data.destNet.ipv4["public"][i].rdns;
destAddr.appendChild(ip);
destAddr.appendChild(br);
destAddr.appendChild(rdns);
var move = document.createElement("input");
move.id = data.destNet.ipv4["public"][i].address;
move.className = elements.destClass;
move.type = "checkbox";
destMove.appendChild(move);
}
row.appendChild(destMove);
row.appendChild(destAddr);
ui.publicIPs.appendChild(row);
}
// Add private IPs
var numIPs = Math.max(data.srcNet.ipv4["private"].length, data.destNet.ipv4["private"].length);
for (var i = 0; i < numIPs; i++) {
var row = document.createElement("tr");
row.className = elements.lmcRow;
var srcAddr = document.createElement("td");
var srcMove = document.createElement("td");
if (data.srcNet.ipv4["private"][i]) {
var ip = document.createElement("span");
ip.innerHTML = data.srcNet.ipv4["private"][i].address;
var br = document.createElement("br");
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = data.srcNet.ipv4["private"][i].rdns;
srcAddr.appendChild(ip);
srcAddr.appendChild(br);
srcAddr.appendChild(rdns);
var move = document.createElement("input");
move.id = data.srcNet.ipv4["private"][i].address;
move.className = elements.srcClass;
move.type = "checkbox";
srcMove.appendChild(move);
}
row.appendChild(srcAddr);
row.appendChild(srcMove);
var arrow = document.createElement("td");
arrow.innerHTML = "↔";
row.appendChild(arrow);
var destAddr = document.createElement("td");
var destMove = document.createElement("td");
if (data.destNet.ipv4["private"][i]) {
var ip = document.createElement("span");
ip.innerHTML = data.destNet.ipv4["private"][i].address;
var br = document.createElement("br");
var rdns = document.createElement("span");
rdns.className = elements.info;
rdns.innerHTML = data.destNet.ipv4["private"][i].rdns;
destAddr.appendChild(ip);
destAddr.appendChild(br);
destAddr.appendChild(rdns);
var move = document.createElement("input");
move.id = data.destNet.ipv4["private"][i].address;
move.className = elements.destClass;
move.type = "checkbox";
destMove.appendChild(move);
}
row.appendChild(destMove);
row.appendChild(destAddr);
ui.privateIPs.appendChild(row);
}
ui.doIt.disabled = false;
ui.selectButton.disabled = false;
};
// Callback for linodes API call
var displayLinodes = function(response)
{
// Add linodes to array
data.linodes = data.linodes.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
var filter = {
"region": data.linode.region
};
apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, filter);
return;
}
// Add linodes to selector
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == data.linode.id)
continue;
var option = document.createElement("option");
option.value = data.linodes[i].id;
option.innerHTML = data.linodes[i].label;
ui.linodeSelect.appendChild(option);
}
ui.selectButton.disabled = false;
};
// Callback for source linode network details API call
var displaySrcNet = function(response)
{
data.srcNet = response;
state.haveSrc = true;
if (state.haveDest)
displayIPs();
};
// Handler for select button
var handleSelect = function(event)
{
if (event.currentTarget.disabled)
return;
state.haveDest = false;
var lid = parseInt(ui.linodeSelect.value);
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].id == lid) {
state.destIndex = i;
break;
}
}
if (state.destIndex == -1)
return;
ui.doIt.disabled = true;
ui.selectButton.disabled = true;
ui.publicIPs.innerHTML = "";
ui.privateIPs.innerHTML = "";
ui.destLinode.innerHTML = data.linodes[state.destIndex].label;
apiGet("/linode/instances/" + data.linodes[state.destIndex].id + "/ips", displayDestNet, null);
};
// Handler for "do it" button
var handleSwap = function(event)
{
if (event.currentTarget.disabled)
return;
var assignments = [];
// Assign all checked source IPs to the destination Linode
var srcBoxes = document.getElementsByClassName(elements.srcClass);
for (var i = 0; i < srcBoxes.length; i++) {
if (!srcBoxes[i].checked)
continue;
assignments.push({
"address": srcBoxes[i].id,
"linode_id": data.linodes[state.destIndex].id
});
}
// Assign all checked destination IPs to the source Linode
var destBoxes = document.getElementsByClassName(elements.destClass);
for (var i = 0; i < destBoxes.length; i++) {
if (!destBoxes[i].checked)
continue;
assignments.push({
"address": destBoxes[i].id,
"linode_id": data.linode.id
});
}
if (!assignments.length)
return;
var req = {
"assignments": assignments,
"region": data.linode.region
};
apiPost("/networking/ipv4/assign", req, function(response) {
location.href = "/linodes/remote_access?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the remote access subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/remote_access")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.destLinode = document.getElementById(elements.destLinode);
ui.doIt = document.getElementById(elements.doIt);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeSelect = document.getElementById(elements.linodeSelect);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.privateIPs = document.getElementById(elements.privateIPs);
ui.publicIPs = document.getElementById(elements.publicIPs);
ui.selectButton = document.getElementById(elements.selectButton);
ui.srcLinode = document.getElementById(elements.srcLinode);
// Add event handlers
ui.selectButton.addEventListener("click", handleSelect);
ui.doIt.addEventListener("click", handleSwap);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

84
linodes/linodes.css Normal file
View File

@ -0,0 +1,84 @@
/*
* 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 url('/global.css');
#transfer-bar {
border: 3px solid #999;
margin: 0 auto;
width: 70%;
}
#bar-remaining {
background-color: #EFEFEF;
border: 2px solid #EFEFEF;
display: none;
font-size: 16px;
line-height: 25px;
text-align: center;
white-space: nowrap;
}
#bar-used {
background-color: #ADD370;
border: 2px dashed #008000;
display: none;
font-size: 16px;
line-height: 25px;
text-align: center;
white-space: nowrap;
}
.backup-no {
font-weight: bold;
}
.backup-yes {
color: #008000;
font-weight: bold;
}
.center-cell {
text-align: center;
}
.dashboard-link {
font-weight: bold;
}
#linodes {
padding: 15px;
}
#transfer-details {
margin: 5px 0px;
text-align: center;
}
#transfer-header {
font-weight: bold;
margin: 50px 0px 5px;
text-align: center;
}
#transfer-notice {
color: #777;
font-size: 12px;
margin: 10px 0px;
padding-bottom: 15px;
text-align: center;
}

386
linodes/linodes.js Normal file
View File

@ -0,0 +1,386 @@
/*
* 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, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.backupNo = "backup-no";
elements.backupYes = "backup-yes";
elements.barRemaining = "bar-remaining";
elements.barUsed = "bar-used";
elements.centerCell = "center-cell";
elements.dashboardLink = "dashboard-link";
elements.info = "info";
elements.linodes = "linodes";
elements.linodeTagPrefix = "linode-tag-";
elements.lmcRow = "lmc-tr1";
elements.lmcRowAlt = "lmc-tr2";
elements.lmcTable = "lmc-table";
elements.loading = "loading";
elements.notification = "notification";
elements.notifications = "notifications";
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.linodes = [];
data.linodeTags = [];
data.noTag = false;
data.notifications = [];
data.plans = [];
// Static references to UI elements
var ui = {};
ui.linodes = {};
ui.linodeTables = {};
ui.loading = {};
ui.notifications = {};
var createLinodeRow = function(linode, 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 = "/linodes/dashboard?lid=" + linode.id;
nameLink.innerHTML = linode.label;
name.appendChild(nameLink);
var status = document.createElement("td");
status.innerHTML = linode.status.charAt(0).toUpperCase() + linode.status.slice(1).replace(/_/g, " ");
var plan = document.createElement("td");
if (linode.type)
plan.innerHTML = getPlanLabel(linode.type);
else
plan.innerHTML = "Unknown";
if (plan.innerHTML == "")
translatePlan(linode.type, plan);
var ip = document.createElement("td");
ip.innerHTML = linode.ipv4[0];
var ipCount = 0;
for (var i = 1; i < linode.ipv4.length; i++) {
if (linode.ipv4[i].startsWith("192.168."))
continue;
if (linode.ipv4[i].startsWith("10."))
continue;
ipCount++;
}
if (ipCount) {
var plus = document.createElement("span");
plus.className = elements.info;
plus.innerHTML = " (+" + ipCount + ")";
ip.appendChild(plus);
}
var region = document.createElement("td");
if (regionNames[linode.region])
region.innerHTML = regionNames[linode.region];
else
region.innerHTML = linode.region;
var backups = document.createElement("td");
backups.className = elements.centerCell;
if (linode.backups.enabled) {
var backupStatus = document.createElement("span");
backupStatus.className = elements.backupYes;
backupStatus.innerHTML = "Yes";
backups.appendChild(backupStatus);
} else {
var backupStatus = document.createElement("span");
backupStatus.className = elements.backupNo;
backupStatus.innerHTML = "No";
var backupSeparator = document.createElement("span");
backupSeparator.innerHTML = " - ";
var backupLink = document.createElement("a");
backupLink.href = "/linodes/backups_enable?lid=" + linode.id;
backupLink.innerHTML = "Enable";
backups.appendChild(backupStatus);
backups.appendChild(backupSeparator);
backups.appendChild(backupLink);
}
var options = document.createElement("td");
options.className = elements.centerCell;
var dashboardLink = document.createElement("a");
dashboardLink.className = elements.dashboardLink;
dashboardLink.href = "/linodes/dashboard?lid=" + linode.id;
dashboardLink.innerHTML = "Dashboard";
var optionsSeparator = document.createElement("span");
optionsSeparator.innerHTML = " | ";
var removeLink = document.createElement("a");
removeLink.href = "/linodes/remove?lid=" + linode.id;
removeLink.innerHTML = "Remove";
options.appendChild(dashboardLink);
options.appendChild(optionsSeparator);
options.appendChild(removeLink);
row.appendChild(name);
row.appendChild(status);
row.appendChild(plan);
row.appendChild(ip);
row.appendChild(region);
row.appendChild(backups);
row.appendChild(options);
return row;
};
var createLinodeTable = function(tag)
{
var table = document.createElement("table");
table.id = elements.linodeTagPrefix + 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 = "Linodes";
else
title.innerHTML = tag;
headRow1.appendChild(title);
var headRow2 = document.createElement("tr");
var cells = ["Linode", "Status", "Plan", "IP", "Location", "Backups", "Options"];
title.colSpan = cells.length;
for (var i = 0; i < cells.length; i++) {
var cell = document.createElement("td");
if (cells[i] == "Backups" || 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.linodeTables[tag] = tbody;
var subLinks = document.createElement("p");
subLinks.className = elements.subLinks;
var volumes = document.createElement("a");
volumes.href = "/volumes";
volumes.innerHTML = "Manage Volumes";
var separator = document.createElement("span");
separator.innerHTML = " | ";
var images = document.createElement("a");
images.href = "/images";
images.innerHTML = "Manage Images";
var stackScripts = document.createElement("a");
stackScripts.href = "/stackscripts";
stackScripts.innerHTML = "Manage StackScripts";
var addLinode = document.createElement("a");
addLinode.href = "/linodes/add";
if (tag.length > 0)
addLinode.href += "?tag=" + tag;
addLinode.innerHTML = "Add a Linode";
subLinks.appendChild(volumes);
subLinks.appendChild(separator);
subLinks.appendChild(images);
subLinks.appendChild(separator.cloneNode(true));
subLinks.appendChild(stackScripts);
subLinks.appendChild(separator.cloneNode(true));
subLinks.appendChild(addLinode);
ui.linodes.appendChild(table);
ui.linodes.appendChild(subLinks);
};
var displayLinodes = function(response)
{
// Add linodes to array
data.linodes = data.linodes.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.linodeTags.includes(response.data[i].tags[j]))
data.linodeTags.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("/linode/instances?page=" + (response.page + 1), displayLinodes, filters);
return;
}
// Redirect to add page if there are no linodes
if (data.linodes.length == 0)
location.href = "/linodes/add";
// Sort
data.linodeTags.sort();
data.linodes.sort(function(a, b)
{
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
});
// Create tables
ui.loading.remove();
if (data.noTag)
createLinodeTable("");
for (var i = 0; i < data.linodeTags.length; i++)
createLinodeTable(data.linodeTags[i]);
// Insert linodes
for (var i = 0; i < data.linodes.length; i++) {
if (data.linodes[i].tags.length == 0)
ui.linodeTables[""].appendChild(createLinodeRow(data.linodes[i], ui.linodeTables[""].children.length % 2));
for (var j = 0; j < data.linodes[i].tags.length; j++)
ui.linodeTables[data.linodes[i].tags[j]].appendChild(createLinodeRow(data.linodes[i], ui.linodeTables[data.linodes[i].tags[j]].children.length % 2));
}
};
var displayNotifications = function(response)
{
// Add notifications to array
data.notifications = data.notifications.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/account/notifications?page=" + (response.page + 1), displayNotifications, null);
return;
}
// Display notifications
for (var i = 0; i < data.notifications.length; i++) {
if (data.notifications[i].entity && data.notifications[i].entity.type == "linode")
continue;
var notification = document.createElement("div");
notification.className = elements.notification;
var header = document.createElement("h1");
header.innerHTML = data.notifications[i].label;
var body = document.createElement("p");
body.innerHTML = data.notifications[i].message;
notification.appendChild(header);
notification.appendChild(body);
ui.notifications.appendChild(notification);
}
};
var displayTransfer = function(response)
{
var barRemaining = document.getElementById(elements.barRemaining);
var barUsed = document.getElementById(elements.barUsed);
var transferQuota = document.getElementById(elements.transferQuota);
var transferRemaining = document.getElementById(elements.transferRemaining);
var transferUsed = document.getElementById(elements.transferUsed);
// 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) {
barUsed.style = "display: inline-block; width: calc(" + usage + "% - " + usedBorderWidth + "px);";
barUsed.innerHTML = usage + "% Used";
}
if (usage != 100) {
barRemaining.style = "display: inline-block; width: calc(" + (100 - usage) + "% - " + remainingBorderWidth + "px);";
barRemaining.innerHTML = (100 - usage) + "% Remaining";
}
transferUsed.innerHTML = response.used + "GB";
transferRemaining.innerHTML = (response.quota - response.used) + "GB";
transferQuota.innerHTML = response.quota + "GB";
};
var getPlanLabel = function(id)
{
for (var i = 0; i < data.plans.length; i++) {
if (id == data.plans[i].id)
return data.plans[i].label;
}
return "";
};
var getPlans = function(response)
{
// Add plans to array
data.plans = data.plans.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/types?page=" + (response.page + 1), getPlans, null);
return;
}
// Get linodes
var filters = null;
if (data.params.tag)
filters = {
"tags": data.params.tag
};
apiGet("/linode/instances", displayLinodes, filters);
};
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
ui.linodes = document.getElementById(elements.linodes);
ui.loading = document.getElementById(elements.loading);
ui.notifications = document.getElementById(elements.notifications);
setupHeader();
// Get linode and transfer info
apiGet("/linode/types", getPlans, null);
apiGet("/account/transfer", displayTransfer, null);
apiGet("/account/notifications", displayNotifications, null);
};
var translatePlan = function(name, cell)
{
var callback = function(response)
{
cell.innerHTML = response.label;
};
apiGet("/linode/types/" + name, callback, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,37 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Add Private IP Address</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="privateip_add.css" />
<script src="privateip_add.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/remote_access?lid=0">Remote Access</a> » <span class="top-links-title">Add Private IP Address</span></div>
<div id="privateip-add">
<p>Are you sure you want to add a private IP address to the Linode <span id="label"></span>?</p>
<button id="add-button" type="button">Yes, add the IP address</button>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
/*
* 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 url('/global.css');
#label {
font-weight: bold;
}
#privateip-add {
padding: 0px 15px 15px;
}

View File

@ -0,0 +1,116 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.addButton = "add-button";
elements.label = "label";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.addButton = {};
ui.label = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
ui.label.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
};
// Handler for add button
var handleAdd = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"public": false,
"type": "ipv4"
};
apiPost("/linode/instances/" + data.params.lid + "/ips", req, function(response) {
location.href = "/linodes/remote_access?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the remote access subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/remote_access")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.addButton = document.getElementById(elements.addButton);
ui.label = document.getElementById(elements.label);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
// Attach event handlers
ui.addButton.addEventListener("click", handleAdd);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

53
linodes/rdns/index.shtml Normal file
View File

@ -0,0 +1,53 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Reverse DNS</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="rdns.css" />
<script src="rdns.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <a href="/linodes/remote_access?lid=0">Remote Access</a> » <span class="top-links-title">Reverse DNS</span></div>
<div id="rdns">
<table class="lmc-table">
<thead>
<tr>
<td colspan="2">Reverse DNS</td>
</tr>
<tr>
<td>IP Address</td>
<td>Target</td>
</tr>
</thead>
<tbody id="rdns-body">
<tr id="save-row" class="lmc-tr3">
<td></td>
<td><button disabled id="save-button" type="button">Save Changes</button></td>
</tr>
</tbody>
</table>
<p>Note: Forward DNS must already be set up for reverse DNS to be applied. Leaving any value blank will reset it to the default.</p>
</div>
</div>
</body>
</html>

34
linodes/rdns/rdns.css Normal file
View File

@ -0,0 +1,34 @@
/*
* 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 url('/global.css');
p {
text-align: center;
}
#rdns {
padding: 0px 15px 15px;
}
tbody tr td:first-of-type {
font-weight: bold;
}
tbody tr:last-of-type {
border: none;
}

166
linodes/rdns/rdns.js Normal file
View File

@ -0,0 +1,166 @@
/*
* 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, apiGet, apiPut, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lmcRow = "lmc-tr3";
elements.rdnsBody = "rdns-body";
elements.rdnsTarget = "rdns-target";
elements.saveButton = "save-button";
elements.saveRow = "save-row";
elements.subnav = "subnav-link";
elements.subnavActive = "subnav-link-active";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.rdnsBody = {};
ui.saveButton = {};
ui.saveRow = {};
// Temporary state
var state = {};
state.numReqs = 0;
state.numReturns = 0;
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
};
// Callback for linode net info API call
var displayNetInfo = function(response)
{
var ips = response.ipv4["public"];
ips.push(response.ipv6.slaac);
// Add IPs to table
for (var i = 0; i < ips.length; i++) {
var row = document.createElement("tr");
row.className = elements.lmcRow;
var addrCell = document.createElement("td");
addrCell.innerHTML = ips[i].address;
var targetCell = document.createElement("td");
var target = document.createElement("input");
target.id = ips[i].address;
target.className = elements.rdnsTarget;
target.type = "text";
target.placeholder = "host.yourdomain.com";
target.size = "36";
target.value = ips[i].rdns;
targetCell.appendChild(target);
row.appendChild(addrCell);
row.appendChild(targetCell);
ui.rdnsBody.insertBefore(row, ui.saveRow);
}
ui.saveButton.disabled = false;
};
// Event handler for save button
var handleSave = function(event)
{
if (event.currentTarget.disabled)
return;
var targets = document.getElementsByClassName(elements.rdnsTarget);
state.numReqs = targets.length;
state.numReturns = 0;
// Submit request for each IP
for (var i = 0; i < targets.length; i++) {
var req = {};
if (!targets[i].value.length)
req.rdns = null;
else
req.rdns = targets[i].value;
apiPut("/linode/instances/" + data.params.lid + "/ips/" + targets[i].id, req, function(response) {
state.numReturns++;
if (state.numReturns >= state.numReqs)
location.href = "/linodes/remote_access?lid=" + data.params.lid;
});
}
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Highlight the remote access subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/remote_access")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.rdnsBody = document.getElementById(elements.rdnsBody);
ui.saveButton = document.getElementById(elements.saveButton);
ui.saveRow = document.getElementById(elements.saveRow);
// Attach event handlers
ui.saveButton.addEventListener("click", handleSave);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/ips", displayNetInfo, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,72 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Rebuild - we have the technology</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="rebuild.css" />
<script src="rebuild.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Rebuild</span></div>
<div id="rebuild">
<p class="warning">Rebuilding will <strong>destroy all data</strong>, wipe your Linode clean, and start fresh.</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Deploy an Image</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Image</td>
<td>
<select id="image">
<optgroup id="current" label="64 bit Distributions - Recommended"></optgroup>
<optgroup id="deprecated" label="Older Distributions"></optgroup>
<optgroup id="custom" label="Images"></optgroup>
<optgroup id="deleted" label="Recently Deleted Disks"></optgroup>
</select>
</td>
<td><span class="info">See also: <a href="/linodes/rebuild_stackscript?lid=0">Deploying using StackScripts</a></span></td>
</tr>
<tr class="lmc-tr3">
<td>Swap</td>
<td>A 512MB swap disk will be automatically created.</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>Root Password</td>
<td><input id="root-pass" type="password" /></td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="rebuild-button" type="button">Rebuild</button></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,31 @@
/*
* 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 url('/global.css');
#rebuild {
padding: 0px 15px 15px;
}
tbody tr:last-of-type {
border: none;
}
tbody tr td:first-of-type {
font-weight: bold;
text-align: right;
}

170
linodes/rebuild/rebuild.js Normal file
View File

@ -0,0 +1,170 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.currentDistros = "current";
elements.customImages = "custom";
elements.deletedDisks = "deleted";
elements.deprecatedDistros = "deprecated";
elements.image = "image";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.rebuildButton = "rebuild-button";
elements.rootPass = "root-pass";
// Data recieved from API calls
var data = {};
data.images = [];
data.linode = {};
// Static references to UI elements
var ui = {};
ui.currentDistros = {};
ui.customImages = {};
ui.deletedDisks = {};
ui.deprecatedDistros = {};
ui.image = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.rebuildButton = {};
ui.rootPass = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
};
// Callback for images API call
var displayImages = function(response)
{
// Add images to array
data.images = data.images.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/images?page=" + (response.page + 1), displayImages, null);
return;
}
// Add images to selector
for (var i = 0; i < data.images.length; i++) {
var image = document.createElement("option");
image.value = data.images[i].id;
image.innerHTML = data.images[i].label;
if (data.images[i].deprecated)
ui.deprecatedDistros.appendChild(image);
else if (data.images[i].type == "automatic")
ui.deletedDisks.appendChild(image);
else if (!data.images[i].vendor)
ui.customImages.appendChild(image);
else
ui.currentDistros.appendChild(image);
if (data.images[i].id == settings.preferredDistro)
ui.image.value = data.images[i].id;
}
if (ui.customImages.childNodes.length == 0)
ui.customImages.style.display = "none";
if (ui.deletedDisks.childNodes.length == 0)
ui.deletedDisks.style.display = "none";
ui.rebuildButton.disabled = false;
};
// Rebuild button handler
var handleRebuild = function(event)
{
if (event.currentTarget.disabled)
return;
if (ui.rootPass.value.length == 0) {
alert("You must supply a root password.");
return;
}
if (!confirm("Delete all existing data on this Linode and redeploy?"))
return;
var request = {
"image": ui.image.value,
"root_pass": ui.rootPass.value,
"booted": false
};
apiPost("/linode/instances/" + data.params.lid + "/rebuild", request, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.currentDistros = document.getElementById(elements.currentDistros);
ui.customImages = document.getElementById(elements.customImages);
ui.deletedDisks = document.getElementById(elements.deletedDisks);
ui.deprecatedDistros = document.getElementById(elements.deprecatedDistros);
ui.image = document.getElementById(elements.image);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.rebuildButton = document.getElementById(elements.rebuildButton);
ui.rootPass = document.getElementById(elements.rootPass);
// Register rebuild button handler
ui.rebuildButton.addEventListener("click", handleRebuild);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/images", displayImages, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,127 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Remote Access</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="remote_access.css" />
<script src="remote_access.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Remote Access</span></div>
<div id="remote-access">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Network Access</td>
</tr>
<tr>
<td colspan="3">Public Network</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>SSH Access</td>
<td><a id="ssh-link"></a></td>
<td><a href="https://www.linode.com/docs/getting-started" target="_blank">Getting Started Guide</a></td>
</tr>
<tr class="lmc-tr3">
<td>Public IPs</td>
<td>
<span id="ipv4-addrs"></span>
<span id="slaac-addr"></span> / <span id="slaac-prefix"></span> ( <span id="slaac-rdns"></span> )<br />
<a href="/support/ticket/new?summary=Additional+IP+Justification">IP Add</a> | <span id="ip-remove" class="disabled">IP Remove</span> | <span id="ip-failover" class="disabled">IP Failover</span> | <span id="ip-swap" class="disabled">IP Swap</span> | <a href="/linodes/rdns?lid=0">Reverse DNS</a>
</td>
<td>
<a href="https://www.linode.com/docs/networking/linux-static-ip-configuration" target="_blank">Static Networking Guide</a><br />
<a href="https://www.linode.com/docs/networking/native-ipv6-networking" target="_blank">IPv6 Networking Guide</a>
</td>
</tr>
<tr class="lmc-tr3">
<td>Default Gateways</td>
<td>
<span id="ipv4-gateways"></span>
<span id="slaac-gateway"></span>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>DNS Resolvers</td>
<td id="resolvers"></td>
<td></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Private/LAN Network</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Private IPs</td>
<td id="private-ips">None - <a href="/linodes/privateip_add?lid=0">Add a Private IP</a></td>
<td><a id="private-ips-guide" href="https://www.linode.com/docs/networking/linux-static-ip-configuration" target="_blank">Static Networking Guide</a></td>
</tr>
<tr class="lmc-tr3">
<td>Link-Local IP</td>
<td id="link-local"></td>
<td></td>
</tr>
</tbody>
</table>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Console Access</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Lish via Browser</td>
<td><a id="weblish-link" href="https://cloud.linode.com/linodes/lid=00/lish/weblish" target="_blank">Launch Lish Console »</a></td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>Lish via SSH</td>
<td><a id="lish-link" href="ssh://@lish-.linode.com">ssh -t @lish-.linode.com</a></td>
<td>
<span class="info">Lish listens on ports 22, 443, and 2200</span><br />
(<a href="https://www.linode.com/docs/networking/using-the-linode-shell-lish#lish-gateway-fingerprints" target="_blank">Lish Guide & Fingerprints</a>)
</td>
</tr>
<tr class="lmc-tr3">
<td>Glish</td>
<td><a id="glish-link" href="https://cloud.linode.com/linodes/lid=00/lish/glish" target="_blank">Launch Graphical Web Console »</a></td>
<td>
<span class="info">Equivalent to plugging a monitor and keyboard into your server.</span><br />
(<a href="https://www.linode.com/docs/networking/using-the-graphic-shell-glish" target="_blank">Using Glish</a>)
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,47 @@
/*
* 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 url('/global.css');
.disabled {
text-decoration: line-through;
}
#private-ips-guide {
visibility: hidden;
}
#remote-access {
padding: 0px 15px 15px;
}
#ssh-link {
font-weight: bold;
}
table:first-of-type {
margin-bottom: 30px;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}
tbody:not(.lmc-tbody-head) tr td:first-of-type {
font-weight: bold;
text-align: right;
}

View File

@ -0,0 +1,496 @@
/*
* 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, apiGet, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.ipFailover = "ip-failover";
elements.ipRemove = "ip-remove";
elements.ipSwap = "ip-swap";
elements.ipv4Addrs = "ipv4-addrs";
elements.ipv4Gateways = "ipv4-gateways";
elements.linkLocal = "link-local";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.lishLink = "lish-link";
elements.privateIPGuide = "private-ips-guide";
elements.privateIPs = "private-ips";
elements.resolvers = "resolvers";
elements.slaacAddr = "slaac-addr";
elements.slaacGateway = "slaac-gateway";
elements.slaacPrefix = "slaac-prefix";
elements.slaacRdns = "slaac-rdns";
elements.sshLink = "ssh-link";
// Data recieved from API calls
var data = {};
data.linode = {};
data.netInfo = {};
// The Linode API does not supply resolvers, so they must be hard-coded
data.resolvers = {
"us-central": [
"173.255.199.5",
"66.228.53.5",
"96.126.122.5",
"96.126.124.5",
"96.126.127.5",
"198.58.107.5",
"198.58.111.5",
"23.239.24.5",
"2600:3c00::5",
"2600:3c00::6",
"2600:3c00::7",
"2600:3c00::8",
"2600:3c00::9",
"2600:3c00::b",
"2600:3c00::c"
],
"us-west": [
"173.230.145.5",
"173.230.147.5",
"173.230.155.5",
"173.255.212.5",
"173.255.219.5",
"173.255.241.5",
"173.255.243.5",
"173.255.244.5",
"2600:3c01::5",
"2600:3c01::6",
"2600:3c01::7",
"2600:3c01::8",
"2600:3c01::9",
"2600:3c01::b",
"2600:3c01::c"
],
"us-southeast": [
"173.230.129.5",
"173.230.136.5",
"173.230.140.5",
"66.228.59.5",
"66.228.62.5",
"50.116.35.5",
"50.116.41.5",
"23.239.18.5",
"2600:3c02::5",
"2600:3c02::6",
"2600:3c02::7",
"2600:3c02::8",
"2600:3c02::9",
"2600:3c02::b",
"2600:3c02::c"
],
"us-east": [
"66.228.42.5",
"96.126.106.5",
"50.116.53.5",
"50.116.58.5",
"50.116.61.5",
"50.116.62.5",
"66.175.211.5",
"2600:3c03::5",
"2600:3c03::6",
"2600:3c03::7",
"2600:3c03::8",
"2600:3c03::9",
"2600:3c03::b",
"2600:3c03::c"
],
"us-east-1b": [
"172.104.200.4",
"172.104.200.5",
"2400:8903::5",
"2400:8903::6",
"2400:8903::7",
"2400:8903::8",
"2400:8903::9",
"2400:8903::b",
"2400:8903::c"
],
"eu-west": [
"178.79.182.5",
"176.58.107.5",
"176.58.116.5",
"176.58.121.5",
"151.236.220.5",
"212.71.252.5",
"212.71.253.5",
"2a01:7e00::5",
"2a01:7e00::6",
"2a01:7e00::7",
"2a01:7e00::8",
"2a01:7e00::9",
"2a01:7e00::b",
"2a01:7e00::c"
],
"ap-south": [
"139.162.11.5",
"139.162.13.5",
"139.162.14.5",
"139.162.15.5",
"139.162.16.5",
"139.162.21.5",
"139.162.27.5",
"2400:8901::5",
"2400:8901::6",
"2400:8901::7",
"2400:8901::8",
"2400:8901::9",
"2400:8901::b",
"2400:8901::c"
],
"eu-central": [
"139.162.130.5",
"139.162.131.5",
"139.162.132.5",
"139.162.133.5",
"139.162.134.5",
"139.162.135.5",
"139.162.136.5",
"139.162.137.5",
"139.162.138.5",
"139.162.139.5",
"2a01:7e01::5",
"2a01:7e01::6",
"2a01:7e01::7",
"2a01:7e01::8",
"2a01:7e01::9",
"2a01:7e01::b",
"2a01:7e01::c"
],
"ap-northeast": [
"106.187.90.5",
"106.187.93.5",
"106.187.94.5",
"106.187.95.5",
"106.186.116.5",
"106.186.123.5",
"106.186.124.5",
"2400:8900::5",
"2400:8900::6",
"2400:8900::7",
"2400:8900::8",
"2400:8900::9",
"2400:8900::b",
"2400:8900::c"
],
"ap-northeast-1a": [
"139.162.66.5",
"139.162.67.5",
"139.162.68.5",
"139.162.69.5",
"139.162.70.5",
"139.162.71.5",
"139.162.72.5",
"139.162.73.5",
"139.162.74.5",
"139.162.75.5",
"2400:8902::5",
"2400:8902::6",
"2400:8902::7",
"2400:8902::8",
"2400:8902::9",
"2400:8902::b",
"2400:8902::c"
],
"ca-central": [
"172.105.0.5",
"172.105.3.5",
"172.105.4.5",
"172.105.5.5",
"172.105.6.5",
"172.105.7.5",
"172.105.8.5",
"172.105.9.5",
"172.105.10.5",
"172.105.11.5",
"2600:3C04::5",
"2600:3C04::6",
"2600:3C04::7",
"2600:3C04::8",
"2600:3C04::9",
"2600:3C04::b",
"2600:3C04::c"
],
"ap-west": [
"172.105.34.5",
"172.105.35.5",
"172.105.36.5",
"172.105.37.5",
"172.105.38.5",
"172.105.39.5",
"172.105.40.5",
"172.105.41.5",
"172.105.42.5",
"172.105.43.5",
"2400:8904::5",
"2400:8904::6",
"2400:8904::7",
"2400:8904::8",
"2400:8904::9",
"2400:8904::b",
"2400:8904::c"
],
"ap-southeast": [
"172.105.166.5",
"172.105.169.5",
"172.105.168.5",
"172.105.172.5",
"172.105.162.5",
"172.105.170.5",
"172.105.167.5",
"172.105.171.5",
"172.105.181.5",
"172.105.161.5",
"2400:8907::5",
"2400:8907::6",
"2400:8907::7",
"2400:8907::8",
"2400:8907::9",
"2400:8907::b",
"2400:8907::c"
],
"philadelphia": [
"100.90.80.253",
"2400:8906::5",
"2400:8906::6",
"2400:8906::7",
"2400:8906::8",
"2400:8906::9",
"2400:8906::b",
"2400:8906::c"
]
};
// LISH uses different DC names than the API uses, so we need to translate them
data.lishDCs = {
"us-central": "dallas",
"us-west": "fremont",
"us-southeast": "atlanta",
"us-east": "newark",
"us-east-1b": "cjj2",
"eu-west": "london",
"ap-south": "singapore",
"eu-central": "frankfurt",
"ap-northeast": "shg1",
"ap-northeast-1a": "shg1",
"ca-central": "tor1",
"ap-west": "mum1",
"ap-southeast": "syd1",
"philadelphia": "phl1"
};
// Static references to UI elements
var ui = {};
ui.ipFailover = {};
ui.ipRemove = {};
ui.ipSwap = {};
ui.ipv4Addrs = {};
ui.ipv4Gateways = {};
ui.linkLocal = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.lishLink = {};
ui.privateIPGuide = {};
ui.privateIPs = {};
ui.resolvers = {};
ui.slaacAddr = {};
ui.slaacGateway = {};
ui.slaacPrefix = {};
ui.slaacRdns = {};
ui.sshLink = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Replace user in SSH link if we're running CoreOS Container Linux
if (data.linode.image == "linode/containerlinux") {
ui.sshLink.href = ui.sshLink.href.replace("root", "core");
ui.sshLink.innerHTML = ui.sshLink.innerHTML.replace("root", "core");
}
// Get list of other instances in the same region
var filters = {
"region": data.linode.region
};
apiGet("/linode/instances", displayIPLinks, filters);
// Display resolvers
for (var i = 0; i < data.resolvers[data.linode.region].length; i++) {
var resolver = document.createElement("span");
resolver.innerHTML = data.resolvers[data.linode.region][i];
var br = document.createElement("br");
ui.resolvers.appendChild(resolver);
ui.resolvers.appendChild(br);
}
// Update the LISH link
ui.lishLink.href = ui.lishLink.href.replace("lish-", "lish-" + data.lishDCs[data.linode.region]);
ui.lishLink.innerHTML = ui.lishLink.innerHTML.replace("lish-", "lish-" + data.lishDCs[data.linode.region]);
ui.lishLink.innerHTML += " " + data.linode.label;
};
// Callback for regional instances API call
var displayIPLinks = function(response)
{
// Only enable IP failover and swap links if there are 2 or more instances in this location
if (response.data.length < 2)
return;
var ipFailover = document.createElement("a");
ipFailover.href = "/linodes/ip_failover?lid=" + data.params.lid;
ipFailover.innerHTML = "IP Failover";
ui.ipFailover.replaceWith(ipFailover);
var ipSwap = document.createElement("a");
ipSwap.href = "/linodes/ip_swap?lid=" + data.params.lid;
ipSwap.innerHTML = "IP Swap";
ui.ipSwap.replaceWith(ipSwap);
};
// Callback for user info API call
var displayLishUser = function(response)
{
// Insert username into LISH link
ui.lishLink.href = ui.lishLink.href.replace("@", response.username + "@");
ui.lishLink.innerHTML = ui.lishLink.innerHTML.replace("@", response.username + "@");
};
// Callback for network info API call
var displayNetInfo = function(response)
{
data.netInfo = response;
// Set SSH link
// CoreOS Container Linux uses core instead of root
var user = "root";
if (data.linode && data.linode.image == "linode/containerlinux")
user = "core";
if (data.netInfo.ipv4["public"].length > 0) {
ui.sshLink.href = "ssh://" + user + "@" + data.netInfo.ipv4["public"][0].address;
ui.sshLink.innerHTML = "ssh " + user + "@" + data.netInfo.ipv4["public"][0].address;
}
// Show public IPv4 info
for (var i = 0; i < data.netInfo.ipv4["public"].length; i++) {
var ipinfo = document.createElement("span");
ipinfo.innerHTML = data.netInfo.ipv4["public"][i].address + " / " + data.netInfo.ipv4["public"][i].prefix + " ( " + data.netInfo.ipv4["public"][i].rdns + " )";
var gateway = document.createElement("span");
gateway.innerHTML = data.netInfo.ipv4["public"][i].gateway;
var br = document.createElement("br");
ui.ipv4Addrs.appendChild(ipinfo);
ui.ipv4Addrs.appendChild(br);
ui.ipv4Gateways.appendChild(gateway);
ui.ipv4Gateways.appendChild(br.cloneNode(false));
}
// Show public IPv6 info
ui.slaacAddr.innerHTML = data.netInfo.ipv6.slaac.address;
ui.slaacGateway.innerHTML = data.netInfo.ipv6.slaac.gateway;
ui.slaacPrefix.innerHTML = data.netInfo.ipv6.slaac.prefix;
ui.slaacRdns.innerHTML = data.netInfo.ipv6.slaac.rdns;
// Enable IP remove link if multiple IPv4s
if (data.netInfo.ipv4["public"].length > 1) {
var ipRemove = document.createElement("a");
ipRemove.href = "/linodes/ip_remove?lid=" + data.params.lid;
ipRemove.innerHTML = "IP Remove";
ui.ipRemove.replaceWith(ipRemove);
}
// Display private IP info
if (data.netInfo.ipv4["private"].length > 0) {
ui.privateIPs.innerHTML = "";
ui.privateIPGuide.style.visibility = "visible";
}
for (var i = 0; i < data.netInfo.ipv4["private"].length; i++) {
var ip = document.createElement("span");
ip.innerHTML = data.netInfo.ipv4["private"][i].address + " / " + data.netInfo.ipv4["private"][i].prefix;
var br = document.createElement("br");
ui.privateIPs.appendChild(ip);
ui.privateIPs.appendChild(br);
}
// Display link-local IPv6 address
ui.linkLocal.innerHTML = data.netInfo.ipv6.link_local.address + " / " + data.netInfo.ipv6.link_local.prefix;
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=00", data.params.lid);
anchors[i].href = anchors[i].href.replace("lid=0", "lid=" + data.params.lid);
}
// Get element references
ui.ipFailover = document.getElementById(elements.ipFailover);
ui.ipRemove = document.getElementById(elements.ipRemove);
ui.ipSwap = document.getElementById(elements.ipSwap);
ui.ipv4Addrs = document.getElementById(elements.ipv4Addrs);
ui.ipv4Gateways = document.getElementById(elements.ipv4Gateways);
ui.linkLocal = document.getElementById(elements.linkLocal);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.lishLink = document.getElementById(elements.lishLink);
ui.privateIPGuide = document.getElementById(elements.privateIPGuide);
ui.privateIPs = document.getElementById(elements.privateIPs);
ui.resolvers = document.getElementById(elements.resolvers);
ui.slaacAddr = document.getElementById(elements.slaacAddr);
ui.slaacGateway = document.getElementById(elements.slaacGateway);
ui.slaacPrefix = document.getElementById(elements.slaacPrefix);
ui.slaacRdns = document.getElementById(elements.slaacRdns);
ui.sshLink = document.getElementById(elements.sshLink);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/ips", displayNetInfo, null);
apiGet("/profile", displayLishUser, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,38 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Remove</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="remove.css" />
<script src="remove.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Edit Disk</span></div>
<div id="remove">
<p id="confirm-warning" class="warning">You must confirm that you want to remove this Linode.</p>
<p>Are you sure you want to remove the "<span id="label"></span>" Linode from your account?</p>
<input id="confirm" type="checkbox" /><label for="confirm">Yes, remove this Linode from my account.</label><br />
<button disabled id="remove-button" type="button">Remove this Linode</button>
</div>
</div>
</body>
</html>

34
linodes/remove/remove.css Normal file
View File

@ -0,0 +1,34 @@
/*
* 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 url('/global.css');
button {
margin-top: 10px;
}
#confirm-warning {
display: none;
}
#label {
font-weight: bold;
}
#remove {
padding: 0px 15px 15px;
}

125
linodes/remove/remove.js Normal file
View File

@ -0,0 +1,125 @@
/*
* 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, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.confirm = "confirm";
elements.confirmWarning = "confirm-warning";
elements.label = "label";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.removeButton = "remove-button";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.confirm = {};
ui.confirmWarning = {};
ui.label = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.removeButton = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
ui.label.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
ui.removeButton.disabled = false;
};
// Remove button handler
var handleRemove = function(event)
{
if (event.currentTarget.disabled)
return;
if (!ui.confirm.checked) {
ui.confirmWarning.style.display = "block";
return;
}
apiDelete("/linode/instances/" + data.params.lid, function(response){
location.href = "/linodes";
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=00", data.params.lid);
anchors[i].href = anchors[i].href.replace("lid=0", "lid=" + data.params.lid);
}
// Highlight the dashboard subnav link
var subnavLinks = document.getElementsByClassName(elements.subnav);
for (var i = 0; i < subnavLinks.length; i++) {
if (subnavLinks[i].pathname == "/linodes/dashboard")
subnavLinks[i].className += " " + elements.subnavActive;
}
// Get element references
ui.confirm = document.getElementById(elements.confirm);
ui.confirmWarning = document.getElementById(elements.confirmWarning);
ui.label = document.getElementById(elements.label);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.removeButton = document.getElementById(elements.removeButton);
// Register event handlers
ui.removeButton.addEventListener("click", handleRemove);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

158
linodes/rescue/index.shtml Normal file
View File

@ -0,0 +1,158 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Rescue</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="rescue.css" />
<script src="rescue.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Rescue</span></div>
<div id="rescue">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Rescue Mode</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td></td>
<td>Boots your Linode into Rescue Mode. Access it via the console.</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sda</td>
<td>
<select id="sda" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdb</td>
<td>
<select id="sdb" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdc</td>
<td>
<select id="sdc" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdd</td>
<td>
<select id="sdd" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sde</td>
<td>
<select id="sde" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdf</td>
<td>
<select id="sdf" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdg</td>
<td>
<select id="sdg" class="drive">
<option selected value="0">-- None --</option>
<optgroup class="disks" label="Disks"></optgroup>
<optgroup class="volumes" label="Volumes"></optgroup>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td>/dev/sdh</td>
<td>Finnix Media</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="rescue-button" type="button">Reboot into Rescue Mode</button></td>
<td></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr>
<td colspan="3">Reset Root Password</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Filesystem</td>
<td><select id="filesystems"></select></td>
<td><span class="info">Linode must be shut down</span></td>
</tr>
<tr class="lmc-tr3">
<td>New Password</td>
<td><input id="root-pass" type="password" /></td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td><button disabled id="reset-button" type="button">Reset Root Password</button></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

35
linodes/rescue/rescue.css Normal file
View File

@ -0,0 +1,35 @@
/*
* 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 url('/global.css');
#rescue {
padding: 0px 15px 15px;
}
#rescue-button {
margin-bottom: 30px;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}
tbody:not(.lmc-tbody-head) tr td:first-of-type {
font-weight: bold;
text-align: right;
}

268
linodes/rescue/rescue.js Normal file
View File

@ -0,0 +1,268 @@
/*
* 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, apiGet, apiPost, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.disks = "disks";
elements.drive = "drive";
elements.filesystems = "filesystems";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.rescueButton = "rescue-button";
elements.resetButton = "reset-button";
elements.rootPass = "root-pass";
elements.sda = "sda";
elements.sdb = "sdb";
elements.sdc = "sdc";
elements.sdd = "sdd";
elements.sde = "sde";
elements.sdf = "sdf";
elements.sdg = "sdg";
elements.volumes = "volumes";
// Data received from API calls
var data = {};
data.disks = [];
data.linode = {};
data.volumes = [];
// Static references to UI elements
var ui = {};
ui.disks = [];
ui.drive = [];
ui.filesystems = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.rescueButton = {};
ui.resetButton = {};
ui.rootPass = {};
ui.sda = {};
ui.sdb = {};
ui.sdc = {};
ui.sdd = {};
ui.sde = {};
ui.sdf = {};
ui.sdg = {};
ui.volumes = [];
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
} else {
ui.linodeTag.style.display = "none";
}
// Get list of volumes
apiGet("/volumes", displayVolumes, null);
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Add disks to drive lists, and disks with filesystems to filesystems list
for (var i = 0; i < data.disks.length; i++) {
var disk = document.createElement("option");
disk.value = "disk-" + data.disks[i].id;
disk.innerHTML = data.disks[i].label;
for (var j = 0; j < ui.disks.length; j++)
ui.disks[j].appendChild(disk.cloneNode(true));
if (data.disks[i].filesystem.match(/ext3|ext4/))
ui.filesystems.appendChild(disk.cloneNode(true));
}
// Preset value of drive lists
for (var i = 0; i < data.disks.length && i < ui.drive.length; i++)
ui.drive[i].value = "disk-" + data.disks[i].id;
if (ui.filesystems.childNodes.length > 0)
ui.resetButton.disabled = false;
};
// Callback for volumes API call
var displayVolumes = function(response)
{
// Add volumes to array
data.volumes = data.volumes.concat(response.data);
// Request the next page if there are more
if (response.page != response.pages) {
apiGet("/volumes?page=" + (response.page + 1), displayVolumes, null);
return;
}
// Add volumes from this Linode's region to drive lists
for (var i = 0; i < data.volumes.length; i++) {
if (data.volumes[i].region != data.linode.region)
continue;
var volume = document.createElement("option");
volume.value = "volume-" + data.volumes[i].id;
volume.innerHTML = data.volumes[i].label;
for (var j = 0; j < ui.volumes.length; j++)
ui.volumes[j].appendChild(volume.cloneNode(true));
}
ui.rescueButton.disabled = false;
};
// Rescue button handler
var handleRescue = function(event)
{
if (event.currentTarget.disabled)
return;
var request = {
"devices": {}
};
if (ui.sda.value.startsWith("disk-"))
request.devices.sda = { "disk_id": parseInt(ui.sda.value.split("-")[1]) };
else if (ui.sda.value.startsWith("volume-"))
request.devices.sda = { "volume_id": parseInt(ui.sda.value.split("-")[1]) };
if (ui.sdb.value.startsWith("disk-"))
request.devices.sdb = { "disk_id": parseInt(ui.sdb.value.split("-")[1]) };
else if (ui.sdb.value.startsWith("volume-"))
request.devices.sdb = { "volume_id": parseInt(ui.sdb.value.split("-")[1]) };
if (ui.sdc.value.startsWith("disk-"))
request.devices.sdc = { "disk_id": parseInt(ui.sdc.value.split("-")[1]) };
else if (ui.sdc.value.startsWith("volume-"))
request.devices.sdc = { "volume_id": parseInt(ui.sdc.value.split("-")[1]) };
if (ui.sdd.value.startsWith("disk-"))
request.devices.sdd = { "disk_id": parseInt(ui.sdd.value.split("-")[1]) };
else if (ui.sdd.value.startsWith("volume-"))
request.devices.sdd = { "volume_id": parseInt(ui.sdd.value.split("-")[1]) };
if (ui.sde.value.startsWith("disk-"))
request.devices.sde = { "disk_id": parseInt(ui.sde.value.split("-")[1]) };
else if (ui.sde.value.startsWith("volume-"))
request.devices.sde = { "volume_id": parseInt(ui.sde.value.split("-")[1]) };
if (ui.sdf.value.startsWith("disk-"))
request.devices.sdf = { "disk_id": parseInt(ui.sdf.value.split("-")[1]) };
else if (ui.sdf.value.startsWith("volume-"))
request.devices.sdf = { "volume_id": parseInt(ui.sdf.value.split("-")[1]) };
if (ui.sdg.value.startsWith("disk-"))
request.devices.sdg = { "disk_id": parseInt(ui.sdg.value.split("-")[1]) };
else if (ui.sdg.value.startsWith("volume-"))
request.devices.sdg = { "volume_id": parseInt(ui.sdg.value.split("-")[1]) };
apiPost("/linode/instances/" + data.params.lid + "/rescue", request, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Reset button handler
var handleReset = function(event)
{
if (event.currentTarget.disabled)
return;
if (ui.rootPass.value.length == 0) {
alert("You must supply a root password.");
return;
}
var request = {
"password": ui.rootPass.value
};
apiPost("/linode/instances/" + data.params.lid + "/disks/" + ui.filesystems.value.split("-")[1] + "/password", request, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.disks = document.getElementsByClassName(elements.disks);
ui.drive = document.getElementsByClassName(elements.drive);
ui.filesystems = document.getElementById(elements.filesystems);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.rescueButton = document.getElementById(elements.rescueButton);
ui.resetButton = document.getElementById(elements.resetButton);
ui.rootPass = document.getElementById(elements.rootPass);
ui.sda = document.getElementById(elements.sda);
ui.sdb = document.getElementById(elements.sdb);
ui.sdc = document.getElementById(elements.sdc);
ui.sdd = document.getElementById(elements.sdd);
ui.sde = document.getElementById(elements.sde);
ui.sdf = document.getElementById(elements.sdf);
ui.sdg = document.getElementById(elements.sdg);
ui.volumes = document.getElementsByClassName(elements.volumes);
// Register button handlers
ui.rescueButton.addEventListener("click", handleRescue);
ui.resetButton.addEventListener("click", handleReset);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,93 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Resize</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="resize.css" />
<script src="resize.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Resize</span></div>
<div id="resize">
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Resize</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr1">
<td colspan="3"><h2>Choose your new plan</h2></td>
</tr>
<tr class="lmc-tr1">
<td>
<h3>Nanode</h3>
<div id="nanode"></div>
<br />
<h3>Standard</h3>
<div id="standard"></div>
</td>
<td>
<h3>Dedicated CPU</h3>
<div id="dedicated"></div>
<br />
<h3>High Memory</h3>
<div id="highmem"></div>
<br />
<h3>Dedicated GPU</h3>
<div id="gpu"></div>
</td>
<td>
<h2>How it works</h2>
<ol>
<li>
<strong>Linode is shut down and migrated</strong><br />
You will experience downtime while your Linode is migrated. It will take about <span id="eta"></span> to migrate your Linode, but that may vary based on host and network load.
</li>
<li>
<strong>Billing</strong><br />
The resized Linode will be billed at the hourly rate of the new Linode plan going forward.
</li>
<li>
<strong>Enjoyment</strong><br />
After the migration completes, you can take advantage of the new resources by resizing your disks.
</li>
</ol>
</td>
</tr>
<tr class="lmc-tr1">
<td colspan="3">
<div id="auto-resize">
<input disabled id="auto-resize-box" type="checkbox" />
<label for="auto-resize-box">Automatically resize disk "<span id="disk-name"></span>"</label>
</div>
<button disabled id="resize-button" type="button">Resize this Linode Now!</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

64
linodes/resize/resize.css Normal file
View File

@ -0,0 +1,64 @@
/*
* 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 url('/global.css');
#auto-resize {
display: none;
margin-bottom: 5px;
}
.current {
text-decoration: line-through;
}
div {
font-size: 14px;
}
#eta {
font-weight: bold;
}
h2 {
margin: 0px;
}
h3 {
margin: 0px;
}
li {
margin-bottom: 15px;
}
.lmc-table td {
vertical-align: top;
width: 25%;
}
.lmc-table td:last-child {
width: 50%;
}
ol {
font-size: 14px;
}
#resize {
padding: 0px 15px 15px;
}

250
linodes/resize/resize.js Normal file
View File

@ -0,0 +1,250 @@
/*
* 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, apiGet, apiPost, migrateETA, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.autoResize = "auto-resize";
elements.autoResizeBox = "auto-resize-box";
elements.current = "current";
elements.dedicated = "dedicated";
elements.diskName = "disk-name";
elements.eta = "eta";
elements.gpu = "gpu";
elements.instanceType = "instance-type";
elements.highmem = "highmem";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.nanode = "nanode";
elements.resizeButton = "resize-button";
elements.standard = "standard";
// Data received from API calls
var data = {};
data.disks = [];
data.linode = {};
data.types = [];
// Static references to UI elements
var ui = {};
ui.autoResize = {};
ui.autoResizeBox = {};
ui.dedicated = {};
ui.diskName = {};
ui.eta = {};
ui.gpu = {};
ui.highmem = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.nanode = {};
ui.resizeButton = {};
ui.standard = {};
// Creates a Linode type radio button and label
var createTypeButton = function(type)
{
// Radio button
var radio = document.createElement("input");
radio.id = type.id;
radio.type = "radio";
radio["name"] = elements.instanceType;
radio.value = type.id;
// Label
var label = document.createElement("label");
label.htmlFor = type.id;
label.innerHTML = type.label;
// Text to display next to current plan
var current = document.createElement("span");
current.innerHTML = " (current plan)";
var br = document.createElement("br");
// Insert elements
ui[type["class"]].appendChild(radio);
ui[type["class"]].appendChild(label);
if (type.id == data.linode.type) {
radio.disabled = true;
label.className = elements.current;
ui[type["class"]].appendChild(current);
}
ui[type["class"]].appendChild(br);
};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
} else {
ui.linodeTag.style.display = "none";
}
// Get linode types
apiGet("/linode/types", displayTypes, null);
};
// Callback for linode disks API call
var displayDisks = function(response)
{
// Add disks to array
data.disks = data.disks.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/instances/" + data.params.lid + "/disks?page=" + (response.page + 1), displayDisks, null);
return;
}
// Compute total size and types of disks
var size = 0;
var numExt = 0;
var numSwap = 0;
for (var i = 0; i < data.disks.length; i++) {
size += data.disks[i].size;
if (data.disks[i].filesystem.match(/ext3|ext4/)) {
numExt++;
ui.diskName.innerHTML = data.disks[i].label;
}
else if (data.disks[i].filesystem == "swap")
numSwap++;
}
// Compute estimated resize time
ui.eta.innerHTML = migrateETA(size, true);
// Show auto-resize option if there is only a single ext disk
if ((data.disks.length == 1 && numExt == 1) || (data.disks.length == 2 && numExt == 1 && numSwap == 1)) {
ui.autoResizeBox.disabled = false;
ui.autoResizeBox.checked = true;
ui.autoResize.style.display = "block";
}
};
// Callback for linode types API call
var displayTypes = function(response)
{
// Add types to array
data.types = data.types.concat(response.data);
// Request the next page if there are more pages
if (response.page != response.pages) {
apiGet("/linode/types?page=" + (response.page + 1), displayTypes, null);
return;
}
// Insert types
for (var i = 0; i < data.types.length; i++)
createTypeButton(data.types[i]);
ui.resizeButton.disabled = false;
};
// Resize button handler
var handleResize = function(event)
{
if (event.currentTarget.disabled)
return;
// Find the selected type
var type = null;
var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
if (inputs[i]["name"] == elements.instanceType && inputs[i].checked) {
type = inputs[i];
break;
}
}
if (!type) {
alert("You must choose a new plan.");
return;
}
if (!confirm("Immediately shut down, migrate your Linode, and invoice this account for the difference?"))
return;
var request = {
"type": type.id,
"allow_auto_disk_resize": (!ui.autoResizeBox.disabled && ui.autoResizeBox.checked)
};
apiPost("/linode/instances/" + data.params.lid + "/resize", request, function(response)
{
location.href = "/linodes/dashboard?lid=" + data.params.lid;
});
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.autoResize = document.getElementById(elements.autoResize);
ui.autoResizeBox = document.getElementById(elements.autoResizeBox);
ui.dedicated = document.getElementById(elements.dedicated);
ui.diskName = document.getElementById(elements.diskName);
ui.eta = document.getElementById(elements.eta);
ui.gpu = document.getElementById(elements.gpu);
ui.highmem = document.getElementById(elements.highmem);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.nanode = document.getElementById(elements.nanode);
ui.resizeButton = document.getElementById(elements.resizeButton);
ui.standard = document.getElementById(elements.standard);
// Register resize button handler
ui.resizeButton.addEventListener("click", handleResize);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
apiGet("/linode/instances/" + data.params.lid + "/disks", displayDisks, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();

View File

@ -0,0 +1,140 @@
<!--
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/>.
-->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LMC - Settings</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" href="settings.css" />
<script src="settings.js" type="module"></script>
</head>
<body>
<!--#include virtual="/include/header.html"-->
<!--#include virtual="/include/linode_subnav.html"-->
<div id="main-content" class="wrapper">
<div id="top-links"><a href="/linodes">Linodes</a> » <span id="linode-tag"><a id="linode-tag-link" href=""></a> » </span><a id="linode-label" href="/linodes/dashboard?lid=0"></a> » <span class="top-links-title">Settings</span></div>
<div id="settings">
<p id="lassie-saved" class="saved-message">Lassie setting saved.</p>
<p id="alerts-saved" class="saved-message">Alert settings saved.</p>
<table class="lmc-table">
<thead>
<tr>
<td colspan="3">Settings</td>
</tr>
<tr>
<td colspan="3">Display Settings</td>
</tr>
</thead>
<tbody>
<tr class="lmc-tr3">
<td>Linode Label</td>
<td><input id="label" type="text" /></td>
<td class="info">Rename your Linode</td>
</tr>
<tr class="lmc-tr3">
<td>Tags</td>
<td><input id="tags" type="text" /> (comma-separated)</td>
<td class="info">Group Linodes together on the Linodes tab using tags!</td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td colspan="2"><button disabled id="save-display" type="button">Save Changes</button></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Shutdown Watchdog</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Description</td>
<td colspan="2">
Lassie is a Shutdown Watchdog that monitors your Linode and will reboot it if it powers off unexpectedly. It works by issuing a boot job when your Linode powers off without a shutdown job being responsible.<br />
<span class="info">To prevent a boot loop, Lassie will give up if there have been more than 5 boot jobs issued within 15 minutes.</span>
</td>
</tr>
<tr class="lmc-tr3">
<td>Lassie is currently</td>
<td>
<select id="lassie">
<option value="enabled">Enabled</option>
<option value="disabled">Disabled</option>
</select>
</td>
<td></td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td colspan="2"><button disabled id="save-lassie" type="button">Save Changes</button></td>
</tr>
</tbody>
<tbody class="lmc-tbody-head">
<tr class="noshow">
<td colspan="3"></td>
</tr>
<tr>
<td colspan="3">Email Alert Thresholds</td>
</tr>
</tbody>
<tbody>
<tr class="lmc-tr3">
<td>Description</td>
<td colspan="2">
When an alert threshold is reached, an email is sent to all users that have "read" permissions on this Linode.<br />
<span class="info">Thresholds are compared to values once per hour, 15 minutes after the hour.</span>
</td>
</tr>
<tr class="lmc-tr3">
<td>CPU Usage</td>
<td><label for="cpu-enabled">Enabled</label><input id="cpu-enabled" type="checkbox" /> | <input id="cpu-value" type="number" min="0" max="100" /> %</td>
<td class="info">Average CPU usage over 2 hours exceeding this value triggers this alert.</td>
</tr>
<tr class="lmc-tr3">
<td>Disk IO Rate</td>
<td><label for="io-enabled">Enabled</label><input id="io-enabled" type="checkbox" /> | <input id="io-value" type="number" min="0" /> IO Ops/sec</td>
<td class="info">Average Disk IO ops/sec over 2 hours exceeding this value triggers this alert.</td>
</tr>
<tr class="lmc-tr3">
<td>Incoming Traffic</td>
<td><label for="incoming-enabled">Enabled</label><input id="incoming-enabled" type="checkbox" /> | <input id="incoming-value" type="number" min="0" /> Mbit/s</td>
<td class="info">Average incoming traffic over a 2 hour period exceeding this value triggers this alert.</td>
</tr>
<tr class="lmc-tr3">
<td>Outbound Traffic</td>
<td><label for="outbound-enabled">Enabled</label><input id="outbound-enabled" type="checkbox" /> | <input id="outbound-value" type="number" min="0" /> Mbit/s</td>
<td class="info">Average outbound traffic over a 2 hour period exceeding this value triggers this alert.</td>
</tr>
<tr class="lmc-tr3">
<td>Transfer Quota</td>
<td><label for="transfer-enabled">Enabled</label><input id="transfer-enabled" type="checkbox" /> | <input id="transfer-value" type="number" min="0" max="100" /> %</td>
<td class="info">Percentage of network transfer quota used being greater than this value will trigger this alert.</td>
</tr>
<tr class="lmc-tr3">
<td></td>
<td colspan="2"><button disabled id="save-alerts" type="button">Save Changes</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,44 @@
/*
* 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 url('/global.css');
input[type="number"] {
width: 60px;
}
.saved-message {
background-color: #ADD370;
display: none;
font-size: 16px;
margin-top: 0;
padding: 7px;
}
#settings {
padding: 0px 15px 15px;
}
tbody:not(.lmc-tbody-head) tr td:first-of-type {
font-weight: bold;
text-align: right;
white-space: nowrap;
}
tbody:not(.lmc-tbody-head) tr:last-of-type {
border: none;
}

View File

@ -0,0 +1,238 @@
/*
* 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, apiGet, apiPut, parseParams, setupHeader } from "/global.js";
(function()
{
// Element names specific to this page
elements.alertsSaved = "alerts-saved";
elements.cpuEnabled = "cpu-enabled";
elements.cpuValue = "cpu-value";
elements.incomingEnabled = "incoming-enabled";
elements.incomingValue = "incoming-value";
elements.ioEnabled = "io-enabled";
elements.ioValue = "io-value";
elements.label = "label";
elements.lassie = "lassie";
elements.lassieSaved = "lassie-saved";
elements.linodeLabel = "linode-label";
elements.linodeTag = "linode-tag";
elements.linodeTagLink = "linode-tag-link";
elements.outboundEnabled = "outbound-enabled";
elements.outboundValue = "outbound-value";
elements.saveAlerts = "save-alerts";
elements.saveDisplay = "save-display";
elements.saveLassie = "save-lassie";
elements.tags = "tags";
elements.transferEnabled = "transfer-enabled";
elements.transferValue = "transfer-value";
// Data recieved from API calls
var data = {};
data.linode = {};
// Static references to UI elements
var ui = {};
ui.alertsSaved = {};
ui.cpuEnabled = {};
ui.cpuValue = {};
ui.incomingEnabled = {};
ui.incomingValue = {};
ui.ioEnabled = {};
ui.ioValue = {};
ui.label = {};
ui.lassie = {};
ui.lassieSaved = {};
ui.linodeLabel = {};
ui.linodeTag = {};
ui.linodeTagLink = {};
ui.outboundEnabled = {};
ui.outboundValue = {};
ui.saveAlerts = {};
ui.saveDisplay = {};
ui.saveLassie = {};
ui.tags = {};
ui.transferEnabled = {};
ui.transferValue = {};
// Callback for linode details API call
var displayDetails = function(response)
{
data.linode = response;
// Set page title and header stuff
document.title += " // " + data.linode.label;
ui.linodeLabel.innerHTML = data.linode.label;
if (data.linode.tags.length == 1) {
ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0];
ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")";
ui.linodeTag.style.display = "inline";
}
// Fill in values
ui.label.value = data.linode.label;
ui.tags.value = data.linode.tags.join(",");
ui.saveDisplay.disabled = false;
if (data.linode.watchdog_enabled)
ui.lassie.value = "enabled";
else
ui.lassie.value = "disabled";
ui.saveLassie.disabled = false;
ui.cpuEnabled.checked = data.linode.alerts.cpu;
ui.cpuValue.value = data.linode.alerts.cpu;
ui.ioEnabled.checked = data.linode.alerts.io;
ui.ioValue.value = data.linode.alerts.io;
ui.incomingEnabled.checked = data.linode.alerts.network_in;
ui.incomingValue.value = data.linode.alerts.network_in;
ui.outboundEnabled.checked = data.linode.alerts.network_out;
ui.outboundValue.value = data.linode.alerts.network_out;
ui.transferEnabled.checked = data.linode.alerts.transfer_quota;
ui.transferValue.value = data.linode.alerts.transfer_quota;
ui.saveAlerts.disabled = false;
};
// Handler for alert settings save
var handleSaveAlerts = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"alerts": {
"cpu": parseInt(ui.cpuValue.value),
"io": parseInt(ui.ioValue.value),
"network_in": parseInt(ui.incomingValue.value),
"network_out": parseInt(ui.outboundValue.value),
"transfer_quota": parseInt(ui.transferValue.value)
}
};
// Set values to 0 if not enabled
if (!ui.cpuEnabled.checked)
req.alerts.cpu = 0;
if (!ui.ioEnabled.checked)
req.alerts.io = 0;
if (!ui.incomingEnabled.checked)
req.alerts.network_in = 0;
if (!ui.outboundEnabled.checked)
req.alerts.network_out = 0;
if (!ui.transferEnabled.checked)
req.alerts.transfer_quota = 0;
var callback = function(response)
{
ui.alertsSaved.style.display = "block";
};
apiPut("/linode/instances/" + data.params.lid, req, callback);
};
// Handler for display settings save
var handleSaveDisplay = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"label": ui.label.value,
"tags": []
};
if (ui.tags.value.length)
req.tags = ui.tags.value.split(",");
var callback = function(response)
{
location.reload();
};
apiPut("/linode/instances/" + data.params.lid, req, callback);
};
// Handler for Lassie settings save
var handleSaveLassie = function(event)
{
if (event.currentTarget.disabled)
return;
var req = {
"watchdog_enabled": (ui.lassie.value == "enabled")
};
var callback = function(response)
{
ui.lassieSaved.style.display = "block";
};
apiPut("/linode/instances/" + data.params.lid, req, callback);
};
// Initial setup
var setup = function()
{
// Parse URL parameters
data.params = parseParams();
// We need a Linode ID, so die if we don't have it
if (!data.params.lid) {
alert("No Linode 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("lid=0", "lid=" + data.params.lid);
// Get element references
ui.alertsSaved = document.getElementById(elements.alertsSaved);
ui.cpuEnabled = document.getElementById(elements.cpuEnabled);
ui.cpuValue = document.getElementById(elements.cpuValue);
ui.incomingEnabled = document.getElementById(elements.incomingEnabled);
ui.incomingValue = document.getElementById(elements.incomingValue);
ui.ioEnabled = document.getElementById(elements.ioEnabled);
ui.ioValue = document.getElementById(elements.ioValue);
ui.label = document.getElementById(elements.label);
ui.lassie = document.getElementById(elements.lassie);
ui.lassieSaved = document.getElementById(elements.lassieSaved);
ui.linodeLabel = document.getElementById(elements.linodeLabel);
ui.linodeTag = document.getElementById(elements.linodeTag);
ui.linodeTagLink = document.getElementById(elements.linodeTagLink);
ui.outboundEnabled = document.getElementById(elements.outboundEnabled);
ui.outboundValue = document.getElementById(elements.outboundValue);
ui.saveAlerts = document.getElementById(elements.saveAlerts);
ui.saveDisplay = document.getElementById(elements.saveDisplay);
ui.saveLassie = document.getElementById(elements.saveLassie);
ui.tags = document.getElementById(elements.tags);
ui.transferEnabled = document.getElementById(elements.transferEnabled);
ui.transferValue = document.getElementById(elements.transferValue);
// Attach event handlers
ui.saveAlerts.addEventListener("click", handleSaveAlerts);
ui.saveDisplay.addEventListener("click", handleSaveDisplay);
ui.saveLassie.addEventListener("click", handleSaveLassie);
// Get data from API
apiGet("/linode/instances/" + data.params.lid, displayDetails, null);
};
// Attach onload handler
window.addEventListener("load", setup);
})();