BIND 10 trac2157_merge, updated. 946c4e8afa9647ee9a3e4481e66760512ce556e0 Merge branch 'master' into trac2157_merge
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Feb 13 09:04:46 UTC 2013
The branch, trac2157_merge has been updated
via 946c4e8afa9647ee9a3e4481e66760512ce556e0 (commit)
via 6409bf0fb2fcb3d60c664009be730f1a71fdac54 (commit)
via 3a3c7f52a1da822814cbd742a565ac4ed9c801d9 (commit)
via 24b3e0cb75ea0a1f6b22fc91d679313ed7a6468f (commit)
via abe78fae4ba3aca5eb01806dd4e05607b1241745 (commit)
via 06ab4db18f6a852f81d5253686d7f9006e6bc27f (commit)
via b4b8c1e5392a8aeee4402bc97f776cfc889f43c6 (commit)
via 24c235cb1b379c6472772d340e21577c3460b742 (commit)
via 70632300d70401c696161dff39ad126ff98663df (commit)
via 894e0ca1da8ca1a1f572a0e0d0a4f91102827d67 (commit)
via 3132b8b19495470bbfd0f2ba0fe7da443926034b (commit)
via 4982a87469884b80b077ec4ad9dc5445aeea6dc3 (commit)
via 1cbacf19a28bdae50bb9bd3767bca0147fde37ed (commit)
via 88b964a46c18be801102503b45d8256f26d3a3d0 (commit)
via 1197c10bcfc5b9a47054a7dc98cb797c14175053 (commit)
via 97371cff7f91db7556294ce559aed170a718dc4c (commit)
via b57fc0894581ef07334a8f6c5bd0a6129d5289a1 (commit)
via 54bbed5fcbe237c5a49b515ae4c55148723406ce (commit)
via aff7100abe378e77ed36e6239a82ca483bcd2288 (commit)
via 87ce14cdb121b37afb5b1931af51bed7f6323dd6 (commit)
via cf0ce4bad603660b8f0d98e76414fd5b3572e2c8 (commit)
via 227f2b1dab3ee9739e1c8671ca242313ad4eb796 (commit)
via b8d6b949eb7f4705e32fbdfd7694ca2e6a6a5cdc (commit)
via 5f9c4eec3c69bb08684969ea118a1eb00cf8dd1b (commit)
via ea110815f2864c353ac69ba54dd837987890d496 (commit)
via 12071a88b91b30fada5848868fc3ecd173785b37 (commit)
via e090b84bd5e2d79d7730563beda5e95140c5d03d (commit)
via e6f86f2f5eec8e6003c13d36804a767a840d96d6 (commit)
via 8d1f4d45b8998de8ca478a1bb600b8cbb88e4a31 (commit)
via 3f272be09aadc78d27333ddeba66ba7e9de25f1f (commit)
via 52f22bb0132d78d07145fec0f1fde03069f7e5fa (commit)
via 3e367ff100f7d1b76ec8743385917ba747b9ad34 (commit)
via 72106475f625075e3e49bdba04e6f9f26b105294 (commit)
via 5aa5b4e403893b1de767cea00b4a3f9d9a17422e (commit)
via 5950991881a51d5b88ec6234d310adda43e11e8a (commit)
via dd2dbeb5a4507ba50ce1547972ab4ea1b56b4655 (commit)
via daf2abe68ce9c111334a15c14e440730f3a085e2 (commit)
via 1eef52e751a97720ba679256b24b2c90ed98b5fd (commit)
via 7782afcefe47162534a377769d9eda2c0fa960ff (commit)
via 660a0d164feaf055677f375977f7ed327ead893e (commit)
via e540ba5b43c265fff937245932c06ed501859574 (commit)
via 50e61198ea74d395b0bc9015c9f01ff29e357e48 (commit)
via aa5b7e1214e00019776d7bab0cf49df604d2a7e9 (commit)
via be156ccbf943ec27f2174e4cfe11f2f67e9b2975 (commit)
via d14e31cb67c834948664d5d958984bdc3aa2cf8b (commit)
via 52b0979f34d6def45fe8a618d4cc79f724d514d7 (commit)
via 9a9b17823a2c57e3013f4f6da055f2a7cc48c289 (commit)
via 9b16b116c909bedfc1353147f3948ba19f42fb5a (commit)
via 1d0c2004865d1bf322bf78d13630d992e39179fd (commit)
via dd447189c8e307c305415a34894c48972cea5a2c (commit)
via b4de3233542a0c98c04c0cf730bd8222efe897b7 (commit)
via 1a80b1dd71902c7942e11316b53c6cba4a16565d (commit)
via 59c744cf4838c919abe8763501208e02aff9526d (commit)
via b5e2be95d21ed750ad7cf5e15de2058aa8bc45f4 (commit)
via 1d6a2e3fb2715b445ce835847d7d353886495fea (commit)
via 964547642571d9146219cf2f9d6e08fa03970a81 (commit)
via a12aed4bde955f0edb68717ee23895bbc78baccf (commit)
via ac75b8db7bb9c0b104672d0987d98ec8055c698c (commit)
via 3fa52fbaed9589ecad689ccf105bbf7365d26d62 (commit)
via 55f8f410621028a556a3b0af8d2d41bc0f60b08e (commit)
via 4d6818eb58a726d0abd92a171a0f18334a9eb3b7 (commit)
via 530f569e47b06f49402611bda07e1956cdf04a24 (commit)
via da67c0642c9403f08e278e2424bc7bfde74e034a (commit)
via 6f83737a9b9deaacd5ce0799cbda9e18fdb81c4b (commit)
via 4c439a4cca7768510b4549c73e0f43120d4c9739 (commit)
via fbf11f41c327130fbdb39fcf64daa16f278eb197 (commit)
via 733d42fa3d0b0b0f426a4817dcd022c764158d0d (commit)
via e5005185351cf73d4a611407c2cfcd163f80e428 (commit)
via bfefbfda28cb512b12643555790149b7c64414f3 (commit)
via 4d074c3e7048f8dde151e078bee4967949d3b32e (commit)
via f7a26a8f9ee4adf64d754e6c2a6c07977854c40c (commit)
via 89fbc1a1f41da33150176d8d0ba83ae8e88a03da (commit)
via 3b03a16056601b26d27db3a4cd0baced7e4ba756 (commit)
via 564f4b8990e4759f57033f4fc9de2359e3baf829 (commit)
via 005cba1c8d62e2f44ad05b512ac9b7be639da725 (commit)
via d85b2e22c5c45050d3191ee73c508bbd3cd1251f (commit)
via db77f1f08e569fc378c1e63361503773f9b9e85e (commit)
via 2284240947b4871b246d6d3a4be073dcb560325d (commit)
via aeda8e4862687e5ecd870a520616b734fa910b39 (commit)
via 64fb39c963cd9e6494f71dfe14d9dabdf869fdc8 (commit)
via 3a185f59245200be3c6b2e86340ac1c2ae464efb (commit)
via b43c93c8cb4e0256677c01d5f649093fc27c998a (commit)
via ffd4a283b18f8eaa453712e1e615e2440b12aa0d (commit)
via 0749f9e194505698031990eb7c544e8ec076fe10 (commit)
via 39c1d353784c56ac2f1c42836348393b7d80303e (commit)
via 2a1d32f1610c1b99a2b6bcfdf350fcf123c51e19 (commit)
via d76159997442d71928d459041d46d89a01fbdefc (commit)
via ebeb7923963456d7f62721327290b75572ab4279 (commit)
via aa4dcd59d930af330b7f082c40a395d0bc424d97 (commit)
via 8df1853f98c6fdfbdc186062426904d047259d53 (commit)
via 1ec905f87eaebf01ae956b1ec5ac05afbfae9836 (commit)
via 8b2f7c325534431cb4f6cca82c5d314583e03248 (commit)
via 6dc113cc0e20a4781ad0f991871966d244371440 (commit)
via 28c7d972110b86833c31631d563b07a2824efbab (commit)
via 3c200a3decdd5bbc30bbdb9c81f9f206eda98ad9 (commit)
via 6b09c6be32b221b73a05f98de7814c650597883a (commit)
via 3188ee1246e7e1b52b334cfa6edb04d2123ea759 (commit)
via 076dad2aada1624b0b632e4eee3e6a1907c51a16 (commit)
via cb95ae3f178ce497a8dce0aad4173a8586dc9ca2 (commit)
via f07dbb59715b26afeef7ff682bba887187ad169b (commit)
via b1f09a967614c9668bedc3d877bb12f1622222f1 (commit)
via db90d30b97219e365c3643fd6c79878eaf1ac518 (commit)
via 9a7c7bf6690bf3a6d85b5f3dc802d819825b3955 (commit)
via 2eeab2ebf0b7e9de2a7c73e553572dbc313d06a7 (commit)
via 78b66fd894cd71185baeef5f4eddce6c9572278e (commit)
via a272beeb913cd0adaf04080b0f4284e1510085a6 (commit)
via 0b249de43aad4472b98dfb147a7f3ac1c15c1d3c (commit)
via 00116a66e0d365563789ff4ed56cb3a08cb95156 (commit)
via a08b7575e7d42740c3f659087420472753bbee16 (commit)
via c274bccc9c7ab201ac00f09896b2511791556278 (commit)
via 20f13469624c75aa090ad74f5ce2518adf826f01 (commit)
via 53dec20f027b589c2202f182a01d8e33ef15c2a9 (commit)
via 463700b34d94d933cc4244480e46f975c798d777 (commit)
via f575d8fc0316d69b2ea54788b43948488dface2e (commit)
via 0479cb528e77e29f67b3a05ed79a83c2ef483455 (commit)
via d985d0dde44a6c4b090cf211c295ab10a65924e1 (commit)
via 4f0716782cba2f94c577e80cc23e4759b2440907 (commit)
via 56e9d0e542d1396e9d0f373bb8cc1fd5d0a945fe (commit)
via 3f74193c572fefc2e718ca0952962494a9680ddb (commit)
via ba7573eb62566aece58b514dfcb3b5a322adfed1 (commit)
via 83b06fb184c17f70a28ab307347e9eb075ee048d (commit)
via 1ec1ffb481e68fdd06d04fa38aaf6b4348669649 (commit)
via 6ad900eeff1c9e2c704dd5259565c28b8846aa37 (commit)
via 62bb1c4ddcb01d285edfdb04016d710597c708e7 (commit)
via 521189be3a1dc89fc9010dfa9fa13a31ee233a38 (commit)
via 1e2111996aa44a583fcdf0997a6aa170542f3ea2 (commit)
via fc03d665a777c47920a85bae41f3e359c61fa42e (commit)
via 2a9656fb9ac69e87273f14f4a6807986ee9739a8 (commit)
via 3d1ea31fe2461f28b7337c78623834eb987c73a5 (commit)
via 388c202a9b3c95f3d8d1aa0c76803b1f398974f3 (commit)
via 368ceac8bfb49a0bd4c0a0c98fe624d623de9c6d (commit)
from e5e511b58b6ad59b3d79f19c2f7d18b0a6843273 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 946c4e8afa9647ee9a3e4481e66760512ce556e0
Merge: e5e511b 6409bf0
Author: Yoshitaka Aharen <aharen at jprs.co.jp>
Date: Wed Feb 13 18:04:32 2013 +0900
Merge branch 'master' into trac2157_merge
Conflicts:
ChangeLog
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 92 ++
configure.ac | 29 +-
doc/guide/bind10-guide.xml | 971 ++++++++++++++++++--
src/bin/auth/auth_config.cc | 2 +-
src/bin/auth/auth_messages.mes | 6 +-
src/bin/auth/auth_srv.cc | 6 +-
src/bin/auth/query.cc | 20 +-
src/bin/auth/tests/config_unittest.cc | 2 +-
src/bin/auth/tests/query_unittest.cc | 87 +-
src/bin/auth/tests/testdata/example-base-inc.zone | 19 +-
src/bin/auth/tests/testdata/example-nsec3-inc.zone | 2 +-
src/bin/bind10/bind10.in | 13 +-
src/bin/bind10/init.py.in | 1 +
src/bin/bind10/tests/Makefile.am | 2 +-
.../tests/{bind10_test.py.in => init_test.py.in} | 2 +-
src/bin/bindctl/bindcmd.py | 2 +-
src/bin/bindctl/run_bindctl.sh.in | 2 +-
src/bin/ddns/ddns.py.in | 8 +-
src/bin/ddns/ddns_messages.mes | 4 +-
src/bin/ddns/tests/ddns_test.py | 34 +-
src/bin/dhcp4/Makefile.am | 10 +-
src/bin/dhcp4/config_parser.cc | 4 +-
src/bin/dhcp4/dhcp4_messages.mes | 7 +-
src/bin/dhcp4/dhcp4_srv.cc | 141 ++-
src/bin/dhcp4/dhcp4_srv.h | 9 -
src/bin/dhcp4/tests/Makefile.am | 10 +-
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 8 +-
src/bin/dhcp6/Makefile.am | 10 +-
src/bin/dhcp6/config_parser.cc | 4 +-
src/bin/dhcp6/dhcp6_messages.mes | 29 +-
src/bin/dhcp6/dhcp6_srv.cc | 163 ++--
src/bin/dhcp6/dhcp6_srv.h | 10 -
src/bin/dhcp6/tests/Makefile.am | 10 +-
src/bin/dhcp6/tests/config_parser_unittest.cc | 2 +-
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 3 +-
src/bin/loadzone/loadzone.py.in | 2 +-
src/bin/loadzone/tests/loadzone_test.py | 6 +-
src/bin/msgq/msgq.py.in | 8 +-
src/bin/msgq/msgq_messages.mes | 8 +-
src/bin/resolver/resolver.cc | 13 +-
src/bin/resolver/resolver_messages.mes | 13 +-
src/bin/sockcreator/tests/sockcreator_tests.cc | 9 +-
src/bin/stats/stats.py.in | 3 +-
src/bin/stats/stats_httpd.py.in | 8 +-
src/bin/stats/stats_httpd_messages.mes | 2 +-
src/bin/stats/tests/b10-stats-httpd_test.py | 2 +
src/bin/stats/tests/b10-stats_test.py | 4 +
src/bin/sysinfo/run_sysinfo.sh.in | 14 +-
src/bin/xfrin/tests/xfrin_test.py | 296 +++---
src/bin/xfrin/xfrin.py.in | 62 +-
src/bin/xfrin/xfrin_messages.mes | 4 -
src/bin/xfrout/tests/xfrout_test.py.in | 122 +--
src/bin/xfrout/xfrout.py.in | 68 +-
src/bin/xfrout/xfrout_messages.mes | 2 +-
src/lib/asiodns/tcp_server.cc | 1 -
src/lib/asiodns/tcp_server.h | 1 -
src/lib/asiodns/udp_server.cc | 7 +-
src/lib/cc/data.cc | 10 +-
src/lib/config/tests/ccsession_unittests.cc | 2 +
src/lib/datasrc/memory/zone_finder.cc | 10 +-
src/lib/datasrc/memory_datasrc.cc | 1 +
src/lib/datasrc/sqlite3_accessor.cc | 3 +
.../datasrc/tests/memory/zone_finder_unittest.cc | 50 +-
src/lib/dhcpsrv/alloc_engine.cc | 358 ++++----
src/lib/dhcpsrv/dhcpdb_create.mysql | 14 +-
src/lib/dhcpsrv/dhcpsrv_messages.mes | 40 +
src/lib/dhcpsrv/lease_mgr.cc | 13 +-
src/lib/dhcpsrv/mysql_lease_mgr.cc | 25 +-
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc | 11 +-
src/lib/dns/Makefile.am | 4 +
src/lib/dns/gen-rdatacode.py.in | 118 ++-
src/lib/dns/master_loader.cc | 1 +
src/lib/dns/name.cc | 1 -
src/lib/dns/python/opcode_python.cc | 140 ---
src/lib/dns/python/pydnspp.cc | 230 +++--
src/lib/dns/python/rcode_python.cc | 146 ---
src/lib/dns/python/rrclass_python.cc | 43 -
src/lib/dns/python/rrtype_python.cc | 144 ---
src/lib/dns/python/tests/edns_python_test.py | 6 +-
src/lib/dns/python/tests/message_python_test.py | 34 +-
.../python/tests/messagerenderer_python_test.py | 8 +-
src/lib/dns/python/tests/nsec3hash_python_test.py | 46 +-
src/lib/dns/python/tests/opcode_python_test.py | 82 +-
src/lib/dns/python/tests/rcode_python_test.py | 60 +-
src/lib/dns/python/tests/rrclass_python_test.py | 20 +-
.../python/tests/rrset_collection_python_test.py | 46 +-
src/lib/dns/python/tests/rrtype_python_test.py | 44 +-
src/lib/dns/python/tests/tsig_python_test.py | 36 +-
src/lib/dns/python/tests/tsigerror_python_test.py | 26 +-
.../dns/python/tests/zone_checker_python_test.py | 61 +-
src/lib/dns/rdata/template.h | 4 +
src/lib/dns/rrclass-placeholder.h | 14 -
src/lib/dns/rrtype-placeholder.h | 30 -
src/lib/dns/tests/rrclass_unittest.cc | 25 +
src/lib/dns/tests/rrset_unittest.cc | 2 +-
src/lib/dns/tests/rrtype_unittest.cc | 53 ++
src/lib/python/isc/__init__.py | 10 +-
.../python/isc/datasrc/tests/clientlist_test.py | 10 +-
src/lib/python/isc/datasrc/tests/datasrc_test.py | 140 +--
.../python/isc/datasrc/tests/zone_loader_test.py | 5 +-
src/lib/python/isc/ddns/libddns_messages.mes | 4 +-
src/lib/python/isc/ddns/session.py | 118 +--
src/lib/python/isc/ddns/tests/session_tests.py | 615 ++++++-------
src/lib/python/isc/ddns/tests/zone_config_tests.py | 14 +-
src/lib/python/isc/notify/notify_out.py | 18 +-
src/lib/python/isc/notify/tests/notify_out_test.py | 14 +-
src/lib/python/isc/server_common/dns_tcp.py | 2 +-
.../isc/server_common/server_common_messages.mes | 2 +-
.../python/isc/statistics/tests/counters_test.py | 6 +-
src/lib/python/isc/sysinfo/sysinfo.py | 15 +-
src/lib/python/isc/testutils/rrset_utils.py | 26 +-
src/lib/python/isc/xfrin/diff.py | 10 +-
src/lib/python/isc/xfrin/tests/diff_tests.py | 60 +-
src/lib/resolve/recursive_query.cc | 2 +-
src/lib/resolve/resolve_messages.mes | 2 +-
src/lib/util/io/socketsession.cc | 2 +-
src/lib/util/unittests/fork.cc | 10 +-
src/lib/util/unittests/fork.h | 4 +-
tests/tools/perfdhcp/command_options.cc | 16 +-
tests/tools/perfdhcp/command_options.h | 8 +-
tests/tools/perfdhcp/main.cc | 8 +-
tools/query_cmp/src/lib/handledns.py | 2 +-
122 files changed, 3179 insertions(+), 2284 deletions(-)
rename src/bin/bind10/tests/{bind10_test.py.in => init_test.py.in} (99%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 1506747..c85262f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,98 @@ TBD. [func]* y-aharen
git 61d7c3959eb991b22bc1c0ef8f4ecb96b65d9325)
(Trac #2157, git TBD)
+579. [bug] jinmei
+ libdatasrc/b10-auth: corrected some corner cases in query handling
+ of in-memory data source that led to the following invalid/odd
+ responses from b10-auth:
+ - duplicate RRs in answer and additional for type ANY query
+ - incorrect NSEC for no error, no data (NXRRSET) response that
+ matches a wildcard
+ (Trac #2585, git abe78fae4ba3aca5eb01806dd4e05607b1241745)
+
+578. [bug] jinmei
+ b10-auth now returns closest encloser NSEC3 proof to queries for
+ an empty non terminal derived from an Opt-Out NSEC RR, as clarified
+ in errata 3441 for RFC5155. Previously it regarded such case as
+ broken zone and returned SERVFAIL.
+ (Trac #2659, git 24c235cb1b379c6472772d340e21577c3460b742)
+
+577. [func] muks
+ Added an SQLite3 index on records(rname, rdtype). This decreases
+ insert performance by ~28% and adds about ~20% to the file size,
+ but increases zone iteration performance. As it introduces a new
+ index, a database upgrade would be required.
+ (Trac #1756, git 9b3c959af13111af1fa248c5010aa33ee7e307ee)
+
+576. [bug] tmark, tomek
+ b10-dhcp6: Fixed bug when the server aborts operation when
+ receiving renew and there are no IPv6 subnets configured.
+ (Trac 2719, git 3132b8b19495470bbfd0f2ba0fe7da443926034b)
+
+575. [bug] marcin
+ b10-dhcp6: Fixed the bug whereby the subnet for the incoming
+ packet was selected using only its source address. The subnet
+ is now selected using either source address or the name of the
+ server's interface on which the packet has been received.
+ (Trac #2704, git 1cbacf19a28bdae50bb9bd3767bca0147fde37ed)
+
+574. [func] tmark
+ b10-dhcp4, b10-dhcp6: Composite key indexes were added to the lease
+ tables to reduce lease search time. The lease4 table now has two
+ additional indexes: a) hwaddr/subnet_id and b) client_id/subnet_id.
+ The lease6 now has the one additional index: iaid/subnet_id/duid.
+ Adding these indexes significantly improves lease acquisition
+ performance.
+ (Trac #2699,#2703, git 54bbed5fcbe237c5a49b515ae4c55148723406ce)
+
+573. [bug] stephen
+ Fixed problem whereby the DHCP server crashed if it ran out of
+ addresses. Such a condition now causes a packet to be returned
+ to the client refusing the allocation of an address.
+ (Trac #2681, git 87ce14cdb121b37afb5b1931af51bed7f6323dd6)
+
+572. [bug] marcin
+ perfdhcp: Fixed bug where the command line switches used to
+ run the perfdhcp where printed as ASCII codes.
+ (Trac #2700, git b8d6b949eb7f4705e32fbdfd7694ca2e6a6a5cdc)
+
+571. [build] jinmei
+ The ./configure script can now handle output from python-config
+ --ldflags that contains a space after -L switches. This fixes
+ failure reported on some Solaris environments.
+ (Trac #2661, git e6f86f2f5eec8e6003c13d36804a767a840d96d6)
+
+570. [bug] tmark, marcin, tomek
+ b10-dhcp4: Address renewal now works properly for DHCPv4 clients
+ that do not send client ID.
+ (Trac #2702, git daf2abe68ce9c111334a15c14e440730f3a085e2)
+
+569. [bug] tomek
+ b10-dhcp4: Fix bug whereby a DHCP packet without a client ID
+ could crash the MySQL lease database backend.
+ (Trac #2697, git b5e2be95d21ed750ad7cf5e15de2058aa8bc45f4)
+
+568. [func] muks
+ Various message IDs have been renamed to remove the word 'ERROR'
+ from them when they are not logged at ERROR severity level.
+ (Trac #2672, git 660a0d164feaf055677f375977f7ed327ead893e)
+
+567. [doc] marcin, stephen, tomek
+ Update DHCP sections of the BIND 10 guide.
+ (Trac #2657, git 1d0c2004865d1bf322bf78d13630d992e39179fd)
+
+566. [func]* jinmei
+ libdns++/Python isc.dns: In Python isc.dns, function style
+ constants for RRType, RRClass, Rcode and Opcode were deprecated
+ and replaced with straightforward object constants, e.g., from
+ RRType.AAAA() to RRType.AAAA. This is a backward incompatible
+ change (see the Trac ticket for a conversion script if needed).
+ Also, these constants are now more consistent between C++
+ and Python, and RRType constants for all currently standardized
+ types are now supported (even if Rdata for these are not yet
+ available).
+ (Trac #1866 and #2409, git e5005185351cf73d4a611407c2cfcd163f80e428)
+
565. [func]* jelte
The main initializer script (formerly known as either 'bind10',
'boss', or 'bob'), has been renamed to b10-init (and Init in
diff --git a/configure.ac b/configure.ac
index 5dfa85c..d855730 100644
--- a/configure.ac
+++ b/configure.ac
@@ -238,6 +238,21 @@ AM_CONDITIONAL(SET_ENV_LIBRARY_PATH, test $SET_ENV_LIBRARY_PATH = yes)
AC_SUBST(SET_ENV_LIBRARY_PATH)
AC_SUBST(ENV_LIBRARY_PATH)
+# Our experiments have shown Solaris 10 has broken support for the
+# IPV6_USE_MIN_MTU socket option for getsockopt(); it doesn't return the value
+# previously set via setsockopt(). We know it doesn't happen on one instance
+# on Solaris 11, but we don't know whether it happens for any Solaris 10
+# implementations or for earlier versions of Solaris. In any case, at the
+# moment this matters for only one unittest case, so we'll simply disable
+# the affected test using the following definition with the specific hardcoding
+# of that version of Solaris.
+case "$host" in
+*-solaris2.10)
+ AC_DEFINE([HAVE_BROKEN_GET_IPV6_USE_MIN_MTU], [1],
+ [Define to 1 if getsockopt(IPV6_USE_MIN_MTU) does not work])
+ ;;
+esac
+
m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3.3 python3.2 python3.1 python3])
AC_ARG_WITH([pythonpath],
AC_HELP_STRING([--with-pythonpath=PATH],
@@ -298,8 +313,16 @@ AC_SUBST(COMMON_PYTHON_PATH)
if test -x ${PYTHON}-config; then
PYTHON_INCLUDES=`${PYTHON}-config --includes`
- for flag in `${PYTHON}-config --ldflags`; do
- # add any '-L..." flags to PYTHON_LDFLAGS
+ # Add any '-L..." flags to PYTHON_LDFLAGS. We first make a copy of
+ # python-config --ldflags, removing any spaces and tabs
+ # between "-L" and its argument (some instances of python-config
+ # insert a space, which would confuse the code below).
+ # Notes: if -L isn't contained at all we can simply skip this process,
+ # so we only go through the flag if it's contained; also, protecting
+ # the output with [] seems necessary for environment to avoid getting
+ # an empty output accidentally.
+ python_config_ldflags=[`${PYTHON}-config --ldflags | sed -ne 's/\([ \t]*-L\)[ ]*\([^ \t]*[ \t]*\)/\1\2/pg'`]
+ for flag in $python_config_ldflags; do
flag=`echo $flag | sed -ne 's/^\(\-L.*\)$/\1/p'`
if test "X${flag}" != X; then
PYTHON_LDFLAGS="$PYTHON_LDFLAGS ${flag}"
@@ -1319,7 +1342,7 @@ AC_OUTPUT([doc/version.ent
src/bin/stats/stats_httpd.py
src/bin/bind10/init.py
src/bin/bind10/run_bind10.sh
- src/bin/bind10/tests/bind10_test.py
+ src/bin/bind10/tests/init_test.py
src/bin/bindctl/run_bindctl.sh
src/bin/bindctl/bindctl_main.py
src/bin/bindctl/tests/bindctl_test
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index a16bf3b..0d1913f 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -7,7 +7,7 @@
]>
<!--
- - Copyright (C) 2010-2012 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2013 Internet Systems Consortium, Inc. ("ISC")
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
@@ -740,17 +740,13 @@ as a dependency earlier -->
</listitem>
</varlistentry>
- <varlistentry>
- <term>--with-dhcp-mysql</term>
- <listitem>
- <simpara>Enable MySQL support for BIND 10 DHCP. For notes on configuring
- and building DHCP with MySQL see <xref linkend="dhcp-install-configure">.</xref>
- </simpara>
- </listitem>
- </varlistentry>
-
</variablelist>
-
+ <note>
+ <para>
+ For additional instructions concerning the building and installation of
+ BIND 10 DHCP, see <xref linkend="dhcp-install-configure"/>.
+ </para>
+ </note>
</para>
<!-- TODO: lcov -->
@@ -3363,7 +3359,7 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
Build and install BIND 10 as described in <xref linkend="installation"/>, with
the following modification: to enable the MySQL database code, at the
"configure" step (see <xref linkend="configure"/>), specify the location of the
- MySQL configuration program "mysql_config" with the "--with-mysql-config" switch,
+ MySQL configuration program "mysql_config" with the "--with-dhcp-mysql" switch,
i.e.
<screen><userinput>./configure [other-options] --with-dhcp-mysql</userinput></screen>
...if MySQL was installed in the default location, or:
@@ -3609,25 +3605,495 @@ Dhcp4/subnet4 [] list (default)
network configurations. If you want to avoid this, please use the "min-max" notation.
</para>
</section>
+
+ <section id="dhcp4-std-options">
+ <title>Standard DHCPv4 options</title>
+ <para>
+ One of the major features of DHCPv4 server is to provide configuration
+ options to clients. Although there are several options that require
+ special behavior, most options are sent by the server only if the client
+ explicitly requested them. The following example shows how to
+ configure DNS servers, which is one of the most frequently used
+ options. Options specified in this way are considered global and apply
+ to all configured subnets.
+
+ <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.3.1, 192.0.3.2"</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ </para>
+ <para>
+ The first line creates new entry in option-data table. It
+ contains information on all global options that the server is
+ supposed to configure in all subnets. The second line specifies
+ option name. For a complete list of currently supported names,
+ see <xref linkend="dhcp4-std-options-list"/> below.
+ The third line specifies option code, which must match one of the
+ values from that list. Line 4 specifies option space, which must always
+ be set to "dhcp4" as these are standard DHCPv4 options. For
+ other option spaces, including custom option spaces, see <xref
+ linkend="dhcp4-option-spaces"/>. The fifth line specifies the format in
+ which the data will be entered: use of CSV (comma
+ separated values) is recommended. The sixth line gives the actual value to
+ be sent to clients. Data is specified as a normal text, with
+ values separated by commas if more than one value is
+ allowed.
+ </para>
+
+ <para>
+ Options can also be configured as hexadecimal values. If csv-format is
+ set to false, option data must be specified as a hex string. The
+ following commands configure the domain-name-servers option for all
+ subnets with the following addresses: 192.0.3.1 and 192.0.3.2.
+ Note that csv-format is set to false.
+ <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format false</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "C0 00 03 01 C0 00 03 02"</userinput>
+> <userinput>config commit</userinput>
+ </screen>
+ </para>
+
+ <para>
+ It is possible to override options on a per-subnet basis. If
+ clients connected to most of your subnets are expected to get the
+ same values of a given option, you should use global options: you
+ can then override specific values for a small number of subnets.
+ On the other hand, if you use different values in each subnet,
+ it does not make sense to specify global option values
+ (Dhcp4/option-data), rather you should set only subnet-specific values
+ (Dhcp4/subnet[X]/option-data[Y]).
+ </para>
+ <para>
+ The following commands override the global
+ DNS servers option for a particular subnet, setting a single DNS
+ server with address 2001:db8:1::3.
+ <screen>
+> <userinput>config add Dhcp4/subnet4[0]/option-data</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/name "domain-name-servers"</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/code 6</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/subnet4[0]/option-data[0]/data "192.0.2.3"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+
+ <note>
+ <para>In a future version of Kea, it will not be necessary to specify
+ the option code, space and csv-format fields as they will be set
+ automatically.</para>
+ </note>
+
+ <para>
+ Below is a list of currently supported standard DHCPv4 options. The "Name" and "Code"
+ are the values that should be used as a name in the option-data
+ structures. "Type" designates the format of the data: the meanings of
+ the various types is given in <xref linkend="dhcp-types"/>.
+ </para>
+ <para>
+ Some options are designated as arrays, which means that more than one
+ value is allowed in such an option. For example the option time-servers
+ allows the specification of more than one IPv4 address, so allowing
+ clients to obtain the the addresses of multiple NTP servers.
+ </para>
+ <!-- @todo: describe record types -->
+
+ <para>
+ <table border="1" cellpadding="5%" id="dhcp4-std-options-list">
+ <caption>List of standard DHCPv4 options</caption>
+ <thead>
+ <tr><th>Name</th><th>Code</th><th>Type</th><th>Array?</th></tr>
+ </thead>
+ <tbody>
+<tr><td>subnet-mask</td><td>1</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>time-offset</td><td>2</td><td>uint32</td><td>false</td></tr>
+<tr><td>routers</td><td>3</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>time-servers</td><td>4</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>name-servers</td><td>5</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>domain-name-servers</td><td>6</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>log-servers</td><td>7</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>cookie-servers</td><td>8</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>lpr-servers</td><td>9</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>impress-servers</td><td>10</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>resource-location-servers</td><td>11</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>host-name</td><td>12</td><td>string</td><td>false</td></tr>
+<tr><td>boot-size</td><td>13</td><td>uint16</td><td>false</td></tr>
+<tr><td>merit-dump</td><td>14</td><td>string</td><td>false</td></tr>
+<tr><td>domain-name</td><td>15</td><td>fqdn</td><td>false</td></tr>
+<tr><td>swap-server</td><td>16</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>root-path</td><td>17</td><td>string</td><td>false</td></tr>
+<tr><td>extensions-path</td><td>18</td><td>string</td><td>false</td></tr>
+<tr><td>ip-forwarding</td><td>19</td><td>boolean</td><td>false</td></tr>
+<tr><td>non-local-source-routing</td><td>20</td><td>boolean</td><td>false</td></tr>
+<tr><td>policy-filter</td><td>21</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>max-dgram-reassembly</td><td>22</td><td>uint16</td><td>false</td></tr>
+<tr><td>default-ip-ttl</td><td>23</td><td>uint8</td><td>false</td></tr>
+<tr><td>path-mtu-aging-timeout</td><td>24</td><td>uint32</td><td>false</td></tr>
+<tr><td>path-mtu-plateau-table</td><td>25</td><td>uint16</td><td>true</td></tr>
+<tr><td>interface-mtu</td><td>26</td><td>uint16</td><td>false</td></tr>
+<tr><td>all-subnets-local</td><td>27</td><td>boolean</td><td>false</td></tr>
+<tr><td>broadcast-address</td><td>28</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>perform-mask-discovery</td><td>29</td><td>boolean</td><td>false</td></tr>
+<tr><td>mask-supplier</td><td>30</td><td>boolean</td><td>false</td></tr>
+<tr><td>router-discovery</td><td>31</td><td>boolean</td><td>false</td></tr>
+<tr><td>router-solicitation-address</td><td>32</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>static-routes</td><td>33</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>trailer-encapsulation</td><td>34</td><td>boolean</td><td>false</td></tr>
+<tr><td>arp-cache-timeout</td><td>35</td><td>uint32</td><td>false</td></tr>
+<tr><td>ieee802-3-encapsulation</td><td>36</td><td>boolean</td><td>false</td></tr>
+<tr><td>default-tcp-ttl</td><td>37</td><td>uint8</td><td>false</td></tr>
+<tr><td>tcp-keepalive-internal</td><td>38</td><td>uint32</td><td>false</td></tr>
+<tr><td>tcp-keepalive-garbage</td><td>39</td><td>boolean</td><td>false</td></tr>
+<tr><td>nis-domain</td><td>40</td><td>string</td><td>false</td></tr>
+<tr><td>nis-servers</td><td>41</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>ntp-servers</td><td>42</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>vendor-encapsulated-options</td><td>43</td><td>empty</td><td>false</td></tr>
+<tr><td>netbios-name-servers</td><td>44</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>netbios-dd-server</td><td>45</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>netbios-node-type</td><td>46</td><td>uint8</td><td>false</td></tr>
+<tr><td>netbios-scope</td><td>47</td><td>string</td><td>false</td></tr>
+<tr><td>font-servers</td><td>48</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>x-display-manager</td><td>49</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>dhcp-requested-address</td><td>50</td><td>ipv4-address</td><td>false</td></tr>
+<!-- Lease time should not be configured by a user.
+<tr><td>dhcp-lease-time</td><td>51</td><td>uint32</td><td>false</td></tr>
+-->
+<tr><td>dhcp-option-overload</td><td>52</td><td>uint8</td><td>false</td></tr>
+<!-- Message Type, Server Identifier and Parameter Request List should not be configured by a user.
+<tr><td>dhcp-message-type</td><td>53</td><td>uint8</td><td>false</td></tr>
+<tr><td>dhcp-server-identifier</td><td>54</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>dhcp-parameter-request-list</td><td>55</td><td>uint8</td><td>true</td></tr>
+-->
+<tr><td>dhcp-message</td><td>56</td><td>string</td><td>false</td></tr>
+<tr><td>dhcp-max-message-size</td><td>57</td><td>uint16</td><td>false</td></tr>
+<!-- Renewal and rebinding time should not be configured by a user.
+<tr><td>dhcp-renewal-time</td><td>58</td><td>uint32</td><td>false</td></tr>
+<tr><td>dhcp-rebinding-time</td><td>59</td><td>uint32</td><td>false</td></tr>
+-->
+<tr><td>vendor-class-identifier</td><td>60</td><td>binary</td><td>false</td></tr>
+<!-- Client identifier should not be configured by a user.
+<tr><td>dhcp-client-identifier</td><td>61</td><td>binary</td><td>false</td></tr>
+-->
+<tr><td>nwip-domain-name</td><td>62</td><td>string</td><td>false</td></tr>
+<tr><td>nwip-suboptions</td><td>63</td><td>binary</td><td>false</td></tr>
+<tr><td>user-class</td><td>77</td><td>binary</td><td>false</td></tr>
+<tr><td>fqdn</td><td>81</td><td>record</td><td>false</td></tr>
+<tr><td>dhcp-agent-options</td><td>82</td><td>empty</td><td>false</td></tr>
+<tr><td>authenticate</td><td>90</td><td>binary</td><td>false</td></tr>
+<tr><td>client-last-transaction-time</td><td>91</td><td>uint32</td><td>false</td></tr>
+<tr><td>associated-ip</td><td>92</td><td>ipv4-address</td><td>true</td></tr>
+<tr><td>subnet-selection</td><td>118</td><td>ipv4-address</td><td>false</td></tr>
+<tr><td>domain-search</td><td>119</td><td>binary</td><td>false</td></tr>
+<tr><td>vivco-suboptions</td><td>124</td><td>binary</td><td>false</td></tr>
+<tr><td>vivso-suboptions</td><td>125</td><td>binary</td><td>false</td></tr>
+ </tbody>
+ </table>
+ </para>
+ <para>
+ <table border="1" cellpadding="5%" id="dhcp-types">
+ <caption>List of standard DHCP option types</caption>
+ <thead>
+ <tr><th>Name</th><th>Meaning</th></tr>
+ </thead>
+ <tbody>
+ <tr><td>binary</td><td>An arbitrary string of bytes, specified as a set of hexadecimal digits.</td></tr>
+ <tr><td>boolean</td><td>Boolean value with allowed values true or false</td></tr>
+ <tr><td>empty</td><td>No value, data is carried in suboptions</td></tr>
+ <tr><td>fqdn</td><td>Fully qualified domain name (e.g. www.example.com)</td></tr>
+ <tr><td>ipv4-address</td><td>IPv4 address in the usual dotted-decimal notation (e.g. 192.0.2.1)</td></tr>
+ <tr><td>ipv6-address</td><td>IPv6 address in the usual colon notation (e.g. 2001:db8::1)</td></tr>
+ <tr><td>record</td><td>Structured data that may comprise any types (except "record" and "empty")</td></tr>
+ <tr><td>string</td><td>Any text</td></tr>
+ <tr><td>uint8</td><td>8 bit unsigned integer with allowed values 0 to 255</td></tr>
+ <tr><td>uint16</td><td>16 bit unsinged integer with allowed values 0 to 65535</td></tr>
+ <tr><td>uint32</td><td>32 bit unsigned integer with allowed values 0 to 4294967295</td></tr>
+ </tbody>
+ </table>
+ </para>
</section>
+ <section id="dhcp4-custom-options">
+ <title>Custom DHCPv4 options</title>
+ <para>It is also possible to define options other than the standard ones.
+ Assume that we want to define a new DHCPv4 option called "foo" which will have
+ code 222 and will convey a single unsigned 32 bit integer value. We can define
+ such an option by using the following commands:
+ <screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 222</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "uint32"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput></screen>
+ The "false" value of the "array" parameter determines that the option
+ does NOT comprise an array of "uint32" values but rather a single value.
+ Two other parameters have been left blank: "record-types" and "encapsulate".
+ The former specifies the comma separated list of option data fields if the
+ option comprises a record of data fields. The "record-fields" value should
+ be non-empty if the "type" is set to "record". Otherwise it must be left
+ blank. The latter parameter specifies the name of the option space being
+ encapsulated by the particular option. If the particular option does not
+ encapsulate any option space it should be left blank.
+ Note that the above set of comments define the format of the new option and do not
+ set its values.
+ </para>
+ <note>
+ <para>
+ In the current release the default values are not propagated to the
+ parser when the new configuration is being set. Therefore, all
+ parameters must be specified at all times, even if their values are
+ left blank.
+ </para>
+ </note>
+
+ <para>Once the new option format is defined, its value is set
+ in the same way as for a standard option. For example the following
+ commands set a global value that applies to all subnets.
+ <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 222</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+
+ <para>New options can take more complex forms than simple use of
+ primitives (uint8, string, ipv4-address etc): it is possible to
+ define an option comprising a number of existing primitives.
+ </para>
+ <para>Assume we
+ want to define a new option that will consist of an IPv4
+ address, followed by unsigned 16 bit integer, followed by a text
+ string. Such an option could be defined in the following way:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "bar"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 223</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types "ipv4-address, uint16, string"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+</screen>
+ The "type" is set to "record" to indicate that the option contains
+ multiple values of different types. These types are given as a comma-separated
+ list in the "record-types" field and should be those listed in <xref linkend="dhcp-types"/>.
+ </para>
+ <para>
+ The values of the option are set as follows:
+<screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "bar"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 223</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.100, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+ "csv-format" is set "true" to indicate that the "data" field comprises a command-separated
+ list of values. The values in the "data" must correspond to the types set in
+ the "record-types" field of the option definition.
+ </section>
+
+ <section id="dhcp4-vendor-opts">
+ <title>DHCPv4 vendor specific options</title>
+ <para>
+ Currently there are three option spaces defined: dhcp4 (to
+ be used in DHCPv4 daemon) and dhcp6 (for the DHCPv6 daemon); there
+ is also vendor-encapsulated-options-space, which is empty by default, but options
+ can be defined in it. Those options are called vendor-specific
+ information options. The following examples show how to define
+ an option "foo" with code 1 that consists of an IPv4 address, an
+ unsigned 16 bit integer and a string. The "foo" option is conveyed
+ in a vendor specific information option.
+ </para>
+ <para>
+ The first step is to define the format of the option:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "vendor-encapsulated-options-space"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types "ipv4-address, uint16, string"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulates ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ (Note that the option space is set to "vendor-encapsulated-options-space".)
+ Once the option format is defined, the next step is to define actual values
+ for that option:
+ <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "vendor-encapsulated-options-space"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.3, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+ We also set up a dummy value for vendor-opts, the option that conveys our sub-option "foo".
+ This is required else the option will not be included in messages sent to the client.
+ <screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[1]/name "vendor-encapsulated-options"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/code 43</userinput>
+> <userinput>config set Dhcp4/option-data[1]/csv-format false</userinput>
+> <userinput>config set Dhcp4/option-data[1]/data ""</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+
+ <note>
+ <para>
+ With this version of BIND 10, the "vendor-encapsulated-options" option
+ must be specified in the configuration although it has no configurable
+ parameters. If it is not specified, the server will assume that it is
+ not configured and will not send it to a client. In the future there
+ will be no need to include this option in the configuration.
+ </para>
+ </note>
+
+ </section>
+
+ <section id="dhcp4-option-spaces">
+
+ <title>Nested DHCPv4 options (custom option spaces)</title>
+ <para>It is sometimes useful to define completely new option
+ space. This is the case when user creates new option in the
+ standard option space ("dhcp4 or "dhcp6") and wants this option
+ to convey sub-options. Thanks to being in the separate space,
+ sub-option codes will have a separate numbering scheme and may
+ overlap with codes of standard options.
+ </para>
+ <para>Note that creation of a new option space when defining
+ sub-options for a standard option is not required, because it is
+ created by default if the standard option is meant to convey any
+ sub-options (see <xref linkend="dhcp4-vendor-opts"/>).
+ </para>
+ <para>
+ Assume that we want to have a DHCPv4 option called "container" with
+ code 222 that conveys two sub-options with codes 1 and 2.
+ First we need to define the new sub-options:
+<screen>
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-def[0]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/type "ipv4-address"</userinput>
+> <userinput>config set Dhcp4/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+
+> <userinput>config add Dhcp4/option-def</userinput>
+> <userinput>config set Dhcp4/option-def[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/code 2</userinput>
+> <userinput>config set Dhcp4/option-def[1]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/type "string"</userinput>
+> <userinput>config set Dhcp4/option-def[1]/record-types ""</userinput>
+> <userinput>config set Dhcp4/option-def[1]/array false</userinput>
+> <userinput>config set Dhcp4/option-def[1]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ Note that we have defined the options to belong to a new option space
+ (in this case, "isc").
+ </para>
+ <para>
+ The next step is to define a regular DHCPv4 option with our desired
+ code and specify that it should include options from the new option space:
+<screen>
+> <userinput>add Dhcp4/option-def</userinput>
+> <userinput>set Dhcp4/option-def[2]/name "container"</userinput>
+> <userinput>set Dhcp4/option-def[2]/code 222</userinput>
+> <userinput>set Dhcp4/option-def[2]/space "dhcp4"</userinput>
+> <userinput>set Dhcp4/option-def[2]/type "empty"</userinput>
+> <userinput>set Dhcp4/option-def[2]/array false</userinput>
+> <userinput>set Dhcp4/option-def[2]/record-types ""</userinput>
+> <userinput>set Dhcp4/option-def[2]/encapsulate "isc"</userinput>
+> <userinput>commit</userinput>
+</screen>
+ The name of the option space in which the sub-options are defined
+ is set in the "encapsulate" field. The "type" field is set to "empty"
+ to indicate that this option does not carry any data other than
+ sub-options.
+ </para>
+ <para>
+ Finally, we can set values for the new options:
+<screen>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp4/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[0]/data "192.0.2.3"</userinput>
+> <userinput>config commit</userinput>
+<userinput></userinput>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/space "isc"</userinput>
+> <userinput>config set Dhcp4/option-data[1]/code 2</userinput>
+> <userinput>config set Dhcp4/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[1]/data "Hello world"</userinput>
+> <userinput>config commit</userinput>
+<userinput></userinput>
+> <userinput>config add Dhcp4/option-data</userinput>
+> <userinput>config set Dhcp4/option-data[2]/name "container"</userinput>
+> <userinput>config set Dhcp4/option-data[2]/space "dhcp4"</userinput>
+> <userinput>config set Dhcp4/option-data[2]/code 222</userinput>
+> <userinput>config set Dhcp4/option-data[2]/csv-format true</userinput>
+> <userinput>config set Dhcp4/option-data[2]/data ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ Even though the "container" option does not carry any data except
+ sub-options, the "data" field must be explictly set to an empty value.
+ This is required because in the current version of BIND 10 DHCP, the
+ default configuration values are not propagated to the configuration parsers:
+ if the "data" is not set the parser will assume that this
+ parameter is not specified and an error will be reported.
+ </para>
+ <para>Note that it is possible to create an option which carries some data
+ in addition to the sub-options defined in the encapsulated option space. For example,
+ if the "container" option from the previous example was required to carry an uint16
+ value as well as the sub-options, the "type" value would have to be set to "uint16" in
+ the option definition. (Such an option would then have the following
+ data structure: DHCP header, uint16 value, sub-options.) The value specified
+ with the "data" parameter - which should be a valid integer enclosed in quotes,
+ e.g. "123" - would then be assigned to the uint16 field in the "container" option.
+ </para>
+ </section>
+ </section>
<section id="dhcp4-serverid">
<title>Server Identifier in DHCPv4</title>
- <para>The DHCPv4 protocol uses a "server identifier" for clients to be able
- to discriminate between several servers present on the same link: this
- value is an IPv4 address of the server. When started for the first time,
- the DHCPv4 server will choose one of its IPv4 addresses as its server-id,
- and store the chosen value to a file. (The file is named b10-dhcp4-serverid and is
- stored in the "local state directory". This is set during installation
- when "configure" is run, and can be changed by using "--localstatedir"
- on the "configure" command line.) That file will be read by the server
- and the contained value used whenever the server is subsequently started.
+ <para>
+ The DHCPv4 protocol uses a "server identifier" for clients to be able
+ to discriminate between several servers present on the same link: this
+ value is an IPv4 address of the server. When started for the first time,
+ the DHCPv4 server will choose one of its IPv4 addresses as its server-id,
+ and store the chosen value to a file. That file will be read by the server
+ and the contained value used whenever the server is subsequently started.
</para>
<para>
- It is unlikely that this parameter needs to be changed. If such a need
- arises, please stop the server, edit the file and restart the server.
- It is a text file that should contain an IPv4 address. Spaces are
- ignored. No extra characters are allowed in this file.
+ It is unlikely that this parameter should ever need to be changed.
+ However, if such a need arises, stop the server, edit the file and restart
+ the server. (The file is named b10-dhcp4-serverid and by default is
+ stored in the "var" subdirectory of the directory in which BIND 10 is installed.
+ This can be changed when BIND 10 is built by using "--localstatedir"
+ on the "configure" command line.) The file is a text file that should
+ contain an IPv4 address. Spaces are ignored, and no extra characters are allowed
+ in this file.
</para>
</section>
@@ -3705,7 +4171,9 @@ Dhcp4/renew-timer 1000 integer (default)
<simpara>Address rebinding (REBIND) and duplication report (DECLINE)
are not supported yet.</simpara>
</listitem>
-
+ <listitem>
+ <simpara>DNS Update is not yet supported.</simpara>
+ </listitem>
</itemizedlist>
</section>
@@ -3739,17 +4207,7 @@ Dhcp4/renew-timer 1000 integer (default)
> <userinput>config commit</userinput>
</screen>
</para>
- <para>
- To change one of the parameters, simply follow
- the usual <command>bindctl</command> procedure. For example, to make the
- leases longer, change their valid-lifetime parameter:
- <screen>
-> <userinput>config set Dhcp6/valid-lifetime 7200</userinput>
-> <userinput>config commit</userinput></screen>
- Please note that most Dhcp6 parameters are of global scope
- and apply to all defined subnets, unless they are overridden on a
- per-subnet basis.
- </para>
+
<para>
During start-up the server will detect available network interfaces
@@ -3921,51 +4379,420 @@ Dhcp6/subnet6/ list
2001:db8:: address may be assigned as well. If you want to avoid this,
please use the "min-max" notation.
</para>
+ </section>
+
+ <section id="dhcp6-std-options">
+ <title>Standard DHCPv6 options</title>
<para>
- Options can also be configured: the following commands configure
- the DNS-SERVERS option for all subnets with the following addresses:
- 2001:db8:1::1 and 2001:db8:1::2
+ One of the major features of DHCPv6 server is to provide configuration
+ options to clients. Although there are several options that require
+ special behavior, most options are sent by the server only if the client
+ explicitly requested them. The following example shows how to
+ configure DNS servers, which is one of the most frequently used
+ options. Numbers in the first column are added for easier reference and
+ will not appear on screen. Options specified in this way are considered
+ global and apply to all configured subnets.
+
<screen>
+1. > <userinput>config add Dhcp6/option-data</userinput>
+2. > <userinput>config set Dhcp6/option-data[0]/name "dns-servers"</userinput>
+3. > <userinput>config set Dhcp6/option-data[0]/code 23</userinput>
+4. > <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+5. > <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+6. > <userinput>config set Dhcp6/option-data[0]/data "2001:db8::cafe, 2001:db8::babe"</userinput>
+7. > <userinput>config commit</userinput>
+</screen>
+ </para>
+ <para>
+ The first line creates new entry in option-data table. It
+ contains information on all global options that the server is
+ supposed to configure in all subnets. The second line specifies
+ option name. For a complete list of currently supported names,
+ see <xref linkend="dhcp6-std-options-list"/> below.
+ The third line specifies option code, which must match one of the
+ values from that
+ list. Line 4 specifies option space, which must always
+ be set to "dhcp6" as these are standard DHCPv6 options. For
+ other name spaces, including custom option spaces, see <xref
+ linkend="dhcp6-option-spaces"/>. The fifth line specifies the format in
+ which the data will be entered: use of CSV (comma
+ separated values) is recommended. The sixth line gives the actual value to
+ be sent to clients. Data is specified as a normal text, with
+ values separated by commas if more than one value is
+ allowed.
+ </para>
+
+ <para>
+ Options can also be configured as hexadecimal values. If csv-format is
+ set to false, the option data must be specified as a string of hexadecimal
+ numbers. The
+ following commands configure the DNS-SERVERS option for all
+ subnets with the following addresses: 2001:db8:1::cafe and
+ 2001:db8:1::babe.
+ <screen>
> <userinput>config add Dhcp6/option-data</userinput>
> <userinput>config set Dhcp6/option-data[0]/name "dns-servers"</userinput>
> <userinput>config set Dhcp6/option-data[0]/code 23</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format false</userinput>
> <userinput>config set Dhcp6/option-data[0]/data "2001 0DB8 0001 0000 0000 0000</userinput>
- <userinput>0000 0001 2001 0DB8 0001 0000 0000 0000 0000 0002"</userinput>
+ <userinput>0000 CAFE 2001 0DB8 0001 0000 0000 0000 0000 BABE"</userinput>
> <userinput>config commit</userinput>
</screen>
(The value for the setting of the "data" element is split across two
- lines in this document for clarity: when entering the command, the whole
- string should be entered on the same line.)
+ lines in this document for clarity: when entering the command, the
+ whole string should be entered on the same line.)
</para>
- <para>
- Currently the only way to set option data is to specify the
- data as a string of hexadecimal digits. It is planned to allow
- alternative ways of specifying the data as a comma-separated list,
- e.g. "2001:db8:1::1,2001:db8:1::2".
- </para>
- <para>
- As with global settings, it is also possible to override options on a
- per-subnet basis, e.g. the following commands override the global DNS
- servers option for a particular subnet, setting a single DNS server with
- address 2001:db8:1::3.
- <screen>
+
+ <para>
+ It is possible to override options on a per-subnet basis. If
+ clients connected to most of your subnets are expected to get the
+ same values of a given option, you should use global options: you
+ can then override specific values for a small number of subnets.
+ On the other hand, if you use different values in each subnet,
+ it does not make sense to specify global option values
+ (Dhcp6/option-data), rather you should set only subnet-specific values
+ (Dhcp6/subnet[X]/option-data[Y]).
+ </para>
+ <para>
+ The following commands override the global
+ DNS servers option for a particular subnet, setting a single DNS
+ server with address 2001:db8:1::3.
+ <screen>
> <userinput>config add Dhcp6/subnet6[0]/option-data</userinput>
> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/name "dns-servers"</userinput>
> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/code 23</userinput>
-> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/data "2001 0DB8 0001 0000</userinput>
- <userinput>0000 0000 0000 0003"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/data "2001:db8:1::3"</userinput>
> <userinput>config commit</userinput></screen>
- (As before, the setting of the "data" element has been split across two
- lines for clarity.)
+ </para>
+
+ <note>
+ <para>
+ In future versions of BIND 10 DHCP, it will not be necessary to specify
+ option code, space and csv-format fields, as those fields will be set
+ automatically.
</para>
+ </note>
+
+
+ <para>
+ Below is a list of currently supported standard DHCPv6 options. The "Name" and "Code"
+ are the values that should be used as a name in the option-data
+ structures. "Type" designates the format of the data: the meanings of
+ the various types is given in <xref linkend="dhcp-types"/>.
+ </para>
+ <para>
+ Some options are designated as arrays, which means that more than one
+ value is allowed in such an option. For example the option dns-servers
+ allows the specification of more than one IPv6 address, so allowing
+ clients to obtain the the addresses of multiple DNS servers.
+ </para>
+
+<!-- @todo: describe record types -->
+
+ <para>
+ <table border="1" cellpadding="5%" id="dhcp6-std-options-list">
+ <caption>List of standard DHCPv6 options</caption>
+ <thead>
+ <tr><th>Name</th><th>Code</th><th>Type</th><th>Array?</th></tr>
+ <tr></tr>
+ </thead>
+ <tbody>
+<!-- Our engine uses those options on its own, admin must not configure them on his own
+<tr><td>clientid</td><td>1</td><td>binary</td><td>false</td></tr>
+<tr><td>serverid</td><td>2</td><td>binary</td><td>false</td></tr>
+<tr><td>ia-na</td><td>3</td><td>record</td><td>false</td></tr>
+<tr><td>ia-ta</td><td>4</td><td>uint32</td><td>false</td></tr>
+<tr><td>iaaddr</td><td>5</td><td>record</td><td>false</td></tr>
+<tr><td>oro</td><td>6</td><td>uint16</td><td>true</td></tr> -->
+<tr><td>preference</td><td>7</td><td>uint8</td><td>false</td></tr>
+
+<!-- Our engine uses those options on its own, admin must not configure them on his own
+<tr><td>elapsed-time</td><td>8</td><td>uint16</td><td>false</td></tr>
+<tr><td>relay-msg</td><td>9</td><td>binary</td><td>false</td></tr>
+<tr><td>auth</td><td>11</td><td>binary</td><td>false</td></tr>
+<tr><td>unicast</td><td>12</td><td>ipv6-address</td><td>false</td></tr>
+<tr><td>status-code</td><td>13</td><td>record</td><td>false</td></tr>
+<tr><td>rapid-commit</td><td>14</td><td>empty</td><td>false</td></tr>
+<tr><td>user-class</td><td>15</td><td>binary</td><td>false</td></tr>
+<tr><td>vendor-class</td><td>16</td><td>record</td><td>false</td></tr>
+<tr><td>vendor-opts</td><td>17</td><td>uint32</td><td>false</td></tr>
+<tr><td>interface-id</td><td>18</td><td>binary</td><td>false</td></tr>
+<tr><td>reconf-msg</td><td>19</td><td>uint8</td><td>false</td></tr>
+<tr><td>reconf-accept</td><td>20</td><td>empty</td><td>false</td></tr> -->
+<tr><td>sip-server-dns</td><td>21</td><td>fqdn</td><td>true</td></tr>
+<tr><td>sip-server-addr</td><td>22</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>dns-servers</td><td>23</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>domain-search</td><td>24</td><td>fqdn</td><td>true</td></tr>
+<!-- <tr><td>ia-pd</td><td>25</td><td>record</td><td>false</td></tr> -->
+<!-- <tr><td>iaprefix</td><td>26</td><td>record</td><td>false</td></tr> -->
+<tr><td>nis-servers</td><td>27</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>nisp-servers</td><td>28</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>nis-domain-name</td><td>29</td><td>fqdn</td><td>true</td></tr>
+<tr><td>nisp-domain-name</td><td>30</td><td>fqdn</td><td>true</td></tr>
+<tr><td>sntp-servers</td><td>31</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>information-refresh-time</td><td>32</td><td>uint32</td><td>false</td></tr>
+<tr><td>bcmcs-server-dns</td><td>33</td><td>fqdn</td><td>true</td></tr>
+<tr><td>bcmcs-server-addr</td><td>34</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>geoconf-civic</td><td>36</td><td>record</td><td>false</td></tr>
+<tr><td>remote-id</td><td>37</td><td>record</td><td>false</td></tr>
+<tr><td>subscriber-id</td><td>38</td><td>binary</td><td>false</td></tr>
+<tr><td>client-fqdn</td><td>39</td><td>record</td><td>false</td></tr>
+<tr><td>pana-agent</td><td>40</td><td>ipv6-address</td><td>true</td></tr>
+<tr><td>new-posix-timezone</td><td>41</td><td>string</td><td>false</td></tr>
+<tr><td>new-tzdb-timezone</td><td>42</td><td>string</td><td>false</td></tr>
+<tr><td>ero</td><td>43</td><td>uint16</td><td>true</td></tr>
+<tr><td>lq-query</td><td>44</td><td>record</td><td>false</td></tr>
+<tr><td>client-data</td><td>45</td><td>empty</td><td>false</td></tr>
+<tr><td>clt-time</td><td>46</td><td>uint32</td><td>false</td></tr>
+<tr><td>lq-relay-data</td><td>47</td><td>record</td><td>false</td></tr>
+<tr><td>lq-client-link</td><td>48</td><td>ipv6-address</td><td>true</td></tr>
+ </tbody>
+ </table>
+ </para>
+ </section>
+
+ <section id="dhcp6-custom-options">
+ <title>Custom DHCPv6 options</title>
+ <para>It is also possible to define options other than the standard ones.
+ Assume that we want to define a new DHCPv6 option called "foo" which will have
+ code 100 and will convey a single unsigned 32 bit integer value. We can define
+ such an option by using the following commands:
+ <screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 100</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "uint32"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput></screen>
+ The "false" value of the "array" parameter determines that the option
+ does NOT comprise an array of "uint32" values but rather a single value.
+ Two other parameters have been left blank: "record-types" and "encapsulate".
+ The former specifies the comma separated list of option data fields if the
+ option comprises a record of data fields. The "record-fields" value should
+ be non-empty if the "type" is set to "record". Otherwise it must be left
+ blank. The latter parameter specifies the name of the option space being
+ encapsulated by the particular option. If the particular option does not
+ encapsulate any option space it should be left blank.
+ Note that the above set of comments define the format of the new option and do not
+ set its values.
+ </para>
+ <para>Once the new option format is defined, its value is set
+ in the same way as for a standard option. For example the following
+ commands set a global value that applies to all subnets.
+ <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 100</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+
+ <para>New options can take more complex forms than simple use of
+ primitives (uint8, string, ipv6-address etc): it is possible to
+ define an option comprising a number of existing primitives.
+ </para>
+ <para>
+ Assume we
+ want to define a new option that will consist of an IPv6
+ address, followed by unsigned 16 bit integer, followed by a text
+ string. Such an option could be defined in the following way:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "bar"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 101</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types "ipv6-address, uint16, string"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+</screen>
+ The "type" is set to "record" to indicate that the option contains
+ multiple values of different types. These types are given as a comma-separated
+ list in the "record-types" field and should be those listed in <xref linkend="dhcp-types"/>.
+ </para>
+ <para>
+ The values of the option are set as follows:
+<screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "bar"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 101</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8:1::10, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+ "csv-format" is set "true" to indicate that the "data" field comprises a command-separated
+ list of values. The values in the "data" must correspond to the types set in
+ the "record-types" field of the option definition.
+ </section>
+
+ <section id="dhcp6-vendor-opts">
+ <title>DHCPv6 vendor specific options</title>
+ <para>
+ Currently there are three option spaces defined: dhcp4 (to be used
+ in DHCPv4 daemon) and dhcp6 (for the DHCPv6 daemon); there is also
+ vendor-opts-space, which is empty by default, but options can be
+ defined in it. Those options are called vendor-specific information
+ options. The following examples show how to define an option "foo"
+ with code 1 that consists of an IPv6 address, an unsigned 16 bit integer
+ and a string. The "foo" option is conveyed in a vendor specific
+ information option. This option comprises a single uint32 value
+ that is set to "12345". The sub-option "foo" follows the data
+ field holding this value.
+ <screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "vendor-opts-space"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "record"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types "ipv6-address, uint16, string"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulates ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ (Note that the option space is set to "vendor-opts-space".)
+ Once the option format is defined, the next step is to define actual values
+ for that option:
+ <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "foo"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "vendor-opts-space"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8:1::10, 123, Hello World"</userinput>
+> <userinput>config commit</userinput></screen>
+ We should also define values for the vendor-opts, that will convey our option foo.
+ <screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[1]/name "vendor-opts"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/code 17</userinput>
+> <userinput>config set Dhcp6/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[1]/data "12345"</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+ </section>
+
+ <section id="dhcp6-option-spaces">
+ <title>Nested DHCPv6 options (custom option spaces)</title>
+ <para>It is sometimes useful to define completely new option
+ spaces. This is useful if the user wants his new option to
+ convey sub-options that use separate numbering scheme, for
+ example sub-options with codes 1 and 2. Those option codes
+ conflict with standard DHCPv6 options, so a separate option
+ space must be defined.
+ </para>
+ <para>Note that it is not required to create new option space when
+ defining sub-options for a standard option because it is by
+ default created if the standard option is meant to convey
+ any sub-options (see <xref linkend="dhcp6-vendor-opts"/>).
+ </para>
+ <para>
+ Assume that we want to have a DHCPv6 option called "container"
+ with code 102 that conveys two sub-options with codes 1 and 2.
+ First we need to define the new sub-options:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-def[0]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/type "ipv6-address"</userinput>
+> <userinput>config set Dhcp6/option-def[0]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[0]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[0]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/code 2</userinput>
+> <userinput>config set Dhcp6/option-def[1]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/type "string"</userinput>
+> <userinput>config set Dhcp6/option-def[1]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[1]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[1]/encapsulate ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ Note that we have defined the options to belong to a new option space
+ (in this case, "isc").
+ </para>
+ <para>
+The next step is to define a regular DHCPv6 option and specify that it
+should include options from the isc option space:
+<screen>
+> <userinput>config add Dhcp6/option-def</userinput>
+> <userinput>config set Dhcp6/option-def[2]/name "container"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/code 102</userinput>
+> <userinput>config set Dhcp6/option-def[2]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/type "empty"</userinput>
+> <userinput>config set Dhcp6/option-def[2]/array false</userinput>
+> <userinput>config set Dhcp6/option-def[2]/record-types ""</userinput>
+> <userinput>config set Dhcp6/option-def[2]/encapsulate "isc"</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ The name of the option space in which the sub-options are defined
+ is set in the "encapsulate" field. The "type" field is set to "empty"
+ which imposes that this option does not carry any data other than
+ sub-options.
+ </para>
+ <para>
+ Finally, we can set values for the new options:
+<screen>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "subopt1"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 1</userinput>
+> <userinput>config set Dhcp6/option-data[0]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001:db8::abcd"</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[1]/name "subopt2"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/space "isc"</userinput>
+> <userinput>config set Dhcp6/option-data[1]/code 2</userinput>
+> <userinput>config set Dhcp6/option-data[1]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[1]/data "Hello world"</userinput>
+> <userinput>config commit</userinput>
+> <userinput></userinput>
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[2]/name "container"</userinput>
+> <userinput>config set Dhcp6/option-data[2]/space "dhcp6"</userinput>
+> <userinput>config set Dhcp6/option-data[2]/code 102</userinput>
+> <userinput>config set Dhcp6/option-data[2]/csv-format true</userinput>
+> <userinput>config set Dhcp6/option-data[2]/data ""</userinput>
+> <userinput>config commit</userinput>
+</screen>
+ Even though the "container" option does not carry any data except
+ sub-options, the "data" field must be explictly set to an empty value.
+ This is required because in the current version of BIND 10 DHCP, the
+ default configuration values are not propagated to the configuration parsers:
+ if the "data" is not set the parser will assume that this
+ parameter is not specified and an error will be reported.
+ </para>
+ <para>Note that it is possible to create an option which carries some data
+ in addition to the sub-options defined in the encapsulated option space. For example,
+ if the "container" option from the previous example was required to carry an uint16
+ value as well as the sub-options, the "type" value would have to be set to "uint16" in
+ the option definition. (Such an option would then have the following
+ data structure: DHCP header, uint16 value, sub-options.) The value specified
+ with the "data" parameter - which should be a valid integer enclosed in quotes,
+ e.g. "123" - would then be assigned to the uint16 field in the "container" option.
+ </para>
</section>
<section id="dhcp6-config-subnets">
<title>Subnet Selection</title>
<para>
- The DHCPv6 server may receive requests from local (connected to the same
- subnet as the server) and remote (connecting via relays)
- clients.
+ The DHCPv6 server may receive requests from local (connected
+ to the same subnet as the server) and remote (connecting via
+ relays) clients.
<note>
<para>
Currently relayed DHCPv6 traffic is not supported. The server will
@@ -4003,28 +4830,30 @@ Dhcp6/subnet6/ list
<para>The DHCPv6 protocol uses a "server identifier" (also known
as a DUID) for clients to be able to discriminate between several
servers present on the same link. There are several types of
- DUIDs defined, but RFC 3315 instructs servers to use DUID-LLT if
+ DUIDs defined, but <ulink url="http://tools.ietf.org/html/rfc3315">RFC 3315</ulink> instructs servers to use DUID-LLT if
possible. This format consists of a link-layer (MAC) address and a
timestamp. When started for the first time, the DHCPv6 server will
automatically generate such a DUID and store the chosen value to
- a file (The file is named b10-dhcp6-serverid and is stored in the
- "local state directory". This is set during installation when
- "configure" is run, and can be changed by using "--localstatedir"
- on the "configure" command line.) That file will be read by the server
+ a file. That file is read by the server
and the contained value used whenever the server is subsequently started.
</para>
<para>
- It is unlikely that this parameter needs to be changed. If such a need
- arises, please stop the server, edit the file and start the server
- again. It is a text file that contains double digit hexadecimal values
+ It is unlikely that this parameter should ever need to be changed.
+ However, if such a need arises, stop the server, edit the file and restart
+ the server. (The file is named b10-dhcp6-serverid and by default is
+ stored in the "var" subdirectory of the directory in which BIND 10 is installed.
+ This can be changed when BIND 10 is built by using "--localstatedir"
+ on the "configure" command line.) The file is a text file that contains
+ double digit hexadecimal values
separated by colons. This format is similar to typical MAC address
format. Spaces are ignored. No extra characters are allowed in this
file.
</para>
+
</section>
<section id="dhcp6-std">
- <title>Supported DHCPv6 Standards</title>
+ <title>Supported Standards</title>
<para>The following standards and draft standards are currently
supported:</para>
<itemizedlist>
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
index e8592ac..de8325b 100644
--- a/src/bin/auth/auth_config.cc
+++ b/src/bin/auth/auth_config.cc
@@ -106,7 +106,7 @@ public:
rollbackAddresses_ = old;
}
virtual void commit() {
- rollbackAddresses_.release();
+ rollbackAddresses_.reset();
}
private:
AuthSrv& server_;
diff --git a/src/bin/auth/auth_messages.mes b/src/bin/auth/auth_messages.mes
index 28b9623..77b20b1 100644
--- a/src/bin/auth/auth_messages.mes
+++ b/src/bin/auth/auth_messages.mes
@@ -14,7 +14,7 @@
$NAMESPACE isc::auth
-% AUTH_AXFR_ERROR error handling AXFR request: %1
+% AUTH_AXFR_PROBLEM error handling AXFR request: %1
This is a debug message produced by the authoritative server when it
has encountered an error processing an AXFR request. The message gives
the reason for the error, and the server will return a SERVFAIL code to
@@ -232,13 +232,13 @@ This is a debug message produced by the authoritative server when it receives
a NOTIFY packet but the XFRIN process is not running. The packet will be
dropped and nothing returned to the sender.
-% AUTH_PACKET_PARSE_ERROR unable to parse received DNS packet: %1
+% AUTH_PACKET_PARSE_FAILED unable to parse received DNS packet: %1
This is a debug message, generated by the authoritative server when an
attempt to parse a received DNS packet has failed due to something other
than a protocol error. The reason for the failure is given in the message;
the server will return a SERVFAIL error code to the sender.
-% AUTH_PACKET_PROTOCOL_ERROR DNS packet protocol error: %1. Returning %2
+% AUTH_PACKET_PROTOCOL_FAILURE DNS packet protocol error: %1. Returning %2
This is a debug message, generated by the authoritative server when an
attempt to parse a received DNS packet has failed due to a protocol error.
The reason for the failure is given in the message, as is the error code
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index f96c882..30875e5 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -529,14 +529,14 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
// Parse the message.
message.fromWire(request_buffer);
} catch (const DNSProtocolError& error) {
- LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
+ LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_FAILURE)
.arg(error.getRcode().toText()).arg(error.what());
makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode(),
stats_attrs);
impl_->resumeServer(server, message, stats_attrs, true);
return;
} catch (const Exception& ex) {
- LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
+ LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_FAILED)
.arg(ex.what());
makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
stats_attrs);
@@ -731,7 +731,7 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
xfrout_connected_ = false;
}
- LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_ERROR)
+ LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_PROBLEM)
.arg(err.what());
makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL(),
stats_attrs, tsig_context);
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index a2a4117..c5b9b16 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -298,14 +298,18 @@ Query::addNXRRsetProof(ZoneFinder& finder,
addWildcardNXRRSETProof(finder, db_context.rrset);
}
} else if (db_context.isNSEC3Signed() && !db_context.isWildcard()) {
- if (*qtype_ == RRType::DS()) {
- // RFC 5155, Section 7.2.4. Add either NSEC3 for the qname or
- // closest (provable) encloser proof in case of optout.
- addClosestEncloserProof(finder, *qname_, true);
- } else {
- // RFC 5155, Section 7.2.3. Just add NSEC3 for the qname.
- addNSEC3ForName(finder, *qname_, true);
- }
+ // Section 7.2.3 and 7.2.4 of RFC 5155 with clarification by errata
+ // http://www.rfc-editor.org/errata_search.php?rfc=5155&eid=3441
+ // In the end, these two cases are basically the same: if the qname is
+ // equal to or derived from insecure delegation covered by an Opt-Out
+ // NSEC3 RR, include the closest provable encloser proof; otherwise we
+ // have a matching NSEC3, so we include it.
+ //
+ // Note: This implementation does not check in the former case whether
+ // the NSEC3 for the next closer has Opt-Out bit on; this must be the
+ // case as long as the zone is correctly signed, and if it's broken
+ // we'd just return what we are given and have the validator detect it.
+ addClosestEncloserProof(finder, *qname_, true);
} else if (db_context.isNSEC3Signed() && db_context.isWildcard()) {
// Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
// qname, construct the matched wildcard name and add NSEC3 for it.
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 830de0d..05c6cce 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -130,7 +130,7 @@ TEST_F(AuthConfigTest, invalidListenAddressConfig) {
isc::testutils::portconfig::invalidListenAddressConfig(server);
}
-// Try setting addresses trough config
+// Try setting addresses through config
TEST_F(AuthConfigTest, listenAddressConfig) {
isc::testutils::portconfig::listenAddressConfig(server);
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 9822768..b017e70 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -217,6 +217,13 @@ public:
"t644ebqk9bibcna874givr6joj62mlhv";
hash_map_[Name("www1.uwild.example.com")] =
"q04jkcevqvmu85r014c7dkba38o0ji6r"; // a bit larger than H(www)
+
+ // For empty-non-terminal derived from insecure delegation (we don't
+ // need a hash for the delegation point itself for that test). the
+ // hash for empty name is the same as that for unsigned-delegation
+ // above, as the case is similar to that.
+ hash_map_[Name("empty.example.com")] =
+ "q81r598950igr1eqvc60aedlq66425b5"; // a bit larger than H(www)
}
virtual string calculate(const Name& name) const {
const NSEC3HashMap::const_iterator found = hash_map_.find(name);
@@ -262,8 +269,6 @@ public:
// to child zones are identified by the existence of non origin NS records.
// Another special name is "dname.example.com". Query names under this name
// will result in DNAME.
-// This mock zone doesn't handle empty non terminal nodes (if we need to test
-// such cases find() should have specialized code for it).
class MockZoneFinder : public ZoneFinder {
public:
MockZoneFinder() :
@@ -1162,12 +1167,6 @@ TEST_P(QueryTest, apexNSMatch) {
// test type any query logic
TEST_P(QueryTest, exactAnyMatch) {
- // This is an in-memory specific bug (#2585), until it's fixed we
- // tentatively skip the test for in-memory
- if (GetParam() == INMEMORY) {
- return;
- }
-
// find match rrset, omit additional data which has already been provided
// in the answer section from the additional.
EXPECT_NO_THROW(query.process(*list_, Name("noglue.example.com"),
@@ -1373,17 +1372,11 @@ TEST_P(QueryTest, nxdomainWithNSEC) {
}
TEST_P(QueryTest, nxdomainWithNSEC2) {
- // there seems to be a bug in the SQLite3 (or database in general) data
- // source and this doesn't work (Trac #2586).
- if (GetParam() == SQLITE3) {
- return;
- }
-
// See comments about no_txt. In this case the best possible wildcard
// is derived from the next domain of the NSEC that proves NXDOMAIN, and
// the NSEC to provide the non existence of wildcard is different from
// the first NSEC.
- query.process(*list_, Name("(.no.example.com"), qtype, response,
+ query.process(*list_, Name("!.no.example.com"), qtype, response,
true);
responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
NULL, (string(soa_minttl_txt) +
@@ -1393,19 +1386,12 @@ TEST_P(QueryTest, nxdomainWithNSEC2) {
string("mx.example.com. 3600 IN RRSIG ") +
getCommonRRSIGText("NSEC") + "\n" +
string(nsec_no_txt) + "\n" +
- string(").no.example.com. 3600 IN RRSIG ") +
+ string("&.no.example.com. 3600 IN RRSIG ") +
getCommonRRSIGText("NSEC")).c_str(),
NULL, mock_finder->getOrigin());
}
TEST_P(QueryTest, nxdomainWithNSECDuplicate) {
- // there seems to be a bug in the SQLite3 (or database in general) data
- // source and this doesn't work. This is probably the same type of bug
- // as nxdomainWithNSEC2 (Trac #2586).
- if (GetParam() == SQLITE3) {
- return;
- }
-
// See comments about nz_txt. In this case we only need one NSEC,
// which proves both NXDOMAIN and the non existence of wildcard.
query.process(*list_, Name("nx.no.example.com"), qtype, response,
@@ -1415,7 +1401,7 @@ TEST_P(QueryTest, nxdomainWithNSECDuplicate) {
string("example.com. 0 IN RRSIG ") +
getCommonRRSIGText("SOA") + "\n" +
string(nsec_no_txt) + "\n" +
- string(").no.example.com. 3600 IN RRSIG ") +
+ string("&.no.example.com. 3600 IN RRSIG ") +
getCommonRRSIGText("NSEC")).c_str(),
NULL, mock_finder->getOrigin());
}
@@ -1529,7 +1515,7 @@ TEST_P(QueryTest, nxrrsetWithNSEC) {
TEST_P(QueryTest, emptyNameWithNSEC) {
// Empty non terminal with DNSSEC proof. This is one of the cases of
// Section 3.1.3.2 of RFC4035.
- // mx.example.com. NSEC ).no.example.com. proves no.example.com. is a
+ // mx.example.com. NSEC &.no.example.com. proves no.example.com. is a
// non empty terminal node. Note that it also implicitly proves there
// should be no closer wildcard match (because the empty name is an
// exact match), so we only need one NSEC.
@@ -1700,12 +1686,6 @@ TEST_F(QueryTestForMockOnly, badWildcardProof3) {
}
TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
- // This is an in-memory specific bug (#2585), until it's fixed we
- // tentatively skip the test for in-memory
- if (GetParam() == INMEMORY) {
- return;
- }
-
// NXRRSET on WILDCARD with DNSSEC proof. We should have SOA, NSEC that
// proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
// which proves both NXDOMAIN and the non existence RRSETs of wildcard.
@@ -1723,12 +1703,6 @@ TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
}
TEST_P(QueryTest, wildcardNxrrsetWithNSEC) {
- // This is an in-memory specific bug (#2585), until it's fixed we
- // tentatively skip the test for in-memory
- if (GetParam() == INMEMORY) {
- return;
- }
-
// WILDCARD + NXRRSET with DNSSEC proof. We should have SOA, NSEC that
// proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
// one proves NXDOMAIN and the other proves non existence RRSETs of
@@ -2468,21 +2442,32 @@ TEST_P(QueryTest, nxrrsetWithNSEC3) {
NULL, mock_finder->getOrigin());
}
-// Check the exception is correctly raised when the NSEC3 thing isn't in the
-// zone
-TEST_F(QueryTestForMockOnly, nxrrsetMissingNSEC3) {
- // This is a broken data source scenario; works only with mock.
-
- mock_finder->setNSEC3Flag(true);
- // We just need it to return false for "matched". This indicates
- // there's no exact match for NSEC3 on www.example.com.
- ZoneFinder::FindNSEC3Result nsec3(false, 0, ConstRRsetPtr(),
- ConstRRsetPtr());
- mock_finder->setNSEC3Result(&nsec3);
+TEST_P(QueryTest, nxrrsetDerivedFromOptOutNSEC3) {
+ // In this test we emulate the situation where an empty non-terminal name
+ // is derived from insecure delegation and covered by an opt-out NSEC3.
+ // In the actual test data the covering NSEC3 really has the opt-out
+ // bit set, although the implementation doesn't check it anyway.
+ enableNSEC3(rrsets_to_add_);
+ query.process(*list_, Name("empty.example.com"), RRType::TXT(), response,
+ true);
- EXPECT_THROW(query.process(*list_, Name("www.example.com"),
- RRType::TXT(), response, true),
- Query::BadNSEC3);
+ // The closest provable encloser is the origin name (example.com.), and
+ // the next closer is the empty name itself, which is expected to be
+ // covered by an opt-out NSEC3 RR. The response should contain these 2
+ // NSEC3s.
+ responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
+ (string(soa_minttl_txt) +
+ string("example.com. 0 IN RRSIG ") +
+ getCommonRRSIGText("SOA") + "\n" +
+ string(nsec3_apex_txt) + "\n" +
+ nsec3_hash_.calculate(Name("example.com.")) +
+ ".example.com. 3600 IN RRSIG " +
+ getCommonRRSIGText("NSEC3") + "\n" +
+ string(nsec3_www_txt) + "\n" +
+ nsec3_hash_.calculate(Name("www.example.com.")) +
+ ".example.com. 3600 IN RRSIG " +
+ getCommonRRSIGText("NSEC3") + "\n").c_str(),
+ NULL, mock_finder->getOrigin());
}
TEST_P(QueryTest, nxrrsetWithNSEC3_ds_exact) {
diff --git a/src/bin/auth/tests/testdata/example-base-inc.zone b/src/bin/auth/tests/testdata/example-base-inc.zone
index bbcbef1..08fbf86 100644
--- a/src/bin/auth/tests/testdata/example-base-inc.zone
+++ b/src/bin/auth/tests/testdata/example-base-inc.zone
@@ -150,32 +150,32 @@ t.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 e
;; the best possible wildcard is below the "next domain" of the NSEC RR that
;; proves the NXDOMAIN, i.e.,
;; mx.example.com. (exist)
-;; (.no.example.com. (qname, NXDOMAIN)
-;; ).no.example.com. (exist)
+;; !.no.example.com. (qname, NXDOMAIN)
+;; &.no.example.com. (exist)
;; *.no.example.com. (best possible wildcard, not exist)
;var=no_txt
-\).no.example.com. 3600 IN AAAA 2001:db8::53
+&.no.example.com. 3600 IN AAAA 2001:db8::53
;; NSEC records.
;var=nsec_apex_txt
example.com. 3600 IN NSEC cname.example.com. NS SOA NSEC RRSIG
;var=
example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
;var=nsec_mx_txt
-mx.example.com. 3600 IN NSEC \).no.example.com. MX NSEC RRSIG
+mx.example.com. 3600 IN NSEC &.no.example.com. MX NSEC RRSIG
;var=
mx.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
;var=nsec_no_txt
-\).no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG
+&.no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG
;var=
-\).no.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
+&.no.example.com. 3600 IN RRSIG NSEC 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
;; We'll also test the case where a single NSEC proves both NXDOMAIN and the
;; non existence of wildcard. The following records will be used for that
;; test.
-;; ).no.example.com. (exist, whose NSEC proves everything)
+;; &.no.example.com. (exist, whose NSEC proves everything)
;; *.no.example.com. (best possible wildcard, not exist)
;; nx.no.example.com. (NXDOMAIN)
;; nz.no.example.com. (exist)
@@ -234,3 +234,8 @@ bad-delegation.example.com. 3600 IN NS ns.example.net.
;; or NSEC3 that proves it.
;var=nosec_delegation_txt
nosec-delegation.example.com. 3600 IN NS ns.nosec.example.net.
+
+;; Setup for emulating insecure delegation that contain an empty name.
+;; the delegation itself isn't expected to be used directly in tests.
+;var=
+delegation.empty.example.com. 3600 IN NS ns.delegation.empty.example
diff --git a/src/bin/auth/tests/testdata/example-nsec3-inc.zone b/src/bin/auth/tests/testdata/example-nsec3-inc.zone
index 7742df0..d480ffe 100644
--- a/src/bin/auth/tests/testdata/example-nsec3-inc.zone
+++ b/src/bin/auth/tests/testdata/example-nsec3-inc.zone
@@ -1,4 +1,4 @@
-;; See query_testzone_data.txt for general notes.
+;; See example-base-inc.zone for general notes.
;; NSEC3PARAM. This is needed for database-based data source to
;; signal the zone is NSEC3-signed
diff --git a/src/bin/bind10/bind10.in b/src/bin/bind10/bind10.in
index fe8c0cc..88c45c9 100755
--- a/src/bin/bind10/bind10.in
+++ b/src/bin/bind10/bind10.in
@@ -1,4 +1,11 @@
#!/bin/sh
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-exec @libexecdir@/@PACKAGE@/b10-init $*
+
+# We use this wrapper script both for production and in-source tests; in
+# the latter case B10_FROM_BUILD environment is expected to be defined.
+if test -n "${B10_FROM_BUILD}"; then
+ exec ${B10_FROM_BUILD}/src/bin/bind10/b10-init $*
+else
+ prefix=@prefix@
+ exec_prefix=@exec_prefix@
+ exec @libexecdir@/@PACKAGE@/b10-init $*
+fi
diff --git a/src/bin/bind10/init.py.in b/src/bin/bind10/init.py.in
index 874fb34..f47de31 100755
--- a/src/bin/bind10/init.py.in
+++ b/src/bin/bind10/init.py.in
@@ -72,6 +72,7 @@ import isc.cc
import isc.util.process
import isc.net.parse
import isc.log
+import isc.config
from isc.log_messages.init_messages import *
import isc.bind10.component
import isc.bind10.special_component
diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am
index a5e3fab..6d59dbd 100644
--- a/src/bin/bind10/tests/Makefile.am
+++ b/src/bin/bind10/tests/Makefile.am
@@ -1,7 +1,7 @@
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
#PYTESTS = args_test.py bind10_test.py
# NOTE: this has a generated test found in the builddir
-PYTESTS = bind10_test.py
+PYTESTS = init_test.py
noinst_SCRIPTS = $(PYTESTS)
# If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
deleted file mode 100644
index 36b98fe..0000000
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ /dev/null
@@ -1,2426 +0,0 @@
-# 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.
-
-# Most of the time, we omit the "init" for brevity. Sometimes,
-# we want to be explicit about what we do, like when hijacking a library
-# call used by the b10-init.
-from init import Init, ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
-import init
-
-# XXX: environment tests are currently disabled, due to the preprocessor
-# setup that we have now complicating the environment
-
-import unittest
-import sys
-import os
-import os.path
-import copy
-import signal
-import socket
-from isc.net.addr import IPAddr
-import time
-import isc
-import isc.log
-import isc.bind10.socket_cache
-import errno
-import random
-
-from isc.testutils.parse_args import TestOptParser, OptsError
-from isc.testutils.ccsession_mock import MockModuleCCSession
-
-class TestProcessInfo(unittest.TestCase):
- def setUp(self):
- # redirect stdout to a pipe so we can check that our
- # process spawning is doing the right thing with stdout
- self.old_stdout = os.dup(sys.stdout.fileno())
- self.pipes = os.pipe()
- os.dup2(self.pipes[1], sys.stdout.fileno())
- os.close(self.pipes[1])
- # note that we use dup2() to restore the original stdout
- # to the main program ASAP in each test... this prevents
- # hangs reading from the child process (as the pipe is only
- # open in the child), and also insures nice pretty output
-
- def tearDown(self):
- # clean up our stdout munging
- os.dup2(self.old_stdout, sys.stdout.fileno())
- os.close(self.pipes[0])
-
- def test_init(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
- pi.spawn()
- os.dup2(self.old_stdout, sys.stdout.fileno())
- self.assertEqual(pi.name, 'Test Process')
- self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
- self.assertEqual(pi.dev_null_stdout, False)
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- self.assertNotEqual(pi.process, None)
- self.assertTrue(type(pi.pid) is int)
-
-# def test_setting_env(self):
-# pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
-# os.dup2(self.old_stdout, sys.stdout.fileno())
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
-# 'FOO': 'BAR' })
-
- def test_setting_null_stdout(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
- dev_null_stdout=True)
- pi.spawn()
- os.dup2(self.old_stdout, sys.stdout.fileno())
- self.assertEqual(pi.dev_null_stdout, True)
- self.assertEqual(os.read(self.pipes[0], 100), b"")
-
- def test_respawn(self):
- pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
- pi.spawn()
- # wait for old process to work...
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- # respawn it
- old_pid = pi.pid
- pi.respawn()
- os.dup2(self.old_stdout, sys.stdout.fileno())
- # make sure the new one started properly
- self.assertEqual(pi.name, 'Test Process')
- self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
- self.assertEqual(pi.dev_null_stdout, False)
- self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
- self.assertNotEqual(pi.process, None)
- self.assertTrue(type(pi.pid) is int)
- self.assertNotEqual(pi.pid, old_pid)
-
-class TestCacheCommands(unittest.TestCase):
- """
- Test methods of b10-init related to the socket cache and socket handling.
- """
- def setUp(self):
- """
- Prepare b10-init for some tests.
-
- Also prepare some variables we need.
- """
- self.__b10_init = Init()
- # Fake the cache here so we can pretend it is us and hijack the
- # calls to its methods.
- self.__b10_init._socket_cache = self
- self.__b10_init._socket_path = '/socket/path'
- self.__raise_exception = None
- self.__socket_args = {
- "port": 53,
- "address": "::",
- "protocol": "UDP",
- "share_mode": "ANY",
- "share_name": "app"
- }
- # What was and wasn't called.
- self.__drop_app_called = None
- self.__get_socket_called = None
- self.__send_fd_called = None
- self.__get_token_called = None
- self.__drop_socket_called = None
- init.libutil_io_python.send_fd = self.__send_fd
-
- def __send_fd(self, to, socket):
- """
- A function to hook the send_fd in the b10-init.
- """
- self.__send_fd_called = (to, socket)
-
- class FalseSocket:
- """
- A socket where we can fake methods we need instead of having a real
- socket.
- """
- def __init__(self):
- self.send = b""
- def fileno(self):
- """
- The file number. Used for identifying the remote application.
- """
- return 42
-
- def sendall(self, data):
- """
- Adds data to the self.send.
- """
- self.send += data
-
- def drop_application(self, application):
- """
- Part of pretending to be the cache. Logs the parameter to
- self.__drop_app_called.
-
- In the case self.__raise_exception is set, the exception there
- is raised instead.
- """
- if self.__raise_exception is not None:
- raise self.__raise_exception
- self.__drop_app_called = application
-
- def test_consumer_dead(self):
- """
- Test that it calls the drop_application method of the cache.
- """
- self.__b10_init.socket_consumer_dead(self.FalseSocket())
- self.assertEqual(42, self.__drop_app_called)
-
- def test_consumer_dead_invalid(self):
- """
- Test that it doesn't crash in case the application is not known to
- the cache, the b10_init doesn't crash, as this actually can happen in
- practice.
- """
- self.__raise_exception = ValueError("This application is unknown")
- # This doesn't crash
- self.__b10_init.socket_consumer_dead(self.FalseSocket())
-
- def get_socket(self, token, application):
- """
- Part of pretending to be the cache. If there's anything in
- __raise_exception, it is raised. Otherwise, the call is logged
- into __get_socket_called and a number is returned.
- """
- if self.__raise_exception is not None:
- raise self.__raise_exception
- self.__get_socket_called = (token, application)
- return 13
-
- def test_request_handler(self):
- """
- Test that a request for socket is forwarded and the socket is sent
- back, if it returns a socket.
- """
- socket = self.FalseSocket()
- # An exception from the cache
- self.__raise_exception = ValueError("Test value error")
- self.__b10_init.socket_request_handler(b"token", socket)
- # It was called, but it threw, so it is not noted here
- self.assertIsNone(self.__get_socket_called)
- self.assertEqual(b"0\n", socket.send)
- # It should not have sent any socket.
- self.assertIsNone(self.__send_fd_called)
- # Now prepare a valid scenario
- self.__raise_exception = None
- socket.send = b""
- self.__b10_init.socket_request_handler(b"token", socket)
- self.assertEqual(b"1\n", socket.send)
- self.assertEqual((42, 13), self.__send_fd_called)
- self.assertEqual(("token", 42), self.__get_socket_called)
-
- def get_token(self, protocol, address, port, share_mode, share_name):
- """
- Part of pretending to be the cache. If there's anything in
- __raise_exception, it is raised. Otherwise, the parameters are
- logged into __get_token_called and a token is returned.
- """
- if self.__raise_exception is not None:
- raise self.__raise_exception
- self.__get_token_called = (protocol, address, port, share_mode,
- share_name)
- return "token"
-
- def test_get_socket_ok(self):
- """
- Test the successful scenario of getting a socket.
- """
- result = self.__b10_init._get_socket(self.__socket_args)
- [code, answer] = result['result']
- self.assertEqual(0, code)
- self.assertEqual({
- 'token': 'token',
- 'path': '/socket/path'
- }, answer)
- addr = self.__get_token_called[1]
- self.assertTrue(isinstance(addr, IPAddr))
- self.assertEqual("::", str(addr))
- self.assertEqual(("UDP", addr, 53, "ANY", "app"),
- self.__get_token_called)
-
- def test_get_socket_error(self):
- """
- Test that bad inputs are handled correctly, etc.
- """
- def check_code(code, args):
- """
- Pass the args there and check if it returns success or not.
-
- The rest is not tested, as it is already checked in the
- test_get_socket_ok.
- """
- [rcode, ranswer] = self.__b10_init._get_socket(args)['result']
- self.assertEqual(code, rcode)
- if code != 0:
- # This should be an error message. The exact formatting
- # is unknown, but we check it is string at least
- self.assertTrue(isinstance(ranswer, str))
-
- def mod_args(name, value):
- """
- Override a parameter in the args.
- """
- result = dict(self.__socket_args)
- result[name] = value
- return result
-
- # Port too large
- check_code(1, mod_args('port', 65536))
- # Not numeric address
- check_code(1, mod_args('address', 'example.org.'))
- # Some bad values of enum-like params
- check_code(1, mod_args('protocol', 'BAD PROTO'))
- check_code(1, mod_args('share_mode', 'BAD SHARE'))
- # Check missing parameters
- for param in self.__socket_args.keys():
- args = dict(self.__socket_args)
- del args[param]
- check_code(1, args)
- # These are OK values for the enum-like parameters
- # The ones from test_get_socket_ok are not tested here
- check_code(0, mod_args('protocol', 'TCP'))
- check_code(0, mod_args('share_mode', 'SAMEAPP'))
- check_code(0, mod_args('share_mode', 'NO'))
- # If an exception is raised from within the cache, it is converted
- # to an error, not propagated
- self.__raise_exception = Exception("Test exception")
- check_code(1, self.__socket_args)
- # The special "expected" exceptions
- self.__raise_exception = \
- isc.bind10.socket_cache.ShareError("Not shared")
- check_code(3, self.__socket_args)
- self.__raise_exception = \
- isc.bind10.socket_cache.SocketError("Not shared", 13)
- check_code(2, self.__socket_args)
-
- def drop_socket(self, token):
- """
- Part of pretending to be the cache. If there's anything in
- __raise_exception, it is raised. Otherwise, the parameter is stored
- in __drop_socket_called.
- """
- if self.__raise_exception is not None:
- raise self.__raise_exception
- self.__drop_socket_called = token
-
- def test_drop_socket(self):
- """
- Check the drop_socket command. It should directly call the method
- on the cache. Exceptions should be translated to error messages.
- """
- # This should be OK and just propagated to the call.
- self.assertEqual({"result": [0]},
- self.__b10_init.command_handler("drop_socket",
- {"token": "token"}))
- self.assertEqual("token", self.__drop_socket_called)
- self.__drop_socket_called = None
- # Missing parameter
- self.assertEqual({"result": [1, "Missing token parameter"]},
- self.__b10_init.command_handler("drop_socket", {}))
- self.assertIsNone(self.__drop_socket_called)
- # An exception is raised from within the cache
- self.__raise_exception = ValueError("Test error")
- self.assertEqual({"result": [1, "Test error"]},
- self.__b10_init.command_handler("drop_socket",
- {"token": "token"}))
-
-
-class TestInit(unittest.TestCase):
- def setUp(self):
- # Save original values that may be tweaked in some tests
- self.__orig_setgid = init.posix.setgid
- self.__orig_setuid = init.posix.setuid
- self.__orig_logger_class = isc.log.Logger
-
- def tearDown(self):
- # Restore original values saved in setUp()
- init.posix.setgid = self.__orig_setgid
- init.posix.setuid = self.__orig_setuid
- isc.log.Logger = self.__orig_logger_class
-
- def test_init(self):
- b10_init = Init()
- self.assertEqual(b10_init.verbose, False)
- self.assertEqual(b10_init.msgq_socket_file, None)
- self.assertEqual(b10_init.cc_session, None)
- self.assertEqual(b10_init.ccs, None)
- self.assertEqual(b10_init.components, {})
- self.assertEqual(b10_init.runnable, False)
- self.assertEqual(b10_init.username, None)
- self.assertIsNone(b10_init._socket_cache)
-
- def __setgid(self, gid):
- self.__gid_set = gid
-
- def __setuid(self, uid):
- self.__uid_set = uid
-
- def test_change_user(self):
- init.posix.setgid = self.__setgid
- init.posix.setuid = self.__setuid
-
- self.__gid_set = None
- self.__uid_set = None
- b10_init = Init()
- b10_init.change_user()
- # No gid/uid set in init, nothing called.
- self.assertIsNone(self.__gid_set)
- self.assertIsNone(self.__uid_set)
-
- Init(setuid=42, setgid=4200).change_user()
- # This time, it get's called
- self.assertEqual(4200, self.__gid_set)
- self.assertEqual(42, self.__uid_set)
-
- def raising_set_xid(gid_or_uid):
- ex = OSError()
- ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
- raise ex
-
- # Let setgid raise an exception
- init.posix.setgid = raising_set_xid
- init.posix.setuid = self.__setuid
- self.assertRaises(init.ChangeUserError,
- Init(setuid=42, setgid=4200).change_user)
-
- # Let setuid raise an exception
- init.posix.setgid = self.__setgid
- init.posix.setuid = raising_set_xid
- self.assertRaises(init.ChangeUserError,
- Init(setuid=42, setgid=4200).change_user)
-
- # Let initial log output after setuid raise an exception
- init.posix.setgid = self.__setgid
- init.posix.setuid = self.__setuid
- isc.log.Logger = raising_set_xid
- self.assertRaises(init.ChangeUserError,
- Init(setuid=42, setgid=4200).change_user)
-
- def test_set_creator(self):
- """
- Test the call to set_creator. First time, the cache is created
- with the passed creator. The next time, it throws an exception.
- """
- init = Init()
- # The cache doesn't use it at start, so just create an empty class
- class Creator: pass
- creator = Creator()
- init.set_creator(creator)
- self.assertTrue(isinstance(init._socket_cache,
- isc.bind10.socket_cache.Cache))
- self.assertEqual(creator, init._socket_cache._creator)
- self.assertRaises(ValueError, init.set_creator, creator)
-
- def test_socket_srv(self):
- """Tests init_socket_srv() and remove_socket_srv() work as expected."""
- init = Init()
-
- self.assertIsNone(init._srv_socket)
- self.assertIsNone(init._tmpdir)
- self.assertIsNone(init._socket_path)
-
- init.init_socket_srv()
-
- self.assertIsNotNone(init._srv_socket)
- self.assertNotEqual(-1, init._srv_socket.fileno())
- self.assertEqual(os.path.join(init._tmpdir, 'sockcreator'),
- init._srv_socket.getsockname())
-
- self.assertIsNotNone(init._tmpdir)
- self.assertTrue(os.path.isdir(init._tmpdir))
- self.assertIsNotNone(init._socket_path)
- self.assertTrue(os.path.exists(init._socket_path))
-
- # Check that it's possible to connect to the socket file (this
- # only works if the socket file exists and the server listens on
- # it).
- s = socket.socket(socket.AF_UNIX)
- try:
- s.connect(init._socket_path)
- can_connect = True
- s.close()
- except socket.error as e:
- can_connect = False
-
- self.assertTrue(can_connect)
-
- init.remove_socket_srv()
-
- self.assertEqual(-1, init._srv_socket.fileno())
- self.assertFalse(os.path.exists(init._socket_path))
- self.assertFalse(os.path.isdir(init._tmpdir))
-
- # These should not fail either:
-
- # second call
- init.remove_socket_srv()
-
- init._srv_socket = None
- init.remove_socket_srv()
-
- def test_init_alternate_socket(self):
- init = Init("alt_socket_file")
- self.assertEqual(init.verbose, False)
- self.assertEqual(init.msgq_socket_file, "alt_socket_file")
- self.assertEqual(init.cc_session, None)
- self.assertEqual(init.ccs, None)
- self.assertEqual(init.components, {})
- self.assertEqual(init.runnable, False)
- self.assertEqual(init.username, None)
-
- def test_command_handler(self):
- class DummySession():
- def group_sendmsg(self, msg, group):
- (self.msg, self.group) = (msg, group)
- def group_recvmsg(self, nonblock, seq): pass
- class DummyModuleCCSession():
- module_spec = isc.config.module_spec.ModuleSpec({
- "module_name": "Init",
- "statistics": [
- {
- "item_name": "boot_time",
- "item_type": "string",
- "item_optional": False,
- "item_default": "1970-01-01T00:00:00Z",
- "item_title": "Boot time",
- "item_description": "A date time when bind10 process starts initially",
- "item_format": "date-time"
- }
- ]
- })
- def get_module_spec(self):
- return self.module_spec
- init = Init()
- init.verbose = True
- init.cc_session = DummySession()
- init.ccs = DummyModuleCCSession()
- # a bad command
- self.assertEqual(init.command_handler(-1, None),
- isc.config.ccsession.create_answer(1, "bad command"))
- # "shutdown" command
- self.assertEqual(init.command_handler("shutdown", None),
- isc.config.ccsession.create_answer(0))
- self.assertFalse(init.runnable)
- # "getstats" command
- self.assertEqual(init.command_handler("getstats", None),
- isc.config.ccsession.create_answer(0,
- { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
- # "ping" command
- self.assertEqual(init.command_handler("ping", None),
- isc.config.ccsession.create_answer(0, "pong"))
- # "show_processes" command
- self.assertEqual(init.command_handler("show_processes", None),
- isc.config.ccsession.create_answer(0,
- init.get_processes()))
- # an unknown command
- self.assertEqual(init.command_handler("__UNKNOWN__", None),
- isc.config.ccsession.create_answer(1, "Unknown command"))
-
- # Fake the get_token of cache and test the command works
- init._socket_path = '/socket/path'
- class cache:
- def get_token(self, protocol, addr, port, share_mode, share_name):
- return str(addr) + ':' + str(port)
- init._socket_cache = cache()
- args = {
- "port": 53,
- "address": "0.0.0.0",
- "protocol": "UDP",
- "share_mode": "ANY",
- "share_name": "app"
- }
- # at all and this is the easiest way to check.
- self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
- 'path': '/socket/path'}]},
- init.command_handler("get_socket", args))
- # The drop_socket is not tested here, but in TestCacheCommands.
- # It needs the cache mocks to be in place and they are there.
-
- def test_stop_process(self):
- """
- Test checking the stop_process method sends the right message over
- the message bus.
- """
- class DummySession():
- def group_sendmsg(self, msg, group, instance="*"):
- (self.msg, self.group, self.instance) = (msg, group, instance)
- init = Init()
- init.cc_session = DummySession()
- init.stop_process('process', 'address', 42)
- self.assertEqual('address', init.cc_session.group)
- self.assertEqual('address', init.cc_session.instance)
- self.assertEqual({'command': ['shutdown', {'pid': 42}]},
- init.cc_session.msg)
-
-# Mock class for testing Init's usage of ProcessInfo
-class MockProcessInfo:
- def __init__(self, name, args, env={}, dev_null_stdout=False,
- dev_null_stderr=False):
- self.name = name
- self.args = args
- self.env = env
- self.dev_null_stdout = dev_null_stdout
- self.dev_null_stderr = dev_null_stderr
- self.process = None
- self.pid = None
-
- def spawn(self):
- # set some pid (only used for testing that it is not None anymore)
- self.pid = 42147
-
-# Class for testing the Init without actually starting processes.
-# This is used for testing the start/stop components routines and
-# the Init commands.
-#
-# Testing that external processes start is outside the scope
-# of the unit test, by overriding the process start methods we can check
-# that the right processes are started depending on the configuration
-# options.
-class MockInit(Init):
- def __init__(self):
- Init.__init__(self)
-
- # Set flags as to which of the overridden methods has been run.
- self.msgq = False
- self.cfgmgr = False
- self.ccsession = False
- self.auth = False
- self.resolver = False
- self.xfrout = False
- self.xfrin = False
- self.zonemgr = False
- self.stats = False
- self.stats_httpd = False
- self.cmdctl = False
- self.dhcp6 = False
- self.dhcp4 = False
- self.c_channel_env = {}
- self.components = { }
- self.creator = False
- self.get_process_exit_status_called = False
-
- class MockSockCreator(isc.bind10.component.Component):
- def __init__(self, process, b10_init, kind, address=None,
- params=None):
- isc.bind10.component.Component.__init__(self, process,
- b10_init, kind,
- 'SockCreator')
- self._start_func = b10_init.start_creator
-
- specials = isc.bind10.special_component.get_specials()
- specials['sockcreator'] = MockSockCreator
- self._component_configurator = \
- isc.bind10.component.Configurator(self, specials)
-
- def start_creator(self):
- self.creator = True
- procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
- procinfo.pid = 1
- return procinfo
-
- def _read_bind10_config(self):
- # Configuration options are set directly
- pass
-
- def start_msgq(self):
- self.msgq = True
- procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
- procinfo.pid = 2
- return procinfo
-
- def start_ccsession(self, c_channel_env):
- # this is not a process, don't have to do anything with procinfo
- self.ccsession = True
-
- def start_cfgmgr(self):
- self.cfgmgr = True
- procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
- procinfo.pid = 3
- return procinfo
-
- def start_auth(self):
- self.auth = True
- procinfo = ProcessInfo('b10-auth', ['/bin/false'])
- procinfo.pid = 5
- return procinfo
-
- def start_resolver(self):
- self.resolver = True
- procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
- procinfo.pid = 6
- return procinfo
-
- def start_simple(self, name):
- procmap = { 'b10-zonemgr': self.start_zonemgr,
- 'b10-stats': self.start_stats,
- 'b10-stats-httpd': self.start_stats_httpd,
- 'b10-cmdctl': self.start_cmdctl,
- 'b10-dhcp6': self.start_dhcp6,
- 'b10-dhcp4': self.start_dhcp4,
- 'b10-xfrin': self.start_xfrin,
- 'b10-xfrout': self.start_xfrout }
- return procmap[name]()
-
- def start_xfrout(self):
- self.xfrout = True
- procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
- procinfo.pid = 7
- return procinfo
-
- def start_xfrin(self):
- self.xfrin = True
- procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
- procinfo.pid = 8
- return procinfo
-
- def start_zonemgr(self):
- self.zonemgr = True
- procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
- procinfo.pid = 9
- return procinfo
-
- def start_stats(self):
- self.stats = True
- procinfo = ProcessInfo('b10-stats', ['/bin/false'])
- procinfo.pid = 10
- return procinfo
-
- def start_stats_httpd(self):
- self.stats_httpd = True
- procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
- procinfo.pid = 11
- return procinfo
-
- def start_cmdctl(self):
- self.cmdctl = True
- procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
- procinfo.pid = 12
- return procinfo
-
- def start_dhcp6(self):
- self.dhcp6 = True
- procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
- procinfo.pid = 13
- return procinfo
-
- def start_dhcp4(self):
- self.dhcp4 = True
- procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
- procinfo.pid = 14
- return procinfo
-
- def stop_process(self, process, recipient, pid):
- procmap = { 'b10-auth': self.stop_auth,
- 'b10-resolver': self.stop_resolver,
- 'b10-xfrout': self.stop_xfrout,
- 'b10-xfrin': self.stop_xfrin,
- 'b10-zonemgr': self.stop_zonemgr,
- 'b10-stats': self.stop_stats,
- 'b10-stats-httpd': self.stop_stats_httpd,
- 'b10-cmdctl': self.stop_cmdctl }
- procmap[process]()
-
- # Some functions to pretend we stop processes, use by stop_process
- def stop_msgq(self):
- if self.msgq:
- del self.components[2]
- self.msgq = False
-
- def stop_cfgmgr(self):
- if self.cfgmgr:
- del self.components[3]
- self.cfgmgr = False
-
- def stop_auth(self):
- if self.auth:
- del self.components[5]
- self.auth = False
-
- def stop_resolver(self):
- if self.resolver:
- del self.components[6]
- self.resolver = False
-
- def stop_xfrout(self):
- if self.xfrout:
- del self.components[7]
- self.xfrout = False
-
- def stop_xfrin(self):
- if self.xfrin:
- del self.components[8]
- self.xfrin = False
-
- def stop_zonemgr(self):
- if self.zonemgr:
- del self.components[9]
- self.zonemgr = False
-
- def stop_stats(self):
- if self.stats:
- del self.components[10]
- self.stats = False
-
- def stop_stats_httpd(self):
- if self.stats_httpd:
- del self.components[11]
- self.stats_httpd = False
-
- def stop_cmdctl(self):
- if self.cmdctl:
- del self.components[12]
- self.cmdctl = False
-
- def _get_process_exit_status(self):
- if self.get_process_exit_status_called:
- return (0, 0)
- self.get_process_exit_status_called = True
- return (53, 0)
-
- def _get_process_exit_status_unknown_pid(self):
- if self.get_process_exit_status_called:
- return (0, 0)
- self.get_process_exit_status_called = True
- return (42, 0)
-
- def _get_process_exit_status_raises_oserror_echild(self):
- raise OSError(errno.ECHILD, 'Mock error')
-
- def _get_process_exit_status_raises_oserror_other(self):
- raise OSError(0, 'Mock error')
-
- def _get_process_exit_status_raises_other(self):
- raise Exception('Mock error')
-
- def _make_mock_process_info(self, name, args, c_channel_env,
- dev_null_stdout=False, dev_null_stderr=False):
- return MockProcessInfo(name, args, c_channel_env,
- dev_null_stdout, dev_null_stderr)
-
-class MockInitSimple(Init):
- def __init__(self):
- Init.__init__(self)
- # Set which process has been started
- self.started_process_name = None
- self.started_process_args = None
- self.started_process_env = None
-
- def _make_mock_process_info(self, name, args, c_channel_env,
- dev_null_stdout=False, dev_null_stderr=False):
- return MockProcessInfo(name, args, c_channel_env,
- dev_null_stdout, dev_null_stderr)
-
- def start_process(self, name, args, c_channel_env, port=None,
- address=None):
- self.started_process_name = name
- self.started_process_args = args
- self.started_process_env = c_channel_env
- return None
-
-class TestStartStopProcessesInit(unittest.TestCase):
- """
- Check that the start_all_components method starts the right combination
- of components and that the right components are started and stopped
- according to changes in configuration.
- """
- def check_environment_unchanged(self):
- # Check whether the environment has not been changed
- self.assertEqual(original_os_environ, os.environ)
-
- def check_started(self, init, core, auth, resolver):
- """
- Check that the right sets of services are started. The ones that
- should be running are specified by the core, auth and resolver parameters
- (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
- and -zonemgr).
- """
- self.assertEqual(init.msgq, core)
- self.assertEqual(init.cfgmgr, core)
- self.assertEqual(init.ccsession, core)
- self.assertEqual(init.creator, core)
- self.assertEqual(init.auth, auth)
- self.assertEqual(init.resolver, resolver)
- self.assertEqual(init.xfrout, auth)
- self.assertEqual(init.xfrin, auth)
- self.assertEqual(init.zonemgr, auth)
- self.assertEqual(init.stats, core)
- self.assertEqual(init.stats_httpd, core)
- self.assertEqual(init.cmdctl, core)
- self.check_environment_unchanged()
-
- def check_preconditions(self, init):
- self.check_started(init, False, False, False)
-
- def check_started_none(self, init):
- """
- Check that the situation is according to configuration where no servers
- should be started. Some components still need to be running.
- """
- self.check_started(init, True, False, False)
- self.check_environment_unchanged()
-
- def check_started_both(self, init):
- """
- Check the situation is according to configuration where both servers
- (auth and resolver) are enabled.
- """
- self.check_started(init, True, True, True)
- self.check_environment_unchanged()
-
- def check_started_auth(self, init):
- """
- Check the set of components needed to run auth only is started.
- """
- self.check_started(init, True, True, False)
- self.check_environment_unchanged()
-
- def check_started_resolver(self, init):
- """
- Check the set of components needed to run resolver only is started.
- """
- self.check_started(init, True, False, True)
- self.check_environment_unchanged()
-
- def check_started_dhcp(self, init, v4, v6):
- """
- Check if proper combinations of DHCPv4 and DHCpv6 can be started
- """
- self.assertEqual(v4, init.dhcp4)
- self.assertEqual(v6, init.dhcp6)
- self.check_environment_unchanged()
-
- def construct_config(self, start_auth, start_resolver):
- # The things that are common, not turned on an off
- config = {}
- config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
- config['b10-stats-httpd'] = { 'kind': 'dispensable',
- 'address': 'StatsHttpd' }
- config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
- if start_auth:
- config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
- config['b10-xfrout'] = { 'kind': 'dispensable',
- 'address': 'Xfrout' }
- config['b10-xfrin'] = { 'kind': 'dispensable',
- 'address': 'Xfrin' }
- config['b10-zonemgr'] = { 'kind': 'dispensable',
- 'address': 'Zonemgr' }
- if start_resolver:
- config['b10-resolver'] = { 'kind': 'needed',
- 'special': 'resolver' }
- return {'components': config}
-
- def config_start_init(self, start_auth, start_resolver):
- """
- Test the configuration is loaded at the startup.
- """
- init = MockInit()
- config = self.construct_config(start_auth, start_resolver)
- class CC:
- def get_full_config(self):
- return config
- # Provide the fake CC with data
- init.ccs = CC()
- # And make sure it's not overwritten
- def start_ccsession():
- init.ccsession = True
- init.start_ccsession = lambda _: start_ccsession()
- # We need to return the original _read_bind10_config
- init._read_bind10_config = lambda: Init._read_bind10_config(init)
- init.start_all_components()
- self.check_started(init, True, start_auth, start_resolver)
- self.check_environment_unchanged()
-
- def test_start_none(self):
- self.config_start_init(False, False)
-
- def test_start_resolver(self):
- self.config_start_init(False, True)
-
- def test_start_auth(self):
- self.config_start_init(True, False)
-
- def test_start_both(self):
- self.config_start_init(True, True)
-
- def test_config_start(self):
- """
- Test that the configuration starts and stops components according
- to configuration changes.
- """
-
- # Create Init and ensure correct initialization
- init = MockInit()
- self.check_preconditions(init)
-
- init.start_all_components()
- init.runnable = True
- init.config_handler(self.construct_config(False, False))
- self.check_started_none(init)
-
- # Enable both at once
- init.config_handler(self.construct_config(True, True))
- self.check_started_both(init)
-
- # Not touched by empty change
- init.config_handler({})
- self.check_started_both(init)
-
- # Not touched by change to the same configuration
- init.config_handler(self.construct_config(True, True))
- self.check_started_both(init)
-
- # Turn them both off again
- init.config_handler(self.construct_config(False, False))
- self.check_started_none(init)
-
- # Not touched by empty change
- init.config_handler({})
- self.check_started_none(init)
-
- # Not touched by change to the same configuration
- init.config_handler(self.construct_config(False, False))
- self.check_started_none(init)
-
- # Start and stop auth separately
- init.config_handler(self.construct_config(True, False))
- self.check_started_auth(init)
-
- init.config_handler(self.construct_config(False, False))
- self.check_started_none(init)
-
- # Start and stop resolver separately
- init.config_handler(self.construct_config(False, True))
- self.check_started_resolver(init)
-
- init.config_handler(self.construct_config(False, False))
- self.check_started_none(init)
-
- # Alternate
- init.config_handler(self.construct_config(True, False))
- self.check_started_auth(init)
-
- init.config_handler(self.construct_config(False, True))
- self.check_started_resolver(init)
-
- init.config_handler(self.construct_config(True, False))
- self.check_started_auth(init)
-
- def test_config_start_once(self):
- """
- Tests that a component is started only once.
- """
- # Create Init and ensure correct initialization
- init = MockInit()
- self.check_preconditions(init)
-
- init.start_all_components()
-
- init.runnable = True
- init.config_handler(self.construct_config(True, True))
- self.check_started_both(init)
-
- init.start_auth = lambda: self.fail("Started auth again")
- init.start_xfrout = lambda: self.fail("Started xfrout again")
- init.start_xfrin = lambda: self.fail("Started xfrin again")
- init.start_zonemgr = lambda: self.fail("Started zonemgr again")
- init.start_resolver = lambda: self.fail("Started resolver again")
-
- # Send again we want to start them. Should not do it, as they are.
- init.config_handler(self.construct_config(True, True))
-
- def test_config_not_started_early(self):
- """
- Test that components are not started by the config handler before
- startup.
- """
- init = MockInit()
- self.check_preconditions(init)
-
- init.start_auth = lambda: self.fail("Started auth again")
- init.start_xfrout = lambda: self.fail("Started xfrout again")
- init.start_xfrin = lambda: self.fail("Started xfrin again")
- init.start_zonemgr = lambda: self.fail("Started zonemgr again")
- init.start_resolver = lambda: self.fail("Started resolver again")
-
- init.config_handler({'start_auth': True, 'start_resolver': True})
-
- # Checks that DHCP (v4 and v6) components are started when expected
- def test_start_dhcp(self):
-
- # Create Init and ensure correct initialization
- init = MockInit()
- self.check_preconditions(init)
-
- init.start_all_components()
- init.config_handler(self.construct_config(False, False))
- self.check_started_dhcp(init, False, False)
-
- def test_start_dhcp_v6only(self):
- # Create Init and ensure correct initialization
- init = MockInit()
- self.check_preconditions(init)
- # v6 only enabled
- init.start_all_components()
- init.runnable = True
- init._Init_started = True
- config = self.construct_config(False, False)
- config['components']['b10-dhcp6'] = { 'kind': 'needed',
- 'address': 'Dhcp6' }
- init.config_handler(config)
- self.check_started_dhcp(init, False, True)
-
- # uncomment when dhcpv4 becomes implemented
- # v4 only enabled
- #init.cfg_start_dhcp6 = False
- #init.cfg_start_dhcp4 = True
- #self.check_started_dhcp(init, True, False)
-
- # both v4 and v6 enabled
- #init.cfg_start_dhcp6 = True
- #init.cfg_start_dhcp4 = True
- #self.check_started_dhcp(init, True, True)
-
-class MockComponent:
- def __init__(self, name, pid, address=None):
- self.name = lambda: name
- self.pid = lambda: pid
- self.address = lambda: address
- self.restarted = False
- self.forceful = False
- self.running = True
- self.has_failed = False
-
- def get_restart_time(self):
- return 0 # arbitrary dummy value
-
- def restart(self, now):
- self.restarted = True
- return True
-
- def is_running(self):
- return self.running
-
- def failed(self, status):
- return self.has_failed
-
- def kill(self, forceful):
- self.forceful = forceful
-
-class TestInitCmd(unittest.TestCase):
- def test_ping(self):
- """
- Confirm simple ping command works.
- """
- init = MockInit()
- answer = init.command_handler("ping", None)
- self.assertEqual(answer, {'result': [0, 'pong']})
-
- def test_show_processes_empty(self):
- """
- Confirm getting a list of processes works.
- """
- init = MockInit()
- answer = init.command_handler("show_processes", None)
- self.assertEqual(answer, {'result': [0, []]})
-
- def test_show_processes(self):
- """
- Confirm getting a list of processes works.
- """
- init = MockInit()
- init.register_process(1, MockComponent('first', 1))
- init.register_process(2, MockComponent('second', 2, 'Second'))
- answer = init.command_handler("show_processes", None)
- processes = [[1, 'first', None],
- [2, 'second', 'Second']]
- self.assertEqual(answer, {'result': [0, processes]})
-
-class TestParseArgs(unittest.TestCase):
- """
- This tests parsing of arguments of the bind10 master process.
- """
- #TODO: Write tests for the original parsing, bad options, etc.
- def test_no_opts(self):
- """
- Test correct default values when no options are passed.
- """
- options = parse_args([], TestOptParser)
- self.assertEqual(None, options.data_path)
- self.assertEqual(None, options.config_file)
- self.assertEqual(None, options.cmdctl_port)
-
- def test_data_path(self):
- """
- Test it can parse the data path.
- """
- self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
- self.assertRaises(OptsError, parse_args, ['--data-path'],
- TestOptParser)
- options = parse_args(['-p', '/data/path'], TestOptParser)
- self.assertEqual('/data/path', options.data_path)
- options = parse_args(['--data-path=/data/path'], TestOptParser)
- self.assertEqual('/data/path', options.data_path)
-
- def test_config_filename(self):
- """
- Test it can parse the config switch.
- """
- self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
- self.assertRaises(OptsError, parse_args, ['--config-file'],
- TestOptParser)
- options = parse_args(['-c', 'config-file'], TestOptParser)
- self.assertEqual('config-file', options.config_file)
- options = parse_args(['--config-file=config-file'], TestOptParser)
- self.assertEqual('config-file', options.config_file)
-
- def test_clear_config(self):
- options = parse_args([], TestOptParser)
- self.assertEqual(False, options.clear_config)
- options = parse_args(['--clear-config'], TestOptParser)
- self.assertEqual(True, options.clear_config)
-
- def test_nokill(self):
- options = parse_args([], TestOptParser)
- self.assertEqual(False, options.nokill)
- options = parse_args(['--no-kill'], TestOptParser)
- self.assertEqual(True, options.nokill)
- options = parse_args([], TestOptParser)
- self.assertEqual(False, options.nokill)
- options = parse_args(['-i'], TestOptParser)
- self.assertEqual(True, options.nokill)
-
- def test_cmdctl_port(self):
- """
- Test it can parse the command control port.
- """
- self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
- TestOptParser)
- self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
- TestOptParser)
- self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
- TestOptParser)
- options = parse_args(['--cmdctl-port=1234'], TestOptParser)
- self.assertEqual(1234, options.cmdctl_port)
-
-class TestPIDFile(unittest.TestCase):
- def setUp(self):
- self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
- if os.path.exists(self.pid_file):
- os.unlink(self.pid_file)
-
- def tearDown(self):
- if os.path.exists(self.pid_file):
- os.unlink(self.pid_file)
-
- def check_pid_file(self):
- # dump PID to the file, and confirm the content is correct
- dump_pid(self.pid_file)
- my_pid = os.getpid()
- with open(self.pid_file, "r") as f:
- self.assertEqual(my_pid, int(f.read()))
-
- def test_dump_pid(self):
- self.check_pid_file()
-
- # make sure any existing content will be removed
- with open(self.pid_file, "w") as f:
- f.write('dummy data\n')
- self.check_pid_file()
-
- def test_unlink_pid_file_notexist(self):
- dummy_data = 'dummy_data\n'
-
- with open(self.pid_file, "w") as f:
- f.write(dummy_data)
-
- unlink_pid_file("no_such_pid_file")
-
- # the file specified for unlink_pid_file doesn't exist,
- # and the original content of the file should be intact.
- with open(self.pid_file, "r") as f:
- self.assertEqual(dummy_data, f.read())
-
- def test_dump_pid_with_none(self):
- # Check the behavior of dump_pid() and unlink_pid_file() with None.
- # This should be no-op.
- dump_pid(None)
- self.assertFalse(os.path.exists(self.pid_file))
-
- dummy_data = 'dummy_data\n'
-
- with open(self.pid_file, "w") as f:
- f.write(dummy_data)
-
- unlink_pid_file(None)
-
- with open(self.pid_file, "r") as f:
- self.assertEqual(dummy_data, f.read())
-
- def test_dump_pid_failure(self):
- # the attempt to open file will fail, which should result in exception.
- self.assertRaises(IOError, dump_pid,
- 'nonexistent_dir' + os.sep + 'bind10.pid')
-
-class TestInitComponents(unittest.TestCase):
- """
- Test b10-init propagates component configuration properly to the
- component configurator and acts sane.
- """
- def setUp(self):
- self.__param = None
- self.__called = False
- self.__compconfig = {
- 'comp': {
- 'kind': 'needed',
- 'process': 'cat'
- }
- }
- self._tmp_time = None
- self._tmp_sleep = None
- self._tmp_module_cc_session = None
- self._tmp_cc_session = None
-
- def tearDown(self):
- if self._tmp_time is not None:
- time.time = self._tmp_time
- if self._tmp_sleep is not None:
- time.sleep = self._tmp_sleep
- if self._tmp_module_cc_session is not None:
- isc.config.ModuleCCSession = self._tmp_module_cc_session
- if self._tmp_cc_session is not None:
- isc.cc.Session = self._tmp_cc_session
-
- def __unary_hook(self, param):
- """
- A hook function that stores the parameter for later examination.
- """
- self.__param = param
-
- def __nullary_hook(self):
- """
- A hook function that notes down it was called.
- """
- self.__called = True
-
- def __check_core(self, config):
- """
- A function checking that the config contains parts for the valid
- core component configuration.
- """
- self.assertIsNotNone(config)
- for component in ['sockcreator', 'msgq', 'cfgmgr']:
- self.assertTrue(component in config)
- self.assertEqual(component, config[component]['special'])
- self.assertEqual('core', config[component]['kind'])
-
- def __check_extended(self, config):
- """
- This checks that the config contains the core and one more component.
- """
- self.__check_core(config)
- self.assertTrue('comp' in config)
- self.assertEqual('cat', config['comp']['process'])
- self.assertEqual('needed', config['comp']['kind'])
- self.assertEqual(4, len(config))
-
- def test_correct_run(self):
- """
- Test the situation when we run in usual scenario, nothing fails,
- we just start, reconfigure and then stop peacefully.
- """
- init = MockInit()
- # Start it
- orig = init._component_configurator.startup
- init._component_configurator.startup = self.__unary_hook
- init.start_all_components()
- init._component_configurator.startup = orig
- self.__check_core(self.__param)
- self.assertEqual(3, len(self.__param))
-
- # Reconfigure it
- self.__param = None
- orig = init._component_configurator.reconfigure
- init._component_configurator.reconfigure = self.__unary_hook
- # Otherwise it does not work
- init.runnable = True
- init.config_handler({'components': self.__compconfig})
- self.__check_extended(self.__param)
- currconfig = self.__param
- # If we reconfigure it, but it does not contain the components part,
- # nothing is called
- init.config_handler({})
- self.assertEqual(self.__param, currconfig)
- self.__param = None
- init._component_configurator.reconfigure = orig
- # Check a configuration that messes up the core components is rejected.
- compconf = dict(self.__compconfig)
- compconf['msgq'] = { 'process': 'echo' }
- result = init.config_handler({'components': compconf})
- # Check it rejected it
- self.assertEqual(1, result['result'][0])
-
- # We can't call shutdown, that one relies on the stuff in main
- # We check somewhere else that the shutdown is actually called
- # from there (the test_kills).
-
- def __real_test_kill(self, nokill=False, ex_on_kill=None):
- """
- Helper function that does the actual kill functionality testing.
- """
- init = MockInit()
- init.nokill = nokill
-
- killed = []
- class ImmortalComponent:
- """
- An immortal component. It does not stop when it is told so
- (anyway it is not told so). It does not die if it is killed
- the first time. It dies only when killed forcefully.
- """
- def __init__(self):
- # number of kill() calls, preventing infinite loop.
- self.__call_count = 0
-
- def kill(self, forceful=False):
- self.__call_count += 1
- if self.__call_count > 2:
- raise Exception('Too many calls to ImmortalComponent.kill')
-
- killed.append(forceful)
- if ex_on_kill is not None:
- # If exception is given by the test, raise it here.
- # In the case of ESRCH, the process should have gone
- # somehow, so we clear the components.
- if ex_on_kill.errno == errno.ESRCH:
- init.components = {}
- raise ex_on_kill
- if forceful:
- init.components = {}
- def pid(self):
- return 1
- def name(self):
- return "Immortal"
- init.components = {}
- init.register_process(1, ImmortalComponent())
-
- # While at it, we check the configurator shutdown is actually called
- orig = init._component_configurator.shutdown
- init._component_configurator.shutdown = self.__nullary_hook
- self.__called = False
-
- init.ccs = MockModuleCCSession()
- self.assertFalse(init.ccs.stopped)
-
- init.shutdown()
-
- self.assertTrue(init.ccs.stopped)
-
- # Here, killed is an array where False is added if SIGTERM
- # should be sent, or True if SIGKILL should be sent, in order in
- # which they're sent.
- if nokill:
- self.assertEqual([], killed)
- else:
- if ex_on_kill is not None:
- self.assertEqual([False], killed)
- else:
- self.assertEqual([False, True], killed)
-
- self.assertTrue(self.__called)
-
- init._component_configurator.shutdown = orig
-
- def test_kills(self):
- """
- Test that b10-init kills components which don't want to stop.
- """
- self.__real_test_kill()
-
- def test_kill_fail(self):
- """Test cases where kill() results in an exception due to OS error.
-
- The behavior should be different for EPERM, so we test two cases.
-
- """
-
- ex = OSError()
- ex.errno, ex.strerror = errno.ESRCH, 'No such process'
- self.__real_test_kill(ex_on_kill=ex)
-
- ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
- self.__real_test_kill(ex_on_kill=ex)
-
- def test_nokill(self):
- """
- Test that b10-init *doesn't* kill components which don't want to
- stop, when asked not to (by passing the --no-kill option which
- sets init.nokill to True).
- """
- self.__real_test_kill(True)
-
- def test_component_shutdown(self):
- """
- Test the component_shutdown sets all variables accordingly.
- """
- init = MockInit()
- self.assertRaises(Exception, init.component_shutdown, 1)
- self.assertEqual(1, init.exitcode)
- init._Init__started = True
- init.component_shutdown(2)
- self.assertEqual(2, init.exitcode)
- self.assertFalse(init.runnable)
-
- def test_init_config(self):
- """
- Test initial configuration is loaded.
- """
- init = MockInit()
- # Start it
- init._component_configurator.reconfigure = self.__unary_hook
- # We need to return the original read_bind10_config
- init._read_bind10_config = lambda: Init._read_bind10_config(init)
- # And provide a session to read the data from
- class CC:
- pass
- init.ccs = CC()
- init.ccs.get_full_config = lambda: {'components': self.__compconfig}
- init.start_all_components()
- self.__check_extended(self.__param)
-
- def __setup_restart(self, init, component):
- '''Common procedure for restarting a component used below.'''
- init.components_to_restart = { component }
- component.restarted = False
- init.restart_processes()
-
- def test_restart_processes(self):
- '''Check some behavior on restarting processes.'''
- init = MockInit()
- init.runnable = True
- component = MockComponent('test', 53)
-
- # A component to be restarted will actually be restarted iff it's
- # in the configurator's configuration.
- # We bruteforce the configurator internal below; ugly, but the easiest
- # way for the test.
- init._component_configurator._components['test'] = (None, component)
- self.__setup_restart(init, component)
- self.assertTrue(component.restarted)
- self.assertNotIn(component, init.components_to_restart)
-
- # Remove the component from the configuration. It won't be restarted
- # even if scheduled, nor will remain in the to-be-restarted list.
- del init._component_configurator._components['test']
- self.__setup_restart(init, component)
- self.assertFalse(component.restarted)
- self.assertNotIn(component, init.components_to_restart)
-
- def test_get_processes(self):
- '''Test that procsses are returned correctly, sorted by pid.'''
- init = MockInit()
-
- pids = list(range(0, 20))
- random.shuffle(pids)
-
- for i in range(0, 20):
- pid = pids[i]
- component = MockComponent('test' + str(pid), pid,
- 'Test' + str(pid))
- init.components[pid] = component
-
- process_list = init.get_processes()
- self.assertEqual(20, len(process_list))
-
- last_pid = -1
- for process in process_list:
- pid = process[0]
- self.assertLessEqual(last_pid, pid)
- last_pid = pid
- self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
- process)
-
- def _test_reap_children_helper(self, runnable, is_running, failed):
- '''Construct a Init instance, set various data in it according to
- passed args and check if the component was added to the list of
- components to restart.'''
- init = MockInit()
- init.runnable = runnable
-
- component = MockComponent('test', 53)
- component.running = is_running
- component.has_failed = failed
- init.components[53] = component
-
- self.assertNotIn(component, init.components_to_restart)
-
- init.reap_children()
-
- if runnable and is_running and not failed:
- self.assertIn(component, init.components_to_restart)
- else:
- self.assertEqual([], init.components_to_restart)
-
- def test_reap_children(self):
- '''Test that children are queued to be restarted when they ask for it.'''
- # test various combinations of 3 booleans
- # (Init.runnable, component.is_running(), component.failed())
- self._test_reap_children_helper(False, False, False)
- self._test_reap_children_helper(False, False, True)
- self._test_reap_children_helper(False, True, False)
- self._test_reap_children_helper(False, True, True)
- self._test_reap_children_helper(True, False, False)
- self._test_reap_children_helper(True, False, True)
- self._test_reap_children_helper(True, True, False)
- self._test_reap_children_helper(True, True, True)
-
- # setup for more tests below
- init = MockInit()
- init.runnable = True
- component = MockComponent('test', 53)
- init.components[53] = component
-
- # case where the returned pid is unknown to us. nothing should
- # happpen then.
- init.get_process_exit_status_called = False
- init._get_process_exit_status = init._get_process_exit_status_unknown_pid
- init.components_to_restart = []
- # this should do nothing as the pid is unknown
- init.reap_children()
- self.assertEqual([], init.components_to_restart)
-
- # case where init._get_process_exit_status() raises OSError with
- # errno.ECHILD
- init._get_process_exit_status = \
- init._get_process_exit_status_raises_oserror_echild
- init.components_to_restart = []
- # this should catch and handle the OSError
- init.reap_children()
- self.assertEqual([], init.components_to_restart)
-
- # case where init._get_process_exit_status() raises OSError with
- # errno other than ECHILD
- init._get_process_exit_status = \
- init._get_process_exit_status_raises_oserror_other
- with self.assertRaises(OSError):
- init.reap_children()
-
- # case where init._get_process_exit_status() raises something
- # other than OSError
- init._get_process_exit_status = \
- init._get_process_exit_status_raises_other
- with self.assertRaises(Exception):
- init.reap_children()
-
- def test_kill_started_components(self):
- '''Test that started components are killed.'''
- init = MockInit()
-
- component = MockComponent('test', 53, 'Test')
- init.components[53] = component
-
- self.assertEqual([[53, 'test', 'Test']], init.get_processes())
- init.kill_started_components()
- self.assertEqual([], init.get_processes())
- self.assertTrue(component.forceful)
-
- def _start_msgq_helper(self, init, verbose):
- init.verbose = verbose
- pi = init.start_msgq()
- self.assertEqual('b10-msgq', pi.name)
- self.assertEqual(['b10-msgq'], pi.args)
- self.assertTrue(pi.dev_null_stdout)
- self.assertEqual(pi.dev_null_stderr, not verbose)
- self.assertEqual({'FOO': 'an env string'}, pi.env)
-
- # this is set by ProcessInfo.spawn()
- self.assertEqual(42147, pi.pid)
-
- def test_start_msgq(self):
- '''Test that b10-msgq is started.'''
- init = MockInitSimple()
- init.c_channel_env = {'FOO': 'an env string'}
- init._run_under_unittests = True
-
- # use the MockProcessInfo creator
- init._make_process_info = init._make_mock_process_info
-
- # non-verbose case
- self._start_msgq_helper(init, False)
-
- # verbose case
- self._start_msgq_helper(init, True)
-
- def test_start_msgq_timeout(self):
- '''Test that b10-msgq startup attempts connections several times
- and times out eventually.'''
- b10_init = MockInitSimple()
- b10_init.c_channel_env = {}
- # set the timeout to an arbitrary pre-determined value (which
- # code below depends on)
- b10_init.msgq_timeout = 1
- b10_init._run_under_unittests = False
-
- # use the MockProcessInfo creator
- b10_init._make_process_info = b10_init._make_mock_process_info
-
- global attempts
- global tsec
- attempts = 0
- tsec = 0
- self._tmp_time = time.time
- self._tmp_sleep = time.sleep
- def _my_time():
- global attempts
- global tsec
- attempts += 1
- return tsec
- def _my_sleep(nsec):
- global tsec
- tsec += nsec
- time.time = _my_time
- time.sleep = _my_sleep
-
- global cc_sub
- cc_sub = None
- class DummySessionAlwaysFails():
- def __init__(self, socket_file):
- raise isc.cc.session.SessionError('Connection fails')
- def group_subscribe(self, s):
- global cc_sub
- cc_sub = s
-
- isc.cc.Session = DummySessionAlwaysFails
-
- with self.assertRaises(init.CChannelConnectError):
- # An exception will be thrown here when it eventually times
- # out.
- pi = b10_init.start_msgq()
-
- # time.time() should be called 12 times within the while loop:
- # starting from 0, and 11 more times from 0.1 to 1.1. There's
- # another call to time.time() outside the loop, which makes it
- # 13.
- self.assertEqual(attempts, 13)
-
- # group_subscribe() should not have been called here.
- self.assertIsNone(cc_sub)
-
- global cc_socket_file
- cc_socket_file = None
- cc_sub = None
- class DummySession():
- def __init__(self, socket_file):
- global cc_socket_file
- cc_socket_file = socket_file
- def group_subscribe(self, s):
- global cc_sub
- cc_sub = s
-
- isc.cc.Session = DummySession
-
- # reset values
- attempts = 0
- tsec = 0
-
- pi = b10_init.start_msgq()
-
- # just one attempt, but 2 calls to time.time()
- self.assertEqual(attempts, 2)
-
- self.assertEqual(cc_socket_file, b10_init.msgq_socket_file)
- self.assertEqual(cc_sub, 'Init')
-
- # isc.cc.Session, time.time() and time.sleep() are restored
- # during tearDown().
-
- def _start_cfgmgr_helper(self, init, data_path, filename, clear_config):
- expect_args = ['b10-cfgmgr']
- if data_path is not None:
- init.data_path = data_path
- expect_args.append('--data-path=' + data_path)
- if filename is not None:
- init.config_filename = filename
- expect_args.append('--config-filename=' + filename)
- if clear_config:
- init.clear_config = clear_config
- expect_args.append('--clear-config')
-
- pi = init.start_cfgmgr()
- self.assertEqual('b10-cfgmgr', pi.name)
- self.assertEqual(expect_args, pi.args)
- self.assertEqual({'TESTENV': 'A test string'}, pi.env)
-
- # this is set by ProcessInfo.spawn()
- self.assertEqual(42147, pi.pid)
-
- def test_start_cfgmgr(self):
- '''Test that b10-cfgmgr is started.'''
- class DummySession():
- def __init__(self):
- self._tries = 0
- def group_recvmsg(self):
- self._tries += 1
- # return running on the 3rd try onwards
- if self._tries >= 3:
- return ({'running': 'ConfigManager'}, None)
- else:
- return ({}, None)
-
- init = MockInitSimple()
- init.c_channel_env = {'TESTENV': 'A test string'}
- init.cc_session = DummySession()
- init.wait_time = 5
-
- # use the MockProcessInfo creator
- init._make_process_info = init._make_mock_process_info
-
- global attempts
- attempts = 0
- self._tmp_sleep = time.sleep
- def _my_sleep(nsec):
- global attempts
- attempts += 1
- time.sleep = _my_sleep
-
- # defaults
- self._start_cfgmgr_helper(init, None, None, False)
-
- # check that 2 attempts were made. on the 3rd attempt,
- # process_running() returns that ConfigManager is running.
- self.assertEqual(attempts, 2)
-
- # data_path is specified
- self._start_cfgmgr_helper(init, '/var/lib/test', None, False)
-
- # config_filename is specified. Because `init` is not
- # reconstructed, data_path is retained from the last call to
- # _start_cfgmgr_helper().
- self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', False)
-
- # clear_config is specified. Because `init` is not reconstructed,
- # data_path and config_filename are retained from the last call
- # to _start_cfgmgr_helper().
- self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', True)
-
- def test_start_cfgmgr_timeout(self):
- '''Test that b10-cfgmgr startup attempts connections several times
- and times out eventually.'''
- class DummySession():
- def group_recvmsg(self):
- return (None, None)
- b10_init = MockInitSimple()
- b10_init.c_channel_env = {}
- b10_init.cc_session = DummySession()
- # set wait_time to an arbitrary pre-determined value (which code
- # below depends on)
- b10_init.wait_time = 2
-
- # use the MockProcessInfo creator
- b10_init._make_process_info = b10_init._make_mock_process_info
-
- global attempts
- attempts = 0
- self._tmp_sleep = time.sleep
- def _my_sleep(nsec):
- global attempts
- attempts += 1
- time.sleep = _my_sleep
-
- # We just check that an exception was thrown, and that several
- # attempts were made to connect.
- with self.assertRaises(init.ProcessStartError):
- pi = b10_init.start_cfgmgr()
-
- # 2 seconds of attempts every 1 second should result in 2 attempts
- self.assertEqual(attempts, 2)
-
- # time.sleep() is restored during tearDown().
-
- def test_start_ccsession(self):
- '''Test that CC session is started.'''
- class DummySession():
- def __init__(self, specfile, config_handler, command_handler,
- socket_file):
- self.specfile = specfile
- self.config_handler = config_handler
- self.command_handler = command_handler
- self.socket_file = socket_file
- self.started = False
- def start(self):
- self.started = True
- b10_init = MockInitSimple()
- self._tmp_module_cc_session = isc.config.ModuleCCSession
- isc.config.ModuleCCSession = DummySession
-
- b10_init.start_ccsession({})
- self.assertEqual(init.SPECFILE_LOCATION, b10_init.ccs.specfile)
- self.assertEqual(b10_init.config_handler, b10_init.ccs.config_handler)
- self.assertEqual(b10_init.command_handler,
- b10_init.ccs.command_handler)
- self.assertEqual(b10_init.msgq_socket_file, b10_init.ccs.socket_file)
- self.assertTrue(b10_init.ccs.started)
-
- # isc.config.ModuleCCSession is restored during tearDown().
-
- def test_start_process(self):
- '''Test that processes can be started.'''
- init = MockInit()
-
- # use the MockProcessInfo creator
- init._make_process_info = init._make_mock_process_info
-
- pi = init.start_process('Test Process', ['/bin/true'], {})
- self.assertEqual('Test Process', pi.name)
- self.assertEqual(['/bin/true'], pi.args)
- self.assertEqual({}, pi.env)
-
- # this is set by ProcessInfo.spawn()
- self.assertEqual(42147, pi.pid)
-
- def test_register_process(self):
- '''Test that processes can be registered with Init.'''
- init = MockInit()
- component = MockComponent('test', 53, 'Test')
-
- self.assertFalse(53 in init.components)
- init.register_process(53, component)
- self.assertTrue(53 in init.components)
- self.assertEqual(init.components[53].name(), 'test')
- self.assertEqual(init.components[53].pid(), 53)
- self.assertEqual(init.components[53].address(), 'Test')
-
- def _start_simple_helper(self, init, verbose):
- init.verbose = verbose
-
- args = ['/bin/true']
- if verbose:
- args.append('-v')
-
- init.start_simple('/bin/true')
- self.assertEqual('/bin/true', init.started_process_name)
- self.assertEqual(args, init.started_process_args)
- self.assertEqual({'TESTENV': 'A test string'}, init.started_process_env)
-
- def test_start_simple(self):
- '''Test simple process startup.'''
- init = MockInitSimple()
- init.c_channel_env = {'TESTENV': 'A test string'}
-
- # non-verbose case
- self._start_simple_helper(init, False)
-
- # verbose case
- self._start_simple_helper(init, True)
-
- def _start_auth_helper(self, init, verbose):
- init.verbose = verbose
-
- args = ['b10-auth']
- if verbose:
- args.append('-v')
-
- init.start_auth()
- self.assertEqual('b10-auth', init.started_process_name)
- self.assertEqual(args, init.started_process_args)
- self.assertEqual({'FOO': 'an env string'}, init.started_process_env)
-
- def test_start_auth(self):
- '''Test that b10-auth is started.'''
- init = MockInitSimple()
- init.c_channel_env = {'FOO': 'an env string'}
-
- # non-verbose case
- self._start_auth_helper(init, False)
-
- # verbose case
- self._start_auth_helper(init, True)
-
- def _start_resolver_helper(self, init, verbose):
- init.verbose = verbose
-
- args = ['b10-resolver']
- if verbose:
- args.append('-v')
-
- init.start_resolver()
- self.assertEqual('b10-resolver', init.started_process_name)
- self.assertEqual(args, init.started_process_args)
- self.assertEqual({'BAR': 'an env string'}, init.started_process_env)
-
- def test_start_resolver(self):
- '''Test that b10-resolver is started.'''
- init = MockInitSimple()
- init.c_channel_env = {'BAR': 'an env string'}
-
- # non-verbose case
- self._start_resolver_helper(init, False)
-
- # verbose case
- self._start_resolver_helper(init, True)
-
- def _start_cmdctl_helper(self, init, verbose, port = None):
- init.verbose = verbose
-
- args = ['b10-cmdctl']
-
- if port is not None:
- init.cmdctl_port = port
- args.append('--port=9353')
-
- if verbose:
- args.append('-v')
-
- init.start_cmdctl()
- self.assertEqual('b10-cmdctl', init.started_process_name)
- self.assertEqual(args, init.started_process_args)
- self.assertEqual({'BAZ': 'an env string'}, init.started_process_env)
-
- def test_start_cmdctl(self):
- '''Test that b10-cmdctl is started.'''
- init = MockInitSimple()
- init.c_channel_env = {'BAZ': 'an env string'}
-
- # non-verbose case
- self._start_cmdctl_helper(init, False)
-
- # verbose case
- self._start_cmdctl_helper(init, True)
-
- # with port, non-verbose case
- self._start_cmdctl_helper(init, False, 9353)
-
- # with port, verbose case
- self._start_cmdctl_helper(init, True, 9353)
-
- def test_socket_data(self):
- '''Test that Init._socket_data works as expected.'''
- class MockSock:
- def __init__(self, fd, throw):
- self.fd = fd
- self.throw = throw
- self.buf = b'Hello World.\nYou are so nice today.\nXX'
- self.i = 0
-
- def recv(self, bufsize, flags = 0):
- if bufsize != 1:
- raise Exception('bufsize != 1')
- if flags != socket.MSG_DONTWAIT:
- raise Exception('flags != socket.MSG_DONTWAIT')
- # after 15 recv()s, throw a socket.error with EAGAIN to
- # get _socket_data() to save back what's been read. The
- # number 15 is arbitrarily chosen, but the checks then
- # depend on this being 15, i.e., if you adjust this
- # number, you may have to adjust the checks below too.
- if self.throw and self.i > 15:
- raise socket.error(errno.EAGAIN, 'Try again')
- if self.i >= len(self.buf):
- return b'';
- t = self.i
- self.i += 1
- return self.buf[t:t+1]
-
- def close(self):
- return
-
- class MockInitSocketData(Init):
- def __init__(self, throw):
- self._unix_sockets = {42: (MockSock(42, throw), b'')}
- self.requests = []
- self.dead = []
-
- def socket_request_handler(self, previous, sock):
- self.requests.append({sock.fd: previous})
-
- def socket_consumer_dead(self, sock):
- self.dead.append(sock.fd)
-
- # Case where we get data every time we call recv()
- init = MockInitSocketData(False)
- init._socket_data(42)
- self.assertEqual(init.requests,
- [{42: b'Hello World.'},
- {42: b'You are so nice today.'}])
- self.assertEqual(init.dead, [42])
- self.assertEqual({}, init._unix_sockets)
-
- # Case where socket.recv() raises EAGAIN. In this case, the
- # routine is supposed to save what it has back to
- # Init._unix_sockets.
- init = MockInitSocketData(True)
- init._socket_data(42)
- self.assertEqual(init.requests, [{42: b'Hello World.'}])
- self.assertFalse(init.dead)
- self.assertEqual(len(init._unix_sockets), 1)
- self.assertEqual(init._unix_sockets[42][1], b'You')
-
- def test_startup(self):
- '''Test that Init.startup() handles failures properly.'''
- class MockInitStartup(Init):
- def __init__(self, throw):
- self.throw = throw
- self.started = False
- self.killed = False
- self.msgq_socket_file = None
- self.curproc = 'myproc'
- self.runnable = False
-
- def start_all_components(self):
- self.started = True
- if self.throw is True:
- raise Exception('Assume starting components has failed.')
- elif self.throw:
- raise self.throw
-
- def kill_started_components(self):
- self.killed = True
-
- class DummySession():
- def __init__(self, socket_file):
- raise isc.cc.session.SessionError('This is the expected case.')
-
- class DummySessionSocketExists():
- def __init__(self, socket_file):
- # simulate that connect passes
- return
-
- isc.cc.Session = DummySession
-
- # All is well case, where all components are started
- # successfully. We check that the actual call to
- # start_all_components() is made, and Init.runnable is true.
- b10_init = MockInitStartup(False)
- r = b10_init.startup()
- self.assertIsNone(r)
- self.assertTrue(b10_init.started)
- self.assertFalse(b10_init.killed)
- self.assertTrue(b10_init.runnable)
- self.assertEqual({}, b10_init.c_channel_env)
-
- # Case where starting components fails. We check that
- # kill_started_components() is called right after, and
- # Init.runnable is not modified.
- b10_init = MockInitStartup(True)
- r = b10_init.startup()
- # r contains an error message
- self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
- self.assertTrue(b10_init.started)
- self.assertTrue(b10_init.killed)
- self.assertFalse(b10_init.runnable)
- self.assertEqual({}, b10_init.c_channel_env)
-
- # Check if msgq_socket_file is carried over
- b10_init = MockInitStartup(False)
- b10_init.msgq_socket_file = 'foo'
- r = b10_init.startup()
- self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'},
- b10_init.c_channel_env)
-
- # Check failure of changing user results in a different message
- b10_init = MockInitStartup(init.ChangeUserError('failed to chusr'))
- r = b10_init.startup()
- self.assertIn('failed to chusr', r)
- self.assertTrue(b10_init.killed)
-
- # Check the case when socket file already exists
- isc.cc.Session = DummySessionSocketExists
- b10_init = MockInitStartup(False)
- r = b10_init.startup()
- self.assertIn('already running', r)
-
- # isc.cc.Session is restored during tearDown().
-
-class SocketSrvTest(unittest.TestCase):
- """
- This tests some methods of b10-init related to the unix domain sockets
- used to transfer other sockets to applications.
- """
- def setUp(self):
- """
- Create the b10-init to test, testdata and backup some functions.
- """
- self.__b10_init = Init()
- self.__select_backup = init.select.select
- self.__select_called = None
- self.__socket_data_called = None
- self.__consumer_dead_called = None
- self.__socket_request_handler_called = None
-
- def tearDown(self):
- """
- Restore functions.
- """
- init.select.select = self.__select_backup
-
- class __FalseSocket:
- """
- A mock socket for the select and accept and stuff like that.
- """
- def __init__(self, owner, fileno=42):
- self.__owner = owner
- self.__fileno = fileno
- self.data = None
- self.closed = False
-
- def fileno(self):
- return self.__fileno
-
- def accept(self):
- return (self.__class__(self.__owner, 13), "/path/to/socket")
-
- def recv(self, bufsize, flags=0):
- self.__owner.assertEqual(1, bufsize)
- self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
- if isinstance(self.data, socket.error):
- raise self.data
- elif self.data is not None:
- if len(self.data):
- result = self.data[0:1]
- self.data = self.data[1:]
- return result
- else:
- raise socket.error(errno.EAGAIN, "Would block")
- else:
- return b''
-
- def close(self):
- self.closed = True
-
- class __CCS:
- """
- A mock CCS, just to provide the socket file number.
- """
- class __Socket:
- def fileno(self):
- return 1
- def get_socket(self):
- return self.__Socket()
-
- def __select_accept(self, r, w, x, t):
- self.__select_called = (r, w, x, t)
- return ([42], [], [])
-
- def __select_data(self, r, w, x, t):
- self.__select_called = (r, w, x, t)
- return ([13], [], [])
-
- def __accept(self):
- """
- Hijack the accept method of the b10-init.
-
- Notes down it was called and stops b10-init.
- """
- self.__accept_called = True
- self.__b10_init.runnable = False
-
- def test_srv_accept_called(self):
- """
- Test that the _srv_accept method of b10-init is called when the
- listening socket is readable.
- """
- self.__b10_init.runnable = True
- self.__b10_init._srv_socket = self.__FalseSocket(self)
- self.__b10_init._srv_accept = self.__accept
- self.__b10_init.ccs = self.__CCS()
- init.select.select = self.__select_accept
- self.__b10_init.run(2)
- # It called the accept
- self.assertTrue(self.__accept_called)
- # And the select had the right parameters
- self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
-
- def test_srv_accept(self):
- """
- Test how the _srv_accept method works.
- """
- self.__b10_init._srv_socket = self.__FalseSocket(self)
- self.__b10_init._srv_accept()
- # After we accepted, a new socket is added there
- socket = self.__b10_init._unix_sockets[13][0]
- # The socket is properly stored there
- self.assertTrue(isinstance(socket, self.__FalseSocket))
- # And the buffer (yet empty) is there
- self.assertEqual({13: (socket, b'')}, self.__b10_init._unix_sockets)
-
- def __socket_data(self, socket):
- self.__b10_init.runnable = False
- self.__socket_data_called = socket
-
- def test_socket_data(self):
- """
- Test that a socket that wants attention gets it.
- """
- self.__b10_init._srv_socket = self.__FalseSocket(self)
- self.__b10_init._socket_data = self.__socket_data
- self.__b10_init.ccs = self.__CCS()
- self.__b10_init._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
- self.__b10_init.runnable = True
- init.select.select = self.__select_data
- self.__b10_init.run(2)
- self.assertEqual(13, self.__socket_data_called)
- self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
-
- def __prepare_data(self, data):
- socket = self.__FalseSocket(self, 13)
- self.__b10_init._unix_sockets = {13: (socket, b'')}
- socket.data = data
- self.__b10_init.socket_consumer_dead = self.__consumer_dead
- self.__b10_init.socket_request_handler = self.__socket_request_handler
- return socket
-
- def __consumer_dead(self, socket):
- self.__consumer_dead_called = socket
-
- def __socket_request_handler(self, token, socket):
- self.__socket_request_handler_called = (token, socket)
-
- def test_socket_closed(self):
- """
- Test that a socket is removed and the socket_consumer_dead is called
- when it is closed.
- """
- socket = self.__prepare_data(None)
- self.__b10_init._socket_data(13)
- self.assertEqual(socket, self.__consumer_dead_called)
- self.assertEqual({}, self.__b10_init._unix_sockets)
- self.assertTrue(socket.closed)
-
- def test_socket_short(self):
- """
- Test that if there's not enough data to get the whole socket, it is
- kept there, but nothing is called.
- """
- socket = self.__prepare_data(b'tok')
- self.__b10_init._socket_data(13)
- self.assertEqual({13: (socket, b'tok')}, self.__b10_init._unix_sockets)
- self.assertFalse(socket.closed)
- self.assertIsNone(self.__consumer_dead_called)
- self.assertIsNone(self.__socket_request_handler_called)
-
- def test_socket_continue(self):
- """
- Test that we call the token handling function when the whole token
- comes. This test pretends to continue reading where the previous one
- stopped.
- """
- socket = self.__prepare_data(b"en\nanothe")
- # The data to finish
- self.__b10_init._unix_sockets[13] = (socket, b'tok')
- self.__b10_init._socket_data(13)
- self.assertEqual({13: (socket, b'anothe')}, self.__b10_init._unix_sockets)
- self.assertFalse(socket.closed)
- self.assertIsNone(self.__consumer_dead_called)
- self.assertEqual((b'token', socket),
- self.__socket_request_handler_called)
-
- def test_broken_socket(self):
- """
- If the socket raises an exception during the read other than EAGAIN,
- it is broken and we remove it.
- """
- sock = self.__prepare_data(socket.error(errno.ENOMEM,
- "There's more memory available, but not for you"))
- self.__b10_init._socket_data(13)
- self.assertEqual(sock, self.__consumer_dead_called)
- self.assertEqual({}, self.__b10_init._unix_sockets)
- self.assertTrue(sock.closed)
-
-class TestFunctions(unittest.TestCase):
- def setUp(self):
- self.lockfile_testpath = \
- "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
- self.assertFalse(os.path.exists(self.lockfile_testpath))
- os.mkdir(self.lockfile_testpath)
- self.assertTrue(os.path.isdir(self.lockfile_testpath))
- self.__isfile_orig = init.os.path.isfile
- self.__unlink_orig = init.os.unlink
-
- def tearDown(self):
- os.rmdir(self.lockfile_testpath)
- self.assertFalse(os.path.isdir(self.lockfile_testpath))
- os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
- init.os.path.isfile = self.__isfile_orig
- init.os.unlink = self.__unlink_orig
-
- def test_remove_lock_files(self):
- os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
-
- # create lockfiles for the testcase
- lockfiles = ["logger_lockfile"]
- for f in lockfiles:
- fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
- self.assertFalse(os.path.exists(fname))
- open(fname, "w").close()
- self.assertTrue(os.path.isfile(fname))
-
- # first call should clear up all the lockfiles
- init.remove_lock_files()
-
- # check if the lockfiles exist
- for f in lockfiles:
- fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
- self.assertFalse(os.path.isfile(fname))
-
- # second call should not assert anyway
- init.remove_lock_files()
-
- def test_remove_lock_files_fail(self):
- # Permission error on unlink is ignored; other exceptions are really
- # unexpected and propagated.
- def __raising_unlink(unused, ex):
- raise ex
-
- init.os.path.isfile = lambda _: True
- os_error = OSError()
- init.os.unlink = lambda f: __raising_unlink(f, os_error)
-
- os_error.errno = errno.EPERM
- init.remove_lock_files() # no disruption
-
- os_error.errno = errno.EACCES
- init.remove_lock_files() # no disruption
-
- os_error.errno = errno.ENOENT
- self.assertRaises(OSError, init.remove_lock_files)
-
- init.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
- self.assertRaises(Exception, init.remove_lock_files)
-
- def test_get_signame(self):
- # just test with some samples
- signame = init.get_signame(signal.SIGTERM)
- self.assertEqual('SIGTERM', signame)
- signame = init.get_signame(signal.SIGKILL)
- self.assertEqual('SIGKILL', signame)
- # 59426 is hopefully an unused signal on most platforms
- signame = init.get_signame(59426)
- self.assertEqual('Unknown signal 59426', signame)
-
- def test_fatal_signal(self):
- self.assertIsNone(init.b10_init)
- init.b10_init = Init()
- init.b10_init.runnable = True
- init.fatal_signal(signal.SIGTERM, None)
- # Now, runnable must be False
- self.assertFalse(init.b10_init.runnable)
- init.b10_init = None
-
-if __name__ == '__main__':
- # store os.environ for test_unchanged_environment
- original_os_environ = copy.deepcopy(os.environ)
- isc.log.resetUnitTestRootLogger()
- unittest.main()
diff --git a/src/bin/bind10/tests/init_test.py.in b/src/bin/bind10/tests/init_test.py.in
new file mode 100644
index 0000000..9a591ef
--- /dev/null
+++ b/src/bin/bind10/tests/init_test.py.in
@@ -0,0 +1,2426 @@
+# 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.
+
+# Most of the time, we omit the "init" for brevity. Sometimes,
+# we want to be explicit about what we do, like when hijacking a library
+# call used by the b10-init.
+from init import Init, ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME
+import init
+
+# XXX: environment tests are currently disabled, due to the preprocessor
+# setup that we have now complicating the environment
+
+import unittest
+import sys
+import os
+import os.path
+import copy
+import signal
+import socket
+from isc.net.addr import IPAddr
+import time
+import isc.log
+import isc.config
+import isc.bind10.socket_cache
+import errno
+import random
+
+from isc.testutils.parse_args import TestOptParser, OptsError
+from isc.testutils.ccsession_mock import MockModuleCCSession
+
+class TestProcessInfo(unittest.TestCase):
+ def setUp(self):
+ # redirect stdout to a pipe so we can check that our
+ # process spawning is doing the right thing with stdout
+ self.old_stdout = os.dup(sys.stdout.fileno())
+ self.pipes = os.pipe()
+ os.dup2(self.pipes[1], sys.stdout.fileno())
+ os.close(self.pipes[1])
+ # note that we use dup2() to restore the original stdout
+ # to the main program ASAP in each test... this prevents
+ # hangs reading from the child process (as the pipe is only
+ # open in the child), and also insures nice pretty output
+
+ def tearDown(self):
+ # clean up our stdout munging
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ os.close(self.pipes[0])
+
+ def test_init(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+ pi.spawn()
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ self.assertEqual(pi.name, 'Test Process')
+ self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+ self.assertEqual(pi.dev_null_stdout, False)
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ self.assertNotEqual(pi.process, None)
+ self.assertTrue(type(pi.pid) is int)
+
+# def test_setting_env(self):
+# pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
+# os.dup2(self.old_stdout, sys.stdout.fileno())
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
+# 'FOO': 'BAR' })
+
+ def test_setting_null_stdout(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
+ dev_null_stdout=True)
+ pi.spawn()
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ self.assertEqual(pi.dev_null_stdout, True)
+ self.assertEqual(os.read(self.pipes[0], 100), b"")
+
+ def test_respawn(self):
+ pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+ pi.spawn()
+ # wait for old process to work...
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ # respawn it
+ old_pid = pi.pid
+ pi.respawn()
+ os.dup2(self.old_stdout, sys.stdout.fileno())
+ # make sure the new one started properly
+ self.assertEqual(pi.name, 'Test Process')
+ self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+# self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+# 'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+ self.assertEqual(pi.dev_null_stdout, False)
+ self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+ self.assertNotEqual(pi.process, None)
+ self.assertTrue(type(pi.pid) is int)
+ self.assertNotEqual(pi.pid, old_pid)
+
+class TestCacheCommands(unittest.TestCase):
+ """
+ Test methods of b10-init related to the socket cache and socket handling.
+ """
+ def setUp(self):
+ """
+ Prepare b10-init for some tests.
+
+ Also prepare some variables we need.
+ """
+ self.__b10_init = Init()
+ # Fake the cache here so we can pretend it is us and hijack the
+ # calls to its methods.
+ self.__b10_init._socket_cache = self
+ self.__b10_init._socket_path = '/socket/path'
+ self.__raise_exception = None
+ self.__socket_args = {
+ "port": 53,
+ "address": "::",
+ "protocol": "UDP",
+ "share_mode": "ANY",
+ "share_name": "app"
+ }
+ # What was and wasn't called.
+ self.__drop_app_called = None
+ self.__get_socket_called = None
+ self.__send_fd_called = None
+ self.__get_token_called = None
+ self.__drop_socket_called = None
+ init.libutil_io_python.send_fd = self.__send_fd
+
+ def __send_fd(self, to, socket):
+ """
+ A function to hook the send_fd in the b10-init.
+ """
+ self.__send_fd_called = (to, socket)
+
+ class FalseSocket:
+ """
+ A socket where we can fake methods we need instead of having a real
+ socket.
+ """
+ def __init__(self):
+ self.send = b""
+ def fileno(self):
+ """
+ The file number. Used for identifying the remote application.
+ """
+ return 42
+
+ def sendall(self, data):
+ """
+ Adds data to the self.send.
+ """
+ self.send += data
+
+ def drop_application(self, application):
+ """
+ Part of pretending to be the cache. Logs the parameter to
+ self.__drop_app_called.
+
+ In the case self.__raise_exception is set, the exception there
+ is raised instead.
+ """
+ if self.__raise_exception is not None:
+ raise self.__raise_exception
+ self.__drop_app_called = application
+
+ def test_consumer_dead(self):
+ """
+ Test that it calls the drop_application method of the cache.
+ """
+ self.__b10_init.socket_consumer_dead(self.FalseSocket())
+ self.assertEqual(42, self.__drop_app_called)
+
+ def test_consumer_dead_invalid(self):
+ """
+ Test that it doesn't crash in case the application is not known to
+ the cache, the b10_init doesn't crash, as this actually can happen in
+ practice.
+ """
+ self.__raise_exception = ValueError("This application is unknown")
+ # This doesn't crash
+ self.__b10_init.socket_consumer_dead(self.FalseSocket())
+
+ def get_socket(self, token, application):
+ """
+ Part of pretending to be the cache. If there's anything in
+ __raise_exception, it is raised. Otherwise, the call is logged
+ into __get_socket_called and a number is returned.
+ """
+ if self.__raise_exception is not None:
+ raise self.__raise_exception
+ self.__get_socket_called = (token, application)
+ return 13
+
+ def test_request_handler(self):
+ """
+ Test that a request for socket is forwarded and the socket is sent
+ back, if it returns a socket.
+ """
+ socket = self.FalseSocket()
+ # An exception from the cache
+ self.__raise_exception = ValueError("Test value error")
+ self.__b10_init.socket_request_handler(b"token", socket)
+ # It was called, but it threw, so it is not noted here
+ self.assertIsNone(self.__get_socket_called)
+ self.assertEqual(b"0\n", socket.send)
+ # It should not have sent any socket.
+ self.assertIsNone(self.__send_fd_called)
+ # Now prepare a valid scenario
+ self.__raise_exception = None
+ socket.send = b""
+ self.__b10_init.socket_request_handler(b"token", socket)
+ self.assertEqual(b"1\n", socket.send)
+ self.assertEqual((42, 13), self.__send_fd_called)
+ self.assertEqual(("token", 42), self.__get_socket_called)
+
+ def get_token(self, protocol, address, port, share_mode, share_name):
+ """
+ Part of pretending to be the cache. If there's anything in
+ __raise_exception, it is raised. Otherwise, the parameters are
+ logged into __get_token_called and a token is returned.
+ """
+ if self.__raise_exception is not None:
+ raise self.__raise_exception
+ self.__get_token_called = (protocol, address, port, share_mode,
+ share_name)
+ return "token"
+
+ def test_get_socket_ok(self):
+ """
+ Test the successful scenario of getting a socket.
+ """
+ result = self.__b10_init._get_socket(self.__socket_args)
+ [code, answer] = result['result']
+ self.assertEqual(0, code)
+ self.assertEqual({
+ 'token': 'token',
+ 'path': '/socket/path'
+ }, answer)
+ addr = self.__get_token_called[1]
+ self.assertTrue(isinstance(addr, IPAddr))
+ self.assertEqual("::", str(addr))
+ self.assertEqual(("UDP", addr, 53, "ANY", "app"),
+ self.__get_token_called)
+
+ def test_get_socket_error(self):
+ """
+ Test that bad inputs are handled correctly, etc.
+ """
+ def check_code(code, args):
+ """
+ Pass the args there and check if it returns success or not.
+
+ The rest is not tested, as it is already checked in the
+ test_get_socket_ok.
+ """
+ [rcode, ranswer] = self.__b10_init._get_socket(args)['result']
+ self.assertEqual(code, rcode)
+ if code != 0:
+ # This should be an error message. The exact formatting
+ # is unknown, but we check it is string at least
+ self.assertTrue(isinstance(ranswer, str))
+
+ def mod_args(name, value):
+ """
+ Override a parameter in the args.
+ """
+ result = dict(self.__socket_args)
+ result[name] = value
+ return result
+
+ # Port too large
+ check_code(1, mod_args('port', 65536))
+ # Not numeric address
+ check_code(1, mod_args('address', 'example.org.'))
+ # Some bad values of enum-like params
+ check_code(1, mod_args('protocol', 'BAD PROTO'))
+ check_code(1, mod_args('share_mode', 'BAD SHARE'))
+ # Check missing parameters
+ for param in self.__socket_args.keys():
+ args = dict(self.__socket_args)
+ del args[param]
+ check_code(1, args)
+ # These are OK values for the enum-like parameters
+ # The ones from test_get_socket_ok are not tested here
+ check_code(0, mod_args('protocol', 'TCP'))
+ check_code(0, mod_args('share_mode', 'SAMEAPP'))
+ check_code(0, mod_args('share_mode', 'NO'))
+ # If an exception is raised from within the cache, it is converted
+ # to an error, not propagated
+ self.__raise_exception = Exception("Test exception")
+ check_code(1, self.__socket_args)
+ # The special "expected" exceptions
+ self.__raise_exception = \
+ isc.bind10.socket_cache.ShareError("Not shared")
+ check_code(3, self.__socket_args)
+ self.__raise_exception = \
+ isc.bind10.socket_cache.SocketError("Not shared", 13)
+ check_code(2, self.__socket_args)
+
+ def drop_socket(self, token):
+ """
+ Part of pretending to be the cache. If there's anything in
+ __raise_exception, it is raised. Otherwise, the parameter is stored
+ in __drop_socket_called.
+ """
+ if self.__raise_exception is not None:
+ raise self.__raise_exception
+ self.__drop_socket_called = token
+
+ def test_drop_socket(self):
+ """
+ Check the drop_socket command. It should directly call the method
+ on the cache. Exceptions should be translated to error messages.
+ """
+ # This should be OK and just propagated to the call.
+ self.assertEqual({"result": [0]},
+ self.__b10_init.command_handler("drop_socket",
+ {"token": "token"}))
+ self.assertEqual("token", self.__drop_socket_called)
+ self.__drop_socket_called = None
+ # Missing parameter
+ self.assertEqual({"result": [1, "Missing token parameter"]},
+ self.__b10_init.command_handler("drop_socket", {}))
+ self.assertIsNone(self.__drop_socket_called)
+ # An exception is raised from within the cache
+ self.__raise_exception = ValueError("Test error")
+ self.assertEqual({"result": [1, "Test error"]},
+ self.__b10_init.command_handler("drop_socket",
+ {"token": "token"}))
+
+
+class TestInit(unittest.TestCase):
+ def setUp(self):
+ # Save original values that may be tweaked in some tests
+ self.__orig_setgid = init.posix.setgid
+ self.__orig_setuid = init.posix.setuid
+ self.__orig_logger_class = isc.log.Logger
+
+ def tearDown(self):
+ # Restore original values saved in setUp()
+ init.posix.setgid = self.__orig_setgid
+ init.posix.setuid = self.__orig_setuid
+ isc.log.Logger = self.__orig_logger_class
+
+ def test_init(self):
+ b10_init = Init()
+ self.assertEqual(b10_init.verbose, False)
+ self.assertEqual(b10_init.msgq_socket_file, None)
+ self.assertEqual(b10_init.cc_session, None)
+ self.assertEqual(b10_init.ccs, None)
+ self.assertEqual(b10_init.components, {})
+ self.assertEqual(b10_init.runnable, False)
+ self.assertEqual(b10_init.username, None)
+ self.assertIsNone(b10_init._socket_cache)
+
+ def __setgid(self, gid):
+ self.__gid_set = gid
+
+ def __setuid(self, uid):
+ self.__uid_set = uid
+
+ def test_change_user(self):
+ init.posix.setgid = self.__setgid
+ init.posix.setuid = self.__setuid
+
+ self.__gid_set = None
+ self.__uid_set = None
+ b10_init = Init()
+ b10_init.change_user()
+ # No gid/uid set in init, nothing called.
+ self.assertIsNone(self.__gid_set)
+ self.assertIsNone(self.__uid_set)
+
+ Init(setuid=42, setgid=4200).change_user()
+ # This time, it get's called
+ self.assertEqual(4200, self.__gid_set)
+ self.assertEqual(42, self.__uid_set)
+
+ def raising_set_xid(gid_or_uid):
+ ex = OSError()
+ ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+ raise ex
+
+ # Let setgid raise an exception
+ init.posix.setgid = raising_set_xid
+ init.posix.setuid = self.__setuid
+ self.assertRaises(init.ChangeUserError,
+ Init(setuid=42, setgid=4200).change_user)
+
+ # Let setuid raise an exception
+ init.posix.setgid = self.__setgid
+ init.posix.setuid = raising_set_xid
+ self.assertRaises(init.ChangeUserError,
+ Init(setuid=42, setgid=4200).change_user)
+
+ # Let initial log output after setuid raise an exception
+ init.posix.setgid = self.__setgid
+ init.posix.setuid = self.__setuid
+ isc.log.Logger = raising_set_xid
+ self.assertRaises(init.ChangeUserError,
+ Init(setuid=42, setgid=4200).change_user)
+
+ def test_set_creator(self):
+ """
+ Test the call to set_creator. First time, the cache is created
+ with the passed creator. The next time, it throws an exception.
+ """
+ init = Init()
+ # The cache doesn't use it at start, so just create an empty class
+ class Creator: pass
+ creator = Creator()
+ init.set_creator(creator)
+ self.assertTrue(isinstance(init._socket_cache,
+ isc.bind10.socket_cache.Cache))
+ self.assertEqual(creator, init._socket_cache._creator)
+ self.assertRaises(ValueError, init.set_creator, creator)
+
+ def test_socket_srv(self):
+ """Tests init_socket_srv() and remove_socket_srv() work as expected."""
+ init = Init()
+
+ self.assertIsNone(init._srv_socket)
+ self.assertIsNone(init._tmpdir)
+ self.assertIsNone(init._socket_path)
+
+ init.init_socket_srv()
+
+ self.assertIsNotNone(init._srv_socket)
+ self.assertNotEqual(-1, init._srv_socket.fileno())
+ self.assertEqual(os.path.join(init._tmpdir, 'sockcreator'),
+ init._srv_socket.getsockname())
+
+ self.assertIsNotNone(init._tmpdir)
+ self.assertTrue(os.path.isdir(init._tmpdir))
+ self.assertIsNotNone(init._socket_path)
+ self.assertTrue(os.path.exists(init._socket_path))
+
+ # Check that it's possible to connect to the socket file (this
+ # only works if the socket file exists and the server listens on
+ # it).
+ s = socket.socket(socket.AF_UNIX)
+ try:
+ s.connect(init._socket_path)
+ can_connect = True
+ s.close()
+ except socket.error as e:
+ can_connect = False
+
+ self.assertTrue(can_connect)
+
+ init.remove_socket_srv()
+
+ self.assertEqual(-1, init._srv_socket.fileno())
+ self.assertFalse(os.path.exists(init._socket_path))
+ self.assertFalse(os.path.isdir(init._tmpdir))
+
+ # These should not fail either:
+
+ # second call
+ init.remove_socket_srv()
+
+ init._srv_socket = None
+ init.remove_socket_srv()
+
+ def test_init_alternate_socket(self):
+ init = Init("alt_socket_file")
+ self.assertEqual(init.verbose, False)
+ self.assertEqual(init.msgq_socket_file, "alt_socket_file")
+ self.assertEqual(init.cc_session, None)
+ self.assertEqual(init.ccs, None)
+ self.assertEqual(init.components, {})
+ self.assertEqual(init.runnable, False)
+ self.assertEqual(init.username, None)
+
+ def test_command_handler(self):
+ class DummySession():
+ def group_sendmsg(self, msg, group):
+ (self.msg, self.group) = (msg, group)
+ def group_recvmsg(self, nonblock, seq): pass
+ class DummyModuleCCSession():
+ module_spec = isc.config.module_spec.ModuleSpec({
+ "module_name": "Init",
+ "statistics": [
+ {
+ "item_name": "boot_time",
+ "item_type": "string",
+ "item_optional": False,
+ "item_default": "1970-01-01T00:00:00Z",
+ "item_title": "Boot time",
+ "item_description": "A date time when bind10 process starts initially",
+ "item_format": "date-time"
+ }
+ ]
+ })
+ def get_module_spec(self):
+ return self.module_spec
+ init = Init()
+ init.verbose = True
+ init.cc_session = DummySession()
+ init.ccs = DummyModuleCCSession()
+ # a bad command
+ self.assertEqual(init.command_handler(-1, None),
+ isc.config.ccsession.create_answer(1, "bad command"))
+ # "shutdown" command
+ self.assertEqual(init.command_handler("shutdown", None),
+ isc.config.ccsession.create_answer(0))
+ self.assertFalse(init.runnable)
+ # "getstats" command
+ self.assertEqual(init.command_handler("getstats", None),
+ isc.config.ccsession.create_answer(0,
+ { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
+ # "ping" command
+ self.assertEqual(init.command_handler("ping", None),
+ isc.config.ccsession.create_answer(0, "pong"))
+ # "show_processes" command
+ self.assertEqual(init.command_handler("show_processes", None),
+ isc.config.ccsession.create_answer(0,
+ init.get_processes()))
+ # an unknown command
+ self.assertEqual(init.command_handler("__UNKNOWN__", None),
+ isc.config.ccsession.create_answer(1, "Unknown command"))
+
+ # Fake the get_token of cache and test the command works
+ init._socket_path = '/socket/path'
+ class cache:
+ def get_token(self, protocol, addr, port, share_mode, share_name):
+ return str(addr) + ':' + str(port)
+ init._socket_cache = cache()
+ args = {
+ "port": 53,
+ "address": "0.0.0.0",
+ "protocol": "UDP",
+ "share_mode": "ANY",
+ "share_name": "app"
+ }
+ # at all and this is the easiest way to check.
+ self.assertEqual({'result': [0, {'token': '0.0.0.0:53',
+ 'path': '/socket/path'}]},
+ init.command_handler("get_socket", args))
+ # The drop_socket is not tested here, but in TestCacheCommands.
+ # It needs the cache mocks to be in place and they are there.
+
+ def test_stop_process(self):
+ """
+ Test checking the stop_process method sends the right message over
+ the message bus.
+ """
+ class DummySession():
+ def group_sendmsg(self, msg, group, instance="*"):
+ (self.msg, self.group, self.instance) = (msg, group, instance)
+ init = Init()
+ init.cc_session = DummySession()
+ init.stop_process('process', 'address', 42)
+ self.assertEqual('address', init.cc_session.group)
+ self.assertEqual('address', init.cc_session.instance)
+ self.assertEqual({'command': ['shutdown', {'pid': 42}]},
+ init.cc_session.msg)
+
+# Mock class for testing Init's usage of ProcessInfo
+class MockProcessInfo:
+ def __init__(self, name, args, env={}, dev_null_stdout=False,
+ dev_null_stderr=False):
+ self.name = name
+ self.args = args
+ self.env = env
+ self.dev_null_stdout = dev_null_stdout
+ self.dev_null_stderr = dev_null_stderr
+ self.process = None
+ self.pid = None
+
+ def spawn(self):
+ # set some pid (only used for testing that it is not None anymore)
+ self.pid = 42147
+
+# Class for testing the Init without actually starting processes.
+# This is used for testing the start/stop components routines and
+# the Init commands.
+#
+# Testing that external processes start is outside the scope
+# of the unit test, by overriding the process start methods we can check
+# that the right processes are started depending on the configuration
+# options.
+class MockInit(Init):
+ def __init__(self):
+ Init.__init__(self)
+
+ # Set flags as to which of the overridden methods has been run.
+ self.msgq = False
+ self.cfgmgr = False
+ self.ccsession = False
+ self.auth = False
+ self.resolver = False
+ self.xfrout = False
+ self.xfrin = False
+ self.zonemgr = False
+ self.stats = False
+ self.stats_httpd = False
+ self.cmdctl = False
+ self.dhcp6 = False
+ self.dhcp4 = False
+ self.c_channel_env = {}
+ self.components = { }
+ self.creator = False
+ self.get_process_exit_status_called = False
+
+ class MockSockCreator(isc.bind10.component.Component):
+ def __init__(self, process, b10_init, kind, address=None,
+ params=None):
+ isc.bind10.component.Component.__init__(self, process,
+ b10_init, kind,
+ 'SockCreator')
+ self._start_func = b10_init.start_creator
+
+ specials = isc.bind10.special_component.get_specials()
+ specials['sockcreator'] = MockSockCreator
+ self._component_configurator = \
+ isc.bind10.component.Configurator(self, specials)
+
+ def start_creator(self):
+ self.creator = True
+ procinfo = ProcessInfo('b10-sockcreator', ['/bin/false'])
+ procinfo.pid = 1
+ return procinfo
+
+ def _read_bind10_config(self):
+ # Configuration options are set directly
+ pass
+
+ def start_msgq(self):
+ self.msgq = True
+ procinfo = ProcessInfo('b10-msgq', ['/bin/false'])
+ procinfo.pid = 2
+ return procinfo
+
+ def start_ccsession(self, c_channel_env):
+ # this is not a process, don't have to do anything with procinfo
+ self.ccsession = True
+
+ def start_cfgmgr(self):
+ self.cfgmgr = True
+ procinfo = ProcessInfo('b10-cfgmgr', ['/bin/false'])
+ procinfo.pid = 3
+ return procinfo
+
+ def start_auth(self):
+ self.auth = True
+ procinfo = ProcessInfo('b10-auth', ['/bin/false'])
+ procinfo.pid = 5
+ return procinfo
+
+ def start_resolver(self):
+ self.resolver = True
+ procinfo = ProcessInfo('b10-resolver', ['/bin/false'])
+ procinfo.pid = 6
+ return procinfo
+
+ def start_simple(self, name):
+ procmap = { 'b10-zonemgr': self.start_zonemgr,
+ 'b10-stats': self.start_stats,
+ 'b10-stats-httpd': self.start_stats_httpd,
+ 'b10-cmdctl': self.start_cmdctl,
+ 'b10-dhcp6': self.start_dhcp6,
+ 'b10-dhcp4': self.start_dhcp4,
+ 'b10-xfrin': self.start_xfrin,
+ 'b10-xfrout': self.start_xfrout }
+ return procmap[name]()
+
+ def start_xfrout(self):
+ self.xfrout = True
+ procinfo = ProcessInfo('b10-xfrout', ['/bin/false'])
+ procinfo.pid = 7
+ return procinfo
+
+ def start_xfrin(self):
+ self.xfrin = True
+ procinfo = ProcessInfo('b10-xfrin', ['/bin/false'])
+ procinfo.pid = 8
+ return procinfo
+
+ def start_zonemgr(self):
+ self.zonemgr = True
+ procinfo = ProcessInfo('b10-zonemgr', ['/bin/false'])
+ procinfo.pid = 9
+ return procinfo
+
+ def start_stats(self):
+ self.stats = True
+ procinfo = ProcessInfo('b10-stats', ['/bin/false'])
+ procinfo.pid = 10
+ return procinfo
+
+ def start_stats_httpd(self):
+ self.stats_httpd = True
+ procinfo = ProcessInfo('b10-stats-httpd', ['/bin/false'])
+ procinfo.pid = 11
+ return procinfo
+
+ def start_cmdctl(self):
+ self.cmdctl = True
+ procinfo = ProcessInfo('b10-cmdctl', ['/bin/false'])
+ procinfo.pid = 12
+ return procinfo
+
+ def start_dhcp6(self):
+ self.dhcp6 = True
+ procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
+ procinfo.pid = 13
+ return procinfo
+
+ def start_dhcp4(self):
+ self.dhcp4 = True
+ procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
+ procinfo.pid = 14
+ return procinfo
+
+ def stop_process(self, process, recipient, pid):
+ procmap = { 'b10-auth': self.stop_auth,
+ 'b10-resolver': self.stop_resolver,
+ 'b10-xfrout': self.stop_xfrout,
+ 'b10-xfrin': self.stop_xfrin,
+ 'b10-zonemgr': self.stop_zonemgr,
+ 'b10-stats': self.stop_stats,
+ 'b10-stats-httpd': self.stop_stats_httpd,
+ 'b10-cmdctl': self.stop_cmdctl }
+ procmap[process]()
+
+ # Some functions to pretend we stop processes, use by stop_process
+ def stop_msgq(self):
+ if self.msgq:
+ del self.components[2]
+ self.msgq = False
+
+ def stop_cfgmgr(self):
+ if self.cfgmgr:
+ del self.components[3]
+ self.cfgmgr = False
+
+ def stop_auth(self):
+ if self.auth:
+ del self.components[5]
+ self.auth = False
+
+ def stop_resolver(self):
+ if self.resolver:
+ del self.components[6]
+ self.resolver = False
+
+ def stop_xfrout(self):
+ if self.xfrout:
+ del self.components[7]
+ self.xfrout = False
+
+ def stop_xfrin(self):
+ if self.xfrin:
+ del self.components[8]
+ self.xfrin = False
+
+ def stop_zonemgr(self):
+ if self.zonemgr:
+ del self.components[9]
+ self.zonemgr = False
+
+ def stop_stats(self):
+ if self.stats:
+ del self.components[10]
+ self.stats = False
+
+ def stop_stats_httpd(self):
+ if self.stats_httpd:
+ del self.components[11]
+ self.stats_httpd = False
+
+ def stop_cmdctl(self):
+ if self.cmdctl:
+ del self.components[12]
+ self.cmdctl = False
+
+ def _get_process_exit_status(self):
+ if self.get_process_exit_status_called:
+ return (0, 0)
+ self.get_process_exit_status_called = True
+ return (53, 0)
+
+ def _get_process_exit_status_unknown_pid(self):
+ if self.get_process_exit_status_called:
+ return (0, 0)
+ self.get_process_exit_status_called = True
+ return (42, 0)
+
+ def _get_process_exit_status_raises_oserror_echild(self):
+ raise OSError(errno.ECHILD, 'Mock error')
+
+ def _get_process_exit_status_raises_oserror_other(self):
+ raise OSError(0, 'Mock error')
+
+ def _get_process_exit_status_raises_other(self):
+ raise Exception('Mock error')
+
+ def _make_mock_process_info(self, name, args, c_channel_env,
+ dev_null_stdout=False, dev_null_stderr=False):
+ return MockProcessInfo(name, args, c_channel_env,
+ dev_null_stdout, dev_null_stderr)
+
+class MockInitSimple(Init):
+ def __init__(self):
+ Init.__init__(self)
+ # Set which process has been started
+ self.started_process_name = None
+ self.started_process_args = None
+ self.started_process_env = None
+
+ def _make_mock_process_info(self, name, args, c_channel_env,
+ dev_null_stdout=False, dev_null_stderr=False):
+ return MockProcessInfo(name, args, c_channel_env,
+ dev_null_stdout, dev_null_stderr)
+
+ def start_process(self, name, args, c_channel_env, port=None,
+ address=None):
+ self.started_process_name = name
+ self.started_process_args = args
+ self.started_process_env = c_channel_env
+ return None
+
+class TestStartStopProcessesInit(unittest.TestCase):
+ """
+ Check that the start_all_components method starts the right combination
+ of components and that the right components are started and stopped
+ according to changes in configuration.
+ """
+ def check_environment_unchanged(self):
+ # Check whether the environment has not been changed
+ self.assertEqual(original_os_environ, os.environ)
+
+ def check_started(self, init, core, auth, resolver):
+ """
+ Check that the right sets of services are started. The ones that
+ should be running are specified by the core, auth and resolver parameters
+ (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
+ and -zonemgr).
+ """
+ self.assertEqual(init.msgq, core)
+ self.assertEqual(init.cfgmgr, core)
+ self.assertEqual(init.ccsession, core)
+ self.assertEqual(init.creator, core)
+ self.assertEqual(init.auth, auth)
+ self.assertEqual(init.resolver, resolver)
+ self.assertEqual(init.xfrout, auth)
+ self.assertEqual(init.xfrin, auth)
+ self.assertEqual(init.zonemgr, auth)
+ self.assertEqual(init.stats, core)
+ self.assertEqual(init.stats_httpd, core)
+ self.assertEqual(init.cmdctl, core)
+ self.check_environment_unchanged()
+
+ def check_preconditions(self, init):
+ self.check_started(init, False, False, False)
+
+ def check_started_none(self, init):
+ """
+ Check that the situation is according to configuration where no servers
+ should be started. Some components still need to be running.
+ """
+ self.check_started(init, True, False, False)
+ self.check_environment_unchanged()
+
+ def check_started_both(self, init):
+ """
+ Check the situation is according to configuration where both servers
+ (auth and resolver) are enabled.
+ """
+ self.check_started(init, True, True, True)
+ self.check_environment_unchanged()
+
+ def check_started_auth(self, init):
+ """
+ Check the set of components needed to run auth only is started.
+ """
+ self.check_started(init, True, True, False)
+ self.check_environment_unchanged()
+
+ def check_started_resolver(self, init):
+ """
+ Check the set of components needed to run resolver only is started.
+ """
+ self.check_started(init, True, False, True)
+ self.check_environment_unchanged()
+
+ def check_started_dhcp(self, init, v4, v6):
+ """
+ Check if proper combinations of DHCPv4 and DHCpv6 can be started
+ """
+ self.assertEqual(v4, init.dhcp4)
+ self.assertEqual(v6, init.dhcp6)
+ self.check_environment_unchanged()
+
+ def construct_config(self, start_auth, start_resolver):
+ # The things that are common, not turned on an off
+ config = {}
+ config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
+ config['b10-stats-httpd'] = { 'kind': 'dispensable',
+ 'address': 'StatsHttpd' }
+ config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
+ if start_auth:
+ config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
+ config['b10-xfrout'] = { 'kind': 'dispensable',
+ 'address': 'Xfrout' }
+ config['b10-xfrin'] = { 'kind': 'dispensable',
+ 'address': 'Xfrin' }
+ config['b10-zonemgr'] = { 'kind': 'dispensable',
+ 'address': 'Zonemgr' }
+ if start_resolver:
+ config['b10-resolver'] = { 'kind': 'needed',
+ 'special': 'resolver' }
+ return {'components': config}
+
+ def config_start_init(self, start_auth, start_resolver):
+ """
+ Test the configuration is loaded at the startup.
+ """
+ init = MockInit()
+ config = self.construct_config(start_auth, start_resolver)
+ class CC:
+ def get_full_config(self):
+ return config
+ # Provide the fake CC with data
+ init.ccs = CC()
+ # And make sure it's not overwritten
+ def start_ccsession():
+ init.ccsession = True
+ init.start_ccsession = lambda _: start_ccsession()
+ # We need to return the original _read_bind10_config
+ init._read_bind10_config = lambda: Init._read_bind10_config(init)
+ init.start_all_components()
+ self.check_started(init, True, start_auth, start_resolver)
+ self.check_environment_unchanged()
+
+ def test_start_none(self):
+ self.config_start_init(False, False)
+
+ def test_start_resolver(self):
+ self.config_start_init(False, True)
+
+ def test_start_auth(self):
+ self.config_start_init(True, False)
+
+ def test_start_both(self):
+ self.config_start_init(True, True)
+
+ def test_config_start(self):
+ """
+ Test that the configuration starts and stops components according
+ to configuration changes.
+ """
+
+ # Create Init and ensure correct initialization
+ init = MockInit()
+ self.check_preconditions(init)
+
+ init.start_all_components()
+ init.runnable = True
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_none(init)
+
+ # Enable both at once
+ init.config_handler(self.construct_config(True, True))
+ self.check_started_both(init)
+
+ # Not touched by empty change
+ init.config_handler({})
+ self.check_started_both(init)
+
+ # Not touched by change to the same configuration
+ init.config_handler(self.construct_config(True, True))
+ self.check_started_both(init)
+
+ # Turn them both off again
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_none(init)
+
+ # Not touched by empty change
+ init.config_handler({})
+ self.check_started_none(init)
+
+ # Not touched by change to the same configuration
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_none(init)
+
+ # Start and stop auth separately
+ init.config_handler(self.construct_config(True, False))
+ self.check_started_auth(init)
+
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_none(init)
+
+ # Start and stop resolver separately
+ init.config_handler(self.construct_config(False, True))
+ self.check_started_resolver(init)
+
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_none(init)
+
+ # Alternate
+ init.config_handler(self.construct_config(True, False))
+ self.check_started_auth(init)
+
+ init.config_handler(self.construct_config(False, True))
+ self.check_started_resolver(init)
+
+ init.config_handler(self.construct_config(True, False))
+ self.check_started_auth(init)
+
+ def test_config_start_once(self):
+ """
+ Tests that a component is started only once.
+ """
+ # Create Init and ensure correct initialization
+ init = MockInit()
+ self.check_preconditions(init)
+
+ init.start_all_components()
+
+ init.runnable = True
+ init.config_handler(self.construct_config(True, True))
+ self.check_started_both(init)
+
+ init.start_auth = lambda: self.fail("Started auth again")
+ init.start_xfrout = lambda: self.fail("Started xfrout again")
+ init.start_xfrin = lambda: self.fail("Started xfrin again")
+ init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ init.start_resolver = lambda: self.fail("Started resolver again")
+
+ # Send again we want to start them. Should not do it, as they are.
+ init.config_handler(self.construct_config(True, True))
+
+ def test_config_not_started_early(self):
+ """
+ Test that components are not started by the config handler before
+ startup.
+ """
+ init = MockInit()
+ self.check_preconditions(init)
+
+ init.start_auth = lambda: self.fail("Started auth again")
+ init.start_xfrout = lambda: self.fail("Started xfrout again")
+ init.start_xfrin = lambda: self.fail("Started xfrin again")
+ init.start_zonemgr = lambda: self.fail("Started zonemgr again")
+ init.start_resolver = lambda: self.fail("Started resolver again")
+
+ init.config_handler({'start_auth': True, 'start_resolver': True})
+
+ # Checks that DHCP (v4 and v6) components are started when expected
+ def test_start_dhcp(self):
+
+ # Create Init and ensure correct initialization
+ init = MockInit()
+ self.check_preconditions(init)
+
+ init.start_all_components()
+ init.config_handler(self.construct_config(False, False))
+ self.check_started_dhcp(init, False, False)
+
+ def test_start_dhcp_v6only(self):
+ # Create Init and ensure correct initialization
+ init = MockInit()
+ self.check_preconditions(init)
+ # v6 only enabled
+ init.start_all_components()
+ init.runnable = True
+ init._Init_started = True
+ config = self.construct_config(False, False)
+ config['components']['b10-dhcp6'] = { 'kind': 'needed',
+ 'address': 'Dhcp6' }
+ init.config_handler(config)
+ self.check_started_dhcp(init, False, True)
+
+ # uncomment when dhcpv4 becomes implemented
+ # v4 only enabled
+ #init.cfg_start_dhcp6 = False
+ #init.cfg_start_dhcp4 = True
+ #self.check_started_dhcp(init, True, False)
+
+ # both v4 and v6 enabled
+ #init.cfg_start_dhcp6 = True
+ #init.cfg_start_dhcp4 = True
+ #self.check_started_dhcp(init, True, True)
+
+class MockComponent:
+ def __init__(self, name, pid, address=None):
+ self.name = lambda: name
+ self.pid = lambda: pid
+ self.address = lambda: address
+ self.restarted = False
+ self.forceful = False
+ self.running = True
+ self.has_failed = False
+
+ def get_restart_time(self):
+ return 0 # arbitrary dummy value
+
+ def restart(self, now):
+ self.restarted = True
+ return True
+
+ def is_running(self):
+ return self.running
+
+ def failed(self, status):
+ return self.has_failed
+
+ def kill(self, forceful):
+ self.forceful = forceful
+
+class TestInitCmd(unittest.TestCase):
+ def test_ping(self):
+ """
+ Confirm simple ping command works.
+ """
+ init = MockInit()
+ answer = init.command_handler("ping", None)
+ self.assertEqual(answer, {'result': [0, 'pong']})
+
+ def test_show_processes_empty(self):
+ """
+ Confirm getting a list of processes works.
+ """
+ init = MockInit()
+ answer = init.command_handler("show_processes", None)
+ self.assertEqual(answer, {'result': [0, []]})
+
+ def test_show_processes(self):
+ """
+ Confirm getting a list of processes works.
+ """
+ init = MockInit()
+ init.register_process(1, MockComponent('first', 1))
+ init.register_process(2, MockComponent('second', 2, 'Second'))
+ answer = init.command_handler("show_processes", None)
+ processes = [[1, 'first', None],
+ [2, 'second', 'Second']]
+ self.assertEqual(answer, {'result': [0, processes]})
+
+class TestParseArgs(unittest.TestCase):
+ """
+ This tests parsing of arguments of the bind10 master process.
+ """
+ #TODO: Write tests for the original parsing, bad options, etc.
+ def test_no_opts(self):
+ """
+ Test correct default values when no options are passed.
+ """
+ options = parse_args([], TestOptParser)
+ self.assertEqual(None, options.data_path)
+ self.assertEqual(None, options.config_file)
+ self.assertEqual(None, options.cmdctl_port)
+
+ def test_data_path(self):
+ """
+ Test it can parse the data path.
+ """
+ self.assertRaises(OptsError, parse_args, ['-p'], TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--data-path'],
+ TestOptParser)
+ options = parse_args(['-p', '/data/path'], TestOptParser)
+ self.assertEqual('/data/path', options.data_path)
+ options = parse_args(['--data-path=/data/path'], TestOptParser)
+ self.assertEqual('/data/path', options.data_path)
+
+ def test_config_filename(self):
+ """
+ Test it can parse the config switch.
+ """
+ self.assertRaises(OptsError, parse_args, ['-c'], TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--config-file'],
+ TestOptParser)
+ options = parse_args(['-c', 'config-file'], TestOptParser)
+ self.assertEqual('config-file', options.config_file)
+ options = parse_args(['--config-file=config-file'], TestOptParser)
+ self.assertEqual('config-file', options.config_file)
+
+ def test_clear_config(self):
+ options = parse_args([], TestOptParser)
+ self.assertEqual(False, options.clear_config)
+ options = parse_args(['--clear-config'], TestOptParser)
+ self.assertEqual(True, options.clear_config)
+
+ def test_nokill(self):
+ options = parse_args([], TestOptParser)
+ self.assertEqual(False, options.nokill)
+ options = parse_args(['--no-kill'], TestOptParser)
+ self.assertEqual(True, options.nokill)
+ options = parse_args([], TestOptParser)
+ self.assertEqual(False, options.nokill)
+ options = parse_args(['-i'], TestOptParser)
+ self.assertEqual(True, options.nokill)
+
+ def test_cmdctl_port(self):
+ """
+ Test it can parse the command control port.
+ """
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port=abc'],
+ TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port=100000000'],
+ TestOptParser)
+ self.assertRaises(OptsError, parse_args, ['--cmdctl-port'],
+ TestOptParser)
+ options = parse_args(['--cmdctl-port=1234'], TestOptParser)
+ self.assertEqual(1234, options.cmdctl_port)
+
+class TestPIDFile(unittest.TestCase):
+ def setUp(self):
+ self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
+ if os.path.exists(self.pid_file):
+ os.unlink(self.pid_file)
+
+ def tearDown(self):
+ if os.path.exists(self.pid_file):
+ os.unlink(self.pid_file)
+
+ def check_pid_file(self):
+ # dump PID to the file, and confirm the content is correct
+ dump_pid(self.pid_file)
+ my_pid = os.getpid()
+ with open(self.pid_file, "r") as f:
+ self.assertEqual(my_pid, int(f.read()))
+
+ def test_dump_pid(self):
+ self.check_pid_file()
+
+ # make sure any existing content will be removed
+ with open(self.pid_file, "w") as f:
+ f.write('dummy data\n')
+ self.check_pid_file()
+
+ def test_unlink_pid_file_notexist(self):
+ dummy_data = 'dummy_data\n'
+
+ with open(self.pid_file, "w") as f:
+ f.write(dummy_data)
+
+ unlink_pid_file("no_such_pid_file")
+
+ # the file specified for unlink_pid_file doesn't exist,
+ # and the original content of the file should be intact.
+ with open(self.pid_file, "r") as f:
+ self.assertEqual(dummy_data, f.read())
+
+ def test_dump_pid_with_none(self):
+ # Check the behavior of dump_pid() and unlink_pid_file() with None.
+ # This should be no-op.
+ dump_pid(None)
+ self.assertFalse(os.path.exists(self.pid_file))
+
+ dummy_data = 'dummy_data\n'
+
+ with open(self.pid_file, "w") as f:
+ f.write(dummy_data)
+
+ unlink_pid_file(None)
+
+ with open(self.pid_file, "r") as f:
+ self.assertEqual(dummy_data, f.read())
+
+ def test_dump_pid_failure(self):
+ # the attempt to open file will fail, which should result in exception.
+ self.assertRaises(IOError, dump_pid,
+ 'nonexistent_dir' + os.sep + 'bind10.pid')
+
+class TestInitComponents(unittest.TestCase):
+ """
+ Test b10-init propagates component configuration properly to the
+ component configurator and acts sane.
+ """
+ def setUp(self):
+ self.__param = None
+ self.__called = False
+ self.__compconfig = {
+ 'comp': {
+ 'kind': 'needed',
+ 'process': 'cat'
+ }
+ }
+ self._tmp_time = None
+ self._tmp_sleep = None
+ self._tmp_module_cc_session = None
+ self._tmp_cc_session = None
+
+ def tearDown(self):
+ if self._tmp_time is not None:
+ time.time = self._tmp_time
+ if self._tmp_sleep is not None:
+ time.sleep = self._tmp_sleep
+ if self._tmp_module_cc_session is not None:
+ isc.config.ModuleCCSession = self._tmp_module_cc_session
+ if self._tmp_cc_session is not None:
+ isc.cc.Session = self._tmp_cc_session
+
+ def __unary_hook(self, param):
+ """
+ A hook function that stores the parameter for later examination.
+ """
+ self.__param = param
+
+ def __nullary_hook(self):
+ """
+ A hook function that notes down it was called.
+ """
+ self.__called = True
+
+ def __check_core(self, config):
+ """
+ A function checking that the config contains parts for the valid
+ core component configuration.
+ """
+ self.assertIsNotNone(config)
+ for component in ['sockcreator', 'msgq', 'cfgmgr']:
+ self.assertTrue(component in config)
+ self.assertEqual(component, config[component]['special'])
+ self.assertEqual('core', config[component]['kind'])
+
+ def __check_extended(self, config):
+ """
+ This checks that the config contains the core and one more component.
+ """
+ self.__check_core(config)
+ self.assertTrue('comp' in config)
+ self.assertEqual('cat', config['comp']['process'])
+ self.assertEqual('needed', config['comp']['kind'])
+ self.assertEqual(4, len(config))
+
+ def test_correct_run(self):
+ """
+ Test the situation when we run in usual scenario, nothing fails,
+ we just start, reconfigure and then stop peacefully.
+ """
+ init = MockInit()
+ # Start it
+ orig = init._component_configurator.startup
+ init._component_configurator.startup = self.__unary_hook
+ init.start_all_components()
+ init._component_configurator.startup = orig
+ self.__check_core(self.__param)
+ self.assertEqual(3, len(self.__param))
+
+ # Reconfigure it
+ self.__param = None
+ orig = init._component_configurator.reconfigure
+ init._component_configurator.reconfigure = self.__unary_hook
+ # Otherwise it does not work
+ init.runnable = True
+ init.config_handler({'components': self.__compconfig})
+ self.__check_extended(self.__param)
+ currconfig = self.__param
+ # If we reconfigure it, but it does not contain the components part,
+ # nothing is called
+ init.config_handler({})
+ self.assertEqual(self.__param, currconfig)
+ self.__param = None
+ init._component_configurator.reconfigure = orig
+ # Check a configuration that messes up the core components is rejected.
+ compconf = dict(self.__compconfig)
+ compconf['msgq'] = { 'process': 'echo' }
+ result = init.config_handler({'components': compconf})
+ # Check it rejected it
+ self.assertEqual(1, result['result'][0])
+
+ # We can't call shutdown, that one relies on the stuff in main
+ # We check somewhere else that the shutdown is actually called
+ # from there (the test_kills).
+
+ def __real_test_kill(self, nokill=False, ex_on_kill=None):
+ """
+ Helper function that does the actual kill functionality testing.
+ """
+ init = MockInit()
+ init.nokill = nokill
+
+ killed = []
+ class ImmortalComponent:
+ """
+ An immortal component. It does not stop when it is told so
+ (anyway it is not told so). It does not die if it is killed
+ the first time. It dies only when killed forcefully.
+ """
+ def __init__(self):
+ # number of kill() calls, preventing infinite loop.
+ self.__call_count = 0
+
+ def kill(self, forceful=False):
+ self.__call_count += 1
+ if self.__call_count > 2:
+ raise Exception('Too many calls to ImmortalComponent.kill')
+
+ killed.append(forceful)
+ if ex_on_kill is not None:
+ # If exception is given by the test, raise it here.
+ # In the case of ESRCH, the process should have gone
+ # somehow, so we clear the components.
+ if ex_on_kill.errno == errno.ESRCH:
+ init.components = {}
+ raise ex_on_kill
+ if forceful:
+ init.components = {}
+ def pid(self):
+ return 1
+ def name(self):
+ return "Immortal"
+ init.components = {}
+ init.register_process(1, ImmortalComponent())
+
+ # While at it, we check the configurator shutdown is actually called
+ orig = init._component_configurator.shutdown
+ init._component_configurator.shutdown = self.__nullary_hook
+ self.__called = False
+
+ init.ccs = MockModuleCCSession()
+ self.assertFalse(init.ccs.stopped)
+
+ init.shutdown()
+
+ self.assertTrue(init.ccs.stopped)
+
+ # Here, killed is an array where False is added if SIGTERM
+ # should be sent, or True if SIGKILL should be sent, in order in
+ # which they're sent.
+ if nokill:
+ self.assertEqual([], killed)
+ else:
+ if ex_on_kill is not None:
+ self.assertEqual([False], killed)
+ else:
+ self.assertEqual([False, True], killed)
+
+ self.assertTrue(self.__called)
+
+ init._component_configurator.shutdown = orig
+
+ def test_kills(self):
+ """
+ Test that b10-init kills components which don't want to stop.
+ """
+ self.__real_test_kill()
+
+ def test_kill_fail(self):
+ """Test cases where kill() results in an exception due to OS error.
+
+ The behavior should be different for EPERM, so we test two cases.
+
+ """
+
+ ex = OSError()
+ ex.errno, ex.strerror = errno.ESRCH, 'No such process'
+ self.__real_test_kill(ex_on_kill=ex)
+
+ ex.errno, ex.strerror = errno.EPERM, 'Operation not permitted'
+ self.__real_test_kill(ex_on_kill=ex)
+
+ def test_nokill(self):
+ """
+ Test that b10-init *doesn't* kill components which don't want to
+ stop, when asked not to (by passing the --no-kill option which
+ sets init.nokill to True).
+ """
+ self.__real_test_kill(True)
+
+ def test_component_shutdown(self):
+ """
+ Test the component_shutdown sets all variables accordingly.
+ """
+ init = MockInit()
+ self.assertRaises(Exception, init.component_shutdown, 1)
+ self.assertEqual(1, init.exitcode)
+ init._Init__started = True
+ init.component_shutdown(2)
+ self.assertEqual(2, init.exitcode)
+ self.assertFalse(init.runnable)
+
+ def test_init_config(self):
+ """
+ Test initial configuration is loaded.
+ """
+ init = MockInit()
+ # Start it
+ init._component_configurator.reconfigure = self.__unary_hook
+ # We need to return the original read_bind10_config
+ init._read_bind10_config = lambda: Init._read_bind10_config(init)
+ # And provide a session to read the data from
+ class CC:
+ pass
+ init.ccs = CC()
+ init.ccs.get_full_config = lambda: {'components': self.__compconfig}
+ init.start_all_components()
+ self.__check_extended(self.__param)
+
+ def __setup_restart(self, init, component):
+ '''Common procedure for restarting a component used below.'''
+ init.components_to_restart = { component }
+ component.restarted = False
+ init.restart_processes()
+
+ def test_restart_processes(self):
+ '''Check some behavior on restarting processes.'''
+ init = MockInit()
+ init.runnable = True
+ component = MockComponent('test', 53)
+
+ # A component to be restarted will actually be restarted iff it's
+ # in the configurator's configuration.
+ # We bruteforce the configurator internal below; ugly, but the easiest
+ # way for the test.
+ init._component_configurator._components['test'] = (None, component)
+ self.__setup_restart(init, component)
+ self.assertTrue(component.restarted)
+ self.assertNotIn(component, init.components_to_restart)
+
+ # Remove the component from the configuration. It won't be restarted
+ # even if scheduled, nor will remain in the to-be-restarted list.
+ del init._component_configurator._components['test']
+ self.__setup_restart(init, component)
+ self.assertFalse(component.restarted)
+ self.assertNotIn(component, init.components_to_restart)
+
+ def test_get_processes(self):
+ '''Test that procsses are returned correctly, sorted by pid.'''
+ init = MockInit()
+
+ pids = list(range(0, 20))
+ random.shuffle(pids)
+
+ for i in range(0, 20):
+ pid = pids[i]
+ component = MockComponent('test' + str(pid), pid,
+ 'Test' + str(pid))
+ init.components[pid] = component
+
+ process_list = init.get_processes()
+ self.assertEqual(20, len(process_list))
+
+ last_pid = -1
+ for process in process_list:
+ pid = process[0]
+ self.assertLessEqual(last_pid, pid)
+ last_pid = pid
+ self.assertEqual([pid, 'test' + str(pid), 'Test' + str(pid)],
+ process)
+
+ def _test_reap_children_helper(self, runnable, is_running, failed):
+ '''Construct a Init instance, set various data in it according to
+ passed args and check if the component was added to the list of
+ components to restart.'''
+ init = MockInit()
+ init.runnable = runnable
+
+ component = MockComponent('test', 53)
+ component.running = is_running
+ component.has_failed = failed
+ init.components[53] = component
+
+ self.assertNotIn(component, init.components_to_restart)
+
+ init.reap_children()
+
+ if runnable and is_running and not failed:
+ self.assertIn(component, init.components_to_restart)
+ else:
+ self.assertEqual([], init.components_to_restart)
+
+ def test_reap_children(self):
+ '''Test that children are queued to be restarted when they ask for it.'''
+ # test various combinations of 3 booleans
+ # (Init.runnable, component.is_running(), component.failed())
+ self._test_reap_children_helper(False, False, False)
+ self._test_reap_children_helper(False, False, True)
+ self._test_reap_children_helper(False, True, False)
+ self._test_reap_children_helper(False, True, True)
+ self._test_reap_children_helper(True, False, False)
+ self._test_reap_children_helper(True, False, True)
+ self._test_reap_children_helper(True, True, False)
+ self._test_reap_children_helper(True, True, True)
+
+ # setup for more tests below
+ init = MockInit()
+ init.runnable = True
+ component = MockComponent('test', 53)
+ init.components[53] = component
+
+ # case where the returned pid is unknown to us. nothing should
+ # happpen then.
+ init.get_process_exit_status_called = False
+ init._get_process_exit_status = init._get_process_exit_status_unknown_pid
+ init.components_to_restart = []
+ # this should do nothing as the pid is unknown
+ init.reap_children()
+ self.assertEqual([], init.components_to_restart)
+
+ # case where init._get_process_exit_status() raises OSError with
+ # errno.ECHILD
+ init._get_process_exit_status = \
+ init._get_process_exit_status_raises_oserror_echild
+ init.components_to_restart = []
+ # this should catch and handle the OSError
+ init.reap_children()
+ self.assertEqual([], init.components_to_restart)
+
+ # case where init._get_process_exit_status() raises OSError with
+ # errno other than ECHILD
+ init._get_process_exit_status = \
+ init._get_process_exit_status_raises_oserror_other
+ with self.assertRaises(OSError):
+ init.reap_children()
+
+ # case where init._get_process_exit_status() raises something
+ # other than OSError
+ init._get_process_exit_status = \
+ init._get_process_exit_status_raises_other
+ with self.assertRaises(Exception):
+ init.reap_children()
+
+ def test_kill_started_components(self):
+ '''Test that started components are killed.'''
+ init = MockInit()
+
+ component = MockComponent('test', 53, 'Test')
+ init.components[53] = component
+
+ self.assertEqual([[53, 'test', 'Test']], init.get_processes())
+ init.kill_started_components()
+ self.assertEqual([], init.get_processes())
+ self.assertTrue(component.forceful)
+
+ def _start_msgq_helper(self, init, verbose):
+ init.verbose = verbose
+ pi = init.start_msgq()
+ self.assertEqual('b10-msgq', pi.name)
+ self.assertEqual(['b10-msgq'], pi.args)
+ self.assertTrue(pi.dev_null_stdout)
+ self.assertEqual(pi.dev_null_stderr, not verbose)
+ self.assertEqual({'FOO': 'an env string'}, pi.env)
+
+ # this is set by ProcessInfo.spawn()
+ self.assertEqual(42147, pi.pid)
+
+ def test_start_msgq(self):
+ '''Test that b10-msgq is started.'''
+ init = MockInitSimple()
+ init.c_channel_env = {'FOO': 'an env string'}
+ init._run_under_unittests = True
+
+ # use the MockProcessInfo creator
+ init._make_process_info = init._make_mock_process_info
+
+ # non-verbose case
+ self._start_msgq_helper(init, False)
+
+ # verbose case
+ self._start_msgq_helper(init, True)
+
+ def test_start_msgq_timeout(self):
+ '''Test that b10-msgq startup attempts connections several times
+ and times out eventually.'''
+ b10_init = MockInitSimple()
+ b10_init.c_channel_env = {}
+ # set the timeout to an arbitrary pre-determined value (which
+ # code below depends on)
+ b10_init.msgq_timeout = 1
+ b10_init._run_under_unittests = False
+
+ # use the MockProcessInfo creator
+ b10_init._make_process_info = b10_init._make_mock_process_info
+
+ global attempts
+ global tsec
+ attempts = 0
+ tsec = 0
+ self._tmp_time = time.time
+ self._tmp_sleep = time.sleep
+ def _my_time():
+ global attempts
+ global tsec
+ attempts += 1
+ return tsec
+ def _my_sleep(nsec):
+ global tsec
+ tsec += nsec
+ time.time = _my_time
+ time.sleep = _my_sleep
+
+ global cc_sub
+ cc_sub = None
+ class DummySessionAlwaysFails():
+ def __init__(self, socket_file):
+ raise isc.cc.session.SessionError('Connection fails')
+ def group_subscribe(self, s):
+ global cc_sub
+ cc_sub = s
+
+ isc.cc.Session = DummySessionAlwaysFails
+
+ with self.assertRaises(init.CChannelConnectError):
+ # An exception will be thrown here when it eventually times
+ # out.
+ pi = b10_init.start_msgq()
+
+ # time.time() should be called 12 times within the while loop:
+ # starting from 0, and 11 more times from 0.1 to 1.1. There's
+ # another call to time.time() outside the loop, which makes it
+ # 13.
+ self.assertEqual(attempts, 13)
+
+ # group_subscribe() should not have been called here.
+ self.assertIsNone(cc_sub)
+
+ global cc_socket_file
+ cc_socket_file = None
+ cc_sub = None
+ class DummySession():
+ def __init__(self, socket_file):
+ global cc_socket_file
+ cc_socket_file = socket_file
+ def group_subscribe(self, s):
+ global cc_sub
+ cc_sub = s
+
+ isc.cc.Session = DummySession
+
+ # reset values
+ attempts = 0
+ tsec = 0
+
+ pi = b10_init.start_msgq()
+
+ # just one attempt, but 2 calls to time.time()
+ self.assertEqual(attempts, 2)
+
+ self.assertEqual(cc_socket_file, b10_init.msgq_socket_file)
+ self.assertEqual(cc_sub, 'Init')
+
+ # isc.cc.Session, time.time() and time.sleep() are restored
+ # during tearDown().
+
+ def _start_cfgmgr_helper(self, init, data_path, filename, clear_config):
+ expect_args = ['b10-cfgmgr']
+ if data_path is not None:
+ init.data_path = data_path
+ expect_args.append('--data-path=' + data_path)
+ if filename is not None:
+ init.config_filename = filename
+ expect_args.append('--config-filename=' + filename)
+ if clear_config:
+ init.clear_config = clear_config
+ expect_args.append('--clear-config')
+
+ pi = init.start_cfgmgr()
+ self.assertEqual('b10-cfgmgr', pi.name)
+ self.assertEqual(expect_args, pi.args)
+ self.assertEqual({'TESTENV': 'A test string'}, pi.env)
+
+ # this is set by ProcessInfo.spawn()
+ self.assertEqual(42147, pi.pid)
+
+ def test_start_cfgmgr(self):
+ '''Test that b10-cfgmgr is started.'''
+ class DummySession():
+ def __init__(self):
+ self._tries = 0
+ def group_recvmsg(self):
+ self._tries += 1
+ # return running on the 3rd try onwards
+ if self._tries >= 3:
+ return ({'running': 'ConfigManager'}, None)
+ else:
+ return ({}, None)
+
+ init = MockInitSimple()
+ init.c_channel_env = {'TESTENV': 'A test string'}
+ init.cc_session = DummySession()
+ init.wait_time = 5
+
+ # use the MockProcessInfo creator
+ init._make_process_info = init._make_mock_process_info
+
+ global attempts
+ attempts = 0
+ self._tmp_sleep = time.sleep
+ def _my_sleep(nsec):
+ global attempts
+ attempts += 1
+ time.sleep = _my_sleep
+
+ # defaults
+ self._start_cfgmgr_helper(init, None, None, False)
+
+ # check that 2 attempts were made. on the 3rd attempt,
+ # process_running() returns that ConfigManager is running.
+ self.assertEqual(attempts, 2)
+
+ # data_path is specified
+ self._start_cfgmgr_helper(init, '/var/lib/test', None, False)
+
+ # config_filename is specified. Because `init` is not
+ # reconstructed, data_path is retained from the last call to
+ # _start_cfgmgr_helper().
+ self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', False)
+
+ # clear_config is specified. Because `init` is not reconstructed,
+ # data_path and config_filename are retained from the last call
+ # to _start_cfgmgr_helper().
+ self._start_cfgmgr_helper(init, '/var/lib/test', 'foo.cfg', True)
+
+ def test_start_cfgmgr_timeout(self):
+ '''Test that b10-cfgmgr startup attempts connections several times
+ and times out eventually.'''
+ class DummySession():
+ def group_recvmsg(self):
+ return (None, None)
+ b10_init = MockInitSimple()
+ b10_init.c_channel_env = {}
+ b10_init.cc_session = DummySession()
+ # set wait_time to an arbitrary pre-determined value (which code
+ # below depends on)
+ b10_init.wait_time = 2
+
+ # use the MockProcessInfo creator
+ b10_init._make_process_info = b10_init._make_mock_process_info
+
+ global attempts
+ attempts = 0
+ self._tmp_sleep = time.sleep
+ def _my_sleep(nsec):
+ global attempts
+ attempts += 1
+ time.sleep = _my_sleep
+
+ # We just check that an exception was thrown, and that several
+ # attempts were made to connect.
+ with self.assertRaises(init.ProcessStartError):
+ pi = b10_init.start_cfgmgr()
+
+ # 2 seconds of attempts every 1 second should result in 2 attempts
+ self.assertEqual(attempts, 2)
+
+ # time.sleep() is restored during tearDown().
+
+ def test_start_ccsession(self):
+ '''Test that CC session is started.'''
+ class DummySession():
+ def __init__(self, specfile, config_handler, command_handler,
+ socket_file):
+ self.specfile = specfile
+ self.config_handler = config_handler
+ self.command_handler = command_handler
+ self.socket_file = socket_file
+ self.started = False
+ def start(self):
+ self.started = True
+ b10_init = MockInitSimple()
+ self._tmp_module_cc_session = isc.config.ModuleCCSession
+ isc.config.ModuleCCSession = DummySession
+
+ b10_init.start_ccsession({})
+ self.assertEqual(init.SPECFILE_LOCATION, b10_init.ccs.specfile)
+ self.assertEqual(b10_init.config_handler, b10_init.ccs.config_handler)
+ self.assertEqual(b10_init.command_handler,
+ b10_init.ccs.command_handler)
+ self.assertEqual(b10_init.msgq_socket_file, b10_init.ccs.socket_file)
+ self.assertTrue(b10_init.ccs.started)
+
+ # isc.config.ModuleCCSession is restored during tearDown().
+
+ def test_start_process(self):
+ '''Test that processes can be started.'''
+ init = MockInit()
+
+ # use the MockProcessInfo creator
+ init._make_process_info = init._make_mock_process_info
+
+ pi = init.start_process('Test Process', ['/bin/true'], {})
+ self.assertEqual('Test Process', pi.name)
+ self.assertEqual(['/bin/true'], pi.args)
+ self.assertEqual({}, pi.env)
+
+ # this is set by ProcessInfo.spawn()
+ self.assertEqual(42147, pi.pid)
+
+ def test_register_process(self):
+ '''Test that processes can be registered with Init.'''
+ init = MockInit()
+ component = MockComponent('test', 53, 'Test')
+
+ self.assertFalse(53 in init.components)
+ init.register_process(53, component)
+ self.assertTrue(53 in init.components)
+ self.assertEqual(init.components[53].name(), 'test')
+ self.assertEqual(init.components[53].pid(), 53)
+ self.assertEqual(init.components[53].address(), 'Test')
+
+ def _start_simple_helper(self, init, verbose):
+ init.verbose = verbose
+
+ args = ['/bin/true']
+ if verbose:
+ args.append('-v')
+
+ init.start_simple('/bin/true')
+ self.assertEqual('/bin/true', init.started_process_name)
+ self.assertEqual(args, init.started_process_args)
+ self.assertEqual({'TESTENV': 'A test string'}, init.started_process_env)
+
+ def test_start_simple(self):
+ '''Test simple process startup.'''
+ init = MockInitSimple()
+ init.c_channel_env = {'TESTENV': 'A test string'}
+
+ # non-verbose case
+ self._start_simple_helper(init, False)
+
+ # verbose case
+ self._start_simple_helper(init, True)
+
+ def _start_auth_helper(self, init, verbose):
+ init.verbose = verbose
+
+ args = ['b10-auth']
+ if verbose:
+ args.append('-v')
+
+ init.start_auth()
+ self.assertEqual('b10-auth', init.started_process_name)
+ self.assertEqual(args, init.started_process_args)
+ self.assertEqual({'FOO': 'an env string'}, init.started_process_env)
+
+ def test_start_auth(self):
+ '''Test that b10-auth is started.'''
+ init = MockInitSimple()
+ init.c_channel_env = {'FOO': 'an env string'}
+
+ # non-verbose case
+ self._start_auth_helper(init, False)
+
+ # verbose case
+ self._start_auth_helper(init, True)
+
+ def _start_resolver_helper(self, init, verbose):
+ init.verbose = verbose
+
+ args = ['b10-resolver']
+ if verbose:
+ args.append('-v')
+
+ init.start_resolver()
+ self.assertEqual('b10-resolver', init.started_process_name)
+ self.assertEqual(args, init.started_process_args)
+ self.assertEqual({'BAR': 'an env string'}, init.started_process_env)
+
+ def test_start_resolver(self):
+ '''Test that b10-resolver is started.'''
+ init = MockInitSimple()
+ init.c_channel_env = {'BAR': 'an env string'}
+
+ # non-verbose case
+ self._start_resolver_helper(init, False)
+
+ # verbose case
+ self._start_resolver_helper(init, True)
+
+ def _start_cmdctl_helper(self, init, verbose, port = None):
+ init.verbose = verbose
+
+ args = ['b10-cmdctl']
+
+ if port is not None:
+ init.cmdctl_port = port
+ args.append('--port=9353')
+
+ if verbose:
+ args.append('-v')
+
+ init.start_cmdctl()
+ self.assertEqual('b10-cmdctl', init.started_process_name)
+ self.assertEqual(args, init.started_process_args)
+ self.assertEqual({'BAZ': 'an env string'}, init.started_process_env)
+
+ def test_start_cmdctl(self):
+ '''Test that b10-cmdctl is started.'''
+ init = MockInitSimple()
+ init.c_channel_env = {'BAZ': 'an env string'}
+
+ # non-verbose case
+ self._start_cmdctl_helper(init, False)
+
+ # verbose case
+ self._start_cmdctl_helper(init, True)
+
+ # with port, non-verbose case
+ self._start_cmdctl_helper(init, False, 9353)
+
+ # with port, verbose case
+ self._start_cmdctl_helper(init, True, 9353)
+
+ def test_socket_data(self):
+ '''Test that Init._socket_data works as expected.'''
+ class MockSock:
+ def __init__(self, fd, throw):
+ self.fd = fd
+ self.throw = throw
+ self.buf = b'Hello World.\nYou are so nice today.\nXX'
+ self.i = 0
+
+ def recv(self, bufsize, flags = 0):
+ if bufsize != 1:
+ raise Exception('bufsize != 1')
+ if flags != socket.MSG_DONTWAIT:
+ raise Exception('flags != socket.MSG_DONTWAIT')
+ # after 15 recv()s, throw a socket.error with EAGAIN to
+ # get _socket_data() to save back what's been read. The
+ # number 15 is arbitrarily chosen, but the checks then
+ # depend on this being 15, i.e., if you adjust this
+ # number, you may have to adjust the checks below too.
+ if self.throw and self.i > 15:
+ raise socket.error(errno.EAGAIN, 'Try again')
+ if self.i >= len(self.buf):
+ return b'';
+ t = self.i
+ self.i += 1
+ return self.buf[t:t+1]
+
+ def close(self):
+ return
+
+ class MockInitSocketData(Init):
+ def __init__(self, throw):
+ self._unix_sockets = {42: (MockSock(42, throw), b'')}
+ self.requests = []
+ self.dead = []
+
+ def socket_request_handler(self, previous, sock):
+ self.requests.append({sock.fd: previous})
+
+ def socket_consumer_dead(self, sock):
+ self.dead.append(sock.fd)
+
+ # Case where we get data every time we call recv()
+ init = MockInitSocketData(False)
+ init._socket_data(42)
+ self.assertEqual(init.requests,
+ [{42: b'Hello World.'},
+ {42: b'You are so nice today.'}])
+ self.assertEqual(init.dead, [42])
+ self.assertEqual({}, init._unix_sockets)
+
+ # Case where socket.recv() raises EAGAIN. In this case, the
+ # routine is supposed to save what it has back to
+ # Init._unix_sockets.
+ init = MockInitSocketData(True)
+ init._socket_data(42)
+ self.assertEqual(init.requests, [{42: b'Hello World.'}])
+ self.assertFalse(init.dead)
+ self.assertEqual(len(init._unix_sockets), 1)
+ self.assertEqual(init._unix_sockets[42][1], b'You')
+
+ def test_startup(self):
+ '''Test that Init.startup() handles failures properly.'''
+ class MockInitStartup(Init):
+ def __init__(self, throw):
+ self.throw = throw
+ self.started = False
+ self.killed = False
+ self.msgq_socket_file = None
+ self.curproc = 'myproc'
+ self.runnable = False
+
+ def start_all_components(self):
+ self.started = True
+ if self.throw is True:
+ raise Exception('Assume starting components has failed.')
+ elif self.throw:
+ raise self.throw
+
+ def kill_started_components(self):
+ self.killed = True
+
+ class DummySession():
+ def __init__(self, socket_file):
+ raise isc.cc.session.SessionError('This is the expected case.')
+
+ class DummySessionSocketExists():
+ def __init__(self, socket_file):
+ # simulate that connect passes
+ return
+
+ isc.cc.Session = DummySession
+
+ # All is well case, where all components are started
+ # successfully. We check that the actual call to
+ # start_all_components() is made, and Init.runnable is true.
+ b10_init = MockInitStartup(False)
+ r = b10_init.startup()
+ self.assertIsNone(r)
+ self.assertTrue(b10_init.started)
+ self.assertFalse(b10_init.killed)
+ self.assertTrue(b10_init.runnable)
+ self.assertEqual({}, b10_init.c_channel_env)
+
+ # Case where starting components fails. We check that
+ # kill_started_components() is called right after, and
+ # Init.runnable is not modified.
+ b10_init = MockInitStartup(True)
+ r = b10_init.startup()
+ # r contains an error message
+ self.assertEqual(r, 'Unable to start myproc: Assume starting components has failed.')
+ self.assertTrue(b10_init.started)
+ self.assertTrue(b10_init.killed)
+ self.assertFalse(b10_init.runnable)
+ self.assertEqual({}, b10_init.c_channel_env)
+
+ # Check if msgq_socket_file is carried over
+ b10_init = MockInitStartup(False)
+ b10_init.msgq_socket_file = 'foo'
+ r = b10_init.startup()
+ self.assertEqual({'BIND10_MSGQ_SOCKET_FILE': 'foo'},
+ b10_init.c_channel_env)
+
+ # Check failure of changing user results in a different message
+ b10_init = MockInitStartup(init.ChangeUserError('failed to chusr'))
+ r = b10_init.startup()
+ self.assertIn('failed to chusr', r)
+ self.assertTrue(b10_init.killed)
+
+ # Check the case when socket file already exists
+ isc.cc.Session = DummySessionSocketExists
+ b10_init = MockInitStartup(False)
+ r = b10_init.startup()
+ self.assertIn('already running', r)
+
+ # isc.cc.Session is restored during tearDown().
+
+class SocketSrvTest(unittest.TestCase):
+ """
+ This tests some methods of b10-init related to the unix domain sockets
+ used to transfer other sockets to applications.
+ """
+ def setUp(self):
+ """
+ Create the b10-init to test, testdata and backup some functions.
+ """
+ self.__b10_init = Init()
+ self.__select_backup = init.select.select
+ self.__select_called = None
+ self.__socket_data_called = None
+ self.__consumer_dead_called = None
+ self.__socket_request_handler_called = None
+
+ def tearDown(self):
+ """
+ Restore functions.
+ """
+ init.select.select = self.__select_backup
+
+ class __FalseSocket:
+ """
+ A mock socket for the select and accept and stuff like that.
+ """
+ def __init__(self, owner, fileno=42):
+ self.__owner = owner
+ self.__fileno = fileno
+ self.data = None
+ self.closed = False
+
+ def fileno(self):
+ return self.__fileno
+
+ def accept(self):
+ return (self.__class__(self.__owner, 13), "/path/to/socket")
+
+ def recv(self, bufsize, flags=0):
+ self.__owner.assertEqual(1, bufsize)
+ self.__owner.assertEqual(socket.MSG_DONTWAIT, flags)
+ if isinstance(self.data, socket.error):
+ raise self.data
+ elif self.data is not None:
+ if len(self.data):
+ result = self.data[0:1]
+ self.data = self.data[1:]
+ return result
+ else:
+ raise socket.error(errno.EAGAIN, "Would block")
+ else:
+ return b''
+
+ def close(self):
+ self.closed = True
+
+ class __CCS:
+ """
+ A mock CCS, just to provide the socket file number.
+ """
+ class __Socket:
+ def fileno(self):
+ return 1
+ def get_socket(self):
+ return self.__Socket()
+
+ def __select_accept(self, r, w, x, t):
+ self.__select_called = (r, w, x, t)
+ return ([42], [], [])
+
+ def __select_data(self, r, w, x, t):
+ self.__select_called = (r, w, x, t)
+ return ([13], [], [])
+
+ def __accept(self):
+ """
+ Hijack the accept method of the b10-init.
+
+ Notes down it was called and stops b10-init.
+ """
+ self.__accept_called = True
+ self.__b10_init.runnable = False
+
+ def test_srv_accept_called(self):
+ """
+ Test that the _srv_accept method of b10-init is called when the
+ listening socket is readable.
+ """
+ self.__b10_init.runnable = True
+ self.__b10_init._srv_socket = self.__FalseSocket(self)
+ self.__b10_init._srv_accept = self.__accept
+ self.__b10_init.ccs = self.__CCS()
+ init.select.select = self.__select_accept
+ self.__b10_init.run(2)
+ # It called the accept
+ self.assertTrue(self.__accept_called)
+ # And the select had the right parameters
+ self.assertEqual(([2, 1, 42], [], [], None), self.__select_called)
+
+ def test_srv_accept(self):
+ """
+ Test how the _srv_accept method works.
+ """
+ self.__b10_init._srv_socket = self.__FalseSocket(self)
+ self.__b10_init._srv_accept()
+ # After we accepted, a new socket is added there
+ socket = self.__b10_init._unix_sockets[13][0]
+ # The socket is properly stored there
+ self.assertTrue(isinstance(socket, self.__FalseSocket))
+ # And the buffer (yet empty) is there
+ self.assertEqual({13: (socket, b'')}, self.__b10_init._unix_sockets)
+
+ def __socket_data(self, socket):
+ self.__b10_init.runnable = False
+ self.__socket_data_called = socket
+
+ def test_socket_data(self):
+ """
+ Test that a socket that wants attention gets it.
+ """
+ self.__b10_init._srv_socket = self.__FalseSocket(self)
+ self.__b10_init._socket_data = self.__socket_data
+ self.__b10_init.ccs = self.__CCS()
+ self.__b10_init._unix_sockets = {13: (self.__FalseSocket(self, 13), b'')}
+ self.__b10_init.runnable = True
+ init.select.select = self.__select_data
+ self.__b10_init.run(2)
+ self.assertEqual(13, self.__socket_data_called)
+ self.assertEqual(([2, 1, 42, 13], [], [], None), self.__select_called)
+
+ def __prepare_data(self, data):
+ socket = self.__FalseSocket(self, 13)
+ self.__b10_init._unix_sockets = {13: (socket, b'')}
+ socket.data = data
+ self.__b10_init.socket_consumer_dead = self.__consumer_dead
+ self.__b10_init.socket_request_handler = self.__socket_request_handler
+ return socket
+
+ def __consumer_dead(self, socket):
+ self.__consumer_dead_called = socket
+
+ def __socket_request_handler(self, token, socket):
+ self.__socket_request_handler_called = (token, socket)
+
+ def test_socket_closed(self):
+ """
+ Test that a socket is removed and the socket_consumer_dead is called
+ when it is closed.
+ """
+ socket = self.__prepare_data(None)
+ self.__b10_init._socket_data(13)
+ self.assertEqual(socket, self.__consumer_dead_called)
+ self.assertEqual({}, self.__b10_init._unix_sockets)
+ self.assertTrue(socket.closed)
+
+ def test_socket_short(self):
+ """
+ Test that if there's not enough data to get the whole socket, it is
+ kept there, but nothing is called.
+ """
+ socket = self.__prepare_data(b'tok')
+ self.__b10_init._socket_data(13)
+ self.assertEqual({13: (socket, b'tok')}, self.__b10_init._unix_sockets)
+ self.assertFalse(socket.closed)
+ self.assertIsNone(self.__consumer_dead_called)
+ self.assertIsNone(self.__socket_request_handler_called)
+
+ def test_socket_continue(self):
+ """
+ Test that we call the token handling function when the whole token
+ comes. This test pretends to continue reading where the previous one
+ stopped.
+ """
+ socket = self.__prepare_data(b"en\nanothe")
+ # The data to finish
+ self.__b10_init._unix_sockets[13] = (socket, b'tok')
+ self.__b10_init._socket_data(13)
+ self.assertEqual({13: (socket, b'anothe')}, self.__b10_init._unix_sockets)
+ self.assertFalse(socket.closed)
+ self.assertIsNone(self.__consumer_dead_called)
+ self.assertEqual((b'token', socket),
+ self.__socket_request_handler_called)
+
+ def test_broken_socket(self):
+ """
+ If the socket raises an exception during the read other than EAGAIN,
+ it is broken and we remove it.
+ """
+ sock = self.__prepare_data(socket.error(errno.ENOMEM,
+ "There's more memory available, but not for you"))
+ self.__b10_init._socket_data(13)
+ self.assertEqual(sock, self.__consumer_dead_called)
+ self.assertEqual({}, self.__b10_init._unix_sockets)
+ self.assertTrue(sock.closed)
+
+class TestFunctions(unittest.TestCase):
+ def setUp(self):
+ self.lockfile_testpath = \
+ "@abs_top_builddir@/src/bin/bind10/tests/lockfile_test"
+ self.assertFalse(os.path.exists(self.lockfile_testpath))
+ os.mkdir(self.lockfile_testpath)
+ self.assertTrue(os.path.isdir(self.lockfile_testpath))
+ self.__isfile_orig = init.os.path.isfile
+ self.__unlink_orig = init.os.unlink
+
+ def tearDown(self):
+ os.rmdir(self.lockfile_testpath)
+ self.assertFalse(os.path.isdir(self.lockfile_testpath))
+ os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = "@abs_top_builddir@"
+ init.os.path.isfile = self.__isfile_orig
+ init.os.unlink = self.__unlink_orig
+
+ def test_remove_lock_files(self):
+ os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] = self.lockfile_testpath
+
+ # create lockfiles for the testcase
+ lockfiles = ["logger_lockfile"]
+ for f in lockfiles:
+ fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+ self.assertFalse(os.path.exists(fname))
+ open(fname, "w").close()
+ self.assertTrue(os.path.isfile(fname))
+
+ # first call should clear up all the lockfiles
+ init.remove_lock_files()
+
+ # check if the lockfiles exist
+ for f in lockfiles:
+ fname = os.environ["B10_LOCKFILE_DIR_FROM_BUILD"] + '/' + f
+ self.assertFalse(os.path.isfile(fname))
+
+ # second call should not assert anyway
+ init.remove_lock_files()
+
+ def test_remove_lock_files_fail(self):
+ # Permission error on unlink is ignored; other exceptions are really
+ # unexpected and propagated.
+ def __raising_unlink(unused, ex):
+ raise ex
+
+ init.os.path.isfile = lambda _: True
+ os_error = OSError()
+ init.os.unlink = lambda f: __raising_unlink(f, os_error)
+
+ os_error.errno = errno.EPERM
+ init.remove_lock_files() # no disruption
+
+ os_error.errno = errno.EACCES
+ init.remove_lock_files() # no disruption
+
+ os_error.errno = errno.ENOENT
+ self.assertRaises(OSError, init.remove_lock_files)
+
+ init.os.unlink = lambda f: __raising_unlink(f, Exception('bad'))
+ self.assertRaises(Exception, init.remove_lock_files)
+
+ def test_get_signame(self):
+ # just test with some samples
+ signame = init.get_signame(signal.SIGTERM)
+ self.assertEqual('SIGTERM', signame)
+ signame = init.get_signame(signal.SIGKILL)
+ self.assertEqual('SIGKILL', signame)
+ # 59426 is hopefully an unused signal on most platforms
+ signame = init.get_signame(59426)
+ self.assertEqual('Unknown signal 59426', signame)
+
+ def test_fatal_signal(self):
+ self.assertIsNone(init.b10_init)
+ init.b10_init = Init()
+ init.b10_init.runnable = True
+ init.fatal_signal(signal.SIGTERM, None)
+ # Now, runnable must be False
+ self.assertFalse(init.b10_init.runnable)
+ init.b10_init = None
+
+if __name__ == '__main__':
+ # store os.environ for test_unchanged_environment
+ original_os_environ = copy.deepcopy(os.environ)
+ isc.log.resetUnitTestRootLogger()
+ unittest.main()
diff --git a/src/bin/bindctl/bindcmd.py b/src/bin/bindctl/bindcmd.py
index af599a4..f382e2a 100644
--- a/src/bin/bindctl/bindcmd.py
+++ b/src/bin/bindctl/bindcmd.py
@@ -25,7 +25,7 @@ from bindctl.moduleinfo import *
from bindctl.cmdparse import BindCmdParser
from bindctl import command_sets
from xml.dom import minidom
-import isc
+import isc.config
import isc.cc.data
import http.client
import json
diff --git a/src/bin/bindctl/run_bindctl.sh.in b/src/bin/bindctl/run_bindctl.sh.in
index 999d7ee..8a5d00b 100755
--- a/src/bin/bindctl/run_bindctl.sh.in
+++ b/src/bin/bindctl/run_bindctl.sh.in
@@ -23,7 +23,7 @@ BINDCTL_PATH=@abs_top_builddir@/src/bin/bindctl
# Note: lib/dns/python/.libs is necessary because __init__.py of isc package
# automatically imports isc.datasrc, which then requires the DNS loadable
# module. #2145 should eliminate the need for it.
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
export PYTHONPATH
# If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/ddns/ddns.py.in b/src/bin/ddns/ddns.py.in
index 094e0ec..d7fcab7 100755
--- a/src/bin/ddns/ddns.py.in
+++ b/src/bin/ddns/ddns.py.in
@@ -134,7 +134,7 @@ def get_datasrc_client(cc_session):
function will simply be removed.
'''
- HARDCODED_DATASRC_CLASS = RRClass.IN()
+ HARDCODED_DATASRC_CLASS = RRClass.IN
file, is_default = cc_session.get_remote_config_value("Auth",
"database_file")
# See xfrout.py:get_db_file() for this trick:
@@ -469,7 +469,7 @@ class DDNSServer:
self.__request_msg.clear(Message.PARSE)
# specify PRESERVE_ORDER as we need to handle each RR separately.
self.__request_msg.from_wire(req_data, Message.PRESERVE_ORDER)
- if self.__request_msg.get_opcode() != Opcode.UPDATE():
+ if self.__request_msg.get_opcode() != Opcode.UPDATE:
raise self.InternalError('Update request has unexpected '
'opcode: ' +
str(self.__request_msg.get_opcode()))
@@ -536,7 +536,7 @@ class DDNSServer:
else:
tcp_ctx.close()
except socket.error as ex:
- logger.warn(DDNS_RESPONSE_SOCKET_ERROR, ClientFormatter(dest), ex)
+ logger.warn(DDNS_RESPONSE_SOCKET_SEND_FAILED, ClientFormatter(dest), ex)
return False
return True
@@ -683,7 +683,7 @@ class DDNSServer:
result = ctx[0].send_ready()
if result != DNSTCPContext.SENDING:
if result == DNSTCPContext.CLOSED:
- logger.warn(DDNS_RESPONSE_TCP_SOCKET_ERROR,
+ logger.warn(DDNS_RESPONSE_TCP_SOCKET_SEND_FAILED,
ClientFormatter(ctx[1]))
ctx[0].close()
del self._tcp_ctxs[fileno]
diff --git a/src/bin/ddns/ddns_messages.mes b/src/bin/ddns/ddns_messages.mes
index d128361..cdc7b4d 100644
--- a/src/bin/ddns/ddns_messages.mes
+++ b/src/bin/ddns/ddns_messages.mes
@@ -134,12 +134,12 @@ appropriate ACL configuration or some lower layer filtering. The
number of existing TCP clients are shown in the log, which should be
identical to the current quota.
-% DDNS_RESPONSE_SOCKET_ERROR failed to send update response to %1: %2
+% DDNS_RESPONSE_SOCKET_SEND_FAILED failed to send update response to %1: %2
Network I/O error happens in sending an update response. The
client's address that caused the error and error details are also
logged.
-% DDNS_RESPONSE_TCP_SOCKET_ERROR failed to complete sending update response to %1 over TCP
+% DDNS_RESPONSE_TCP_SOCKET_SEND_FAILED failed to complete sending update response to %1 over TCP
b10-ddns had tried to send an update response over TCP, and it hadn't
been completed at that time, and a followup attempt to complete the
send operation failed due to some network I/O error. While a network
diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py
index 9119a89..d366f09 100755
--- a/src/bin/ddns/tests/ddns_test.py
+++ b/src/bin/ddns/tests/ddns_test.py
@@ -39,9 +39,9 @@ TESTDATA_PATH = os.environ['TESTDATA_PATH'] + os.sep
READ_ZONE_DB_FILE = TESTDATA_PATH + "rwtest.sqlite3" # original, to be copied
TEST_ZONE_NAME = Name('example.org')
TEST_ZONE_NAME_STR = TEST_ZONE_NAME.to_text()
-UPDATE_RRTYPE = RRType.SOA()
+UPDATE_RRTYPE = RRType.SOA
TEST_QID = 5353 # arbitrary chosen
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
TEST_RRCLASS_STR = TEST_RRCLASS.to_text()
TEST_SERVER6 = ('2001:db8::53', 53, 0, 0)
TEST_CLIENT6 = ('2001:db8::1', 53000, 0, 0)
@@ -169,9 +169,9 @@ class FakeUpdateSession:
self.__msg.make_response()
self.__msg.clear_section(SECTION_ZONE)
if self.__faked_result == UPDATE_SUCCESS:
- self.__msg.set_rcode(Rcode.NOERROR())
+ self.__msg.set_rcode(Rcode.NOERROR)
else:
- self.__msg.set_rcode(Rcode.REFUSED())
+ self.__msg.set_rcode(Rcode.REFUSED)
return self.__msg
class FakeKeyringModule:
@@ -478,7 +478,7 @@ class TestDDNSServer(unittest.TestCase):
# By default (in our faked config) it should be derived from the
# test data source
rrclass, datasrc_client = self.ddns_server._datasrc_info
- self.assertEqual(RRClass.IN(), rrclass)
+ self.assertEqual(RRClass.IN, rrclass)
self.assertEqual(DataSourceClient.SUCCESS,
datasrc_client.find_zone(Name('example.org'))[0])
@@ -491,7 +491,7 @@ class TestDDNSServer(unittest.TestCase):
{'database_file': './notexistentdir/somedb.sqlite3'}
self.__cc_session.add_remote_config_by_name('Auth')
rrclass, datasrc_client = self.ddns_server._datasrc_info
- self.assertEqual(RRClass.IN(), rrclass)
+ self.assertEqual(RRClass.IN, rrclass)
self.assertRaises(isc.datasrc.Error,
datasrc_client.find_zone, Name('example.org'))
@@ -887,12 +887,12 @@ class TestDDNSServer(unittest.TestCase):
self.__select_answer = ([], [10], [])
self.assertRaises(KeyError, self.ddns_server.run)
-def create_msg(opcode=Opcode.UPDATE(), zones=[TEST_ZONE_RECORD], prereq=[],
+def create_msg(opcode=Opcode.UPDATE, zones=[TEST_ZONE_RECORD], prereq=[],
tsigctx=None):
msg = Message(Message.RENDER)
msg.set_qid(TEST_QID)
msg.set_opcode(opcode)
- msg.set_rcode(Rcode.NOERROR())
+ msg.set_rcode(Rcode.NOERROR)
for z in zones:
msg.add_question(z)
for p in prereq:
@@ -936,7 +936,7 @@ class TestDDNSSession(unittest.TestCase):
return FakeUpdateSession(req_message, client_addr, zone_config,
self.__faked_result)
- def check_update_response(self, resp_wire, expected_rcode=Rcode.NOERROR(),
+ def check_update_response(self, resp_wire, expected_rcode=Rcode.NOERROR,
tsig_ctx=None, tcp=False):
'''Check if given wire data are valid form of update response.
@@ -963,7 +963,7 @@ class TestDDNSSession(unittest.TestCase):
self.assertNotEqual(None, tsig_record)
self.assertEqual(TSIGError.NOERROR,
tsig_ctx.verify(tsig_record, resp_wire))
- self.assertEqual(Opcode.UPDATE(), msg.get_opcode())
+ self.assertEqual(Opcode.UPDATE, msg.get_opcode())
self.assertEqual(expected_rcode, msg.get_rcode())
self.assertEqual(TEST_QID, msg.get_qid())
for section in [SECTION_ZONE, SECTION_PREREQUISITE, SECTION_UPDATE]:
@@ -977,7 +977,7 @@ class TestDDNSSession(unittest.TestCase):
server_addr = TEST_SERVER6 if ipv6 else TEST_SERVER4
client_addr = TEST_CLIENT6 if ipv6 else TEST_CLIENT4
tsig = TSIGContext(tsig_key) if tsig_key is not None else None
- rcode = Rcode.NOERROR() if result == UPDATE_SUCCESS else Rcode.REFUSED()
+ rcode = Rcode.NOERROR if result == UPDATE_SUCCESS else Rcode.REFUSED
has_response = (result != UPDATE_DROP)
self.assertEqual(has_response,
@@ -1015,7 +1015,7 @@ class TestDDNSSession(unittest.TestCase):
# Opcode is not UPDATE
self.assertFalse(self.server.handle_request(
- (self.__sock, None, None, create_msg(opcode=Opcode.QUERY()))))
+ (self.__sock, None, None, create_msg(opcode=Opcode.QUERY))))
self.assertEqual((None, None), (s._sent_data, s._sent_addr))
# TSIG verification error. We use UPDATE_DROP to signal check_session
@@ -1031,7 +1031,7 @@ class TestDDNSSession(unittest.TestCase):
TEST_CLIENT6,
create_msg())))
# this check ensures sendto() was really attempted.
- self.check_update_response(self.__sock._sent_data, Rcode.NOERROR())
+ self.check_update_response(self.__sock._sent_data, Rcode.NOERROR)
def test_tcp_request(self):
# A simple case using TCP: all resopnse data are sent out at once.
@@ -1040,7 +1040,7 @@ class TestDDNSSession(unittest.TestCase):
self.assertTrue(self.server.handle_request((s, TEST_SERVER6,
TEST_CLIENT6,
create_msg())))
- self.check_update_response(s._sent_data, Rcode.NOERROR(), tcp=True)
+ self.check_update_response(s._sent_data, Rcode.NOERROR, tcp=True)
# In the current implementation, the socket should be closed
# immedidately after a successful send.
self.assertEqual(1, s._close_called)
@@ -1071,7 +1071,7 @@ class TestDDNSSession(unittest.TestCase):
s.make_send_ready()
self.assertEqual(DNSTCPContext.SEND_DONE,
self.server._tcp_ctxs[s.fileno()][0].send_ready())
- self.check_update_response(s._sent_data, Rcode.NOERROR(), tcp=True)
+ self.check_update_response(s._sent_data, Rcode.NOERROR, tcp=True)
def test_tcp_request_error(self):
# initial send() on the TCP socket will fail. The request handling
@@ -1127,9 +1127,9 @@ class TestDDNSSession(unittest.TestCase):
self.__faked_result = UPDATE_DROP
# Put the same RR twice in the prerequisite section. We should see
# them as separate RRs.
- dummy_record = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(),
+ dummy_record = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS,
RRTTL(0))
- dummy_record.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS, "ns.example."))
+ dummy_record.add_rdata(Rdata(RRType.NS, TEST_RRCLASS, "ns.example."))
self.server.handle_request((self.__sock, TEST_SERVER6, TEST_CLIENT6,
create_msg(prereq=[dummy_record,
dummy_record])))
diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am
index 28f08f7..b3818c7 100644
--- a/src/bin/dhcp4/Makefile.am
+++ b/src/bin/dhcp4/Makefile.am
@@ -5,6 +5,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
if USE_STATIC_LINK
AM_LDFLAGS = -static
@@ -51,12 +55,6 @@ b10_dhcp4_SOURCES += dhcp4_srv.cc dhcp4_srv.h
nodist_b10_dhcp4_SOURCES = dhcp4_messages.h dhcp4_messages.cc
EXTRA_DIST += dhcp4_messages.mes
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-b10_dhcp4_CXXFLAGS = -Wno-unused-parameter
-endif
-
b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
b10_dhcp4_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
b10_dhcp4_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
diff --git a/src/bin/dhcp4/config_parser.cc b/src/bin/dhcp4/config_parser.cc
index 9e9360c..d8a586b 100644
--- a/src/bin/dhcp4/config_parser.cc
+++ b/src/bin/dhcp4/config_parser.cc
@@ -967,13 +967,13 @@ public:
return (new OptionDataListParser(param_name));
}
+ /// Pointer to options instances storage.
+ OptionStorage* options_;
/// Intermediate option storage. This storage is used by
/// lower level parsers to add new options. Values held
/// in this storage are assigned to main storage (options_)
/// if overall parsing was successful.
OptionStorage local_options_;
- /// Pointer to options instances storage.
- OptionStorage* options_;
/// Collection of parsers;
ParserCollection parsers_;
};
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index 17f9967..247d6c3 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -94,6 +94,11 @@ server is about to open sockets on the specified port.
The IPv4 DHCP server has received a packet that it is unable to
interpret. The reason why the packet is invalid is included in the message.
+% DHCP4_PACKET_PROCESS_FAIL failed to process packet received from %1: %2
+This is a general catch-all message indicating that the processing of a
+received packet failed. The reason is given in the message. The server
+will not send a response but will instead ignore the packet.
+
% DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
A debug message noting that the server has received the specified type of
packet on the specified interface. Note that a packet marked as UNKNOWN
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 4538ad6..261e213 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -42,6 +42,18 @@ using namespace isc::dhcp;
using namespace isc::log;
using namespace std;
+namespace isc {
+namespace dhcp {
+
+/// @brief file name of a server-id file
+///
+/// Server must store its server identifier in persistent storage that must not
+/// change between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
+/// first run and then use it afterwards.
+static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
+
// These are hardcoded parameters. Currently this is a skeleton server that only
// grants those options and a single, fixed, hardcoded lease.
@@ -98,7 +110,8 @@ Dhcpv4Srv::~Dhcpv4Srv() {
IfaceMgr::instance().closeSockets();
}
-void Dhcpv4Srv::shutdown() {
+void
+Dhcpv4Srv::shutdown() {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_SHUTDOWN_REQUEST);
shutdown_ = true;
}
@@ -136,32 +149,53 @@ Dhcpv4Srv::run() {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
.arg(query->toText());
- switch (query->getType()) {
- case DHCPDISCOVER:
- rsp = processDiscover(query);
- break;
-
- case DHCPREQUEST:
- rsp = processRequest(query);
- break;
-
- case DHCPRELEASE:
- processRelease(query);
- break;
-
- case DHCPDECLINE:
- processDecline(query);
- break;
-
- case DHCPINFORM:
- processInform(query);
- break;
-
- default:
- // Only action is to output a message if debug is enabled,
- // and that will be covered by the debug statement before
- // the "switch" statement.
- ;
+ try {
+ switch (query->getType()) {
+ case DHCPDISCOVER:
+ rsp = processDiscover(query);
+ break;
+
+ case DHCPREQUEST:
+ rsp = processRequest(query);
+ break;
+
+ case DHCPRELEASE:
+ processRelease(query);
+ break;
+
+ case DHCPDECLINE:
+ processDecline(query);
+ break;
+
+ case DHCPINFORM:
+ processInform(query);
+ break;
+
+ default:
+ // Only action is to output a message if debug is enabled,
+ // and that is covered by the debug statement before the
+ // "switch" statement.
+ ;
+ }
+ } catch (const isc::Exception& e) {
+
+ // Catch-all exception (at least for ones based on the isc
+ // Exception class, which covers more or less all that
+ // are explicitly raised in the BIND 10 code). Just log
+ // the problem and ignore the packet. (The problem is logged
+ // as a debug message because debug is disabled by default -
+ // it prevents a DDOS attack based on the sending of problem
+ // packets.)
+ if (dhcp4_logger.isDebugEnabled(DBG_DHCP4_BASIC)) {
+ std::string source = "unknown";
+ HWAddrPtr hwptr = query->getHWAddr();
+ if (hwptr) {
+ source = hwptr->toText();
+ }
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
+ DHCP4_PACKET_PROCESS_FAIL)
+ .arg(source).arg(e.what());
+ }
}
if (rsp) {
@@ -199,7 +233,8 @@ Dhcpv4Srv::run() {
return (true);
}
-bool Dhcpv4Srv::loadServerID(const std::string& file_name) {
+bool
+Dhcpv4Srv::loadServerID(const std::string& file_name) {
// load content of the file into a string
fstream f(file_name.c_str(), ios::in);
@@ -233,7 +268,8 @@ bool Dhcpv4Srv::loadServerID(const std::string& file_name) {
return (true);
}
-void Dhcpv4Srv::generateServerID() {
+void
+Dhcpv4Srv::generateServerID() {
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
@@ -270,16 +306,19 @@ void Dhcpv4Srv::generateServerID() {
isc_throw(BadValue, "No suitable interfaces for server-identifier found");
}
-bool Dhcpv4Srv::writeServerID(const std::string& file_name) {
+bool
+Dhcpv4Srv::writeServerID(const std::string& file_name) {
fstream f(file_name.c_str(), ios::out | ios::trunc);
if (!f.good()) {
return (false);
}
f << srvidToString(getServerID());
f.close();
+ return (true);
}
-string Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
+string
+Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
if (!srvid) {
isc_throw(BadValue, "NULL pointer passed to srvidToString()");
}
@@ -298,7 +337,8 @@ string Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
return (addrs[0].toText());
}
-void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
+void
+Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
answer->setIface(question->getIface());
answer->setIndex(question->getIndex());
answer->setCiaddr(question->getCiaddr());
@@ -327,7 +367,8 @@ void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
}
-void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
+void
+Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
OptionPtr opt;
// add Message Type Option (type 53)
@@ -339,8 +380,8 @@ void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
// more options will be added here later
}
-
-void Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
+void
+Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
// Get the subnet relevant for the client. We will need it
// to get the options associated with it.
@@ -411,7 +452,8 @@ Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
}
}
-void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
+void
+Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
// We need to select a subnet the client is connected in.
Subnet4Ptr subnet = selectSubnet(question);
@@ -509,7 +551,8 @@ void Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
}
-OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
+OptionPtr
+Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
uint32_t netmask = getNetmask4(subnet->get().second);
OptionPtr opt(new OptionInt<uint32_t>(Option::V4,
@@ -518,7 +561,8 @@ OptionPtr Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
return (opt);
}
-Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
+Pkt4Ptr
+Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
Pkt4Ptr offer = Pkt4Ptr
(new Pkt4(DHCPOFFER, discover->getTransid()));
@@ -536,7 +580,8 @@ Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
return (offer);
}
-Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
+Pkt4Ptr
+Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
Pkt4Ptr ack = Pkt4Ptr
(new Pkt4(DHCPACK, request->getTransid()));
@@ -554,7 +599,8 @@ Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
return (ack);
}
-void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
+void
+Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
// Try to find client-id
ClientIdPtr client_id;
@@ -622,11 +668,13 @@ void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
}
-void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
+void
+Dhcpv4Srv::processDecline(Pkt4Ptr& /* decline */) {
/// TODO: Implement this.
}
-Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
+Pkt4Ptr
+Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
/// TODO: Currently implemented echo mode. Implement this for real
return (inform);
}
@@ -662,7 +710,8 @@ Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
return (UNKNOWN);
}
-Subnet4Ptr Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
+Subnet4Ptr
+Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
// Is this relayed message?
IOAddress relay = question->getGiaddr();
@@ -677,7 +726,8 @@ Subnet4Ptr Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
}
}
-void Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
+void
+Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
OptionPtr server_id = pkt->getOption(DHO_DHCP_SERVER_IDENTIFIER);
switch (serverid) {
case FORBIDDEN:
@@ -700,3 +750,6 @@ void Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
;
}
}
+
+} // namespace dhcp
+} // namespace isc
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index cb9581f..1c988b1 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -28,15 +28,6 @@
namespace isc {
namespace dhcp {
-/// @brief file name of a server-id file
-///
-/// Server must store its server identifier in persistent storage that must not
-/// change between restarts. This is name of the file that is created in dataDir
-/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
-/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
-/// first run and then use it afterwards.
-static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
-
/// @brief DHCPv4 server service.
///
/// This singleton class represents DHCPv4 server. It contains all
diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am
index c0ebcb9..73bf00b 100644
--- a/src/bin/dhcp4/tests/Makefile.am
+++ b/src/bin/dhcp4/tests/Makefile.am
@@ -34,6 +34,10 @@ AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
if USE_STATIC_LINK
AM_LDFLAGS = -static
@@ -56,12 +60,6 @@ dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
dhcp4_unittests_SOURCES += config_parser_unittest.cc
nodist_dhcp4_unittests_SOURCES = ../dhcp4_messages.h ../dhcp4_messages.cc
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-dhcp4_unittests_CXXFLAGS = -Wno-unused-parameter
-endif
-
dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
dhcp4_unittests_LDADD = $(GTEST_LDADD)
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
index 99e4b17..c938155 100644
--- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -234,11 +234,13 @@ public:
/// Check that address was returned from proper range, that its lease
/// lifetime is correct, that T1 and T2 are returned properly
/// @param rsp response to be checked
- /// @param subnet subnet that should be used to verify assigned address and options
+ /// @param subnet subnet that should be used to verify assigned address
+ /// and options
/// @param t1_mandatory is T1 mandatory?
/// @param t2_mandatory is T2 mandatory?
void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
- bool t1_mandatory = false, bool t2_mandatory = false) {
+ bool t1_mandatory = false,
+ bool t2_mandatory = false) {
// Technically inPool implies inRange, but let's be on the safe
// side and check both.
@@ -268,7 +270,7 @@ public:
if (opt) {
EXPECT_EQ(opt->getUint32(), subnet->getT2());
} else {
- if (t1_mandatory) {
+ if (t2_mandatory) {
ADD_FAILURE() << "Required T2 option missing";
}
}
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index decd986..3b07510 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -6,6 +6,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
if USE_STATIC_LINK
AM_LDFLAGS = -static
@@ -53,12 +57,6 @@ b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h
nodist_b10_dhcp6_SOURCES = dhcp6_messages.h dhcp6_messages.cc
EXTRA_DIST += dhcp6_messages.mes
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
-endif
-
b10_dhcp6_LDADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index 665e684..76ed228 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -996,13 +996,13 @@ public:
return (new OptionDataListParser(param_name));
}
+ /// Pointer to options instances storage.
+ OptionStorage* options_;
/// Intermediate option storage. This storage is used by
/// lower level parsers to add new options. Values held
/// in this storage are assigned to main storage (options_)
/// if overall parsing was successful.
OptionStorage local_options_;
- /// Pointer to options instances storage.
- OptionStorage* options_;
/// Collection of parsers;
ParserCollection parsers_;
};
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 65ad74b..72dff4c 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -93,6 +93,11 @@ This message indicates that the server failed to grant (in response to
received REQUEST) a lease for a given client. There may be many reasons for
such failure. Each specific failure is logged in a separate log entry.
+% DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3
+This is a general catch-all message indicating that the processing of the
+specified packet type from the indicated address failed. The reason is given in the
+message. The server will not send a response but will instead ignore the packet.
+
% DHCP6_RELEASE address %1 belonging to client duid=%2, iaid=%3 was released properly.
This debug message indicates that an address was released properly. It
is a normal operation during client shutdown.
@@ -132,18 +137,6 @@ IPv6 DHCP server but it is not running.
During startup the IPv6 DHCP server failed to detect any network
interfaces and is therefore shutting down.
-% DHCP6_NO_SUBNET_DEF_OPT failed to find subnet for address %1 when adding default options
-This warning message indicates that when attempting to add default options
-to a response, the server found that it was not configured to support
-the subnet from which the DHCPv6 request was received. The packet has
-been ignored.
-
-% DHCP6_NO_SUBNET_REQ_OPT failed to find subnet for address %1 when adding requested options
-This warning message indicates that when attempting to add requested
-options to a response, the server found that it was not configured
-to support the subnet from which the DHCPv6 request was received.
-The packet has been ignored.
-
% DHCP6_OPEN_SOCKET opening sockets on port %1
A debug message issued during startup, this indicates that the IPv6 DHCP
server is about to open sockets on the specified port.
@@ -217,6 +210,16 @@ as a hint for possible requested address.
% DHCP6_QUERY_DATA received packet length %1, data length %2, data is %3
A debug message listing the data received from the client or relay.
+% DHCP6_RENEW_UNKNOWN_SUBNET RENEW message received from client on unknown subnet (duid=%1, iaid=%2)
+A warning message indicating that a client is attempting to renew his lease,
+but the server does not have any information about the subnet this client belongs
+to. This may mean that faulty the mobile client changed its location and is trying to
+renew its old address (client is supposed to send confirm, not rewew in such cases,
+according to RFC3315) or the server configuration has changed and information about
+existing subnet was removed. Note that in a sense this is worse case of DHCP6_UNKNOWN_RENEW,
+as not only the lease is unknown, but also the subnet is. Depending on the reasons
+of this condition, it may or may not correct on its own.
+
% DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3
This message indicates that received DHCPv6 packet is invalid. This may be due
to a number of reasons, e.g. the mandatory client-id option is missing,
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index f7f7ca7..5f1580f 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -56,6 +56,16 @@ using namespace std;
namespace isc {
namespace dhcp {
+/// @brief file name of a server-id file
+///
+/// Server must store its duid in persistent storage that must not change
+/// between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// double digit hex values separated by colons format, e.g.
+/// 01:ff:02:03:06:80:90:ab:cd:ef. Server will create it during first
+/// run and then use it afterwards.
+static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
+
Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
: alloc_engine_(), serverid_(), shutdown_(true) {
@@ -172,8 +182,8 @@ bool Dhcpv6Srv::run() {
break;
case DHCPV6_RELEASE:
- rsp = processRelease(query);
- break;
+ rsp = processRelease(query);
+ break;
case DHCPV6_DECLINE:
rsp = processDecline(query);
@@ -189,11 +199,26 @@ bool Dhcpv6Srv::run() {
// the "switch" statement.
;
}
+
} catch (const RFCViolation& e) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
.arg(query->getName())
.arg(query->getRemoteAddr())
.arg(e.what());
+
+ } catch (const isc::Exception& e) {
+
+ // Catch-all exception (at least for ones based on the isc
+ // Exception class, which covers more or less all that
+ // are explicitly raised in the BIND 10 code). Just log
+ // the problem and ignore the packet. (The problem is logged
+ // as a debug message because debug is disabled by default -
+ // it prevents a DDOS attack based on the sending of problem
+ // packets.)
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
+ .arg(query->getName())
+ .arg(query->getRemoteAddr())
+ .arg(e.what());
}
if (rsp) {
@@ -256,7 +281,8 @@ bool Dhcpv6Srv::loadServerID(const std::string& file_name) {
return (true);
}
-std::string Dhcpv6Srv::duidToString(const OptionPtr& opt) {
+std::string
+Dhcpv6Srv::duidToString(const OptionPtr& opt) {
stringstream tmp;
OptionBuffer data = opt->getData();
@@ -275,16 +301,19 @@ std::string Dhcpv6Srv::duidToString(const OptionPtr& opt) {
return tmp.str();
}
-bool Dhcpv6Srv::writeServerID(const std::string& file_name) {
+bool
+Dhcpv6Srv::writeServerID(const std::string& file_name) {
fstream f(file_name.c_str(), ios::out | ios::trunc);
if (!f.good()) {
return (false);
}
f << duidToString(getServerID());
f.close();
+ return (true);
}
-void Dhcpv6Srv::generateServerID() {
+void
+Dhcpv6Srv::generateServerID() {
/// @todo: This code implements support for DUID-LLT (the recommended one).
/// We should eventually add support for other DUID types: DUID-LL, DUID-EN
@@ -367,7 +396,8 @@ void Dhcpv6Srv::generateServerID() {
srvid.begin(), srvid.end()));
}
-void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// Add client-id.
OptionPtr clientid = question->getOption(D6O_CLIENTID);
if (clientid) {
@@ -377,28 +407,22 @@ void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
}
-void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr&, Pkt6Ptr& answer) {
// add server-id
answer->addOption(getServerID());
-
- // Get the subnet object. It holds options to be sent to the client
- // that belongs to the particular subnet.
- Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
- // Warn if subnet is not supported and quit.
- if (!subnet) {
- LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_DEF_OPT)
- .arg(question->getRemoteAddr().toText());
- return;
- }
-
}
-void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
- // Get the subnet for a particular address.
- Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+void
+Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+ // Get the configured subnet suitable for the incoming packet.
+ Subnet6Ptr subnet = selectSubnet(question);
+ // Leave if there is no subnet matching the incoming packet.
+ // There is no need to log the error message here because
+ // it will be logged in the assignLease() when it fails to
+ // pick the suitable subnet. We don't want to duplicate
+ // error messages in such case.
if (!subnet) {
- LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT)
- .arg(question->getRemoteAddr().toText());
return;
}
@@ -420,7 +444,8 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
}
}
-OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
+OptionPtr
+Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
// @todo This function uses OptionCustom class to manage contents
// of the data fields. Since this this option is frequently used
// it may be good to implement dedicated class to avoid performance
@@ -446,8 +471,9 @@ OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
return (option_status);
}
-void Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
- RequirementLevel serverid) {
+void
+Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
+ RequirementLevel serverid) {
Option::OptionCollection client_ids = pkt->getOptions(D6O_CLIENTID);
switch (clientid) {
case MANDATORY:
@@ -494,7 +520,8 @@ void Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
}
}
-Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
+Subnet6Ptr
+Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
/// @todo: pass interface information only if received direct (non-relayed) message
@@ -510,7 +537,8 @@ Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
return (subnet);
}
-void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+void
+Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// We need to allocate addresses for all IA_NA options in the client's
// question (i.e. SOLICIT or REQUEST) message.
@@ -528,9 +556,7 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// thing this client can get is some global information (like DNS
// servers).
- // perhaps this should be logged on some higher level? This is most likely
- // configuration bug.
- LOG_ERROR(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
+ LOG_WARN(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
.arg(question->getRemoteAddr().toText())
.arg(question->getName());
@@ -579,8 +605,9 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
}
-OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
- Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
// If there is no subnet selected for handling this IA_NA, the only thing to do left is
// to say that we are sorry, but the user won't get an address. As a convenience, we
// use a different status text to indicate that (compare to the same status code,
@@ -663,11 +690,10 @@ OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
// cause of that failure. The only thing left is to insert
// status code to pass the sad news to the client.
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation?
- DHCP6_LEASE_ADVERT_FAIL:DHCP6_LEASE_ALLOC_FAIL)
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation ?
+ DHCP6_LEASE_ADVERT_FAIL : DHCP6_LEASE_ALLOC_FAIL)
.arg(duid?duid->toText():"(no-duid)")
- .arg(ia->getIAID())
- .arg(subnet->toText());
+ .arg(ia->getIAID());
ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
"Sorry, no address could be allocated."));
@@ -675,8 +701,24 @@ OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
return (ia_rsp);
}
-OptionPtr Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
- Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia) {
+ if (!subnet) {
+ // There's no subnet select for this client. There's nothing to renew.
+ boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+ // Insert status code NoAddrsAvail.
+ ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
+ "Sorry, no known leases for this duid/iaid."));
+
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_RENEW_UNKNOWN_SUBNET)
+ .arg(duid->toText())
+ .arg(ia->getIAID());
+
+ return (ia_rsp);
+ }
+
Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(*duid, ia->getIAID(),
subnet->getID());
@@ -719,7 +761,8 @@ OptionPtr Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
return (ia_rsp);
}
-void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
+void
+Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
// We need to renew addresses for all IA_NA options in the client's
// RENEW message.
@@ -737,9 +780,9 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
// thing this client can get is some global information (like DNS
// servers).
- // perhaps this should be logged on some higher level? This is most likely
- // configuration bug.
- LOG_ERROR(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED);
+ LOG_WARN(dhcp6_logger, DHCP6_SUBNET_SELECTION_FAILED)
+ .arg(renew->getRemoteAddr().toText())
+ .arg(renew->getName());
} else {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_SUBNET_SELECTED)
.arg(subnet->toText());
@@ -775,7 +818,8 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
}
}
-void Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
+void
+Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
// We need to release addresses for all IA_NA options in the client's
// RELEASE message.
@@ -831,9 +875,9 @@ void Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
"Summary status for all processed IA_NAs"));
}
-OptionPtr Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
- int& general_status,
- boost::shared_ptr<Option6IA> ia) {
+OptionPtr
+Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
+ int& general_status, boost::shared_ptr<Option6IA> ia) {
// Release can be done in one of two ways:
// Approach 1: extract address from client's IA_NA and see if it belongs
// to this particular client.
@@ -942,8 +986,8 @@ OptionPtr Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
}
}
-
-Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
+Pkt6Ptr
+Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
sanityCheck(solicit, MANDATORY, FORBIDDEN);
@@ -958,7 +1002,8 @@ Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
return (advertise);
}
-Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
+Pkt6Ptr
+Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
sanityCheck(request, MANDATORY, MANDATORY);
@@ -973,7 +1018,8 @@ Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
return (reply);
}
-Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+Pkt6Ptr
+Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
sanityCheck(renew, MANDATORY, MANDATORY);
@@ -988,19 +1034,22 @@ Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
return reply;
}
-Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+Pkt6Ptr
+Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
/// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
return reply;
}
-Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
+Pkt6Ptr
+Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
/// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
return reply;
}
-Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+Pkt6Ptr
+Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
sanityCheck(release, MANDATORY, MANDATORY);
@@ -1014,13 +1063,15 @@ Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
return reply;
}
-Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+Pkt6Ptr
+Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
/// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
return reply;
}
-Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
+Pkt6Ptr
+Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
/// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
return reply;
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 7c6f77b..bdcb560 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -31,16 +31,6 @@
namespace isc {
namespace dhcp {
-/// @brief file name of a server-id file
-///
-/// Server must store its duid in persistent storage that must not change
-/// between restarts. This is name of the file that is created in dataDir
-/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
-/// double digit hex values separated by colons format, e.g.
-/// 01:ff:02:03:06:80:90:ab:cd:ef. Server will create it during first
-/// run and then use it afterwards.
-static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
-
/// @brief DHCPv6 server service.
///
/// This class represents DHCPv6 server. It contains all
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index d251df3..feb4bfa 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -30,6 +30,10 @@ AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
AM_CXXFLAGS = $(B10_CXXFLAGS)
+if USE_CLANGPP
+# Disable unused parameter warning caused by some Boost headers when compiling with clang
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
if USE_STATIC_LINK
AM_LDFLAGS = -static
@@ -53,12 +57,6 @@ dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc
dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc
-if USE_CLANGPP
-# Disable unused parameter warning caused by some of the
-# Boost headers when compiling with clang.
-dhcp6_unittests_CXXFLAGS = -Wno-unused-parameter
-endif
-
dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
dhcp6_unittests_LDADD = $(GTEST_LDADD)
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index 158ad62..4430cb2 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -277,9 +277,9 @@ public:
expected_data_len));
}
+ int rcode_;
Dhcpv6Srv srv_;
- int rcode_;
ConstElementPtr comment_;
string valid_iface_;
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index ef443e7..b742a13 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -222,7 +222,8 @@ public:
// Check that generated IAADDR option contains expected address.
void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
const IOAddress& expected_addr,
- uint32_t expected_preferred, uint32_t expected_valid) {
+ uint32_t /* expected_preferred */,
+ uint32_t /* expected_valid */) {
// Check that the assigned address is indeed from the configured pool.
// Note that when comparing addresses, we compare the textual
diff --git a/src/bin/loadzone/loadzone.py.in b/src/bin/loadzone/loadzone.py.in
index 949446b..736aa31 100755
--- a/src/bin/loadzone/loadzone.py.in
+++ b/src/bin/loadzone/loadzone.py.in
@@ -164,7 +164,7 @@ class LoadZoneRunner:
self._zone_class = RRClass(options.zone_class)
except isc.dns.InvalidRRClass as ex:
raise BadArgument('Invalid zone class: ' + str(ex))
- if self._zone_class != RRClass.IN():
+ if self._zone_class != RRClass.IN:
raise BadArgument("RR class is not supported: " +
str(self._zone_class))
diff --git a/src/bin/loadzone/tests/loadzone_test.py b/src/bin/loadzone/tests/loadzone_test.py
index fee8c2a..351bc59 100755
--- a/src/bin/loadzone/tests/loadzone_test.py
+++ b/src/bin/loadzone/tests/loadzone_test.py
@@ -79,7 +79,7 @@ class TestLoadZoneRunner(unittest.TestCase):
self.assertEqual(DATASRC_CONFIG, self.__runner._datasrc_config)
self.assertEqual('sqlite3', self.__runner._datasrc_type) # default
self.assertEqual(10000, self.__runner._report_interval) # default
- self.assertEqual(RRClass.IN(), self.__runner._zone_class) # default
+ self.assertEqual(RRClass.IN, self.__runner._zone_class) # default
self.assertEqual('INFO', self.__runner._log_severity) # default
self.assertEqual(0, self.__runner._log_debuglevel)
@@ -135,7 +135,7 @@ class TestLoadZoneRunner(unittest.TestCase):
'memory')
def __common_load_setup(self):
- self.__runner._zone_class = RRClass.IN()
+ self.__runner._zone_class = RRClass.IN
self.__runner._zone_name = TEST_ZONE_NAME
self.__runner._zone_file = NEW_ZONE_TXT_FILE
self.__runner._datasrc_type = 'sqlite3'
@@ -159,7 +159,7 @@ class TestLoadZoneRunner(unittest.TestCase):
self.assertEqual(client.NOTFOUND, result)
return
self.assertEqual(client.SUCCESS, result)
- result, rrset, _ = finder.find(zone_name, RRType.SOA())
+ result, rrset, _ = finder.find(zone_name, RRType.SOA)
if soa_txt:
self.assertEqual(finder.SUCCESS, result)
self.assertEqual(soa_txt, rrset.to_text())
diff --git a/src/bin/msgq/msgq.py.in b/src/bin/msgq/msgq.py.in
index 28052d6..ca5d705 100755
--- a/src/bin/msgq/msgq.py.in
+++ b/src/bin/msgq/msgq.py.in
@@ -411,7 +411,7 @@ class MsgQ:
if isinstance(err, MsgQCloseOnReceive) and not err.partial_read:
logger.debug(TRACE_BASIC, MSGQ_CLOSE_ON_RECV, fd)
else:
- logger.error(MSGQ_RECV_ERR, fd, err)
+ logger.error(MSGQ_RECV_ERROR, fd, err)
self.kill_socket(fd, sock)
return
@@ -419,7 +419,7 @@ class MsgQ:
routingmsg = isc.cc.message.from_wire(routing)
except DecodeError as err:
self.kill_socket(fd, sock)
- logger.error(MSGQ_HDR_DECODE_ERR, fd, err)
+ logger.error(MSGQ_HDR_DECODE_ERROR, fd, err)
return
self.process_command(fd, sock, routingmsg, data)
@@ -492,7 +492,7 @@ class MsgQ:
if e.errno == errno.EPIPE:
logger.warn(MSGQ_CLOSE_ON_SEND, sock.fileno())
else:
- logger.error(MSGQ_SEND_ERR, sock.fileno(),
+ logger.error(MSGQ_SEND_ERROR, sock.fileno(),
errno.errorcode[e.errno])
self.kill_socket(sock.fileno(), sock)
return None
@@ -620,7 +620,7 @@ class MsgQ:
if err.args[0] == errno.EINTR:
events = []
else:
- logger.fatal(MSGQ_POLL_ERR, err)
+ logger.fatal(MSGQ_POLL_ERROR, err)
break
with self.__lock:
for (fd, event) in events:
diff --git a/src/bin/msgq/msgq_messages.mes b/src/bin/msgq/msgq_messages.mes
index 7fb962d..09c9030 100644
--- a/src/bin/msgq/msgq_messages.mes
+++ b/src/bin/msgq/msgq_messages.mes
@@ -62,7 +62,7 @@ Debug message. The message queue received a configuration update, handling it.
% MSGQ_EXITING exiting
The msgq daemon is exiting.
-% MSGQ_HDR_DECODE_ERR Error decoding header received from socket %1: %2
+% MSGQ_HDR_DECODE_ERROR Error decoding header received from socket %1: %2
The socket with mentioned file descriptor sent a packet. However, it was not
possible to decode the routing header of the packet. The packet is ignored.
This may be caused by a programmer error (one of the components sending invalid
@@ -85,7 +85,7 @@ Debug message. The listener is trying to open a listening socket.
Debug message. The message queue successfully opened a listening socket and
waits for incoming connections.
-% MSGQ_POLL_ERR Error while polling for events: %1
+% MSGQ_POLL_ERROR Error while polling for events: %1
A low-level error happened when waiting for events, the error is logged. The
reason for this varies, but it usually means the system is short on some
resources.
@@ -96,7 +96,7 @@ happen and it is either a programmer error or OS bug. The event is ignored. The
number noted as the event is the raw encoded value, which might be useful to
the authors when figuring the problem out.
-% MSGQ_RECV_ERR Error reading from socket %1: %2
+% MSGQ_RECV_ERROR Error reading from socket %1: %2
There was a low-level error when reading from a socket. The error is logged and
the corresponding socket is dropped. The errors include receiving
broken or (non empty but) incomplete data. In either case it usually suggests
@@ -119,7 +119,7 @@ on shutdown unless there's really something unexpected.
% MSGQ_RECV_HDR Received header: %1
Debug message. This message includes the whole routing header of a packet.
-% MSGQ_SEND_ERR Error while sending to socket %1: %2
+% MSGQ_SEND_ERROR Error while sending to socket %1: %2
There was a low-level error when sending data to a socket. The error is logged
and the corresponding socket is dropped.
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 9536608..a3de340 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -431,13 +431,14 @@ Resolver::processMessage(const IOMessage& io_message,
// Ignore all responses.
if (query_message->getHeaderFlag(Message::HEADERFLAG_QR)) {
- LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_UNEXPECTED_RESPONSE);
+ LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+ RESOLVER_UNEXPECTED_RESPONSE);
server->resume(false);
return;
}
} catch (const Exception& ex) {
- LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_HEADER_ERROR)
- .arg(ex.what());
+ LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+ RESOLVER_HEADER_PROCESSING_FAILED).arg(ex.what());
server->resume(false);
return;
}
@@ -446,14 +447,16 @@ Resolver::processMessage(const IOMessage& io_message,
try {
query_message->fromWire(request_buffer);
} catch (const DNSProtocolError& error) {
- LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_PROTOCOL_ERROR)
+ LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+ RESOLVER_PROTOCOL_BODY_PARSE_FAILED)
.arg(error.what()).arg(error.getRcode());
makeErrorMessage(query_message, answer_message,
buffer, error.getRcode());
server->resume(true);
return;
} catch (const Exception& ex) {
- LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_MESSAGE_ERROR)
+ LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO,
+ RESOLVER_MESSAGE_PROCESSING_FAILED)
.arg(ex.what()).arg(Rcode::SERVFAIL());
makeErrorMessage(query_message, answer_message,
buffer, Rcode::SERVFAIL());
diff --git a/src/bin/resolver/resolver_messages.mes b/src/bin/resolver/resolver_messages.mes
index 214519b..c722af1 100644
--- a/src/bin/resolver/resolver_messages.mes
+++ b/src/bin/resolver/resolver_messages.mes
@@ -81,7 +81,7 @@ has passed a set of checks (message is well-formed, it is allowed by the
ACL, it is a supported opcode, etc.) and is being forwarded to upstream
servers.
-% RESOLVER_HEADER_ERROR message received, exception when processing header: %1
+% RESOLVER_HEADER_PROCESSING_FAILED message received, exception when processing header: %1
This is a debug message from the resolver noting that an exception
occurred during the processing of a received packet. The packet has
been dropped.
@@ -97,7 +97,7 @@ During the update of the resolver's configuration parameters, the value
of the lookup timeout was found to be too small. The configuration
update will not be applied.
-% RESOLVER_MESSAGE_ERROR error parsing received message: %1 - returning %2
+% RESOLVER_MESSAGE_PROCESSING_FAILED error parsing received message: %1 - returning %2
This is a debug message noting that parsing of the body of a received
message by the resolver failed due to some error (although the parsing of
the header succeeded). The message parameters give a textual description
@@ -135,18 +135,11 @@ A warning message issued during resolver startup, this indicates that
no root addresses have been set. This may be because the resolver will
get them from a priming query.
-% RESOLVER_PARSE_ERROR error parsing received message: %1 - returning %2
-This is a debug message noting that the resolver received a message and
-the parsing of the body of the message failed due to some non-protocol
-related reason (although the parsing of the header succeeded).
-The message parameters give a textual description of the problem and
-the RCODE returned.
-
% RESOLVER_PRINT_COMMAND print message command, arguments are: %1
This debug message is logged when a "print_message" command is received
by the resolver over the command channel.
-% RESOLVER_PROTOCOL_ERROR protocol error parsing received message: %1 - returning %2
+% RESOLVER_PROTOCOL_BODY_PARSE_FAILED protocol error parsing received message: %1 - returning %2
This is a debug message noting that the resolver received a message and
the parsing of the body of the message failed due to some protocol error
(although the parsing of the header succeeded). The message parameters
diff --git a/src/bin/sockcreator/tests/sockcreator_tests.cc b/src/bin/sockcreator/tests/sockcreator_tests.cc
index 9604567..b834e1c 100644
--- a/src/bin/sockcreator/tests/sockcreator_tests.cc
+++ b/src/bin/sockcreator/tests/sockcreator_tests.cc
@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <config.h>
+
#include "../sockcreator.h"
#include <util/unittests/fork.h>
@@ -195,7 +197,12 @@ TEST(get_sock, tcp4_create) {
testAnyCreate<sockaddr_in>(SOCK_STREAM, tcpCheck);
}
-TEST(get_sock, udp6_create) {
+#ifdef HAVE_BROKEN_GET_IPV6_USE_MIN_MTU
+TEST(get_sock, DISABLED_udp6_create)
+#else
+TEST(get_sock, udp6_create)
+#endif
+{
testAnyCreate<sockaddr_in6>(SOCK_DGRAM, udpCheck<sockaddr_in6>);
}
diff --git a/src/bin/stats/stats.py.in b/src/bin/stats/stats.py.in
index 17d2f74..0af0933 100755
--- a/src/bin/stats/stats.py.in
+++ b/src/bin/stats/stats.py.in
@@ -26,7 +26,8 @@ from optparse import OptionParser, OptionValueError
import errno
import select
-import isc
+import isc.cc
+import isc.config
import isc.util.process
import isc.log
from isc.log_messages.stats_messages import *
diff --git a/src/bin/stats/stats_httpd.py.in b/src/bin/stats/stats_httpd.py.in
index 659f8f4..367f56e 100755
--- a/src/bin/stats/stats_httpd.py.in
+++ b/src/bin/stats/stats_httpd.py.in
@@ -130,9 +130,9 @@ def item_name_list(element, identifier):
return ret
class HttpHandler(http.server.BaseHTTPRequestHandler):
- """HTTP handler class for HttpServer class. The class inhrits the super
- class http.server.BaseHTTPRequestHandler. It implemets do_GET()
- and do_HEAD() and orverrides log_message()"""
+ """HTTP handler class for HttpServer class. The class inherits the super
+ class http.server.BaseHTTPRequestHandler. It implements do_GET()
+ and do_HEAD() and overrides log_message()"""
def do_GET(self):
body = self.send_head()
if body is not None:
@@ -413,7 +413,7 @@ class StatsHttpd:
try:
self.open_httpd()
except HttpServerError as err:
- logger.error(STATSHTTPD_SERVER_ERROR, err)
+ logger.error(STATSHTTPD_SERVER_INIT_ERROR, err)
# restore old config
self.load_config(old_config)
self.open_httpd()
diff --git a/src/bin/stats/stats_httpd_messages.mes b/src/bin/stats/stats_httpd_messages.mes
index 511289f..93491b6 100644
--- a/src/bin/stats/stats_httpd_messages.mes
+++ b/src/bin/stats/stats_httpd_messages.mes
@@ -68,7 +68,7 @@ corresponding to the requested URI is incorrect.
An internal error occurred while handling an HTTP request. An HTTP 500
response will be sent back, and the specific error is printed. This
is an error condition that likely points to a module that is not
-responding correctly to statistic requests.
+responding correctly to statistics requests.
% STATSHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1
There was a problem initializing the HTTP server in the stats-httpd
diff --git a/src/bin/stats/tests/b10-stats-httpd_test.py b/src/bin/stats/tests/b10-stats-httpd_test.py
index 98689c8..961986e 100644
--- a/src/bin/stats/tests/b10-stats-httpd_test.py
+++ b/src/bin/stats/tests/b10-stats-httpd_test.py
@@ -34,6 +34,7 @@ import http.client
import xml.etree.ElementTree
import random
import urllib.parse
+import sys
# load this module for xml validation with xsd. For this test, an
# installation of lxml is required in advance. See http://lxml.de/.
try:
@@ -250,6 +251,7 @@ class TestHttpHandler(unittest.TestCase):
# reset the signal handler
self.sig_handler.reset()
+ @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
@unittest.skipUnless(xml_parser, "skipping the test using XMLParser")
def test_do_GET(self):
self.assertTrue(type(self.stats_httpd.httpd) is list)
diff --git a/src/bin/stats/tests/b10-stats_test.py b/src/bin/stats/tests/b10-stats_test.py
index 80bd3a6..b76e4d2 100644
--- a/src/bin/stats/tests/b10-stats_test.py
+++ b/src/bin/stats/tests/b10-stats_test.py
@@ -27,6 +27,7 @@ import threading
import io
import time
import imp
+import sys
import stats
import isc.log
@@ -605,6 +606,7 @@ class TestStats(unittest.TestCase):
self.assertEqual(self.stats.update_statistics_data(
'Foo', 'foo1', _test_exp6), ['unknown module name: Foo'])
+ @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
def test_update_statistics_data_withmid(self):
self.stats = stats.Stats()
self.stats.do_polling()
@@ -736,6 +738,7 @@ class TestStats(unittest.TestCase):
isc.config.create_answer(0))
self.assertFalse(self.stats.running)
+ @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
def test_command_show(self):
# two auth instances invoked
list_auth = [ self.base.auth.server,
@@ -1143,6 +1146,7 @@ class TestStats(unittest.TestCase):
isc.config.create_answer(
1, "module name is not specified"))
+ @unittest.skipIf(sys.version_info >= (3, 3), "Unsupported in Python 3.3 or higher")
def test_polling(self):
stats_server = ThreadingServerManager(MyStats)
stat = stats_server.server
diff --git a/src/bin/sysinfo/run_sysinfo.sh.in b/src/bin/sysinfo/run_sysinfo.sh.in
index 6459c2d..b5593b9 100755
--- a/src/bin/sysinfo/run_sysinfo.sh.in
+++ b/src/bin/sysinfo/run_sysinfo.sh.in
@@ -20,20 +20,8 @@ export PYTHON_EXEC
SYSINFO_PATH=@abs_top_builddir@/src/bin/sysinfo
-# Note: we shouldn't need log_messages and lib/dns except for the seemingly
-# necessary dependency due to the automatic import in the isc package (its
-# __init__.py imports some other modules)
-# #2145 should eliminate the need for them.
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/dns/python/.libs
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python
export PYTHONPATH
-# Likewise, we need only because isc.log requires some loadable modules.
-# sysinfo itself shouldn't need any of them.
-SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
-if test $SET_ENV_LIBRARY_PATH = yes; then
- @ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/cryptolink/.libs:@abs_top_builddir@/src/lib/cc/.libs:@abs_top_builddir@/src/lib/config/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/acl/.libs:@abs_top_builddir@/src/lib/util/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:@abs_top_builddir@/src/lib/datasrc/.libs:$@ENV_LIBRARY_PATH@
- export @ENV_LIBRARY_PATH@
-fi
-
cd ${SYSINFO_PATH}
exec ${PYTHON_EXEC} -O sysinfo.py "$@"
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index 899747f..a1714de 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -40,7 +40,7 @@ import sqlite3
#
TEST_ZONE_NAME_STR = "example.com."
TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
TEST_RRCLASS_STR = 'IN'
TEST_DB_FILE = 'db_file'
TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
@@ -59,21 +59,21 @@ TEST_MASTER_PORT = '53535'
TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
# SOA intended to be used for the new SOA as a result of transfer.
-soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
'master.example.com. admin.example.com. ' +
'1234 3600 1800 2419200 7200')
-soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
+soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA, RRTTL(3600))
soa_rrset.add_rdata(soa_rdata)
# SOA intended to be used for the current SOA at the secondary side.
# Note that its serial is smaller than that of soa_rdata.
-begin_soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+begin_soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
'master.example.com. admin.example.com. ' +
'1230 3600 1800 2419200 7200')
-begin_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
+begin_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA, RRTTL(3600))
begin_soa_rrset.add_rdata(begin_soa_rdata)
-example_axfr_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR())
-example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA())
+example_axfr_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)
+example_soa_question = Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA)
default_questions = [example_axfr_question]
default_answers = [soa_rrset]
@@ -208,12 +208,12 @@ class MockDataSourceClient():
zone names.
'''
- if name == TEST_ZONE_NAME and rrtype == RRType.SOA():
+ if name == TEST_ZONE_NAME and rrtype == RRType.SOA:
return (ZoneFinder.SUCCESS, begin_soa_rrset, 0)
if name == Name('no-soa.example'):
return (ZoneFinder.NXDOMAIN, None, 0)
if name == Name('dup-soa.example'):
- dup_soa_rrset = RRset(name, TEST_RRCLASS, RRType.SOA(), RRTTL(0))
+ dup_soa_rrset = RRset(name, TEST_RRCLASS, RRType.SOA, RRTTL(0))
dup_soa_rrset.add_rdata(begin_soa_rdata)
dup_soa_rrset.add_rdata(soa_rdata)
return (ZoneFinder.SUCCESS, dup_soa_rrset, 0)
@@ -329,7 +329,7 @@ class MockXfrinConnection(XfrinConnection):
return len(data)
def create_response_data(self, response=True, auth=True, bad_qid=False,
- rcode=Rcode.NOERROR(),
+ rcode=Rcode.NOERROR,
questions=default_questions,
answers=default_answers,
authorities=[],
@@ -339,7 +339,7 @@ class MockXfrinConnection(XfrinConnection):
if bad_qid:
qid += 1
resp.set_qid(qid)
- resp.set_opcode(Opcode.QUERY())
+ resp.set_opcode(Opcode.QUERY)
resp.set_rcode(rcode)
if response:
resp.set_header_flag(Message.HEADERFLAG_QR)
@@ -366,17 +366,17 @@ class TestXfrinState(unittest.TestCase):
TEST_RRCLASS, None, threading.Event(),
TEST_MASTER_IPV4_ADDRINFO)
self.conn.init_socket()
- self.begin_soa = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+ self.begin_soa = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
RRTTL(3600))
- self.begin_soa.add_rdata(Rdata(RRType.SOA(), TEST_RRCLASS,
+ self.begin_soa.add_rdata(Rdata(RRType.SOA, TEST_RRCLASS,
'm. r. 1230 0 0 0 0'))
- self.ns_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(),
+ self.ns_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS,
RRTTL(3600))
- self.ns_rrset.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS,
+ self.ns_rrset.add_rdata(Rdata(RRType.NS, TEST_RRCLASS,
'ns.example.com.'))
- self.a_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.A(),
+ self.a_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.A,
RRTTL(3600))
- self.a_rrset.add_rdata(Rdata(RRType.A(), TEST_RRCLASS, '192.0.2.1'))
+ self.a_rrset.add_rdata(Rdata(RRType.A, TEST_RRCLASS, '192.0.2.1'))
self.conn._datasrc_client = MockDataSourceClient()
self.conn._diff = Diff(self.conn._datasrc_client, TEST_ZONE_NAME)
@@ -408,14 +408,14 @@ class TestXfrinInitialSOA(TestXfrinState):
self.ns_rrset)
def test_handle_ixfr_uptodate(self):
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
self.conn._request_serial = isc.dns.Serial(1234) # same as soa_rrset
self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
self.assertEqual(type(XfrinIXFRUptodate()),
type(self.conn.get_xfrstate()))
def test_handle_ixfr_uptodate2(self):
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
self.conn._request_serial = isc.dns.Serial(1235) # > soa_rrset
self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
self.assertEqual(type(XfrinIXFRUptodate()),
@@ -424,7 +424,7 @@ class TestXfrinInitialSOA(TestXfrinState):
def test_handle_ixfr_uptodate3(self):
# Similar to the previous case, but checking serial number arithmetic
# comparison
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
self.conn._request_serial = isc.dns.Serial(0xffffffff)
self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
self.assertEqual(type(XfrinFirstData()),
@@ -432,7 +432,7 @@ class TestXfrinInitialSOA(TestXfrinState):
def test_handle_axfr_uptodate(self):
# "request serial" should matter only for IXFR
- self.conn._request_type = RRType.AXFR()
+ self.conn._request_type = RRType.AXFR
self.conn._request_serial = isc.dns.Serial(1234) # same as soa_rrset
self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
self.assertEqual(type(XfrinFirstData()),
@@ -445,13 +445,13 @@ class TestXfrinFirstData(TestXfrinState):
def setUp(self):
super().setUp()
self.state = XfrinFirstData()
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
# arbitrary chosen serial < 1234:
self.conn._request_serial = isc.dns.Serial(1230)
self.conn._diff = None # should be replaced in the AXFR case
def test_handle_ixfr_begin_soa(self):
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
self.assertFalse(self.state.handle_rr(self.conn, self.begin_soa))
self.assertEqual(type(XfrinIXFRDeleteSOA()),
type(self.conn.get_xfrstate()))
@@ -459,7 +459,7 @@ class TestXfrinFirstData(TestXfrinState):
def test_handle_axfr(self):
# If the original type is AXFR, other conditions aren't considered,
# and AXFR processing will continue
- self.conn._request_type = RRType.AXFR()
+ self.conn._request_type = RRType.AXFR
self.assertFalse(self.state.handle_rr(self.conn, self.begin_soa))
self.assertEqual(type(XfrinAXFR()), type(self.conn.get_xfrstate()))
@@ -598,9 +598,9 @@ class TestXfrinIXFRAdd(TestXfrinState):
# First, push a starting SOA inside. This should be OK, nothing checked
# yet.
self.state.handle_rr(self.conn, self.begin_soa)
- end_soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+ end_soa_rdata = Rdata(RRType.SOA, TEST_RRCLASS,
'm. r. 1234 0 0 0 0')
- end_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+ end_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
RRTTL(3600))
end_soa_rrset.add_rdata(end_soa_rdata)
# This would try to finish up. But the TSIG pretends not everything is
@@ -724,7 +724,7 @@ class TestXfrinConnection(unittest.TestCase):
'bad_qid': False,
'response': True,
'auth': True,
- 'rcode': Rcode.NOERROR(),
+ 'rcode': Rcode.NOERROR,
'answers': default_answers,
'authorities': [],
'tsig': False,
@@ -817,21 +817,21 @@ class TestXfrinConnection(unittest.TestCase):
self.conn.reply_data += bogus_data
def _create_a(self, address):
- rrset = RRset(Name('a.example.com'), TEST_RRCLASS, RRType.A(),
+ rrset = RRset(Name('a.example.com'), TEST_RRCLASS, RRType.A,
RRTTL(3600))
- rrset.add_rdata(Rdata(RRType.A(), TEST_RRCLASS, address))
+ rrset.add_rdata(Rdata(RRType.A, TEST_RRCLASS, address))
return rrset
def _create_soa(self, serial):
- rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(),
+ rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA,
RRTTL(3600))
rdata_str = 'm. r. ' + serial + ' 3600 1800 2419200 7200'
- rrset.add_rdata(Rdata(RRType.SOA(), TEST_RRCLASS, rdata_str))
+ rrset.add_rdata(Rdata(RRType.SOA, TEST_RRCLASS, rdata_str))
return rrset
def _create_ns(self, nsname='ns.'+TEST_ZONE_NAME_STR):
- rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS(), RRTTL(3600))
- rrset.add_rdata(Rdata(RRType.NS(), TEST_RRCLASS, nsname))
+ rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.NS, RRTTL(3600))
+ rrset.add_rdata(Rdata(RRType.NS, TEST_RRCLASS, nsname))
return rrset
def _set_test_zone(self, zone_name):
@@ -899,19 +899,19 @@ class TestAXFR(TestXfrinConnection):
c.close()
def test_init_chclass(self):
- c = MockXfrinConnection({}, TEST_ZONE_NAME, RRClass.CH(), None,
+ c = MockXfrinConnection({}, TEST_ZONE_NAME, RRClass.CH, None,
threading.Event(), TEST_MASTER_IPV4_ADDRINFO)
c.init_socket()
- axfrmsg = c._create_query(RRType.AXFR())
+ axfrmsg = c._create_query(RRType.AXFR)
self.assertEqual(axfrmsg.get_question()[0].get_class(),
- RRClass.CH())
+ RRClass.CH)
c.close()
def test_create_query(self):
def check_query(expected_qtype, expected_auth):
'''Helper method to repeat the same pattern of tests'''
- self.assertEqual(Opcode.QUERY(), msg.get_opcode())
- self.assertEqual(Rcode.NOERROR(), msg.get_rcode())
+ self.assertEqual(Opcode.QUERY, msg.get_opcode())
+ self.assertEqual(Rcode.NOERROR, msg.get_rcode())
self.assertEqual(1, msg.get_rr_count(Message.SECTION_QUESTION))
self.assertEqual(TEST_ZONE_NAME, msg.get_question()[0].get_name())
self.assertEqual(expected_qtype, msg.get_question()[0].get_type())
@@ -936,16 +936,16 @@ class TestAXFR(TestXfrinConnection):
# Actual tests start here
# SOA query
- msg = self.conn._create_query(RRType.SOA())
- check_query(RRType.SOA(), None)
+ msg = self.conn._create_query(RRType.SOA)
+ check_query(RRType.SOA, None)
# AXFR query
- msg = self.conn._create_query(RRType.AXFR())
- check_query(RRType.AXFR(), None)
+ msg = self.conn._create_query(RRType.AXFR)
+ check_query(RRType.AXFR, None)
# IXFR query
- msg = self.conn._create_query(RRType.IXFR())
- check_query(RRType.IXFR(), begin_soa_rrset)
+ msg = self.conn._create_query(RRType.IXFR)
+ check_query(RRType.IXFR, begin_soa_rrset)
self.assertEqual(1230, self.conn._request_serial.get_value())
def test_create_ixfr_query_fail(self):
@@ -954,20 +954,20 @@ class TestAXFR(TestXfrinConnection):
self._set_test_zone(Name('no-such-zone.example'))
self.assertRaises(XfrinException, self.conn._create_query,
- RRType.IXFR())
+ RRType.IXFR)
self._set_test_zone(Name('partial-match-zone.example'))
self.assertRaises(XfrinException, self.conn._create_query,
- RRType.IXFR())
+ RRType.IXFR)
self._set_test_zone(Name('no-soa.example'))
self.assertRaises(XfrinException, self.conn._create_query,
- RRType.IXFR())
+ RRType.IXFR)
self._set_test_zone(Name('dup-soa.example'))
self.conn._zone_soa = self.conn._get_zone_soa()
self.assertRaises(XfrinException, self.conn._create_query,
- RRType.IXFR())
+ RRType.IXFR)
def test_send_query(self):
def message_has_tsig(data):
@@ -980,11 +980,11 @@ class TestAXFR(TestXfrinConnection):
# soa request with tsig
self.conn._tsig_key = TSIG_KEY
- self.conn._send_query(RRType.SOA())
+ self.conn._send_query(RRType.SOA)
self.assertTrue(message_has_tsig(self.conn.query_data[2:]))
# axfr request with tsig
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.assertTrue(message_has_tsig(self.conn.query_data[2:]))
def test_response_with_invalid_msg(self):
@@ -995,14 +995,14 @@ class TestAXFR(TestXfrinConnection):
def test_response_with_tsigfail(self):
self.conn._tsig_key = TSIG_KEY
# server tsig check fail, return with RCODE 9 (NOTAUTH)
- self.conn._send_query(RRType.SOA())
+ self.conn._send_query(RRType.SOA)
self.conn.reply_data = \
- self.conn.create_response_data(rcode=Rcode.NOTAUTH())
+ self.conn.create_response_data(rcode=Rcode.NOTAUTH)
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
def test_response_without_end_soa(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data()
# This should result in timeout in the asyncore loop. We emulate
# that situation in recv() by emptying the reply data buffer.
@@ -1010,7 +1010,7 @@ class TestAXFR(TestXfrinConnection):
self.conn._handle_xfrin_responses)
def test_response_bad_qid(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(bad_qid=True)
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
@@ -1019,9 +1019,9 @@ class TestAXFR(TestXfrinConnection):
self.conn._tsig_key = TSIG_KEY
self.conn._tsig_ctx_creator = \
lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
- rcode=Rcode.SERVFAIL())
+ rcode=Rcode.SERVFAIL)
# xfrin should check TSIG before other part of incoming message
# validate log message for XfrinException
self.__match_exception(XfrinProtocolError,
@@ -1032,7 +1032,7 @@ class TestAXFR(TestXfrinConnection):
self.conn._tsig_key = TSIG_KEY
self.conn._tsig_ctx_creator = \
lambda key: self.__create_mock_tsig(key, TSIGError.BAD_KEY)
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(bad_qid=True)
# xfrin should check TSIG before other part of incoming message
# validate log message for XfrinException
@@ -1041,26 +1041,26 @@ class TestAXFR(TestXfrinConnection):
self.conn._handle_xfrin_responses)
def test_response_non_response(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(response=False)
self.assertRaises(XfrinException, self.conn._handle_xfrin_responses)
def test_response_error_code(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
- rcode=Rcode.SERVFAIL())
+ rcode=Rcode.SERVFAIL)
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
def test_response_multi_question(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
questions=[example_axfr_question, example_axfr_question])
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
def test_response_non_response(self):
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(response = False)
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
@@ -1098,7 +1098,7 @@ class TestAXFR(TestXfrinConnection):
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
def test_soacheck_error_code(self):
- self.soa_response_params['rcode'] = Rcode.SERVFAIL()
+ self.soa_response_params['rcode'] = Rcode.SERVFAIL
self.conn.response_generator = self._create_soa_response_data
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
@@ -1146,21 +1146,21 @@ class TestAXFR(TestXfrinConnection):
self.conn.response_generator = self._create_soa_response_data
self.soa_response_params['questions'] = [Question(Name('example.org'),
TEST_RRCLASS,
- RRType.SOA())]
+ RRType.SOA)]
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
def test_soacheck_question_class_mismatch(self):
self.conn.response_generator = self._create_soa_response_data
self.soa_response_params['questions'] = [Question(TEST_ZONE_NAME,
- RRClass.CH(),
- RRType.SOA())]
+ RRClass.CH,
+ RRType.SOA)]
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
def test_soacheck_question_type_mismatch(self):
self.conn.response_generator = self._create_soa_response_data
self.soa_response_params['questions'] = [Question(TEST_ZONE_NAME,
TEST_RRCLASS,
- RRType.AAAA())]
+ RRType.AAAA)]
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
def test_soacheck_no_soa(self):
@@ -1178,8 +1178,8 @@ class TestAXFR(TestXfrinConnection):
def test_soacheck_soa_class_mismatch(self):
self.conn.response_generator = self._create_soa_response_data
- soa = RRset(TEST_ZONE_NAME, RRClass.CH(), RRType.SOA(), RRTTL(0))
- soa.add_rdata(Rdata(RRType.SOA(), RRClass.CH(), 'm. r. 1234 0 0 0 0'))
+ soa = RRset(TEST_ZONE_NAME, RRClass.CH, RRType.SOA, RRTTL(0))
+ soa.add_rdata(Rdata(RRType.SOA, RRClass.CH, 'm. r. 1234 0 0 0 0'))
self.soa_response_params['answers'] = [soa]
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
@@ -1220,7 +1220,7 @@ class TestAXFR(TestXfrinConnection):
self.conn._tsig_key = TSIG_KEY
self.conn._tsig_ctx_creator = \
lambda key: self.__create_mock_tsig(key, TSIGError.BAD_SIG)
- self.soa_response_params['rcode'] = Rcode.NOTAUTH()
+ self.soa_response_params['rcode'] = Rcode.NOTAUTH
self.conn.response_generator = self._create_soa_response_data
self.assertRaises(XfrinProtocolError, self.conn._check_soa_serial)
@@ -1257,7 +1257,7 @@ class TestAXFR(TestXfrinConnection):
def test_response_shutdown(self):
self.conn.response_generator = self._create_normal_response_data
self.conn._shutdown_event.set()
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.assertRaises(XfrinException, self.conn._handle_xfrin_responses)
def test_response_timeout(self):
@@ -1272,13 +1272,13 @@ class TestAXFR(TestXfrinConnection):
def test_response_bad_message(self):
self.conn.response_generator = self._create_broken_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.assertRaises(Exception, self.conn._handle_xfrin_responses)
def test_axfr_response(self):
# A simple normal case: AXFR consists of SOA, NS, then trailing SOA.
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1299,7 +1299,7 @@ class TestAXFR(TestXfrinConnection):
self._create_ns(),
soa_rrset]
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1314,10 +1314,9 @@ class TestAXFR(TestXfrinConnection):
'''
ns_rr = self._create_ns()
a_rr = self._create_a('192.0.2.1')
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.AXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)],
# begin serial=1230, end serial=1234. end will be used.
answers=[begin_soa_rrset, ns_rr, a_rr, soa_rrset])
self.conn._handle_xfrin_responses()
@@ -1331,10 +1330,9 @@ class TestAXFR(TestXfrinConnection):
Test we reject a zone transfer if it fails the check_zone validation.
"""
a_rr = self._create_a('192.0.2.1')
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.AXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.AXFR)],
# begin serial=1230, end serial=1234. end will be used.
answers=[begin_soa_rrset, a_rr, soa_rrset])
# Make it fail the validation
@@ -1361,10 +1359,10 @@ class TestAXFR(TestXfrinConnection):
'''
ns_rr = self._create_ns()
a_rr = self._create_a('192.0.2.1')
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.AXFR())],
+ RRType.AXFR)],
answers=[soa_rrset, ns_rr, a_rr, soa_rrset, a_rr])
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
@@ -1378,9 +1376,9 @@ class TestAXFR(TestXfrinConnection):
'''
self.axfr_response_params['question_1st'] = \
- [Question(Name('mismatch.example'), TEST_RRCLASS, RRType.AXFR())]
+ [Question(Name('mismatch.example'), TEST_RRCLASS, RRType.AXFR)]
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1394,9 +1392,9 @@ class TestAXFR(TestXfrinConnection):
'''
self.axfr_response_params['question_1st'] = \
- [Question(TEST_ZONE_NAME, RRClass.CH(), RRType.AXFR())]
+ [Question(TEST_ZONE_NAME, RRClass.CH, RRType.AXFR)]
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1411,9 +1409,9 @@ class TestAXFR(TestXfrinConnection):
'''
# returning IXFR in question to AXFR query
self.axfr_response_params['question_1st'] = \
- [Question(TEST_ZONE_NAME, RRClass.CH(), RRType.IXFR())]
+ [Question(TEST_ZONE_NAME, RRClass.CH, RRType.IXFR)]
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1428,7 +1426,7 @@ class TestAXFR(TestXfrinConnection):
'''
self.axfr_response_params['question_1st'] = []
self.conn.response_generator = self._create_normal_response_data
- self.conn._send_query(RRType.AXFR())
+ self.conn._send_query(RRType.AXFR)
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
check_diffs(self.assertEqual,
@@ -1617,7 +1615,7 @@ class TestIXFRResponse(TestXfrinConnection):
super().setUp()
self.conn._query_id = self.conn.qid = 1035
self.conn._request_serial = isc.dns.Serial(1230)
- self.conn._request_type = RRType.IXFR()
+ self.conn._request_type = RRType.IXFR
self.conn._datasrc_client = MockDataSourceClient()
XfrinInitialSOA().set_xfrstate(self.conn, XfrinInitialSOA())
@@ -1631,7 +1629,7 @@ class TestIXFRResponse(TestXfrinConnection):
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1646,7 +1644,7 @@ class TestIXFRResponse(TestXfrinConnection):
An IXFR that fails validation later on. Check it is rejected.
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self._check_zone_result = False
self.assertRaises(XfrinZoneError, self.conn._handle_xfrin_responses)
@@ -1666,7 +1664,7 @@ class TestIXFRResponse(TestXfrinConnection):
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset,
# removing one A in serial 1230
begin_soa_rrset, self._create_a('192.0.2.1'),
@@ -1706,10 +1704,10 @@ class TestIXFRResponse(TestXfrinConnection):
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset])
self.conn.reply_data += self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1720,7 +1718,7 @@ class TestIXFRResponse(TestXfrinConnection):
def test_ixfr_response_uptodate(self):
'''IXFR response indicates the zone is new enough'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[begin_soa_rrset])
self.assertRaises(XfrinZoneUptodate, self.conn._handle_xfrin_responses)
# no diffs should have been committed
@@ -1733,7 +1731,7 @@ class TestIXFRResponse(TestXfrinConnection):
'''
# SOA sequence is out-of-sync
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset,
self._create_soa('1235')])
self.assertRaises(XfrinProtocolError,
@@ -1750,7 +1748,7 @@ class TestIXFRResponse(TestXfrinConnection):
specification, but it is how BIND 9 works and we do the same.
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset,
self._create_a('192.0.2.1')])
self.assertRaises(XfrinProtocolError,
@@ -1767,7 +1765,7 @@ class TestIXFRResponse(TestXfrinConnection):
'''
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[begin_soa_rrset, soa_rrset])
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
@@ -1784,7 +1782,7 @@ class TestIXFRResponse(TestXfrinConnection):
ns_rr = self._create_ns()
a_rr = self._create_a('192.0.2.1')
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, ns_rr, a_rr, soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
@@ -1806,7 +1804,7 @@ class TestIXFRResponse(TestXfrinConnection):
ns_rr = self._create_ns()
a_rr = self._create_a('192.0.2.1')
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, ns_rr, a_rr, begin_soa_rrset])
self.conn._handle_xfrin_responses()
self.assertEqual(type(XfrinAXFREnd()), type(self.conn.get_xfrstate()))
@@ -1825,7 +1823,7 @@ class TestIXFRResponse(TestXfrinConnection):
ns_rr = self._create_ns()
a_rr = self._create_a('192.0.2.1')
self.conn.reply_data = self.conn.create_response_data(
- questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR())],
+ questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS, RRType.IXFR)],
answers=[soa_rrset, ns_rr, a_rr, soa_rrset, a_rr])
self.assertRaises(XfrinProtocolError,
self.conn._handle_xfrin_responses)
@@ -1852,10 +1850,10 @@ class TestIXFRSession(TestXfrinConnection):
def create_ixfr_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.IXFR())],
+ RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self.conn.response_generator = create_ixfr_response
- self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
# Check some details of the IXFR protocol processing
self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
@@ -1869,7 +1867,7 @@ class TestIXFRSession(TestXfrinConnection):
qmsg.from_wire(qdata, len(qdata))
self.assertEqual(1, qmsg.get_rr_count(Message.SECTION_QUESTION))
self.assertEqual(TEST_ZONE_NAME, qmsg.get_question()[0].get_name())
- self.assertEqual(RRType.IXFR(), qmsg.get_question()[0].get_type())
+ self.assertEqual(RRType.IXFR, qmsg.get_question()[0].get_type())
self.assertEqual(1, self.conn._transfer_stats.message_count)
self.assertEqual(0, self.conn._transfer_stats.axfr_rr_count)
@@ -1886,18 +1884,18 @@ class TestIXFRSession(TestXfrinConnection):
def create_ixfr_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.IXFR())],
+ RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset,
self._create_soa('1235')])
self.conn.response_generator = create_ixfr_response
- self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
def test_do_xfrin_fail2(self):
'''IXFR fails due to a bogus DNS message.
'''
self._create_broken_response_data()
- self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
def test_do_xfrin_uptodate(self):
'''IXFR is (gracefully) aborted because serial is not new
@@ -1906,10 +1904,10 @@ class TestIXFRSession(TestXfrinConnection):
def create_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.IXFR())],
+ RRType.IXFR)],
answers=[begin_soa_rrset])
self.conn.response_generator = create_response
- self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
self.assertEqual(1, self.conn._transfer_stats.message_count)
self.assertEqual(0, self.conn._transfer_stats.axfr_rr_count)
@@ -1956,7 +1954,7 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
def get_zone_serial(self):
result, finder = self.conn._datasrc_client.find_zone(TEST_ZONE_NAME)
self.assertEqual(DataSourceClient.SUCCESS, result)
- result, soa, _ = finder.find(TEST_ZONE_NAME, RRType.SOA())
+ result, soa, _ = finder.find(TEST_ZONE_NAME, RRType.SOA)
self.assertEqual(ZoneFinder.SUCCESS, result)
self.assertEqual(1, soa.get_rdata_count())
return get_soa_serial(soa.get_rdata()[0])
@@ -1971,13 +1969,13 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
def create_ixfr_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.IXFR())],
+ RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset, soa_rrset])
self.conn.response_generator = create_ixfr_response
# Confirm xfrin succeeds and SOA is updated
self.assertEqual(1230, self.get_zone_serial().get_value())
- self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.IXFR))
self.assertEqual(1234, self.get_zone_serial().get_value())
# Also confirm the corresponding diffs are stored in the diffs table
@@ -2002,18 +2000,18 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
def create_ixfr_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.IXFR())],
+ RRType.IXFR)],
answers=[soa_rrset, begin_soa_rrset, soa_rrset,
self._create_soa('1235')])
self.conn.response_generator = create_ixfr_response
self.assertEqual(1230, self.get_zone_serial().get_value())
- self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
self.assertEqual(1230, self.get_zone_serial().get_value())
def test_do_ixfrin_nozone_sqlite3(self):
self._set_test_zone(Name('nosuchzone.example'))
- self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR()))
+ self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, RRType.IXFR))
# This should fail even before starting state transition
self.assertEqual(None, self.conn.get_xfrstate())
@@ -2030,23 +2028,23 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
# Confirm xfrin succeeds and SOA is updated, A RR is deleted.
self.assertEqual(1230, self.get_zone_serial().get_value())
self.assertTrue(self.record_exist(Name('dns01.example.com'),
- RRType.A()))
+ RRType.A))
self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, type))
self.assertEqual(1234, self.get_zone_serial().get_value())
self.assertFalse(self.record_exist(Name('dns01.example.com'),
- RRType.A()))
+ RRType.A))
def test_do_ixfrin_axfr_sqlite3(self):
'''AXFR-style IXFR.
'''
- self.axfr_check(RRType.IXFR())
+ self.axfr_check(RRType.IXFR)
def test_do_axfrin_sqlite3(self):
'''AXFR.
'''
- self.axfr_check(RRType.AXFR())
+ self.axfr_check(RRType.AXFR)
def axfr_failure_check(self, type):
'''Similar to the previous two tests, but xfrin fails due to error.
@@ -2062,23 +2060,23 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
self.assertEqual(1230, self.get_zone_serial().get_value())
self.assertTrue(self.record_exist(Name('dns01.example.com'),
- RRType.A()))
+ RRType.A))
self.assertEqual(XFRIN_FAIL, self.conn.do_xfrin(False, type))
self.assertEqual(1230, self.get_zone_serial().get_value())
self.assertTrue(self.record_exist(Name('dns01.example.com'),
- RRType.A()))
+ RRType.A))
def test_do_xfrin_axfr_sqlite3_fail(self):
'''Failure case for AXFR-style IXFR.
'''
- self.axfr_failure_check(RRType.IXFR())
+ self.axfr_failure_check(RRType.IXFR)
def test_do_axfrin_sqlite3_fail(self):
'''Failure case for AXFR.
'''
- self.axfr_failure_check(RRType.AXFR())
+ self.axfr_failure_check(RRType.AXFR)
def test_do_axfrin_nozone_sqlite3(self):
'''AXFR test with an empty SQLite3 DB file, thus no target zone there.
@@ -2095,16 +2093,16 @@ class TestXFRSessionWithSQLite3(TestXfrinConnection):
def create_response():
self.conn.reply_data = self.conn.create_response_data(
questions=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.AXFR())],
+ RRType.AXFR)],
answers=[soa_rrset, self._create_ns(), soa_rrset])
self.conn.response_generator = create_response
self._set_test_zone(Name('example.com'))
- self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.AXFR()))
+ self.assertEqual(XFRIN_OK, self.conn.do_xfrin(False, RRType.AXFR))
self.assertEqual(type(XfrinAXFREnd()),
type(self.conn.get_xfrstate()))
self.assertEqual(1234, self.get_zone_serial().get_value())
self.assertFalse(self.record_exist(Name('dns01.example.com'),
- RRType.A()))
+ RRType.A))
class TestXfrinRecorder(unittest.TestCase):
def setUp(self):
@@ -2213,7 +2211,7 @@ class TestXfrinProcess(unittest.TestCase):
# Normal, successful case. We only check that things are cleaned up
# at the tearDown time.
process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
- self.master, False, None, RRType.AXFR(),
+ self.master, False, None, RRType.AXFR,
self.create_xfrinconn)
def test_process_xfrin_exception_on_connect(self):
@@ -2221,7 +2219,7 @@ class TestXfrinProcess(unittest.TestCase):
# cleaned up.
self.do_raise_on_connect = True
process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
- self.master, False, None, RRType.AXFR(),
+ self.master, False, None, RRType.AXFR,
self.create_xfrinconn)
def test_process_xfrin_exception_on_close(self):
@@ -2231,7 +2229,7 @@ class TestXfrinProcess(unittest.TestCase):
self.do_raise_on_connect = True
self.do_raise_on_close = True
process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
- self.master, False, None, RRType.AXFR(),
+ self.master, False, None, RRType.AXFR,
self.create_xfrinconn)
def test_process_xfrin_exception_on_publish(self):
@@ -2239,7 +2237,7 @@ class TestXfrinProcess(unittest.TestCase):
# everything must still be cleaned up.
self.do_raise_on_publish = True
process_xfrin(self, self, TEST_ZONE_NAME, TEST_RRCLASS, None, None,
- self.master, False, None, RRType.AXFR(),
+ self.master, False, None, RRType.AXFR,
self.create_xfrinconn)
class TestXfrin(unittest.TestCase):
@@ -2292,7 +2290,7 @@ class TestXfrin(unittest.TestCase):
def test_parse_cmd_params_chclass(self):
self.args['zone_class'] = 'CH'
- self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH())
+ self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH)
def test_parse_cmd_params_bogusclass(self):
self.args['zone_class'] = 'XXX'
@@ -2339,7 +2337,7 @@ class TestXfrin(unittest.TestCase):
self.assertEqual(self.args['master'], self.xfr.xfrin_started_master_addr)
self.assertEqual(int(self.args['port']), self.xfr.xfrin_started_master_port)
# By default we use AXFR (for now)
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_retransfer_short_command1(self):
# try it when only specifying the zone name (of unknown zone)
@@ -2453,7 +2451,7 @@ class TestXfrin(unittest.TestCase):
self.assertEqual(int(TEST_MASTER_PORT),
self.xfr.xfrin_started_master_port)
# By default we use AXFR (for now)
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_notify(self):
# at this level, refresh is no different than retransfer.
@@ -2520,7 +2518,7 @@ class TestXfrin(unittest.TestCase):
self.xfr._max_transfers_in)
for zone_config in config_given['zones']:
zone_name = zone_config['name']
- zone_info = self.xfr._get_zone_info(Name(zone_name), RRClass.IN())
+ zone_info = self.xfr._get_zone_info(Name(zone_name), RRClass.IN)
self.assertEqual(str(zone_info.master_addr), zone_config['master_addr'])
self.assertEqual(zone_info.master_port, zone_config['master_port'])
if 'tsig_key' in zone_config:
@@ -2695,16 +2693,16 @@ class TestXfrin(unittest.TestCase):
def test_command_handler_retransfer_ixfr_enabled(self):
# If IXFR is explicitly enabled in config, IXFR will be used
self.common_ixfr_setup('retransfer', True)
- self.assertEqual(RRType.IXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.IXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_refresh_ixfr_enabled(self):
# Same for refresh
self.common_ixfr_setup('refresh', True)
- self.assertEqual(RRType.IXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.IXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_retransfer_with_tsig(self):
self.common_ixfr_setup('retransfer', False, 'example.com.key')
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_retransfer_with_tsig_bad_key(self):
# bad keys should not reach xfrin, but should they somehow,
@@ -2718,7 +2716,7 @@ class TestXfrin(unittest.TestCase):
def test_command_handler_refresh_with_tsig(self):
self.common_ixfr_setup('refresh', False, 'example.com.key')
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_refresh_with_tsig_bad_key(self):
# bad keys should not reach xfrin, but should they somehow,
@@ -2734,12 +2732,12 @@ class TestXfrin(unittest.TestCase):
# Similar to the previous case, but explicitly disabled. AXFR should
# be used.
self.common_ixfr_setup('retransfer', False)
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
def test_command_handler_refresh_ixfr_disabled(self):
# Same for refresh
self.common_ixfr_setup('refresh', False)
- self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+ self.assertEqual(RRType.AXFR, self.xfr.xfrin_started_request_type)
class TestXfrinMemoryZones(unittest.TestCase):
def setUp(self):
@@ -3015,7 +3013,7 @@ class TestXfrinProcess(unittest.TestCase):
self.__rets = rets
published = rets[-1]
xfrin.process_xfrin(self, XfrinRecorder(), Name("example.org."),
- RRClass.IN(), None, None, None, True, None,
+ RRClass.IN, None, None, None, True, None,
request_type, self.__get_connection)
self.assertEqual([], self.__rets)
self.assertEqual(transfers, self.__transfers)
@@ -3027,7 +3025,7 @@ class TestXfrinProcess(unittest.TestCase):
"""
Everything OK the first time, over IXFR.
"""
- self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
+ self.__do_test([XFRIN_OK], [RRType.IXFR], RRType.IXFR)
# Check there was loadzone command
self.assertTrue(self._send_cc_session.send_called)
self.assertTrue(self._send_cc_session.send_called_correctly)
@@ -3038,7 +3036,7 @@ class TestXfrinProcess(unittest.TestCase):
"""
Everything OK the first time, over AXFR.
"""
- self.__do_test([XFRIN_OK], [RRType.AXFR()], RRType.AXFR())
+ self.__do_test([XFRIN_OK], [RRType.AXFR], RRType.AXFR)
def test_axfr_fail(self):
"""
@@ -3046,15 +3044,15 @@ class TestXfrinProcess(unittest.TestCase):
to fail on AXFR, but succeed on IXFR and we didn't use IXFR in the first
place for some reason.
"""
- self.__do_test([XFRIN_FAIL], [RRType.AXFR()], RRType.AXFR())
+ self.__do_test([XFRIN_FAIL], [RRType.AXFR], RRType.AXFR)
def test_ixfr_fallback(self):
"""
The transfer fails over IXFR, but suceeds over AXFR. It should fall back
to it and say everything is OK.
"""
- self.__do_test([XFRIN_FAIL, XFRIN_OK], [RRType.IXFR(), RRType.AXFR()],
- RRType.IXFR())
+ self.__do_test([XFRIN_FAIL, XFRIN_OK], [RRType.IXFR, RRType.AXFR],
+ RRType.IXFR)
def test_ixfr_fail(self):
"""
@@ -3062,13 +3060,13 @@ class TestXfrinProcess(unittest.TestCase):
(only once) and should try both before giving up.
"""
self.__do_test([XFRIN_FAIL, XFRIN_FAIL],
- [RRType.IXFR(), RRType.AXFR()], RRType.IXFR())
+ [RRType.IXFR, RRType.AXFR], RRType.IXFR)
def test_send_loadzone(self):
"""
Check the loadzone command is sent after successful transfer.
"""
- self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
+ self.__do_test([XFRIN_OK], [RRType.IXFR], RRType.IXFR)
self.assertTrue(self._send_cc_session.send_called)
self.assertTrue(self._send_cc_session.send_called_correctly)
self.assertTrue(self._send_cc_session.recv_called)
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 279284f..55d9818 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -78,7 +78,7 @@ DBG_XFRIN_TRACE = logger.DBGLVL_TRACE_BASIC
# (TODO: have similar support to get default values for command
# arguments as we do for config options)
DEFAULT_MASTER_PORT = 53
-DEFAULT_ZONE_CLASS = RRClass.IN()
+DEFAULT_ZONE_CLASS = RRClass.IN
__version__ = 'BIND10'
@@ -135,7 +135,7 @@ def _check_zone_class(zone_class_str):
"""If the given argument is a string: checks if the given class is
a valid one, and returns an RRClass object if so.
Raises XfrinZoneInfoException if not.
- If it is None, this function returns the default RRClass.IN()"""
+ If it is None, this function returns the default RRClass.IN"""
if zone_class_str is None:
return DEFAULT_ZONE_CLASS
try:
@@ -316,12 +316,12 @@ class XfrinState:
class XfrinInitialSOA(XfrinState):
def handle_rr(self, conn, rr):
- if rr.get_type() != RRType.SOA():
+ if rr.get_type() != RRType.SOA:
raise XfrinProtocolError('First RR in zone transfer must be SOA ('
+ rr.get_type().to_text() + ' received)')
conn._end_serial = get_soa_serial(rr.get_rdata()[0])
- if conn._request_type == RRType.IXFR() and \
+ if conn._request_type == RRType.IXFR and \
conn._end_serial <= conn._request_serial:
logger.info(XFRIN_IXFR_UPTODATE, conn.zone_str(),
conn._request_serial, conn._end_serial)
@@ -364,8 +364,8 @@ class XfrinFirstData(XfrinState):
http://www.ietf.org/mail-archive/web/dnsext/current/msg07908.html
'''
- if conn._request_type == RRType.IXFR() and \
- rr.get_type() == RRType.SOA() and \
+ if conn._request_type == RRType.IXFR and \
+ rr.get_type() == RRType.SOA and \
conn._request_serial == get_soa_serial(rr.get_rdata()[0]):
logger.debug(DBG_XFRIN_TRACE, XFRIN_GOT_INCREMENTAL_RESP,
conn.zone_str())
@@ -382,7 +382,7 @@ class XfrinFirstData(XfrinState):
class XfrinIXFRDeleteSOA(XfrinState):
def handle_rr(self, conn, rr):
- if rr.get_type() != RRType.SOA():
+ if rr.get_type() != RRType.SOA:
# this shouldn't happen; should this occur it means an internal
# bug.
raise XfrinException(rr.get_type().to_text() +
@@ -402,7 +402,7 @@ class XfrinIXFRDeleteSOA(XfrinState):
class XfrinIXFRDelete(XfrinState):
def handle_rr(self, conn, rr):
- if rr.get_type() == RRType.SOA():
+ if rr.get_type() == RRType.SOA:
# This is the only place where current_serial is set
conn._current_serial = get_soa_serial(rr.get_rdata()[0])
self.set_xfrstate(conn, XfrinIXFRAddSOA())
@@ -413,7 +413,7 @@ class XfrinIXFRDelete(XfrinState):
class XfrinIXFRAddSOA(XfrinState):
def handle_rr(self, conn, rr):
- if rr.get_type() != RRType.SOA():
+ if rr.get_type() != RRType.SOA:
# this shouldn't happen; should this occur it means an internal
# bug.
raise XfrinException(rr.get_type().to_text() +
@@ -425,7 +425,7 @@ class XfrinIXFRAddSOA(XfrinState):
class XfrinIXFRAdd(XfrinState):
def handle_rr(self, conn, rr):
- if rr.get_type() == RRType.SOA():
+ if rr.get_type() == RRType.SOA:
# This SOA marks the end of a difference sequence
conn.get_transfer_stats().ixfr_changeset_count += 1
soa_serial = get_soa_serial(rr.get_rdata()[0])
@@ -480,7 +480,7 @@ class XfrinAXFR(XfrinState):
Handle the RR by putting it into the zone.
"""
conn._diff.add_data(rr)
- if rr.get_type() == RRType.SOA():
+ if rr.get_type() == RRType.SOA:
# SOA means end. Don't commit it yet - we need to perform
# post-transfer checks
@@ -662,7 +662,7 @@ class XfrinConnection(asyncore.dispatcher):
result, finder = self._datasrc_client.find_zone(self._zone_name)
if result != DataSourceClient.SUCCESS:
return None
- result, soa_rrset, _ = finder.find(self._zone_name, RRType.SOA())
+ result, soa_rrset, _ = finder.find(self._zone_name, RRType.SOA)
if result != ZoneFinder.SUCCESS:
logger.info(XFRIN_ZONE_NO_SOA, self.zone_str())
return None
@@ -714,8 +714,8 @@ class XfrinConnection(asyncore.dispatcher):
query_id = random.randint(0, 0xFFFF)
self._query_id = query_id
msg.set_qid(query_id)
- msg.set_opcode(Opcode.QUERY())
- msg.set_rcode(Rcode.NOERROR())
+ msg.set_opcode(Opcode.QUERY)
+ msg.set_rcode(Rcode.NOERROR)
msg.add_question(Question(self._zone_name, self._rrclass, query_type))
# Remember our serial, if known
@@ -723,7 +723,7 @@ class XfrinConnection(asyncore.dispatcher):
if self._zone_soa is not None else None
# Set the authority section with our SOA for IXFR
- if query_type == RRType.IXFR():
+ if query_type == RRType.IXFR:
if self._zone_soa is None:
# (incremental) IXFR doesn't work without known SOA
raise XfrinException('Failed to create IXFR query due to no ' +
@@ -855,7 +855,7 @@ class XfrinConnection(asyncore.dispatcher):
resp_question = msg.get_question()[0]
if resp_question.get_name() != self._zone_name or \
resp_question.get_class() != self._rrclass or \
- resp_question.get_type() != RRType.SOA():
+ resp_question.get_type() != RRType.SOA:
raise XfrinProtocolError('Invalid response to SOA query: '
'question mismatch: ' +
str(resp_question))
@@ -863,21 +863,21 @@ class XfrinConnection(asyncore.dispatcher):
# Look into the answer section for SOA
soa = None
for rr in msg.get_section(Message.SECTION_ANSWER):
- if rr.get_type() == RRType.SOA():
+ if rr.get_type() == RRType.SOA:
if soa is not None:
raise XfrinProtocolError('SOA response had multiple SOAs')
soa = rr
# There should not be a CNAME record at top of zone.
- if rr.get_type() == RRType.CNAME():
+ if rr.get_type() == RRType.CNAME:
raise XfrinProtocolError('SOA query resulted in CNAME')
# If SOA is not found, try to figure out the reason then report it.
if soa is None:
# See if we have any SOA records in the authority section.
for rr in msg.get_section(Message.SECTION_AUTHORITY):
- if rr.get_type() == RRType.NS():
+ if rr.get_type() == RRType.NS:
raise XfrinProtocolError('SOA query resulted in referral')
- if rr.get_type() == RRType.SOA():
+ if rr.get_type() == RRType.SOA:
raise XfrinProtocolError('SOA query resulted in NODATA')
raise XfrinProtocolError('No SOA record found in response to ' +
'SOA query')
@@ -901,7 +901,7 @@ class XfrinConnection(asyncore.dispatcher):
'''
- self._send_query(RRType.SOA())
+ self._send_query(RRType.SOA)
data_len = self._get_request_response(2)
msg_len = socket.htons(struct.unpack('H', data_len)[0])
soa_response = self._get_request_response(msg_len)
@@ -925,7 +925,7 @@ class XfrinConnection(asyncore.dispatcher):
return XFRIN_OK
- def do_xfrin(self, check_soa, request_type=RRType.AXFR()):
+ def do_xfrin(self, check_soa, request_type=RRType.AXFR):
'''Do an xfr session by sending xfr request and parsing responses.'''
try:
@@ -933,7 +933,7 @@ class XfrinConnection(asyncore.dispatcher):
self._request_type = request_type
# Right now RRType.[IA]XFR().to_text() is 'TYPExxx', so we need
# to hardcode here.
- req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
+ req_str = 'IXFR' if request_type == RRType.IXFR else 'AXFR'
if check_soa:
self._check_soa_serial()
self.close()
@@ -1024,7 +1024,7 @@ class XfrinConnection(asyncore.dispatcher):
# cause interoperability trouble with stricter checks.
msg_rcode = msg.get_rcode()
- if msg_rcode != Rcode.NOERROR():
+ if msg_rcode != Rcode.NOERROR:
raise XfrinProtocolError('error response: %s' %
msg_rcode.to_text())
@@ -1120,13 +1120,13 @@ def __process_xfrin(server, zone_name, rrclass, db_file,
ret = XFRIN_FAIL
if conn.connect_to_master():
ret = conn.do_xfrin(check_soa, request_type)
- if ret == XFRIN_FAIL and request_type == RRType.IXFR():
+ if ret == XFRIN_FAIL and request_type == RRType.IXFR:
# IXFR failed for some reason. It might mean the server can't
# handle it, or we don't have the zone or we are out of sync or
# whatever else. So we retry with with AXFR, as it may succeed
# in many such cases.
retry = True
- request_type = RRType.AXFR()
+ request_type = RRType.AXFR
logger.warn(XFRIN_XFR_TRANSFER_FALLBACK, conn.zone_str())
conn.close()
conn = None
@@ -1172,7 +1172,7 @@ def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
xfrin_recorder.decrement(zone_name)
if exception is not None:
- typestr = "AXFR" if request_type == RRType.AXFR() else "IXFR"
+ typestr = "AXFR" if request_type == RRType.AXFR else "IXFR"
logger.error(XFRIN_XFR_PROCESS_FAILURE, typestr, zone_name.to_text(),
str(rrclass), str(exception))
@@ -1507,9 +1507,9 @@ class Xfrin:
logger.info(XFRIN_RETRANSFER_UNKNOWN_ZONE, zone_str)
answer = create_answer(1, errmsg)
else:
- request_type = RRType.AXFR()
+ request_type = RRType.AXFR
if zone_info.use_ixfr:
- request_type = RRType.IXFR()
+ request_type = RRType.IXFR
master_addr = zone_info.get_master_addr_info()
if notify_addr[0] == master_addr[0] and\
notify_addr[2] == master_addr[2]:
@@ -1538,11 +1538,11 @@ class Xfrin:
rrclass)
zone_info = self._get_zone_info(zone_name, rrclass)
tsig_key = None
- request_type = RRType.AXFR()
+ request_type = RRType.AXFR
if zone_info:
tsig_key = zone_info.get_tsig_key()
if zone_info.use_ixfr:
- request_type = RRType.IXFR()
+ request_type = RRType.IXFR
db_file = args.get('db_file') or self._get_db_file()
ret = self.xfrin_start(zone_name,
rrclass,
diff --git a/src/bin/xfrin/xfrin_messages.mes b/src/bin/xfrin/xfrin_messages.mes
index 42e55ac..1d90b75 100644
--- a/src/bin/xfrin/xfrin_messages.mes
+++ b/src/bin/xfrin/xfrin_messages.mes
@@ -125,10 +125,6 @@ There was a problem sending a message to the xfrout module or the
zone manager. This most likely means that the msgq daemon has quit or
was killed.
-% XFRIN_MSGQ_SEND_ERROR_AUTH error while contacting %1
-There was a problem sending a message to b10-auth. This most likely
-means that the msgq daemon has quit or was killed.
-
% XFRIN_MSGQ_SEND_ERROR_ZONE_MANAGER error while contacting %1
There was a problem sending a message to the zone manager. This most
likely means that the msgq daemon has quit or was killed.
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index 7bc395e..bc0fae9 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -38,7 +38,7 @@ TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
#
TEST_ZONE_NAME_STR = "example.com."
TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
IXFR_OK_VERSION = 2011111802
IXFR_NG_VERSION = 2011111803
SOA_CURRENT_VERSION = 2011112001
@@ -109,16 +109,16 @@ class MockDataSrcClient:
zone names.
'''
- if name == Name('nosoa.example.com') and rrtype == RRType.SOA():
+ if name == Name('nosoa.example.com') and rrtype == RRType.SOA:
return (ZoneFinder.NXDOMAIN, None, 0)
- elif name == Name('multisoa.example.com') and rrtype == RRType.SOA():
+ elif name == Name('multisoa.example.com') and rrtype == RRType.SOA:
soa_rrset = create_soa(SOA_CURRENT_VERSION)
soa_rrset.add_rdata(soa_rrset.get_rdata()[0])
return (ZoneFinder.SUCCESS, soa_rrset, 0)
elif name == Name('maxserial.example.com'):
soa_rrset = create_soa(0xffffffff)
return (ZoneFinder.SUCCESS, soa_rrset, 0)
- elif rrtype == RRType.SOA():
+ elif rrtype == RRType.SOA:
return (ZoneFinder.SUCCESS, create_soa(SOA_CURRENT_VERSION), 0)
raise ValueError('Unexpected input to mock finder: bug in test case?')
@@ -238,17 +238,17 @@ class TestXfroutSessionBase(unittest.TestCase):
msg = Message(Message.RENDER)
query_id = 0x1035
msg.set_qid(query_id)
- msg.set_opcode(Opcode.QUERY())
- msg.set_rcode(Rcode.NOERROR())
- req_type = RRType.AXFR() if ixfr is None else RRType.IXFR()
+ msg.set_opcode(Opcode.QUERY)
+ msg.set_rcode(Rcode.NOERROR)
+ req_type = RRType.AXFR if ixfr is None else RRType.IXFR
if with_question:
- msg.add_question(Question(zone_name, RRClass.IN(),
+ msg.add_question(Question(zone_name, RRClass.IN,
req_type if qtype is None else qtype))
- if req_type == RRType.IXFR():
- soa = RRset(zone_name, soa_class, RRType.SOA(), RRTTL(0))
+ if req_type == RRType.IXFR:
+ soa = RRset(zone_name, soa_class, RRType.SOA, RRTTL(0))
# In the RDATA only the serial matters.
for i in range(0, num_soa):
- soa.add_rdata(Rdata(RRType.SOA(), soa_class,
+ soa.add_rdata(Rdata(RRType.SOA, soa_class,
'm. r. ' + str(ixfr) + ' 1 1 1 1'))
msg.add_rrset(Message.SECTION_AUTHORITY, soa)
@@ -263,7 +263,7 @@ class TestXfroutSessionBase(unittest.TestCase):
def set_request_type(self, type):
self.xfrsess._request_type = type
- if type == RRType.AXFR():
+ if type == RRType.AXFR:
self.xfrsess._request_typestr = 'AXFR'
else:
self.xfrsess._request_typestr = 'IXFR'
@@ -280,7 +280,7 @@ class TestXfroutSessionBase(unittest.TestCase):
[{"action": "ACCEPT"}]),
{},
**self._counters)
- self.set_request_type(RRType.AXFR()) # test AXFR by default
+ self.set_request_type(RRType.AXFR) # test AXFR by default
self.mdata = self.create_request_data()
self.soa_rrset = create_soa(SOA_CURRENT_VERSION)
# some test replaces a module-wide function. We should ensure the
@@ -342,7 +342,7 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess._request_data = self.mdata
self.xfrsess._server.increase_transfers_counter = lambda : False
XfroutSession._handle(self.xfrsess)
- self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.REFUSED())
+ self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.REFUSED)
def test_quota_ok(self):
'''The default case in terms of the xfrout quota.
@@ -355,7 +355,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# Replace the data source client to avoid datasrc related exceptions
self.xfrsess.ClientClass = MockDataSrcClient
XfroutSession._handle(self.xfrsess)
- self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.FORMERR())
+ self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.FORMERR)
def test_exception_from_session(self):
'''Test the case where the main processing raises an exception.
@@ -372,14 +372,14 @@ class TestXfroutSession(TestXfroutSessionBase):
def test_parse_query_message(self):
# Valid AXFR
[get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
- self.assertEqual(RRType.AXFR(), self.xfrsess._request_type)
+ self.assertEqual(RRType.AXFR, self.xfrsess._request_type)
self.assertEqual(get_rcode.to_text(), "NOERROR")
# Valid IXFR
request_data = self.create_request_data(ixfr=2011111801)
rcode, msg = self.xfrsess._parse_query_message(request_data)
- self.assertEqual(RRType.IXFR(), self.xfrsess._request_type)
- self.assertEqual(Rcode.NOERROR(), rcode)
+ self.assertEqual(RRType.IXFR, self.xfrsess._request_type)
+ self.assertEqual(Rcode.NOERROR, rcode)
# Broken request: no question
self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
@@ -387,7 +387,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# Broken request: invalid RR type (neither AXFR nor IXFR)
self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
- self.create_request_data(qtype=RRType.A()))
+ self.create_request_data(qtype=RRType.A))
# NOERROR
request_data = self.create_request_data(ixfr=IXFR_OK_VERSION)
@@ -554,7 +554,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# should be used.
self.xfrsess._acl = isc.acl.dns.REQUEST_LOADER.load([
{"from": "127.0.0.1", "action": "ACCEPT"}])
- acl = self.xfrsess._get_transfer_acl(Name('example.com'), RRClass.IN())
+ acl = self.xfrsess._get_transfer_acl(Name('example.com'), RRClass.IN)
self.assertEqual(acl, self.xfrsess._acl)
# install a per zone config with transfer ACL for example.com. Then
@@ -567,15 +567,15 @@ class TestXfroutSession(TestXfroutSessionBase):
com_acl
self.assertEqual(com_acl,
self.xfrsess._get_transfer_acl(Name('example.com'),
- RRClass.IN()))
+ RRClass.IN))
self.assertEqual(self.xfrsess._acl,
self.xfrsess._get_transfer_acl(Name('example.org'),
- RRClass.IN()))
+ RRClass.IN))
# Name matching should be case insensitive.
self.assertEqual(com_acl,
self.xfrsess._get_transfer_acl(Name('EXAMPLE.COM'),
- RRClass.IN()))
+ RRClass.IN))
def test_send_data(self):
self.xfrsess._send_data(self.sock, self.mdata)
@@ -600,9 +600,9 @@ class TestXfroutSession(TestXfroutSessionBase):
msg = self.getmsg()
msg.make_response()
# SOA record data with different cases
- soa_rrset = RRset(Name('Example.com.'), RRClass.IN(), RRType.SOA(),
+ soa_rrset = RRset(Name('Example.com.'), RRClass.IN, RRType.SOA,
RRTTL(3600))
- soa_rrset.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+ soa_rrset.add_rdata(Rdata(RRType.SOA, RRClass.IN,
'master.Example.com. admin.exAmple.com. ' +
'2011112001 3600 1800 2419200 7200'))
msg.add_rrset(Message.SECTION_ANSWER, soa_rrset)
@@ -680,8 +680,8 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
def test_trigger_send_message_with_last_soa(self):
- rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
- rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
+ rrset_a = RRset(Name("example.com"), RRClass.IN, RRType.A, RRTTL(3600))
+ rrset_a.add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
msg = self.getmsg()
msg.make_response()
@@ -759,36 +759,36 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess.ClientClass = MockDataSrcClient
# Successful case. A zone iterator should be set up.
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
self.assertNotEqual(None, self.xfrsess._iterator)
# Failure cases
self.assertEqual(self.xfrsess._xfrout_setup(
self.getmsg(), Name('notauth.example.com'), TEST_RRCLASS),
- Rcode.NOTAUTH())
+ Rcode.NOTAUTH)
self.assertEqual(self.xfrsess._xfrout_setup(
self.getmsg(), Name('nosoa.example.com'), TEST_RRCLASS),
- Rcode.SERVFAIL())
+ Rcode.SERVFAIL)
self.assertEqual(self.xfrsess._xfrout_setup(
self.getmsg(), Name('multisoa.example.com'), TEST_RRCLASS),
- Rcode.SERVFAIL())
+ Rcode.SERVFAIL)
def test_xfrout_ixfr_setup(self):
self.xfrsess.ClientClass = MockDataSrcClient
- self.set_request_type(RRType.IXFR())
+ self.set_request_type(RRType.IXFR)
# Successful case of pure IXFR. A zone journal reader should be set
# up.
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
self.assertNotEqual(None, self.xfrsess._jnl_reader)
# Successful case, but as a result of falling back to AXFR-style
# IXFR. A zone iterator should be set up instead of a journal reader.
self.mdata = self.create_request_data(ixfr=IXFR_NG_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
self.assertNotEqual(None, self.xfrsess._iterator)
self.assertEqual(None, self.xfrsess._jnl_reader)
@@ -797,7 +797,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# indicating that the response will contain just one SOA.
self.mdata = self.create_request_data(ixfr=SOA_CURRENT_VERSION+1)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
self.assertEqual(None, self.xfrsess._iterator)
self.assertEqual(None, self.xfrsess._jnl_reader)
@@ -805,7 +805,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# the local SOA.
self.mdata = self.create_request_data(ixfr=SOA_CURRENT_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR)
self.assertEqual(None, self.xfrsess._iterator)
self.assertEqual(None, self.xfrsess._jnl_reader)
@@ -814,7 +814,7 @@ class TestXfroutSession(TestXfroutSessionBase):
zone_name = Name('maxserial.example.com') # whose SOA is 0xffffffff
self.mdata = self.create_request_data(ixfr=1, zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR)
self.assertEqual(None, self.xfrsess._iterator)
self.assertEqual(None, self.xfrsess._jnl_reader)
@@ -823,7 +823,7 @@ class TestXfroutSession(TestXfroutSessionBase):
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR)
self.assertNotEqual(None, self.xfrsess._iterator)
# Failure cases
@@ -831,42 +831,42 @@ class TestXfroutSession(TestXfroutSessionBase):
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH)
# this is a strange case: zone's SOA will be found but the journal
# reader won't be created due to 'no such zone'.
zone_name = Name('notauth2.example.com')
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH)
zone_name = Name('nosoa.example.com')
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL)
zone_name = Name('multisoa.example.com')
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL)
# query name doesn't match the SOA's owner
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
# query's RR class doesn't match the SOA's class
zone_name = TEST_ZONE_NAME # make sure the name matches this time
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
- soa_class=RRClass.CH())
+ soa_class=RRClass.CH)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
# multiple SOA RRs
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
num_soa=2)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR)
def test_dns_xfrout_start_formerror(self):
# formerror
@@ -876,7 +876,7 @@ class TestXfroutSession(TestXfroutSessionBase):
def test_dns_xfrout_start_notauth(self):
def notauth(msg, name, rrclass):
- return Rcode.NOTAUTH()
+ return Rcode.NOTAUTH
self.xfrsess._xfrout_setup = notauth
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
get_msg = self.sock.read_msg()
@@ -887,11 +887,11 @@ class TestXfroutSession(TestXfroutSessionBase):
raise isc.datasrc.Error('exception for the sake of test')
self.xfrsess.ClientClass = internal_raise
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
- self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL())
+ self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL)
def test_dns_xfrout_start_noerror(self):
def noerror(msg, name, rrclass):
- return Rcode.NOERROR()
+ return Rcode.NOERROR
self.xfrsess._xfrout_setup = noerror
def myreply(msg, sock):
@@ -905,7 +905,7 @@ class TestXfroutSession(TestXfroutSessionBase):
def test_dns_xfrout_start_with_notcallable_xfrreqdone(self):
def noerror(msg, name, rrclass):
- return Rcode.NOERROR()
+ return Rcode.NOERROR
self.xfrsess._xfrout_setup = noerror
def myreply(msg, sock):
@@ -925,9 +925,9 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
def test_reply_xfrout_query_axfr_with_tsig(self):
- rrset = RRset(Name('a.example.com'), RRClass.IN(), RRType.A(),
+ rrset = RRset(Name('a.example.com'), RRClass.IN, RRType.A,
RRTTL(3600))
- rrset.add_rdata(Rdata(RRType.A(), RRClass.IN(), '192.0.2.1'))
+ rrset.add_rdata(Rdata(RRType.A, RRClass.IN, '192.0.2.1'))
global xfrout
def get_rrset_len(rrset):
@@ -1015,8 +1015,8 @@ class TestXfroutSession(TestXfroutSessionBase):
algorithm = hmac-md5)
'''
- soa = RRset(Name('.'), RRClass.IN(), RRType.SOA(), RRTTL(3600))
- soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(), '. . 0 0 0 0 0'))
+ soa = RRset(Name('.'), RRClass.IN, RRType.SOA, RRTTL(3600))
+ soa.add_rdata(Rdata(RRType.SOA, RRClass.IN, '. . 0 0 0 0 0'))
self.mdata = self.create_request_data(zone_name=Name('.'))
self.xfrsess._soa = soa
if tsig:
@@ -1177,10 +1177,10 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.assertEqual(self.get_counter('ixfr_ended'), 0)
XfroutSession._handle(self.xfrsess)
response = self.sock.read_msg(Message.PRESERVE_ORDER);
- self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+ self.assertEqual(Rcode.NOERROR, response.get_rcode())
self.check_axfr_stream(response)
- self.assertEqual(self.xfrsess._request_type, RRType.AXFR())
- self.assertNotEqual(self.xfrsess._request_type, RRType.IXFR())
+ self.assertEqual(self.xfrsess._request_type, RRType.AXFR)
+ self.assertNotEqual(self.xfrsess._request_type, RRType.IXFR)
self.assertEqual(self.get_counter('axfr_started'), 1)
self.assertEqual(self.get_counter('axfr_ended'), 1)
self.assertEqual(self.get_counter('ixfr_started'), 0)
@@ -1191,10 +1191,10 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.create_request_data(ixfr=IXFR_NG_VERSION)
XfroutSession._handle(self.xfrsess)
response = self.sock.read_msg(Message.PRESERVE_ORDER);
- self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+ self.assertEqual(Rcode.NOERROR, response.get_rcode())
# This is an AXFR-style IXFR. So the question section should indicate
# that it's an IXFR resposne.
- self.assertEqual(RRType.IXFR(), response.get_question()[0].get_type())
+ self.assertEqual(RRType.IXFR, response.get_question()[0].get_type())
self.check_axfr_stream(response)
def test_ixfr_normal_session(self):
@@ -1222,8 +1222,8 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.assertEqual(len(expected_records), len(actual_records))
for (expected_rr, actual_rr) in zip(expected_records, actual_records):
self.assertTrue(rrsets_equal(expected_rr, actual_rr))
- self.assertNotEqual(self.xfrsess._request_type, RRType.AXFR())
- self.assertEqual(self.xfrsess._request_type, RRType.IXFR())
+ self.assertNotEqual(self.xfrsess._request_type, RRType.AXFR)
+ self.assertEqual(self.xfrsess._request_type, RRType.IXFR)
self.assertEqual(self.get_counter('axfr_started'), 0)
self.assertEqual(self.get_counter('axfr_ended'), 0)
self.assertEqual(self.get_counter('ixfr_started'), 1)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index c1885a9..5d25276 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -227,9 +227,9 @@ class XfroutSession():
self._tsig_key_ring)
tsig_error = self._tsig_ctx.verify(tsig_record, request_data)
if tsig_error != TSIGError.NOERROR:
- return Rcode.NOTAUTH()
+ return Rcode.NOTAUTH
- return Rcode.NOERROR()
+ return Rcode.NOERROR
def _parse_query_message(self, mdata):
''' parse query message to [socket,message]'''
@@ -239,11 +239,11 @@ class XfroutSession():
Message.from_wire(msg, mdata)
except Exception as err: # Exception is too broad
logger.error(XFROUT_PARSE_QUERY_ERROR, err)
- return Rcode.FORMERR(), None
+ return Rcode.FORMERR, None
# TSIG related checks
rcode = self._check_request_tsig(msg, mdata)
- if rcode != Rcode.NOERROR():
+ if rcode != Rcode.NOERROR:
return rcode, msg
# Make sure the question is valid. This should be ensured by
@@ -257,9 +257,9 @@ class XfroutSession():
# Identify the request type
self._request_type = question.get_type()
- if self._request_type == RRType.AXFR():
+ if self._request_type == RRType.AXFR:
self._request_typestr = 'AXFR'
- elif self._request_type == RRType.IXFR():
+ elif self._request_type == RRType.IXFR:
self._request_typestr = 'IXFR'
else:
# Likewise, this should be impossible.
@@ -283,7 +283,7 @@ class XfroutSession():
logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
self._request_type, format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
- return Rcode.REFUSED(), msg
+ return Rcode.REFUSED, msg
return rcode, msg
@@ -351,16 +351,16 @@ class XfroutSession():
'''
result, finder = self._datasrc_client.find_zone(zone_name)
if result != DataSourceClient.SUCCESS:
- return (Rcode.NOTAUTH(), None)
- result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+ return (Rcode.NOTAUTH, None)
+ result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
if result != ZoneFinder.SUCCESS:
- return (Rcode.SERVFAIL(), None)
+ return (Rcode.SERVFAIL, None)
# Especially for database-based zones, a working zone may be in
# a broken state where it has more than one SOA RR. We proactively
# check the condition and abort the xfr attempt if we identify it.
if soa_rrset.get_rdata_count() != 1:
- return (Rcode.SERVFAIL(), None)
- return (Rcode.NOERROR(), soa_rrset)
+ return (Rcode.SERVFAIL, None)
+ return (Rcode.NOERROR, soa_rrset)
def __axfr_setup(self, zone_name):
'''Setup a zone iterator for AXFR or AXFR-style IXFR.
@@ -379,16 +379,16 @@ class XfroutSession():
# update get_iterator() API so that we can distinguish "no such
# zone" and other cases (#1373). For now we consider all these
# cases as NOTAUTH.
- return Rcode.NOTAUTH()
+ return Rcode.NOTAUTH
# If we are an authoritative name server for the zone, but fail
# to find the zone's SOA record in datasource, xfrout can't
# provide zone transfer for it.
self._soa = self._iterator.get_soa()
if self._soa is None or self._soa.get_rdata_count() != 1:
- return Rcode.SERVFAIL()
+ return Rcode.SERVFAIL
- return Rcode.NOERROR()
+ return Rcode.NOERROR
def __ixfr_setup(self, request_msg, zone_name, zone_class):
'''Setup a zone journal reader for IXFR.
@@ -405,21 +405,21 @@ class XfroutSession():
# Ignore data whose owner name is not the zone apex, and
# ignore non-SOA or different class of records.
if auth_rrset.get_name() != zone_name or \
- auth_rrset.get_type() != RRType.SOA() or \
+ auth_rrset.get_type() != RRType.SOA or \
auth_rrset.get_class() != zone_class:
continue
if auth_rrset.get_rdata_count() != 1:
logger.info(XFROUT_IXFR_MULTIPLE_SOA,
format_addrinfo(self._remote))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
remote_soa = auth_rrset
if remote_soa is None:
logger.info(XFROUT_IXFR_NO_SOA, format_addrinfo(self._remote))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
# Retrieve the local SOA
rcode, self._soa = self._get_zone_soa(zone_name)
- if rcode != Rcode.NOERROR():
+ if rcode != Rcode.NOERROR:
return rcode
# RFC1995 says "If an IXFR query with the same or newer version
@@ -437,7 +437,7 @@ class XfroutSession():
logger.info(XFROUT_IXFR_UPTODATE, format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class),
begin_serial, end_serial)
- return Rcode.NOERROR()
+ return Rcode.NOERROR
# Set up the journal reader or fall back to AXFR-style IXFR
try:
@@ -462,12 +462,12 @@ class XfroutSession():
# between these two operations. We treat it as NOTAUTH.
logger.warn(XFROUT_IXFR_NO_ZONE, format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
- return Rcode.NOTAUTH()
+ return Rcode.NOTAUTH
# Use the reader as the iterator to generate the response.
self._iterator = self._jnl_reader
- return Rcode.NOERROR()
+ return Rcode.NOERROR
def _xfrout_setup(self, request_msg, zone_name, zone_class):
'''Setup a context for xfr responses according to the request type.
@@ -490,7 +490,7 @@ class XfroutSession():
self._server.get_db_file() + '"}'
self._datasrc_client = self.ClientClass('sqlite3', datasrc_config)
- if self._request_type == RRType.AXFR():
+ if self._request_type == RRType.AXFR:
return self.__axfr_setup(zone_name)
else:
return self.__ixfr_setup(request_msg, zone_name, zone_class)
@@ -500,17 +500,17 @@ class XfroutSession():
#TODO. create query message and parse header
if rcode_ is None: # Dropped by ACL
return
- elif rcode_ == Rcode.NOTAUTH() or rcode_ == Rcode.REFUSED():
+ elif rcode_ == Rcode.NOTAUTH or rcode_ == Rcode.REFUSED:
return self._reply_query_with_error_rcode(msg, sock_fd, rcode_)
- elif rcode_ != Rcode.NOERROR():
+ elif rcode_ != Rcode.NOERROR:
return self._reply_query_with_error_rcode(msg, sock_fd,
- Rcode.FORMERR())
+ Rcode.FORMERR)
elif not quota_ok:
logger.warn(XFROUT_QUERY_QUOTA_EXCCEEDED, self._request_typestr,
format_addrinfo(self._remote),
self._server._max_transfers_out)
return self._reply_query_with_error_rcode(msg, sock_fd,
- Rcode.REFUSED())
+ Rcode.REFUSED)
question = msg.get_question()[0]
zone_name = question.get_name()
@@ -522,15 +522,15 @@ class XfroutSession():
except Exception as ex:
logger.error(XFROUT_XFR_TRANSFER_CHECK_ERROR, self._request_typestr,
format_addrinfo(self._remote), zone_str, ex)
- rcode_ = Rcode.SERVFAIL()
- if rcode_ != Rcode.NOERROR():
+ rcode_ = Rcode.SERVFAIL
+ if rcode_ != Rcode.NOERROR:
logger.info(XFROUT_XFR_TRANSFER_FAILED, self._request_typestr,
format_addrinfo(self._remote), zone_str, rcode_)
return self._reply_query_with_error_rcode(msg, sock_fd, rcode_)
try:
# increment Xfr starts by RRType
- if self._request_type == RRType.AXFR():
+ if self._request_type == RRType.AXFR:
self._inc_axfr_running()
else:
self._inc_ixfr_running()
@@ -542,7 +542,7 @@ class XfroutSession():
format_addrinfo(self._remote), zone_str, err)
finally:
# decrement Xfr starts by RRType
- if self._request_type == RRType.AXFR():
+ if self._request_type == RRType.AXFR:
self._dec_axfr_running()
else:
self._dec_ixfr_running()
@@ -614,7 +614,7 @@ class XfroutSession():
# For AXFR (or AXFR-style IXFR), in which case _jnl_reader is None,
# we should skip SOAs from the iterator.
- if self._jnl_reader is None and rrset.get_type() == RRType.SOA():
+ if self._jnl_reader is None and rrset.get_type() == RRType.SOA:
continue
# We calculate the maximum size of the RRset (i.e. the
@@ -756,7 +756,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
"""
sock_fd = recv_fd(request.fileno())
if sock_fd < 0:
- logger.warn(XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR)
+ logger.warn(XFROUT_RECEIVE_FD_FAILED)
return False
# receive request msg. If it fails we simply terminate the thread;
@@ -1215,7 +1215,7 @@ class XfroutServer:
zone_name = args.get('zone_name')
zone_class = args.get('zone_class')
if not zone_class:
- zone_class = str(RRClass.IN())
+ zone_class = str(RRClass.IN)
if zone_name:
logger.info(XFROUT_NOTIFY_COMMAND, zone_name, zone_class)
if self.send_notify(zone_name, zone_class):
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index 6b88d27..5fb254e 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -155,7 +155,7 @@ statistics data should be sent to the stats daemon.
The xfrout daemon received a shutdown command from the command channel
and will now shut down.
-% XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR error receiving the file descriptor for an XFR connection
+% XFROUT_RECEIVE_FD_FAILED error receiving the file descriptor for an XFR connection
There was an error receiving the file descriptor for the transfer
request from b10-auth. There can be several reasons for this, but
the most likely cause is that b10-auth terminates for some reason
diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc
index 3442de9..397e004 100644
--- a/src/lib/asiodns/tcp_server.cc
+++ b/src/lib/asiodns/tcp_server.cc
@@ -184,7 +184,6 @@ TCPServer::operator()(asio::error_code ec, size_t length) {
// provides the appropriate operator() but is otherwise functionless.
iosock_.reset(new TCPSocket<DummyIOCallback>(*socket_));
io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
- bytes_ = length;
// Perform any necessary operations prior to processing the incoming
// packet (e.g., checking for queued configuration messages).
diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h
index 46f484b..50e8717 100644
--- a/src/lib/asiodns/tcp_server.h
+++ b/src/lib/asiodns/tcp_server.h
@@ -122,7 +122,6 @@ private:
// State information that is entirely internal to a given instance
// of the coroutine can be declared here.
- size_t bytes_;
bool done_;
// Callback functions provided by the caller
diff --git a/src/lib/asiodns/udp_server.cc b/src/lib/asiodns/udp_server.cc
index bdf79a7..cf4b1c4 100644
--- a/src/lib/asiodns/udp_server.cc
+++ b/src/lib/asiodns/udp_server.cc
@@ -61,7 +61,7 @@ struct UDPServer::Data {
*/
Data(io_service& io_service, const ip::address& addr, const uint16_t port,
SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
- io_(io_service), done_(false),
+ io_(io_service), bytes_(0), done_(false),
checkin_callback_(checkin),lookup_callback_(lookup),
answer_callback_(answer)
{
@@ -77,7 +77,7 @@ struct UDPServer::Data {
}
Data(io_service& io_service, int fd, int af, SimpleCallback* checkin,
DNSLookup* lookup, DNSAnswer* answer) :
- io_(io_service), done_(false),
+ io_(io_service), bytes_(0), done_(false),
checkin_callback_(checkin),lookup_callback_(lookup),
answer_callback_(answer)
{
@@ -104,7 +104,7 @@ struct UDPServer::Data {
* We also allocate data for receiving the packet here.
*/
Data(const Data& other) :
- io_(other.io_), socket_(other.socket_), done_(false),
+ io_(other.io_), socket_(other.socket_), bytes_(0), done_(false),
checkin_callback_(other.checkin_callback_),
lookup_callback_(other.lookup_callback_),
answer_callback_(other.answer_callback_)
@@ -168,7 +168,6 @@ struct UDPServer::Data {
size_t bytes_;
bool done_;
-
// Callback functions provided by the caller
const SimpleCallback* checkin_callback_;
const DNSLookup* lookup_callback_;
diff --git a/src/lib/cc/data.cc b/src/lib/cc/data.cc
index f9c23db..af3602a 100644
--- a/src/lib/cc/data.cc
+++ b/src/lib/cc/data.cc
@@ -261,7 +261,7 @@ skipChars(std::istream& in, const char* chars, int& line, int& pos) {
} else {
++pos;
}
- in.get();
+ in.ignore();
c = in.peek();
}
}
@@ -291,7 +291,7 @@ skipTo(std::istream& in, const std::string& file, int& line,
pos = 1;
++line;
}
- in.get();
+ in.ignore();
++pos;
}
in.putback(c);
@@ -352,7 +352,7 @@ strFromStringstream(std::istream& in, const std::string& file,
throwJSONError("Bad escape", file, line, pos);
}
// drop the escaped char
- in.get();
+ in.ignore();
++pos;
}
ss.put(c);
@@ -490,14 +490,14 @@ fromStringstreamMap(std::istream& in, const std::string& file, int& line,
throwJSONError(std::string("Unterminated map, <string> or } expected"), file, line, pos);
} else if (c == '}') {
// empty map, skip closing curly
- c = in.get();
+ in.ignore();
} else {
while (c != EOF && c != '}') {
std::string key = strFromStringstream(in, file, line, pos);
skipTo(in, file, line, pos, ":", WHITESPACE);
// skip the :
- in.get();
+ in.ignore();
pos++;
ConstElementPtr value = Element::fromJSON(in, file, line, pos);
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index e07c5a3..2a5e758 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -343,6 +343,7 @@ TEST_F(CCSessionTest, checkCommand) {
session.addMessage(el("{ \"command\": \"bad_command\" }"), "Spec29", "*");
result = mccs.checkCommand();
EXPECT_EQ(0, session.getMsgQueue()->size());
+ EXPECT_EQ(0, result);
session.addMessage(el("{ \"command\": [ \"bad_command\" ] }"),
"Spec29", "*");
@@ -627,6 +628,7 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
EXPECT_EQ(1, session.getMsgQueue()->size());
result = mccs.checkCommand();
EXPECT_EQ(0, session.getMsgQueue()->size());
+ EXPECT_EQ(0, result);
}
TEST_F(CCSessionTest, initializationFail) {
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 56c4110..e70cbe3 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -573,6 +573,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
/// For (successful) type ANY query, found_node points to the
/// corresponding zone node, which is recorded within this specialized
/// context.
+// cppcheck-suppress noConstructor
class InMemoryZoneFinder::Context : public ZoneFinder::Context {
public:
Context(InMemoryZoneFinder& finder, ZoneFinder::FindOptions options,
@@ -865,7 +866,8 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
const RdataSet* cur_rds = node->getData();
while (cur_rds != NULL) {
target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
- options, &name));
+ options,
+ wild ? &name : NULL));
cur_rds = cur_rds->getNext();
}
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
@@ -892,9 +894,13 @@ InMemoryZoneFinder::findInternal(const isc::dns::Name& name,
}
}
// No exact match or CNAME. Get NSEC if necessary and return NXRRSET.
+ // Note that we don't have to provide the "real name" even if this is
+ // a wildcard; if NSEC is needed its owner name shouldn't be subject to
+ // wildcard substitution; if NSEC isn't needed the "real name" doesn't
+ // matter anyway.
return (createFindResult(rrclass_, zone_data_, NXRRSET, node,
getNSECForNXRRSET(zone_data_, options, node),
- options, wild, &name));
+ options, wild));
}
isc::datasrc::ZoneFinder::FindNSEC3Result
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 45d7920..3081759 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -782,6 +782,7 @@ struct RBNodeResultContext {
};
}
+// cppcheck-suppress noConstructor
class InMemoryZoneFinder::Context : public ZoneFinder::Context {
public:
/// \brief Constructor.
diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc
index 632c271..a858028 100644
--- a/src/lib/datasrc/sqlite3_accessor.cc
+++ b/src/lib/datasrc/sqlite3_accessor.cc
@@ -682,6 +682,8 @@ convertToPlainChar(const unsigned char* ucp, sqlite3 *db) {
}
}
+
+// cppcheck-suppress noConstructor
class SQLite3Accessor::Context : public DatabaseAccessor::IteratorContext {
public:
// Construct an iterator for all records. When constructed this
@@ -887,6 +889,7 @@ SQLite3Accessor::getAllRecords(int id) const {
/// This iterator is used to search through the differences table for the
/// resouce records making up an IXFR between two versions of a zone.
+// cppcheck-suppress noConstructor
class SQLite3Accessor::DiffContext : public DatabaseAccessor::IteratorContext {
public:
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index e59013e..b1ebaf4 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -442,14 +442,23 @@ protected:
}
EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
find_result->isWildcard());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
- != 0, find_result->isNSECSigned());
- EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
- != 0, find_result->isNSEC3Signed());
- // Convert all rrsets to 'full' ones before checking
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
+ find_result->isNSECSigned());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
+ find_result->isNSEC3Signed());
+ // Convert all rrsets to 'full' ones before checking. Also, confirm
+ // each RRset of the vector is of the "same kind" as one would be
+ // found by the find() method.
std::vector<ConstRRsetPtr> converted_rrsets;
BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
converted_rrsets.push_back(convertRRset(cur_rrset));
+
+ // As we know findAll() succeeded, this find() should also
+ // succeed, and the two sets should be "identical".
+ const ZoneFinderContextPtr result =
+ finder->find(name, cur_rrset->getType());
+ ASSERT_TRUE(result->rrset);
+ EXPECT_TRUE(result->rrset->isSameKind(*cur_rrset));
}
rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
converted_rrsets.begin(), converted_rrsets.end());
@@ -1133,21 +1142,42 @@ InMemoryZoneFinderTest::wildcardCheck(
}
}
+// We have combinations of these cases (6 in total)
+// expected_flags: NSEC, NSEC3, RESULT_DEFAULT
+// options: NO_WILDCARD, FIND_DEFAULT
+
+// 1. Normal case: expected = DEFAULT, options = DEFAULT
TEST_F(InMemoryZoneFinderTest, wildcard) {
- // Normal case
wildcardCheck();
}
+// 2. options: expected = DEFAULT, options = NO_WILDCARD
+TEST_F(InMemoryZoneFinderTest, wildcardDisabled) {
+ // Similar to the previous once, but check the behavior for a non signed
+ // zone just in case.
+ wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
+}
+
+// 3. options: expected = NSEC_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardWithNSEC) {
+ wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DEFAULT);
+}
+
+// 4. options: expected = NSEC_SIGNED, options = NO_WILDCARD
TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
// Wildcard is disabled. In practice, this is used as part of query
// processing for an NSEC-signed zone, so we test that case specifically.
wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
}
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
- // Similar to the previous once, but check the behavior for a non signed
- // zone just in case.
- wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
+// 5. options: expected = NSEC3_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardWithNSEC3) {
+ wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DEFAULT);
+}
+
+// 6. options: expected = NSEC3_SIGNED, options = DEFAULT
+TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC3) {
+ wildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::NO_WILDCARD);
}
/*
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
index 7a64dac..bcb7851 100644
--- a/src/lib/dhcpsrv/alloc_engine.cc
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <cstring>
@@ -169,95 +170,104 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
const IOAddress& hint,
bool fake_allocation /* = false */ ) {
- // That check is not necessary. We create allocator in AllocEngine
- // constructor
- if (!allocator_) {
- isc_throw(InvalidOperation, "No allocator selected");
- }
-
- // check if there's existing lease for that subnet/duid/iaid combination.
- Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
- if (existing) {
- // we have a lease already. This is a returning client, probably after
- // his reboot.
- return (existing);
- }
+ try {
+ // That check is not necessary. We create allocator in AllocEngine
+ // constructor
+ if (!allocator_) {
+ isc_throw(InvalidOperation, "No allocator selected");
+ }
- // check if the hint is in pool and is available
- if (subnet->inPool(hint)) {
- existing = LeaseMgrFactory::instance().getLease6(hint);
- if (!existing) {
- /// @todo: check if the hint is reserved once we have host support
- /// implemented
+ // check if there's existing lease for that subnet/duid/iaid combination.
+ Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
+ if (existing) {
+ // we have a lease already. This is a returning client, probably after
+ // his reboot.
+ return (existing);
+ }
- // the hint is valid and not currently used, let's create a lease for it
- Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, fake_allocation);
+ // check if the hint is in pool and is available
+ if (subnet->inPool(hint)) {
+ existing = LeaseMgrFactory::instance().getLease6(hint);
+ if (!existing) {
+ /// @todo: check if the hint is reserved once we have host support
+ /// implemented
+
+ // the hint is valid and not currently used, let's create a lease for it
+ Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, fake_allocation);
+
+ // It can happen that the lease allocation failed (we could have lost
+ // the race condition. That means that the hint is lo longer usable and
+ // we need to continue the regular allocation path.
+ if (lease) {
+ return (lease);
+ }
+ } else {
+ if (existing->expired()) {
+ return (reuseExpiredLease(existing, subnet, duid, iaid,
+ fake_allocation));
+ }
- // It can happen that the lease allocation failed (we could have lost
- // the race condition. That means that the hint is lo longer usable and
- // we need to continue the regular allocation path.
- if (lease) {
- return (lease);
}
- } else {
- if (existing->expired()) {
- return (reuseExpiredLease(existing, subnet, duid, iaid,
- fake_allocation));
- }
-
}
- }
- // Hint is in the pool but is not available. Search the pool until first of
- // the following occurs:
- // - we find a free address
- // - we find an address for which the lease has expired
- // - we exhaust number of tries
- //
- // @todo: Current code does not handle pool exhaustion well. It will be
- // improved. Current problems:
- // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
- // 10 addresses), we will iterate over it 100 times before giving up
- // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
- // 3. the whole concept of infinite attempts is just asking for infinite loop
- // We may consider some form or reference counting (this pool has X addresses
- // left), but this has one major problem. We exactly control allocation
- // moment, but we currently do not control expiration time at all
-
- unsigned int i = attempts_;
- do {
- IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
-
- /// @todo: check if the address is reserved once we have host support
- /// implemented
-
- Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
- if (!existing) {
- // there's no existing lease for selected candidate, so it is
- // free. Let's allocate it.
- Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
- fake_allocation);
- if (lease) {
- return (lease);
- }
+ // Hint is in the pool but is not available. Search the pool until first of
+ // the following occurs:
+ // - we find a free address
+ // - we find an address for which the lease has expired
+ // - we exhaust number of tries
+ //
+ // @todo: Current code does not handle pool exhaustion well. It will be
+ // improved. Current problems:
+ // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
+ // 10 addresses), we will iterate over it 100 times before giving up
+ // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
+ // 3. the whole concept of infinite attempts is just asking for infinite loop
+ // We may consider some form or reference counting (this pool has X addresses
+ // left), but this has one major problem. We exactly control allocation
+ // moment, but we currently do not control expiration time at all
+
+ unsigned int i = attempts_;
+ do {
+ IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
+
+ /// @todo: check if the address is reserved once we have host support
+ /// implemented
- // Although the address was free just microseconds ago, it may have
- // been taken just now. If the lease insertion fails, we continue
- // allocation attempts.
- } else {
- if (existing->expired()) {
- return (reuseExpiredLease(existing, subnet, duid, iaid,
- fake_allocation));
+ Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
+ if (!existing) {
+ // there's no existing lease for selected candidate, so it is
+ // free. Let's allocate it.
+ Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
+ fake_allocation);
+ if (lease) {
+ return (lease);
+ }
+
+ // Although the address was free just microseconds ago, it may have
+ // been taken just now. If the lease insertion fails, we continue
+ // allocation attempts.
+ } else {
+ if (existing->expired()) {
+ return (reuseExpiredLease(existing, subnet, duid, iaid,
+ fake_allocation));
+ }
}
- }
- // continue trying allocation until we run out of attempts
- // (or attempts are set to 0, which means infinite)
- --i;
- } while ( i || !attempts_);
+ // Continue trying allocation until we run out of attempts
+ // (or attempts are set to 0, which means infinite)
+ --i;
+ } while ((i > 0) || !attempts_);
- isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
- << " tries");
+ // Unable to allocate an address, return an empty lease.
+ LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_FAIL).arg(attempts_);
+
+ } catch (const isc::Exception& e) {
+
+ // Some other error, return an empty lease.
+ LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_ERROR).arg(e.what());
+ }
+
+ return (Lease6Ptr());
}
Lease4Ptr
@@ -267,115 +277,123 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
const IOAddress& hint,
bool fake_allocation /* = false */ ) {
- // Allocator is always created in AllocEngine constructor and there is
- // currently no other way to set it, so that check is not really necessary.
- if (!allocator_) {
- isc_throw(InvalidOperation, "No allocator selected");
- }
-
- // Check if there's existing lease for that subnet/clientid/hwaddr combination.
- Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(hwaddr->hwaddr_, subnet->getID());
- if (existing) {
- // We have a lease already. This is a returning client, probably after
- // its reboot.
- existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
- if (existing) {
- return (existing);
+ try {
+ // Allocator is always created in AllocEngine constructor and there is
+ // currently no other way to set it, so that check is not really necessary.
+ if (!allocator_) {
+ isc_throw(InvalidOperation, "No allocator selected");
}
- // If renewal failed (e.g. the lease no longer matches current configuration)
- // let's continue the allocation process
- }
-
- if (clientid) {
- existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
+ // Check if there's existing lease for that subnet/clientid/hwaddr combination.
+ Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(hwaddr->hwaddr_, subnet->getID());
if (existing) {
- // we have a lease already. This is a returning client, probably after
+ // We have a lease already. This is a returning client, probably after
// its reboot.
existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
- // @todo: produce a warning. We haven't found him using MAC address, but
- // we found him using client-id
if (existing) {
return (existing);
}
+
+ // If renewal failed (e.g. the lease no longer matches current configuration)
+ // let's continue the allocation process
}
- }
- // check if the hint is in pool and is available
- if (subnet->inPool(hint)) {
- existing = LeaseMgrFactory::instance().getLease4(hint);
- if (!existing) {
- /// @todo: Check if the hint is reserved once we have host support
- /// implemented
+ if (clientid) {
+ existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
+ if (existing) {
+ // we have a lease already. This is a returning client, probably after
+ // its reboot.
+ existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
+ // @todo: produce a warning. We haven't found him using MAC address, but
+ // we found him using client-id
+ if (existing) {
+ return (existing);
+ }
+ }
+ }
- // The hint is valid and not currently used, let's create a lease for it
- Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, hint, fake_allocation);
+ // check if the hint is in pool and is available
+ if (subnet->inPool(hint)) {
+ existing = LeaseMgrFactory::instance().getLease4(hint);
+ if (!existing) {
+ /// @todo: Check if the hint is reserved once we have host support
+ /// implemented
+
+ // The hint is valid and not currently used, let's create a lease for it
+ Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, hint, fake_allocation);
+
+ // It can happen that the lease allocation failed (we could have lost
+ // the race condition. That means that the hint is lo longer usable and
+ // we need to continue the regular allocation path.
+ if (lease) {
+ return (lease);
+ }
+ } else {
+ if (existing->expired()) {
+ return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
+ fake_allocation));
+ }
- // It can happen that the lease allocation failed (we could have lost
- // the race condition. That means that the hint is lo longer usable and
- // we need to continue the regular allocation path.
- if (lease) {
- return (lease);
}
- } else {
- if (existing->expired()) {
- return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
- fake_allocation));
- }
-
}
- }
- // Hint is in the pool but is not available. Search the pool until first of
- // the following occurs:
- // - we find a free address
- // - we find an address for which the lease has expired
- // - we exhaust the number of tries
- //
- // @todo: Current code does not handle pool exhaustion well. It will be
- // improved. Current problems:
- // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
- // 10 addresses), we will iterate over it 100 times before giving up
- // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
- // 3. the whole concept of infinite attempts is just asking for infinite loop
- // We may consider some form or reference counting (this pool has X addresses
- // left), but this has one major problem. We exactly control allocation
- // moment, but we currently do not control expiration time at all
-
- unsigned int i = attempts_;
- do {
- IOAddress candidate = allocator_->pickAddress(subnet, clientid, hint);
-
- /// @todo: check if the address is reserved once we have host support
- /// implemented
-
- Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(candidate);
- if (!existing) {
- // there's no existing lease for selected candidate, so it is
- // free. Let's allocate it.
- Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, candidate,
- fake_allocation);
- if (lease) {
- return (lease);
- }
+ // Hint is in the pool but is not available. Search the pool until first of
+ // the following occurs:
+ // - we find a free address
+ // - we find an address for which the lease has expired
+ // - we exhaust the number of tries
+ //
+ // @todo: Current code does not handle pool exhaustion well. It will be
+ // improved. Current problems:
+ // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
+ // 10 addresses), we will iterate over it 100 times before giving up
+ // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
+ // 3. the whole concept of infinite attempts is just asking for infinite loop
+ // We may consider some form or reference counting (this pool has X addresses
+ // left), but this has one major problem. We exactly control allocation
+ // moment, but we currently do not control expiration time at all
+
+ unsigned int i = attempts_;
+ do {
+ IOAddress candidate = allocator_->pickAddress(subnet, clientid, hint);
+
+ /// @todo: check if the address is reserved once we have host support
+ /// implemented
- // Although the address was free just microseconds ago, it may have
- // been taken just now. If the lease insertion fails, we continue
- // allocation attempts.
- } else {
- if (existing->expired()) {
- return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
- fake_allocation));
+ Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(candidate);
+ if (!existing) {
+ // there's no existing lease for selected candidate, so it is
+ // free. Let's allocate it.
+ Lease4Ptr lease = createLease4(subnet, clientid, hwaddr, candidate,
+ fake_allocation);
+ if (lease) {
+ return (lease);
+ }
+
+ // Although the address was free just microseconds ago, it may have
+ // been taken just now. If the lease insertion fails, we continue
+ // allocation attempts.
+ } else {
+ if (existing->expired()) {
+ return (reuseExpiredLease(existing, subnet, clientid, hwaddr,
+ fake_allocation));
+ }
}
- }
- // Continue trying allocation until we run out of attempts
- // (or attempts are set to 0, which means infinite)
- --i;
- } while ( i || !attempts_);
+ // Continue trying allocation until we run out of attempts
+ // (or attempts are set to 0, which means infinite)
+ --i;
+ } while ((i > 0) || !attempts_);
- isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
- << " tries");
+ // Unable to allocate an address, return an empty lease.
+ LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_FAIL).arg(attempts_);
+
+ } catch (const isc::Exception& e) {
+
+ // Some other error, return an empty lease.
+ LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_ERROR).arg(e.what());
+ }
+ return (Lease4Ptr());
}
Lease4Ptr AllocEngine::renewLease4(const SubnetPtr& subnet,
diff --git a/src/lib/dhcpsrv/dhcpdb_create.mysql b/src/lib/dhcpsrv/dhcpdb_create.mysql
index 695091d..f0da337 100644
--- a/src/lib/dhcpsrv/dhcpdb_create.mysql
+++ b/src/lib/dhcpsrv/dhcpdb_create.mysql
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Internet Systems Consortium.
+# Copyright (C) 2012-2013 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
@@ -39,6 +39,14 @@ CREATE TABLE lease4 (
subnet_id INT UNSIGNED # Subnet identification
) ENGINE = INNODB;
+
+# Create search indexes for lease4 table
+# index by hwaddr and subnet_id
+CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id);
+
+# index by client_id and subnet_id
+CREATE INDEX lease4_by_client_id_subnet_id ON lease4 (client_id, subnet_id);
+
# Holds the IPv6 leases.
# N.B. The use of a VARCHAR for the address is temporary for development:
# it will eventually be replaced by BINARY(16).
@@ -55,6 +63,10 @@ CREATE TABLE lease6 (
prefix_len TINYINT UNSIGNED # For IA_PD only
) ENGINE = INNODB;
+# Create search indexes for lease4 table
+# index by iaid, subnet_id, and duid
+CREATE INDEX lease6_by_iaid_subnet_id_duid ON lease6 (iaid, subnet_id, duid);
+
# ... and a definition of lease6 types. This table is a convenience for
# users of the database - if they want to view the lease table and use the
# type names, they can join this table with the lease6 table
diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes
index bf4e1e1..a54577f 100644
--- a/src/lib/dhcpsrv/dhcpsrv_messages.mes
+++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes
@@ -14,6 +14,46 @@
$NAMESPACE isc::dhcp
+% DHCPSRV_ADDRESS4_ALLOC_ERROR error during attempt to allocate an IPv4 address: %1
+An error occurred during an attempt to allocate an IPv4 address, the
+reason for the failure being contained in the message. The server will
+return a message to the client refusing a lease.
+
+% DHCPSRV_ADDRESS4_ALLOC_FAIL failed to allocate an IPv4 address after %1 attempt(s)
+THE DHCP allocation engine gave up trying to allocate an IPv4 address
+after the specified number of attempts. This probably means that the
+address pool from which the allocation is being attempted is either
+empty, or very nearly empty. As a result, the client will have been
+refused a lease.
+
+This message may indicate that your address pool is too small for the
+number of clients you are trying to service and should be expanded.
+Alternatively, if the you know that the number of concurrently active
+clients is less than the addresses you have available, you may want to
+consider reducing the lease lifetime. In this way, addresses allocated
+to clients that are no longer active on the network will become available
+available sooner.
+
+% DHCPSRV_ADDRESS6_ALLOC_ERROR error during attempt to allocate an IPv6 address: %1
+An error occurred during an attempt to allocate an IPv6 address, the
+reason for the failure being contained in the message. The server will
+return a message to the client refusing a lease.
+
+% DHCPSRV_ADDRESS6_ALLOC_FAIL failed to allocate an IPv6 address after %1 attempt(s)
+The DHCP allocation engine gave up trying to allocate an IPv6 address
+after the specified number of attempts. This probably means that the
+address pool from which the allocation is being attempted is either
+empty, or very nearly empty. As a result, the client will have been
+refused a lease.
+
+This message may indicate that your address pool is too small for the
+number of clients you are trying to service and should be expanded.
+Alternatively, if the you know that the number of concurrently active
+clients is less than the addresses you have available, you may want to
+consider reducing the lease lifetime. In this way, addresses allocated
+to clients that are no longer active on the network will become available
+available sooner.
+
% DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1
A debug message reported when the DHCP configuration manager is adding the
specified IPv4 subnet to its database.
diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc
index 6608b14..2310dd4 100644
--- a/src/lib/dhcpsrv/lease_mgr.cc
+++ b/src/lib/dhcpsrv/lease_mgr.cc
@@ -113,11 +113,22 @@ Lease4::toText() const {
bool
Lease4::operator==(const Lease4& other) const {
+ if ( (client_id_ && !other.client_id_) ||
+ (!client_id_ && other.client_id_) ) {
+ // One lease has client-id, but the other doesn't
+ return false;
+ }
+
+ if (client_id_ && other.client_id_ &&
+ *client_id_ != *other.client_id_) {
+ // Different client-ids
+ return false;
+ }
+
return (
addr_ == other.addr_ &&
ext_ == other.ext_ &&
hwaddr_ == other.hwaddr_ &&
- *client_id_ == *other.client_id_ &&
t1_ == other.t1_ &&
t2_ == other.t2_ &&
valid_lft_ == other.valid_lft_ &&
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
index 292df61..6b6cde5 100644
--- a/src/lib/dhcpsrv/mysql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -338,12 +338,25 @@ public:
bind_[1].length = &hwaddr_length_;
// client_id: varbinary(128)
- client_id_ = lease_->client_id_->getClientId();
- client_id_length_ = client_id_.size();
- bind_[2].buffer_type = MYSQL_TYPE_BLOB;
- bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
- bind_[2].buffer_length = client_id_length_;
- bind_[2].length = &client_id_length_;
+ if (lease_->client_id_) {
+ client_id_ = lease_->client_id_->getClientId();
+ client_id_length_ = client_id_.size();
+ bind_[2].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
+ bind_[2].buffer_length = client_id_length_;
+ bind_[2].length = &client_id_length_;
+ } else {
+ bind_[2].buffer_type = MYSQL_TYPE_NULL;
+
+ // According to http://dev.mysql.com/doc/refman/5.5/en/
+ // c-api-prepared-statement-data-structures.html, the other
+ // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
+ // but let's set them to some sane values in case earlier versions
+ // didn't have that assumption.
+ static my_bool no_clientid = MLM_TRUE;
+ bind_[2].buffer = NULL;
+ bind_[2].is_null = &no_clientid;
+ }
// valid lifetime: unsigned int
bind_[3].buffer_type = MYSQL_TYPE_LONG;
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index 078998d..ddc0f62 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -461,9 +461,9 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
// There is just a single address in the pool and allocated it to someone
// else, so the allocation should fail
-
- EXPECT_THROW(engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),false),
- AllocFailed);
+ Lease6Ptr lease2 = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("::"), false);
+ EXPECT_FALSE(lease2);
}
// This test checks if an expired lease can be reused in SOLICIT (fake allocation)
@@ -838,8 +838,9 @@ TEST_F(AllocEngine4Test, outOfAddresses4) {
// There is just a single address in the pool and allocated it to someone
// else, so the allocation should fail
- EXPECT_THROW(engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),false),
- AllocFailed);
+ Lease4Ptr lease2 = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
+ IOAddress("0.0.0.0"), false);
+ EXPECT_FALSE(lease2);
}
// This test checks if an expired lease can be reused in DISCOVER (fake allocation)
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 286bd8c..bbf33ed 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -8,6 +8,10 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
CLEANFILES += rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc
+# These two are created with rrtype/class.h, so not explicitly listed in
+# BUILT_SOURCES.
+CLEANFILES += python/rrtype_constants_inc.cc
+CLEANFILES += python/rrclass_constants_inc.cc
EXTRA_DIST = rrclass-placeholder.h
EXTRA_DIST += rrparamregistry-placeholder.cc
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index ab2fa2e..b385bf4 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -46,9 +46,30 @@ new_rdata_factory_users = [('aaaa', 'in'),
('txt', 'generic')
]
-re_typecode = re.compile('([\da-z]+)_(\d+)')
+re_typecode = re.compile('([\da-z\-]+)_(\d+)')
classcode2txt = {}
typecode2txt = {}
+# For meta types and types well-known but not implemented. This is a dict from
+# type code values (as string) to textual mnemonic.
+meta_types = {
+ # Real meta types. We won't have Rdata implement for them, but we need
+ # RRType constants.
+ '251': 'ixfr', '252': 'axfr', '255': 'any',
+ # Obsolete types. We probalby won't implement Rdata for them, but it's
+ # better to have RRType constants.
+ '3': 'md', '4': 'mf', '7': 'mb', '8': 'mg', '9': 'mr', '30': 'nxt',
+ '38': 'a6', '254': 'maila',
+ # Types officially assigned but not yet supported in our implementation.
+ '10': 'null', '11': 'wks', '19': 'x25', '21': 'rt', '22': 'nsap',
+ '23': 'nsap-ptr', '24': 'sig', '20': 'isdn', '25': 'key', '26': 'px',
+ '27': 'gpos', '29': 'loc', '36': 'kx', '37': 'cert', '42': 'apl',
+ '45': 'ipseckey', '52': 'tlsa', '55': 'hip', '103': 'unspec',
+ '104': 'nid', '105': 'l32', '106': 'l64', '107': 'lp', '249': 'tkey',
+ '253': 'mailb', '256': 'uri', '257': 'caa'
+ }
+# Classes that don't have any known types. This is a dict from type code
+# values (as string) to textual mnemonic.
+meta_classes = {'254': 'none'}
typeandclass = []
generic_code = 65536 # something larger than any code value
rdata_declarations = ''
@@ -191,11 +212,11 @@ def import_definitions(classcode2txt, typecode2txt, typeandclass):
type_code = m.group(2)
if not type_code in typecode2txt:
typecode2txt[type_code] = type_txt
- if re.search('\cc$', file):
+ if re.search('\.cc$', file):
if rdatadef_mtime < getmtime(file):
rdatadef_mtime = getmtime(file)
class_definitions += import_classdef(class_txt, file)
- elif re.search('\h$', file):
+ elif re.search('\.h$', file):
if rdatahdr_mtime < getmtime(file):
rdatahdr_mtime = getmtime(file)
rdata_declarations += import_classheader(class_txt,
@@ -261,36 +282,66 @@ class MasterLoaderCallbacks;
def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
outputfile = '@builddir@/' + fileprefix + '.h'
+ py_outputfile = '@builddir@/python/' + fileprefix + '_constants_inc.cc'
upper_key = type_or_class.upper() # TYPE or CLASS
lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
cap_key = type_or_class # Type or Class
- if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+ # We only decide whether to generate files for libdns++ files; Python
+ # files are generated if and only if libdns++ files are generated.
+ # In practice it should be sufficient.
+ if (not need_generate(outputfile, basemtime) and
+ getmtime(outputfile) > getmtime(placeholder)):
print('skip generating ' + outputfile)
return
- declarationtxt = ''
- deftxt = ''
- for code in code2txt.keys():
- codetxt = code2txt[code].upper()
- declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
- deftxt += '''inline const RR''' + cap_key + '''&
-RR''' + cap_key + '''::''' + codetxt + '''() {
- static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
+ # Create a list of (code, code-text) pairs, where code-text is generally
+ # upper-cased, with applying speicial filters when necessary.
+ def convert(code_txt):
+ # Workaround by heuristics: there's a "NULL" RR type, but it would
+ # cause conflict with the C/C++ macro. We use Null as a special case.
+ if code_txt == 'null':
+ return 'Null'
+ # Likewise, convert "nsap-ptr" to "NSAP_PTR" as a dash cannot be part
+ # of a C/C++ variable.
+ if code_txt == 'nsap-ptr':
+ return 'NSAP_PTR'
+ return code_txt.upper()
+ codes = [ (code, convert(txt)) for code, txt in code2txt.items() ]
+
+ # Dump source code for libdns++
+ with open(placeholder, 'r') as header_temp:
+ with open(outputfile, 'w') as header_out:
+ header_out.write(heading_txt)
+ for line in header_temp:
+ header_out.write(line)
+ if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key +
+ '_DECLARATIONS$', line):
+ for code in codes:
+ header_out.write(' ' * 4 + 'static const RR' +
+ cap_key + '& ' + code[1] + '();\n')
+ if re.match('// BEGIN_WELL_KNOWN_' + upper_key +
+ '_DEFINITIONS$', line):
+ for code in codes:
+ header_out.write('''inline const RR''' + cap_key +
+ '''&
+RR''' + cap_key + '''::''' + code[1] + '''() {
+ static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code[0] + ''');
return (''' + lower_key + ''');
}\n
-'''
- header_temp = open(placeholder, 'r')
- header_out = open(outputfile, 'w')
- header_out.write(heading_txt)
- for line in header_temp.readlines():
- header_out.write(line)
- if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
- header_out.write(declarationtxt)
- if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
- header_out.write('\n' + deftxt)
- header_out.close()
- header_temp.close()
+''')
+
+ # Dump source code snippet for isc.dns Python module
+ with open(py_outputfile, 'w') as py_out:
+ py_out.write(" // auto-generated by ../gen-rdatacode.py."
+ " Don't edit this file.\n")
+ py_out.write("\n")
+ for code in codes:
+ py_out.write('''\
+ installClassVariable(''' + lower_key + '''_type, "''' + code[1] + '''",
+ createRR''' + cap_key + '''Object(RR''' + \
+ cap_key + '''::''' + code[1] + '''()));
+''')
def generate_rrparam(fileprefix, basemtime):
placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
@@ -337,6 +388,16 @@ def generate_rrparam(fileprefix, basemtime):
typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
+ typeandclassparams += indent + '// Meta and non-implemented RR types\n'
+ for type_code, type_txt in meta_types.items():
+ typeandclassparams += indent + \
+ 'addType("' + type_txt.upper() + '", ' + type_code + ');\n'
+
+ typeandclassparams += indent + '// Meta classes\n'
+ for cls_code, cls_txt in meta_classes.items():
+ typeandclassparams += indent + \
+ 'addClass("' + cls_txt.upper() + '", ' + cls_code + ');\n'
+
rrparam_temp = open(placeholder, 'r')
rrparam_out = open(outputfile, 'w')
rrparam_out.write(heading_txt)
@@ -353,9 +414,14 @@ if __name__ == "__main__":
generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
generate_rdatahdr('@builddir@/rdataclass.h', heading_txt,
rdata_declarations, rdatahdr_mtime)
- generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
+
+ # merge auto-generated types/classes with meta maps and generate the
+ # corresponding code.
+ generate_typeclasscode('rrtype', rdatahdr_mtime,
+ dict(typecode2txt, **meta_types), 'Type')
generate_typeclasscode('rrclass', classdir_mtime,
- classcode2txt, 'Class')
+ dict(classcode2txt, **meta_classes), 'Class')
+
generate_rrparam('rrparamregistry', rdatahdr_mtime)
except:
sys.stderr.write('Code generation failed due to exception: %s\n' %
diff --git a/src/lib/dns/master_loader.cc b/src/lib/dns/master_loader.cc
index 29e7e1d..1c822ea 100644
--- a/src/lib/dns/master_loader.cc
+++ b/src/lib/dns/master_loader.cc
@@ -54,6 +54,7 @@ public:
} // end unnamed namespace
+// cppcheck-suppress noConstructor
class MasterLoader::MasterLoaderImpl {
public:
MasterLoaderImpl(const char* master_file,
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index 079033a..ff00374 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -227,7 +227,6 @@ stringParse(Iterator s, Iterator send, bool downcase, Offsets& offsets,
isc_throw(BadLabelType,
"invalid label type in " << string(orig_s, send));
}
- state = ft_escape;
// FALLTHROUGH
case ft_escape:
if (!isdigit(c & 0xff)) {
diff --git a/src/lib/dns/python/opcode_python.cc b/src/lib/dns/python/opcode_python.cc
index 50436a9..8d40d9d 100644
--- a/src/lib/dns/python/opcode_python.cc
+++ b/src/lib/dns/python/opcode_python.cc
@@ -43,62 +43,12 @@ void Opcode_destroy(s_Opcode* const self);
PyObject* Opcode_getCode(const s_Opcode* const self);
PyObject* Opcode_toText(const s_Opcode* const self);
PyObject* Opcode_str(PyObject* self);
-PyObject* Opcode_QUERY(const s_Opcode* self);
-PyObject* Opcode_IQUERY(const s_Opcode* self);
-PyObject* Opcode_STATUS(const s_Opcode* self);
-PyObject* Opcode_RESERVED3(const s_Opcode* self);
-PyObject* Opcode_NOTIFY(const s_Opcode* self);
-PyObject* Opcode_UPDATE(const s_Opcode* self);
-PyObject* Opcode_RESERVED6(const s_Opcode* self);
-PyObject* Opcode_RESERVED7(const s_Opcode* self);
-PyObject* Opcode_RESERVED8(const s_Opcode* self);
-PyObject* Opcode_RESERVED9(const s_Opcode* self);
-PyObject* Opcode_RESERVED10(const s_Opcode* self);
-PyObject* Opcode_RESERVED11(const s_Opcode* self);
-PyObject* Opcode_RESERVED12(const s_Opcode* self);
-PyObject* Opcode_RESERVED13(const s_Opcode* self);
-PyObject* Opcode_RESERVED14(const s_Opcode* self);
-PyObject* Opcode_RESERVED15(const s_Opcode* self);
-PyObject* Opcode_richcmp(const s_Opcode* const self,
- const s_Opcode* const other, int op);
PyMethodDef Opcode_methods[] = {
{ "get_code", reinterpret_cast<PyCFunction>(Opcode_getCode), METH_NOARGS,
"Returns the code value" },
{ "to_text", reinterpret_cast<PyCFunction>(Opcode_toText), METH_NOARGS,
"Returns the text representation" },
- { "QUERY", reinterpret_cast<PyCFunction>(Opcode_QUERY),
- METH_NOARGS | METH_STATIC, "Creates a QUERY Opcode" },
- { "IQUERY", reinterpret_cast<PyCFunction>(Opcode_IQUERY),
- METH_NOARGS | METH_STATIC, "Creates a IQUERY Opcode" },
- { "STATUS", reinterpret_cast<PyCFunction>(Opcode_STATUS),
- METH_NOARGS | METH_STATIC, "Creates a STATUS Opcode" },
- { "RESERVED3", reinterpret_cast<PyCFunction>(Opcode_RESERVED3),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED3 Opcode" },
- { "NOTIFY", reinterpret_cast<PyCFunction>(Opcode_NOTIFY),
- METH_NOARGS | METH_STATIC, "Creates a NOTIFY Opcode" },
- { "UPDATE", reinterpret_cast<PyCFunction>(Opcode_UPDATE),
- METH_NOARGS | METH_STATIC, "Creates a UPDATE Opcode" },
- { "RESERVED6", reinterpret_cast<PyCFunction>(Opcode_RESERVED6),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED6 Opcode" },
- { "RESERVED7", reinterpret_cast<PyCFunction>(Opcode_RESERVED7),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED7 Opcode" },
- { "RESERVED8", reinterpret_cast<PyCFunction>(Opcode_RESERVED8),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED8 Opcode" },
- { "RESERVED9", reinterpret_cast<PyCFunction>(Opcode_RESERVED9),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED9 Opcode" },
- { "RESERVED10", reinterpret_cast<PyCFunction>(Opcode_RESERVED10),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED10 Opcode" },
- { "RESERVED11", reinterpret_cast<PyCFunction>(Opcode_RESERVED11),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED11 Opcode" },
- { "RESERVED12", reinterpret_cast<PyCFunction>(Opcode_RESERVED12),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED12 Opcode" },
- { "RESERVED13", reinterpret_cast<PyCFunction>(Opcode_RESERVED13),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED13 Opcode" },
- { "RESERVED14", reinterpret_cast<PyCFunction>(Opcode_RESERVED14),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED14 Opcode" },
- { "RESERVED15", reinterpret_cast<PyCFunction>(Opcode_RESERVED15),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED15 Opcode" },
{ NULL, NULL, 0, NULL }
};
@@ -156,96 +106,6 @@ Opcode_str(PyObject* self) {
}
PyObject*
-Opcode_createStatic(const Opcode& opcode) {
- s_Opcode* ret = PyObject_New(s_Opcode, &opcode_type);
- if (ret != NULL) {
- ret->cppobj = &opcode;
- ret->static_code = true;
- }
- return (ret);
-}
-
-PyObject*
-Opcode_QUERY(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::QUERY()));
-}
-
-PyObject*
-Opcode_IQUERY(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::IQUERY()));
-}
-
-PyObject*
-Opcode_STATUS(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::STATUS()));
-}
-
-PyObject*
-Opcode_RESERVED3(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED3()));
-}
-
-PyObject*
-Opcode_NOTIFY(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::NOTIFY()));
-}
-
-PyObject*
-Opcode_UPDATE(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::UPDATE()));
-}
-
-PyObject*
-Opcode_RESERVED6(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED6()));
-}
-
-PyObject*
-Opcode_RESERVED7(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED7()));
-}
-
-PyObject*
-Opcode_RESERVED8(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED8()));
-}
-
-PyObject*
-Opcode_RESERVED9(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED9()));
-}
-
-PyObject*
-Opcode_RESERVED10(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED10()));
-}
-
-PyObject*
-Opcode_RESERVED11(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED11()));
-}
-
-PyObject*
-Opcode_RESERVED12(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED12()));
-}
-
-PyObject*
-Opcode_RESERVED13(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED13()));
-}
-
-PyObject*
-Opcode_RESERVED14(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED14()));
-}
-
-PyObject*
-Opcode_RESERVED15(const s_Opcode*) {
- return (Opcode_createStatic(Opcode::RESERVED15()));
-}
-
-PyObject*
Opcode_richcmp(const s_Opcode* const self, const s_Opcode* const other,
const int op)
{
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index c75c737..30dc090 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -294,38 +294,83 @@ initModulePart_Opcode(PyObject* mod) {
return (false);
}
- addClassVariable(opcode_type, "QUERY_CODE",
- Py_BuildValue("h", Opcode::QUERY_CODE));
- addClassVariable(opcode_type, "IQUERY_CODE",
- Py_BuildValue("h", Opcode::IQUERY_CODE));
- addClassVariable(opcode_type, "STATUS_CODE",
- Py_BuildValue("h", Opcode::STATUS_CODE));
- addClassVariable(opcode_type, "RESERVED3_CODE",
- Py_BuildValue("h", Opcode::RESERVED3_CODE));
- addClassVariable(opcode_type, "NOTIFY_CODE",
- Py_BuildValue("h", Opcode::NOTIFY_CODE));
- addClassVariable(opcode_type, "UPDATE_CODE",
- Py_BuildValue("h", Opcode::UPDATE_CODE));
- addClassVariable(opcode_type, "RESERVED6_CODE",
- Py_BuildValue("h", Opcode::RESERVED6_CODE));
- addClassVariable(opcode_type, "RESERVED7_CODE",
- Py_BuildValue("h", Opcode::RESERVED7_CODE));
- addClassVariable(opcode_type, "RESERVED8_CODE",
- Py_BuildValue("h", Opcode::RESERVED8_CODE));
- addClassVariable(opcode_type, "RESERVED9_CODE",
- Py_BuildValue("h", Opcode::RESERVED9_CODE));
- addClassVariable(opcode_type, "RESERVED10_CODE",
- Py_BuildValue("h", Opcode::RESERVED10_CODE));
- addClassVariable(opcode_type, "RESERVED11_CODE",
- Py_BuildValue("h", Opcode::RESERVED11_CODE));
- addClassVariable(opcode_type, "RESERVED12_CODE",
- Py_BuildValue("h", Opcode::RESERVED12_CODE));
- addClassVariable(opcode_type, "RESERVED13_CODE",
- Py_BuildValue("h", Opcode::RESERVED13_CODE));
- addClassVariable(opcode_type, "RESERVED14_CODE",
- Py_BuildValue("h", Opcode::RESERVED14_CODE));
- addClassVariable(opcode_type, "RESERVED15_CODE",
- Py_BuildValue("h", Opcode::RESERVED15_CODE));
+ try {
+ installClassVariable(opcode_type, "QUERY_CODE",
+ Py_BuildValue("h", Opcode::QUERY_CODE));
+ installClassVariable(opcode_type, "IQUERY_CODE",
+ Py_BuildValue("h", Opcode::IQUERY_CODE));
+ installClassVariable(opcode_type, "STATUS_CODE",
+ Py_BuildValue("h", Opcode::STATUS_CODE));
+ installClassVariable(opcode_type, "RESERVED3_CODE",
+ Py_BuildValue("h", Opcode::RESERVED3_CODE));
+ installClassVariable(opcode_type, "NOTIFY_CODE",
+ Py_BuildValue("h", Opcode::NOTIFY_CODE));
+ installClassVariable(opcode_type, "UPDATE_CODE",
+ Py_BuildValue("h", Opcode::UPDATE_CODE));
+ installClassVariable(opcode_type, "RESERVED6_CODE",
+ Py_BuildValue("h", Opcode::RESERVED6_CODE));
+ installClassVariable(opcode_type, "RESERVED7_CODE",
+ Py_BuildValue("h", Opcode::RESERVED7_CODE));
+ installClassVariable(opcode_type, "RESERVED8_CODE",
+ Py_BuildValue("h", Opcode::RESERVED8_CODE));
+ installClassVariable(opcode_type, "RESERVED9_CODE",
+ Py_BuildValue("h", Opcode::RESERVED9_CODE));
+ installClassVariable(opcode_type, "RESERVED10_CODE",
+ Py_BuildValue("h", Opcode::RESERVED10_CODE));
+ installClassVariable(opcode_type, "RESERVED11_CODE",
+ Py_BuildValue("h", Opcode::RESERVED11_CODE));
+ installClassVariable(opcode_type, "RESERVED12_CODE",
+ Py_BuildValue("h", Opcode::RESERVED12_CODE));
+ installClassVariable(opcode_type, "RESERVED13_CODE",
+ Py_BuildValue("h", Opcode::RESERVED13_CODE));
+ installClassVariable(opcode_type, "RESERVED14_CODE",
+ Py_BuildValue("h", Opcode::RESERVED14_CODE));
+ installClassVariable(opcode_type, "RESERVED15_CODE",
+ Py_BuildValue("h", Opcode::RESERVED15_CODE));
+
+ installClassVariable(opcode_type, "QUERY",
+ createOpcodeObject(Opcode::QUERY()));
+ installClassVariable(opcode_type, "IQUERY",
+ createOpcodeObject(Opcode::IQUERY()));
+ installClassVariable(opcode_type, "STATUS",
+ createOpcodeObject(Opcode::STATUS()));
+ installClassVariable(opcode_type, "RESERVED3",
+ createOpcodeObject(Opcode::RESERVED3()));
+ installClassVariable(opcode_type, "NOTIFY",
+ createOpcodeObject(Opcode::NOTIFY()));
+ installClassVariable(opcode_type, "UPDATE",
+ createOpcodeObject(Opcode::UPDATE()));
+ installClassVariable(opcode_type, "RESERVED6",
+ createOpcodeObject(Opcode::RESERVED6()));
+ installClassVariable(opcode_type, "RESERVED7",
+ createOpcodeObject(Opcode::RESERVED7()));
+ installClassVariable(opcode_type, "RESERVED8",
+ createOpcodeObject(Opcode::RESERVED8()));
+ installClassVariable(opcode_type, "RESERVED9",
+ createOpcodeObject(Opcode::RESERVED9()));
+ installClassVariable(opcode_type, "RESERVED10",
+ createOpcodeObject(Opcode::RESERVED10()));
+ installClassVariable(opcode_type, "RESERVED11",
+ createOpcodeObject(Opcode::RESERVED11()));
+ installClassVariable(opcode_type, "RESERVED12",
+ createOpcodeObject(Opcode::RESERVED12()));
+ installClassVariable(opcode_type, "RESERVED13",
+ createOpcodeObject(Opcode::RESERVED13()));
+ installClassVariable(opcode_type, "RESERVED14",
+ createOpcodeObject(Opcode::RESERVED14()));
+ installClassVariable(opcode_type, "RESERVED15",
+ createOpcodeObject(Opcode::RESERVED15()));
+ } catch (const std::exception& ex) {
+ const std::string ex_what =
+ "Unexpected failure in Opcode initialization: " +
+ std::string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (false);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError,
+ "Unexpected failure in Opcode initialization");
+ return (false);
+ }
return (true);
}
@@ -341,40 +386,87 @@ initModulePart_Rcode(PyObject* mod) {
return (false);
}
- addClassVariable(rcode_type, "NOERROR_CODE",
- Py_BuildValue("h", Rcode::NOERROR_CODE));
- addClassVariable(rcode_type, "FORMERR_CODE",
- Py_BuildValue("h", Rcode::FORMERR_CODE));
- addClassVariable(rcode_type, "SERVFAIL_CODE",
- Py_BuildValue("h", Rcode::SERVFAIL_CODE));
- addClassVariable(rcode_type, "NXDOMAIN_CODE",
- Py_BuildValue("h", Rcode::NXDOMAIN_CODE));
- addClassVariable(rcode_type, "NOTIMP_CODE",
- Py_BuildValue("h", Rcode::NOTIMP_CODE));
- addClassVariable(rcode_type, "REFUSED_CODE",
- Py_BuildValue("h", Rcode::REFUSED_CODE));
- addClassVariable(rcode_type, "YXDOMAIN_CODE",
- Py_BuildValue("h", Rcode::YXDOMAIN_CODE));
- addClassVariable(rcode_type, "YXRRSET_CODE",
- Py_BuildValue("h", Rcode::YXRRSET_CODE));
- addClassVariable(rcode_type, "NXRRSET_CODE",
- Py_BuildValue("h", Rcode::NXRRSET_CODE));
- addClassVariable(rcode_type, "NOTAUTH_CODE",
- Py_BuildValue("h", Rcode::NOTAUTH_CODE));
- addClassVariable(rcode_type, "NOTZONE_CODE",
- Py_BuildValue("h", Rcode::NOTZONE_CODE));
- addClassVariable(rcode_type, "RESERVED11_CODE",
- Py_BuildValue("h", Rcode::RESERVED11_CODE));
- addClassVariable(rcode_type, "RESERVED12_CODE",
- Py_BuildValue("h", Rcode::RESERVED12_CODE));
- addClassVariable(rcode_type, "RESERVED13_CODE",
- Py_BuildValue("h", Rcode::RESERVED13_CODE));
- addClassVariable(rcode_type, "RESERVED14_CODE",
- Py_BuildValue("h", Rcode::RESERVED14_CODE));
- addClassVariable(rcode_type, "RESERVED15_CODE",
- Py_BuildValue("h", Rcode::RESERVED15_CODE));
- addClassVariable(rcode_type, "BADVERS_CODE",
- Py_BuildValue("h", Rcode::BADVERS_CODE));
+ try {
+ installClassVariable(rcode_type, "NOERROR_CODE",
+ Py_BuildValue("h", Rcode::NOERROR_CODE));
+ installClassVariable(rcode_type, "FORMERR_CODE",
+ Py_BuildValue("h", Rcode::FORMERR_CODE));
+ installClassVariable(rcode_type, "SERVFAIL_CODE",
+ Py_BuildValue("h", Rcode::SERVFAIL_CODE));
+ installClassVariable(rcode_type, "NXDOMAIN_CODE",
+ Py_BuildValue("h", Rcode::NXDOMAIN_CODE));
+ installClassVariable(rcode_type, "NOTIMP_CODE",
+ Py_BuildValue("h", Rcode::NOTIMP_CODE));
+ installClassVariable(rcode_type, "REFUSED_CODE",
+ Py_BuildValue("h", Rcode::REFUSED_CODE));
+ installClassVariable(rcode_type, "YXDOMAIN_CODE",
+ Py_BuildValue("h", Rcode::YXDOMAIN_CODE));
+ installClassVariable(rcode_type, "YXRRSET_CODE",
+ Py_BuildValue("h", Rcode::YXRRSET_CODE));
+ installClassVariable(rcode_type, "NXRRSET_CODE",
+ Py_BuildValue("h", Rcode::NXRRSET_CODE));
+ installClassVariable(rcode_type, "NOTAUTH_CODE",
+ Py_BuildValue("h", Rcode::NOTAUTH_CODE));
+ installClassVariable(rcode_type, "NOTZONE_CODE",
+ Py_BuildValue("h", Rcode::NOTZONE_CODE));
+ installClassVariable(rcode_type, "RESERVED11_CODE",
+ Py_BuildValue("h", Rcode::RESERVED11_CODE));
+ installClassVariable(rcode_type, "RESERVED12_CODE",
+ Py_BuildValue("h", Rcode::RESERVED12_CODE));
+ installClassVariable(rcode_type, "RESERVED13_CODE",
+ Py_BuildValue("h", Rcode::RESERVED13_CODE));
+ installClassVariable(rcode_type, "RESERVED14_CODE",
+ Py_BuildValue("h", Rcode::RESERVED14_CODE));
+ installClassVariable(rcode_type, "RESERVED15_CODE",
+ Py_BuildValue("h", Rcode::RESERVED15_CODE));
+ installClassVariable(rcode_type, "BADVERS_CODE",
+ Py_BuildValue("h", Rcode::BADVERS_CODE));
+
+ installClassVariable(rcode_type, "NOERROR",
+ createRcodeObject(Rcode::NOERROR()));
+ installClassVariable(rcode_type, "FORMERR",
+ createRcodeObject(Rcode::FORMERR()));
+ installClassVariable(rcode_type, "SERVFAIL",
+ createRcodeObject(Rcode::SERVFAIL()));
+ installClassVariable(rcode_type, "NXDOMAIN",
+ createRcodeObject(Rcode::NXDOMAIN()));
+ installClassVariable(rcode_type, "NOTIMP",
+ createRcodeObject(Rcode::NOTIMP()));
+ installClassVariable(rcode_type, "REFUSED",
+ createRcodeObject(Rcode::REFUSED()));
+ installClassVariable(rcode_type, "YXDOMAIN",
+ createRcodeObject(Rcode::YXDOMAIN()));
+ installClassVariable(rcode_type, "YXRRSET",
+ createRcodeObject(Rcode::YXRRSET()));
+ installClassVariable(rcode_type, "NXRRSET",
+ createRcodeObject(Rcode::NXRRSET()));
+ installClassVariable(rcode_type, "NOTAUTH",
+ createRcodeObject(Rcode::NOTAUTH()));
+ installClassVariable(rcode_type, "NOTZONE",
+ createRcodeObject(Rcode::NOTZONE()));
+ installClassVariable(rcode_type, "RESERVED11",
+ createRcodeObject(Rcode::RESERVED11()));
+ installClassVariable(rcode_type, "RESERVED12",
+ createRcodeObject(Rcode::RESERVED12()));
+ installClassVariable(rcode_type, "RESERVED13",
+ createRcodeObject(Rcode::RESERVED13()));
+ installClassVariable(rcode_type, "RESERVED14",
+ createRcodeObject(Rcode::RESERVED14()));
+ installClassVariable(rcode_type, "RESERVED15",
+ createRcodeObject(Rcode::RESERVED15()));
+ installClassVariable(rcode_type, "BADVERS",
+ createRcodeObject(Rcode::BADVERS()));
+ } catch (const std::exception& ex) {
+ const std::string ex_what =
+ "Unexpected failure in Rcode initialization: " +
+ std::string(ex.what());
+ PyErr_SetString(po_IscException, ex_what.c_str());
+ return (false);
+ } catch (...) {
+ PyErr_SetString(PyExc_SystemError,
+ "Unexpected failure in Rcode initialization");
+ return (false);
+ }
return (true);
}
@@ -432,6 +524,9 @@ initModulePart_RRClass(PyObject* mod) {
NULL, NULL);
PyObjectContainer(po_IncompleteRRClass).installToModule(
mod, "IncompleteRRClass");
+
+ // Incorporate auto-generated RRClass constants
+#include <dns/python/rrclass_constants_inc.cc>
} catch (const std::exception& ex) {
const std::string ex_what =
"Unexpected failure in RRClass initialization: " +
@@ -518,6 +613,9 @@ initModulePart_RRType(PyObject* mod) {
NULL, NULL);
PyObjectContainer(po_IncompleteRRType).installToModule(
mod, "IncompleteRRType");
+
+ // Incorporate auto-generated RRType constants
+#include <dns/python/rrtype_constants_inc.cc>
} catch (const std::exception& ex) {
const std::string ex_what =
"Unexpected failure in RRType initialization: " +
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
index 42b48e7..67b45e7 100644
--- a/src/lib/dns/python/rcode_python.cc
+++ b/src/lib/dns/python/rcode_python.cc
@@ -55,23 +55,6 @@ PyObject* Rcode_getCode(const s_Rcode* const self);
PyObject* Rcode_getExtendedCode(const s_Rcode* const self);
PyObject* Rcode_toText(const s_Rcode* const self);
PyObject* Rcode_str(PyObject* self);
-PyObject* Rcode_NOERROR(const s_Rcode* self);
-PyObject* Rcode_FORMERR(const s_Rcode* self);
-PyObject* Rcode_SERVFAIL(const s_Rcode* self);
-PyObject* Rcode_NXDOMAIN(const s_Rcode* self);
-PyObject* Rcode_NOTIMP(const s_Rcode* self);
-PyObject* Rcode_REFUSED(const s_Rcode* self);
-PyObject* Rcode_YXDOMAIN(const s_Rcode* self);
-PyObject* Rcode_YXRRSET(const s_Rcode* self);
-PyObject* Rcode_NXRRSET(const s_Rcode* self);
-PyObject* Rcode_NOTAUTH(const s_Rcode* self);
-PyObject* Rcode_NOTZONE(const s_Rcode* self);
-PyObject* Rcode_RESERVED11(const s_Rcode* self);
-PyObject* Rcode_RESERVED12(const s_Rcode* self);
-PyObject* Rcode_RESERVED13(const s_Rcode* self);
-PyObject* Rcode_RESERVED14(const s_Rcode* self);
-PyObject* Rcode_RESERVED15(const s_Rcode* self);
-PyObject* Rcode_BADVERS(const s_Rcode* self);
PyObject* Rcode_richcmp(const s_Rcode* const self,
const s_Rcode* const other, int op);
@@ -83,40 +66,6 @@ PyMethodDef Rcode_methods[] = {
"Returns the upper 8-bit part of the extended code value" },
{ "to_text", reinterpret_cast<PyCFunction>(Rcode_toText), METH_NOARGS,
"Returns the text representation" },
- { "NOERROR", reinterpret_cast<PyCFunction>(Rcode_NOERROR),
- METH_NOARGS | METH_STATIC, "Creates a NOERROR Rcode" },
- { "FORMERR", reinterpret_cast<PyCFunction>(Rcode_FORMERR),
- METH_NOARGS | METH_STATIC, "Creates a FORMERR Rcode" },
- { "SERVFAIL", reinterpret_cast<PyCFunction>(Rcode_SERVFAIL),
- METH_NOARGS | METH_STATIC, "Creates a SERVFAIL Rcode" },
- { "NXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_NXDOMAIN),
- METH_NOARGS | METH_STATIC, "Creates a NXDOMAIN Rcode" },
- { "NOTIMP", reinterpret_cast<PyCFunction>(Rcode_NOTIMP),
- METH_NOARGS | METH_STATIC, "Creates a NOTIMP Rcode" },
- { "REFUSED", reinterpret_cast<PyCFunction>(Rcode_REFUSED),
- METH_NOARGS | METH_STATIC, "Creates a REFUSED Rcode" },
- { "YXDOMAIN", reinterpret_cast<PyCFunction>(Rcode_YXDOMAIN),
- METH_NOARGS | METH_STATIC, "Creates a YXDOMAIN Rcode" },
- { "YXRRSET", reinterpret_cast<PyCFunction>(Rcode_YXRRSET),
- METH_NOARGS | METH_STATIC, "Creates a YYRRSET Rcode" },
- { "NXRRSET", reinterpret_cast<PyCFunction>(Rcode_NXRRSET),
- METH_NOARGS | METH_STATIC, "Creates a NXRRSET Rcode" },
- { "NOTAUTH", reinterpret_cast<PyCFunction>(Rcode_NOTAUTH),
- METH_NOARGS | METH_STATIC, "Creates a NOTAUTH Rcode" },
- { "NOTZONE", reinterpret_cast<PyCFunction>(Rcode_NOTZONE),
- METH_NOARGS | METH_STATIC, "Creates a NOTZONE Rcode" },
- { "RESERVED11", reinterpret_cast<PyCFunction>(Rcode_RESERVED11),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED11 Rcode" },
- { "RESERVED12", reinterpret_cast<PyCFunction>(Rcode_RESERVED12),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED12 Rcode" },
- { "RESERVED13", reinterpret_cast<PyCFunction>(Rcode_RESERVED13),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED13 Rcode" },
- { "RESERVED14", reinterpret_cast<PyCFunction>(Rcode_RESERVED14),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED14 Rcode" },
- { "RESERVED15", reinterpret_cast<PyCFunction>(Rcode_RESERVED15),
- METH_NOARGS | METH_STATIC, "Creates a RESERVED15 Rcode" },
- { "BADVERS", reinterpret_cast<PyCFunction>(Rcode_BADVERS),
- METH_NOARGS | METH_STATIC, "Creates a BADVERS Rcode" },
{ NULL, NULL, 0, NULL }
};
@@ -193,101 +142,6 @@ Rcode_str(PyObject* self) {
}
PyObject*
-Rcode_createStatic(const Rcode& rcode) {
- s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
- if (ret != NULL) {
- ret->cppobj = &rcode;
- ret->static_code = true;
- }
- return (ret);
-}
-
-PyObject*
-Rcode_NOERROR(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NOERROR()));
-}
-
-PyObject*
-Rcode_FORMERR(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::FORMERR()));
-}
-
-PyObject*
-Rcode_SERVFAIL(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::SERVFAIL()));
-}
-
-PyObject*
-Rcode_NXDOMAIN(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NXDOMAIN()));
-}
-
-PyObject*
-Rcode_NOTIMP(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NOTIMP()));
-}
-
-PyObject*
-Rcode_REFUSED(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::REFUSED()));
-}
-
-PyObject*
-Rcode_YXDOMAIN(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::YXDOMAIN()));
-}
-
-PyObject*
-Rcode_YXRRSET(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::YXRRSET()));
-}
-
-PyObject*
-Rcode_NXRRSET(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NXRRSET()));
-}
-
-PyObject*
-Rcode_NOTAUTH(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NOTAUTH()));
-}
-
-PyObject*
-Rcode_NOTZONE(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::NOTZONE()));
-}
-
-PyObject*
-Rcode_RESERVED11(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::RESERVED11()));
-}
-
-PyObject*
-Rcode_RESERVED12(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::RESERVED12()));
-}
-
-PyObject*
-Rcode_RESERVED13(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::RESERVED13()));
-}
-
-PyObject*
-Rcode_RESERVED14(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::RESERVED14()));
-}
-
-PyObject*
-Rcode_RESERVED15(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::RESERVED15()));
-}
-
-PyObject*
-Rcode_BADVERS(const s_Rcode*) {
- return (Rcode_createStatic(Rcode::BADVERS()));
-}
-
-PyObject*
Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
const int op)
{
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index a566f47..d62c88d 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -54,13 +54,6 @@ PyObject* RRClass_getCode(s_RRClass* self);
PyObject* RRClass_richcmp(s_RRClass* self, s_RRClass* other, int op);
Py_hash_t RRClass_hash(PyObject* pyself);
-// Static function for direct class creation
-PyObject* RRClass_IN(s_RRClass *self);
-PyObject* RRClass_CH(s_RRClass *self);
-PyObject* RRClass_HS(s_RRClass *self);
-PyObject* RRClass_NONE(s_RRClass *self);
-PyObject* RRClass_ANY(s_RRClass *self);
-
typedef CPPPyObjectContainer<s_RRClass, RRClass> RRClassContainer;
// This list contains the actual set of functions we have in
@@ -81,11 +74,6 @@ PyMethodDef RRClass_methods[] = {
"returned" },
{ "get_code", reinterpret_cast<PyCFunction>(RRClass_getCode), METH_NOARGS,
"Returns the class code as an integer" },
- { "IN", reinterpret_cast<PyCFunction>(RRClass_IN), METH_NOARGS | METH_STATIC, "Creates an IN RRClass" },
- { "CH", reinterpret_cast<PyCFunction>(RRClass_CH), METH_NOARGS | METH_STATIC, "Creates a CH RRClass" },
- { "HS", reinterpret_cast<PyCFunction>(RRClass_HS), METH_NOARGS | METH_STATIC, "Creates an HS RRClass" },
- { "NONE", reinterpret_cast<PyCFunction>(RRClass_NONE), METH_NOARGS | METH_STATIC, "Creates a NONE RRClass" },
- { "ANY", reinterpret_cast<PyCFunction>(RRClass_ANY), METH_NOARGS | METH_STATIC, "Creates an ANY RRClass" },
{ NULL, NULL, 0, NULL }
};
@@ -234,37 +222,6 @@ RRClass_richcmp(s_RRClass* self, s_RRClass* other, int op) {
Py_RETURN_FALSE;
}
-//
-// Common function for RRClass_IN/CH/etc.
-//
-PyObject* RRClass_createStatic(RRClass stc) {
- s_RRClass* ret = PyObject_New(s_RRClass, &rrclass_type);
- if (ret != NULL) {
- ret->cppobj = new RRClass(stc);
- }
- return (ret);
-}
-
-PyObject* RRClass_IN(s_RRClass*) {
- return (RRClass_createStatic(RRClass::IN()));
-}
-
-PyObject* RRClass_CH(s_RRClass*) {
- return (RRClass_createStatic(RRClass::CH()));
-}
-
-PyObject* RRClass_HS(s_RRClass*) {
- return (RRClass_createStatic(RRClass::HS()));
-}
-
-PyObject* RRClass_NONE(s_RRClass*) {
- return (RRClass_createStatic(RRClass::NONE()));
-}
-
-PyObject* RRClass_ANY(s_RRClass*) {
- return (RRClass_createStatic(RRClass::ANY()));
-}
-
Py_hash_t
RRClass_hash(PyObject* pyself) {
const s_RRClass* const self = static_cast<s_RRClass*>(pyself);
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index 97b66d4..bf705cc 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -50,25 +50,6 @@ PyObject* RRType_toWire(s_RRType* self, PyObject* args);
PyObject* RRType_getCode(s_RRType* self);
PyObject* RRType_richcmp(s_RRType* self, s_RRType* other, int op);
Py_hash_t RRType_hash(PyObject* pyself);
-PyObject* RRType_NSEC3PARAM(s_RRType *self);
-PyObject* RRType_DNAME(s_RRType *self);
-PyObject* RRType_PTR(s_RRType *self);
-PyObject* RRType_MX(s_RRType *self);
-PyObject* RRType_DNSKEY(s_RRType *self);
-PyObject* RRType_TXT(s_RRType *self);
-PyObject* RRType_RRSIG(s_RRType *self);
-PyObject* RRType_NSEC(s_RRType *self);
-PyObject* RRType_AAAA(s_RRType *self);
-PyObject* RRType_DS(s_RRType *self);
-PyObject* RRType_OPT(s_RRType *self);
-PyObject* RRType_A(s_RRType *self);
-PyObject* RRType_NS(s_RRType *self);
-PyObject* RRType_CNAME(s_RRType *self);
-PyObject* RRType_SOA(s_RRType *self);
-PyObject* RRType_NSEC3(s_RRType *self);
-PyObject* RRType_IXFR(s_RRType *self);
-PyObject* RRType_AXFR(s_RRType *self);
-PyObject* RRType_ANY(s_RRType *self);
typedef CPPPyObjectContainer<s_RRType, RRType> RRTypeContainer;
@@ -90,25 +71,6 @@ PyMethodDef RRType_methods[] = {
"returned" },
{ "get_code", reinterpret_cast<PyCFunction>(RRType_getCode), METH_NOARGS,
"Returns the type code as an integer" },
- { "NSEC3PARAM", reinterpret_cast<PyCFunction>(RRType_NSEC3PARAM), METH_NOARGS | METH_STATIC, "Creates an NSEC3PARAM RRType" },
- { "DNAME", reinterpret_cast<PyCFunction>(RRType_DNAME), METH_NOARGS | METH_STATIC, "Creates a DNAME RRType" },
- { "PTR", reinterpret_cast<PyCFunction>(RRType_PTR), METH_NOARGS | METH_STATIC, "Creates a PTR RRType" },
- { "MX", reinterpret_cast<PyCFunction>(RRType_MX), METH_NOARGS | METH_STATIC, "Creates an MX RRType" },
- { "DNSKEY", reinterpret_cast<PyCFunction>(RRType_DNSKEY), METH_NOARGS | METH_STATIC, "Creates a DNSKEY RRType" },
- { "TXT", reinterpret_cast<PyCFunction>(RRType_TXT), METH_NOARGS | METH_STATIC, "Creates a TXT RRType" },
- { "RRSIG", reinterpret_cast<PyCFunction>(RRType_RRSIG), METH_NOARGS | METH_STATIC, "Creates a RRSIG RRType" },
- { "NSEC", reinterpret_cast<PyCFunction>(RRType_NSEC), METH_NOARGS | METH_STATIC, "Creates a NSEC RRType" },
- { "AAAA", reinterpret_cast<PyCFunction>(RRType_AAAA), METH_NOARGS | METH_STATIC, "Creates an AAAA RRType" },
- { "DS", reinterpret_cast<PyCFunction>(RRType_DS), METH_NOARGS | METH_STATIC, "Creates a DS RRType" },
- { "OPT", reinterpret_cast<PyCFunction>(RRType_OPT), METH_NOARGS | METH_STATIC, "Creates an OPT RRType" },
- { "A", reinterpret_cast<PyCFunction>(RRType_A), METH_NOARGS | METH_STATIC, "Creates an A RRType" },
- { "NS", reinterpret_cast<PyCFunction>(RRType_NS), METH_NOARGS | METH_STATIC, "Creates an NS RRType" },
- { "CNAME", reinterpret_cast<PyCFunction>(RRType_CNAME), METH_NOARGS | METH_STATIC, "Creates a CNAME RRType" },
- { "SOA", reinterpret_cast<PyCFunction>(RRType_SOA), METH_NOARGS | METH_STATIC, "Creates a SOA RRType" },
- { "NSEC3", reinterpret_cast<PyCFunction>(RRType_NSEC3), METH_NOARGS | METH_STATIC, "Creates an NSEC3 RRType" },
- { "IXFR", reinterpret_cast<PyCFunction>(RRType_IXFR), METH_NOARGS | METH_STATIC, "Creates an IXFR RRType" },
- { "AXFR", reinterpret_cast<PyCFunction>(RRType_AXFR), METH_NOARGS | METH_STATIC, "Creates an AXFR RRType" },
- { "ANY", reinterpret_cast<PyCFunction>(RRType_ANY), METH_NOARGS | METH_STATIC, "Creates an ANY RRType" },
{ NULL, NULL, 0, NULL }
};
@@ -263,112 +225,6 @@ RRType_richcmp(s_RRType* self, s_RRType* other, int op) {
Py_RETURN_FALSE;
}
-//
-// Common function for RRType_A/NS/etc.
-//
-PyObject* RRType_createStatic(RRType stc) {
- s_RRType* ret = PyObject_New(s_RRType, &rrtype_type);
- if (ret != NULL) {
- ret->cppobj = new RRType(stc);
- }
- return (ret);
-}
-
-PyObject*
-RRType_NSEC3PARAM(s_RRType*) {
- return (RRType_createStatic(RRType::NSEC3PARAM()));
-}
-
-PyObject*
-RRType_DNAME(s_RRType*) {
- return (RRType_createStatic(RRType::DNAME()));
-}
-
-PyObject*
-RRType_PTR(s_RRType*) {
- return (RRType_createStatic(RRType::PTR()));
-}
-
-PyObject*
-RRType_MX(s_RRType*) {
- return (RRType_createStatic(RRType::MX()));
-}
-
-PyObject*
-RRType_DNSKEY(s_RRType*) {
- return (RRType_createStatic(RRType::DNSKEY()));
-}
-
-PyObject*
-RRType_TXT(s_RRType*) {
- return (RRType_createStatic(RRType::TXT()));
-}
-
-PyObject*
-RRType_RRSIG(s_RRType*) {
- return (RRType_createStatic(RRType::RRSIG()));
-}
-
-PyObject*
-RRType_NSEC(s_RRType*) {
- return (RRType_createStatic(RRType::NSEC()));
-}
-
-PyObject*
-RRType_AAAA(s_RRType*) {
- return (RRType_createStatic(RRType::AAAA()));
-}
-
-PyObject*
-RRType_DS(s_RRType*) {
- return (RRType_createStatic(RRType::DS()));
-}
-
-PyObject*
-RRType_OPT(s_RRType*) {
- return (RRType_createStatic(RRType::OPT()));
-}
-
-PyObject*
-RRType_A(s_RRType*) {
- return (RRType_createStatic(RRType::A()));
-}
-
-PyObject*
-RRType_NS(s_RRType*) {
- return (RRType_createStatic(RRType::NS()));
-}
-
-PyObject*
-RRType_CNAME(s_RRType*) {
- return (RRType_createStatic(RRType::CNAME()));
-}
-
-PyObject*
-RRType_SOA(s_RRType*) {
- return (RRType_createStatic(RRType::SOA()));
-}
-
-PyObject*
-RRType_NSEC3(s_RRType*) {
- return (RRType_createStatic(RRType::NSEC3()));
-}
-
-PyObject*
-RRType_IXFR(s_RRType*) {
- return (RRType_createStatic(RRType::IXFR()));
-}
-
-PyObject*
-RRType_AXFR(s_RRType*) {
- return (RRType_createStatic(RRType::AXFR()));
-}
-
-PyObject*
-RRType_ANY(s_RRType*) {
- return (RRType_createStatic(RRType::ANY()));
-}
-
Py_hash_t
RRType_hash(PyObject* pyself) {
const s_RRType* const self = static_cast<s_RRType*>(pyself);
diff --git a/src/lib/dns/python/tests/edns_python_test.py b/src/lib/dns/python/tests/edns_python_test.py
index b249213..150dfd6 100644
--- a/src/lib/dns/python/tests/edns_python_test.py
+++ b/src/lib/dns/python/tests/edns_python_test.py
@@ -108,8 +108,8 @@ class EDNSTest(unittest.TestCase):
def test_towire_renderer(self):
renderer = MessageRenderer()
- extrcode_noerror = Rcode.NOERROR().get_extended_code()
- extrcode_badvers = Rcode.BADVERS().get_extended_code()
+ extrcode_noerror = Rcode.NOERROR.get_extended_code()
+ extrcode_badvers = Rcode.BADVERS.get_extended_code()
self.assertEqual(1, self.edns_base.to_wire(renderer, extrcode_noerror))
wiredata = read_wire_data("edns_toWire1.wire")
@@ -148,7 +148,7 @@ class EDNSTest(unittest.TestCase):
self.assertEqual(0, renderer.get_length())
def test_towire_buffer(self):
- extrcode_noerror = Rcode.NOERROR().get_extended_code()
+ extrcode_noerror = Rcode.NOERROR.get_extended_code()
obuffer = bytes()
obuffer = self.edns_base.to_wire(obuffer, extrcode_noerror)
diff --git a/src/lib/dns/python/tests/message_python_test.py b/src/lib/dns/python/tests/message_python_test.py
index b9c0d5c..bf39a83 100644
--- a/src/lib/dns/python/tests/message_python_test.py
+++ b/src/lib/dns/python/tests/message_python_test.py
@@ -59,8 +59,8 @@ LONG_TXT4 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef012
def create_message():
message_render = Message(Message.RENDER)
message_render.set_qid(0x1035)
- message_render.set_opcode(Opcode.QUERY())
- message_render.set_rcode(Rcode.NOERROR())
+ message_render.set_opcode(Opcode.QUERY)
+ message_render.set_rcode(Rcode.NOERROR)
message_render.set_header_flag(Message.HEADERFLAG_QR)
message_render.set_header_flag(Message.HEADERFLAG_RD)
message_render.set_header_flag(Message.HEADERFLAG_AA)
@@ -161,7 +161,7 @@ class MessageTest(unittest.TestCase):
def test_set_rcode(self):
self.assertRaises(TypeError, self.r.set_rcode, "wrong")
- rcode = Rcode.BADVERS()
+ rcode = Rcode.BADVERS
self.r.set_rcode(rcode)
self.assertEqual(rcode, self.r.get_rcode())
@@ -173,7 +173,7 @@ class MessageTest(unittest.TestCase):
def test_set_opcode(self):
self.assertRaises(TypeError, self.r.set_opcode, "wrong")
- opcode = Opcode.IQUERY()
+ opcode = Opcode.IQUERY
self.r.set_opcode(opcode)
self.assertEqual(opcode, self.r.get_opcode())
@@ -304,8 +304,8 @@ class MessageTest(unittest.TestCase):
self.assertRaises(TypeError, self.r.clear, 3)
def test_clear_question_section(self):
- self.r.add_question(Question(Name("www.example.com"), RRClass.IN(),
- RRType.A()))
+ self.r.add_question(Question(Name("www.example.com"), RRClass.IN,
+ RRType.A))
self.assertEqual(1, self.r.get_rr_count(Message.SECTION_QUESTION))
self.r.clear_section(Message.SECTION_QUESTION)
self.assertEqual(0, self.r.get_rr_count(Message.SECTION_QUESTION))
@@ -336,19 +336,19 @@ class MessageTest(unittest.TestCase):
renderer.get_data())
def test_to_wire_without_opcode(self):
- self.r.set_rcode(Rcode.NOERROR())
+ self.r.set_rcode(Rcode.NOERROR)
self.assertRaises(InvalidMessageOperation, self.r.to_wire,
MessageRenderer())
def test_to_wire_without_rcode(self):
- self.r.set_opcode(Opcode.QUERY())
+ self.r.set_opcode(Opcode.QUERY)
self.assertRaises(InvalidMessageOperation, self.r.to_wire,
MessageRenderer())
def __common_tsigmessage_setup(self, flags=[Message.HEADERFLAG_RD],
rrtype=RRType("A"), answer_data=None):
- self.r.set_opcode(Opcode.QUERY())
- self.r.set_rcode(Rcode.NOERROR())
+ self.r.set_opcode(Opcode.QUERY)
+ self.r.set_rcode(Rcode.NOERROR)
for flag in flags:
self.r.set_header_flag(flag)
if answer_data is not None:
@@ -407,8 +407,8 @@ class MessageTest(unittest.TestCase):
self.__common_tsig_checks("message_toWire4.wire")
def test_to_wire_tsig_truncation3(self):
- self.r.set_opcode(Opcode.QUERY())
- self.r.set_rcode(Rcode.NOERROR())
+ self.r.set_opcode(Opcode.QUERY)
+ self.r.set_rcode(Rcode.NOERROR)
for i in range(1, 68):
self.r.add_question(Question(Name("www.example.com"),
RRClass("IN"), RRType(i)))
@@ -469,11 +469,11 @@ test.example.com. 3600 IN A 192.0.2.2
self.assertEqual(msg_str, str(message_render))
def test_to_text_without_opcode(self):
- self.r.set_rcode(Rcode.NOERROR())
+ self.r.set_rcode(Rcode.NOERROR)
self.assertRaises(InvalidMessageOperation, self.r.to_text)
def test_to_text_without_rcode(self):
- self.r.set_opcode(Opcode.QUERY())
+ self.r.set_opcode(Opcode.QUERY)
self.assertRaises(InvalidMessageOperation, self.r.to_text)
def test_from_wire(self):
@@ -488,8 +488,8 @@ test.example.com. 3600 IN A 192.0.2.2
message_parse = Message(0)
factoryFromFile(message_parse, "message_fromWire1")
self.assertEqual(0x1035, message_parse.get_qid())
- self.assertEqual(Opcode.QUERY(), message_parse.get_opcode())
- self.assertEqual(Rcode.NOERROR(), message_parse.get_rcode())
+ self.assertEqual(Opcode.QUERY, message_parse.get_opcode())
+ self.assertEqual(Rcode.NOERROR, message_parse.get_rcode())
self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_QR))
self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_RD))
self.assertTrue(message_parse.get_header_flag(Message.HEADERFLAG_AA))
@@ -568,7 +568,7 @@ test.example.com. 3600 IN A 192.0.2.2
# Extended Rcode = BADVERS
message_parse = Message(Message.PARSE)
factoryFromFile(message_parse, "message_fromWire10.wire")
- self.assertEqual(Rcode.BADVERS(), message_parse.get_rcode())
+ self.assertEqual(Rcode.BADVERS, message_parse.get_rcode())
# Maximum extended Rcode
message_parse.clear(Message.PARSE)
diff --git a/src/lib/dns/python/tests/messagerenderer_python_test.py b/src/lib/dns/python/tests/messagerenderer_python_test.py
index 5362496..8d5f26f 100644
--- a/src/lib/dns/python/tests/messagerenderer_python_test.py
+++ b/src/lib/dns/python/tests/messagerenderer_python_test.py
@@ -31,8 +31,8 @@ class MessageRendererTest(unittest.TestCase):
message = Message(Message.RENDER)
message.set_qid(123)
- message.set_opcode(Opcode.QUERY())
- message.set_rcode(Rcode.NOERROR())
+ message.set_opcode(Opcode.QUERY)
+ message.set_rcode(Rcode.NOERROR)
message.add_question(Question(name, c, t))
self.message1 = message
@@ -40,8 +40,8 @@ class MessageRendererTest(unittest.TestCase):
message.set_qid(123)
message.set_header_flag(Message.HEADERFLAG_AA, True)
message.set_header_flag(Message.HEADERFLAG_QR, True)
- message.set_opcode(Opcode.QUERY())
- message.set_rcode(Rcode.NOERROR())
+ message.set_opcode(Opcode.QUERY)
+ message.set_rcode(Rcode.NOERROR)
message.add_question(Question(name, c, t))
rrset = RRset(name, c, t, ttl)
rrset.add_rdata(Rdata(t, c, "192.0.2.98"))
diff --git a/src/lib/dns/python/tests/nsec3hash_python_test.py b/src/lib/dns/python/tests/nsec3hash_python_test.py
index 1a247d0..320529a 100644
--- a/src/lib/dns/python/tests/nsec3hash_python_test.py
+++ b/src/lib/dns/python/tests/nsec3hash_python_test.py
@@ -24,9 +24,9 @@ class NSEC3HashTest(unittest.TestCase):
def setUp(self):
self.nsec3_common = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"
- self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM, RRClass.IN,
"1 0 12 aabbccdd"))
- self.test_hash_nsec3 = NSEC3Hash(Rdata(RRType.NSEC3(), RRClass.IN(),
+ self.test_hash_nsec3 = NSEC3Hash(Rdata(RRType.NSEC3, RRClass.IN,
"1 0 12 aabbccdd " +
self.nsec3_common))
def test_bad_construct(self):
@@ -37,20 +37,20 @@ class NSEC3HashTest(unittest.TestCase):
self.assertRaises(TypeError, NSEC3Hash, "1 0 12 aabbccdd")
# additional parameter
- self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.NSEC3PARAM(),
- RRClass.IN(),
+ self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.NSEC3PARAM,
+ RRClass.IN,
"1 0 12 aabbccdd"), 1)
# Invaid type of RDATA
- self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.A(), RRClass.IN(),
+ self.assertRaises(TypeError, NSEC3Hash, Rdata(RRType.A, RRClass.IN,
"192.0.2.1"))
def test_unknown_algorithm(self):
self.assertRaises(UnknownNSEC3HashAlgorithm, NSEC3Hash,
- Rdata(RRType.NSEC3PARAM(), RRClass.IN(),
+ Rdata(RRType.NSEC3PARAM, RRClass.IN,
"2 0 12 aabbccdd"))
self.assertRaises(UnknownNSEC3HashAlgorithm, NSEC3Hash,
- Rdata(RRType.NSEC3(), RRClass.IN(),
+ Rdata(RRType.NSEC3, RRClass.IN,
"2 0 12 aabbccdd " + self.nsec3_common))
def calculate_check(self, hash):
@@ -71,15 +71,15 @@ class NSEC3HashTest(unittest.TestCase):
# Using unusually large iterations, something larger than the 8-bit
#range. (expected hash value generated by BIND 9's dnssec-signzone)
- self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
- RRClass.IN(), "1 0 256 AABBCCDD"))
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM,
+ RRClass.IN, "1 0 256 AABBCCDD"))
self.assertEqual("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3",
self.test_hash.calculate(Name("example.org")))
# Some boundary cases: 0-iteration and empty salt. Borrowed from the
# .com zone data.
- self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM(),
- RRClass.IN(),"1 0 0 -"))
+ self.test_hash = NSEC3Hash(Rdata(RRType.NSEC3PARAM,
+ RRClass.IN,"1 0 0 -"))
self.assertEqual("CK0POJMG874LJREF7EFN8430QVIT8BSM",
self.test_hash.calculate(Name("com")))
@@ -90,39 +90,39 @@ class NSEC3HashTest(unittest.TestCase):
def check_match(self, hash, rrtype, postfix):
# If all parameters match, it's considered to be matched.
- self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN,
"1 0 12 aabbccdd" + postfix)))
# Algorithm doesn't match
- self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
"2 0 12 aabbccdd" + postfix)))
# Iterations doesn't match
- self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
"1 0 1 aabbccdd" + postfix)))
# Salt doesn't match
- self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
"1 0 12 aabbccde" + postfix)))
# Salt doesn't match: the other has an empty salt
- self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertFalse(hash.match(Rdata(rrtype, RRClass.IN,
"1 0 12 -" + postfix)))
# Flag doesn't matter
- self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN(),
+ self.assertTrue(hash.match(Rdata(rrtype, RRClass.IN,
"1 1 12 aabbccdd" + postfix)))
def test_match(self):
- self.check_match(self.test_hash, RRType.NSEC3(),
+ self.check_match(self.test_hash, RRType.NSEC3,
" " + self.nsec3_common)
- self.check_match(self.test_hash_nsec3, RRType.NSEC3(),
+ self.check_match(self.test_hash_nsec3, RRType.NSEC3,
" " + self.nsec3_common)
- self.check_match(self.test_hash, RRType.NSEC3PARAM(), "")
- self.check_match(self.test_hash_nsec3, RRType.NSEC3PARAM(), "")
+ self.check_match(self.test_hash, RRType.NSEC3PARAM, "")
+ self.check_match(self.test_hash_nsec3, RRType.NSEC3PARAM, "")
# bad parameter checks
self.assertRaises(TypeError, self.test_hash.match, 1)
self.assertRaises(TypeError, self.test_hash.match,
- Rdata(RRType.NSEC3(), RRClass.IN(),
+ Rdata(RRType.NSEC3, RRClass.IN,
"1 0 12 aabbccdd " + self.nsec3_common), 1)
self.assertRaises(TypeError, self.test_hash.match,
- Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
+ Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/python/tests/opcode_python_test.py b/src/lib/dns/python/tests/opcode_python_test.py
index 84f449f..d938aa6 100644
--- a/src/lib/dns/python/tests/opcode_python_test.py
+++ b/src/lib/dns/python/tests/opcode_python_test.py
@@ -34,53 +34,53 @@ class OpcodeTest(unittest.TestCase):
self.assertEqual(Opcode.UPDATE_CODE, Opcode(5).get_code())
self.assertEqual(Opcode.RESERVED15_CODE, Opcode(15).get_code())
- self.assertEqual(Opcode.QUERY_CODE, Opcode.QUERY().get_code())
- self.assertEqual(Opcode.IQUERY_CODE, Opcode.IQUERY().get_code())
- self.assertEqual(Opcode.NOTIFY_CODE, Opcode.NOTIFY().get_code())
- self.assertEqual(Opcode.UPDATE_CODE, Opcode.UPDATE().get_code())
- self.assertEqual(Opcode.RESERVED15_CODE, Opcode.RESERVED15().get_code())
+ self.assertEqual(Opcode.QUERY_CODE, Opcode.QUERY.get_code())
+ self.assertEqual(Opcode.IQUERY_CODE, Opcode.IQUERY.get_code())
+ self.assertEqual(Opcode.NOTIFY_CODE, Opcode.NOTIFY.get_code())
+ self.assertEqual(Opcode.UPDATE_CODE, Opcode.UPDATE.get_code())
+ self.assertEqual(Opcode.RESERVED15_CODE, Opcode.RESERVED15.get_code())
def test_get_code(self):
- self.assertEqual(0, Opcode.QUERY().get_code())
- self.assertEqual(1, Opcode.IQUERY().get_code())
- self.assertEqual(2, Opcode.STATUS().get_code())
- self.assertEqual(3, Opcode.RESERVED3().get_code())
- self.assertEqual(4, Opcode.NOTIFY().get_code())
- self.assertEqual(5, Opcode.UPDATE().get_code())
- self.assertEqual(6, Opcode.RESERVED6().get_code())
- self.assertEqual(7, Opcode.RESERVED7().get_code())
- self.assertEqual(8, Opcode.RESERVED8().get_code())
- self.assertEqual(9, Opcode.RESERVED9().get_code())
- self.assertEqual(10, Opcode.RESERVED10().get_code())
- self.assertEqual(11, Opcode.RESERVED11().get_code())
- self.assertEqual(12, Opcode.RESERVED12().get_code())
- self.assertEqual(13, Opcode.RESERVED13().get_code())
- self.assertEqual(14, Opcode.RESERVED14().get_code())
- self.assertEqual(15, Opcode.RESERVED15().get_code())
+ self.assertEqual(0, Opcode.QUERY.get_code())
+ self.assertEqual(1, Opcode.IQUERY.get_code())
+ self.assertEqual(2, Opcode.STATUS.get_code())
+ self.assertEqual(3, Opcode.RESERVED3.get_code())
+ self.assertEqual(4, Opcode.NOTIFY.get_code())
+ self.assertEqual(5, Opcode.UPDATE.get_code())
+ self.assertEqual(6, Opcode.RESERVED6.get_code())
+ self.assertEqual(7, Opcode.RESERVED7.get_code())
+ self.assertEqual(8, Opcode.RESERVED8.get_code())
+ self.assertEqual(9, Opcode.RESERVED9.get_code())
+ self.assertEqual(10, Opcode.RESERVED10.get_code())
+ self.assertEqual(11, Opcode.RESERVED11.get_code())
+ self.assertEqual(12, Opcode.RESERVED12.get_code())
+ self.assertEqual(13, Opcode.RESERVED13.get_code())
+ self.assertEqual(14, Opcode.RESERVED14.get_code())
+ self.assertEqual(15, Opcode.RESERVED15.get_code())
def test_to_text(self):
- self.assertEqual("QUERY", Opcode.QUERY().to_text())
- self.assertEqual("QUERY", str(Opcode.QUERY()))
- self.assertEqual("IQUERY", Opcode.IQUERY().to_text())
- self.assertEqual("STATUS", Opcode.STATUS().to_text())
- self.assertEqual("RESERVED3", Opcode.RESERVED3().to_text())
- self.assertEqual("NOTIFY", Opcode.NOTIFY().to_text())
- self.assertEqual("UPDATE", Opcode.UPDATE().to_text())
- self.assertEqual("RESERVED6", Opcode.RESERVED6().to_text())
- self.assertEqual("RESERVED7", Opcode.RESERVED7().to_text())
- self.assertEqual("RESERVED8", Opcode.RESERVED8().to_text())
- self.assertEqual("RESERVED9", Opcode.RESERVED9().to_text())
- self.assertEqual("RESERVED10", Opcode.RESERVED10().to_text())
- self.assertEqual("RESERVED11", Opcode.RESERVED11().to_text())
- self.assertEqual("RESERVED12", Opcode.RESERVED12().to_text())
- self.assertEqual("RESERVED13", Opcode.RESERVED13().to_text())
- self.assertEqual("RESERVED14", Opcode.RESERVED14().to_text())
- self.assertEqual("RESERVED15", Opcode.RESERVED15().to_text())
+ self.assertEqual("QUERY", Opcode.QUERY.to_text())
+ self.assertEqual("QUERY", str(Opcode.QUERY))
+ self.assertEqual("IQUERY", Opcode.IQUERY.to_text())
+ self.assertEqual("STATUS", Opcode.STATUS.to_text())
+ self.assertEqual("RESERVED3", Opcode.RESERVED3.to_text())
+ self.assertEqual("NOTIFY", Opcode.NOTIFY.to_text())
+ self.assertEqual("UPDATE", Opcode.UPDATE.to_text())
+ self.assertEqual("RESERVED6", Opcode.RESERVED6.to_text())
+ self.assertEqual("RESERVED7", Opcode.RESERVED7.to_text())
+ self.assertEqual("RESERVED8", Opcode.RESERVED8.to_text())
+ self.assertEqual("RESERVED9", Opcode.RESERVED9.to_text())
+ self.assertEqual("RESERVED10", Opcode.RESERVED10.to_text())
+ self.assertEqual("RESERVED11", Opcode.RESERVED11.to_text())
+ self.assertEqual("RESERVED12", Opcode.RESERVED12.to_text())
+ self.assertEqual("RESERVED13", Opcode.RESERVED13.to_text())
+ self.assertEqual("RESERVED14", Opcode.RESERVED14.to_text())
+ self.assertEqual("RESERVED15", Opcode.RESERVED15.to_text())
def test_richcmp(self):
- o1 = Opcode.QUERY()
- o2 = Opcode.NOTIFY()
- o3 = Opcode.NOTIFY()
+ o1 = Opcode.QUERY
+ o2 = Opcode.NOTIFY
+ o3 = Opcode.NOTIFY
self.assertTrue(o2 == o3)
self.assertFalse(o2 != o3)
self.assertTrue(o1 != o2)
diff --git a/src/lib/dns/python/tests/rcode_python_test.py b/src/lib/dns/python/tests/rcode_python_test.py
index 77fed3a..c4a8067 100644
--- a/src/lib/dns/python/tests/rcode_python_test.py
+++ b/src/lib/dns/python/tests/rcode_python_test.py
@@ -54,36 +54,36 @@ class RcodeTest(unittest.TestCase):
self.assertEqual(Rcode.RESERVED15_CODE, Rcode(15).get_code())
self.assertEqual(Rcode.BADVERS_CODE, Rcode(16).get_code())
- self.assertEqual(Rcode.NOERROR_CODE, Rcode.NOERROR().get_code())
- self.assertEqual(Rcode.FORMERR_CODE, Rcode.FORMERR().get_code())
- self.assertEqual(Rcode.NOTIMP_CODE, Rcode.NOTIMP().get_code())
- self.assertEqual(Rcode.REFUSED_CODE, Rcode.REFUSED().get_code())
- self.assertEqual(Rcode.RESERVED15_CODE, Rcode.RESERVED15().get_code())
- self.assertEqual(Rcode.BADVERS_CODE, Rcode.BADVERS().get_code())
+ self.assertEqual(Rcode.NOERROR_CODE, Rcode.NOERROR.get_code())
+ self.assertEqual(Rcode.FORMERR_CODE, Rcode.FORMERR.get_code())
+ self.assertEqual(Rcode.NOTIMP_CODE, Rcode.NOTIMP.get_code())
+ self.assertEqual(Rcode.REFUSED_CODE, Rcode.REFUSED.get_code())
+ self.assertEqual(Rcode.RESERVED15_CODE, Rcode.RESERVED15.get_code())
+ self.assertEqual(Rcode.BADVERS_CODE, Rcode.BADVERS.get_code())
def test_get_code(self):
- self.assertEqual(0, Rcode.NOERROR().get_code())
- self.assertEqual(1, Rcode.FORMERR().get_code())
- self.assertEqual(2, Rcode.SERVFAIL().get_code())
- self.assertEqual(3, Rcode.NXDOMAIN().get_code())
- self.assertEqual(4, Rcode.NOTIMP().get_code())
- self.assertEqual(5, Rcode.REFUSED().get_code())
- self.assertEqual(6, Rcode.YXDOMAIN().get_code())
- self.assertEqual(7, Rcode.YXRRSET().get_code())
- self.assertEqual(8, Rcode.NXRRSET().get_code())
- self.assertEqual(9, Rcode.NOTAUTH().get_code())
- self.assertEqual(10, Rcode.NOTZONE().get_code())
- self.assertEqual(11, Rcode.RESERVED11().get_code())
- self.assertEqual(12, Rcode.RESERVED12().get_code())
- self.assertEqual(13, Rcode.RESERVED13().get_code())
- self.assertEqual(14, Rcode.RESERVED14().get_code())
- self.assertEqual(15, Rcode.RESERVED15().get_code())
- self.assertEqual(16, Rcode.BADVERS().get_code())
+ self.assertEqual(0, Rcode.NOERROR.get_code())
+ self.assertEqual(1, Rcode.FORMERR.get_code())
+ self.assertEqual(2, Rcode.SERVFAIL.get_code())
+ self.assertEqual(3, Rcode.NXDOMAIN.get_code())
+ self.assertEqual(4, Rcode.NOTIMP.get_code())
+ self.assertEqual(5, Rcode.REFUSED.get_code())
+ self.assertEqual(6, Rcode.YXDOMAIN.get_code())
+ self.assertEqual(7, Rcode.YXRRSET.get_code())
+ self.assertEqual(8, Rcode.NXRRSET.get_code())
+ self.assertEqual(9, Rcode.NOTAUTH.get_code())
+ self.assertEqual(10, Rcode.NOTZONE.get_code())
+ self.assertEqual(11, Rcode.RESERVED11.get_code())
+ self.assertEqual(12, Rcode.RESERVED12.get_code())
+ self.assertEqual(13, Rcode.RESERVED13.get_code())
+ self.assertEqual(14, Rcode.RESERVED14.get_code())
+ self.assertEqual(15, Rcode.RESERVED15.get_code())
+ self.assertEqual(16, Rcode.BADVERS.get_code())
def test_get_extended_code(self):
- self.assertEqual(0, Rcode.NOERROR().get_extended_code())
- self.assertEqual(0, Rcode.YXRRSET().get_extended_code())
- self.assertEqual(1, Rcode.BADVERS().get_extended_code())
+ self.assertEqual(0, Rcode.NOERROR.get_extended_code())
+ self.assertEqual(0, Rcode.YXRRSET.get_extended_code())
+ self.assertEqual(1, Rcode.BADVERS.get_extended_code())
self.assertEqual(0xab, Rcode(0xabf).get_extended_code())
self.assertEqual(0xff, Rcode(0xfff).get_extended_code())
@@ -107,13 +107,13 @@ class RcodeTest(unittest.TestCase):
self.assertEqual("RESERVED15", Rcode(15).to_text())
self.assertEqual("BADVERS", Rcode(16).to_text())
- self.assertEqual("17", Rcode(Rcode.BADVERS().get_code() + 1).to_text())
+ self.assertEqual("17", Rcode(Rcode.BADVERS.get_code() + 1).to_text())
self.assertEqual("4095", Rcode(0xfff).to_text())
def test_richcmp(self):
- r1 = Rcode.NOERROR()
- r2 = Rcode.FORMERR()
- r3 = Rcode.FORMERR()
+ r1 = Rcode.NOERROR
+ r2 = Rcode.FORMERR
+ r3 = Rcode.FORMERR
self.assertTrue(r2 == r3)
self.assertTrue(r1 != r2)
self.assertFalse(r1 == r2)
diff --git a/src/lib/dns/python/tests/rrclass_python_test.py b/src/lib/dns/python/tests/rrclass_python_test.py
index a048c4c..880e331 100644
--- a/src/lib/dns/python/tests/rrclass_python_test.py
+++ b/src/lib/dns/python/tests/rrclass_python_test.py
@@ -23,8 +23,8 @@ from pydnspp import *
class RRClassTest(unittest.TestCase):
def setUp(self):
- self.c1 = RRClass.IN()
- self.c2 = RRClass.CH()
+ self.c1 = RRClass.IN
+ self.c2 = RRClass.CH
def test_init(self):
self.assertRaises(InvalidRRClass, RRClass, "wrong")
@@ -81,17 +81,17 @@ class RRClassTest(unittest.TestCase):
def test_hash(self):
# Exploiting the knowledge that the hash value is the numeric class
# value, we can predict the comparison result.
- self.assertEqual(hash(RRClass.IN()), hash(RRClass("IN")))
+ self.assertEqual(hash(RRClass.IN), hash(RRClass("IN")))
self.assertEqual(hash(RRClass("in")), hash(RRClass("IN")))
- self.assertNotEqual(hash(RRClass.IN()), hash(RRClass.CH()))
- self.assertNotEqual(hash(RRClass.IN()), hash(RRClass("CLASS65535")))
+ self.assertNotEqual(hash(RRClass.IN), hash(RRClass.CH))
+ self.assertNotEqual(hash(RRClass.IN), hash(RRClass("CLASS65535")))
def test_statics(self):
- self.assertEqual(RRClass.IN(), RRClass("IN"))
- self.assertEqual(RRClass.CH(), RRClass("CH"))
- self.assertEqual(RRClass.HS(), RRClass("HS"))
- self.assertEqual(254, RRClass.NONE().get_code())
- self.assertEqual(255, RRClass.ANY().get_code())
+ self.assertEqual(RRClass.IN, RRClass("IN"))
+ self.assertEqual(RRClass.CH, RRClass("CH"))
+ self.assertEqual(RRClass.HS, RRClass("HS"))
+ self.assertEqual(254, RRClass.NONE.get_code())
+ self.assertEqual(255, RRClass.ANY.get_code())
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/python/tests/rrset_collection_python_test.py b/src/lib/dns/python/tests/rrset_collection_python_test.py
index 2cf286e..1bbbc80 100644
--- a/src/lib/dns/python/tests/rrset_collection_python_test.py
+++ b/src/lib/dns/python/tests/rrset_collection_python_test.py
@@ -34,64 +34,64 @@ class RRsetCollectionTest(unittest.TestCase):
self.assertRaises(TypeError, RRsetCollection, 1)
self.assertRaises(TypeError, RRsetCollection, # extra arg
b'example. 0 A 192.0.2.1',
- Name('example'), RRClass.IN(), 1)
+ Name('example'), RRClass.IN, 1)
self.assertRaises(TypeError, RRsetCollection, # incorrect order
- b'example. 0 A 192.0.2.1', RRClass.IN(),
+ b'example. 0 A 192.0.2.1', RRClass.IN,
Name('example'))
# constructor will result in C++ exception.
self.assertRaises(IscException, RRsetCollection,
TESTDATA_DIR + '/no_such_file', Name('example.org'),
- RRClass.IN())
+ RRClass.IN)
def check_find_result(self, rrsets):
# Commonly used check pattern
- found = rrsets.find(Name('www.example.org'), RRClass.IN(), RRType.A())
+ found = rrsets.find(Name('www.example.org'), RRClass.IN, RRType.A)
self.assertNotEqual(None, found)
self.assertEqual(Name('www.example.org'), found.get_name())
- self.assertEqual(RRClass.IN(), found.get_class())
- self.assertEqual(RRType.A(), found.get_type())
+ self.assertEqual(RRClass.IN, found.get_class())
+ self.assertEqual(RRType.A, found.get_type())
self.assertEqual('192.0.2.1', found.get_rdata()[0].to_text())
def test_find(self):
# Checking the underlying find() is called as intended, both for
# success and failure cases, and with two different constructors.
rrsets = RRsetCollection(TESTDATA_DIR + '/example.org',
- Name('example.org'), RRClass.IN())
+ Name('example.org'), RRClass.IN)
self.check_find_result(rrsets)
- self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN(),
- RRType.A()))
+ self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN,
+ RRType.A))
rrsets = RRsetCollection(b'www.example.org. 3600 IN A 192.0.2.1',
- Name('example.org'), RRClass.IN())
+ Name('example.org'), RRClass.IN)
self.check_find_result(rrsets)
- self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN(),
- RRType.A()))
+ self.assertEqual(None, rrsets.find(Name('example.org'), RRClass.IN,
+ RRType.A))
def test_find_badargs(self):
rrsets = RRsetCollection()
# Check bad arguments: bad types
- self.assertRaises(TypeError, rrsets.find, 1, RRClass.IN(), RRType.A())
+ self.assertRaises(TypeError, rrsets.find, 1, RRClass.IN, RRType.A)
self.assertRaises(TypeError, rrsets.find, Name('example'), 1,
- RRType.A())
+ RRType.A)
self.assertRaises(TypeError, rrsets.find, Name('example'), 1,
- RRType.A())
+ RRType.A)
self.assertRaises(TypeError, rrsets.find, Name('example'),
- RRClass.IN(), 1)
- self.assertRaises(TypeError, rrsets.find, Name('example'), RRType.A(),
- RRClass.IN())
+ RRClass.IN, 1)
+ self.assertRaises(TypeError, rrsets.find, Name('example'), RRType.A,
+ RRClass.IN)
# Check bad arguments: too many/few arguments
self.assertRaises(TypeError, rrsets.find, Name('example'),
- RRClass.IN(), RRType.A(), 0)
+ RRClass.IN, RRType.A, 0)
self.assertRaises(TypeError, rrsets.find, Name('example'),
- RRClass.IN())
+ RRClass.IN)
def test_add_remove_rrset(self):
name = Name('www.example.org')
- rrclass = RRClass.IN()
- rrtype = RRType.A()
+ rrclass = RRClass.IN
+ rrtype = RRType.A
# Create a collection with no RRsets
rrsets = RRsetCollection()
@@ -134,7 +134,7 @@ class RRsetCollectionTest(unittest.TestCase):
pass
rrsets = EmptyRRsetCollection()
self.assertRaises(TypeError, rrsets.find, Name('www.example.org'),
- RRClass.IN(), RRType.A())
+ RRClass.IN, RRType.A)
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/python/tests/rrtype_python_test.py b/src/lib/dns/python/tests/rrtype_python_test.py
index 4548b50..7d20136 100644
--- a/src/lib/dns/python/tests/rrtype_python_test.py
+++ b/src/lib/dns/python/tests/rrtype_python_test.py
@@ -119,35 +119,35 @@ class TestModuleSpec(unittest.TestCase):
def test_hash(self):
# Exploiting the knowledge that the hash value is the numeric class
# value, we can predict the comparison result.
- self.assertEqual(hash(RRType.AAAA()), hash(RRType("AAAA")))
+ self.assertEqual(hash(RRType.AAAA), hash(RRType("AAAA")))
self.assertEqual(hash(RRType("aaaa")), hash(RRType("AAAA")))
self.assertEqual(hash(RRType(28)), hash(RRType("AAAA")))
- self.assertNotEqual(hash(RRType.A()), hash(RRType.NS()))
- self.assertNotEqual(hash(RRType.AAAA()), hash(RRType("Type65535")))
+ self.assertNotEqual(hash(RRType.A), hash(RRType.NS))
+ self.assertNotEqual(hash(RRType.AAAA), hash(RRType("Type65535")))
def test_statics(self):
- self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM())
- self.assertEqual(RRType("DNAME"), RRType.DNAME())
- self.assertEqual(RRType("PTR"), RRType.PTR())
- self.assertEqual(RRType("MX"), RRType.MX())
- self.assertEqual(RRType("DNSKEY"), RRType.DNSKEY())
- self.assertEqual(RRType("TXT"), RRType.TXT())
- self.assertEqual(RRType("RRSIG"), RRType.RRSIG())
- self.assertEqual(RRType("NSEC"), RRType.NSEC())
- self.assertEqual(RRType("AAAA"), RRType.AAAA())
- self.assertEqual(RRType("DS"), RRType.DS())
- self.assertEqual(RRType("OPT"), RRType.OPT())
- self.assertEqual(RRType("A"), RRType.A())
- self.assertEqual(RRType("NS"), RRType.NS())
- self.assertEqual(RRType("CNAME"), RRType.CNAME())
- self.assertEqual(RRType("SOA"), RRType.SOA())
- self.assertEqual(RRType("NSEC3"), RRType.NSEC3())
+ self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM)
+ self.assertEqual(RRType("DNAME"), RRType.DNAME)
+ self.assertEqual(RRType("PTR"), RRType.PTR)
+ self.assertEqual(RRType("MX"), RRType.MX)
+ self.assertEqual(RRType("DNSKEY"), RRType.DNSKEY)
+ self.assertEqual(RRType("TXT"), RRType.TXT)
+ self.assertEqual(RRType("RRSIG"), RRType.RRSIG)
+ self.assertEqual(RRType("NSEC"), RRType.NSEC)
+ self.assertEqual(RRType("AAAA"), RRType.AAAA)
+ self.assertEqual(RRType("DS"), RRType.DS)
+ self.assertEqual(RRType("OPT"), RRType.OPT)
+ self.assertEqual(RRType("A"), RRType.A)
+ self.assertEqual(RRType("NS"), RRType.NS)
+ self.assertEqual(RRType("CNAME"), RRType.CNAME)
+ self.assertEqual(RRType("SOA"), RRType.SOA)
+ self.assertEqual(RRType("NSEC3"), RRType.NSEC3)
# these can't be built with string input
# (see the original cpp TODO)
- self.assertEqual(251, RRType.IXFR().get_code())
- self.assertEqual(252, RRType.AXFR().get_code())
- self.assertEqual(255, RRType.ANY().get_code())
+ self.assertEqual(251, RRType.IXFR.get_code())
+ self.assertEqual(252, RRType.AXFR.get_code())
+ self.assertEqual(255, RRType.ANY.get_code())
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/python/tests/tsig_python_test.py b/src/lib/dns/python/tests/tsig_python_test.py
index 4d99175..282431c 100644
--- a/src/lib/dns/python/tests/tsig_python_test.py
+++ b/src/lib/dns/python/tests/tsig_python_test.py
@@ -40,7 +40,7 @@ class TSIGContextTest(unittest.TestCase):
self.keyring = TSIGKeyRing()
self.message = Message(Message.RENDER)
self.renderer = MessageRenderer()
- self.test_class = RRClass.IN()
+ self.test_class = RRClass.IN
self.test_ttl = RRTTL(86400)
self.secret = base64.b64decode(b"SFuWd/q99SzF8Yzd1QbB9g==")
self.tsig_ctx = TSIGContext(TSIGKey(self.test_name,
@@ -59,12 +59,12 @@ class TSIGContextTest(unittest.TestCase):
# Note: intentionally use camelCase so that we can easily copy-paste
# corresponding C++ tests.
def createMessageAndSign(self, id, qname, ctx, message_flags=RD_FLAG,
- qtype=RRType.A(), answer_data=None,
+ qtype=RRType.A, answer_data=None,
answer_type=None, add_question=True,
- rcode=Rcode.NOERROR()):
+ rcode=Rcode.NOERROR):
self.message.clear(Message.RENDER)
self.message.set_qid(id)
- self.message.set_opcode(Opcode.QUERY())
+ self.message.set_opcode(Opcode.QUERY)
self.message.set_rcode(rcode)
if (message_flags & QR_FLAG) != 0:
self.message.set_header_flag(Message.HEADERFLAG_QR)
@@ -120,7 +120,7 @@ class TSIGContextTest(unittest.TestCase):
self.assertEqual(TSIGContext.STATE_INIT, self.tsig_ctx.get_state())
# And there should be no error code.
- self.assertEqual(TSIGError(Rcode.NOERROR()), self.tsig_ctx.get_error())
+ self.assertEqual(TSIGError(Rcode.NOERROR), self.tsig_ctx.get_error())
# No message signed yet
self.assertRaises(TSIGContextError, self.tsig_ctx.last_had_signature)
@@ -249,7 +249,7 @@ class TSIGContextTest(unittest.TestCase):
tsig = self.createMessageAndSign(self.qid, self.test_name,
self.tsig_verify_ctx,
QR_FLAG|AA_FLAG|RD_FLAG,
- RRType.A(), "192.0.2.1")
+ RRType.A, "192.0.2.1")
expected_mac = b"\x8f\xcd\xa6\x6a\x7c\xd1\xa3\xb9\x94\x8e\xb1\x86" + \
b"\x9d\x38\x4a\x9f"
@@ -280,7 +280,7 @@ class TSIGContextTest(unittest.TestCase):
zone_name = Name("example.com")
tsig = self.createMessageAndSign(axfr_qid, zone_name, self.tsig_ctx,
- 0, RRType.AXFR())
+ 0, RRType.AXFR)
received_data = read_wire_data("tsig_verify1.wire")
self.commonVerifyChecks(self.tsig_verify_ctx, tsig, received_data,
@@ -289,10 +289,10 @@ class TSIGContextTest(unittest.TestCase):
tsig = self.createMessageAndSign(axfr_qid, zone_name,
self.tsig_verify_ctx,
- AA_FLAG|QR_FLAG, RRType.AXFR(),
+ AA_FLAG|QR_FLAG, RRType.AXFR,
"ns.example.com. root.example.com." +\
" 2011041503 7200 3600 2592000 1200",
- RRType.SOA())
+ RRType.SOA)
received_data = read_wire_data("tsig_verify2.wire")
self.commonVerifyChecks(self.tsig_ctx, tsig, received_data,
@@ -302,8 +302,8 @@ class TSIGContextTest(unittest.TestCase):
b"\x60\x34\x13\x09\x68"
tsig = self.createMessageAndSign(axfr_qid, zone_name,
self.tsig_verify_ctx,
- AA_FLAG|QR_FLAG, RRType.AXFR(),
- "ns.example.com.", RRType.NS(),
+ AA_FLAG|QR_FLAG, RRType.AXFR,
+ "ns.example.com.", RRType.NS,
False)
self.commonSignChecks(tsig, axfr_qid, 0x4da8e951, expected_mac)
@@ -316,7 +316,7 @@ class TSIGContextTest(unittest.TestCase):
test_qid = 0x7fc4
tsig = self.createMessageAndSign(test_qid, self.test_name,
- self.tsig_ctx, 0, RRType.SOA())
+ self.tsig_ctx, 0, RRType.SOA)
# "advance the clock" and try validating, which should fail due to
# BADTIME
@@ -328,8 +328,8 @@ class TSIGContextTest(unittest.TestCase):
# make and sign a response in the context of TSIG error.
tsig = self.createMessageAndSign(test_qid, self.test_name,
self.tsig_verify_ctx,
- QR_FLAG, RRType.SOA(), None, None,
- True, Rcode.NOTAUTH())
+ QR_FLAG, RRType.SOA, None, None,
+ True, Rcode.NOTAUTH)
expected_otherdata = b"\x00\x00\x4d\xa8\xbe\x86"
expected_mac = b"\xd4\xb0\x43\xf6\xf4\x44\x95\xec\x8a\x01\x26" +\
@@ -344,7 +344,7 @@ class TSIGContextTest(unittest.TestCase):
fix_current_time(0x4da8b9d6)
tsig = self.createMessageAndSign(self.qid, self.test_name,
- self.tsig_ctx, 0, RRType.SOA())
+ self.tsig_ctx, 0, RRType.SOA)
# "rewind the clock" and try validating, which should fail due to
# BADTIME
@@ -361,7 +361,7 @@ class TSIGContextTest(unittest.TestCase):
fix_current_time(0x4da8b9d6)
tsig = self.createMessageAndSign(self.qid, self.test_name,
- self.tsig_ctx, 0, RRType.SOA())
+ self.tsig_ctx, 0, RRType.SOA)
fix_current_time(0x4da8b9d6 + 301)
self.assertEqual(TSIGError.BAD_TIME,
@@ -382,7 +382,7 @@ class TSIGContextTest(unittest.TestCase):
def test_badtime_overflow(self):
fix_current_time(200)
tsig = self.createMessageAndSign(self.qid, self.test_name,
- self.tsig_ctx, 0, RRType.SOA())
+ self.tsig_ctx, 0, RRType.SOA)
# This should be in the okay range, but since "200 - fudge" overflows
# and we compare them as 64-bit unsigned integers, it results in a
@@ -522,7 +522,7 @@ class TSIGContextTest(unittest.TestCase):
self.tsig_verify_ctx.get_state())
self.createMessageAndSign(self.qid, self.test_name,
self.tsig_verify_ctx,
- QR_FLAG|AA_FLAG|RD_FLAG, RRType.A(),
+ QR_FLAG|AA_FLAG|RD_FLAG, RRType.A,
"192.0.2.1")
self.assertEqual(TSIGContext.STATE_SENT_RESPONSE,
self.tsig_verify_ctx.get_state())
diff --git a/src/lib/dns/python/tests/tsigerror_python_test.py b/src/lib/dns/python/tests/tsigerror_python_test.py
index a968b6b..01860d3 100644
--- a/src/lib/dns/python/tests/tsigerror_python_test.py
+++ b/src/lib/dns/python/tests/tsigerror_python_test.py
@@ -28,7 +28,7 @@ class TSIGErrorTest(unittest.TestCase):
def test_from_rcode(self):
# We use RCODE for code values from 0-15.
- self.assertEqual(0, TSIGError(Rcode.NOERROR()).get_code())
+ self.assertEqual(0, TSIGError(Rcode.NOERROR).get_code())
self.assertEqual(15, TSIGError(Rcode(15)).get_code())
# From error code 16 TSIG errors define a separate space, so passing
@@ -50,19 +50,19 @@ class TSIGErrorTest(unittest.TestCase):
self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError.BAD_TIME.get_code())
def test_equal(self):
- self.assertTrue(TSIGError.NOERROR == TSIGError(Rcode.NOERROR()))
- self.assertTrue(TSIGError(Rcode.NOERROR()) == TSIGError.NOERROR)
+ self.assertTrue(TSIGError.NOERROR == TSIGError(Rcode.NOERROR))
+ self.assertTrue(TSIGError(Rcode.NOERROR) == TSIGError.NOERROR)
self.assertTrue(TSIGError.BAD_SIG == TSIGError(16))
self.assertTrue(TSIGError(16) == TSIGError.BAD_SIG)
def test_nequal(self):
- self.assertTrue(TSIGError.BAD_KEY != TSIGError(Rcode.NOERROR()))
- self.assertTrue(TSIGError(Rcode.NOERROR()) != TSIGError.BAD_KEY)
+ self.assertTrue(TSIGError.BAD_KEY != TSIGError(Rcode.NOERROR))
+ self.assertTrue(TSIGError(Rcode.NOERROR) != TSIGError.BAD_KEY)
def test_to_text(self):
# TSIGError derived from the standard Rcode
- self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR()).to_text())
+ self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR).to_text())
# Well known TSIG errors
self.assertEqual("BADSIG", TSIGError.BAD_SIG.to_text())
@@ -74,21 +74,21 @@ class TSIGErrorTest(unittest.TestCase):
self.assertEqual("65535", TSIGError(65535).to_text());
# also check str() works same way
- self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR())))
+ self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR)))
self.assertEqual("BADSIG", str(TSIGError.BAD_SIG))
def test_to_rcode(self):
# TSIGError derived from the standard Rcode
- self.assertEqual(Rcode.NOERROR(), TSIGError(Rcode.NOERROR()).to_rcode())
+ self.assertEqual(Rcode.NOERROR, TSIGError(Rcode.NOERROR).to_rcode())
# Well known TSIG errors
- self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_SIG.to_rcode())
- self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_KEY.to_rcode())
- self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_TIME.to_rcode())
+ self.assertEqual(Rcode.NOTAUTH, TSIGError.BAD_SIG.to_rcode())
+ self.assertEqual(Rcode.NOTAUTH, TSIGError.BAD_KEY.to_rcode())
+ self.assertEqual(Rcode.NOTAUTH, TSIGError.BAD_TIME.to_rcode())
# Unknown (or not yet supported) codes are treated as SERVFAIL.
- self.assertEqual(Rcode.SERVFAIL(), TSIGError(19).to_rcode())
- self.assertEqual(Rcode.SERVFAIL(), TSIGError(65535).to_rcode())
+ self.assertEqual(Rcode.SERVFAIL, TSIGError(19).to_rcode())
+ self.assertEqual(Rcode.SERVFAIL, TSIGError(65535).to_rcode())
# Check there's no redundant refcount (which would cause leak)
self.assertEqual(1, sys.getrefcount(TSIGError.BAD_SIG.to_rcode()))
diff --git a/src/lib/dns/python/tests/zone_checker_python_test.py b/src/lib/dns/python/tests/zone_checker_python_test.py
index ec3a3b0..dc7d258 100644
--- a/src/lib/dns/python/tests/zone_checker_python_test.py
+++ b/src/lib/dns/python/tests/zone_checker_python_test.py
@@ -35,8 +35,8 @@ class ZoneCheckerTest(unittest.TestCase):
rrsets = RRsetCollection(b'example.org. 0 SOA . . 0 0 0 0 0\n' +
b'example.org. 0 NS ns.example.org.\n' +
b'ns.example.org. 0 A 192.0.2.1\n',
- Name('example.org'), RRClass.IN())
- self.assertTrue(check_zone(Name('example.org'), RRClass.IN(),
+ Name('example.org'), RRClass.IN)
+ self.assertTrue(check_zone(Name('example.org'), RRClass.IN,
rrsets,
(lambda r: self.__callback(r, errors),
lambda r: self.__callback(r, warns))))
@@ -45,8 +45,8 @@ class ZoneCheckerTest(unittest.TestCase):
# Check fails and one additional warning.
rrsets = RRsetCollection(b'example.org. 0 NS ns.example.org.',
- Name('example.org'), RRClass.IN())
- self.assertFalse(check_zone(Name('example.org'), RRClass.IN(), rrsets,
+ Name('example.org'), RRClass.IN)
+ self.assertFalse(check_zone(Name('example.org'), RRClass.IN, rrsets,
(lambda r: self.__callback(r, errors),
lambda r: self.__callback(r, warns))))
self.assertEqual(['zone example.org/IN: has 0 SOA records'], errors)
@@ -56,7 +56,7 @@ class ZoneCheckerTest(unittest.TestCase):
# Same RRset collection, suppressing callbacks
errors = []
warns = []
- self.assertFalse(check_zone(Name('example.org'), RRClass.IN(), rrsets,
+ self.assertFalse(check_zone(Name('example.org'), RRClass.IN, rrsets,
(None, None)))
self.assertEqual([], errors)
self.assertEqual([], warns)
@@ -64,29 +64,29 @@ class ZoneCheckerTest(unittest.TestCase):
def test_check_badarg(self):
rrsets = RRsetCollection()
# Bad types
- self.assertRaises(TypeError, check_zone, 1, RRClass.IN(), rrsets,
+ self.assertRaises(TypeError, check_zone, 1, RRClass.IN, rrsets,
(None, None))
self.assertRaises(TypeError, check_zone, Name('example'), 1, rrsets,
(None, None))
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
1, (None, None))
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, 1)
# Bad callbacks
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, (None, None, None))
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, (1, None))
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, (None, 1))
# Extra/missing args
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, (None, None), 1)
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets)
- check_zone(Name('example'), RRClass.IN(), rrsets, (None, None))
+ check_zone(Name('example'), RRClass.IN, rrsets, (None, None))
def test_check_callback_fail(self):
# Let the call raise a Python exception. It should be propagated to
@@ -96,7 +96,7 @@ class ZoneCheckerTest(unittest.TestCase):
# Using an empty collection, triggering an error callback.
self.assertRaises(FakeException, check_zone, Name('example.org'),
- RRClass.IN(), RRsetCollection(),
+ RRClass.IN, RRsetCollection(),
(__bad_callback, None))
# An unusual case: the callback is expected to return None, but if it
@@ -108,7 +108,7 @@ class ZoneCheckerTest(unittest.TestCase):
ref_checker = RefChecker()
orig_refcnt = sys.getrefcount(ref_checker)
- check_zone(Name('example.org'), RRClass.IN(), RRsetCollection(),
+ check_zone(Name('example.org'), RRClass.IN, RRsetCollection(),
(lambda r: __callback(r, ref_checker), None))
self.assertEqual(orig_refcnt, sys.getrefcount(ref_checker))
@@ -132,48 +132,45 @@ class ZoneCheckerTest(unittest.TestCase):
raise FakeException('find error')
if self.__find_result is not 'use_default':
return self.__find_result
- if rrtype == RRType.SOA():
- soa = RRset(Name('example'), RRClass.IN(), rrtype,
- RRTTL(0))
- soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+ if rrtype == RRType.SOA:
+ soa = RRset(Name('example'), RRClass.IN, rrtype, RRTTL(0))
+ soa.add_rdata(Rdata(RRType.SOA, RRClass.IN,
'. . 0 0 0 0 0'))
return soa
- if rrtype == RRType.NS():
- ns = RRset(Name('example'), RRClass.IN(), rrtype,
- RRTTL(0))
- ns.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
- 'example.org.'))
+ if rrtype == RRType.NS:
+ ns = RRset(Name('example'), RRClass.IN, rrtype, RRTTL(0))
+ ns.add_rdata(Rdata(RRType.NS, RRClass.IN, 'example.org.'))
return ns
return None
# A successful case. Just checking it works in that case.
rrsets = FakeRRsetCollection()
- self.assertTrue(check_zone(Name('example'), RRClass.IN(), rrsets,
+ self.assertTrue(check_zone(Name('example'), RRClass.IN, rrsets,
(None, None)))
# Likewise, normal case but zone check fails.
rrsets = FakeRRsetCollection(False, None)
- self.assertFalse(check_zone(Name('example'), RRClass.IN(), rrsets,
+ self.assertFalse(check_zone(Name('example'), RRClass.IN, rrsets,
(None, None)))
# Our find() returns a bad type of result.
rrsets = FakeRRsetCollection(False, 1)
- self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN(),
+ self.assertRaises(TypeError, check_zone, Name('example'), RRClass.IN,
rrsets, (None, None))
# Our find() returns an empty SOA RRset. C++ zone checker code
# throws, which results in IscException.
rrsets = FakeRRsetCollection(False, RRset(Name('example'),
- RRClass.IN(),
- RRType.SOA(), RRTTL(0)))
+ RRClass.IN,
+ RRType.SOA, RRTTL(0)))
self.assertRaises(IscException, check_zone, Name('example'),
- RRClass.IN(), rrsets, (None, None))
+ RRClass.IN, rrsets, (None, None))
# Our find() raises an exception. That exception is propagated to
# the top level.
rrsets = FakeRRsetCollection(True)
self.assertRaises(FakeException, check_zone, Name('example'),
- RRClass.IN(), rrsets, (None, None))
+ RRClass.IN, rrsets, (None, None))
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/dns/rdata/template.h b/src/lib/dns/rdata/template.h
index 9e84cc3..3bfeb85 100644
--- a/src/lib/dns/rdata/template.h
+++ b/src/lib/dns/rdata/template.h
@@ -39,6 +39,10 @@
// Note: do not remove the comment lines beginning with "BEGIN_" and "END_".
// These are markers used by a script for auto-generating build-able source
// files.
+//
+// On completion of implementing a new type of Rdata, remove the corresponding
+// entry from the meta_types dictionary of gen-rdatacode.py.in. Otherwise
+// it will cause build failure.
class MyType : public Rdata {
public:
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index 1ff4163..89dc49d 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -294,28 +294,14 @@ public:
// BEGIN_WELL_KNOWN_CLASS_DECLARATIONS
// END_WELL_KNOWN_CLASS_DECLARATIONS
-
- static const RRClass& NONE();
private:
- // \brief Meta-classes
- enum {
- RRCLASS_RESERVED0 = 0,
- RRCLASS_NONE = 254
- };
uint16_t classcode_;
};
// BEGIN_WELL_KNOWN_CLASS_DEFINITIONS
// END_WELL_KNOWN_CLASS_DEFINITIONS
-inline const RRClass&
-RRClass::NONE() {
- static RRClass rrclass(RRCLASS_NONE);
-
- return (rrclass);
-}
-
///
/// \brief Insert the \c RRClass as a string into stream.
///
diff --git a/src/lib/dns/rrtype-placeholder.h b/src/lib/dns/rrtype-placeholder.h
index 273a486..5541635 100644
--- a/src/lib/dns/rrtype-placeholder.h
+++ b/src/lib/dns/rrtype-placeholder.h
@@ -262,43 +262,13 @@ public:
// BEGIN_WELL_KNOWN_TYPE_DECLARATIONS
// END_WELL_KNOWN_TYPE_DECLARATIONS
- static const RRType& IXFR();
- static const RRType& AXFR();
- static const RRType& ANY();
-
private:
- // \brief Meta-classes
- // XXX: these should be implemented using rrparamregistry
- enum {
- RRTYPE_IXFR = 251,
- RRTYPE_AXFR = 252,
- RRTYPE_ANY = 255
- };
-
uint16_t typecode_;
};
// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS
// END_WELL_KNOWN_TYPE_DEFINITIONS
-inline const RRType&
-RRType::IXFR() {
- static RRType rrtype(RRTYPE_IXFR);
- return (rrtype);
-}
-
-inline const RRType&
-RRType::AXFR() {
- static RRType rrtype(RRTYPE_AXFR);
- return (rrtype);
-}
-
-inline const RRType&
-RRType::ANY() {
- static RRType rrtype(RRTYPE_ANY);
- return (rrtype);
-}
-
///
/// \brief Insert the \c RRType as a string into stream.
///
diff --git a/src/lib/dns/tests/rrclass_unittest.cc b/src/lib/dns/tests/rrclass_unittest.cc
index 11f1c54..17af873 100644
--- a/src/lib/dns/tests/rrclass_unittest.cc
+++ b/src/lib/dns/tests/rrclass_unittest.cc
@@ -148,4 +148,29 @@ TEST_F(RRClassTest, LeftShiftOperator) {
oss << RRClass::IN();
EXPECT_EQ(RRClass::IN().toText(), oss.str());
}
+
+// Below, we'll check definitions for all well-known RR classes; whether they
+// are defined and have the correct parameter values. Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct ClassParam {
+ const char* const txt; // "IN", "CH", etc
+ const uint16_t code; // 1, 3,
+ const RRClass& (*obj)(); // RRClass::IN(), etc
+} known_classes[] = {
+ {"IN", 1, RRClass::IN}, {"CH", 3, RRClass::CH}, {"HS", 4, RRClass::HS},
+ {"NONE", 254, RRClass::NONE}, {"ANY", 255, RRClass::ANY},
+ {NULL, 0, NULL}
+};
+
+TEST(RRClassConstTest, wellKnowns) {
+ for (int i = 0; known_classes[i].txt; ++i) {
+ SCOPED_TRACE("Checking well known RRClass: " +
+ string(known_classes[i].txt));
+ EXPECT_EQ(known_classes[i].code,
+ RRClass(known_classes[i].txt).getCode());
+ EXPECT_EQ(known_classes[i].code,
+ (*known_classes[i].obj)().getCode());
+ }
+}
}
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc
index 1b4abfd..d16ce3c 100644
--- a/src/lib/dns/tests/rrset_unittest.cc
+++ b/src/lib/dns/tests/rrset_unittest.cc
@@ -205,7 +205,7 @@ TEST_F(RRsetTest, toText) {
// Unless it is type ANY or NONE
EXPECT_EQ("test.example.com. 3600 ANY A\n",
rrset_any_a_empty.toText());
- EXPECT_EQ("test.example.com. 3600 CLASS254 A\n",
+ EXPECT_EQ("test.example.com. 3600 NONE A\n",
rrset_none_a_empty.toText());
}
diff --git a/src/lib/dns/tests/rrtype_unittest.cc b/src/lib/dns/tests/rrtype_unittest.cc
index 28ecee6..ee302a1 100644
--- a/src/lib/dns/tests/rrtype_unittest.cc
+++ b/src/lib/dns/tests/rrtype_unittest.cc
@@ -145,4 +145,57 @@ TEST_F(RRTypeTest, LeftShiftOperator) {
oss << RRType::A();
EXPECT_EQ(RRType::A().toText(), oss.str());
}
+
+// Below, we'll check definitions for all well-known RR types; whether they
+// are defined and have the correct parameter values. Test data are generated
+// from the list available at:
+// http://www.iana.org/assignments/dns-parameters/dns-parameters.xml
+struct TypeParam {
+ const char* const txt; // "A", "AAAA", "NS", etc
+ const uint16_t code; // 1, 28, 2, etc
+ const RRType& (*obj)(); // RRType::A(), etc
+} known_types[] = {
+ {"A", 1, RRType::A}, {"NS", 2, RRType::NS}, {"MD", 3, RRType::MD},
+ {"MF", 4, RRType::MF}, {"CNAME", 5, RRType::CNAME},
+ {"SOA", 6, RRType::SOA}, {"MB", 7, RRType::MB}, {"MG", 8, RRType::MG},
+ {"MR", 9, RRType::MR}, {"NULL", 10, RRType::Null},
+ {"WKS", 11, RRType::WKS}, {"PTR", 12, RRType::PTR},
+ {"HINFO", 13, RRType::HINFO}, {"MINFO", 14, RRType::MINFO},
+ {"MX", 15, RRType::MX}, {"TXT", 16, RRType::TXT}, {"RP", 17, RRType::RP},
+ {"AFSDB", 18, RRType::AFSDB}, {"X25", 19, RRType::X25},
+ {"ISDN", 20, RRType::ISDN}, {"RT", 21, RRType::RT},
+ {"NSAP", 22, RRType::NSAP}, {"NSAP-PTR", 23, RRType::NSAP_PTR},
+ {"SIG", 24, RRType::SIG}, {"KEY", 25, RRType::KEY},
+ {"PX", 26, RRType::PX}, {"GPOS", 27, RRType::GPOS},
+ {"AAAA", 28, RRType::AAAA}, {"LOC", 29, RRType::LOC},
+ {"NXT", 30, RRType::NXT}, {"SRV", 33, RRType::SRV},
+ {"NAPTR", 35, RRType::NAPTR}, {"KX", 36, RRType::KX},
+ {"CERT", 37, RRType::CERT}, {"A6", 38, RRType::A6},
+ {"DNAME", 39, RRType::DNAME}, {"OPT", 41, RRType::OPT},
+ {"APL", 42, RRType::APL}, {"DS", 43, RRType::DS},
+ {"SSHFP", 44, RRType::SSHFP}, {"IPSECKEY", 45, RRType::IPSECKEY},
+ {"RRSIG", 46, RRType::RRSIG}, {"NSEC", 47, RRType::NSEC},
+ {"DNSKEY", 48, RRType::DNSKEY}, {"DHCID", 49, RRType::DHCID},
+ {"NSEC3", 50, RRType::NSEC3}, {"NSEC3PARAM", 51, RRType::NSEC3PARAM},
+ {"TLSA", 52, RRType::TLSA}, {"HIP", 55, RRType::HIP},
+ {"SPF", 99, RRType::SPF}, {"UNSPEC", 103, RRType::UNSPEC},
+ {"NID", 104, RRType::NID}, {"L32", 105, RRType::L32},
+ {"L64", 106, RRType::L64}, {"LP", 107, RRType::LP},
+ {"TKEY", 249, RRType::TKEY}, {"TSIG", 250, RRType::TSIG},
+ {"IXFR", 251, RRType::IXFR}, {"AXFR", 252, RRType::AXFR},
+ {"MAILB", 253, RRType::MAILB}, {"MAILA", 254, RRType::MAILA},
+ {"ANY", 255, RRType::ANY}, {"URI", 256, RRType::URI},
+ {"CAA", 257, RRType::CAA}, {"DLV", 32769, RRType::DLV},
+ {NULL, 0, NULL}
+};
+
+TEST(RRTypeConstTest, wellKnowns) {
+ for (int i = 0; known_types[i].txt; ++i) {
+ SCOPED_TRACE("Checking well known RRType: " +
+ string(known_types[i].txt));
+ EXPECT_EQ(known_types[i].code, RRType(known_types[i].txt).getCode());
+ EXPECT_EQ(known_types[i].code,
+ (*known_types[i].obj)().getCode());
+ }
+}
}
diff --git a/src/lib/python/isc/__init__.py b/src/lib/python/isc/__init__.py
index 029f110..37138a2 100644
--- a/src/lib/python/isc/__init__.py
+++ b/src/lib/python/isc/__init__.py
@@ -1,7 +1,3 @@
-# On some systems, it appears the dynamic linker gets
-# confused if the order is not right here
-# There is probably a solution for this, but for now:
-# order is important here!
-import isc.cc
-import isc.config
-import isc.datasrc
+"""
+This is the top directory for common BIND 10 Python modules and packages.
+"""
diff --git a/src/lib/python/isc/datasrc/tests/clientlist_test.py b/src/lib/python/isc/datasrc/tests/clientlist_test.py
index ea39d4e..bdac69c 100644
--- a/src/lib/python/isc/datasrc/tests/clientlist_test.py
+++ b/src/lib/python/isc/datasrc/tests/clientlist_test.py
@@ -43,8 +43,8 @@ class ClientListTest(unittest.TestCase):
Test the constructor. It should accept an RRClass. Check it
reject invalid inputs.
"""
- isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
- isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH())
+ isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
+ isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH)
# Not enough arguments
self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList)
# Bad types of arguments
@@ -52,7 +52,7 @@ class ClientListTest(unittest.TestCase):
self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList, "IN")
# Too many arguments
self.assertRaises(TypeError, isc.datasrc.ConfigurableClientList,
- isc.dns.RRClass.IN(), isc.dns.RRClass.IN())
+ isc.dns.RRClass.IN, isc.dns.RRClass.IN)
def test_configure(self):
"""
@@ -60,7 +60,7 @@ class ClientListTest(unittest.TestCase):
ones are acceptend and invalid rejected. We check the changes
have effect.
"""
- self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+ self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
# This should be NOP now
self.clist.configure("[]", True)
# Check the zone is not there yet
@@ -102,7 +102,7 @@ class ClientListTest(unittest.TestCase):
Test the find accepts the right arguments, some of them can be omitted,
etc.
"""
- self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+ self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
self.clist.configure('''[{
"type": "MasterFiles",
"params": {
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index 36cf951..64f3e53 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -51,8 +51,8 @@ def check_for_rrset(expected_rrsets, rrset):
return False
def create_soa(serial):
- soa = RRset(Name('example.org'), RRClass.IN(), RRType.SOA(), RRTTL(3600))
- soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
+ soa = RRset(Name('example.org'), RRClass.IN, RRType.SOA, RRTTL(3600))
+ soa.add_rdata(Rdata(RRType.SOA, RRClass.IN,
'ns1.example.org. admin.example.org. ' +
str(serial) + ' 3600 1800 2419200 7200'))
return soa
@@ -66,13 +66,13 @@ def test_findall_common(self, tested):
result, rrset, _ = tested.find_all(isc.dns.Name("www.sql1.example.com"),
ZoneFinder.FIND_DEFAULT)
self.assertEqual(ZoneFinder.DELEGATION, result)
- expected = RRset(Name('sql1.example.com.'), RRClass.IN(), RRType.NS(),
+ expected = RRset(Name('sql1.example.com.'), RRClass.IN, RRType.NS,
RRTTL(3600))
- expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+ expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
'dns01.example.com.'))
- expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+ expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
'dns02.example.com.'))
- expected.add_rdata(Rdata(RRType.NS(), RRClass.IN(),
+ expected.add_rdata(Rdata(RRType.NS, RRClass.IN,
'dns03.example.com.'))
self.assertTrue(rrsets_equal(expected, rrset))
@@ -88,16 +88,16 @@ def test_findall_common(self, tested):
self.assertEqual(2, len(rrsets))
rrsets.sort(key=lambda rrset: rrset.get_type().to_text())
expected = [
- RRset(Name('mix.example.com.'), RRClass.IN(), RRType.A(),
+ RRset(Name('mix.example.com.'), RRClass.IN, RRType.A,
RRTTL(3600)),
- RRset(Name('mix.example.com.'), RRClass.IN(), RRType.AAAA(),
+ RRset(Name('mix.example.com.'), RRClass.IN, RRType.AAAA,
RRTTL(3600))
]
- expected[0].add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
- expected[0].add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.2"))
- expected[1].add_rdata(Rdata(RRType.AAAA(), RRClass.IN(),
+ expected[0].add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.1"))
+ expected[0].add_rdata(Rdata(RRType.A, RRClass.IN, "192.0.2.2"))
+ expected[1].add_rdata(Rdata(RRType.AAAA, RRClass.IN,
"2001:db8::1"))
- expected[1].add_rdata(Rdata(RRType.AAAA(), RRClass.IN(),
+ expected[1].add_rdata(Rdata(RRType.AAAA, RRClass.IN,
"2001:db8::2"))
for (rrset, exp) in zip(rrsets, expected):
self.assertTrue(rrsets_equal(exp, rrset))
@@ -158,9 +158,9 @@ class DataSrcClient(unittest.TestCase):
expected_rrset_list = []
name = isc.dns.Name("sql1.example.com")
- rrclass = isc.dns.RRClass.IN()
+ rrclass = isc.dns.RRClass.IN
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.DNSKEY(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.DNSKEY, isc.dns.RRTTL(3600),
[
"256 3 5 AwEAAdYdRhBAEY67R/8G1N5AjGF6asIiNh/pNGeQ8xDQP13J"+
"N2lo+sNqWcmpYNhuVqRbLB+mamsU1XcCICSBvAlSmfz/ZUdafX23knAr"+
@@ -168,7 +168,7 @@ class DataSrcClient(unittest.TestCase):
"5fs0dE/xLztL/CzZ"
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.DNSKEY(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.DNSKEY, isc.dns.RRTTL(3600),
[
"257 3 5 AwEAAbaKDSa9XEFTsjSYpUTHRotTS9Tz3krfDucugW5UokGQ"+
"KC26QlyHXlPTZkC+aRFUs/dicJX2kopndLcnlNAPWiKnKtrsFSCnIJDB"+
@@ -179,22 +179,22 @@ class DataSrcClient(unittest.TestCase):
"jRWAzGsxJiJyjd6w2k0="
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.NS, isc.dns.RRTTL(3600),
[
"dns01.example.com."
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.NS, isc.dns.RRTTL(3600),
[
"dns02.example.com."
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.NS(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.NS, isc.dns.RRTTL(3600),
[
"dns03.example.com."
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.NSEC(), isc.dns.RRTTL(7200),
+ isc.dns.RRType.NSEC, isc.dns.RRTTL(7200),
[
"www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"
])
@@ -204,36 +204,36 @@ class DataSrcClient(unittest.TestCase):
# Since we passed separate_rrs = True to get_iterator, we get several
# sets of RRSIGs, one for each TTL
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(7200), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(7200), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.SOA(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.SOA, isc.dns.RRTTL(3600),
[
"master.example.com. admin.example.com. 678 3600 1800 2419200 7200"
])
name = isc.dns.Name("www.sql1.example.com.")
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.A(), isc.dns.RRTTL(3600),
+ isc.dns.RRType.A, isc.dns.RRTTL(3600),
[
"192.0.2.100"
])
name = isc.dns.Name("www.sql1.example.com.")
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.NSEC(), isc.dns.RRTTL(7200),
+ isc.dns.RRType.NSEC, isc.dns.RRTTL(7200),
[
"sql1.example.com. A RRSIG NSEC"
])
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(3600), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(3600), None)
add_rrset(expected_rrset_list, name, rrclass,
- isc.dns.RRType.RRSIG(), isc.dns.RRTTL(7200), None)
+ isc.dns.RRType.RRSIG, isc.dns.RRTTL(7200), None)
# rrs is an iterator, but also has direct get_next_rrset(), use
# the latter one here
@@ -287,11 +287,11 @@ class DataSrcClient(unittest.TestCase):
dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
iterator = dsc.get_iterator(isc.dns.Name("sql1.example.com."))
expected_soa = isc.dns.RRset(isc.dns.Name("sql1.example.com."),
- isc.dns.RRClass.IN(),
- isc.dns.RRType.SOA(),
+ isc.dns.RRClass.IN,
+ isc.dns.RRType.SOA,
isc.dns.RRTTL(3600))
- expected_soa.add_rdata(isc.dns.Rdata(isc.dns.RRType.SOA(),
- isc.dns.RRClass.IN(),
+ expected_soa.add_rdata(isc.dns.Rdata(isc.dns.RRType.SOA,
+ isc.dns.RRClass.IN,
"master.example.com. " +
"admin.example.com. 678 " +
"3600 1800 2419200 7200"))
@@ -337,7 +337,7 @@ class DataSrcClient(unittest.TestCase):
result, finder = dsc.find_zone(isc.dns.Name("example.com"))
self.assertEqual(finder.SUCCESS, result)
- self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+ self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
self.assertEqual("example.com.", finder.get_origin().to_text())
test_findall_common(self, finder)
@@ -347,11 +347,11 @@ class DataSrcClient(unittest.TestCase):
result, finder = dsc.find_zone(isc.dns.Name("example.com"))
self.assertEqual(finder.SUCCESS, result)
- self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+ self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
self.assertEqual("example.com.", finder.get_origin().to_text())
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -359,13 +359,13 @@ class DataSrcClient(unittest.TestCase):
# Check the optional parameters are optional
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A())
+ isc.dns.RRType.A)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
rrset.to_text())
result, rrset, _ = finder.find(isc.dns.Name("www.sql1.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.DELEGATION, result)
self.assertEqual("sql1.example.com. 3600 IN NS dns01.example.com.\n" +
@@ -374,7 +374,7 @@ class DataSrcClient(unittest.TestCase):
rrset.to_text())
result, rrset, _ = finder.find(isc.dns.Name("doesnotexist.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXDOMAIN, result)
self.assertEqual(None, rrset)
@@ -382,16 +382,16 @@ class DataSrcClient(unittest.TestCase):
self.assertRaises(isc.datasrc.OutOfZone, finder.find,
isc.dns.Name("www.some.other.domain"),
- isc.dns.RRType.A())
+ isc.dns.RRType.A)
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.TXT(),
+ isc.dns.RRType.TXT,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXRRSET, result)
self.assertEqual(None, rrset)
result, rrset, _ = finder.find(isc.dns.Name("cname-ext.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.CNAME, result)
self.assertEqual(
@@ -400,14 +400,14 @@ class DataSrcClient(unittest.TestCase):
result, rrset, flags = \
finder.find(isc.dns.Name("foo.wild.example.com"),
- isc.dns.RRType.A(), finder.FIND_DEFAULT)
+ isc.dns.RRType.A, finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual(finder.RESULT_WILDCARD, flags)
self.assertEqual("foo.wild.example.com. 3600 IN A 192.0.2.255\n",
rrset.to_text())
result, rrset, _ = finder.find(isc.dns.Name("foo.wild.example.com"),
- isc.dns.RRType.TXT(),
+ isc.dns.RRType.TXT,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXRRSET, result)
self.assertTrue(finder.RESULT_WILDCARD, flags)
@@ -415,7 +415,7 @@ class DataSrcClient(unittest.TestCase):
self.assertRaises(TypeError, finder.find,
"foo",
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertRaises(TypeError, finder.find,
isc.dns.Name("cname-ext.example.com"),
@@ -423,7 +423,7 @@ class DataSrcClient(unittest.TestCase):
finder.FIND_DEFAULT)
self.assertRaises(TypeError, finder.find,
isc.dns.Name("cname-ext.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
"foo")
class DataSrcUpdater(unittest.TestCase):
@@ -451,7 +451,7 @@ class DataSrcUpdater(unittest.TestCase):
dsc = isc.datasrc.DataSourceClient("sqlite3", WRITE_ZONE_DB_CONFIG)
updater = dsc.get_updater(isc.dns.Name("example.com"), False)
result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
ZoneFinder.FIND_DEFAULT)
self.assertEqual(ZoneFinder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -459,7 +459,7 @@ class DataSrcUpdater(unittest.TestCase):
# Omit optional parameters
result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A())
+ isc.dns.RRType.A)
self.assertEqual(ZoneFinder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
rrset.to_text())
@@ -471,11 +471,11 @@ class DataSrcUpdater(unittest.TestCase):
# first make sure, through a separate finder, that some record exists
result, finder = dsc.find_zone(isc.dns.Name("example.com"))
self.assertEqual(finder.SUCCESS, result)
- self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+ self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
self.assertEqual("example.com.", finder.get_origin().to_text())
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -490,13 +490,13 @@ class DataSrcUpdater(unittest.TestCase):
# The record should be gone in the updater, but not in the original
# finder (since we have not committed)
result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXDOMAIN, result)
self.assertEqual(None, rrset)
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -508,7 +508,7 @@ class DataSrcUpdater(unittest.TestCase):
# the record should be gone now in the 'real' finder as well
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXDOMAIN, result)
self.assertEqual(None, rrset)
@@ -522,7 +522,7 @@ class DataSrcUpdater(unittest.TestCase):
self.assertRaises(isc.datasrc.Error, updater.commit)
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -537,26 +537,26 @@ class DataSrcUpdater(unittest.TestCase):
rrsets = updater.get_rrset_collection()
# From this point we cannot make further updates
- rrset = RRset(isc.dns.Name('www.example.com'), isc.dns.RRClass.IN(),
- isc.dns.RRType.AAAA(), isc.dns.RRTTL(10))
- rrset.add_rdata(isc.dns.Rdata(isc.dns.RRType.AAAA(),
- isc.dns.RRClass.IN(), '2001:db8::1'))
+ rrset = RRset(isc.dns.Name('www.example.com'), isc.dns.RRClass.IN,
+ isc.dns.RRType.AAAA, isc.dns.RRTTL(10))
+ rrset.add_rdata(isc.dns.Rdata(isc.dns.RRType.AAAA,
+ isc.dns.RRClass.IN, '2001:db8::1'))
self.assertRaises(isc.datasrc.Error, updater.add_rrset, rrset)
# Checks basic API
found = rrsets.find(isc.dns.Name("www.example.com"),
- isc.dns.RRClass.IN(), isc.dns.RRType.A())
+ isc.dns.RRClass.IN, isc.dns.RRType.A)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
found.to_text())
self.assertEqual(None, rrsets.find(isc.dns.Name("www.example.com"),
- isc.dns.RRClass.IN(),
- isc.dns.RRType.AAAA()))
+ isc.dns.RRClass.IN,
+ isc.dns.RRType.AAAA))
# Once committed collection cannot be used any more.
updater.commit()
self.assertRaises(isc.dns.RRsetCollectionError,
rrsets.find, isc.dns.Name("www.example.com"),
- isc.dns.RRClass.IN(), isc.dns.RRType.A())
+ isc.dns.RRClass.IN, isc.dns.RRType.A)
# When we destroy the RRsetCollection it should release the refcount
# to the updater.
@@ -578,10 +578,10 @@ class DataSrcUpdater(unittest.TestCase):
# see if a lookup succeeds in sqlite3 ds
result, finder = dsc_sql.find_zone(isc.dns.Name("example.com"))
self.assertEqual(finder.SUCCESS, result)
- self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+ self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
self.assertEqual("example.com.", finder.get_origin().to_text())
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -600,11 +600,11 @@ class DataSrcUpdater(unittest.TestCase):
# first make sure, through a separate finder, that some record exists
result, finder = dsc.find_zone(isc.dns.Name("example.com"))
self.assertEqual(finder.SUCCESS, result)
- self.assertEqual(isc.dns.RRClass.IN(), finder.get_class())
+ self.assertEqual(isc.dns.RRClass.IN, finder.get_class())
self.assertEqual("example.com.", finder.get_origin().to_text())
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -619,7 +619,7 @@ class DataSrcUpdater(unittest.TestCase):
# The record should be gone in the updater, but not in the original
# finder (since we have not committed)
result, rrset, _ = updater.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.NXDOMAIN, result)
self.assertEqual(None, rrset)
@@ -629,7 +629,7 @@ class DataSrcUpdater(unittest.TestCase):
# the record should still be available in the 'real' finder as well
result, rrset, _ = finder.find(isc.dns.Name("www.example.com"),
- isc.dns.RRType.A(),
+ isc.dns.RRType.A,
finder.FIND_DEFAULT)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
@@ -755,9 +755,9 @@ class JournalWrite(unittest.TestCase):
conn.close()
def create_a(self, address):
- a_rr = RRset(Name('www.example.org'), RRClass.IN(), RRType.A(),
+ a_rr = RRset(Name('www.example.org'), RRClass.IN, RRType.A,
RRTTL(3600))
- a_rr.add_rdata(Rdata(RRType.A(), RRClass.IN(), address))
+ a_rr.add_rdata(Rdata(RRType.A, RRClass.IN, address))
return (a_rr)
def test_journal_write(self):
diff --git a/src/lib/python/isc/datasrc/tests/zone_loader_test.py b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
index 62f67cd..4cd4879 100644
--- a/src/lib/python/isc/datasrc/tests/zone_loader_test.py
+++ b/src/lib/python/isc/datasrc/tests/zone_loader_test.py
@@ -13,6 +13,7 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+import isc.log
import isc.datasrc
import isc.dns
@@ -96,7 +97,7 @@ class ZoneLoaderTests(unittest.TestCase):
"""
result, finder = self.client.find_zone(self.test_name)
self.assertEqual(self.client.SUCCESS, result)
- result, rrset, _ = finder.find(self.test_name, isc.dns.RRType.SOA())
+ result, rrset, _ = finder.find(self.test_name, isc.dns.RRType.SOA)
self.assertEqual(finder.SUCCESS, result)
self.assertEqual(soa_txt, rrset.to_text())
@@ -231,7 +232,7 @@ class ZoneLoaderTests(unittest.TestCase):
def test_wrong_class_from_client(self):
# For ds->ds loading, wrong class is detected upon construction
# Need a bit of the extended setup for CH source client
- clientlist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH())
+ clientlist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH)
clientlist.configure('[ { "type": "static", "params": "' +
STATIC_ZONE_FILE +'" } ]', False)
self.source_client, _, _ = clientlist.find(isc.dns.Name("bind."),
diff --git a/src/lib/python/isc/ddns/libddns_messages.mes b/src/lib/python/isc/ddns/libddns_messages.mes
index 406151c..abdd4e0 100644
--- a/src/lib/python/isc/ddns/libddns_messages.mes
+++ b/src/lib/python/isc/ddns/libddns_messages.mes
@@ -121,7 +121,7 @@ a bad class. The class of the update RRset must be either the same
as the class in the Zone Section, ANY, or NONE.
A FORMERR response is sent back to the client.
-% LIBDDNS_UPDATE_DATASRC_ERROR error in datasource during DDNS update: %1
+% LIBDDNS_UPDATE_DATASRC_COMMIT_FAILED error in datasource during DDNS update: %1
An error occurred while committing the DDNS update changes to the
datasource. The specific error is printed. A SERVFAIL response is sent
back to the client.
@@ -167,7 +167,7 @@ rejected by the zone's update ACL. When this library is used by
b10-ddns, the server will then completely ignore the request; no
response will be sent.
-% LIBDDNS_UPDATE_ERROR update client %1 for zone %2: %3
+% LIBDDNS_UPDATE_PROCESSING_FAILED update client %1 for zone %2: %3
Debug message. An error is found in processing a dynamic update
request. This log message is used for general errors that are not
normally expected to happen. So, in general, it would mean some
diff --git a/src/lib/python/isc/ddns/session.py b/src/lib/python/isc/ddns/session.py
index 60834fb..3368523 100644
--- a/src/lib/python/isc/ddns/session.py
+++ b/src/lib/python/isc/ddns/session.py
@@ -135,7 +135,7 @@ class DDNS_SOA:
def __write_soa_internal(self, origin_soa, soa_num):
'''Write back serial number to soa'''
new_soa = RRset(origin_soa.get_name(), origin_soa.get_class(),
- RRType.SOA(), origin_soa.get_ttl())
+ RRType.SOA, origin_soa.get_ttl())
soa_rdata_parts = origin_soa.get_rdata()[0].to_text().split()
soa_rdata_parts[2] = str(soa_num.get_value())
new_soa.add_rdata(Rdata(origin_soa.get_type(), origin_soa.get_class(),
@@ -248,18 +248,18 @@ class UpdateSession:
self.__check_update_acl(self.__zname, self.__zclass)
self._create_diff()
prereq_result = self.__check_prerequisites()
- if prereq_result != Rcode.NOERROR():
+ if prereq_result != Rcode.NOERROR:
self.__make_response(prereq_result)
return UPDATE_ERROR, self.__zname, self.__zclass
update_result = self.__do_update()
- if update_result != Rcode.NOERROR():
+ if update_result != Rcode.NOERROR:
self.__make_response(update_result)
return UPDATE_ERROR, self.__zname, self.__zclass
- self.__make_response(Rcode.NOERROR())
+ self.__make_response(Rcode.NOERROR)
return UPDATE_SUCCESS, self.__zname, self.__zclass
except UpdateError as e:
if not e.nolog:
- logger.debug(logger.DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_ERROR,
+ logger.debug(logger.DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_PROCESSING_FAILED,
ClientFormatter(self.__client_addr, self.__tsig),
ZoneFormatter(e.zname, e.zclass), e)
# If RCODE is specified, create a corresponding resonse and return
@@ -272,7 +272,7 @@ class UpdateSession:
except isc.datasrc.Error as e:
logger.error(LIBDDNS_DATASRC_ERROR,
ClientFormatter(self.__client_addr, self.__tsig), e)
- self.__make_response(Rcode.SERVFAIL())
+ self.__make_response(Rcode.SERVFAIL)
return UPDATE_ERROR, None, None
def _get_update_zone(self):
@@ -295,11 +295,11 @@ class UpdateSession:
n_zones = self.__message.get_rr_count(SECTION_ZONE)
if n_zones != 1:
raise UpdateError('Invalid number of records in zone section: ' +
- str(n_zones), None, None, Rcode.FORMERR())
+ str(n_zones), None, None, Rcode.FORMERR)
zrecord = self.__message.get_question()[0]
- if zrecord.get_type() != RRType.SOA():
+ if zrecord.get_type() != RRType.SOA:
raise UpdateError('update zone section contains non-SOA',
- None, None, Rcode.FORMERR())
+ None, None, Rcode.FORMERR)
# See if we're serving a primary zone specified in the zone section.
zname = zrecord.get_name()
@@ -316,12 +316,12 @@ class UpdateSession:
logger.debug(DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_FORWARD_FAIL,
ClientFormatter(self.__client_addr, self.__tsig),
ZoneFormatter(zname, zclass))
- raise UpdateError('forward', zname, zclass, Rcode.NOTIMP(), True)
+ raise UpdateError('forward', zname, zclass, Rcode.NOTIMP, True)
# zone wasn't found
logger.debug(DBGLVL_TRACE_BASIC, LIBDDNS_UPDATE_NOTAUTH,
ClientFormatter(self.__client_addr, self.__tsig),
ZoneFormatter(zname, zclass))
- raise UpdateError('notauth', zname, zclass, Rcode.NOTAUTH(), True)
+ raise UpdateError('notauth', zname, zclass, Rcode.NOTAUTH, True)
def _create_diff(self):
'''
@@ -352,7 +352,7 @@ class UpdateSession:
logger.info(LIBDDNS_UPDATE_DENIED,
ClientFormatter(self.__client_addr, self.__tsig),
ZoneFormatter(zname, zclass))
- raise UpdateError('rejected', zname, zclass, Rcode.REFUSED(), True)
+ raise UpdateError('rejected', zname, zclass, Rcode.REFUSED, True)
if action == DROP:
logger.info(LIBDDNS_UPDATE_DROPPED,
ClientFormatter(self.__client_addr, self.__tsig),
@@ -459,7 +459,7 @@ class UpdateSession:
def __check_prerequisites(self):
'''Check the prerequisites section of the UPDATE Message.
RFC2136 Section 2.4.
- Returns a dns Rcode signaling either no error (Rcode.NOERROR())
+ Returns a dns Rcode signaling either no error (Rcode.NOERROR)
or that one of the prerequisites failed (any other Rcode).
'''
@@ -473,20 +473,20 @@ class UpdateSession:
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.NOTZONE()
+ return Rcode.NOTZONE
# Algorithm taken from RFC2136 Section 3.2
- if rrset.get_class() == RRClass.ANY():
+ if rrset.get_class() == RRClass.ANY:
if rrset.get_ttl().get_value() != 0 or\
rrset.get_rdata_count() != 0:
logger.info(LIBDDNS_PREREQ_FORMERR_ANY,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
- elif rrset.get_type() == RRType.ANY():
+ return Rcode.FORMERR
+ elif rrset.get_type() == RRType.ANY:
if not self.__prereq_name_in_use(rrset):
- rcode = Rcode.NXDOMAIN()
+ rcode = Rcode.NXDOMAIN
logger.info(LIBDDNS_PREREQ_NAME_IN_USE_FAILED,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
@@ -494,23 +494,23 @@ class UpdateSession:
return rcode
else:
if not self.__prereq_rrset_exists(rrset):
- rcode = Rcode.NXRRSET()
+ rcode = Rcode.NXRRSET
logger.info(LIBDDNS_PREREQ_RRSET_EXISTS_FAILED,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset), rcode)
return rcode
- elif rrset.get_class() == RRClass.NONE():
+ elif rrset.get_class() == RRClass.NONE:
if rrset.get_ttl().get_value() != 0 or\
rrset.get_rdata_count() != 0:
logger.info(LIBDDNS_PREREQ_FORMERR_NONE,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
- elif rrset.get_type() == RRType.ANY():
+ return Rcode.FORMERR
+ elif rrset.get_type() == RRType.ANY:
if not self.__prereq_name_not_in_use(rrset):
- rcode = Rcode.YXDOMAIN()
+ rcode = Rcode.YXDOMAIN
logger.info(LIBDDNS_PREREQ_NAME_NOT_IN_USE_FAILED,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
@@ -518,7 +518,7 @@ class UpdateSession:
return rcode
else:
if not self.__prereq_rrset_does_not_exist(rrset):
- rcode = Rcode.YXRRSET()
+ rcode = Rcode.YXRRSET
logger.info(LIBDDNS_PREREQ_RRSET_DOES_NOT_EXIST_FAILED,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
@@ -530,7 +530,7 @@ class UpdateSession:
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
else:
collect_rrsets(exact_match_rrsets, rrset)
else:
@@ -538,11 +538,11 @@ class UpdateSession:
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
for collected_rrset in exact_match_rrsets:
if not self.__prereq_rrset_exists_value(collected_rrset):
- rcode = Rcode.NXRRSET()
+ rcode = Rcode.NXRRSET
logger.info(LIBDDNS_PREREQ_RRSET_EXISTS_VAL_FAILED,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
@@ -550,7 +550,7 @@ class UpdateSession:
return rcode
# All prerequisites are satisfied
- return Rcode.NOERROR()
+ return Rcode.NOERROR
def __set_soa_rrset(self, rrset):
'''Sets the given rrset to the member __added_soa (which
@@ -570,7 +570,7 @@ class UpdateSession:
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.NOTZONE()
+ return Rcode.NOTZONE
if rrset.get_class() == self.__zclass:
# In fact, all metatypes are in a specific range,
# so one check can test TKEY to ANY
@@ -581,52 +581,52 @@ class UpdateSession:
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
- if rrset.get_type() == RRType.SOA():
+ return Rcode.FORMERR
+ if rrset.get_type() == RRType.SOA:
# In case there's multiple soa records in the update
# somehow, just take the last
for rr in foreach_rr(rrset):
self.__set_soa_rrset(rr)
- elif rrset.get_class() == RRClass.ANY():
+ elif rrset.get_class() == RRClass.ANY:
if rrset.get_ttl().get_value() != 0:
logger.info(LIBDDNS_UPDATE_DELETE_NONZERO_TTL,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
if rrset.get_rdata_count() > 0:
logger.info(LIBDDNS_UPDATE_DELETE_RRSET_NOT_EMPTY,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
if rrset.get_type().get_code() >= 249 and\
rrset.get_type().get_code() <= 254:
logger.info(LIBDDNS_UPDATE_DELETE_BAD_TYPE,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
- elif rrset.get_class() == RRClass.NONE():
+ return Rcode.FORMERR
+ elif rrset.get_class() == RRClass.NONE:
if rrset.get_ttl().get_value() != 0:
logger.info(LIBDDNS_UPDATE_DELETE_RR_NONZERO_TTL,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
if rrset.get_type().get_code() >= 249:
logger.info(LIBDDNS_UPDATE_DELETE_RR_BAD_TYPE,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
+ return Rcode.FORMERR
else:
logger.info(LIBDDNS_UPDATE_BAD_CLASS,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
RRsetFormatter(rrset))
- return Rcode.FORMERR()
- return Rcode.NOERROR()
+ return Rcode.FORMERR
+ return Rcode.NOERROR
def __do_update_add_single_rr(self, rr, existing_rrset):
'''Helper for __do_update_add_rrs_to_rrset: only add the
@@ -657,7 +657,7 @@ class UpdateSession:
# For a number of cases, we may need to remove data in the zone
# (note; SOA is handled separately by __do_update, so that one
# is explicitely ignored here)
- if rrset.get_type() == RRType.SOA():
+ if rrset.get_type() == RRType.SOA:
return
result, orig_rrset, _ = self.__diff.find(rrset.get_name(),
rrset.get_type())
@@ -668,7 +668,7 @@ class UpdateSession:
return
elif result == ZoneFinder.SUCCESS:
# if update is cname, and zone rr is not, ignore
- if rrset.get_type() == RRType.CNAME():
+ if rrset.get_type() == RRType.CNAME:
# Remove original CNAME record (the new one
# is added below)
self.__diff.delete_data(orig_rrset)
@@ -679,7 +679,7 @@ class UpdateSession:
elif result == ZoneFinder.NXRRSET:
# There is data present, but not for this type.
# If this type is CNAME, ignore the update
- if rrset.get_type() == RRType.CNAME():
+ if rrset.get_type() == RRType.CNAME:
return
for rr in foreach_rr(rrset):
self.__do_update_add_single_rr(rr, orig_rrset)
@@ -696,8 +696,8 @@ class UpdateSession:
rrset.get_type())
if result == ZoneFinder.SUCCESS:
if to_delete.get_name() == self.__zname and\
- (to_delete.get_type() == RRType.SOA() or\
- to_delete.get_type() == RRType.NS()):
+ (to_delete.get_type() == RRType.SOA or\
+ to_delete.get_type() == RRType.NS):
# ignore
return
for rr in foreach_rr(to_delete):
@@ -749,8 +749,8 @@ class UpdateSession:
for to_delete in rrsets:
# if name == self.__zname and type is soa or ns, don't delete!
if to_delete.get_name() == self.__zname and\
- (to_delete.get_type() == RRType.SOA() or
- to_delete.get_type() == RRType.NS()):
+ (to_delete.get_type() == RRType.SOA or
+ to_delete.get_type() == RRType.NS):
continue
else:
for rr in foreach_rr(to_delete):
@@ -771,10 +771,10 @@ class UpdateSession:
to_delete = convert_rrset_class(rrset, self.__zclass)
if rrset.get_name() == self.__zname:
- if rrset.get_type() == RRType.SOA():
+ if rrset.get_type() == RRType.SOA:
# ignore
return
- elif rrset.get_type() == RRType.NS():
+ elif rrset.get_type() == RRType.NS:
# hmm. okay. annoying. There must be at least one left,
# delegate to helper method
self.__ns_deleter_helper(to_delete)
@@ -793,14 +793,14 @@ class UpdateSession:
# serial magic and add the newly created one
# get it from DS and to increment and stuff
- result, old_soa, _ = self.__diff.find(self.__zname, RRType.SOA(),
+ result, old_soa, _ = self.__diff.find(self.__zname, RRType.SOA,
ZoneFinder.NO_WILDCARD |
ZoneFinder.FIND_GLUE_OK)
# We may implement recovering from missing SOA data at some point, but
# for now servfail on such a broken state
if result != ZoneFinder.SUCCESS:
raise UpdateError("Error finding SOA record in datasource.",
- self.__zname, self.__zclass, Rcode.SERVFAIL())
+ self.__zname, self.__zclass, Rcode.SERVFAIL)
serial_operation = DDNS_SOA()
if self.__added_soa is not None and\
serial_operation.soa_update_check(old_soa, self.__added_soa):
@@ -820,7 +820,7 @@ class UpdateSession:
'''
# prescan
prescan_result = self.__do_prescan()
- if prescan_result != Rcode.NOERROR():
+ if prescan_result != Rcode.NOERROR:
return prescan_result
# update
@@ -841,22 +841,22 @@ class UpdateSession:
for rrset in self.__message.get_section(SECTION_UPDATE):
if rrset.get_class() == self.__zclass:
self.__do_update_add_rrs_to_rrset(rrset)
- elif rrset.get_class() == RRClass.ANY():
- if rrset.get_type() == RRType.ANY():
+ elif rrset.get_class() == RRClass.ANY:
+ if rrset.get_type() == RRType.ANY:
self.__do_update_delete_name(rrset)
else:
self.__do_update_delete_rrset(rrset)
- elif rrset.get_class() == RRClass.NONE():
+ elif rrset.get_class() == RRClass.NONE:
self.__do_update_delete_rrs_from_rrset(rrset)
self.__diff.commit()
- return Rcode.NOERROR()
+ return Rcode.NOERROR
except isc.datasrc.Error as dse:
- logger.info(LIBDDNS_UPDATE_DATASRC_ERROR, dse)
- return Rcode.SERVFAIL()
+ logger.info(LIBDDNS_UPDATE_DATASRC_COMMIT_FAILED, dse)
+ return Rcode.SERVFAIL
except Exception as uce:
logger.error(LIBDDNS_UPDATE_UNCAUGHT_EXCEPTION,
ClientFormatter(self.__client_addr),
ZoneFormatter(self.__zname, self.__zclass),
uce)
- return Rcode.SERVFAIL()
+ return Rcode.SERVFAIL
diff --git a/src/lib/python/isc/ddns/tests/session_tests.py b/src/lib/python/isc/ddns/tests/session_tests.py
index 6a67c3a..bc25310 100644
--- a/src/lib/python/isc/ddns/tests/session_tests.py
+++ b/src/lib/python/isc/ddns/tests/session_tests.py
@@ -30,8 +30,8 @@ WRITE_ZONE_DB_FILE = TESTDATA_WRITE_PATH + "rwtest.sqlite3.copied"
WRITE_ZONE_DB_CONFIG = "{ \"database_file\": \"" + WRITE_ZONE_DB_FILE + "\"}"
TEST_ZONE_NAME = Name('example.org')
-UPDATE_RRTYPE = RRType.SOA()
-TEST_RRCLASS = RRClass.IN()
+UPDATE_RRTYPE = RRType.SOA
+TEST_RRCLASS = RRClass.IN
TEST_ZONE_RECORD = Question(TEST_ZONE_NAME, TEST_RRCLASS, UPDATE_RRTYPE)
TEST_CLIENT6 = ('2001:db8::1', 53, 0, 0)
TEST_CLIENT4 = ('192.0.2.1', 53)
@@ -42,8 +42,8 @@ def create_update_msg(zones=[TEST_ZONE_RECORD], prerequisites=[],
updates=[], tsig_key=None):
msg = Message(Message.RENDER)
msg.set_qid(5353) # arbitrary chosen
- msg.set_opcode(Opcode.UPDATE())
- msg.set_rcode(Rcode.NOERROR())
+ msg.set_opcode(Opcode.UPDATE)
+ msg.set_rcode(Rcode.NOERROR)
for z in zones:
msg.add_question(z)
for p in prerequisites:
@@ -99,7 +99,7 @@ class SessionModuleTests(unittest.TestCase):
def test_foreach_rr_in_rrset(self):
rrset = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.A(), 3600, [ "192.0.2.1" ])
+ RRType.A, 3600, [ "192.0.2.1" ])
l = []
for rr in foreach_rr(rrset):
@@ -121,17 +121,17 @@ class SessionModuleTests(unittest.TestCase):
def test_convert_rrset_class(self):
# Converting an RRSET to a different class should work
# if the rdata types can be converted
- rrset = create_rrset("www.example.org", RRClass.NONE(), RRType.A(),
+ rrset = create_rrset("www.example.org", RRClass.NONE, RRType.A,
3600, [ b'\xc0\x00\x02\x01', b'\xc0\x00\x02\x02'])
- rrset2 = convert_rrset_class(rrset, RRClass.IN())
+ rrset2 = convert_rrset_class(rrset, RRClass.IN)
self.assertEqual("www.example.org. 3600 IN A 192.0.2.1\n" +
"www.example.org. 3600 IN A 192.0.2.2\n",
str(rrset2))
- rrset3 = convert_rrset_class(rrset2, RRClass.NONE())
- self.assertEqual("www.example.org. 3600 CLASS254 A \\# 4 " +
- "c0000201\nwww.example.org. 3600 CLASS254 " +
+ rrset3 = convert_rrset_class(rrset2, RRClass.NONE)
+ self.assertEqual("www.example.org. 3600 NONE A \\# 4 " +
+ "c0000201\nwww.example.org. 3600 NONE " +
"A \\# 4 c0000202\n",
str(rrset3))
@@ -140,10 +140,10 @@ class SessionModuleTests(unittest.TestCase):
# there was a ticket about making a better hierarchy for
# dns/parsing related exceptions)
self.assertRaises(InvalidRdataLength, convert_rrset_class,
- rrset, RRClass.CH())
+ rrset, RRClass.CH)
add_rdata(rrset, b'\xc0\x00')
self.assertRaises(DNSMessageFORMERR, convert_rrset_class,
- rrset, RRClass.IN())
+ rrset, RRClass.IN)
def test_collect_rrsets(self):
'''
@@ -152,25 +152,25 @@ class SessionModuleTests(unittest.TestCase):
'''
collected = []
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.1" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.1" ]))
# Same name and class, different type
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.TXT(), 0, [ "one" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.2" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.TXT(), 0, [ "two" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.TXT, 0, [ "one" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.2" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.TXT, 0, [ "two" ]))
# Same class and type as an existing one, different name
- collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.3" ]))
+ collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.3" ]))
# Same name and type as an existing one, different class
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
- RRType.TXT(), 0, [ "one" ]))
- collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.4" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
- RRType.TXT(), 0, [ "two" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+ RRType.TXT, 0, [ "one" ]))
+ collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.4" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+ RRType.TXT, 0, [ "two" ]))
strings = [ rrset.to_text() for rrset in collected ]
# note + vs , in this list
@@ -216,7 +216,7 @@ class SessionTestBase(unittest.TestCase):
'''Perform common checks on update resposne message.'''
self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_QR))
# note: we convert opcode to text it'd be more helpful on failure.
- self.assertEqual(Opcode.UPDATE().to_text(), msg.get_opcode().to_text())
+ self.assertEqual(Opcode.UPDATE.to_text(), msg.get_opcode().to_text())
self.assertEqual(expected_rcode.to_text(), msg.get_rcode().to_text())
# All sections should be cleared
self.assertEqual(0, msg.get_rr_count(SECTION_ZONE))
@@ -230,22 +230,22 @@ class TestDDNSSOA(unittest.TestCase):
'''unittest for update_soa function'''
soa_update = DDNS_SOA()
soa_rr = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600, ["ns1.example.org. " +
+ RRType.SOA, 3600, ["ns1.example.org. " +
"admin.example.org. " +
"1233 3600 1800 2419200 7200"])
expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600, ["ns1.example.org. "
+ RRType.SOA, 3600, ["ns1.example.org. "
+ "admin.example.org. " +
"1234 3600 1800 2419200 7200"])
self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
expected_soa_rr.get_rdata()[0].to_text())
max_serial = 2 ** 32 - 1
soa_rdata = "%d %s"%(max_serial,"3600 1800 2419200 7200")
- soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(), 3600,
+ soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA, 3600,
["ns1.example.org. " + "admin.example.org. " +
soa_rdata])
expected_soa_rr = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600, ["ns1.example.org. "
+ RRType.SOA, 3600, ["ns1.example.org. "
+ "admin.example.org. " +
"1 3600 1800 2419200 7200"])
self.assertEqual(soa_update.update_soa(soa_rr).get_rdata()[0].to_text(),
@@ -253,11 +253,11 @@ class TestDDNSSOA(unittest.TestCase):
def test_soa_update_check(self):
'''unittest for soa_update_check function'''
- small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+ small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
3600, ["ns1.example.org. " +
"admin.example.org. " +
"1233 3600 1800 2419200 7200"])
- large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+ large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
3600, ["ns1.example.org. " +
"admin.example.org. " +
"1234 3600 1800 2419200 7200"])
@@ -269,11 +269,11 @@ class TestDDNSSOA(unittest.TestCase):
small_soa_rr))
small_serial = 1235 + 2 ** 31
soa_rdata = "%d %s"%(small_serial,"3600 1800 2419200 7200")
- small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+ small_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
3600, ["ns1.example.org. " +
"admin.example.org. " +
soa_rdata])
- large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA(),
+ large_soa_rr = create_rrset("example.org", TEST_RRCLASS, RRType.SOA,
3600, ["ns1.example.org. " +
"admin.example.org. " +
"1234 3600 1800 2419200 7200"])
@@ -305,41 +305,41 @@ class SessionTest(SessionTestBase):
self.assertEqual(UPDATE_ERROR, result)
self.assertEqual(None, zname)
self.assertEqual(None, zclass)
- self.check_response(session.get_message(), Rcode.FORMERR())
+ self.check_response(session.get_message(), Rcode.FORMERR)
# Zone section contains multiple records
msg = create_update_msg(zones=[TEST_ZONE_RECORD, TEST_ZONE_RECORD])
session = UpdateSession(msg, TEST_CLIENT4, None)
self.assertEqual(UPDATE_ERROR, session.handle()[0])
- self.check_response(session.get_message(), Rcode.FORMERR())
+ self.check_response(session.get_message(), Rcode.FORMERR)
# Zone section's type is not SOA
msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.A())])
+ RRType.A)])
session = UpdateSession(msg, TEST_CLIENT4, None)
self.assertEqual(UPDATE_ERROR, session.handle()[0])
- self.check_response(session.get_message(), Rcode.FORMERR())
+ self.check_response(session.get_message(), Rcode.FORMERR)
def test_update_secondary(self):
# specified zone is configured as a secondary. Since this
# implementation doesn't support update forwarding, the result
# should be NOTIMP.
msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.SOA())])
+ RRType.SOA)])
session = UpdateSession(msg, TEST_CLIENT4,
ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
TEST_RRCLASS, self._datasrc_client))
self.assertEqual(UPDATE_ERROR, session.handle()[0])
- self.check_response(session.get_message(), Rcode.NOTIMP())
+ self.check_response(session.get_message(), Rcode.NOTIMP)
def check_notauth(self, zname, zclass=TEST_RRCLASS):
'''Common test sequence for the 'notauth' test'''
- msg = create_update_msg(zones=[Question(zname, zclass, RRType.SOA())])
+ msg = create_update_msg(zones=[Question(zname, zclass, RRType.SOA)])
session = UpdateSession(msg, TEST_CLIENT4,
ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
TEST_RRCLASS, self._datasrc_client))
self.assertEqual(UPDATE_ERROR, session.handle()[0])
- self.check_response(session.get_message(), Rcode.NOTAUTH())
+ self.check_response(session.get_message(), Rcode.NOTAUTH)
def test_update_notauth(self):
'''Update attempt for non authoritative zones'''
@@ -349,7 +349,7 @@ class SessionTest(SessionTestBase):
# (match must be exact)
self.check_notauth(Name('sub.example.org'))
# zone class doesn't match
- self.check_notauth(Name('example.org'), RRClass.CH())
+ self.check_notauth(Name('example.org'), RRClass.CH)
def test_update_datasrc_error(self):
# if the data source client raises an exception, it should result in
@@ -358,17 +358,17 @@ class SessionTest(SessionTestBase):
def find_zone(self, name):
raise isc.datasrc.Error('faked exception')
msg = create_update_msg(zones=[Question(TEST_ZONE_NAME, TEST_RRCLASS,
- RRType.SOA())])
+ RRType.SOA)])
session = UpdateSession(msg, TEST_CLIENT4,
ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
TEST_RRCLASS,
BadDataSourceClient()))
self.assertEqual(UPDATE_ERROR, session.handle()[0])
- self.check_response(session.get_message(), Rcode.SERVFAIL())
+ self.check_response(session.get_message(), Rcode.SERVFAIL)
def test_foreach_rr_in_rrset(self):
rrset = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.A(), 3600, [ "192.0.2.1" ])
+ RRType.A, 3600, [ "192.0.2.1" ])
l = []
for rr in foreach_rr(rrset):
@@ -390,17 +390,17 @@ class SessionTest(SessionTestBase):
def test_convert_rrset_class(self):
# Converting an RRSET to a different class should work
# if the rdata types can be converted
- rrset = create_rrset("www.example.org", RRClass.NONE(), RRType.A(),
+ rrset = create_rrset("www.example.org", RRClass.NONE, RRType.A,
3600, [ b'\xc0\x00\x02\x01', b'\xc0\x00\x02\x02'])
- rrset2 = convert_rrset_class(rrset, RRClass.IN())
+ rrset2 = convert_rrset_class(rrset, RRClass.IN)
self.assertEqual("www.example.org. 3600 IN A 192.0.2.1\n" +
"www.example.org. 3600 IN A 192.0.2.2\n",
str(rrset2))
- rrset3 = convert_rrset_class(rrset2, RRClass.NONE())
- self.assertEqual("www.example.org. 3600 CLASS254 A \\# 4 " +
- "c0000201\nwww.example.org. 3600 CLASS254 " +
+ rrset3 = convert_rrset_class(rrset2, RRClass.NONE)
+ self.assertEqual("www.example.org. 3600 NONE A \\# 4 " +
+ "c0000201\nwww.example.org. 3600 NONE " +
"A \\# 4 c0000202\n",
str(rrset3))
@@ -409,10 +409,10 @@ class SessionTest(SessionTestBase):
# there was a ticket about making a better hierarchy for
# dns/parsing related exceptions)
self.assertRaises(InvalidRdataLength, convert_rrset_class,
- rrset, RRClass.CH())
+ rrset, RRClass.CH)
add_rdata(rrset, b'\xc0\x00')
self.assertRaises(DNSMessageFORMERR, convert_rrset_class,
- rrset, RRClass.IN())
+ rrset, RRClass.IN)
def test_collect_rrsets(self):
'''
@@ -421,25 +421,25 @@ class SessionTest(SessionTestBase):
'''
collected = []
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.1" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.1" ]))
# Same name and class, different type
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.TXT(), 0, [ "one" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.2" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN(),
- RRType.TXT(), 0, [ "two" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.TXT, 0, [ "one" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.2" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.IN,
+ RRType.TXT, 0, [ "two" ]))
# Same class and type as an existing one, different name
- collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.3" ]))
+ collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.3" ]))
# Same name and type as an existing one, different class
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
- RRType.TXT(), 0, [ "one" ]))
- collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.4" ]))
- collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH(),
- RRType.TXT(), 0, [ "two" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+ RRType.TXT, 0, [ "one" ]))
+ collect_rrsets(collected, create_rrset("b.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.4" ]))
+ collect_rrsets(collected, create_rrset("a.example.org", RRClass.CH,
+ RRType.TXT, 0, [ "two" ]))
strings = [ rrset.to_text() for rrset in collected ]
# note + vs , in this list
@@ -469,64 +469,64 @@ class SessionTest(SessionTestBase):
'''
# Basic existence checks
# www.example.org should have an A, but not an MX
- rrset = create_rrset("www.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("www.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, expected, rrset)
- rrset = create_rrset("www.example.org", rrclass, RRType.MX(), 0)
+ rrset = create_rrset("www.example.org", rrclass, RRType.MX, 0)
self.__prereq_helper(method, not expected, rrset)
# example.org should have an MX, but not an A
- rrset = create_rrset("example.org", rrclass, RRType.MX(), 0)
+ rrset = create_rrset("example.org", rrclass, RRType.MX, 0)
self.__prereq_helper(method, expected, rrset)
- rrset = create_rrset("example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, not expected, rrset)
# Also check the case where the name does not even exist
- rrset = create_rrset("doesnotexist.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("doesnotexist.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, not expected, rrset)
# Wildcard expansion should not be applied, but literal matches
# should work
- rrset = create_rrset("foo.wildcard.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("foo.wildcard.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, not expected, rrset)
- rrset = create_rrset("*.wildcard.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("*.wildcard.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, expected, rrset)
# Likewise, CNAME directly should match, but what it points to should
# not
- rrset = create_rrset("cname.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("cname.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, not expected, rrset)
- rrset = create_rrset("cname.example.org", rrclass, RRType.CNAME(), 0)
+ rrset = create_rrset("cname.example.org", rrclass, RRType.CNAME, 0)
self.__prereq_helper(method, expected, rrset)
# And also make sure a delegation (itself) is not treated as existing
# data
- rrset = create_rrset("foo.sub.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("foo.sub.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, not expected, rrset)
# But the delegation data itself should match
- rrset = create_rrset("sub.example.org", rrclass, RRType.NS(), 0)
+ rrset = create_rrset("sub.example.org", rrclass, RRType.NS, 0)
self.__prereq_helper(method, expected, rrset)
# As should glue
- rrset = create_rrset("ns.sub.example.org", rrclass, RRType.A(), 0)
+ rrset = create_rrset("ns.sub.example.org", rrclass, RRType.A, 0)
self.__prereq_helper(method, expected, rrset)
def test_check_prerequisite_exists(self):
method = self._session._UpdateSession__prereq_rrset_exists
self.__check_prerequisite_exists_combined(method,
- RRClass.ANY(),
+ RRClass.ANY,
True)
def test_check_prerequisite_does_not_exist(self):
method = self._session._UpdateSession__prereq_rrset_does_not_exist
self.__check_prerequisite_exists_combined(method,
- RRClass.NONE(),
+ RRClass.NONE,
False)
def test_check_prerequisite_exists_value(self):
method = self._session._UpdateSession__prereq_rrset_exists_value
- rrset = create_rrset("www.example.org", RRClass.IN(), RRType.A(), 0)
+ rrset = create_rrset("www.example.org", RRClass.IN, RRType.A, 0)
# empty one should not match
self.__prereq_helper(method, False, rrset)
@@ -539,7 +539,7 @@ class SessionTest(SessionTestBase):
self.__prereq_helper(method, False, rrset)
# Also test one with more than one RR
- rrset = create_rrset("example.org", RRClass.IN(), RRType.NS(), 0)
+ rrset = create_rrset("example.org", RRClass.IN, RRType.NS, 0)
self.__prereq_helper(method, False, rrset)
add_rdata(rrset, "ns1.example.org.")
self.__prereq_helper(method, False, rrset)
@@ -551,7 +551,7 @@ class SessionTest(SessionTestBase):
self.__prereq_helper(method, False, rrset)
# Repeat that, but try a different order of Rdata addition
- rrset = create_rrset("example.org", RRClass.IN(), RRType.NS(), 0)
+ rrset = create_rrset("example.org", RRClass.IN, RRType.NS, 0)
self.__prereq_helper(method, False, rrset)
add_rdata(rrset, "ns3.example.org.")
self.__prereq_helper(method, False, rrset)
@@ -563,8 +563,8 @@ class SessionTest(SessionTestBase):
self.__prereq_helper(method, False, rrset)
# and test one where the name does not even exist
- rrset = create_rrset("doesnotexist.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.1" ])
+ rrset = create_rrset("doesnotexist.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.1" ])
self.__prereq_helper(method, False, rrset)
def __check_prerequisite_name_in_use_combined(self, method, rrclass,
@@ -573,42 +573,42 @@ class SessionTest(SessionTestBase):
in behaviour) methods __prereq_name_in_use and
__prereq_name_not_in_use
'''
- rrset = create_rrset("example.org", rrclass, RRType.ANY(), 0)
+ rrset = create_rrset("example.org", rrclass, RRType.ANY, 0)
self.__prereq_helper(method, expected, rrset)
- rrset = create_rrset("www.example.org", rrclass, RRType.ANY(), 0)
+ rrset = create_rrset("www.example.org", rrclass, RRType.ANY, 0)
self.__prereq_helper(method, expected, rrset)
rrset = create_rrset("doesnotexist.example.org", rrclass,
- RRType.ANY(), 0)
+ RRType.ANY, 0)
self.__prereq_helper(method, not expected, rrset)
rrset = create_rrset("belowdelegation.sub.example.org", rrclass,
- RRType.ANY(), 0)
+ RRType.ANY, 0)
self.__prereq_helper(method, not expected, rrset)
rrset = create_rrset("foo.wildcard.example.org", rrclass,
- RRType.ANY(), 0)
+ RRType.ANY, 0)
self.__prereq_helper(method, not expected, rrset)
# empty nonterminal should not match
rrset = create_rrset("nonterminal.example.org", rrclass,
- RRType.ANY(), 0)
+ RRType.ANY, 0)
self.__prereq_helper(method, not expected, rrset)
rrset = create_rrset("empty.nonterminal.example.org", rrclass,
- RRType.ANY(), 0)
+ RRType.ANY, 0)
self.__prereq_helper(method, expected, rrset)
def test_check_prerequisite_name_in_use(self):
method = self._session._UpdateSession__prereq_name_in_use
self.__check_prerequisite_name_in_use_combined(method,
- RRClass.ANY(),
+ RRClass.ANY,
True)
def test_check_prerequisite_name_not_in_use(self):
method = self._session._UpdateSession__prereq_name_not_in_use
self.__check_prerequisite_name_in_use_combined(method,
- RRClass.NONE(),
+ RRClass.NONE,
False)
def check_prerequisite_result(self, expected, prerequisites):
@@ -632,7 +632,7 @@ class SessionTest(SessionTestBase):
self.assertEqual(expected.to_text(),
session._UpdateSession__message.get_rcode().to_text())
# And that the result looks right
- if expected == Rcode.NOERROR():
+ if expected == Rcode.NOERROR:
self.assertEqual(UPDATE_SUCCESS, result)
else:
self.assertEqual(UPDATE_ERROR, result)
@@ -672,7 +672,7 @@ class SessionTest(SessionTestBase):
self.assertEqual(expected.to_text(),
session._UpdateSession__message.get_rcode().to_text())
# And that the result looks right
- if expected == Rcode.NOERROR():
+ if expected == Rcode.NOERROR:
self.assertEqual(UPDATE_SUCCESS, result)
else:
self.assertEqual(UPDATE_ERROR, result)
@@ -685,78 +685,75 @@ class SessionTest(SessionTestBase):
# in the specific prerequisite type tests)
# Let's first define a number of prereq's that should succeed
- rrset_exists_yes = create_rrset("example.org", RRClass.ANY(),
- RRType.SOA(), 0)
+ rrset_exists_yes = create_rrset("example.org", RRClass.ANY,
+ RRType.SOA, 0)
- rrset_exists_value_yes = create_rrset("www.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.1" ])
+ rrset_exists_value_yes = create_rrset("www.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.1" ])
rrset_does_not_exist_yes = create_rrset("foo.example.org",
- RRClass.NONE(), RRType.SOA(),
+ RRClass.NONE, RRType.SOA,
0)
- name_in_use_yes = create_rrset("www.example.org", RRClass.ANY(),
- RRType.ANY(), 0)
+ name_in_use_yes = create_rrset("www.example.org", RRClass.ANY,
+ RRType.ANY, 0)
- name_not_in_use_yes = create_rrset("foo.example.org", RRClass.NONE(),
- RRType.ANY(), 0)
+ name_not_in_use_yes = create_rrset("foo.example.org", RRClass.NONE,
+ RRType.ANY, 0)
- rrset_exists_value_1 = create_rrset("example.org", RRClass.IN(),
- RRType.NS(), 0,
- [ "ns1.example.org." ])
- rrset_exists_value_2 = create_rrset("example.org", RRClass.IN(),
- RRType.NS(), 0,
- [ "ns2.example.org." ])
- rrset_exists_value_3 = create_rrset("example.org", RRClass.IN(),
- RRType.NS(), 0,
- [ "ns3.example.org." ])
+ rrset_exists_value_1 = create_rrset("example.org", RRClass.IN,
+ RRType.NS, 0, ["ns1.example.org."])
+ rrset_exists_value_2 = create_rrset("example.org", RRClass.IN,
+ RRType.NS, 0, ["ns2.example.org."])
+ rrset_exists_value_3 = create_rrset("example.org", RRClass.IN,
+ RRType.NS, 0, ["ns3.example.org."])
# and a number that should not
- rrset_exists_no = create_rrset("foo.example.org", RRClass.ANY(),
- RRType.SOA(), 0)
+ rrset_exists_no = create_rrset("foo.example.org", RRClass.ANY,
+ RRType.SOA, 0)
- rrset_exists_value_no = create_rrset("www.example.org", RRClass.IN(),
- RRType.A(), 0, [ "192.0.2.2" ])
+ rrset_exists_value_no = create_rrset("www.example.org", RRClass.IN,
+ RRType.A, 0, [ "192.0.2.2" ])
- rrset_does_not_exist_no = create_rrset("example.org", RRClass.NONE(),
- RRType.SOA(), 0)
+ rrset_does_not_exist_no = create_rrset("example.org", RRClass.NONE,
+ RRType.SOA, 0)
- name_in_use_no = create_rrset("foo.example.org", RRClass.ANY(),
- RRType.ANY(), 0)
+ name_in_use_no = create_rrset("foo.example.org", RRClass.ANY,
+ RRType.ANY, 0)
- name_not_in_use_no = create_rrset("www.example.org", RRClass.NONE(),
- RRType.ANY(), 0)
+ name_not_in_use_no = create_rrset("www.example.org", RRClass.NONE,
+ RRType.ANY, 0)
# check 'no' result codes
- self.check_prerequisite_result(Rcode.NXRRSET(),
+ self.check_prerequisite_result(Rcode.NXRRSET,
[ rrset_exists_no ])
- self.check_prerequisite_result(Rcode.NXRRSET(),
+ self.check_prerequisite_result(Rcode.NXRRSET,
[ rrset_exists_value_no ])
- self.check_prerequisite_result(Rcode.YXRRSET(),
+ self.check_prerequisite_result(Rcode.YXRRSET,
[ rrset_does_not_exist_no ])
- self.check_prerequisite_result(Rcode.NXDOMAIN(),
+ self.check_prerequisite_result(Rcode.NXDOMAIN,
[ name_in_use_no ])
- self.check_prerequisite_result(Rcode.YXDOMAIN(),
+ self.check_prerequisite_result(Rcode.YXDOMAIN,
[ name_not_in_use_no ])
# the 'yes' codes should result in ok
# individually
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_exists_yes ] )
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_exists_value_yes ])
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_does_not_exist_yes ])
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ name_in_use_yes ])
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ name_not_in_use_yes ])
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_exists_value_1,
rrset_exists_value_2,
rrset_exists_value_3])
# and together
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_exists_yes,
rrset_exists_value_yes,
rrset_does_not_exist_yes,
@@ -768,7 +765,7 @@ class SessionTest(SessionTestBase):
# try out a permutation, note that one rrset is split up,
# and the order of the RRs should not matter
- self.check_prerequisite_result(Rcode.NOERROR(),
+ self.check_prerequisite_result(Rcode.NOERROR,
[ rrset_exists_value_3,
rrset_exists_yes,
rrset_exists_value_2,
@@ -777,7 +774,7 @@ class SessionTest(SessionTestBase):
# Should fail on the first error, even if most of the
# prerequisites are ok
- self.check_prerequisite_result(Rcode.NXDOMAIN(),
+ self.check_prerequisite_result(Rcode.NXDOMAIN,
[ rrset_exists_value_3,
rrset_exists_yes,
rrset_exists_value_2,
@@ -786,39 +783,39 @@ class SessionTest(SessionTestBase):
rrset_exists_value_1])
def test_prerequisite_notzone(self):
- rrset = create_rrset("some.other.zone.", RRClass.ANY(), RRType.SOA(), 0)
- self.check_prerequisite_result(Rcode.NOTZONE(), [ rrset ])
+ rrset = create_rrset("some.other.zone.", RRClass.ANY, RRType.SOA, 0)
+ self.check_prerequisite_result(Rcode.NOTZONE, [ rrset ])
def test_prerequisites_formerr(self):
# test for form errors in the prerequisite section
# Class ANY, non-zero TTL
- rrset = create_rrset("example.org", RRClass.ANY(), RRType.SOA(), 1)
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ rrset = create_rrset("example.org", RRClass.ANY, RRType.SOA, 1)
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
# Class ANY, but with rdata
- rrset = create_rrset("example.org", RRClass.ANY(), RRType.A(), 0,
+ rrset = create_rrset("example.org", RRClass.ANY, RRType.A, 0,
[ b'\x00\x00\x00\x00' ])
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
# Class NONE, non-zero TTL
- rrset = create_rrset("example.org", RRClass.NONE(), RRType.SOA(), 1)
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ rrset = create_rrset("example.org", RRClass.NONE, RRType.SOA, 1)
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
# Class NONE, but with rdata
- rrset = create_rrset("example.org", RRClass.NONE(), RRType.A(), 0,
+ rrset = create_rrset("example.org", RRClass.NONE, RRType.A, 0,
[ b'\x00\x00\x00\x00' ])
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
# Matching class and type, but non-zero TTL
- rrset = create_rrset("www.example.org", RRClass.IN(), RRType.A(), 1,
+ rrset = create_rrset("www.example.org", RRClass.IN, RRType.A, 1,
[ "192.0.2.1" ])
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
# Completely different class
- rrset = create_rrset("example.org", RRClass.CH(), RRType.TXT(), 0,
+ rrset = create_rrset("example.org", RRClass.CH, RRType.TXT, 0,
[ "foo" ])
- self.check_prerequisite_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prerequisite_result(Rcode.FORMERR, [ rrset ])
def __prereq_helper(self, method, expected, rrset):
'''Calls the given method with self._datasrc_client
@@ -830,84 +827,84 @@ class SessionTest(SessionTestBase):
'''Prepare a number of RRsets to be used in several update tests
The rrsets are stored in self'''
orig_a_rrset = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.A(), 3600, [ "192.0.2.1" ])
+ RRType.A, 3600, [ "192.0.2.1" ])
self.orig_a_rrset = orig_a_rrset
rrset_update_a = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.A(), 3600,
+ RRType.A, 3600,
[ "192.0.2.2", "192.0.2.3" ])
self.rrset_update_a = rrset_update_a
rrset_update_soa = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600,
+ RRType.SOA, 3600,
[ "ns1.example.org. " +
"admin.example.org. " +
"1233 3600 1800 2419200 7200" ])
self.rrset_update_soa = rrset_update_soa
- rrset_update_soa_del = create_rrset("example.org", RRClass.NONE(),
- RRType.SOA(), 0,
+ rrset_update_soa_del = create_rrset("example.org", RRClass.NONE,
+ RRType.SOA, 0,
[ "ns1.example.org. " +
"admin.example.org. " +
"1233 3600 1800 2419200 7200" ])
self.rrset_update_soa_del = rrset_update_soa_del
rrset_update_soa2 = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600,
+ RRType.SOA, 3600,
[ "ns1.example.org. " +
"admin.example.org. " +
"4000 3600 1800 2419200 7200" ])
self.rrset_update_soa2 = rrset_update_soa2
- rrset_update_del_name = create_rrset("www.example.org", RRClass.ANY(),
- RRType.ANY(), 0)
+ rrset_update_del_name = create_rrset("www.example.org", RRClass.ANY,
+ RRType.ANY, 0)
self.rrset_update_del_name = rrset_update_del_name
- rrset_update_del_name_apex = create_rrset("example.org", RRClass.ANY(),
- RRType.ANY(), 0)
+ rrset_update_del_name_apex = create_rrset("example.org", RRClass.ANY,
+ RRType.ANY, 0)
self.rrset_update_del_name_apex = rrset_update_del_name_apex
- rrset_update_del_rrset = create_rrset("www.example.org", RRClass.ANY(),
- RRType.A(), 0)
+ rrset_update_del_rrset = create_rrset("www.example.org", RRClass.ANY,
+ RRType.A, 0)
self.rrset_update_del_rrset = rrset_update_del_rrset
- rrset_update_del_mx_apex = create_rrset("example.org", RRClass.ANY(),
- RRType.MX(), 0)
+ rrset_update_del_mx_apex = create_rrset("example.org", RRClass.ANY,
+ RRType.MX, 0)
self.rrset_update_del_mx_apex = rrset_update_del_mx_apex
- rrset_update_del_soa_apex = create_rrset("example.org", RRClass.ANY(),
- RRType.SOA(), 0)
+ rrset_update_del_soa_apex = create_rrset("example.org", RRClass.ANY,
+ RRType.SOA, 0)
self.rrset_update_del_soa_apex = rrset_update_del_soa_apex
- rrset_update_del_ns_apex = create_rrset("example.org", RRClass.ANY(),
- RRType.NS(), 0)
+ rrset_update_del_ns_apex = create_rrset("example.org", RRClass.ANY,
+ RRType.NS, 0)
self.rrset_update_del_ns_apex = rrset_update_del_ns_apex
rrset_update_del_rrset_part = create_rrset("www.example.org",
- RRClass.NONE(), RRType.A(),
+ RRClass.NONE, RRType.A,
0,
[ b'\xc0\x00\x02\x02',
b'\xc0\x00\x02\x03' ])
self.rrset_update_del_rrset_part = rrset_update_del_rrset_part
- rrset_update_del_rrset_ns = create_rrset("example.org", RRClass.NONE(),
- RRType.NS(), 0,
+ rrset_update_del_rrset_ns = create_rrset("example.org", RRClass.NONE,
+ RRType.NS, 0,
[ b'\x03ns1\x07example\x03org\x00',
b'\x03ns2\x07example\x03org\x00',
b'\x03ns3\x07example\x03org\x00' ])
self.rrset_update_del_rrset_ns = rrset_update_del_rrset_ns
- rrset_update_del_rrset_mx = create_rrset("example.org", RRClass.NONE(),
- RRType.MX(), 0,
+ rrset_update_del_rrset_mx = create_rrset("example.org", RRClass.NONE,
+ RRType.MX, 0,
[ b'\x00\x0a\x04mail\x07example\x03org\x00' ])
self.rrset_update_del_rrset_mx = rrset_update_del_rrset_mx
def test_acl_before_prereq(self):
- name_in_use_no = create_rrset("foo.example.org", RRClass.ANY(),
- RRType.ANY(), 0)
+ name_in_use_no = create_rrset("foo.example.org", RRClass.ANY,
+ RRType.ANY, 0)
# Test a prerequisite that would fail
- self.check_full_handle_result(Rcode.NXDOMAIN(), [], [ name_in_use_no ])
+ self.check_full_handle_result(Rcode.NXDOMAIN, [], [ name_in_use_no ])
# Change ACL so that it would be denied
self._acl_map = {(TEST_ZONE_NAME, TEST_RRCLASS):
@@ -915,7 +912,7 @@ class SessionTest(SessionTestBase):
# The prerequisite should now not be reached; it should fail on the
# ACL
- self.check_full_handle_result(Rcode.REFUSED(), [], [ name_in_use_no ])
+ self.check_full_handle_result(Rcode.REFUSED, [], [ name_in_use_no ])
def test_prescan(self):
'''Test whether the prescan succeeds on data that is ok, and whether
@@ -923,29 +920,29 @@ class SessionTest(SessionTestBase):
# prepare a set of correct update statements
self.__initialize_update_rrsets()
- self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+ self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_a ])
# check if soa is noticed
- self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_soa ],
+ self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_soa ],
self.rrset_update_soa)
# Other types of succesful prechecks
- self.check_prescan_result(Rcode.NOERROR(), [ self.rrset_update_soa2 ],
+ self.check_prescan_result(Rcode.NOERROR, [ self.rrset_update_soa2 ],
self.rrset_update_soa2)
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_del_name ])
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_del_name_apex ])
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset ])
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_del_mx_apex ])
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset_part ])
# and check a few permutations of the above
# all of them (with one of the soas)
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[
self.rrset_update_a,
self.rrset_update_soa,
@@ -960,16 +957,16 @@ class SessionTest(SessionTestBase):
# Two soas. Should we reject or simply use the last?
# (RFC is not really explicit on this, but between the lines I read
# use the last)
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_soa,
self.rrset_update_soa2 ],
self.rrset_update_soa2)
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[ self.rrset_update_soa2,
self.rrset_update_soa ],
self.rrset_update_soa)
- self.check_prescan_result(Rcode.NOERROR(),
+ self.check_prescan_result(Rcode.NOERROR,
[
self.rrset_update_del_mx_apex,
self.rrset_update_del_name,
@@ -984,36 +981,36 @@ class SessionTest(SessionTestBase):
def test_prescan_failures(self):
'''Test whether prescan fails on bad data'''
# out of zone data
- rrset = create_rrset("different.zone", RRClass.ANY(), RRType.TXT(), 0)
- self.check_prescan_result(Rcode.NOTZONE(), [ rrset ])
+ rrset = create_rrset("different.zone", RRClass.ANY, RRType.TXT, 0)
+ self.check_prescan_result(Rcode.NOTZONE, [ rrset ])
# forbidden type, zone class
- rrset = create_rrset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.ANY(), 0,
+ rrset = create_rrset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.ANY, 0,
[ b'\x00' ])
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
# non-zero TTL, class ANY
- rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.TXT(), 1)
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.TXT, 1)
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
# non-zero Rdata, class ANY
- rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.TXT(), 0,
+ rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.TXT, 0,
[ "foo" ])
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
# forbidden type, class ANY
- rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY(), RRType.AXFR(), 0,
+ rrset = create_rrset(TEST_ZONE_NAME, RRClass.ANY, RRType.AXFR, 0,
[ b'\x00' ])
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
# non-zero TTL, class NONE
- rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE(), RRType.TXT(), 1)
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE, RRType.TXT, 1)
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
# forbidden type, class NONE
- rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE(), RRType.AXFR(), 0,
+ rrset = create_rrset(TEST_ZONE_NAME, RRClass.NONE, RRType.AXFR, 0,
[ b'\x00' ])
- self.check_prescan_result(Rcode.FORMERR(), [ rrset ])
+ self.check_prescan_result(Rcode.FORMERR, [ rrset ])
def __check_inzone_data(self, expected_result, name, rrtype,
expected_rrset = None):
@@ -1054,7 +1051,7 @@ class SessionTest(SessionTestBase):
# during this test, we will extend it at some point
extended_a_rrset = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.A(), 3600,
+ RRType.A, 3600,
[ "192.0.2.1",
"192.0.2.2",
"192.0.2.3" ])
@@ -1062,90 +1059,90 @@ class SessionTest(SessionTestBase):
# Sanity check, make sure original data is really there before updates
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.orig_a_rrset)
# Add two rrs
- self.check_full_handle_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+ self.check_full_handle_result(Rcode.NOERROR, [ self.rrset_update_a ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
extended_a_rrset)
# Adding the same RRsets should not make a difference.
- self.check_full_handle_result(Rcode.NOERROR(), [ self.rrset_update_a ])
+ self.check_full_handle_result(Rcode.NOERROR, [ self.rrset_update_a ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
extended_a_rrset)
# Now delete those two, and we should end up with the original RRset
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset_part ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.orig_a_rrset)
# 'Deleting' them again should make no difference
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset_part ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.orig_a_rrset)
# But deleting the entire rrset, independent of its contents, should
# work
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
# Check that if we update the SOA, it is updated to our value
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_soa2 ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.SOA(),
+ RRType.SOA,
self.rrset_update_soa2)
def test_glue_deletions(self):
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("sub.example.org."),
- RRType.NS())
+ RRType.NS)
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("ns.sub.example.org."),
- RRType.A())
+ RRType.A)
# See that we can delete glue
rrset_delete_glue = create_rrset("ns.sub.example.org.",
- RRClass.ANY(),
- RRType.A(),
+ RRClass.ANY,
+ RRType.A,
0)
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ rrset_delete_glue ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("sub.example.org."),
- RRType.NS())
+ RRType.NS)
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("ns.sub.example.org."),
- RRType.A())
+ RRType.A)
# Check that we don't accidentally delete a delegation if we
# try to delete non-existent glue
rrset_delete_nonexistent_glue = create_rrset("foo.sub.example.org.",
- RRClass.ANY(),
- RRType.A(),
+ RRClass.ANY,
+ RRType.A,
0)
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ rrset_delete_nonexistent_glue ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("sub.example.org."),
- RRType.NS())
+ RRType.NS)
def test_update_add_new_data(self):
'''
@@ -1154,26 +1151,26 @@ class SessionTest(SessionTestBase):
# Add data at a completely new name
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("new.example.org"),
- RRType.A())
- rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.A(),
+ RRType.A)
+ rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.A,
3600, [ "192.0.2.1", "192.0.2.2" ])
- self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+ self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("new.example.org"),
- RRType.A(),
+ RRType.A,
rrset)
# Also try a name where data is present, but none of this
# specific type
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
isc.dns.Name("new.example.org"),
- RRType.TXT())
- rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.TXT(),
+ RRType.TXT)
+ rrset = create_rrset("new.example.org", TEST_RRCLASS, RRType.TXT,
3600, [ "foo" ])
- self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+ self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("new.example.org"),
- RRType.TXT(),
+ RRType.TXT,
rrset)
def test_update_add_new_data_interspersed(self):
@@ -1186,36 +1183,36 @@ class SessionTest(SessionTestBase):
# Add data at a completely new name
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("new_a.example.org"),
- RRType.A())
+ RRType.A)
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("new_txt.example.org"),
- RRType.TXT())
+ RRType.TXT)
- rrset1 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A(),
+ rrset1 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A,
3600, [ "192.0.2.1" ])
- rrset2 = create_rrset("new_txt.example.org", TEST_RRCLASS, RRType.TXT(),
+ rrset2 = create_rrset("new_txt.example.org", TEST_RRCLASS, RRType.TXT,
3600, [ "foo" ])
- rrset3 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A(),
+ rrset3 = create_rrset("new_a.example.org", TEST_RRCLASS, RRType.A,
3600, [ "192.0.2.2" ])
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ rrset1, rrset2, rrset3 ])
# The update should have merged rrset1 and rrset3
rrset_merged = create_rrset("new_a.example.org", TEST_RRCLASS,
- RRType.A(), 3600,
+ RRType.A, 3600,
[ "192.0.2.1", "192.0.2.2" ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("new_a.example.org"),
- RRType.A(),
+ RRType.A,
rrset_merged)
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("new_txt.example.org"),
- RRType.TXT(),
+ RRType.TXT,
rrset2)
def test_update_delete_name(self):
@@ -1227,21 +1224,21 @@ class SessionTest(SessionTestBase):
# First check it is there
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
# Delete the entire name
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_name ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
# Should still be gone after pointless second delete
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_name ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
def test_update_apex_special_cases(self):
'''
@@ -1251,23 +1248,23 @@ class SessionTest(SessionTestBase):
# the original SOA
orig_soa_rrset = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600,
+ RRType.SOA, 3600,
[ "ns1.example.org. " +
"admin.example.org. " +
"1234 3600 1800 2419200 7200" ])
# At some point, the SOA SERIAL will be auto-incremented
incremented_soa_rrset_01 = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600, ["ns1.example.org. " +
+ RRType.SOA, 3600, ["ns1.example.org. " +
"admin.example.org. " +
"1235 3600 1800 2419200 7200" ])
incremented_soa_rrset_02 = create_rrset("example.org", TEST_RRCLASS,
- RRType.SOA(), 3600, ["ns1.example.org. " +
+ RRType.SOA, 3600, ["ns1.example.org. " +
"admin.example.org. " +
"1236 3600 1800 2419200 7200" ])
# We will delete some of the NS records
orig_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
- RRType.NS(), 3600,
+ RRType.NS, 3600,
[ "ns1.example.org.",
"ns2.example.org.",
"ns3.example.org." ])
@@ -1275,48 +1272,48 @@ class SessionTest(SessionTestBase):
# Sanity check, make sure original data is really there before updates
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.NS(),
+ RRType.NS,
orig_ns_rrset)
# We will delete the MX record later in this test, so let's make
# sure that it exists (we do not care about its value)
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.MX())
+ RRType.MX)
# Check that we cannot delete the SOA record by direct deletion
# both by name+type and by full rrset
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_soa_apex,
self.rrset_update_soa_del ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.SOA(),
+ RRType.SOA,
incremented_soa_rrset_01)
# If we delete everything at the apex, the SOA and NS rrsets should be
# untouched (but serial will be incremented)
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_name_apex ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.SOA(),
+ RRType.SOA,
incremented_soa_rrset_02)
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.NS(),
+ RRType.NS,
orig_ns_rrset)
# but the MX should be gone
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
isc.dns.Name("example.org"),
- RRType.MX())
+ RRType.MX)
# Deleting the NS rrset by name and type only, it should also be left
# untouched
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_ns_apex ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.NS(),
+ RRType.NS,
orig_ns_rrset)
def test_update_apex_special_case_ns_rrset(self):
@@ -1325,28 +1322,28 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
# When we are done, we should have a reduced NS rrset
short_ns_rrset = create_rrset("example.org", TEST_RRCLASS,
- RRType.NS(), 3600,
+ RRType.NS, 3600,
[ "ns3.example.org." ])
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset_ns ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.NS(),
+ RRType.NS,
short_ns_rrset)
def test_update_apex_special_case_ns_rrset2(self):
# If we add new NS records, then delete all existing ones, it
# should not keep any
self.__initialize_update_rrsets()
- new_ns = create_rrset("example.org", TEST_RRCLASS, RRType.NS(), 3600,
+ new_ns = create_rrset("example.org", TEST_RRCLASS, RRType.NS, 3600,
[ "newns1.example.org.", "newns2.example.org." ])
- self.check_full_handle_result(Rcode.NOERROR(),
+ self.check_full_handle_result(Rcode.NOERROR,
[ new_ns,
self.rrset_update_del_rrset_ns ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.NS(),
+ RRType.NS,
new_ns)
def test_update_delete_normal_rrset_at_apex(self):
@@ -1358,12 +1355,12 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("example.org"),
- RRType.MX())
- self.check_full_handle_result(Rcode.NOERROR(),
+ RRType.MX)
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset_mx ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXRRSET,
isc.dns.Name("example.org"),
- RRType.MX())
+ RRType.MX)
def test_update_add_then_delete_rrset(self):
# If we add data, then delete the whole rrset, added data should
@@ -1371,13 +1368,13 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A())
- self.check_full_handle_result(Rcode.NOERROR(),
+ RRType.A)
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_a,
self.rrset_update_del_rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
def test_update_add_then_delete_name(self):
# If we add data, then delete the entire name, added data should
@@ -1385,13 +1382,13 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A())
- self.check_full_handle_result(Rcode.NOERROR(),
+ RRType.A)
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_a,
self.rrset_update_del_name ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.NXDOMAIN,
isc.dns.Name("www.example.org"),
- RRType.A())
+ RRType.A)
def test_update_delete_then_add_rrset(self):
# If we delete an entire rrset, then add something there again,
@@ -1399,13 +1396,13 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A())
- self.check_full_handle_result(Rcode.NOERROR(),
+ RRType.A)
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_rrset,
self.rrset_update_a ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.rrset_update_a)
def test_update_delete_then_add_rrset(self):
@@ -1414,13 +1411,13 @@ class SessionTest(SessionTestBase):
self.__initialize_update_rrsets()
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A())
- self.check_full_handle_result(Rcode.NOERROR(),
+ RRType.A)
+ self.check_full_handle_result(Rcode.NOERROR,
[ self.rrset_update_del_name,
self.rrset_update_a ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.rrset_update_a)
def test_update_cname_special_cases(self):
@@ -1428,31 +1425,31 @@ class SessionTest(SessionTestBase):
# Sanity check
orig_cname_rrset = create_rrset("cname.example.org", TEST_RRCLASS,
- RRType.CNAME(), 3600,
+ RRType.CNAME, 3600,
[ "www.example.org." ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
isc.dns.Name("cname.example.org"),
- RRType.A(),
+ RRType.A,
orig_cname_rrset)
# If we try to add data where a cname is preset
- rrset = create_rrset("cname.example.org", TEST_RRCLASS, RRType.A(),
+ rrset = create_rrset("cname.example.org", TEST_RRCLASS, RRType.A,
3600, [ "192.0.2.1" ])
- self.check_full_handle_result(Rcode.NOERROR(), [ rrset ])
+ self.check_full_handle_result(Rcode.NOERROR, [ rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
isc.dns.Name("cname.example.org"),
- RRType.A(),
+ RRType.A,
orig_cname_rrset)
# But updating the cname itself should work
new_cname_rrset = create_rrset("cname.example.org", TEST_RRCLASS,
- RRType.CNAME(), 3600,
+ RRType.CNAME, 3600,
[ "mail.example.org." ])
- self.check_full_handle_result(Rcode.NOERROR(), [ new_cname_rrset ])
+ self.check_full_handle_result(Rcode.NOERROR, [ new_cname_rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.CNAME,
isc.dns.Name("cname.example.org"),
- RRType.A(),
+ RRType.A,
new_cname_rrset)
self.__initialize_update_rrsets()
@@ -1461,27 +1458,27 @@ class SessionTest(SessionTestBase):
# present should do nothing either
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.orig_a_rrset)
new_cname_rrset = create_rrset("www.example.org", TEST_RRCLASS,
- RRType.CNAME(), 3600,
+ RRType.CNAME, 3600,
[ "mail.example.org." ])
- self.check_full_handle_result(Rcode.NOERROR(), [ new_cname_rrset ])
+ self.check_full_handle_result(Rcode.NOERROR, [ new_cname_rrset ])
self.__check_inzone_data(isc.datasrc.ZoneFinder.SUCCESS,
isc.dns.Name("www.example.org"),
- RRType.A(),
+ RRType.A,
self.orig_a_rrset)
def test_update_bad_class(self):
- rrset = create_rrset("example.org.", RRClass.CH(), RRType.TXT(), 0,
+ rrset = create_rrset("example.org.", RRClass.CH, RRType.TXT, 0,
[ "foo" ])
- self.check_full_handle_result(Rcode.FORMERR(), [ rrset ])
+ self.check_full_handle_result(Rcode.FORMERR, [ rrset ])
def test_uncaught_exception(self):
def my_exc():
raise Exception("foo")
self._session._UpdateSession__update_soa = my_exc
- self.assertEqual(Rcode.SERVFAIL().to_text(),
+ self.assertEqual(Rcode.SERVFAIL.to_text(),
self._session._UpdateSession__do_update().to_text())
class SessionACLTest(SessionTestBase):
@@ -1527,7 +1524,7 @@ class SessionACLTest(SessionTestBase):
self._datasrc_client,
acl_map))
self.assertEqual((UPDATE_ERROR, None, None), session.handle())
- self.check_response(session.get_message(), Rcode.REFUSED())
+ self.check_response(session.get_message(), Rcode.REFUSED)
# If the message contains TSIG, it should match the ACCEPT
# ACL entry, and the request should be granted.
diff --git a/src/lib/python/isc/ddns/tests/zone_config_tests.py b/src/lib/python/isc/ddns/tests/zone_config_tests.py
index 7facb48..0ada906 100644
--- a/src/lib/python/isc/ddns/tests/zone_config_tests.py
+++ b/src/lib/python/isc/ddns/tests/zone_config_tests.py
@@ -26,7 +26,7 @@ import socket
# Some common test parameters
TEST_ZONE_NAME = Name('example.org')
TEST_SECONDARY_ZONE_NAME = Name('example.com')
-TEST_RRCLASS = RRClass.IN()
+TEST_RRCLASS = RRClass.IN
TEST_TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
TEST_ACL_CONTEXT = isc.acl.dns.RequestContext(
socket.getaddrinfo("192.0.2.1", 1234, 0, socket.SOCK_DGRAM,
@@ -88,12 +88,12 @@ class ZoneConfigTest(unittest.TestCase):
# zone class doesn't match (but zone name matches)
self.__datasrc_client.set_find_result(DataSourceClient.SUCCESS)
zconfig = ZoneConfig({(TEST_SECONDARY_ZONE_NAME, TEST_RRCLASS)},
- RRClass.CH(), self.__datasrc_client)
+ RRClass.CH, self.__datasrc_client)
self.assertEqual((ZONE_NOTFOUND, None),
(zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS)))
# similar to the previous case, but also in the secondary list
zconfig = ZoneConfig({(TEST_ZONE_NAME, TEST_RRCLASS)},
- RRClass.CH(), self.__datasrc_client)
+ RRClass.CH, self.__datasrc_client)
self.assertEqual((ZONE_NOTFOUND, None),
(zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS)))
@@ -107,7 +107,7 @@ class ZoneConfigTest(unittest.TestCase):
zconfig = ZoneConfig({(TEST_SECONDARY_ZONE_NAME, TEST_RRCLASS),
(Name('example'), TEST_RRCLASS),
(Name('sub.example.org'), TEST_RRCLASS),
- (TEST_ZONE_NAME, RRClass.CH())},
+ (TEST_ZONE_NAME, RRClass.CH)},
TEST_RRCLASS, self.__datasrc_client)
self.assertEqual((ZONE_PRIMARY, self.__datasrc_client),
self.zconfig.find_zone(TEST_ZONE_NAME, TEST_RRCLASS))
@@ -134,7 +134,7 @@ class ACLConfigTest(unittest.TestCase):
# 'All reject' ACL will still apply for any other zones
acl = self.__zconfig.get_update_acl(Name('example.com'), TEST_RRCLASS)
self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
- acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH())
+ acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH)
self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
# Test with a map with a few more ACL entries. Should be nothing
@@ -143,14 +143,14 @@ class ACLConfigTest(unittest.TestCase):
REQUEST_LOADER.load([{"action": "REJECT"}]),
(TEST_ZONE_NAME, TEST_RRCLASS):
REQUEST_LOADER.load([{"action": "ACCEPT"}]),
- (TEST_ZONE_NAME, RRClass.CH()):
+ (TEST_ZONE_NAME, RRClass.CH):
REQUEST_LOADER.load([{"action": "DROP"}])}
self.__zconfig.set_update_acl_map(acl_map)
acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, TEST_RRCLASS)
self.assertEqual(ACCEPT, acl.execute(TEST_ACL_CONTEXT))
acl = self.__zconfig.get_update_acl(Name('example.com'), TEST_RRCLASS)
self.assertEqual(REJECT, acl.execute(TEST_ACL_CONTEXT))
- acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH())
+ acl = self.__zconfig.get_update_acl(TEST_ZONE_NAME, RRClass.CH)
self.assertEqual(DROP, acl.execute(TEST_ACL_CONTEXT))
if __name__ == "__main__":
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 46bb00b..1f75256 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -302,12 +302,12 @@ class NotifyOut:
format_zone_str(zone_name, zone_class))
return []
- result, ns_rrset, _ = finder.find(zone_name, RRType.NS())
+ result, ns_rrset, _ = finder.find(zone_name, RRType.NS)
if result is not finder.SUCCESS or ns_rrset is None:
logger.warn(NOTIFY_OUT_ZONE_NO_NS,
format_zone_str(zone_name, zone_class))
return []
- result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+ result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
if result is not finder.SUCCESS or soa_rrset is None or \
soa_rrset.get_rdata_count() != 1:
logger.warn(NOTIFY_OUT_ZONE_BAD_SOA,
@@ -323,11 +323,11 @@ class NotifyOut:
ns_result, ns_finder = ds_client.find_zone(ns_name)
if ns_result is DataSourceClient.SUCCESS or \
ns_result is DataSourceClient.PARTIALMATCH:
- result, rrset, _ = ns_finder.find(ns_name, RRType.A())
+ result, rrset, _ = ns_finder.find(ns_name, RRType.A)
if result is ns_finder.SUCCESS and rrset is not None:
addrs.extend([a.to_text() for a in rrset.get_rdata()])
- result, rrset, _ = ns_finder.find(ns_name, RRType.AAAA())
+ result, rrset, _ = ns_finder.find(ns_name, RRType.AAAA)
if result is ns_finder.SUCCESS and rrset is not None:
addrs.extend([aaaa.to_text()
for aaaa in rrset.get_rdata()])
@@ -509,10 +509,10 @@ class NotifyOut:
msg = Message(Message.RENDER)
qid = random.randint(0, 0xFFFF)
msg.set_qid(qid)
- msg.set_opcode(Opcode.NOTIFY())
- msg.set_rcode(Rcode.NOERROR())
+ msg.set_opcode(Opcode.NOTIFY)
+ msg.set_rcode(Rcode.NOERROR)
msg.set_header_flag(Message.HEADERFLAG_AA)
- msg.add_question(Question(zone_name, zone_class, RRType.SOA()))
+ msg.add_question(Question(zone_name, zone_class, RRType.SOA))
msg.add_rrset(Message.SECTION_ANSWER, self._get_zone_soa(zone_name,
zone_class))
return msg, qid
@@ -531,7 +531,7 @@ class NotifyOut:
zone_name.to_text() + '/' +
zone_class.to_text() + ' not found')
- result, soa_rrset, _ = finder.find(zone_name, RRType.SOA())
+ result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
if result is not finder.SUCCESS or soa_rrset is None or \
soa_rrset.get_rdata_count() != 1:
raise NotifyOutDataSourceError('_get_zone_soa: Zone ' +
@@ -566,7 +566,7 @@ class NotifyOut:
Name(zone_notify_info.zone_name).to_text())
return _BAD_QUERY_NAME
- if msg.get_opcode() != Opcode.NOTIFY():
+ if msg.get_opcode() != Opcode.NOTIFY:
logger.warn(NOTIFY_OUT_REPLY_BAD_OPCODE, from_addr[0],
from_addr[1], msg.get_opcode().to_text())
return _BAD_OPCODE
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index 60c8f2f..ad1107f 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -377,7 +377,7 @@ class TestNotifyOut(unittest.TestCase):
def test_get_notify_slaves_from_ns(self):
records = self._notify._get_notify_slaves_from_ns(Name('example.net.'),
- RRClass.IN())
+ RRClass.IN)
self.assertEqual(6, len(records))
self.assertEqual('8:8::8:8', records[5])
self.assertEqual('7.7.7.7', records[4])
@@ -387,7 +387,7 @@ class TestNotifyOut(unittest.TestCase):
self.assertEqual('3.3.3.3', records[0])
records = self._notify._get_notify_slaves_from_ns(Name('example.com.'),
- RRClass.IN())
+ RRClass.IN)
self.assertEqual(3, len(records))
self.assertEqual('5:5::5:5', records[2])
self.assertEqual('4:4::4:4', records[1])
@@ -396,19 +396,19 @@ class TestNotifyOut(unittest.TestCase):
def test_get_notify_slaves_from_ns_unusual(self):
self._notify._db_file = TESTDATA_SRCDIR + '/brokentest.sqlite3'
self.assertEqual([], self._notify._get_notify_slaves_from_ns(
- Name('nons.example'), RRClass.IN()))
+ Name('nons.example'), RRClass.IN))
self.assertEqual([], self._notify._get_notify_slaves_from_ns(
- Name('nosoa.example'), RRClass.IN()))
+ Name('nosoa.example'), RRClass.IN))
self.assertEqual([], self._notify._get_notify_slaves_from_ns(
- Name('multisoa.example'), RRClass.IN()))
+ Name('multisoa.example'), RRClass.IN))
self.assertEqual([], self._notify._get_notify_slaves_from_ns(
- Name('nosuchzone.example'), RRClass.IN()))
+ Name('nosuchzone.example'), RRClass.IN))
# This will cause failure in getting access to the data source.
self._notify._db_file = TESTDATA_SRCDIR + '/nodir/error.sqlite3'
self.assertEqual([], self._notify._get_notify_slaves_from_ns(
- Name('example.com'), RRClass.IN()))
+ Name('example.com'), RRClass.IN))
def test_init_notify_out(self):
self._notify._init_notify_out(self._db_file)
diff --git a/src/lib/python/isc/server_common/dns_tcp.py b/src/lib/python/isc/server_common/dns_tcp.py
index 3b78d0d..9ce94fe 100644
--- a/src/lib/python/isc/server_common/dns_tcp.py
+++ b/src/lib/python/isc/server_common/dns_tcp.py
@@ -248,7 +248,7 @@ class DNSTCPContext:
ClientFormatter(self.__remote_addr),
self.__send_marker, total_len)
return self.SENDING
- logger.warn(PYSERVER_COMMON_DNS_TCP_SEND_ERROR,
+ logger.warn(PYSERVER_COMMON_DNS_TCP_SEND_FAILED,
ClientFormatter(self.__remote_addr),
self.__send_marker, total_len, ex)
self.__sock.close()
diff --git a/src/lib/python/isc/server_common/server_common_messages.mes b/src/lib/python/isc/server_common/server_common_messages.mes
index bd4e3cc..f22ce65 100644
--- a/src/lib/python/isc/server_common/server_common_messages.mes
+++ b/src/lib/python/isc/server_common/server_common_messages.mes
@@ -27,7 +27,7 @@ transmitted over a TCP connection, possibly after multiple send
operations. The destination address and the total size of the message
(including the 2-byte length field) are shown in the log message.
-% PYSERVER_COMMON_DNS_TCP_SEND_ERROR failed to send TCP message to %1 (%2/%3 bytes sent): %4
+% PYSERVER_COMMON_DNS_TCP_SEND_FAILED failed to send TCP message to %1 (%2/%3 bytes sent): %4
A DNS message has been attempted to be sent out over a TCP connection,
but it failed due to some network error. Although it's not expected
to happen too often, it can still happen for various reasons. The
diff --git a/src/lib/python/isc/statistics/tests/counters_test.py b/src/lib/python/isc/statistics/tests/counters_test.py
index 550fd1f..2d791c4 100644
--- a/src/lib/python/isc/statistics/tests/counters_test.py
+++ b/src/lib/python/isc/statistics/tests/counters_test.py
@@ -139,9 +139,9 @@ class TestBasicMethods(unittest.TestCase):
counters._get_counter(self.counters._statistics._data,
counter_name),
concurrency * number)
- self.assertGreater(
+ self.assertGreaterEqual(
counters._get_counter(self.counters._statistics._data,
- timer_name), 0)
+ timer_name), 0.0)
def test_concat(self):
# only strings
@@ -200,7 +200,7 @@ class BaseTestCounters():
if name.find('time_to_') == 0:
self.counters.start_timer(*args)
self.counters.stop_timer(*args)
- self.assertGreater(self.counters.get(*args), 0)
+ self.assertGreaterEqual(self.counters.get(*args), 0.0)
sec = self.counters.get(*args)
for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
isc.cc.data.set(self._statistics_data,
diff --git a/src/lib/python/isc/sysinfo/sysinfo.py b/src/lib/python/isc/sysinfo/sysinfo.py
index 8e4610c..099ac89 100644
--- a/src/lib/python/isc/sysinfo/sysinfo.py
+++ b/src/lib/python/isc/sysinfo/sysinfo.py
@@ -44,7 +44,7 @@ class SysInfo:
self._net_stats = 'Unknown\n'
self._net_connections = 'Unknown\n'
- # The following are Linux speicific, and should eventually be removed
+ # The following are Linux specific, and should eventually be removed
# from this level; for now we simply default to None (so they won't
# be printed)
self._platform_distro = None
@@ -162,9 +162,12 @@ class SysInfoPOSIX(SysInfo):
u = os.uname()
self._platform_name = u[0]
+ self._hostname = u[1]
self._platform_version = u[2]
self._platform_machine = u[4]
+ self._loadavg = os.getloadavg()
+
class SysInfoLinux(SysInfoPOSIX):
"""Linux implementation of the SysInfo class.
See the SysInfo class documentation for more information.
@@ -322,8 +325,8 @@ class SysInfoBSD(SysInfoPOSIX):
except (subprocess.CalledProcessError, OSError):
self._net_connections = 'Warning: "netstat -nr" command failed.\n'
-class SysInfoOpenBSD(SysInfoBSD):
- """OpenBSD implementation of the SysInfo class.
+class SysInfoNetBSD(SysInfoBSD):
+ """NetBSD and OpenBSD implementation of the SysInfo class.
See the SysInfo class documentation for more information.
"""
def __init__(self):
@@ -499,8 +502,8 @@ def SysInfoFromFactory():
osname = platform.system()
if osname == 'Linux':
return SysInfoLinux()
- elif osname == 'OpenBSD':
- return SysInfoOpenBSD()
+ elif (osname == 'NetBSD') or (osname == 'OpenBSD'):
+ return SysInfoNetBSD()
elif osname == 'FreeBSD':
return SysInfoFreeBSD()
elif osname == 'Darwin':
@@ -508,4 +511,4 @@ def SysInfoFromFactory():
elif osname == 'BIND10Testcase':
return SysInfoTestcase()
else:
- return SysInfo()
+ return SysInfoPOSIX()
diff --git a/src/lib/python/isc/testutils/rrset_utils.py b/src/lib/python/isc/testutils/rrset_utils.py
index 7d54063..eb3da28 100644
--- a/src/lib/python/isc/testutils/rrset_utils.py
+++ b/src/lib/python/isc/testutils/rrset_utils.py
@@ -30,7 +30,7 @@ def rrsets_equal(a, b):
a.get_class() == b.get_class() and \
a.get_type() == b.get_type() and \
a.get_ttl() == b.get_ttl() and \
- (a.get_type() == RRType.RRSIG() or
+ (a.get_type() == RRType.RRSIG or
sorted(a.get_rdata()) == sorted(b.get_rdata()))
# The following are short cut utilities to create an RRset of a specific
@@ -38,25 +38,25 @@ def rrsets_equal(a, b):
# tests, so we define default values for them for convenience.
def create_a(name, address, ttl=3600):
- rrset = RRset(name, RRClass.IN(), RRType.A(), RRTTL(ttl))
- rrset.add_rdata(Rdata(RRType.A(), RRClass.IN(), address))
+ rrset = RRset(name, RRClass.IN, RRType.A, RRTTL(ttl))
+ rrset.add_rdata(Rdata(RRType.A, RRClass.IN, address))
return rrset
def create_aaaa(name, address, ttl=3600):
- rrset = RRset(name, RRClass.IN(), RRType.AAAA(), RRTTL(ttl))
- rrset.add_rdata(Rdata(RRType.AAAA(), RRClass.IN(), address))
+ rrset = RRset(name, RRClass.IN, RRType.AAAA, RRTTL(ttl))
+ rrset.add_rdata(Rdata(RRType.AAAA, RRClass.IN, address))
return rrset
def create_ns(nsname, name=Name('example.com'), ttl=3600):
'''For convenience we use a default name often used as a zone name'''
- rrset = RRset(name, RRClass.IN(), RRType.NS(), RRTTL(ttl))
- rrset.add_rdata(Rdata(RRType.NS(), RRClass.IN(), nsname))
+ rrset = RRset(name, RRClass.IN, RRType.NS, RRTTL(ttl))
+ rrset.add_rdata(Rdata(RRType.NS, RRClass.IN, nsname))
return rrset
def create_cname(target='target.example.com.', name=Name('example.com'),
ttl=3600):
- rrset = RRset(name, RRClass.IN(), RRType.CNAME(), RRTTL(ttl))
- rrset.add_rdata(Rdata(RRType.CNAME(), RRClass.IN(), target))
+ rrset = RRset(name, RRClass.IN, RRType.CNAME, RRTTL(ttl))
+ rrset.add_rdata(Rdata(RRType.CNAME, RRClass.IN, target))
return rrset
def create_generic(name, rdlen, type=RRType('TYPE65300'), ttl=3600):
@@ -67,16 +67,16 @@ def create_generic(name, rdlen, type=RRType('TYPE65300'), ttl=3600):
The RDATA will be filled with specified length of all-0 data.
'''
- rrset = RRset(name, RRClass.IN(), type, RRTTL(ttl))
- rrset.add_rdata(Rdata(type, RRClass.IN(), '\\# ' +
+ rrset = RRset(name, RRClass.IN, type, RRTTL(ttl))
+ rrset.add_rdata(Rdata(type, RRClass.IN, '\\# ' +
str(rdlen) + ' ' + '00' * rdlen))
return rrset
def create_soa(serial, name=Name('example.com'), ttl=3600):
'''For convenience we use a default name often used as a zone name'''
- rrset = RRset(name, RRClass.IN(), RRType.SOA(), RRTTL(ttl))
+ rrset = RRset(name, RRClass.IN, RRType.SOA, RRTTL(ttl))
rdata_str = 'master.example.com. admin.example.com. ' + \
str(serial) + ' 3600 1800 2419200 7200'
- rrset.add_rdata(Rdata(RRType.SOA(), RRClass.IN(), rdata_str))
+ rrset.add_rdata(Rdata(RRType.SOA, RRClass.IN, rdata_str))
return rrset
diff --git a/src/lib/python/isc/xfrin/diff.py b/src/lib/python/isc/xfrin/diff.py
index 8d0bb08..4e06eea 100644
--- a/src/lib/python/isc/xfrin/diff.py
+++ b/src/lib/python/isc/xfrin/diff.py
@@ -146,12 +146,12 @@ class Diff:
"""
# first add or delete must be of type SOA
if len(buf) == 0 and\
- rr.get_type() != isc.dns.RRType.SOA():
+ rr.get_type() != isc.dns.RRType.SOA:
raise ValueError("First " + operation +
" in single update mode must be of type SOA")
# And later adds or deletes may not
elif len(buf) != 0 and\
- rr.get_type() == isc.dns.RRType.SOA():
+ rr.get_type() == isc.dns.RRType.SOA:
raise ValueError("Multiple SOA records in single " +
"update mode " + operation)
buf.append((operation, rr))
@@ -238,8 +238,8 @@ class Diff:
'''A helper routine to identify whether two RRsets are of the
same 'type'. For RRSIGs we should consider type covered, too.
'''
- if rrset1.get_type() != isc.dns.RRType.RRSIG() or \
- rrset2.get_type != isc.dns.RRType.RRSIG():
+ if rrset1.get_type() != isc.dns.RRType.RRSIG or \
+ rrset2.get_type != isc.dns.RRType.RRSIG:
return rrset1.get_type() == rrset2.get_type()
# RR type of the both RRsets is RRSIG. Compare type covered.
# We know they have exactly one RDATA.
@@ -425,7 +425,7 @@ class Diff:
return a.get_name() == b.get_name() and\
a.get_type() == b.get_type() and\
a.get_rdata()[0] == b.get_rdata()[0]
- if rr.get_type() == isc.dns.RRType.SOA():
+ if rr.get_type() == isc.dns.RRType.SOA:
return buf
else:
return [ op for op in buf if not same_rr(op[1], rr)]
diff --git a/src/lib/python/isc/xfrin/tests/diff_tests.py b/src/lib/python/isc/xfrin/tests/diff_tests.py
index f013cd5..bb83340 100644
--- a/src/lib/python/isc/xfrin/tests/diff_tests.py
+++ b/src/lib/python/isc/xfrin/tests/diff_tests.py
@@ -57,8 +57,8 @@ class DiffTest(unittest.TestCase):
self.__find_all_name = None
self.__find_all_options = None
# Some common values
- self.__rrclass = RRClass.IN()
- self.__type = RRType.A()
+ self.__rrclass = RRClass.IN
+ self.__type = RRType.A
self.__ttl = RRTTL(3600)
# And RRsets
# Create two valid rrsets
@@ -81,27 +81,27 @@ class DiffTest(unittest.TestCase):
# Also create a few other (valid) rrsets
# A SOA record
self.__rrset_soa = RRset(Name('example.org.'), self.__rrclass,
- RRType.SOA(), RRTTL(3600))
- self.__rrset_soa.add_rdata(Rdata(RRType.SOA(), self.__rrclass,
+ RRType.SOA, RRTTL(3600))
+ self.__rrset_soa.add_rdata(Rdata(RRType.SOA, self.__rrclass,
"ns1.example.org. " +
"admin.example.org. " +
"1233 3600 1800 2419200 7200"))
# A few single-rr rrsets that together would for a multi-rr rrset
self.__rrset3 = RRset(Name('c.example.org.'), self.__rrclass,
- RRType.TXT(), self.__ttl)
- self.__rrset3.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "one"))
+ RRType.TXT, self.__ttl)
+ self.__rrset3.add_rdata(Rdata(RRType.TXT, self.__rrclass, "one"))
self.__rrset4 = RRset(Name('c.example.org.'), self.__rrclass,
- RRType.TXT(), self.__ttl)
- self.__rrset4.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "two"))
+ RRType.TXT, self.__ttl)
+ self.__rrset4.add_rdata(Rdata(RRType.TXT, self.__rrclass, "two"))
self.__rrset5 = RRset(Name('c.example.org.'), self.__rrclass,
- RRType.TXT(), self.__ttl)
- self.__rrset5.add_rdata(Rdata(RRType.TXT(), self.__rrclass, "three"))
+ RRType.TXT, self.__ttl)
+ self.__rrset5.add_rdata(Rdata(RRType.TXT, self.__rrclass, "three"))
self.__rrset6 = RRset(Name('d.example.org.'), self.__rrclass,
- RRType.A(), self.__ttl)
- self.__rrset6.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.1"))
+ RRType.A, self.__ttl)
+ self.__rrset6.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.1"))
self.__rrset7 = RRset(Name('d.example.org.'), self.__rrclass,
- RRType.A(), self.__ttl)
- self.__rrset7.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.2"))
+ RRType.A, self.__ttl)
+ self.__rrset7.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.2"))
def __mock_compact(self):
"""
@@ -316,7 +316,7 @@ class DiffTest(unittest.TestCase):
self.assertRaises(ValueError, diff.add_data, self.__rrset2)
self.assertRaises(ValueError, diff.delete_data, self.__rrset1)
self.assertRaises(ValueError, diff.find, Name('foo.example.org.'),
- RRType.A())
+ RRType.A)
self.assertRaises(ValueError, diff.find_all, Name('foo.example.org.'))
diff.apply = orig_apply
self.assertRaises(ValueError, diff.apply)
@@ -435,9 +435,9 @@ class DiffTest(unittest.TestCase):
Test a wrong class of rrset is rejected.
"""
diff = Diff(self, Name('example.org.'))
- rrset = RRset(Name('a.example.org.'), RRClass.CH(), RRType.NS(),
+ rrset = RRset(Name('a.example.org.'), RRClass.CH, RRType.NS,
self.__ttl)
- rrset.add_rdata(Rdata(RRType.NS(), RRClass.CH(), 'ns.example.org.'))
+ rrset.add_rdata(Rdata(RRType.NS, RRClass.CH, 'ns.example.org.'))
self.assertRaises(ValueError, diff.add_data, rrset)
self.assertRaises(ValueError, diff.delete_data, rrset)
@@ -517,14 +517,14 @@ class DiffTest(unittest.TestCase):
'''
diff = Diff(self, Name('example.org.'))
rrsig1 = RRset(Name('example.org'), self.__rrclass,
- RRType.RRSIG(), RRTTL(3600))
- rrsig1.add_rdata(Rdata(RRType.RRSIG(), self.__rrclass,
+ RRType.RRSIG, RRTTL(3600))
+ rrsig1.add_rdata(Rdata(RRType.RRSIG, self.__rrclass,
'A 5 3 3600 20000101000000 20000201000000 ' +
'0 example.org. FAKEFAKEFAKE'))
diff.add_data(rrsig1)
rrsig2 = RRset(Name('example.org'), self.__rrclass,
- RRType.RRSIG(), RRTTL(1800))
- rrsig2.add_rdata(Rdata(RRType.RRSIG(), self.__rrclass,
+ RRType.RRSIG, RRTTL(1800))
+ rrsig2.add_rdata(Rdata(RRType.RRSIG, self.__rrclass,
'AAAA 5 3 3600 20000101000000 20000201000000 ' +
'1 example.org. FAKEFAKEFAKE'))
diff.add_data(rrsig2)
@@ -558,7 +558,7 @@ class DiffTest(unittest.TestCase):
'''
diff_multi = Diff(self, Name('example.org.'), single_update_mode=False)
self.assertRaises(ValueError, diff_multi.find_updated,
- Name('example.org.'), RRType.A())
+ Name('example.org.'), RRType.A)
self.assertRaises(ValueError, diff_multi.find_all_updated,
Name('example.org.'))
@@ -571,12 +571,12 @@ class DiffTest(unittest.TestCase):
'''
# full rrset for A (to check compact())
- txt = RRset(Name('c.example.org.'), self.__rrclass, RRType.TXT(),
+ txt = RRset(Name('c.example.org.'), self.__rrclass, RRType.TXT,
RRTTL(3600))
txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "one"))
txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "two"))
txt.add_rdata(Rdata(txt.get_type(), txt.get_class(), "three"))
- a = RRset(Name('d.example.org.'), self.__rrclass, RRType.A(),
+ a = RRset(Name('d.example.org.'), self.__rrclass, RRType.A,
RRTTL(3600))
a.add_rdata(Rdata(a.get_type(), a.get_class(), "192.0.2.1"))
a.add_rdata(Rdata(a.get_type(), a.get_class(), "192.0.2.2"))
@@ -680,7 +680,7 @@ class DiffTest(unittest.TestCase):
def test_find(self):
diff = Diff(self, Name('example.org.'))
name = Name('www.example.org.')
- rrtype = RRType.A()
+ rrtype = RRType.A
self.assertFalse(self.__find_called)
self.assertEqual(None, self.__find_name)
@@ -698,7 +698,7 @@ class DiffTest(unittest.TestCase):
def test_find_options(self):
diff = Diff(self, Name('example.org.'))
name = Name('foo.example.org.')
- rrtype = RRType.TXT()
+ rrtype = RRType.TXT
options = ZoneFinder.NO_WILDCARD
self.assertEqual("find_return", diff.find(name, rrtype, options))
@@ -998,8 +998,8 @@ class DiffTest(unittest.TestCase):
# Add a second rr with different type at same name
add_rrset = RRset(self.__rrset3.get_name(), self.__rrclass,
- RRType.A(), self.__ttl)
- add_rrset.add_rdata(Rdata(RRType.A(), self.__rrclass, "192.0.2.2"))
+ RRType.A, self.__ttl)
+ add_rrset.add_rdata(Rdata(RRType.A, self.__rrclass, "192.0.2.2"))
diff.add_data(add_rrset)
self.__check_find_all_call(diff.find_all_updated, self.__rrset3,
@@ -1131,8 +1131,8 @@ class DiffTest(unittest.TestCase):
self.assertTrue(isinstance(collection, self.Collection))
# The collection is just the mock from above, so this doesn't do much
# testing, but we check that the mock got through and didn't get hurt.
- self.assertIsNone(collection.find(Name('example.org'), RRClass.IN(),
- RRType.SOA()))
+ self.assertIsNone(collection.find(Name('example.org'), RRClass.IN,
+ RRType.SOA))
if __name__ == "__main__":
isc.log.init("bind10")
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index 7eae6fe..8d4ae58 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -609,7 +609,7 @@ SERVFAIL:
if (category == ResponseClassifier::RCODE) {
// Special case as this message takes two arguments.
- LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERROR).
+ LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_RETURNED).
arg(questionText(question_)).arg(rcode);
} else {
diff --git a/src/lib/resolve/resolve_messages.mes b/src/lib/resolve/resolve_messages.mes
index 6447082..c89dedb 100644
--- a/src/lib/resolve/resolve_messages.mes
+++ b/src/lib/resolve/resolve_messages.mes
@@ -133,7 +133,7 @@ A debug message indicating that a protocol error was received and that
the resolver is repeating the query to the same nameserver. After this
repeated query, there will be the indicated number of retries left.
-% RESLIB_RCODE_ERROR response to query for <%1> returns RCODE of %2
+% RESLIB_RCODE_RETURNED response to query for <%1> returns RCODE of %2
A debug message, the response to the specified query indicated an error
that is not covered by a specific code path. A SERVFAIL will be returned.
diff --git a/src/lib/util/io/socketsession.cc b/src/lib/util/io/socketsession.cc
index ba4e6c7..4acca92 100644
--- a/src/lib/util/io/socketsession.cc
+++ b/src/lib/util/io/socketsession.cc
@@ -82,7 +82,7 @@ const size_t INITIAL_BUFSIZE = 512;
const int SOCKSESSION_BUFSIZE = (DEFAULT_HEADER_BUFLEN + MAX_DATASIZE) * 2;
struct SocketSessionForwarder::ForwarderImpl {
- ForwarderImpl() : buf_(DEFAULT_HEADER_BUFLEN) {}
+ ForwarderImpl() : fd_(-1), buf_(DEFAULT_HEADER_BUFLEN) {}
struct sockaddr_un sock_un_;
socklen_t sock_un_len_;
int fd_;
diff --git a/src/lib/util/unittests/fork.cc b/src/lib/util/unittests/fork.cc
index 3414a3c..7ed22f8 100644
--- a/src/lib/util/unittests/fork.cc
+++ b/src/lib/util/unittests/fork.cc
@@ -93,10 +93,10 @@ provide_input(int *read_pipe, const void *input, const size_t length)
/*
* This creates a pipe, forks and reads the pipe and compares it
- * with given data. Used to check output of run in asynchronous way.
+ * with given data. Used to check output of run in an asynchronous way.
*/
pid_t
-check_output(int *write_pipe, const void *output, const size_t length)
+check_output(int *write_pipe, const void* const output, const size_t length)
{
int pipes[2];
if (pipe(pipes)) {
@@ -109,9 +109,7 @@ check_output(int *write_pipe, const void *output, const size_t length)
return pid;
} else {
close(pipes[1]);
- // We don't return the memory, but we're in tests and end this process
- // right away.
- unsigned char *buffer = new unsigned char[length + 1];
+ unsigned char* buffer = new unsigned char[length + 1];
// Try to read one byte more to see if the output ends here
size_t got_length(read_data(pipes[0], buffer, length + 1));
bool ok(true);
@@ -133,8 +131,10 @@ check_output(int *write_pipe, const void *output, const size_t length)
fprintf(stderr, "%02hhx", output_c[i]);
}
fprintf(stderr, "\n");
+ delete [] buffer;
exit(1);
} else {
+ delete [] buffer;
exit(0);
}
}
diff --git a/src/lib/util/unittests/fork.h b/src/lib/util/unittests/fork.h
index d5623a7..6b9e749 100644
--- a/src/lib/util/unittests/fork.h
+++ b/src/lib/util/unittests/fork.h
@@ -40,10 +40,10 @@ bool
process_ok(pid_t process);
pid_t
-provide_input(int *read_pipe, const void *input, const size_t length);
+provide_input(int* read_pipe, const void* input, const size_t length);
pid_t
-check_output(int *write_pipe, const void *output, const size_t length);
+check_output(int* write_pipe, const void* const output, const size_t length);
} // End of the namespace
}
diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc
index f770373..9433442 100644
--- a/tests/tools/perfdhcp/command_options.cc
+++ b/tests/tools/perfdhcp/command_options.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -87,7 +87,7 @@ CommandOptions::reset() {
}
bool
-CommandOptions::parse(int argc, char** const argv) {
+CommandOptions::parse(int argc, char** const argv, bool print_cmd_line) {
// Reset internal variables used by getopt
// to eliminate undefined behavior when
// parsing different command lines multiple times
@@ -125,7 +125,7 @@ CommandOptions::parse(int argc, char** const argv) {
reset();
// Informs if program has been run with 'h' or 'v' option.
- bool help_or_version_mode = initialize(argc, argv);
+ bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
if (!help_or_version_mode) {
validate();
}
@@ -133,7 +133,7 @@ CommandOptions::parse(int argc, char** const argv) {
}
bool
-CommandOptions::initialize(int argc, char** argv) {
+CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
int opt = 0; // Subsequent options returned by getopt()
std::string drop_arg; // Value of -D<value>argument
size_t percent_loc = 0; // Location of % sign in -D<value>
@@ -151,10 +151,10 @@ CommandOptions::initialize(int argc, char** argv) {
// they will be tuned and validated elsewhere
while((opt = getopt(argc, argv, "hv46r:t:R:b:n:p:d:D:l:P:a:L:"
"s:iBc1T:X:O:E:S:I:x:w:")) != -1) {
- stream << " -" << opt;
+ stream << " -" << static_cast<char>(opt);
if (optarg) {
stream << " " << optarg;
- }
+ }
switch (opt) {
case '1':
use_first_ = true;
@@ -416,7 +416,9 @@ CommandOptions::initialize(int argc, char** argv) {
}
}
- std::cout << "Running: " << stream.str() << std::endl;
+ if (print_cmd_line) {
+ std::cout << "Running: " << stream.str() << std::endl;
+ }
// Handle the local '-l' address/interface
if (!localname_.empty()) {
diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h
index cbb6236..4b804dc 100644
--- a/tests/tools/perfdhcp/command_options.h
+++ b/tests/tools/perfdhcp/command_options.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -56,9 +56,10 @@ public:
///
/// \param argc Argument count passed to main().
/// \param argv Argument value array passed to main().
+ /// \param print_cmd_line Print the command line being run to the console.
/// \throws isc::InvalidParameter if parse fails.
/// \return true if program has been run in help or version mode ('h' or 'v' flag).
- bool parse(int argc, char** const argv);
+ bool parse(int argc, char** const argv, bool print_cmd_line = false);
/// \brief Returns IP version.
///
@@ -261,9 +262,10 @@ private:
///
/// \param argc Argument count passed to main().
/// \param argv Argument value array passed to main().
+ /// \param print_cmd_line Print the command line being run to the console.
/// \throws isc::InvalidParameter if command line options initialization fails.
/// \return true if program has been run in help or version mode ('h' or 'v' flag).
- bool initialize(int argc, char** argv);
+ bool initialize(int argc, char** argv, bool print_cmd_line);
/// \brief Validates initialized options.
///
diff --git a/tests/tools/perfdhcp/main.cc b/tests/tools/perfdhcp/main.cc
index aa202f1..a5254fc 100644
--- a/tests/tools/perfdhcp/main.cc
+++ b/tests/tools/perfdhcp/main.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -32,7 +32,11 @@ main(int argc, char* argv[]) {
// If parser returns true it means that user specified
// 'h' or 'v' command line option. Program shows the
// help or version message and exits here.
- if (command_options.parse(argc, argv)) {
+ // The third argument indicates that the command line
+ // should be printed when it gets parsed. This is useful
+ // in particular when the command line needs to be
+ // extracted from the log file.
+ if (command_options.parse(argc, argv, true)) {
return (ret_code);
}
} catch(isc::Exception& e) {
diff --git a/tools/query_cmp/src/lib/handledns.py b/tools/query_cmp/src/lib/handledns.py
index e33ce9e..e906bae 100755
--- a/tools/query_cmp/src/lib/handledns.py
+++ b/tools/query_cmp/src/lib/handledns.py
@@ -187,7 +187,7 @@ def send_req(query, server, port=53, timeout=5):
msg = Message(Message.RENDER)
msg.set_qid(int(qheader['id']))
- msg.set_opcode(Opcode.QUERY())
+ msg.set_opcode(Opcode.QUERY)
msg.set_rcode(Rcode(int(qheader['rcode'])))
if qheader['qr'] == 1:
More information about the bind10-changes
mailing list