Commit 96a12cba authored by Jelte Jansen's avatar Jelte Jansen

'checkpoint' commit, can address individual list items, not set them yet, need...

'checkpoint' commit, can address individual list items, not set them yet, need a bit of refactoring first


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac405@3643 e5f2f494-b856-4b98-b285-d166d9295462
parent b72efb55
......@@ -7,6 +7,17 @@
"item_type": "string",
"item_optional": true,
"item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
},
{ "item_name": "simple_list_int",
"item_type": "list",
"item_optional": true,
"item_default": [ 1, 2, 3],
"list_item_spec":
{ "item_name": "int_element",
"item_type": "integer",
"item_optional": false,
"item_default": 0
}
}
],
"commands": [
......
......@@ -553,6 +553,9 @@ class BindCmdInterpreter(Cmd):
if cmd.command == "show":
values = self.config_data.get_value_maps(identifier)
print("[XX] VALUE MAPS:")
print(str(values))
print("[XX] END VALUE MAPS")
for value_map in values:
line = value_map['name']
if value_map['type'] in [ 'module', 'map', 'list' ]:
......@@ -593,8 +596,8 @@ class BindCmdInterpreter(Cmd):
self.go(identifier)
except isc.cc.data.DataTypeError as dte:
print("Error: " + str(dte))
except isc.cc.data.DataNotFoundError as dnfe:
print("Error: " + identifier + " not found")
#except isc.cc.data.DataNotFoundError as dnfe:
# print("Error: " + identifier + " not found")
except KeyError as ke:
print("Error: missing " + str(ke))
raise ke
......
......@@ -112,7 +112,7 @@ def set_bindctl_options(parser):
help = 'PEM formatted server certificate validation chain file')
if __name__ == '__main__':
try:
#try:
parser = OptionParser(version = __version__)
set_bindctl_options(parser)
(options, args) = parser.parse_args()
......@@ -120,7 +120,7 @@ if __name__ == '__main__':
tool = BindCmdInterpreter(server_addr, pem_file=options.cert_chain)
prepare_config_commands(tool)
tool.run()
except Exception as e:
print(e, "\nFailed to connect with b10-cmdctl module, is it running?")
#except Exception as e:
# print(e, "\nFailed to connect with b10-cmdctl module, is it running?")
......@@ -63,15 +63,40 @@ def _split_identifier(identifier):
return id_parts
def _find_child_el(element, id):
"""Finds the child of element with the given id. If the id contains
[i], where i is a number, and the child element is a list, the
i-th element of that list is returned instead of the list itself.
Raises a DataTypeError if the element is of wrong type, if id
is not a string, or if the id string contains a bad value.
Raises a DataNotFoundError if the element at id could not be
found.
"""
i = id.find('[')
e = id.find(']')
list_index = None
if i >= 0 and e > i + 1:
try:
list_index = int(id[i + 1:e])
except ValueError as ve:
# repack as datatypeerror
raise DataTypeError(ve)
id = id[:i]
if type(element) == dict and id in element.keys():
return element[id]
result = element[id]
else:
raise DataNotFoundError(id + " in " + str(element))
if type(result) == list and list_index is not None:
print("[XX] GETTING ELEMENT NUMBER " + str(list_index) + " (of " + str(len(result)) + ")")
if list_index >= len(result):
print("[XX] OUT OF RANGE")
raise DataNotFoundError("Element " + str(list_index) + " in " + str(result))
result = result[list_index]
return result
def find(element, identifier):
"""Returns the subelement in the given data element, raises DataNotFoundError if not found"""
if (type(element) != dict and identifier != ""):
raise DataTypeError("element in merge() is not a dict")
raise DataTypeError("element in find() is not a dict")
id_parts = _split_identifier(identifier)
cur_el = element
for id in id_parts:
......@@ -88,12 +113,17 @@ def set(element, identifier, value):
el.set().set().set() is possible)"""
if type(element) != dict:
raise DataTypeError("element in set() is not a dict")
print("[XX] full identifier: " + identifier)
id_parts = _split_identifier(identifier)
cur_el = element
print("[XX] Full element:")
print(element)
for id in id_parts[:-1]:
try:
print("[XX] find " + id)
cur_el = _find_child_el(cur_el, id)
except DataNotFoundError:
print("[XX] DNF for " + id)
if value is None:
# ok we are unsetting a value that wasn't set in
# the first place. Simply stop.
......@@ -102,6 +132,7 @@ def set(element, identifier, value):
cur_el = cur_el[id]
# value can be an empty list or dict, so check for None eplicitely
print("[XX] Current value: " + str(cur_el))
if value is not None:
cur_el[id_parts[-1]] = value
elif id_parts[-1] in cur_el:
......
......@@ -95,6 +95,17 @@ class TestData(unittest.TestCase):
self.assertRaises(data.DataTypeError, data.find, None, 1)
self.assertRaises(data.DataTypeError, data.find, "123", "123")
self.assertEqual(data.find("123", ""), "123")
d2 = { 'a': [ 1, 2, 3 ] }
self.assertEqual(data.find(d2, 'a[0]'), 1)
self.assertEqual(data.find(d2, 'a[1]'), 2)
self.assertEqual(data.find(d2, 'a[2]'), 3)
self.assertRaises(data.DataNotFoundError, data.find, d2, 'a[3]')
self.assertRaises(data.DataTypeError, data.find, d2, 'a[a]')
d3 = { 'a': [ { 'b': [ {}, { 'c': 'd' } ] } ] }
self.assertEqual(data.find(d3, 'a[0]/b[1]/c'), 'd')
self.assertRaises(data.DataNotFoundError, data.find, d3, 'a[1]/b[1]/c')
def test_set(self):
d1 = { 'a': 'a', 'b': 1, 'c': { 'd': 'd', 'e': 2 } }
......
......@@ -109,6 +109,12 @@ def find_spec_part(element, identifier):
id_parts[:] = (value for value in id_parts if value != "")
cur_el = element
for id in id_parts:
# strip list selector part
# don't need it for the spec part, so just drop it
i = id.find('[')
e = id.find(']')
if i >= 0 and e > i + 1:
id = id[:i]
if type(cur_el) == dict and 'map_item_spec' in cur_el.keys():
found = False
for cur_el_item in cur_el['map_item_spec']:
......@@ -121,12 +127,20 @@ def find_spec_part(element, identifier):
found = False
for cur_el_item in cur_el:
if cur_el_item['item_name'] == id:
#print("[XX] full list item:")
#print(cur_el_item)
#if 'list_item_spec' in cur_el_item:
# cur_el = cur_el_item['list_item_spec']
#else:
cur_el = cur_el_item
found = True
if not found:
raise isc.cc.data.DataNotFoundError(id + " in " + str(cur_el))
else:
raise isc.cc.data.DataNotFoundError("Not a correct config specification")
print("[XX] Returning: ")
print(cur_el)
print("[XX] end")
return cur_el
def spec_name_list(spec, prefix="", recurse=False):
......@@ -336,28 +350,47 @@ class MultiConfigData:
try:
spec = find_spec_part(self._specifications[module].get_config_spec(), id)
if 'item_default' in spec:
return spec['item_default']
i = id.find('[')
e = id.find(']')
if i >= 0 and e > i + 1 \
and type(spec['item_default']) == list:
default_list = spec['item_default']
index = int(id[i + 1:e])
if index < len(default_list):
return default_list[index]
else:
return None
else:
return spec['item_default']
else:
return None
except isc.cc.data.DataNotFoundError as dnfe:
return None
def get_value(self, identifier):
def get_value(self, identifier, default = True):
"""Returns a tuple containing value,status.
The value contains the configuration value for the given
identifier. The status reports where this value came from;
it is one of: LOCAL, CURRENT, DEFAULT or NONE, corresponding
(local change, current setting, default as specified by the
specification, or not found at all)."""
specification, or not found at all). Does not check and
set DEFAULT if the argument 'default' is False (default
defaults to True)"""
value = self.get_local_value(identifier)
print("[XX] mcd get_value() for: " + identifier)
print("[XX] mcd get_value() local: " + str(value))
if value != None:
return value, self.LOCAL
value = self.get_current_value(identifier)
print("[XX] mcd get_value() current: " + str(value))
if value != None:
return value, self.CURRENT
value = self.get_default_value(identifier)
if value != None:
return value, self.DEFAULT
if default:
value = self.get_default_value(identifier)
print("[XX] mcd get_value() default: " + str(value))
if value != None:
return value, self.DEFAULT
print("[XX] mcd get_value() nothing found")
return None, self.NONE
def get_value_maps(self, identifier = None):
......@@ -393,6 +426,7 @@ class MultiConfigData:
entry = {}
entry['name'] = item['item_name']
entry['type'] = item['item_type']
print("[XX] GET VALUE FOR: " + str("/" + identifier + "/" + item['item_name']))
value, status = self.get_value("/" + identifier + "/" + item['item_name'])
entry['value'] = value
if status == self.LOCAL:
......@@ -408,32 +442,53 @@ class MultiConfigData:
item = spec_part
if item['item_type'] == 'list':
li_spec = item['list_item_spec']
item_list, status = self.get_value("/" + identifier)
if item_list != None:
for value in item_list:
print("[XX] GET VALUE FOR: " + str("/" + identifier))
value, status = self.get_value("/" + identifier)
print("[XX] ITEM_LIST: " + str(value))
if type(value) == list:
for list_value in value:
result_part2 = {}
result_part2['name'] = li_spec['item_name']
result_part2['value'] = value
result_part2['value'] = list_value
result_part2['type'] = li_spec['item_type']
result_part2['default'] = False
result_part2['modified'] = False
result.append(result_part2)
elif value is not None:
entry = {}
entry['name'] = li_spec['item_name']
entry['type'] = li_spec['item_type']
entry['value'] = value
if status == self.LOCAL:
entry['modified'] = True
else:
entry['modified'] = False
if status == self.DEFAULT:
entry['default'] = False
else:
entry['default'] = False
result.append(entry)
else:
entry = {}
entry['name'] = item['item_name']
entry['type'] = item['item_type']
#value, status = self.get_value("/" + identifier + "/" + item['item_name'])
value, status = self.get_value("/" + identifier)
entry['value'] = value
if status == self.LOCAL:
entry['modified'] = True
else:
entry['modified'] = False
if status == self.DEFAULT:
entry['default'] = False
else:
entry['default'] = False
result.append(entry)
print("[XX] GET VALUE FOR: " + str("/" + identifier))
# The type of the config data is a list,
# so we do not want to have a default if it's
# out of range
value, status = self.get_value("/" + identifier, False)
if value is not None:
entry = {}
entry['name'] = item['item_name']
entry['type'] = item['item_type']
entry['value'] = value
if status == self.LOCAL:
entry['modified'] = True
else:
entry['modified'] = False
if status == self.DEFAULT:
entry['default'] = False
else:
entry['default'] = False
result.append(entry)
return result
def set_value(self, identifier, value):
......@@ -441,8 +496,15 @@ class MultiConfigData:
there is a specification for the given identifier, the type
is checked."""
spec_part = self.find_spec_part(identifier)
print("[XX] SPEC PART FOR " + identifier + ": ")
print(spec_part)
if spec_part != None:
i = identifier.find('[')
e = identifier.find(']')
if i >= 0 and e > i and spec_part['item_type'] == 'list':
spec_part = spec_part['list_item_spec']
check_type(spec_part, value)
# TODO: get the local list to value
isc.cc.data.set(self._local_changes, identifier, value)
def get_config_item_list(self, identifier = None, recurse = False):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment