-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
103 lines (88 loc) · 3.1 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const {promisify} = require('util');
const fs = require('fs');
const getExternalIP = promisify(require('external-ip')());
const {DNS} = require('@google-cloud/dns');
async function main() {
console.log('********************');
console.log(new Date().toISOString() + ' - updating dynamic dns entries');
// read and parse config
const config = JSON.parse(fs.readFileSync('./secrets/config.json', 'utf8'));
const {
projectId,
keyFileLocation,
zoneName,
dnsNames,
ttl,
} = config;
if (!projectId || !zoneName || !dnsNames || !ttl) throw new Error('config is missing some things!');
const dnsNamesSet = new Set(dnsNames);
if (!Number.isFinite(ttl) || ttl < 10 || ttl > 86400) throw new Error(`invalid TTL ${ttl}`);
// get external IP
const externalIp = await getExternalIP();
if (!externalIp) throw new Error(`failed to get external IP: ${externalIp}`);
console.log('external IP of this server was detected: ', externalIp);
// initialize DNS API
const dns = new DNS({
projectId,
keyFilename: keyFileLocation
});
// find the zone and records
const zone = await dns.zone(zoneName);
const records = (await zone.getRecords())[0];
// find existing records that match the DNS names we want to set
const recordsOfInterest = records.filter((record) => dnsNamesSet.has(record.name) && record.type === 'A');
// filter out records that already match our external IP and TTL (no need to modify them)
const recordsToModify = recordsOfInterest.filter((record) => {
if (
record.data && record.data[0] && record.data[0] === externalIp
&& record.metadata.ttl === ttl
) {
return false;
}
return true;
});
// modifying a record entails removing and then re-adding the record
const recordsToRemove = [...recordsToModify];
const modifiedRecords = recordsToModify.map((record) => {
return zone.record('a', {
name: record.name,
data: externalIp,
ttl: ttl,
});
});
// dns names are in the config that did not previously exist, create those records
const dnsNamesThatNeedToBeAdded = dnsNames.filter((dnsName) => !recordsOfInterest.find((record) => record.name === dnsName));
const newRecords = dnsNamesThatNeedToBeAdded.map((dnsName) => {
return zone.record('a', {
name: dnsName,
data: externalIp,
ttl: ttl
});
});
// join the records to add
const recordsToAdd = [
...newRecords,
...modifiedRecords,
];
if (!recordsToAdd.length && !recordsToRemove.length) {
console.log('no records to modify');
}
else {
recordsToRemove.forEach((record) => {
console.log(`removing record: ${record.name} | ${record.data} | ${record.metadata.ttl}`);
});
recordsToAdd.forEach((record) => {
console.log(`adding record: ${record.name} | ${record.data} | ${record.metadata.ttl}`);
});
// effect the change
const changeConfig = {
delete: recordsToRemove,
add: recordsToAdd,
};
const change = await zone.createChange(changeConfig);
console.log('change completed');
}
}
main()
.then(() => console.log('done'))
.catch((err) => console.error(err));