declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
declare(suffix, "info-all-master-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER')");
- declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=? and records.type='SOA' and records.disabled=0");
- declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=?'");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=?");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=? and name=? and type=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
- declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=? and records.type='SOA' and records.disabled=0");
- declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=?'");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=?");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=? and name=? and type=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=$1 where id=$2");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=$1 where id=$2");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER')");
- declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=$1 and records.type='SOA' and records.disabled=0");
- declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=$1'");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=$1 and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=$1");
declare(suffix, "delete-domain-query", "", "delete from domains where name=$1");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=$1");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=$1 and name=$2 and type=$3");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
- declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog:catalog and records.type='SOA' and records.disabled=0");
- declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog:catalog'");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog:catalog and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog:catalog");
declare(suffix, "delete-domain-query", "", "delete from domains where name=:domain");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype");
id = txn.get<0>(domain, di);
}
- if (!d_rwtxn || d_transactiondomainid != id) {
- throw DBException(std::string(__PRETTY_FUNCTION__) + " called without a proper transaction");
+ if (!d_rwtxn) {
+ throw DBException(std::string(__PRETTY_FUNCTION__) + " called without a transaction");
+ }
+ if (d_transactiondomainid != id) {
+ commitTransaction();
+ startTransaction(domain);
}
{ // Remove metadata
CatalogInfo ci;
ci.d_id = iter->id;
ci.d_zone = iter->zone;
+ ci.d_primaries = iter->masters;
try {
ci.fromJson(iter->options, type);
}
void fromJson(const std::string& json, CatalogType type);
std::string toJson() const;
+ void setType(CatalogType type) { d_type = type; }
void updateHash(CatalogHashMap& hashes, const DomainInfo& di) const;
DNSName getUnique() const { return DNSName(toBase32Hex(hashQNameWithSalt(std::to_string(d_id), 0, d_zone))); } // salt with domain id to detect recreated zones
uint32_t d_id;
DNSName d_zone, d_coo, d_unique;
std::set<std::string> d_group;
+ vector<ComboAddress> d_primaries;
private:
CatalogType d_type;
}
else if (type == CatalogInfo::CatalogType::Consumer) {
// clang-format off
- d_InfoProducerMembersQuery_stmt->
+ d_InfoConsumerMembersQuery_stmt->
bind("catalog", catalog)->
execute()->
getResult(d_result)->
throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of member zones: " + e.txtReason());
}
- for (const auto& row : d_result) { // id, zone, options
- ASSERT_ROW_COLUMNS("info-producer/consumer-members-query", row, 3);
+ for (const auto& row : d_result) { // id, zone, options, [master]
+ if (type == CatalogInfo::CatalogType::Producer) {
+ ASSERT_ROW_COLUMNS("info-producer/consumer-members-query", row, 3);
+ }
+ else {
+ ASSERT_ROW_COLUMNS("info-producer/consumer-members-query", row, 4);
+ }
CatalogInfo ci;
return false;
}
+ if (row.size() >= 4) { // Consumer only
+ vector<string> masters;
+ stringtok(masters, row[3], ", \t");
+ for (const auto& m : masters) {
+ try {
+ ci.d_primaries.emplace_back(m, 53);
+ }
+ catch (const PDNSException& e) {
+ g_log << Logger::Warning << "Could not parse master address '" << m << "' for zone '" << ci.d_zone << "': " << e.reason << endl;
+ members.clear();
+ return false;
+ }
+ }
+ }
+
members.emplace_back(ci);
}
return true;
int numDeltas{0};
};
+static bool catalogDiff(const DomainInfo& di, vector<CatalogInfo>& fromXFR, vector<CatalogInfo>& fromDB, const string& logPrefix)
+{
+ extern CommunicatorClass Communicator;
+
+ bool doTransaction{true};
+ bool inTransaction{false};
+ bool doOptions{false};
+ CatalogInfo ciCreate, ciRemove;
+ vector<CatalogInfo> retrieve;
+
+ try {
+ sort(fromXFR.begin(), fromXFR.end());
+ sort(fromDB.begin(), fromDB.end());
+
+ auto xfr = fromXFR.cbegin();
+ auto db = fromDB.cbegin();
+
+ while (xfr != fromXFR.end() || db != fromDB.end()) {
+ bool create{false};
+ bool remove{false};
+
+ if ((xfr != fromXFR.end() && db == fromDB.end()) || *xfr < *db) { // create
+ ciCreate = *xfr;
+ create = true;
+ ++xfr;
+ }
+ else if ((db != fromDB.end() && xfr == fromXFR.end()) || *db < *xfr) { // remove
+ ciRemove = *db;
+ remove = true;
+ ++db;
+ }
+ else {
+ CatalogInfo ciXFR = *xfr;
+ CatalogInfo ciDB = *db;
+ if (ciXFR.d_unique == ciDB.d_unique) { // update
+
+ if (ciXFR.d_coo != ciDB.d_coo) { // update coo
+ g_log << Logger::Warning << logPrefix << "update coo for zone '" << ciXFR.d_zone << "' to '" << ciXFR.d_coo << "'" << endl;
+ ciDB.d_coo = ciXFR.d_coo;
+ doOptions = true;
+ }
+
+ if (ciXFR.d_group != ciDB.d_group) { // update group
+ g_log << Logger::Warning << logPrefix << "update group for zone '" << ciXFR.d_zone << "' to '" << boost::join(ciXFR.d_group, ", ") << "'" << endl;
+ ciDB.d_group = ciXFR.d_group;
+ doOptions = true;
+ }
+
+ if (doOptions) { // update zone options
+ if (doTransaction && (inTransaction = di.backend->startTransaction(di.zone))) {
+ g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
+ doTransaction = false;
+ }
+
+ g_log << Logger::Warning << logPrefix << "update options for zone '" << ciXFR.d_zone << "'" << endl;
+ di.backend->setOptions(ciXFR.d_zone, ciDB.toJson());
+ }
+
+ if (di.masters != ciDB.d_primaries) { // update primaries
+ if (doTransaction && (inTransaction = di.backend->startTransaction(di.zone))) {
+ g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
+ doTransaction = false;
+ }
+
+ vector<string> primaries;
+ for (const auto& primary : di.masters) {
+ primaries.push_back(primary.toStringWithPortExcept(53));
+ }
+ g_log << Logger::Warning << logPrefix << "update primaries for zone '" << ciXFR.d_zone << "' to '" << boost::join(primaries, ", ") << "'" << endl;
+ di.backend->setMasters(ciXFR.d_zone, di.masters);
+
+ retrieve.emplace_back(ciXFR);
+ }
+ }
+ else { // reset
+ ciCreate = *xfr;
+ ciRemove = *db;
+ create = true;
+ remove = true;
+ }
+ ++xfr;
+ ++db;
+ }
+
+ DomainInfo d;
+ if (create && remove) {
+ g_log << Logger::Warning << logPrefix << "zone '" << ciCreate.d_zone << "' state reset" << endl;
+ }
+ else if (create && di.backend->getDomainInfo(ciCreate.d_zone, d)) { // detect clash
+ CatalogInfo ci;
+ ci.fromJson(d.options, CatalogInfo::CatalogType::Consumer);
+
+ if (di.zone != d.catalog && di.zone == ci.d_coo) {
+ if (ciCreate.d_unique == ci.d_unique) {
+ g_log << Logger::Warning << logPrefix << "zone '" << d.zone << "' owner change without state reset, old catalog '" << d.catalog << "', new catalog '" << di.zone << "'" << endl;
+
+ if (doTransaction && (inTransaction = di.backend->startTransaction(di.zone))) {
+ g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
+ doTransaction = false;
+ }
+
+ di.backend->setMasters(ciCreate.d_zone, di.masters);
+ di.backend->setOptions(ciCreate.d_zone, ciCreate.toJson());
+ di.backend->setCatalog(ciCreate.d_zone, di.zone);
+
+ retrieve.emplace_back(ciCreate);
+ continue;
+ }
+ g_log << Logger::Warning << logPrefix << "zone '" << d.zone << "' owner change with state reset, old catalog '" << d.catalog << "', new catalog '" << di.zone << "'" << endl;
+
+ ciRemove.d_zone = d.zone;
+ remove = true;
+ }
+ else {
+ g_log << Logger::Warning << logPrefix << "zone '" << d.zone << "' already exists";
+ if (!d.catalog.empty()) {
+ g_log << " in catalog '" << d.catalog;
+ }
+ g_log << "', create skipped" << endl;
+ continue;
+ }
+ }
+
+ if (remove) { // delete zone
+ if (doTransaction && (inTransaction = di.backend->startTransaction(di.zone))) {
+ g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
+ doTransaction = false;
+ }
+
+ g_log << Logger::Warning << logPrefix << "delete zone '" << ciRemove.d_zone << "'" << endl;
+ di.backend->deleteDomain(ciRemove.d_zone);
+
+ if (g_zoneCache.isEnabled()) {
+ g_zoneCache.remove(ciRemove.d_zone);
+ }
+ }
+
+ if (create) { // create zone
+ if (doTransaction && (inTransaction = di.backend->startTransaction(ciCreate.d_zone))) {
+ g_log << Logger::Warning << logPrefix << "backend transaction started" << endl;
+ doTransaction = false;
+ }
+
+ g_log << Logger::Warning << logPrefix << "create zone '" << ciCreate.d_zone << "'" << endl;
+ di.backend->createDomain(ciCreate.d_zone, DomainInfo::Slave, ciCreate.d_primaries, "");
+
+ di.backend->setMasters(ciCreate.d_zone, di.masters);
+ di.backend->setOptions(ciCreate.d_zone, ciCreate.toJson());
+ di.backend->setCatalog(ciCreate.d_zone, di.zone);
+
+ retrieve.emplace_back(ciCreate);
+
+ if (g_zoneCache.isEnabled()) {
+ if (di.backend->getDomainInfo(ciCreate.d_zone, d)) {
+ g_zoneCache.add(ciCreate.d_zone, d.id);
+ }
+ else {
+ g_log << Logger::Error << logPrefix << "new zone '" << ciCreate.d_zone << "' does not exists and was not inserted in the zone-cache" << endl;
+ }
+ }
+ }
+ }
+
+ if (inTransaction && di.backend->commitTransaction()) {
+ g_log << Logger::Warning << logPrefix << "backend transaction committed" << endl;
+ }
+
+ // retrieve new and updated zones with new primaries
+ auto masters = di.masters;
+ if (!masters.empty()) {
+ for (auto& ret : retrieve) {
+ shuffle(masters.begin(), masters.end(), pdns::dns_random_engine());
+ const auto& master = masters.front();
+ Communicator.addSuckRequest(ret.d_zone, master, SuckRequest::Notify);
+ }
+ }
+
+ return true;
+ }
+ catch (DBException& re) {
+ g_log << Logger::Error << logPrefix << "DBException " << re.reason << endl;
+ }
+ catch (PDNSException& pe) {
+ g_log << Logger::Error << logPrefix << "PDNSException " << pe.reason << endl;
+ }
+ catch (std::exception& re) {
+ g_log << Logger::Error << logPrefix << "std::exception " << re.what() << endl;
+ }
+
+ if (di.backend && inTransaction) {
+ g_log << Logger::Info << logPrefix << "aborting possible open transaction" << endl;
+ di.backend->abortTransaction();
+ }
+
+ return false;
+}
+
+static bool catalogProcess(const DomainInfo& di, vector<DNSResourceRecord>& rrs, string logPrefix)
+{
+ logPrefix += "Catalog-Zone ";
+
+ vector<CatalogInfo> fromXFR, fromDB;
+ std::unordered_set<DNSName> dupcheck;
+
+ // From XFR
+ bool hasSOA{false};
+ bool hasVersion{false};
+ bool zoneInvalid{false};
+
+ CatalogInfo ci;
+
+ vector<DNSResourceRecord> ret;
+
+ const auto compare = [](const DNSResourceRecord& a, const DNSResourceRecord& b) { return a.qname == b.qname ? a.qtype < b.qtype : a.qname.canonCompare(b.qname); };
+ sort(rrs.begin(), rrs.end(), compare);
+
+ DNSName rel;
+ DNSName unique;
+ for (auto& rr : rrs) {
+ if (di.zone == rr.qname) {
+ if (rr.qtype == QType::SOA) {
+ hasSOA = true;
+ continue;
+ }
+ }
+
+ else if (rr.qname == DNSName("version") + di.zone && rr.qtype == QType::TXT) {
+ if (rr.content == "\"2\"") {
+ hasVersion = true;
+ continue;
+ }
+ else {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "', unsupported catalog zone schema version " << rr.content << ", aborting" << endl;
+ return false;
+ }
+ }
+
+ else if (rr.qname.isPartOf(DNSName("zones") + di.zone)) {
+ if (rel.empty() && !hasVersion) {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "', catalog zone schema version missing, aborting" << endl;
+ return false;
+ }
+
+ rel = rr.qname.makeRelative(DNSName("zones") + di.zone);
+
+ if (rel.countLabels() == 1 && rr.qtype == QType::PTR) {
+ if (!unique.empty()) {
+ if (rel != unique) {
+ fromXFR.emplace_back(ci);
+ }
+ else {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "', duplicate unique '" << unique << "'" << endl;
+ zoneInvalid = true;
+ }
+ }
+
+ unique = rel;
+
+ ci = {};
+ ci.setType(CatalogInfo::CatalogType::Consumer);
+ ci.d_zone = DNSName(rr.content);
+ ci.d_unique = unique;
+
+ if (!dupcheck.insert(ci.d_zone).second) {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "', duplicate member zone'" << ci.d_zone << "'" << endl;
+ zoneInvalid = true;
+ }
+ }
+
+ else if (rel == (DNSName("coo") + unique) && rr.qtype == QType::PTR) {
+ if (!ci.d_coo.empty()) {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "', duplicate COO for unique '" << unique << "'" << endl;
+ zoneInvalid = true;
+ }
+ else {
+ ci.d_coo = DNSName(rr.content);
+ }
+ }
+ else if (rel == (DNSName("group") + unique) && rr.qtype == QType::TXT) {
+ std::string content = rr.content;
+ if (content.length() >= 2 && content.at(0) == '\"' && content.at(content.length() - 1) == '\"') { // TXT pain
+ content = content.substr(1, content.length() - 2);
+ }
+ ci.d_group.insert(content);
+ }
+ }
+ rr.disabled = true;
+ }
+ if (!ci.d_zone.empty()) {
+ fromXFR.emplace_back(ci);
+ }
+
+ if (!hasSOA || !hasVersion || zoneInvalid) {
+ g_log << Logger::Warning << logPrefix << "zone '" << di.zone << "' is invalid, skip updates" << endl;
+ return false;
+ }
+
+ // Get catalog ifo from db
+ if (!di.backend->getCatalogMembers(di.zone, fromDB, CatalogInfo::CatalogType::Consumer)) {
+ return false;
+ }
+
+ // Process
+ return catalogDiff(di, fromXFR, fromDB, logPrefix);
+}
void CommunicatorClass::ixfrSuck(const DNSName &domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, unique_ptr<AuthLua4>& pdl,
ZoneStatus& zs, vector<DNSRecord>* axfr)
DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
bool wrongDomainKind = false;
// this checks three error conditions & sets wrongDomainKind if we hit the third
- if(!B.getDomainInfo(domain, di) || !di.backend || (wrongDomainKind = true, !force && di.kind != DomainInfo::Slave)) { // di.backend and B are mostly identical
+ if (!B.getDomainInfo(domain, di) || !di.backend || (wrongDomainKind = true, !force && !di.isSecondaryType())) { // di.backend and B are mostly identical
if(wrongDomainKind)
- g_log<<Logger::Warning<<logPrefix<<"can't determine backend, not configured as slave"<<endl;
+ g_log << Logger::Warning << logPrefix << "can't determine backend, not configured as secondary" << endl;
else
g_log<<Logger::Warning<<logPrefix<<"can't determine backend"<<endl;
return;
g_log<<Logger::Notice<<logPrefix<<"retrieval finished"<<endl;
}
+ if (di.kind == DomainInfo::Consumer) {
+ if (!catalogProcess(di, rrs, logPrefix)) {
+ g_log << Logger::Warning << logPrefix << "Catalog-Zone update failed, only import records" << endl;
+ }
+ }
+
if(zs.isNSEC3) {
zs.ns3pr.d_flags = zs.optOutFlag ? 1 : 0;
}
echo "gmysql-dnssec" >> pdns-gmysql2.conf
fi
+ zones=0
for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | perl -e 'print reverse <STDIN>')
do
- mysql --user="$GMYSQL2USER" --password="$GMYSQL2PASSWD" --host="$GMYSQL2HOST" \
- "$GMYSQL2DB" -e "INSERT INTO domains (name, type, master) VALUES('$zone','SLAVE','127.0.0.1:$port')"
+ zones=$((zones+1))
+ if [ "$zone" = "example.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone $zone 127.0.0.1:$port
+ fi
+ if [ "$zone" = "test.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone $zone 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-catalog $zone other-catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-options $zone '{"consumer":{"coo":"catalog.invalid","unique":"42"}}'
+ fi
if [ "$zone" = "tsig.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone $zone 127.0.0.2:$port
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-catalog $zone catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-options $zone "{\"consumer\":{\"unique\":\"$($SAXFR 127.0.0.1 $port catalog.invalid | grep $zone | grep PTR | cut -d'.' -f1)\"}}"
$PDNSUTIL --config-dir=. --config-name=gmysql2 import-tsig-key test $ALGORITHM $KEY
$PDNSUTIL --config-dir=. --config-name=gmysql2 activate-tsig-key tsig.com test slave
fi
if [ "$zone" = "stest.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone $zone 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-catalog $zone other-catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-options $zone "{\"consumer\":{\"coo\":\"catalog.invalid\",\"unique\":\"$($SAXFR 127.0.0.1 $port catalog.invalid | grep $zone | grep PTR | cut -d'.' -f1)\"}}"
if [[ $skipreasons != *nolua* ]]; then
$PDNSUTIL --config-dir=. --config-name=gmysql2 set-meta stest.com AXFR-SOURCE 127.0.0.2
fi
fi
+ if [ "$zone" = "." ]; then
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone $zone 127.0.0.1:$port
+ fi
done
+ # setup catalog zone
+ if [ $zones -ne 1 ] # detect root tests
+ then
+ zones=$((zones+1))
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone catalog.invalid 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-kind catalog.invalid consumer
+
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 create-slave-zone remove.invalid 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=gmysql2 set-catalog remove.invalid catalog.invalid
+ fi
+
port=$((port+100))
$RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --config-dir=. \
while [ $loopcount -lt 30 ]
do
sleep 5
- todo=$(mysql --user="$GMYSQL2USER" --password="$GMYSQL2PASSWD" --host="$GMYSQL2HOST" \
- "$GMYSQL2DB" -ss -e 'SELECT COUNT(id) FROM domains WHERE last_check IS NULL')
- if [ $todo = 0 ]
+ present=$(mysql --user="$GMYSQL2USER" --password="$GMYSQL2PASSWD" --host="$GMYSQL2HOST" \
+ "$GMYSQL2DB" -ss -e "SELECT COUNT(DISTINCT(name)) FROM records WHERE type='SOA'")
+ if [ $present -eq $zones ]
then
break
fi
let loopcount=loopcount+1
done
- if [ $todo -ne 0 ]
+ if [ $present -ne $zones ]
then
echo "AXFR FAILED" >> failed_tests
exit
godbc-get-tsig-keys-query=select name,algorithm, secret from tsigkeys
godbc-publish-domain-key-query=update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?
godbc-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=? and domain_id=?
-godbc-info-all-master-query=select id,name,master,last_check,notified_serial,type from domains where type='MASTER'
-godbc-info-all-slaves-query=select id,name,master,last_check from domains where type='SLAVE'
-godbc-info-zone-query=select id,name,master,last_check,notified_serial,type,account from domains where name=?
+godbc-info-all-master-query=select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')
+godbc-info-all-slaves-query=select domains.id, domains.name, domains.type, domains.master, domains.last_check, records.content from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name where domains.type in ('SLAVE', 'CONSUMER')
+godbc-info-zone-query=select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=?
+godbc-info-producer-members-query=select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0
+godbc-info-consumer-members-query=select id, name, options, master from domains where type='SLAVE' and catalog=?
godbc-insert-comment-query=INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)
godbc-insert-empty-non-terminal-order-query=insert into records (type,domain_id,disabled,name,ordername,auth,ttl,prio,content) values (null,?,0,?,?,?,null,null,null)
godbc-insert-record-query=insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (?,?,?,?,?,?,?,?,?)
zones=0
for zone in $(grep 'zone ' named.conf | cut -f2 -d\" | grep -v '^nztest.com$' | perl -e 'print reverse <STDIN>')
do
- let zones=zones+1
- $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.1:$port
+ zones=$((zones+1))
+ if [ "$zone" = "example.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.1:$port
+ fi
+ if [ "$zone" = "test.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-catalog $zone other-catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-options $zone '{"consumer":{"coo":"catalog.invalid","unique":"42"}}'
+ fi
if [ "$zone" = "tsig.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.2:$port
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-catalog $zone catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-options $zone "{\"consumer\":{\"unique\":\"$($SAXFR 127.0.0.1 $port catalog.invalid | grep $zone | grep PTR | cut -d'.' -f1)\"}}"
$PDNSUTIL --config-dir=. --config-name=lmdb2 import-tsig-key test $ALGORITHM $KEY
$PDNSUTIL --config-dir=. --config-name=lmdb2 activate-tsig-key tsig.com test slave
fi
if [ "$zone" = "stest.com" ]; then
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-catalog $zone other-catalog.invalid
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-options $zone "{\"consumer\":{\"coo\":\"catalog.invalid\",\"unique\":\"$($SAXFR 127.0.0.1 $port catalog.invalid | grep $zone | grep PTR | cut -d'.' -f1)\"}}"
if [[ $skipreasons != *nolua* ]]; then
$PDNSUTIL --config-dir=. --config-name=lmdb2 set-meta stest.com AXFR-SOURCE 127.0.0.2
fi
fi
+ if [ "$zone" = "." ]; then
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone $zone 127.0.0.1:$port
+ fi
done
+ # setup catalog zone
+ if [ $zones -ne 1 ] # detect root tests
+ then
+ zones=$((zones+1))
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone catalog.invalid 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-kind catalog.invalid consumer
+
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 create-slave-zone remove.invalid 127.0.0.1:$port
+ $PDNSUTIL --config-dir=. --config-name=lmdb2 set-catalog remove.invalid catalog.invalid
+ fi
+
port=$((port+100))
$RUNWRAPPER $PDNS2 --daemon=no --local-port=$port --config-dir=. \