зеркало из https://github.com/mozilla/hubs-ops.git
Add option for deleting a single record or all unmatched
This commit is contained in:
Родитель
d9f380d8de
Коммит
b1e7704ed8
|
@ -2,6 +2,7 @@ const AWS = require("aws-sdk");
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const yargs = require("yargs");
|
||||
const readline = require("readline");
|
||||
|
||||
const argv = yargs
|
||||
.usage("Usage: node $0 <command> [options]")
|
||||
|
@ -24,11 +25,34 @@ const argv = yargs
|
|||
"$0 filter",
|
||||
"Identifies the DNS records that should be deleted and writes that to unmatched_dns_records.json"
|
||||
)
|
||||
.command("delete", "Delete a DNS record by the given name.")
|
||||
.example(
|
||||
"$0 delete -n some-subdomain -z MY_HOSTED_ZONE_ID",
|
||||
"Finds the Route53 DNS record with name some-subdomain.my-hosted-zone"
|
||||
)
|
||||
.command(
|
||||
"delete-unmatched",
|
||||
"Delete the DNS records that do not match an EC2 node."
|
||||
)
|
||||
.example(
|
||||
"$0 delete-unmatched -z MY_HOSTED_ZONE_ID",
|
||||
"Deletes the unmatched DNS records (asks for confirmation in batches)."
|
||||
)
|
||||
.options("hosted_zone_id", {
|
||||
alias: "z",
|
||||
description: "The Route53 HostedZoneId",
|
||||
type: "string",
|
||||
})
|
||||
.options("record_name", {
|
||||
alias: "n",
|
||||
description: "A record name to delete",
|
||||
type: "string",
|
||||
})
|
||||
.options("dry", {
|
||||
alias: "d",
|
||||
description: "Dry run. Will not execute deletes.",
|
||||
type: "boolean",
|
||||
})
|
||||
.options("quiet", {
|
||||
alias: "q",
|
||||
description:
|
||||
|
@ -53,7 +77,7 @@ const promisify = (f) => (arg) =>
|
|||
new Promise((res, rej) =>
|
||||
f(arg, (err, data) => {
|
||||
if (err) {
|
||||
logger.log(err);
|
||||
logger.error(err);
|
||||
rej(err);
|
||||
} else {
|
||||
res(data);
|
||||
|
@ -205,7 +229,7 @@ function filter_by_ec2_instances(dns_records, ec2_instances) {
|
|||
async function fetch_aws_info() {
|
||||
if (!argv.hosted_zone_id) {
|
||||
logger.error(
|
||||
"Must set the hosted_zone_id.\n node ./index.js fetch --hosted_zone_id <your_hosted_zone_id>\n node ./index.js fetch -z <your_hosted_zone_id>"
|
||||
`Must set the hosted_zone_id.\n node ${argv["$0"]} fetch --hosted_zone_id <your_hosted_zone_id>\n node ${argv["$0"]} fetch -z <your_hosted_zone_id>`
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
@ -235,39 +259,138 @@ async function filter_dns_records() {
|
|||
logger.log(`Matched ${records.length} records. See ${output_filename}.json`);
|
||||
}
|
||||
|
||||
// I have not tested this yet.
|
||||
async function remove_record(record) {
|
||||
async function batch_delete_dns_records(records) {
|
||||
if (argv.dry) {
|
||||
logger.log("Not deleting any records. This is a dry run...");
|
||||
return 0;
|
||||
}
|
||||
changes = records.map(function (record) {
|
||||
return {
|
||||
Action: "DELETE",
|
||||
ResourceRecordSet: {
|
||||
Name: record.Name,
|
||||
Type: record.Type,
|
||||
ResourceRecords: record.ResourceRecords,
|
||||
TTL: record.TTL,
|
||||
// MultiValueAnswer: true,
|
||||
// SetIdentifier: record.SetIdentifier,
|
||||
// HealthCheckId: record.HealthCheckId,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const route53 = new AWS.Route53();
|
||||
try {
|
||||
await promisify(route53.changeResourceRecordSets.bind(route53))({
|
||||
ChangeBatch: {
|
||||
Changes: [
|
||||
{
|
||||
Action: "DELETE",
|
||||
ResourceRecordSet: {
|
||||
Name: record.Name,
|
||||
Type: record.Type,
|
||||
TTL: record.TTL,
|
||||
ResourceRecords: record.ResourceRecords,
|
||||
// MultiValueAnswer: true,
|
||||
// SetIdentifier: record.SetIdentifier,
|
||||
// HealthCheckId: record.HealthCheckId,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
const result = await promisify(
|
||||
route53.changeResourceRecordSets.bind(route53)
|
||||
)({
|
||||
ChangeBatch: { Changes: changes },
|
||||
HostedZoneId: argv.hosted_zone_id,
|
||||
});
|
||||
logger.log(result);
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
// logger.error(e); // Already logged by promisify
|
||||
logger.error("Batch delete request failed. Did not delete records:");
|
||||
logger.error(records);
|
||||
}
|
||||
}
|
||||
|
||||
function prompt_for_continue() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
rl.question("Press any key to continue...", function (anything) {
|
||||
rl.close();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delete_records_with_confirmation_prompt(records) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
logger.log(records);
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
const message = argv.dry
|
||||
? "(This is a dry run. Records will NOT be deleted.)\n"
|
||||
: "(CAUTION: THIS IS NOT A DRY RUN. Records WILL be deleted.)\n";
|
||||
rl.question(
|
||||
`Are you sure you want to delete these records? (Type "delete" to confirm.)\n${message}`,
|
||||
async function (answer) {
|
||||
rl.close();
|
||||
if (answer === "delete") {
|
||||
logger.log("Attempting to delete records...");
|
||||
await batch_delete_dns_records(records);
|
||||
await prompt_for_continue();
|
||||
} else {
|
||||
logger.log("You chose not to delete these records. Exiting...");
|
||||
process.exit(0);
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function delete_unmatched_dns_records() {
|
||||
if (!argv.hosted_zone_id) {
|
||||
logger.error(
|
||||
`Must set the hosted_zone_id.\n node ${argv["$0"]} delete --record_name <your_record_name> --hosted_zone_id <your_hosted_zone_id> \n node ${argv["$0"]} delete -n <your_record_name> -z <your_hosted_zone_id>`
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
const unmatched_dns_records = load_json("unmatched_dns_records.json");
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
let records_to_delete = unmatched_dns_records.splice(0, BATCH_SIZE);
|
||||
while (records_to_delete.length) {
|
||||
await delete_records_with_confirmation_prompt(records_to_delete);
|
||||
records_to_delete = unmatched_dns_records.splice(0, BATCH_SIZE);
|
||||
}
|
||||
logger.log("Finished.");
|
||||
}
|
||||
|
||||
async function delete_dns_record() {
|
||||
if (!argv.hosted_zone_id) {
|
||||
logger.error(
|
||||
`Must set the hosted_zone_id.\n node ${argv["$0"]} delete --record_name <your_record_name> --hosted_zone_id <your_hosted_zone_id> \n node ${argv["$0"]} delete -n <your_record_name> -z <your_hosted_zone_id>`
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
if (!argv.record_name) {
|
||||
logger.error(
|
||||
`Must set the record_name.\n node ${argv["$0"]} delete --record_name <your_record_name> --hosted_zone_id <your_hosted_zone_id> \n node ${argv["$0"]} delete -n <your_record_name> -z <your_hosted_zone_id>`
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
const dns_records = load_json("dns_records.json");
|
||||
const record = dns_records.find(function ({ Name }) {
|
||||
return Name === `${argv.record_name}.reticulum.io.`;
|
||||
});
|
||||
if (!record) {
|
||||
logger.log(
|
||||
`Could not find dns record with name ${argv.record_name}. Exiting...`
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
await delete_records_with_confirmation_prompt([record]);
|
||||
logger.log("Finished.");
|
||||
}
|
||||
|
||||
function main() {
|
||||
if (argv._.includes("fetch")) {
|
||||
fetch_aws_info();
|
||||
} else if (argv._.includes("filter")) {
|
||||
filter_dns_records();
|
||||
} else if (argv._.includes("delete")) {
|
||||
delete_dns_record();
|
||||
} else if (argv._.includes("delete-unmatched")) {
|
||||
delete_unmatched_dns_records();
|
||||
} else {
|
||||
logger.log("Unknown command.", argv._);
|
||||
logger.log("Try invoking --help");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "remove_dead_ip_records",
|
||||
"name": "check_dns",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
|
@ -140,6 +140,11 @@
|
|||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||
},
|
||||
"readline": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz",
|
||||
"integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw="
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"aws-sdk": "^2.821.0",
|
||||
"fs": "0.0.1-security",
|
||||
"path": "^0.12.7",
|
||||
"readline": "^1.3.0",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче