From 1ffa87a9800f87232ade7f6f6c04b1c343bbcb9a Mon Sep 17 00:00:00 2001 From: "L. Bradley LaBoon" Date: Sat, 18 Jan 2020 17:50:00 -0500 Subject: [PATCH] Added all DNS functionality --- dns/dns.css | 26 ++ dns/dns.js | 225 ++++++++++++ dns/domain/domain.css | 44 +++ dns/domain/domain.js | 450 ++++++++++++++++++++++++ dns/domain/index.shtml | 204 +++++++++++ dns/domain_add/domain_add.css | 43 +++ dns/domain_add/domain_add.js | 243 +++++++++++++ dns/domain_add/index.shtml | 91 +++++ dns/domain_clone/domain_clone.css | 31 ++ dns/domain_clone/domain_clone.js | 95 +++++ dns/domain_clone/index.shtml | 55 +++ dns/domain_delete/domain_delete.css | 26 ++ dns/domain_delete/domain_delete.js | 87 +++++ dns/domain_delete/index.shtml | 36 ++ dns/domain_import/domain_import.css | 36 ++ dns/domain_import/domain_import.js | 72 ++++ dns/domain_import/index.shtml | 56 +++ dns/domain_soa/domain_soa.css | 32 ++ dns/domain_soa/domain_soa.js | 164 +++++++++ dns/domain_soa/index.shtml | 165 +++++++++ dns/index.shtml | 34 ++ dns/resource/index.shtml | 226 ++++++++++++ dns/resource/resource.css | 36 ++ dns/resource/resource.js | 315 +++++++++++++++++ dns/resource_delete/index.shtml | 36 ++ dns/resource_delete/resource_delete.css | 22 ++ dns/resource_delete/resource_delete.js | 121 +++++++ global.css | 4 + linodes/linodes.js | 6 +- 29 files changed, 2980 insertions(+), 1 deletion(-) create mode 100644 dns/dns.css create mode 100644 dns/dns.js create mode 100644 dns/domain/domain.css create mode 100644 dns/domain/domain.js create mode 100644 dns/domain/index.shtml create mode 100644 dns/domain_add/domain_add.css create mode 100644 dns/domain_add/domain_add.js create mode 100644 dns/domain_add/index.shtml create mode 100644 dns/domain_clone/domain_clone.css create mode 100644 dns/domain_clone/domain_clone.js create mode 100644 dns/domain_clone/index.shtml create mode 100644 dns/domain_delete/domain_delete.css create mode 100644 dns/domain_delete/domain_delete.js create mode 100644 dns/domain_delete/index.shtml create mode 100644 dns/domain_import/domain_import.css create mode 100644 dns/domain_import/domain_import.js create mode 100644 dns/domain_import/index.shtml create mode 100644 dns/domain_soa/domain_soa.css create mode 100644 dns/domain_soa/domain_soa.js create mode 100644 dns/domain_soa/index.shtml create mode 100644 dns/index.shtml create mode 100644 dns/resource/index.shtml create mode 100644 dns/resource/resource.css create mode 100644 dns/resource/resource.js create mode 100644 dns/resource_delete/index.shtml create mode 100644 dns/resource_delete/resource_delete.css create mode 100644 dns/resource_delete/resource_delete.js diff --git a/dns/dns.css b/dns/dns.css new file mode 100644 index 0000000..c6ee82d --- /dev/null +++ b/dns/dns.css @@ -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 . + */ + +@import url('/global.css'); + +.center-cell { + text-align: center; +} + +#domains { + padding: 15px; +} diff --git a/dns/dns.js b/dns/dns.js new file mode 100644 index 0000000..dca48c2 --- /dev/null +++ b/dns/dns.js @@ -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 . + */ + +import { settings, elements, apiGet, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.centerCell = "center-cell"; + elements.domains = "domains"; + elements.domainTagPrefix = "domain-tag-"; + elements.lmcRow = "lmc-tr1"; + elements.lmcRowAlt = "lmc-tr2"; + elements.lmcTable = "lmc-table"; + elements.loading = "loading"; + elements.sublinks = "sub-links"; + + // Data recieved from API calls + var data = {}; + data.domains = []; + data.domainTags = []; + data.noTag = false; + + // Static references to UI elements + var ui = {}; + ui.domains = {}; + ui.domainTables = {}; + ui.loading = {}; + + var createDomainRow = function(domain, 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 = "/dns/domain?did=" + domain.id; + nameLink.innerHTML = domain.domain; + name.appendChild(nameLink); + row.appendChild(name); + + var type = document.createElement("td"); + type.innerHTML = domain.type; + row.appendChild(type); + + var email = document.createElement("td"); + email.innerHTML = domain.soa_email; + row.appendChild(email); + + var status = document.createElement("td"); + status.innerHTML = domain.status.charAt(0).toUpperCase() + domain.status.slice(1).replace(/_/g, " "); + row.appendChild(status); + + var options = document.createElement("td"); + options.className = elements.centerCell; + var editLink = document.createElement("a"); + editLink.href = "/dns/domain?did=" + domain.id; + editLink.innerHTML = "Edit"; + var separator = document.createElement("span"); + separator.innerHTML = " | "; + var removeLink = document.createElement("a"); + removeLink.href = "/dns/domain_delete?did=" + domain.id; + removeLink.innerHTML = "Remove"; + options.appendChild(editLink); + options.appendChild(separator); + options.appendChild(removeLink); + row.appendChild(options); + + return row; + }; + + var createDomainTable = function(tag) + { + var table = document.createElement("table"); + table.id = elements.domainTagPrefix + tag; + table.className = elements.lmcTable; + + var thead = document.createElement("thead"); + var headRow1 = document.createElement("tr"); + var title = document.createElement("td"); + if (!tag.length) + title.innerHTML = "Domains"; + else + title.innerHTML = tag; + headRow1.appendChild(title); + var headRow2 = document.createElement("tr"); + var cells = ["Domain Zone", "Type", "SOA Email", "Status", "Options"]; + title.colspan = cells.length; + for (var i = 0; i < cells.length; i++) { + var cell = document.createElement("td"); + if (cells[i] == "Options") + cell.className = elements.centerCell; + cell.innerHTML = cells[i]; + headRow2.appendChild(cell); + } + thead.appendChild(headRow1); + thead.appendChild(headRow2); + + var tbody = document.createElement("tbody"); + table.appendChild(thead); + table.appendChild(tbody); + ui.domainTables[tag] = tbody; + + var sublinks = document.createElement("p"); + sublinks.className = elements.sublinks; + var importZone = document.createElement("a"); + importZone.href = "/dns/domain_import"; + importZone.innerHTML = "Import a zone"; + var separator = document.createElement("span"); + separator.innerHTML = " | "; + var clone = document.createElement("a"); + clone.href = "/dns/domain_clone"; + clone.innerHTML = "Clone an existing zone"; + var add = document.createElement("a"); + add.href = "/dns/domain_add"; + add.innerHTML = "Add a domain zone"; + sublinks.appendChild(importZone); + sublinks.appendChild(separator); + sublinks.appendChild(clone); + sublinks.appendChild(separator.cloneNode(true)); + sublinks.appendChild(add); + + ui.domains.appendChild(table); + ui.domains.appendChild(sublinks); + }; + + // Callback for domains API call + var displayDomains = function(response) + { + // Add domains to array + data.domains = data.domains.concat(response.data); + + // Add new tags to array + for (var i = 0; i < response.data.length; i++) { + if (!response.data[i].tags.length) + data.noTag = true; + + for (var j = 0; j < response.data[i].tags.length; j++) { + if (!data.domainTags.includes(response.data[i].tags[j])) + data.domainTags.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("/domains?page=" + (response.page + 1), displayDomains, filters); + return; + } + + // Remove tag filter if there are no domains with given tag + if (!data.domains.length && data.params.tag) + location.href = "/dns"; + + // Redirect to add page if there are no domains + if (!data.domains.length && !data.params.tag) + location.href = "/dns/domain_add"; + + // Sort + data.domainTags.sort(); + data.domains.sort(function(a, b) + { + return a.domain.toLowerCase().localeCompare(b.domain.toLowerCase()); + }); + + // Create tables + ui.loading.remove(); + if (data.noTag) + createDomainTable(""); + for (var i = 0; i < data.domainTags.length; i++) + createDomainTable(data.domainTags[i]); + + // Insert domains + for (var i = 0; i < data.domains.length; i++) { + if (!data.domains[i].tags.length) + ui.domainTables[""].appendChild(createDomainRow(data.domains[i], ui.domainTables[""].children.length % 2)); + + for (var j = 0; j < data.domains[i].tags.length; j++) + ui.domainTables[data.domains[i].tags[j]].appendChild(createDomainRow(data.domains[i], ui.domainTables[data.domains[i].tags[j]].children.length % 2)); + } + }; + + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + setupHeader(); + + // Get element references + ui.domains = document.getElementById(elements.domains); + ui.loading = document.getElementById(elements.loading); + + // Get linode and transfer info + var filters = null; + if (data.params.tag) + filters = { "tags": data.params.tag }; + apiGet("/domains", displayDomains, filters); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain/domain.css b/dns/domain/domain.css new file mode 100644 index 0000000..2b9a5ca --- /dev/null +++ b/dns/domain/domain.css @@ -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 . + */ + +@import url('/global.css'); + +#domain { + padding: 0px 15px 15px; +} + +#note { + font-size: 13px; + text-align: center; +} + +.strike { + text-decoration: line-through; +} + +table { + margin-bottom: 15px; +} + +tbody tr td:last-of-type { + text-align: right; + width: 90px; +} + +thead tr:last-of-type td:last-of-type { + text-align: center; +} diff --git a/dns/domain/domain.js b/dns/domain/domain.js new file mode 100644 index 0000000..4d55e18 --- /dev/null +++ b/dns/domain/domain.js @@ -0,0 +1,450 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiGet, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.a = "a"; + elements.caa = "caa"; + elements.cname = "cname"; + elements.domainLabel = "domain-label"; + elements.domainTag = "domain-tag"; + elements.domainTagLink = "domain-tag-link"; + elements.email = "email"; + elements.expire = "expire"; + elements.lmcRow = "lmc-tr1"; + elements.lmcRowAlt = "lmc-tr2"; + elements.mx = "mx"; + elements.ns = "ns"; + elements.refresh = "refresh"; + elements.retry = "retry"; + elements.srv = "srv"; + elements.subdomain = "subdomain"; + elements.ttl = "ttl"; + elements.txt = "txt"; + + // Data recieved from API calls + var data = {}; + data.domain = {}; + data.records = []; + + // Static references to UI elements + var ui = {}; + ui.a = {}; + ui.caa = {}; + ui.cname = {}; + ui.domainLabel = {}; + ui.domainTag = {}; + ui.domainTagLink = {}; + ui.email = {}; + ui.expire = {}; + ui.mx = {}; + ui.ns = {}; + ui.refresh = {}; + ui.retry = {}; + ui.srv = {}; + ui.subdomains = []; + ui.ttl = {}; + ui.txt = {}; + + // Creates an A record table row + var createARow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var hostname = document.createElement("td"); + hostname.innerHTML = record.name; + row.appendChild(hostname); + + var ip = document.createElement("td"); + ip.innerHTML = record.target; + row.appendChild(ip); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates a CAA record table row + var createCAARow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var name = document.createElement("td"); + name.innerHTML = record.name; + row.appendChild(name); + + var tag = document.createElement("td"); + tag.innerHTML = record.tag; + row.appendChild(tag); + + var value = document.createElement("td"); + value.innerHTML = record.target; + row.appendChild(value); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates a CNAME record table row + var createCNAMERow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var hostname = document.createElement("td"); + hostname.innerHTML = record.name; + row.appendChild(hostname); + + var alias = document.createElement("td"); + alias.innerHTML = record.target; + row.appendChild(alias); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates an MX record table row + var createMXRow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var server = document.createElement("td"); + server.innerHTML = record.target; + row.appendChild(server); + + var preference = document.createElement("td"); + preference.innerHTML = record.priority; + row.appendChild(preference); + + var subdomain = document.createElement("td"); + subdomain.innerHTML = record.name; + row.appendChild(subdomain); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates an NS record table row + var createNSRow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var nameserver = document.createElement("td"); + nameserver.innerHTML = record.target; + row.appendChild(nameserver); + + var subdomain = document.createElement("td"); + subdomain.className = elements.subdomain; + if (record.name) + subdomain.innerHTML = record.name; + else if (data.domain.domain) + subdomain.innerHTML = data.domain.domain; + row.appendChild(subdomain); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates the options section for a record + var createOptions = function(record) + { + var options = document.createElement("td"); + var editLink = document.createElement("a"); + editLink.href = "/dns/resource?did=" + data.params.did + "&rid=" + record.id; + editLink.innerHTML = "Edit"; + var separator = document.createElement("span"); + separator.innerHTML = " | "; + var removeLink = document.createElement("a"); + removeLink.href = "/dns/resource_delete?did=" + data.params.did + "&rid=" + record.id; + removeLink.innerHTML = "Remove"; + options.appendChild(editLink); + options.appendChild(separator); + options.appendChild(removeLink); + + return options; + }; + + // Creates an SRV record table row + var createSRVRow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var service = document.createElement("td"); + service.innerHTML = record.name; + row.appendChild(service); + + var domain = document.createElement("td"); + domain.className = elements.subdomain; + if (data.domain.domain) + domain.innerHTML = data.domain.domain; + row.appendChild(domain); + + var priority = document.createElement("td"); + priority.innerHTML = record.priority; + row.appendChild(priority); + + var weight = document.createElement("td"); + weight.innerHTML = record.weight; + row.appendChild(weight); + + var port = document.createElement("td"); + port.innerHTML = record.port; + row.appendChild(port); + + var target = document.createElement("td"); + target.innerHTML = record.target; + row.appendChild(target); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Creates a TXT record table row + var createTXTRow = function(record, alt) + { + var row = document.createElement("tr"); + if (alt) + row.className = elements.lmcRowAlt; + else + row.className = elements.lmcRow; + + var name = document.createElement("td"); + name.innerHTML = record.name; + row.appendChild(name); + + var value = document.createElement("td"); + value.innerHTML = record.target; + row.appendChild(value); + + var ttl = document.createElement("td"); + if (record.ttl_sec == 0) + ttl.innerHTML = "Default"; + else + ttl.innerHTML = record.ttl_sec; + row.appendChild(ttl); + + row.appendChild(createOptions(record)); + + return row; + }; + + // Callback for domain details API call + var displayDetails = function(response) + { + data.domain = response; + + // Set page title and header stuff + document.title += " // " + data.domain.domain; + ui.domainLabel.innerHTML = data.domain.domain; + if (data.domain.tags.length == 1) { + ui.domainTagLink.href = "/dns?tag=" + data.domain.tags[0]; + ui.domainTagLink.innerHTML = "(" + data.domain.tags[0] + ")"; + ui.domainTag.style.display = "inline"; + } + + // Set SOA info + ui.email.innerHTML = data.domain.soa_email; + if (data.domain.ttl_sec == 0) + ui.ttl.innerHTML = "Default"; + else + ui.ttl.innerHTML = data.domain.ttl_sec; + if (data.domain.refresh_sec == 0) + ui.refresh.innerHTML = "Default"; + else + ui.refresh.innerHTML = data.domain.refresh_sec; + if (data.domain.retry_sec == 0) + ui.retry.innerHTML = "Default"; + else + ui.retry.innerHTML = data.domain.retry_sec; + if (data.domain.expire_sec == 0) + ui.expire.innerHTML = "Default"; + else + ui.expire.innerHTML = data.domain.expire_sec; + + // Set NS subdomain labels + ui.subdomains = document.getElementsByClassName(elements.subdomain); + for (var i = 0; i < ui.subdomains.length; i++) + ui.subdomains[i].innerHTML = data.domain.domain; + }; + + // Callback for records API call + var displayRecords = function(response) + { + // Add records to array + data.records = data.records.concat(response.data); + + // Request the next page if there are more pages + if (response.page != response.pages) { + apiGet("/domains/" + data.params.did + "/records?page=" + (response.page + 1), displayRecords, null); + return; + } + + // Sort records by type + data.records.sort(function(a, b) + { + return a.type.localeCompare(b.type); + }); + + // Add records into record tables + for (var i = 0; i < data.records.length; i++) { + switch (data.records[i].type) { + case "A": + case "AAAA": + ui.a.appendChild(createARow(data.records[i], ui.a.children.length % 2)); + break; + case "CAA": + ui.caa.appendChild(createCAARow(data.records[i], ui.caa.children.length % 2)); + break; + case "CNAME": + ui.cname.appendChild(createCNAMERow(data.records[i], ui.cname.children.length % 2)); + break; + case "MX": + ui.mx.appendChild(createMXRow(data.records[i], ui.mx.children.length % 2)); + break; + case "NS": + ui.ns.appendChild(createNSRow(data.records[i], ui.ns.children.length % 2)); + break; + case "SRV": + ui.srv.appendChild(createSRVRow(data.records[i], ui.srv.children.length % 2)); + break; + case "TXT": + ui.txt.appendChild(createTXTRow(data.records[i], ui.txt.children.length % 2)); + break; + default: + console.log(data.records[i]); + break; + } + } + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + // We need a domain ID, so die if we don't have it + if (!data.params.did) { + alert("No domain 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("did=0", "did=" + data.params.did); + + // Get element references + ui.a = document.getElementById(elements.a); + ui.caa = document.getElementById(elements.caa); + ui.cname = document.getElementById(elements.cname); + ui.domainLabel = document.getElementById(elements.domainLabel); + ui.domainTag = document.getElementById(elements.domainTag); + ui.domainTagLink = document.getElementById(elements.domainTagLink); + ui.email = document.getElementById(elements.email); + ui.expire = document.getElementById(elements.expire); + ui.mx = document.getElementById(elements.mx); + ui.ns = document.getElementById(elements.ns); + ui.refresh = document.getElementById(elements.refresh); + ui.retry = document.getElementById(elements.retry); + ui.srv = document.getElementById(elements.srv); + ui.ttl = document.getElementById(elements.ttl); + ui.txt = document.getElementById(elements.txt); + + // Get data from API + apiGet("/domains/" + data.params.did, displayDetails, null); + apiGet("/domains/" + data.params.did + "/records", displayRecords, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain/index.shtml b/dns/domain/index.shtml new file mode 100644 index 0000000..77ce0ba --- /dev/null +++ b/dns/domain/index.shtml @@ -0,0 +1,204 @@ + + + + + + LMC - DNS Manager + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
SOA Record
Primary DNSEmailDefault TTLRefresh RateRetry RateExpire TimeOptions
ns1.linode.comSettings
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NS Records
Name ServerSubdomainTTLOptions
ns1.linode.comDefaultEdit | Remove
ns2.linode.comDefaultEdit | Remove
ns3.linode.comDefaultEdit | Remove
ns4.linode.comDefaultEdit | Remove
ns5.linode.comDefaultEdit | Remove
+ + + + + + + + + + + + + + + +
MX Records
Mail ServerPreferenceSubdomainTTLOptions
+ + + + + + + + + + + + + + +
A/AAAA Records
HostnameIP AddressTTLOptions
+ + + + + + + + + + + + + + +
CNAME Records
HostnameAliases toTTLOptions
+ + + + + + + + + + + + + + +
TXT Records
NameValueTTLOptions
+ + + + + + + + + + + + + + + + + + +
SRV Records
ServiceDomainPriorityWeightPortTargetTTLOptions
+ + + + + + + + + + + + + + + +
CAA Records
NameTagValueTTLOptions
+ +

NOTE: Changes made to a master zone will take effect in Linode's nameservers every quarter hour.

+
+
+ + diff --git a/dns/domain_add/domain_add.css b/dns/domain_add/domain_add.css new file mode 100644 index 0000000..2d7800d --- /dev/null +++ b/dns/domain_add/domain_add.css @@ -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 . + */ + +@import url('/global.css'); + +#domain-add { + padding: 0px 15px 15px; +} + +.master-section { + display: none; +} + +.slave-section { + display: none; +} + +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; +} + +td:nth-of-type(3):not(.info) { + text-align: right; +} diff --git a/dns/domain_add/domain_add.js b/dns/domain_add/domain_add.js new file mode 100644 index 0000000..a9c3260 --- /dev/null +++ b/dns/domain_add/domain_add.js @@ -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 . + */ + +import { settings, elements, apiGet, apiPost, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.addMaster = "add-master"; + elements.addSlave = "add-slave"; + elements.email = "email"; + elements.linode = "linode"; + elements.masterDomain = "master-domain"; + elements.masters = "masters"; + elements.masterSection = "master-section"; + elements.no = "no"; + elements.slaveDomain = "slave-domain"; + elements.slaveSection = "slave-section"; + elements.yes = "yes"; + + // Data recieved from API calls + var data = {}; + data.linodes = []; + + // Static references to UI elements + var ui = {}; + ui.addMaster = {}; + ui.addSlave = {}; + ui.email = {}; + ui.linode = {}; + ui.masterDomain = {}; + ui.masters = {}; + ui.masterSection = []; + ui.no = {}; + ui.slaveDomain = {}; + ui.slaveSection = []; + ui.yes = {}; + + // Temporary state + var state = {}; + state.did = 0; + state.returned = 0; + state.total = 0; + + // Add initial records to new domain + var addRecords = function(response) + { + // Find the selected linode + var linode = null; + for (var i = 0; i < data.linodes.length; i++) { + if (data.linodes[i].id == parseInt(ui.linode.value)) { + linode = data.linodes[i]; + break; + } + } + + if (!linode) { + location.href = "/dns/domain?did=" + response.id; + return; + } + + // Create record requests + state.did = response.id; + var callback = function(response) { + state.returned++; + if (state.returned >= state.total) + location.href = "/dns/domain?did=" + state.did; + } + + var reqs = [ + { + "type": "A", + "name": "", + "target": linode.ipv4[0] + }, + { + "type": "A", + "name": "mail", + "target": linode.ipv4[0] + }, + { + "type": "A", + "name": "www", + "target": linode.ipv4[0] + }, + { + "type": "AAAA", + "name": "", + "target": linode.ipv6.split("/")[0] + }, + { + "type": "AAAA", + "name": "mail", + "target": linode.ipv6.split("/")[0] + }, + { + "type": "AAAA", + "name": "www", + "target": linode.ipv6.split("/")[0] + }, + { + "type": "MX", + "target": "mail.meredithlaboon.com", + "priority": 10, + "name": "" + } + ]; + + state.total = reqs.length; + for (var i = 0; i < reqs.length; i++) + apiPost("/domains/" + response.id + "/records", reqs[i], callback); + }; + + // 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) { + apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, null); + return; + } + + // Add linodes to selector + for (var i = 0; i < data.linodes.length; i++) { + var option = document.createElement("option"); + option.value = data.linodes[i].id; + option.innerHTML = data.linodes[i].label; + ui.linode.appendChild(option); + } + + ui.addMaster.disabled = false; + }; + + // Click handler for add master button + var handleAddMaster = function(event) + { + if (event.currentTarget.disabled) + return; + + // This request takes a few seconds + ui.addMaster.disabled = true; + + var req = { + "domain": ui.masterDomain.value, + "type": "master", + "soa_email": ui.email.value + }; + + var callback = function(response) + { + location.href = "/dns/domain?did=" + response.id; + }; + if (ui.yes.checked) + callback = addRecords; + + apiPost("/domains", req, callback); + }; + + // Click handler for add slave button + var handleAddSlave = function(event) + { + if (event.currentTarget.disabled) + return; + + // This request takes a few seconds + ui.addSlave.disabled = true; + + var ips = []; + var masterLines = ui.masters.value.split("\n"); + for (var i = 0; i < masterLines.length; i++) + ips = ips.concat(masterLines[i].split(";")); + + var req = { + "domain": ui.slaveDomain.value, + "type": "slave", + "master_ips": ips + }; + + apiPost("/domains", req, function(response) + { + location.href = "/dns/domain?did=" + response.id; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + setupHeader(); + + // Get element references + ui.addMaster = document.getElementById(elements.addMaster); + ui.addSlave = document.getElementById(elements.addSlave); + ui.email = document.getElementById(elements.email); + ui.linode = document.getElementById(elements.linode); + ui.masterDomain = document.getElementById(elements.masterDomain); + ui.masters = document.getElementById(elements.masters); + ui.masterSection = document.getElementsByClassName(elements.masterSection); + ui.no = document.getElementById(elements.no); + ui.slaveDomain = document.getElementById(elements.slaveDomain); + ui.slaveSection = document.getElementsByClassName(elements.slaveSection); + ui.yes = document.getElementById(elements.yes); + + // Display desired section + var section = null; + if (data.params.type && data.params.type == "slave") + section = ui.slaveSection; + else + section = ui.masterSection; + for (var i = 0; i < section.length; i++) + section[i].style.display = "table-row-group"; + + // Attach event handlers + ui.addMaster.addEventListener("click", handleAddMaster); + ui.addSlave.addEventListener("click", handleAddSlave); + + // Get data from API + if (!data.params.type || data.params.type != "slave") + apiGet("/linode/instances", displayLinodes, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain_add/index.shtml b/dns/domain_add/index.shtml new file mode 100644 index 0000000..2ecf22f --- /dev/null +++ b/dns/domain_add/index.shtml @@ -0,0 +1,91 @@ + + + + + + LMC - Add a Zone + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Add a Master Zone
Domain
SOA Email
Insert Default Records +
+ +
I wanted a slave zone
Add a Slave Zone
Domain
Masters + The IP addresses of the master DNS servers for this zone.
+ Semicolon or new line delimited. +
I wanted a master zone
+
+
+ + diff --git a/dns/domain_clone/domain_clone.css b/dns/domain_clone/domain_clone.css new file mode 100644 index 0000000..642469b --- /dev/null +++ b/dns/domain_clone/domain_clone.css @@ -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 . + */ + +@import url('/global.css'); + +#domain-clone { + 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; +} diff --git a/dns/domain_clone/domain_clone.js b/dns/domain_clone/domain_clone.js new file mode 100644 index 0000000..ca3a026 --- /dev/null +++ b/dns/domain_clone/domain_clone.js @@ -0,0 +1,95 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiGet, apiPost, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.cloneButton = "clone-button"; + elements.existingDomain = "existing-domain"; + elements.newDomain = "new-domain"; + + // Data recieved from API calls + var data = {}; + + // Static references to UI elements + var ui = {}; + ui.cloneButton = {}; + ui.existingDomain = {}; + ui.newDomain = {}; + + // Callback for domains API call + var displayDomains = function(response) + { + // Add domains to selector + for (var i = 0; i < response.data.length; i++) { + var domain = document.createElement("option"); + domain.value = response.data[i].id; + domain.innerHTML = response.data[i].domain; + ui.existingDomain.appendChild(domain); + } + + // Request the next page if there are more pages + if (response.page != response.pages) + apiGet("/domains?page=" + (response.page + 1), displayDomains, null); + else + ui.cloneButton.disabled = false; + }; + + // Click handler for clone button + var handleClone = function(event) + { + if (event.currentTarget.disabled) + return; + + // This request takes a few seconds + ui.cloneButton.disabled = true; + + var req = { + "domain": ui.newDomain.value + }; + + apiPost("/domains/" + ui.existingDomain.value + "/clone", req, function(response) + { + location.href = "/dns/domain?did=" + response.id; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + setupHeader(); + + // Get element references + ui.cloneButton = document.getElementById(elements.cloneButton); + ui.existingDomain = document.getElementById(elements.existingDomain); + ui.newDomain = document.getElementById(elements.newDomain); + + // Attach event handlers + ui.cloneButton.addEventListener("click", handleClone); + + // Get data from API + apiGet("/domains", displayDomains, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain_clone/index.shtml b/dns/domain_clone/index.shtml new file mode 100644 index 0000000..21b9259 --- /dev/null +++ b/dns/domain_clone/index.shtml @@ -0,0 +1,55 @@ + + + + + + LMC - Clone a Zone + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
Clone an existing Zone
Clone this zone
Into this zone
+
+
+ + diff --git a/dns/domain_delete/domain_delete.css b/dns/domain_delete/domain_delete.css new file mode 100644 index 0000000..9e202f8 --- /dev/null +++ b/dns/domain_delete/domain_delete.css @@ -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 . + */ + +@import url('/global.css'); + +#domain { + font-weight: bold; +} + +#domain-delete { + padding: 0px 15px 15px; +} diff --git a/dns/domain_delete/domain_delete.js b/dns/domain_delete/domain_delete.js new file mode 100644 index 0000000..087fae6 --- /dev/null +++ b/dns/domain_delete/domain_delete.js @@ -0,0 +1,87 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiDelete, apiGet, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.deleteButton = "delete-button"; + elements.domain = "domain"; + + // Data recieved from API calls + var data = {}; + + // Static references to UI elements + var ui = {}; + ui.deleteButton = {}; + ui.domain = {}; + + // Callback for domain details API call + var displayDetails = function(response) + { + // Set page title and header stuff + document.title += " // " + response.domain; + ui.domain.innerHTML = response.domain; + ui.deleteButton.disabled = false; + }; + + // Click handler for delete button + var handleDelete = function(event) + { + if (event.currentTarget.disabled) + return; + + apiDelete("/domains/" + data.params.did, function(response) + { + location.href = "/dns"; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + // We need a domain ID, so die if we don't have it + if (!data.params.did) { + alert("No domain 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("did=0", "did=" + data.params.did); + + // Get element references + ui.deleteButton = document.getElementById(elements.deleteButton); + ui.domain = document.getElementById(elements.domain); + + // Attach event handlers + ui.deleteButton.addEventListener("click", handleDelete); + + // Get data from API + apiGet("/domains/" + data.params.did, displayDetails, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain_delete/index.shtml b/dns/domain_delete/index.shtml new file mode 100644 index 0000000..e7155ae --- /dev/null +++ b/dns/domain_delete/index.shtml @@ -0,0 +1,36 @@ + + + + + + LMC - Remove Zone + + + + + + +
+ +
+

Are you sure you want to delete the entire zone ?

+ +
+
+ + diff --git a/dns/domain_import/domain_import.css b/dns/domain_import/domain_import.css new file mode 100644 index 0000000..997b6f8 --- /dev/null +++ b/dns/domain_import/domain_import.css @@ -0,0 +1,36 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +@import url('/global.css'); + +#domain-import { + padding: 0px 15px 15px; +} + +#domain-import p { + background-color: #8BCBEA; + padding: 8px; +} + +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; +} diff --git a/dns/domain_import/domain_import.js b/dns/domain_import/domain_import.js new file mode 100644 index 0000000..45a128e --- /dev/null +++ b/dns/domain_import/domain_import.js @@ -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 . + */ + +import { settings, elements, apiPost, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.domain = "domain"; + elements.importButton = "import-button"; + elements.nameserver = "nameserver"; + + // Data recieved from API calls + var data = {}; + + // Static references to UI elements + var ui = {}; + ui.domain = {}; + ui.importButton = {}; + ui.nameserver = {}; + + // Click handler for import button + var handleImport = function(event) + { + if (event.currentTarget.disabled) + return; + + var req = { + "domain": ui.domain.value, + "remote_nameserver": ui.nameserver.value + }; + + apiPost("/domains/import", req, function(response) + { + location.href = "/dns/domain?did=" + response.id; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + setupHeader(); + + // Get element references + ui.domain = document.getElementById(elements.domain); + ui.importButton = document.getElementById(elements.importButton); + ui.nameserver = document.getElementById(elements.nameserver); + + // Attach event handlers + ui.importButton.addEventListener("click", handleImport); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain_import/index.shtml b/dns/domain_import/index.shtml new file mode 100644 index 0000000..30b5e81 --- /dev/null +++ b/dns/domain_import/index.shtml @@ -0,0 +1,56 @@ + + + + + + LMC - Import a Zone + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
Import a zone from a remote nameserver
Domain
Remote Nameserver
+

Your nameserver must allow zone transfers (AXFR) from 96.126.114.97, 96.126.114.98, 2600:3c00::5e, and 2600:3c00::5f

+
+
+ + diff --git a/dns/domain_soa/domain_soa.css b/dns/domain_soa/domain_soa.css new file mode 100644 index 0000000..c99a7f1 --- /dev/null +++ b/dns/domain_soa/domain_soa.css @@ -0,0 +1,32 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +@import url('/global.css'); + +#domain-soa { + 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; +} diff --git a/dns/domain_soa/domain_soa.js b/dns/domain_soa/domain_soa.js new file mode 100644 index 0000000..4681691 --- /dev/null +++ b/dns/domain_soa/domain_soa.js @@ -0,0 +1,164 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiGet, apiPut, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.axfr = "axfr"; + elements.email = "email"; + elements.expire = "expire"; + elements.domain = "domain"; + elements.domainLabel = "domain-label"; + elements.domainTag = "domain-tag"; + elements.domainTagLink = "domain-tag-link"; + elements.refresh = "refresh"; + elements.retry = "retry"; + elements.saveButton = "save-button"; + elements.status = "status"; + elements.tags = "tags"; + elements.ttl = "ttl"; + + // Data recieved from API calls + var data = {}; + data.domain = {}; + + // Static references to UI elements + var ui = {}; + ui.axfr = {}; + ui.email = {}; + ui.expire = {}; + ui.domain = {}; + ui.domainLabel = {}; + ui.domainTag = {}; + ui.domainTagLink = {}; + ui.refresh = {}; + ui.retry = {}; + ui.saveButton = {}; + ui.status = {}; + ui.tags = {}; + ui.ttl = {}; + + // Callback for domain details API call + var displayDetails = function(response) + { + data.domain = response; + + // Set page title and header stuff + document.title += " // " + data.domain.domain; + ui.domainLabel.innerHTML = data.domain.domain; + if (data.domain.tags.length == 1) { + ui.domainTagLink.href = "/dns?tag=" + data.domain.tags[0]; + ui.domainTagLink.innerHTML = "(" + data.domain.tags[0] + ")"; + ui.domainTag.style.display = "inline"; + } + + // Set form info + ui.domain.value = data.domain.domain; + ui.email.value = data.domain.soa_email; + ui.status.value = data.domain.status; + ui.tags.value = data.domain.tags.join(","); + ui.axfr.value = data.domain.axfr_ips.join("\n"); + ui.ttl.value = data.domain.ttl_sec; + ui.refresh.value = data.domain.refresh_sec; + ui.retry.value = data.domain.retry_sec; + ui.expire.value = data.domain.expire_sec; + + ui.saveButton.disabled = false; + }; + + // Click handler for save button + var handleSave = function(event) + { + if (event.currentTarget.disabled) + return; + + // This request can take a few seconds, + // so disable the button to prevent antsy users from double-submitting + ui.saveButton.disabled = true; + + var req = { + "domain": ui.domain.value, + "soa_email": ui.email.value, + "status": ui.status.value, + "tags": [], + "axfr_ips": [], + "ttl_sec": parseInt(ui.ttl.value), + "refresh_sec": parseInt(ui.refresh.value), + "retry_sec": parseInt(ui.retry.value), + "expire_sec": parseInt(ui.expire.value) + }; + + if (ui.tags.value.length) + req.tags = ui.tags.value.split(","); + if (ui.axfr.value.length) { + var axfrLines = ui.axfr.value.split("\n"); + for (var i = 0; i < axfrLines.length; i++) + req.axfr_ips = req.axfr_ips.concat(axfrLines[i].split(";")); + } + + apiPut("/domains/" + data.params.did, req, function(response) + { + location.href = "/dns/domain?did=" + data.params.did; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + // We need a domain ID, so die if we don't have it + if (!data.params.did) { + alert("No domain 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("did=0", "did=" + data.params.did); + + // Get element references + ui.axfr = document.getElementById(elements.axfr); + ui.email = document.getElementById(elements.email); + ui.expire = document.getElementById(elements.expire); + ui.domain = document.getElementById(elements.domain); + ui.domainLabel = document.getElementById(elements.domainLabel); + ui.domainTag = document.getElementById(elements.domainTag); + ui.domainTagLink = document.getElementById(elements.domainTagLink); + ui.refresh = document.getElementById(elements.refresh); + ui.retry = document.getElementById(elements.retry); + ui.saveButton = document.getElementById(elements.saveButton); + ui.status = document.getElementById(elements.status); + ui.tags = document.getElementById(elements.tags); + ui.ttl = document.getElementById(elements.ttl); + + // Attach event handlers + ui.saveButton.addEventListener("click", handleSave); + + // Get data from API + apiGet("/domains/" + data.params.did, displayDetails, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/domain_soa/index.shtml b/dns/domain_soa/index.shtml new file mode 100644 index 0000000..24d7c7f --- /dev/null +++ b/dns/domain_soa/index.shtml @@ -0,0 +1,165 @@ + + + + + + LMC - Edit Domain + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Domain Settings and Defaults
DomainExample: ns1.example.com
SOA emailYour email address
Domain Status + +
TagsGroup domains together using tags! (comma-separated)
Advanced Settings
Domain Transfers + The IP addresses allowed to AXFR this entire zone.
+ Semicolon or new line delimited. (maximum: 6 IPs) +
Default TTL + + Defines the default Time To Live for all entries in the zone
Refresh Rate + + Determines how often the secondary/slave nameservers check with the master for updates
Retry Rate + + The amount of time the secondary/slave nameservers will wait to contact the master nameserver again if the last attempt failed
Expire Rate + + How long a secondary/slave nameserver will wait before considering its DNS data stale if it can't reach the primary nameserver
+
+
+ + diff --git a/dns/index.shtml b/dns/index.shtml new file mode 100644 index 0000000..11d7ca2 --- /dev/null +++ b/dns/index.shtml @@ -0,0 +1,34 @@ + + + + + + LMC - DNS Manager + + + + + + +
+
+ Loading... +
+
+ + diff --git a/dns/resource/index.shtml b/dns/resource/index.shtml new file mode 100644 index 0000000..85af7f2 --- /dev/null +++ b/dns/resource/index.shtml @@ -0,0 +1,226 @@ + + + + + + LMC - Edit Resource + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Add/edit an A/AAAA Record
HostnameExample: www.example.com
IP Address
Add/edit a CAA Record
SubdomainSee Linode's CAA records guide for more info.
Tag + +
Value
Add/edit a CNAME Record
HostnameExample: www.example.com
Aliases toExample: www.example.org
Add/edit an MX Record
Mail ServerExample: mail2.example.com
Priority0-255
SubdomainLeave blank unless delegating a subdomain to the mail server above. A wildcard is also valid here.
Add/edit an NS Record
Name ServerExample: ns1.example.com
SubdomainLeave this blank unless you're delegating a subdomain to the nameserver above.
Add/edit an SRV Record
ServiceExample: _sip
Protocol + +
Target
Priority0-65535
Weight0-65535
Port0-65535
Add/edit a TXT Record
Name
Value
TTL + +
+
+
+ + diff --git a/dns/resource/resource.css b/dns/resource/resource.css new file mode 100644 index 0000000..82ab969 --- /dev/null +++ b/dns/resource/resource.css @@ -0,0 +1,36 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +@import url('/global.css'); + +#resource { + padding: 0px 15px 15px; +} + +.resource-section { + display: none; +} + +tbody:not(.lmc-tbody-head) tr td:first-of-type { + font-weight: bold; + text-align: right; + white-space: nowrap; +} + +tbody:not(.lmc-tbody-head):not(.resource-section) tr:last-of-type { + border: none; +} diff --git a/dns/resource/resource.js b/dns/resource/resource.js new file mode 100644 index 0000000..e86cb3f --- /dev/null +++ b/dns/resource/resource.js @@ -0,0 +1,315 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiGet, apiPost, apiPut, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.a = "a"; + elements.aHostname = "a-hostname"; + elements.aIP = "a-ip"; + elements.caa = "caa"; + elements.caaSubdomain = "caa-subdomain"; + elements.caaTag = "caa-tag"; + elements.caaValue = "caa-value"; + elements.cname = "cname"; + elements.cnameHostname = "cname-hostname"; + elements.cnameAlias = "cname-alias"; + elements.domainLabel = "domain-label"; + elements.domainTag = "domain-tag"; + elements.domainTagLink = "domain-tag-link"; + elements.mx = "mx"; + elements.mxServer = "mx-server"; + elements.mxPriority = "mx-priority"; + elements.mxSubdomain = "mx-subdomain"; + elements.ns = "ns"; + elements.nsNameserver = "ns-nameserver"; + elements.nsSubdomain = "ns-subdomain"; + elements.saveButton = "save-button"; + elements.srv = "srv"; + elements.srvService = "srv-service"; + elements.srvProtocol = "srv-protocol"; + elements.srvTarget = "srv-target"; + elements.srvPriority = "srv-priority"; + elements.srvWeight = "srv-weight"; + elements.srvPort = "srv-port"; + elements.ttl = "ttl"; + elements.txt = "txt"; + elements.txtName = "txt-name"; + elements.txtValue = "txt-value"; + + // Data recieved from API calls + var data = {}; + data.domain = {}; + data.record = {}; + + // Static references to UI elements + var ui = {}; + ui.a = []; + ui.aHostname = {}; + ui.aIP = {}; + ui.caa = []; + ui.caaSubdomain = {}; + ui.caaTag = {}; + ui.caaValue = {}; + ui.cname = []; + ui.cnameHostname = {}; + ui.cnameAlias = {}; + ui.domainLabel = {}; + ui.domainTag = {}; + ui.domainTagLink = {}; + ui.mx = []; + ui.mxServer = {}; + ui.mxPriority = {}; + ui.mxSubdomain = {}; + ui.ns = []; + ui.nsNameserver = {}; + ui.nsSubdomain = {}; + ui.saveButton = {}; + ui.srv = []; + ui.srvService = {}; + ui.srvProtocol = {}; + ui.srvTarget = {}; + ui.srvPriority = {}; + ui.srvWeight = {}; + ui.srvPort = {}; + ui.ttl = {}; + ui.txt = []; + ui.txtName = {}; + ui.txtValue = {}; + + // Callback for domain details API call + var displayDetails = function(response) + { + data.domain = response; + + // Set page title and header stuff + document.title += " // " + data.domain.domain; + ui.domainLabel.innerHTML = data.domain.domain; + if (data.domain.tags.length == 1) { + ui.domainTagLink.href = "/dns?tag=" + data.domain.tags[0]; + ui.domainTagLink.innerHTML = "(" + data.domain.tags[0] + ")"; + ui.domainTag.style.display = "inline"; + } + }; + + // Callback for record details API call + var displayRecord = function(response) + { + data.record = response; + + // Display controls for record type + data.record.type = data.record.type.toLowerCase(); + for (var i = 0; i < ui[data.record.type].length; i++) + ui[data.record.type][i].style.display = "table-row-group"; + + // Fill in form data + switch (data.record.type) { + case "a": + case "aaaa": + ui.aHostname.value = data.record.name; + ui.aIP.value = data.record.target; + break; + case "caa": + ui.caaSubdomain.value = data.record.name; + ui.caaTag.value = data.record.tag; + ui.caaValue.value = data.record.target; + break; + case "cname": + ui.cnameHostname.value = data.record.name; + ui.cnameAlias.value = data.record.target; + break; + case "mx": + ui.mxServer.value = data.record.target; + ui.mxPriority.value = data.record.priority; + ui.mxSubdomain.value = data.record.name; + break; + case "ns": + ui.nsNameserver.value = data.record.target; + ui.nsSubdomain.value = data.record.name; + break; + case "srv": + if (data.record.service.charAt(0) == "_") + ui.srvService.value = data.record.service; + else + ui.srvService.value = "_" + data.record.service; + ui.srvProtocol.value = data.record.protocol; + ui.srvTarget.value = data.record.target; + ui.srvPriority.value = data.record.priority; + ui.srvWeight.value = data.record.weight; + ui.srvPort.value = data.record.port; + break; + case "txt": + ui.txtName.value = data.record.name; + ui.txtValue.value = data.record.target; + break; + } + + ui.ttl.value = data.record.ttl_sec; + ui.saveButton.disabled = false; + }; + + // Click handler for save button + var handleSave = function(event) + { + if (event.currentTarget.disabled) + return; + + var type; + if (data.record.type) + type = data.record.type; + else + type = data.params.type; + + var req = { + "ttl_sec": parseInt(ui.ttl.value), + "type": type.toUpperCase() + }; + + switch (type) { + case "a": + case "aaaa": + req.name = ui.aHostname.value; + req.target = ui.aIP.value; + break; + case "caa": + req.name = ui.caaSubdomain.value; + req.tag = ui.caaTag.value; + req.target = ui.caaValue.value; + break; + case "cname": + req.name = ui.cnameHostname.value; + req.target = ui.cnameAlias.value; + break; + case "mx": + req.target = ui.mxServer.value; + req.priority = parseInt(ui.mxPriority.value); + req.name = ui.mxSubdomain.value; + break; + case "ns": + req.target = ui.nsNameserver.value; + req.name = ui.nsSubdomain.value; + break; + case "srv": + req.service = ui.srvService.value; + req.protocol = ui.srvProtocol.value; + req.target = ui.srvTarget.value; + req.priority = parseInt(ui.srvPriority.value); + req.weight = parseInt(ui.srvWeight.value); + req.port = parseInt(ui.srvPort.value); + break; + case "txt": + req.name = ui.txtName.value; + req.target = ui.txtValue.value; + break; + } + + var callback = function(response) + { + location.href = "/dns/domain?did=" + data.params.did; + }; + if (data.params.rid == "0") + apiPost("/domains/" + data.params.did + "/records", req, callback); + else + apiPut("/domains/" + data.params.did + "/records/" + data.params.rid, req, callback); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + // We need a domain ID, so die if we don't have it + if (!data.params.did) { + alert("No domain ID supplied!"); + return; + } + + // We also need a resource ID + if (!data.params.rid) { + alert("No resource ID supplied!"); + return; + } + + // If this is a new resource, we also need a resource type + if (data.params.rid == "0" && !data.params.type) { + alert("No resource type 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("did=0", "did=" + data.params.did); + + // Get element references + ui.a = document.getElementsByClassName(elements.a); + ui.aHostname = document.getElementById(elements.aHostname); + ui.aIP = document.getElementById(elements.aIP); + ui.caa = document.getElementsByClassName(elements.caa); + ui.caaSubdomain = document.getElementById(elements.caaSubdomain); + ui.caaTag = document.getElementById(elements.caaTag); + ui.caaValue = document.getElementById(elements.caaValue); + ui.cname = document.getElementsByClassName(elements.cname); + ui.cnameHostname = document.getElementById(elements.cnameHostname); + ui.cnameAlias = document.getElementById(elements.cnameAlias); + ui.domainLabel = document.getElementById(elements.domainLabel); + ui.domainTag = document.getElementById(elements.domainTag); + ui.domainTagLink = document.getElementById(elements.domainTagLink); + ui.mx = document.getElementsByClassName(elements.mx); + ui.mxServer = document.getElementById(elements.mxServer); + ui.mxPriority = document.getElementById(elements.mxPriority); + ui.mxSubdomain = document.getElementById(elements.mxSubdomain); + ui.ns = document.getElementsByClassName(elements.ns); + ui.nsNameserver = document.getElementById(elements.nsNameserver); + ui.nsSubdomain = document.getElementById(elements.nsSubdomain); + ui.saveButton = document.getElementById(elements.saveButton); + ui.srv = document.getElementsByClassName(elements.srv); + ui.srvService = document.getElementById(elements.srvService); + ui.srvProtocol = document.getElementById(elements.srvProtocol); + ui.srvTarget = document.getElementById(elements.srvTarget); + ui.srvPriority = document.getElementById(elements.srvPriority); + ui.srvWeight = document.getElementById(elements.srvWeight); + ui.srvPort = document.getElementById(elements.srvPort); + ui.ttl = document.getElementById(elements.ttl); + ui.txt = document.getElementsByClassName(elements.txt); + ui.txtName = document.getElementById(elements.txtName); + ui.txtValue = document.getElementById(elements.txtValue); + + // Display controls for given type + if (data.params.rid == "0") { + for (var i = 0; i < ui[data.params.type].length; i++) + ui[data.params.type][i].style.display = "table-row-group"; + ui.saveButton.disabled = false; + } + + // Attach event handlers + ui.saveButton.addEventListener("click", handleSave); + + // Get data from API + apiGet("/domains/" + data.params.did, displayDetails, null); + if (data.params.rid != "0") + apiGet("/domains/" + data.params.did + "/records/" + data.params.rid, displayRecord, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/dns/resource_delete/index.shtml b/dns/resource_delete/index.shtml new file mode 100644 index 0000000..a931ead --- /dev/null +++ b/dns/resource_delete/index.shtml @@ -0,0 +1,36 @@ + + + + + + LMC - Remove Record + + + + + + +
+ +
+

