Commit ab3f90da authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1390] Merge branch 'master' into trac1390 with fixing conflicts:

	src/bin/xfrout/tests/xfrout_test.py.in
	src/bin/xfrout/xfrout.py.in
	src/bin/xfrout/xfrout_messages.mes
parents 3ff33cfe 710e8207
327. [func] jinmei
b10-xfrout now supports IXFR. (Right now there is no user
configurable parameter about this feature; b10-xfrout will
always respond to IXFR requests according to RFC1995).
Note also that Trac #1390 is necessary for outbound IXFR to work
in practice, so as of this writing this is not a user visible
feature.
(Trac #1371 and #1372, git 80c131f5b0763753d199b0fb9b51f10990bcd92b)
326. [build]* jinmei
Added a check script for the SQLite3 schema version. It will be
run at the beginning of 'make install', and if it detects an old
version of schema, installation will stop. You'll then need to
upgrade the database file by following the error message.
(Trac #1404, git a435f3ac50667bcb76dca44b7b5d152f45432b57)
325. [func] jinmei
Python isc.datasrc: added interfaces for difference management:
DataSourceClient.get_updater() now has the 'journaling' parameter
to enable storing diffs to the data source, and a new class
ZoneJournalReader was introduced to retrieve them, which can be
created by the new DataSourceClient.get_journal_reader() method.
(Trac #1333, git 3e19362bc1ba7dc67a87768e2b172c48b32417f5,
git 39def1d39c9543fc485eceaa5d390062edb97676)
324. [bug] jinmei
Fixed reference leak in the isc.log Python module. Most of all
BIND 10 Python programs had memory leak (even though the pace of
leak may be slow) due to this bug.
(Trac #1359, git 164d651a0e4c1059c71f56b52ea87ac72b7f6c77)
323. [bug] jinmei
b10-xfrout incorrectly skipped adding TSIG RRs to some
intermediate responses (when TSIG is to be used for the
responses). While RFC2845 optionally allows to skip intermediate
TSIGs (as long as the digest for the skipped part was included
in a later TSIG), the underlying TSIG API doesn't support this
mode of signing.
(Trac #1370, git 76fb414ea5257b639ba58ee336fae9a68998b30d)
322. [func] jinmei
datasrc: Added C++ API for retrieving difference of two versions
of a zone. A new ZoneJournalReader class was introduced for this
purpose, and a corresponding factory method was added to
DataSourceClient.
(Trac #1332, git c1138d13b2692fa3a4f2ae1454052c866d24e654)
321. [func]* jinmei
b10-xfrin now installs IXFR differences into the underlying data
source (if it supports journaling) so that the stored differences
can be used for subsequent IXFR-out transactions.
Note: this is a backward incompatibility change for older sqlite3
database files. They need to be upgraded to have a "diffs" table.
(Trac #1376, git 1219d81b49e51adece77dc57b5902fa1c6be1407)
320. [func]* vorner
The --brittle switch was removed from the bind10 executable. It didn't
work after the #213 change and the same effect can be accomplished by
declaring all components as core.
The --brittle switch was removed from the bind10 executable.
It didn't work after change #316 (Trac #213) and the same
effect can be accomplished by declaring all components as core.
(Trac #1340, git f9224368908dd7ba16875b0d36329cf1161193f0)
319. [func] naokikambe
......@@ -15,12 +70,12 @@
only for the XML documents but also is for the XSD and XSL documents.
(Trac #917, git b34bf286c064d44746ec0b79e38a6177d01e6956)
318. [func] stephen
318. [func] stephen
Add C++ API for accessing zone difference information in database-based
data sources.
(Trac #1330, git 78770f52c7f1e7268d99e8bfa8c61e889813bb33)
317. [func] vorner
317. [func] vorner
datasrc: the getUpdater method of DataSourceClient supports an optional
'journaling' parameter to indicate the generated updater to store diffs.
The database based derived class implements this extension.
......
SUBDIRS = doc src tests
SUBDIRS = compatcheck doc src tests
USE_LCOV=@USE_LCOV@
LCOV=@LCOV@
GENHTML=@GENHTML@
......
noinst_SCRIPTS = sqlite3-difftbl-check.py
# We're going to abuse install-data-local for a pre-install check.
# This is to be considered a short term hack and is expected to be removed
# in a near future version.
install-data-local:
$(PYTHON) sqlite3-difftbl-check.py \
$(localstatedir)/$(PACKAGE)/zone.sqlite3
This directory is a collection of compatibility checker programs.
They will be run before any other installation attempts on 'make install'
to see if the installation causes any substantial compatibility problems
with existing configuratons. If any checker program finds an issue,
'make install' will stop at that point.
#!@PYTHON@
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import os, sqlite3, sys
from optparse import OptionParser
usage = 'usage: %prog [options] db_file'
parser = OptionParser(usage=usage)
parser.add_option("-u", "--upgrade", action="store_true",
dest="upgrade", default=False,
help="Upgrade the database file [default: %default]")
(options, args) = parser.parse_args()
if len(args) == 0:
parser.error('missing argument')
db_file = args[0]
# If the file doesn't exist, there's nothing to do
if not os.path.exists(db_file):
sys.exit(0)
conn = sqlite3.connect(db_file)
cur = conn.cursor()
try:
# This can be anything that works iff the "diffs" table exists
cur.execute('SELECT name FROM diffs DESC LIMIT 1')
except sqlite3.OperationalError as ex:
# If it fails with 'no such table', create a new one or fail with
# warning depending on the --upgrade command line option.
if str(ex) == 'no such table: diffs':
if options.upgrade:
cur.execute('CREATE TABLE diffs (id INTEGER PRIMARY KEY, ' +
'zone_id INTEGER NOT NULL, ' +
'version INTEGER NOT NULL, ' +
'operation INTEGER NOT NULL, ' +
'name STRING NOT NULL COLLATE NOCASE, ' +
'rrtype STRING NOT NULL COLLATE NOCASE, ' +
'ttl INTEGER NOT NULL, rdata STRING NOT NULL)')
else:
sys.stdout.write('Found an older version of SQLite3 DB file: ' +
db_file + '\n' + "Perform '" + os.getcwd() +
"/sqlite3-difftbl-check.py --upgrade " +
db_file + "'\n" +
'before continuing install.\n')
sys.exit(1)
conn.close()
......@@ -816,6 +816,7 @@ AM_CONDITIONAL(INSTALL_CONFIGURATIONS, test x$install_configurations = xyes || t
AC_CONFIG_FILES([Makefile
doc/Makefile
doc/guide/Makefile
compatcheck/Makefile
src/Makefile
src/bin/Makefile
src/bin/bind10/Makefile
......@@ -937,6 +938,7 @@ AC_CONFIG_FILES([Makefile
tests/tools/badpacket/tests/Makefile
])
AC_OUTPUT([doc/version.ent
compatcheck/sqlite3-difftbl-check.py
src/bin/cfgmgr/b10-cfgmgr.py
src/bin/cfgmgr/tests/b10-cfgmgr_test.py
src/bin/cmdctl/cmdctl.py
......@@ -1016,6 +1018,7 @@ AC_OUTPUT([doc/version.ent
tests/system/ixfr/in-3/setup.sh
tests/system/ixfr/in-4/setup.sh
], [
chmod +x compatcheck/sqlite3-difftbl-check.py
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/xfrin/run_b10-xfrin.sh
chmod +x src/bin/xfrout/run_b10-xfrout.sh
......
......@@ -1369,20 +1369,72 @@ what if a NOTIFY is sent?
The <command>b10-xfrout</command> process is started by
<command>bind10</command>.
When the <command>b10-auth</command> authoritative DNS server
receives an AXFR request, <command>b10-xfrout</command>
sends the zone.
This is used to provide master DNS service to share zones
receives an AXFR or IXFR request, <command>b10-auth</command>
internally forwards the request to <command>b10-xfrout</command>,
which handles the rest of request processing.
This is used to provide primary DNS service to share zones
to secondary name servers.
The <command>b10-xfrout</command> is also used to send
NOTIFY messages to slaves.
NOTIFY messages to secondary servers.
</para>
<para>
A global or per zone <option>transfer_acl</option> configuration
can be used to control accessibility of the outbound zone
transfer service.
By default, <command>b10-xfrout</command> allows any clients to
perform zone transfers for any zones:
</para>
<screen>&gt; <userinput>config show Xfrout/transfer_acl</userinput>
Xfrout/transfer_acl[0] {"action": "ACCEPT"} any (default)</screen>
<para>
You can change this to, for example, rejecting all transfer
requests by default while allowing requests for the transfer
of zone "example.com" from 192.0.2.1 and 2001:db8::1 as follows:
</para>
<screen>&gt; <userinput>config set Xfrout/transfer_acl[0] {"action": "REJECT"}</userinput>
&gt; <userinput>config add Xfrout/zone_config</userinput>
&gt; <userinput>config set Xfrout/zone_config[0]/origin "example.com"</userinput>
&gt; <userinput>config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1"},</userinput>
<userinput> {"action": "ACCEPT", "from": "2001:db8::1"}]</userinput>
&gt; <userinput>config commit</userinput></screen>
<note><simpara>
The current development release of BIND 10 only supports
AXFR. (IXFR is not supported.)
Access control is not yet provided.
In the above example the lines
for <option>transfer_acl</option> were divided for
readability. In the actual input it must be in a single line.
</simpara></note>
<para>
If you want to require TSIG in access control, a separate TSIG
"key ring" must be configured specifically
for <command>b10-xfrout</command> as well as a system wide
key ring, both containing a consistent set of keys.
For example, to change the previous example to allowing requests
from 192.0.2.1 signed by a TSIG with a key name of
"key.example", you'll need to do this:
</para>
<screen>&gt; <userinput>config set tsig_keys/keys ["key.example:&lt;base64-key&gt;"]</userinput>
&gt; <userinput>config set Xfrout/tsig_keys/keys ["key.example:&lt;base64-key&gt;"]</userinput>
&gt; <userinput>config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}]</userinput>
&gt; <userinput>config commit</userinput></screen>
<para>
The first line of configuration defines a system wide key ring.
This is necessary because the <command>b10-auth</command> server
also checks TSIGs and it uses the system wide configuration.
</para>
<note><simpara>
In a future version, <command>b10-xfrout</command> will also
use the system wide TSIG configuration.
The way to specify zone specific configuration (ACLs, etc) is
likely to be changed, too.
</simpara></note>
<!--
TODO:
......
......@@ -92,51 +92,6 @@ VERSION = "bind10 20110223 (BIND 10 @PACKAGE_VERSION@)"
# This is for boot_time of Boss
_BASETIME = time.gmtime()
class RestartSchedule:
"""
Keeps state when restarting something (in this case, a process).
When a process dies unexpectedly, we need to restart it. However, if
it fails to restart for some reason, then we should not simply keep
restarting it at high speed.
A more sophisticated algorithm can be developed, but for now we choose
a simple set of rules:
* If a process was been running for >=10 seconds, we restart it
right away.
* If a process was running for <10 seconds, we wait until 10 seconds
after it was started.
To avoid programs getting into lockstep, we use a normal distribution
to avoid being restarted at exactly 10 seconds."""
def __init__(self, restart_frequency=10.0):
self.restart_frequency = restart_frequency
self.run_start_time = None
self.run_stop_time = None
self.restart_time = None
def set_run_start_time(self, when=None):
if when is None:
when = time.time()
self.run_start_time = when
sigma = self.restart_frequency * 0.05
self.restart_time = when + random.normalvariate(self.restart_frequency,
sigma)
def set_run_stop_time(self, when=None):
"""We don't actually do anything with stop time now, but it
might be useful for future algorithms."""
if when is None:
when = time.time()
self.run_stop_time = when
def get_restart_time(self, when=None):
if when is None:
when = time.time()
return max(when, self.restart_time)
class ProcessInfoError(Exception): pass
class ProcessInfo:
......@@ -151,7 +106,6 @@ class ProcessInfo:
self.env = env
self.dev_null_stdout = dev_null_stdout
self.dev_null_stderr = dev_null_stderr
self.restart_schedule = RestartSchedule()
self.uid = uid
self.username = username
self.process = None
......@@ -200,7 +154,6 @@ class ProcessInfo:
env=spawn_env,
preexec_fn=self._preexec_work)
self.pid = self.process.pid
self.restart_schedule.set_run_start_time()
# spawn() and respawn() are the same for now, but in the future they
# may have different functionality
......@@ -239,13 +192,7 @@ class BoB:
"""
self.cc_session = None
self.ccs = None
self.cfg_start_auth = True
self.cfg_start_resolver = False
self.cfg_start_dhcp6 = False
self.cfg_start_dhcp4 = False
self.curproc = None
# XXX: Not used now, waits for reintroduction of restarts.
self.dead_processes = {}
self.msgq_socket_file = msgq_socket_file
self.nocache = nocache
self.component_config = {}
......@@ -254,6 +201,9 @@ class BoB:
# inapropriate. But as the code isn't probably completely ready
# for it, we leave it at components for now.
self.components = {}
# Simply list of components that died and need to wait for a
# restart. Components manage their own restart schedule now
self.components_to_restart = []
self.runnable = False
self.uid = setuid
self.username = username
......@@ -825,7 +775,11 @@ class BoB:
# Tell it it failed. But only if it matters (we are
# not shutting down and the component considers itself
# to be running.
component.failed(exit_status);
component_restarted = component.failed(exit_status);
# if the process wants to be restarted, but not just yet,
# it returns False
if not component_restarted:
self.components_to_restart.append(component)
else:
logger.info(BIND10_UNKNOWN_CHILD_PROCESS_ENDED, pid)
......@@ -841,39 +795,22 @@ class BoB:
timeout value.
"""
# TODO: This is an artefact of previous way of handling processes. The
# restart queue is currently empty at all times, so this returns None
# every time it is called (thought is a relict that is obviously wrong,
# it is called and it doesn't hurt).
#
# It is preserved for archeological reasons for the time when we return
# the delayed restarts, most of it might be useful then (or, if it is
# found useless, removed).
next_restart = None
# if we're shutting down, then don't restart
if not self.runnable:
return 0
# otherwise look through each dead process and try to restart
still_dead = {}
still_dead = []
# keep track of the first time we need to check this queue again,
# if at all
next_restart_time = None
now = time.time()
for proc_info in self.dead_processes.values():
restart_time = proc_info.restart_schedule.get_restart_time(now)
if restart_time > now:
if (next_restart is None) or (next_restart > restart_time):
next_restart = restart_time
still_dead[proc_info.pid] = proc_info
else:
logger.info(BIND10_RESURRECTING_PROCESS, proc_info.name)
try:
proc_info.respawn()
self.components[proc_info.pid] = proc_info
logger.info(BIND10_RESURRECTED_PROCESS, proc_info.name, proc_info.pid)
except:
still_dead[proc_info.pid] = proc_info
# remember any processes that refuse to be resurrected
self.dead_processes = still_dead
# return the time when the next process is ready to be restarted
return next_restart
for component in self.components_to_restart:
if not component.restart(now):
still_dead.append(component)
if next_restart_time is None or\
next_restart_time > component.get_restart_time():
next_restart_time = component.get_restart_time()
self.components_to_restart = still_dead
return next_restart_time
# global variables, needed for signal handlers
options = None
......@@ -1056,10 +993,6 @@ def main():
while boss_of_bind.runnable:
# clean up any processes that exited
boss_of_bind.reap_children()
# XXX: As we don't put anything into the processes to be restarted,
# this is really a complicated NOP. But we will try to reintroduce
# delayed restarts, so it stays here for now, until we find out if
# it's useful.
next_restart = boss_of_bind.restart_processes()
if next_restart is None:
wait_time = None
......
......@@ -105,16 +105,10 @@ class TestBoB(unittest.TestCase):
self.assertEqual(bob.cc_session, None)
self.assertEqual(bob.ccs, None)
self.assertEqual(bob.components, {})
self.assertEqual(bob.dead_processes, {})
self.assertEqual(bob.runnable, False)
self.assertEqual(bob.uid, None)
self.assertEqual(bob.username, None)
self.assertEqual(bob.nocache, False)
self.assertEqual(bob.cfg_start_auth, True)
self.assertEqual(bob.cfg_start_resolver, False)
self.assertEqual(bob.cfg_start_dhcp4, False)
self.assertEqual(bob.cfg_start_dhcp6, False)
def test_init_alternate_socket(self):
bob = BoB("alt_socket_file")
......@@ -123,15 +117,10 @@ class TestBoB(unittest.TestCase):
self.assertEqual(bob.cc_session, None)
self.assertEqual(bob.ccs, None)
self.assertEqual(bob.components, {})
self.assertEqual(bob.dead_processes, {})
self.assertEqual(bob.runnable, False)
self.assertEqual(bob.uid, None)
self.assertEqual(bob.username, None)
self.assertEqual(bob.nocache, False)
self.assertEqual(bob.cfg_start_auth, True)
self.assertEqual(bob.cfg_start_resolver, False)
self.assertEqual(bob.cfg_start_dhcp4, False)
self.assertEqual(bob.cfg_start_dhcp6, False)
def test_command_handler(self):
class DummySession():
......
......@@ -14,8 +14,10 @@
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import unittest
import re
import shutil
import socket
import sqlite3
import sys
import io
from isc.testutils.tsigctx_mock import MockTSIGContext
......@@ -170,7 +172,8 @@ class MockDataSourceClient():
return (ZoneFinder.SUCCESS, dup_soa_rrset)
raise ValueError('Unexpected input to mock finder: bug in test case?')
def get_updater(self, zone_name, replace):
def get_updater(self, zone_name, replace, journaling=False):
self._journaling_enabled = journaling
return self
def add_rrset(self, rrset):
......@@ -1132,6 +1135,7 @@ class TestAXFR(TestXfrinConnection):
def test_do_xfrin(self):
self.conn.response_generator = self._create_normal_response_data
self.assertEqual(self.conn.do_xfrin(False), XFRIN_OK)
self.assertFalse(self.conn._datasrc_client._journaling_enabled)
def test_do_xfrin_with_tsig(self):
# use TSIG with a mock context. we fake all verify results to
......@@ -1283,6 +1287,7 @@ class TestIXFRResponse(TestXfrinConnection):
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
self.assertTrue(self.conn._datasrc_client._journaling_enabled)
self.assertEqual([], self.conn._datasrc_client.diffs)
check_diffs(self.assertEqual,
[[('delete', begin_soa_rrset), ('add', soa_rrset)]],
......@@ -1387,6 +1392,8 @@ class TestIXFRResponse(TestXfrinConnection):
answers=[soa_rrset, ns_rr, a_rr, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
# In the case AXFR-style IXFR, journaling must have been disabled.
self.assertFalse(self.conn._datasrc_client._journaling_enabled)
self.assertEqual([], self.conn._datasrc_client.diffs)
# The SOA should be added exactly once, and in our implementation
# it should be added at the end of the sequence.
......@@ -1540,6 +1547,19 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
self.assertEqual(1234, self.get_zone_serial())
# Also confirm the corresponding diffs are stored in the diffs table
conn = sqlite3.connect(self.sqlite3db_obj)
cur = conn.cursor()
cur.execute('SELECT name, rrtype, ttl, rdata FROM diffs ORDER BY id')
soa_rdata_base = 'master.example.com. admin.example.com. ' + \
'SERIAL 3600 1800 2419200 7200'
self.assertEqual(cur.fetchall(),
[(TEST_ZONE_NAME_STR, 'SOA', 3600,
re.sub('SERIAL', str(1230), soa_rdata_base)),
(TEST_ZONE_NAME_STR, 'SOA', 3600,
re.sub('SERIAL', str(1234), soa_rdata_base))])
conn.close()
def test_do_ixfrin_sqlite3_fail(self):
'''Similar to the previous test, but xfrin fails due to error.
......
......@@ -367,7 +367,10 @@ class XfrinIXFRDeleteSOA(XfrinState):
' RR is given in IXFRDeleteSOA state')
# This is the beginning state of one difference sequence (changes
# for one SOA update). We need to create a new Diff object now.
conn._diff = Diff(conn._datasrc_client, conn._zone_name)
# Note also that we (unconditionally) enable journaling here. The
# Diff constructor may internally disable it, however, if the
# underlying data source doesn't support journaling.
conn._diff = Diff(conn._datasrc_client, conn._zone_name, False, True)
conn._diff.delete_data(rr)
self.set_xfrstate(conn, XfrinIXFRDelete())
return True
......
......@@ -97,6 +97,31 @@
defines the maximum number of outgoing zone transfers
that can run concurrently. The default is 10.
</para>
<para>
<varname>tsig_key_ring</varname>
A list of TSIG keys (each of which is in the form of
name:base64-key[:algorithm]) used for access control on transfer
requests.
The default is an empty list.
</para>
<para>
<varname>transfer_acl</varname>
A list of ACL elements that apply to all transfer requests by
default (unless overridden in zone_config). See the BIND 10
guide for configuration examples.
The default is an element that allows any transfer requests.
</para>
<para>
<varname>zone_config</varname>
A list of JSON objects (i.e. maps) that define per zone
configuration concerning <command>b10-xfrout</command>.
The supported names of each object are "origin" (the origin
name of the zone), "class" (the RR class of the zone, optional,
default to "IN"), and "acl_element" (ACL only applicable to
transfer requests for that zone).
See the BIND 10 guide for configuration examples.
The default is an empty list, that is, no zone specific configuration.
</para>
<para>
<varname>log_name</varname>
<!-- TODO -->
......
......@@ -3,8 +3,8 @@ PYTESTS = xfrout_test.py
noinst_SCRIPTS = $(PYTESTS)
EXTRA_DIST = testdata/test.sqlite3
# This one is actually not necessary, but added for reference
EXTRA_DIST += testdata/example.com
# These are actually not necessary, but added for reference
EXTRA_DIST += testdata/example.com testdata/creatediff.py
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
......
#!/usr/bin/env python3.1
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''This script was used to create zone differences for IXFR tests.
The result was stored in the test SQLite3 database file, so this script
itself isn't necessary for testing. It's provided here for reference
purposes.
'''
import isc.datasrc
import isc.log
from isc.dns import *
from isc.testutils.rrset_utils import *
isc.log.init("dummy") # XXX
ZONE_NAME = Name('example.com')
NS_NAME_STR = 'a.dns.example.com'
NS_NAME = Name(NS_NAME_STR)
client = isc.datasrc.DataSourceClient('sqlite3',
'{ "database_file": "test.sqlite3" }')
# Install the initial data
updater = client.get_updater(ZONE_NAME, True)
updater.add_rrset(create_soa(2011111802))