mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-02 15:05:16 +00:00
[master] Merge branch 'trac2184'
(conflicts purely in generated files, regenerated them) Conflicts: doc/guide/bind10-guide.html doc/guide/bind10-guide.txt doc/guide/bind10-messages.html
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -968,9 +968,18 @@ Chapter 8. Authoritative Server
|
|||||||
> config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }
|
> config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }
|
||||||
> config commit
|
> config commit
|
||||||
|
|
||||||
Unfortunately, due to current technical limitations, the params must be
|
Initially, a map value has to be set, but this value may be an empty map.
|
||||||
set as one JSON blob, it can't be edited in bindctl. To reload a zone, you
|
After that, key/value pairs can be added with 'config add' and keys can be
|
||||||
the same command as above.
|
removed with 'config remove'. The initial value may be an empty map, but
|
||||||
|
it has to be set before zones are added or removed.
|
||||||
|
|
||||||
|
> config set data_sources/classes/IN[1]/params {}
|
||||||
|
> config add data_sources/classes/IN[1]/params another.example.org /path/to/another.example.org
|
||||||
|
> config add data_sources/classes/IN[1]/params another.example.com /path/to/another.example.com
|
||||||
|
> config remove data_sources/classes/IN[1]/params another.example.org
|
||||||
|
|
||||||
|
|
||||||
|
bindctl. To reload a zone, you the same command as above.
|
||||||
|
|
||||||
Note
|
Note
|
||||||
|
|
||||||
|
@@ -1611,8 +1611,19 @@ can use various data source backends.
|
|||||||
> <userinput>config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }</userinput>
|
> <userinput>config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }</userinput>
|
||||||
> <userinput>config commit</userinput></screen>
|
> <userinput>config commit</userinput></screen>
|
||||||
|
|
||||||
Unfortunately, due to current technical limitations, the params must
|
Initially, a map value has to be set, but this value may be an
|
||||||
be set as one JSON blob, it can't be edited in
|
empty map. After that, key/value pairs can be added with 'config
|
||||||
|
add' and keys can be removed with 'config remove'. The initial
|
||||||
|
value may be an empty map, but it has to be set before zones are
|
||||||
|
added or removed.
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
> <userinput>config set data_sources/classes/IN[1]/params {}</userinput>
|
||||||
|
> <userinput>config add data_sources/classes/IN[1]/params another.example.org /path/to/another.example.org</userinput>
|
||||||
|
> <userinput>config add data_sources/classes/IN[1]/params another.example.com /path/to/another.example.com</userinput>
|
||||||
|
> <userinput>config remove data_sources/classes/IN[1]/params another.example.org</userinput>
|
||||||
|
</screen>
|
||||||
|
|
||||||
<command>bindctl</command>. To reload a zone, you the same command
|
<command>bindctl</command>. To reload a zone, you the same command
|
||||||
as above.
|
as above.
|
||||||
</para>
|
</para>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Messages Manual</title><link rel="stylesheet" type="text/css" href="./bind10-guide.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1"><meta name="description" content="BIND 10 is a Domain Name System (DNS) suite managed by Internet Systems Consortium (ISC). It includes DNS libraries and modular components for controlling authoritative and recursive DNS servers. This is the messages manual for BIND 10 version 20120712. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Messages Manual"><div class="titlepage"><div><div><h1 class="title"><a name="idp25824"></a>BIND 10 Messages Manual</h1></div><div><p class="releaseinfo">This is the messages manual for BIND 10 version
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Messages Manual</title><link rel="stylesheet" href="./bind10-guide.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><meta name="description" content="BIND 10 is a Domain Name System (DNS) suite managed by Internet Systems Consortium (ISC). It includes DNS libraries and modular components for controlling authoritative and recursive DNS servers. This is the messages manual for BIND 10 version 20120712. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Messages Manual"><div class="titlepage"><div><div><h1 class="title"><a name="idp74800"></a>BIND 10 Messages Manual</h1></div><div><p class="releaseinfo">This is the messages manual for BIND 10 version
|
||||||
20120712.</p></div><div><p class="copyright">Copyright <20> 2011-2012 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>BIND 10 is a Domain Name System (DNS) suite managed by
|
20120712.</p></div><div><p class="copyright">Copyright <20> 2011-2012 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>BIND 10 is a Domain Name System (DNS) suite managed by
|
||||||
Internet Systems Consortium (ISC). It includes DNS libraries
|
Internet Systems Consortium (ISC). It includes DNS libraries
|
||||||
and modular components for controlling authoritative and
|
and modular components for controlling authoritative and
|
||||||
|
9
src/lib/config/tests/testdata/spec40.spec
vendored
9
src/lib/config/tests/testdata/spec40.spec
vendored
@@ -6,6 +6,15 @@
|
|||||||
"item_type": "any",
|
"item_type": "any",
|
||||||
"item_optional": false,
|
"item_optional": false,
|
||||||
"item_default": "asdf"
|
"item_default": "asdf"
|
||||||
|
},
|
||||||
|
{ "item_name": "item2",
|
||||||
|
"item_type": "any",
|
||||||
|
"item_optional": true
|
||||||
|
},
|
||||||
|
{ "item_name": "item3",
|
||||||
|
"item_type": "any",
|
||||||
|
"item_optional": true,
|
||||||
|
"item_default": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -521,7 +521,7 @@ class UIModuleCCSession(MultiConfigData):
|
|||||||
if not cur_list:
|
if not cur_list:
|
||||||
cur_list = []
|
cur_list = []
|
||||||
|
|
||||||
if value is None:
|
if value is None and "list_item_spec" in module_spec:
|
||||||
if "item_default" in module_spec["list_item_spec"]:
|
if "item_default" in module_spec["list_item_spec"]:
|
||||||
value = module_spec["list_item_spec"]["item_default"]
|
value = module_spec["list_item_spec"]["item_default"]
|
||||||
|
|
||||||
@@ -572,8 +572,14 @@ class UIModuleCCSession(MultiConfigData):
|
|||||||
if module_spec is None:
|
if module_spec is None:
|
||||||
raise isc.cc.data.DataNotFoundError("Unknown item " + str(identifier))
|
raise isc.cc.data.DataNotFoundError("Unknown item " + str(identifier))
|
||||||
|
|
||||||
|
# for type any, we determine the 'type' by what value is set
|
||||||
|
# (which would be either list or dict)
|
||||||
|
cur_value, _ = self.get_value(identifier)
|
||||||
|
type_any = module_spec['item_type'] == 'any'
|
||||||
|
|
||||||
# the specified element must be a list or a named_set
|
# the specified element must be a list or a named_set
|
||||||
if 'list_item_spec' in module_spec:
|
if 'list_item_spec' in module_spec or\
|
||||||
|
(type_any and type(cur_value) == list):
|
||||||
value = None
|
value = None
|
||||||
# in lists, we might get the value with spaces, making it
|
# in lists, we might get the value with spaces, making it
|
||||||
# the third argument. In that case we interpret both as
|
# the third argument. In that case we interpret both as
|
||||||
@@ -583,11 +589,12 @@ class UIModuleCCSession(MultiConfigData):
|
|||||||
value_str += set_value_str
|
value_str += set_value_str
|
||||||
value = isc.cc.data.parse_value_str(value_str)
|
value = isc.cc.data.parse_value_str(value_str)
|
||||||
self._add_value_to_list(identifier, value, module_spec)
|
self._add_value_to_list(identifier, value, module_spec)
|
||||||
elif 'named_set_item_spec' in module_spec:
|
elif 'named_set_item_spec' in module_spec or\
|
||||||
|
(type_any and type(cur_value) == dict):
|
||||||
item_name = None
|
item_name = None
|
||||||
item_value = None
|
item_value = None
|
||||||
if value_str is not None:
|
if value_str is not None:
|
||||||
item_name = isc.cc.data.parse_value_str(value_str)
|
item_name = value_str
|
||||||
if set_value_str is not None:
|
if set_value_str is not None:
|
||||||
item_value = isc.cc.data.parse_value_str(set_value_str)
|
item_value = isc.cc.data.parse_value_str(set_value_str)
|
||||||
else:
|
else:
|
||||||
@@ -643,12 +650,23 @@ class UIModuleCCSession(MultiConfigData):
|
|||||||
if value_str is not None:
|
if value_str is not None:
|
||||||
value = isc.cc.data.parse_value_str(value_str)
|
value = isc.cc.data.parse_value_str(value_str)
|
||||||
|
|
||||||
if 'list_item_spec' in module_spec:
|
# for type any, we determine the 'type' by what value is set
|
||||||
if value is not None:
|
# (which would be either list or dict)
|
||||||
|
cur_value, _ = self.get_value(identifier)
|
||||||
|
type_any = module_spec['item_type'] == 'any'
|
||||||
|
|
||||||
|
# there's two forms of 'remove from list'; the remove-value-from-list
|
||||||
|
# form, and the 'remove-by-index' form. We can recognize the second
|
||||||
|
# case by value is None
|
||||||
|
if 'list_item_spec' in module_spec or\
|
||||||
|
(type_any and type(cur_value) == list) or\
|
||||||
|
value is None:
|
||||||
|
if not type_any and value is not None:
|
||||||
isc.config.config_data.check_type(module_spec['list_item_spec'], value)
|
isc.config.config_data.check_type(module_spec['list_item_spec'], value)
|
||||||
self._remove_value_from_list(identifier, value)
|
self._remove_value_from_list(identifier, value)
|
||||||
elif 'named_set_item_spec' in module_spec:
|
elif 'named_set_item_spec' in module_spec or\
|
||||||
self._remove_value_from_named_set(identifier, value)
|
(type_any and type(cur_value) == dict):
|
||||||
|
self._remove_value_from_named_set(identifier, value_str)
|
||||||
else:
|
else:
|
||||||
raise isc.cc.data.DataNotFoundError(str(identifier) + " is not a list or a named_set")
|
raise isc.cc.data.DataNotFoundError(str(identifier) + " is not a list or a named_set")
|
||||||
|
|
||||||
|
@@ -204,6 +204,9 @@ def find_spec_part(element, identifier, strict_identifier = True):
|
|||||||
# always want the 'full' spec of the item
|
# always want the 'full' spec of the item
|
||||||
for id_part in id_parts[:-1]:
|
for id_part in id_parts[:-1]:
|
||||||
cur_el = _find_spec_part_single(cur_el, id_part)
|
cur_el = _find_spec_part_single(cur_el, id_part)
|
||||||
|
# As soon as we find 'any', return that
|
||||||
|
if cur_el["item_type"] == "any":
|
||||||
|
return cur_el
|
||||||
if strict_identifier and spec_part_is_list(cur_el) and\
|
if strict_identifier and spec_part_is_list(cur_el) and\
|
||||||
not isc.cc.data.identifier_has_list_index(id_part):
|
not isc.cc.data.identifier_has_list_index(id_part):
|
||||||
raise isc.cc.data.DataNotFoundError(id_part +
|
raise isc.cc.data.DataNotFoundError(id_part +
|
||||||
@@ -553,7 +556,6 @@ class MultiConfigData:
|
|||||||
if 'item_default' in spec:
|
if 'item_default' in spec:
|
||||||
# one special case, named_set
|
# one special case, named_set
|
||||||
if spec['item_type'] == 'named_set':
|
if spec['item_type'] == 'named_set':
|
||||||
print("is " + id_part + " in named set?")
|
|
||||||
return spec['item_default']
|
return spec['item_default']
|
||||||
else:
|
else:
|
||||||
return spec['item_default']
|
return spec['item_default']
|
||||||
@@ -582,6 +584,14 @@ class MultiConfigData:
|
|||||||
value = self.get_default_value(identifier)
|
value = self.get_default_value(identifier)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return value, self.DEFAULT
|
return value, self.DEFAULT
|
||||||
|
else:
|
||||||
|
# get_default_value returns None for both
|
||||||
|
# the cases where there is no default, and where
|
||||||
|
# it is set to null, so we need to catch the latter
|
||||||
|
spec_part = self.find_spec_part(identifier)
|
||||||
|
if spec_part and 'item_default' in spec_part and\
|
||||||
|
spec_part['item_default'] is None:
|
||||||
|
return None, self.DEFAULT
|
||||||
return None, self.NONE
|
return None, self.NONE
|
||||||
|
|
||||||
def _append_value_item(self, result, spec_part, identifier, all, first = False):
|
def _append_value_item(self, result, spec_part, identifier, all, first = False):
|
||||||
@@ -742,6 +752,8 @@ class MultiConfigData:
|
|||||||
# list
|
# list
|
||||||
cur_list = cur_value
|
cur_list = cur_value
|
||||||
for list_index in list_indices:
|
for list_index in list_indices:
|
||||||
|
if type(cur_list) != list:
|
||||||
|
raise isc.cc.data.DataTypeError(id + " is not a list")
|
||||||
if list_index >= len(cur_list):
|
if list_index >= len(cur_list):
|
||||||
raise isc.cc.data.DataNotFoundError("No item " +
|
raise isc.cc.data.DataNotFoundError("No item " +
|
||||||
str(list_index) + " in " + id_part)
|
str(list_index) + " in " + id_part)
|
||||||
|
@@ -920,8 +920,8 @@ class TestUIModuleCCSession(unittest.TestCase):
|
|||||||
def spec_file(self, file):
|
def spec_file(self, file):
|
||||||
return self.data_path + os.sep + file
|
return self.data_path + os.sep + file
|
||||||
|
|
||||||
def create_uccs2(self, fake_conn):
|
def create_uccs(self, fake_conn, specfile="spec2.spec"):
|
||||||
module_spec = isc.config.module_spec_from_file(self.spec_file("spec2.spec"))
|
module_spec = isc.config.module_spec_from_file(self.spec_file(specfile))
|
||||||
fake_conn.set_get_answer('/module_spec', { module_spec.get_module_name(): module_spec.get_full_spec()})
|
fake_conn.set_get_answer('/module_spec', { module_spec.get_module_name(): module_spec.get_full_spec()})
|
||||||
fake_conn.set_get_answer('/config_data', { 'version': BIND10_CONFIG_DATA_VERSION })
|
fake_conn.set_get_answer('/config_data', { 'version': BIND10_CONFIG_DATA_VERSION })
|
||||||
return UIModuleCCSession(fake_conn)
|
return UIModuleCCSession(fake_conn)
|
||||||
@@ -989,7 +989,7 @@ class TestUIModuleCCSession(unittest.TestCase):
|
|||||||
|
|
||||||
def test_add_remove_value(self):
|
def test_add_remove_value(self):
|
||||||
fake_conn = fakeUIConn()
|
fake_conn = fakeUIConn()
|
||||||
uccs = self.create_uccs2(fake_conn)
|
uccs = self.create_uccs(fake_conn)
|
||||||
|
|
||||||
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, 1, "a")
|
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, 1, "a")
|
||||||
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, "no_such_item", "a")
|
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, "no_such_item", "a")
|
||||||
@@ -1020,6 +1020,88 @@ class TestUIModuleCCSession(unittest.TestCase):
|
|||||||
self.assertRaises(isc.cc.data.DataTypeError,
|
self.assertRaises(isc.cc.data.DataTypeError,
|
||||||
uccs.remove_value, "Spec2/item5", None)
|
uccs.remove_value, "Spec2/item5", None)
|
||||||
|
|
||||||
|
# Check that the difference between no default and default = null
|
||||||
|
# is recognized
|
||||||
|
def test_default_null(self):
|
||||||
|
fake_conn = fakeUIConn()
|
||||||
|
uccs = self.create_uccs(fake_conn, "spec40.spec")
|
||||||
|
(value, status) = uccs.get_value("/Spec40/item2")
|
||||||
|
self.assertIsNone(value)
|
||||||
|
self.assertEqual(uccs.NONE, status)
|
||||||
|
(value, status) = uccs.get_value("/Spec40/item3")
|
||||||
|
self.assertIsNone(value)
|
||||||
|
self.assertEqual(uccs.DEFAULT, status)
|
||||||
|
|
||||||
|
# Test adding and removing values for type = any
|
||||||
|
def test_add_remove_value_any(self):
|
||||||
|
fake_conn = fakeUIConn()
|
||||||
|
uccs = self.create_uccs(fake_conn, "spec40.spec")
|
||||||
|
|
||||||
|
# Test item set of basic types
|
||||||
|
items = [ 1234, "foo", True, False ]
|
||||||
|
items_as_str = [ '1234', 'foo', 'true', 'false' ]
|
||||||
|
|
||||||
|
def test_fails():
|
||||||
|
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, "Spec40/item1", "foo")
|
||||||
|
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.add_value, "Spec40/item1", "foo", "bar")
|
||||||
|
self.assertRaises(isc.cc.data.DataNotFoundError, uccs.remove_value, "Spec40/item1", "foo")
|
||||||
|
self.assertRaises(isc.cc.data.DataTypeError, uccs.remove_value, "Spec40/item1[0]", None)
|
||||||
|
|
||||||
|
# A few helper functions to perform a number of tests
|
||||||
|
# (to repeat the same test for nested data)
|
||||||
|
def check_list(identifier):
|
||||||
|
for item in items_as_str:
|
||||||
|
uccs.add_value(identifier, item)
|
||||||
|
self.assertEqual((items, 1), uccs.get_value(identifier))
|
||||||
|
|
||||||
|
# Removing from list should work in both ways
|
||||||
|
uccs.remove_value(identifier, "foo")
|
||||||
|
uccs.remove_value(identifier + "[1]", None)
|
||||||
|
self.assertEqual(([1234, False], 1), uccs.get_value(identifier))
|
||||||
|
|
||||||
|
# As should item indexing
|
||||||
|
self.assertEqual((1234, 1), uccs.get_value(identifier + "[0]"))
|
||||||
|
self.assertEqual((False, 1), uccs.get_value(identifier + "[1]"))
|
||||||
|
|
||||||
|
def check_named_set(identifier):
|
||||||
|
for item in items_as_str:
|
||||||
|
# use string version as key as well
|
||||||
|
uccs.add_value(identifier, item, item)
|
||||||
|
|
||||||
|
self.assertEqual((1234, 1), uccs.get_value(identifier + "/1234"))
|
||||||
|
self.assertEqual((True, 1), uccs.get_value(identifier + "/true"))
|
||||||
|
|
||||||
|
for item in items_as_str:
|
||||||
|
# use string version as key as well
|
||||||
|
uccs.remove_value(identifier, item)
|
||||||
|
|
||||||
|
|
||||||
|
# should fail when set to value of primitive type
|
||||||
|
for item in items:
|
||||||
|
uccs.set_value("Spec40/item1", item)
|
||||||
|
test_fails()
|
||||||
|
|
||||||
|
# When set to list, add and remove should work, and its elements
|
||||||
|
# should be considered of type 'any' themselves.
|
||||||
|
uccs.set_value("Spec40/item1", [])
|
||||||
|
check_list("Spec40/item1")
|
||||||
|
|
||||||
|
# When set to dict, it should have the behaviour of a named set
|
||||||
|
uccs.set_value("Spec40/item1", {})
|
||||||
|
check_named_set("Spec40/item1")
|
||||||
|
|
||||||
|
# And, or course, we may need nesting.
|
||||||
|
uccs.set_value("Spec40/item1", { "foo": {}, "bar": [] })
|
||||||
|
check_named_set("Spec40/item1/foo")
|
||||||
|
check_list("Spec40/item1/bar")
|
||||||
|
uccs.set_value("Spec40/item1", [ {}, [] ] )
|
||||||
|
check_named_set("Spec40/item1[0]")
|
||||||
|
check_list("Spec40/item1[1]")
|
||||||
|
uccs.set_value("Spec40/item1", [[[[[[]]]]]] )
|
||||||
|
check_list("Spec40/item1[0][0][0][0][0]")
|
||||||
|
uccs.set_value("Spec40/item1", { 'a': { 'a': { 'a': {} } } } )
|
||||||
|
check_named_set("Spec40/item1/a/a/a")
|
||||||
|
|
||||||
def test_add_dup_value(self):
|
def test_add_dup_value(self):
|
||||||
fake_conn = fakeUIConn()
|
fake_conn = fakeUIConn()
|
||||||
uccs = self.create_uccs_listtest(fake_conn)
|
uccs = self.create_uccs_listtest(fake_conn)
|
||||||
@@ -1101,7 +1183,7 @@ class TestUIModuleCCSession(unittest.TestCase):
|
|||||||
|
|
||||||
def test_commit(self):
|
def test_commit(self):
|
||||||
fake_conn = fakeUIConn()
|
fake_conn = fakeUIConn()
|
||||||
uccs = self.create_uccs2(fake_conn)
|
uccs = self.create_uccs(fake_conn)
|
||||||
uccs.commit()
|
uccs.commit()
|
||||||
uccs._local_changes = {'Spec2': {'item5': [ 'a' ]}}
|
uccs._local_changes = {'Spec2': {'item5': [ 'a' ]}}
|
||||||
uccs.commit()
|
uccs.commit()
|
||||||
|
Reference in New Issue
Block a user