Are you sure you want to delete this record?

+ +
+
+ + diff --git a/dns/resource_delete/resource_delete.css b/dns/resource_delete/resource_delete.css new file mode 100644 index 0000000..4c1e73d --- /dev/null +++ b/dns/resource_delete/resource_delete.css @@ -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 . + */ + +@import url('/global.css'); + +#resource-delete { + padding: 0px 15px 15px; +} diff --git a/dns/resource_delete/resource_delete.js b/dns/resource_delete/resource_delete.js new file mode 100644 index 0000000..c5036b4 --- /dev/null +++ b/dns/resource_delete/resource_delete.js @@ -0,0 +1,121 @@ +/* + * This file is part of Linode Manager Classic. + * + * Linode Manager Classic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Linode Manager Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Linode Manager Classic. If not, see . + */ + +import { settings, elements, apiDelete, apiGet, parseParams, setupHeader } from "/global.js"; + +(function() +{ + // Element names specific to this page + elements.deleteButton = "delete-button"; + elements.domainLabel = "domain-label"; + elements.domainTag = "domain-tag"; + elements.domainTagLink = "domain-tag-link"; + elements.recordType = "record-type"; + elements.topLinksTitle = "top-links-title"; + + // Data recieved from API calls + var data = {}; + + // Static references to UI elements + var ui = {}; + ui.deleteButton = {}; + ui.domainLabel = {}; + ui.domainTag = {}; + ui.domainTagLink = {}; + ui.recordType = {}; + ui.topLinksTitle = {}; + + // Callback for domain details API call + var displayDetails = function(response) + { + // Set page title and header stuff + document.title += " // " + response.domain; + ui.domainLabel.innerHTML = response.domain; + if (response.tags.length == 1) { + ui.domainTagLink.href = "/dns?tag=" + response.tags[0]; + ui.domainTagLink.innerHTML = "(" + response.tags[0] + ")"; + ui.domainTag.style.display = "inline"; + } + }; + + // Callback for record details API call + var displayRecord = function(response) + { + ui.recordType.innerHTML = response.type; + if (response.name && response.name.length != 0) + ui.topLinksTitle.innerHTML += " " + response.name; + else + ui.topLinksTitle.innerHTML += " " + response.target; + ui.deleteButton.disabled = false; + }; + + // Click handler for delete button + var handleDelete = function(event) + { + if (event.currentTarget.disabled) + return; + + apiDelete("/domains/" + data.params.did + "/records/" + data.params.rid, function(response) + { + location.href = "/dns/domain?did=" + data.params.did; + }); + }; + + // Initial setup + var setup = function() + { + // Parse URL parameters + data.params = parseParams(); + + // We need a domain ID, so die if we don't have it + if (!data.params.did) { + alert("No domain ID supplied!"); + return; + } + + // We also need a resource ID + if (!data.params.rid) { + alert("No resource 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("did=0", "did=" + data.params.did); + + // Get element references + ui.deleteButton = document.getElementById(elements.deleteButton); + ui.domainLabel = document.getElementById(elements.domainLabel); + ui.domainTag = document.getElementById(elements.domainTag); + ui.domainTagLink = document.getElementById(elements.domainTagLink); + ui.recordType = document.getElementById(elements.recordType); + ui.topLinksTitle = document.getElementsByClassName(elements.topLinksTitle)[0]; + + // Attach event handlers + ui.deleteButton.addEventListener("click", handleDelete); + + // Get data from API + apiGet("/domains/" + data.params.did, displayDetails, null); + apiGet("/domains/" + data.params.did + "/records/" + data.params.rid, displayRecord, null); + }; + + // Attach onload handler + window.addEventListener("load", setup); +})(); diff --git a/global.css b/global.css index 724d015..c159c60 100644 --- a/global.css +++ b/global.css @@ -57,6 +57,10 @@ button { font-size: 14px; } +#domain-tag { + display: none; +} + header { background-color: #32AE4D; } diff --git a/linodes/linodes.js b/linodes/linodes.js index 5c52981..f03e3f2 100644 --- a/linodes/linodes.js +++ b/linodes/linodes.js @@ -233,8 +233,12 @@ import { settings, elements, regionNames, apiGet, parseParams, setupHeader } fro return; } + // Remove tag filter if there are no linodes with given tag + if (data.linodes.length == 0 && data.params.tag) + location.href = "/linodes"; + // Redirect to add page if there are no linodes - if (data.linodes.length == 0) + if (data.linodes.length == 0 && !data.params.tag) location.href = "/linodes/add"; // Sort