2015-12-11 13:14:27 -08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
exports = module.exports = waitForDns;
|
|
|
|
|
|
|
|
|
|
var assert = require('assert'),
|
|
|
|
|
async = require('async'),
|
2015-12-11 21:49:24 -08:00
|
|
|
debug = require('debug')('box:src/waitfordns'),
|
2016-04-22 15:56:05 -07:00
|
|
|
dns = require('native-dns'),
|
|
|
|
|
tld = require('tldjs');
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
// the first arg to callback is not an error argument; this is required for async.every
|
2016-04-22 15:48:26 -07:00
|
|
|
function isChangeSynced(domain, value, type, nameserver, callback) {
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof domain, 'string');
|
2016-04-22 15:48:26 -07:00
|
|
|
assert.strictEqual(typeof value, 'string');
|
|
|
|
|
assert.strictEqual(typeof type, 'string');
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof nameserver, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
// ns records cannot have cname
|
|
|
|
|
dns.resolve4(nameserver, function (error, nsIps) {
|
|
|
|
|
if (error || !nsIps || nsIps.length === 0) return callback(false);
|
|
|
|
|
|
|
|
|
|
async.every(nsIps, function (nsIp, iteratorCallback) {
|
|
|
|
|
var req = dns.Request({
|
2016-04-22 15:48:26 -07:00
|
|
|
question: dns.Question({ name: domain, type: type }),
|
2015-12-11 13:14:27 -08:00
|
|
|
server: { address: nsIp },
|
|
|
|
|
timeout: 5000
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
req.on('timeout', function () { return iteratorCallback(false); });
|
|
|
|
|
|
|
|
|
|
req.on('message', function (error, message) {
|
2016-04-22 15:48:26 -07:00
|
|
|
if (error) return iteratorCallback(false);
|
|
|
|
|
|
|
|
|
|
var answer = type === 'A' ? message.answer : message.data;
|
|
|
|
|
|
|
|
|
|
if (!answer || answer.length === 0) return iteratorCallback(false);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 15:48:26 -07:00
|
|
|
debug('isChangeSynced: ns: %s (%s), name:%s Actual:%j Expecting:%s', nameserver, nsIp, domain, answer[0], value);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 15:48:26 -07:00
|
|
|
if (answer[0].address !== value) return iteratorCallback(false);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
iteratorCallback(true); // done
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
req.send();
|
|
|
|
|
}, callback);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if IP change has propagated to every nameserver
|
2016-04-22 16:04:29 -07:00
|
|
|
function waitForDns(domain, value, type, callback) {
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof domain, 'string');
|
2016-04-22 15:48:26 -07:00
|
|
|
assert.strictEqual(typeof value, 'string');
|
|
|
|
|
assert(type === 'A' || type === 'CNAME');
|
2016-04-22 16:04:29 -07:00
|
|
|
assert.strictEqual(typeof callback, 'function');
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 15:56:05 -07:00
|
|
|
var zoneName = tld.getDomain(zoneName);
|
2016-04-22 15:48:26 -07:00
|
|
|
debug('waitForIp: domain %s to be %s in zone %s.', domain, value, zoneName);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 16:01:19 -07:00
|
|
|
var attempt = 1;
|
2016-04-22 16:04:29 -07:00
|
|
|
async.retry({ interval: 5000, times: Infinity }, function retryCallback() {
|
2016-04-22 16:01:19 -07:00
|
|
|
debug('waitForDNS: %s attempt %s.', domain, attempt++);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
dns.resolveNs(zoneName, function (error, nameservers) {
|
2016-04-22 16:01:19 -07:00
|
|
|
if (error || !nameservers) return retryCallback(error || new Error('Unable to get nameservers'));
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 15:48:26 -07:00
|
|
|
async.every(nameservers, isChangeSynced.bind(null, domain, value, type), function (synced) {
|
|
|
|
|
debug('waitForIp: %s %s ns: %j', domain, synced ? 'done' : 'not done', nameservers);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-22 16:01:19 -07:00
|
|
|
retryCallback(synced ? null : new Error('ETRYAGAIN'));
|
2015-12-11 13:14:27 -08:00
|
|
|
});
|
|
|
|
|
});
|
2016-04-22 16:01:19 -07:00
|
|
|
}, function retryDone(error) {
|
2015-12-11 13:14:27 -08:00
|
|
|
if (error) return callback(error);
|
|
|
|
|
|
|
|
|
|
debug('waitForDNS: %s done.', domain);
|
|
|
|
|
|
|
|
|
|
callback(null);
|
|
|
|
|
});
|
|
|
|
|
}
|