Commit b8b0f55e authored by Jelte Jansen's avatar Jelte Jansen

refactoring;

renamed the DataDefinition class to the much more accurate ModuleSpec
also renamed some ambiguously named functions therein



git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jelte-configuration@833 e5f2f494-b856-4b98-b285-d166d9295462
parent 976107dd
{
"data_specification": {
"module_spec": {
"module_name": "Auth",
"config_data": [
{ "item_name": "default_name",
......
......@@ -116,7 +116,7 @@ class BoB:
print("[XX] handling new config:")
print(new_config)
errors = []
if self.ccs.get_config_data().get_specification().validate(False, new_config, errors):
if self.ccs.get_config_spec().get_module_spec().validate(False, new_config, errors):
print("[XX] new config validated")
self.ccs.set_config(new_config)
answer = isc.config.ccsession.create_answer(0)
......
{
"data_specification": {
"module_spec": {
"module_name": "Boss",
"config_data": [
{
......
......@@ -188,7 +188,7 @@ class CommandControl():
self.config_data = self.get_config_data()
def get_cmd_specification(self):
return self.send_command('ConfigManager', 'get_commands')
return self.send_command('ConfigManager', 'get_commands_spec')
def get_config_data(self):
return self.send_command('ConfigManager', 'get_config')
......@@ -198,7 +198,7 @@ class CommandControl():
self.config_data = self.get_config_data()
def get_data_specification(self):
return self.send_command('ConfigManager', 'get_data_spec')
return self.send_command('ConfigManager', 'get_module_spec')
def handle_recv_msg(self):
# Handle received message, if 'shutdown' is received, return False
......
{
"data_specification": {
"module_spec": {
"module_name": "ParkingLot",
"config_data": [
{
......
{
"data_specification": {
"module_spec": {
"module_name": "ParkingLot",
"config_data": [
{
......
......@@ -81,7 +81,7 @@ CommandSession::CommandSession(std::string spec_file_name,
read_data_definition(spec_file_name);
sleep(1);
module_name_ = data_definition_.getDefinition()->get("data_specification")->get("module_name")->stringValue();
module_name_ = data_definition_.getDefinition()->get("module_spec")->get("module_name")->stringValue();
config_handler_ = config_handler;
command_handler_ = command_handler;
......
......@@ -141,10 +141,10 @@ check_data_specification(const ElementPtr& spec) {
static void
check_definition(const ElementPtr& def)
{
if (!def->contains("data_specification")) {
throw DataDefinitionError("Data specification does not contain data_specification element");
if (!def->contains("module_spec")) {
throw DataDefinitionError("Data specification does not contain module_spec element");
} else {
check_data_specification(def->get("data_specification"));
check_data_specification(def->get("module_spec"));
}
}
......@@ -276,7 +276,7 @@ DataDefinition::validate_spec_list(const ElementPtr spec, const ElementPtr data)
// form, we should do that in the constructor
bool
DataDefinition::validate(const ElementPtr data) {
ElementPtr spec = definition->find("data_specification/config_data");
ElementPtr spec = definition->find("module_spec/config_data");
return validate_spec_list(spec, data);
}
......@@ -47,11 +47,11 @@ TEST(DataDefinition, ReadingSpecfiles) {
// Tests whether we can open specfiles and if we get the
// right parse errors
DataDefinition dd = DataDefinition(specfile("spec1.spec"));
EXPECT_EQ(dd.getDefinition()->get("data_specification")
EXPECT_EQ(dd.getDefinition()->get("module_spec")
->get("module_name")
->stringValue(), "Spec1");
dd = DataDefinition(specfile("spec2.spec"));
EXPECT_EQ(dd.getDefinition()->get("data_specification")
EXPECT_EQ(dd.getDefinition()->get("module_spec")
->get("config_data")->size(), 6);
data_def_error("doesnotexist",
"Error opening ",
......@@ -61,7 +61,7 @@ TEST(DataDefinition, ReadingSpecfiles) {
std::ifstream file;
file.open(specfile("spec1.spec").c_str());
dd = DataDefinition(file);
EXPECT_EQ(dd.getDefinition()->get("data_specification")
EXPECT_EQ(dd.getDefinition()->get("module_spec")
->get("module_name")
->stringValue(), "Spec1");
}
......@@ -96,7 +96,7 @@ TEST(DataDefinition, SpecfileConfigData)
data_def_error("spec7.spec",
"module_name missing in {}");
data_def_error("spec8.spec",
"Data specification does not contain data_specification element");
"Data specification does not contain module_spec element");
data_def_error("spec16.spec",
"config_data is not a list of elements");
data_def_error("spec21.spec",
......
......@@ -80,7 +80,7 @@ class CCSession:
config_handler and command_handler are callback functions,
see set_config_handler and set_command_handler for more
information on their signatures."""
data_definition = isc.config.data_spec_from_file(spec_file_name)
data_definition = isc.config.module_spec_from_file(spec_file_name)
self._config_data = isc.config.config_data.ConfigData(data_definition)
self._module_name = data_definition.get_module_name()
......@@ -121,9 +121,8 @@ class CCSession:
"""Returns the current or non-default configuration"""
return self._config_data.get_full_config()
def get_config_data(self):
"""Returns the config_data part of the specification"""
return self._config_data
def get_module_spec(self):
return self._config_data.get_module_spec()
def close(self):
"""Close the session to the command channel"""
......@@ -165,7 +164,7 @@ class CCSession:
def __send_spec(self):
"""Sends the data specification to the configuration manager"""
print("[XX] send spec for " + self._module_name + " to ConfigManager")
self._session.group_sendmsg({ "data_specification": self._config_data.get_specification().get_definition() }, "ConfigManager")
self._session.group_sendmsg({ "module_spec": self._config_data.get_module_spec().get_full_spec() }, "ConfigManager")
answer, env = self._session.group_recvmsg(False)
print("[XX] got answer from cfgmgr:")
print(answer)
......@@ -176,7 +175,7 @@ class CCSession:
answer, env = self._session.group_recvmsg(False)
rcode, value = parse_answer(answer)
if rcode == 0:
if self._config_data.get_specification().validate(False, value):
if self._config_data.get_module_spec().validate(False, value):
self._config_data.set_local_config(value);
if self._config_handler:
self._config_handler(value)
......
......@@ -106,12 +106,12 @@ class ConfigManager:
The ability to specify a custom session is for testing purposes
and should not be needed for normal usage."""
def __init__(self, data_path, session = None):
# remove these and use self.data_specs
# remove these and use self.module_specs
#self.commands = {}
self.data_definitions = {}
self.data_path = data_path
self.data_specs = {}
self.module_specs = {}
self.config = ConfigManagerData(data_path)
if session:
self.cc = session
......@@ -125,38 +125,38 @@ class ConfigManager:
"""Notifies the Boss module that the Config Manager is running"""
self.cc.group_sendmsg({"running": "configmanager"}, "Boss")
def set_data_spec(self, spec):
#data_def = isc.config.DataDefinition(spec)
self.data_specs[spec.get_module_name()] = spec
def set_module_spec(self, spec):
#data_def = isc.config.ModuleSpec(spec)
self.module_specs[spec.get_module_name()] = spec
def get_data_spec(self, module_name):
if module_name in self.data_specs:
return self.data_specs[module_name]
def get_module_spec(self, module_name):
if module_name in self.module_specs:
return self.module_specs[module_name]
def get_config_data(self, name = None):
def get_config_spec(self, name = None):
"""Returns a dict containing 'module_name': config_data for
all modules. If name is specified, only that module will
be included"""
config_data = {}
if name:
if name in self.data_specs:
config_data[name] = self.data_specs[name].get_data
if name in self.module_specs:
config_data[name] = self.module_specs[name].get_data
else:
for module_name in self.data_specs.keys():
config_data[module_name] = self.data_specs[module_name].get_config_data()
for module_name in self.module_specs.keys():
config_data[module_name] = self.module_specs[module_name].get_config_spec()
return config_data
def get_commands(self, name = None):
def get_commands_spec(self, name = None):
"""Returns a dict containing 'module_name': commands_dict for
all modules. If name is specified, only that module will
be included"""
commands = {}
if name:
if name in self.data_specs:
commands[name] = self.data_specs[name].get_commands
if name in self.module_specs:
commands[name] = self.module_specs[name].get_commands_spec
else:
for module_name in self.data_specs.keys():
commands[module_name] = self.data_specs[module_name].get_commands()
for module_name in self.module_specs.keys():
commands[module_name] = self.module_specs[module_name].get_commands_spec()
return commands
def read_config(self):
......@@ -173,19 +173,19 @@ class ConfigManager:
at the path specificied at init()"""
self.config.write_to_file()
def _handle_get_data_spec(self, cmd):
def _handle_get_module_spec(self, cmd):
answer = {}
if len(cmd) > 1:
if type(cmd[1]) == dict:
if 'module_name' in cmd[1] and cmd[1]['module_name'] != '':
module_name = cmd[1]['module_name']
answer = isc.config.ccsession.create_answer(0, self.get_config_data(module_name))
answer = isc.config.ccsession.create_answer(0, self.get_config_spec(module_name))
else:
answer = isc.config.ccsession.create_answer(1, "Bad module_name in get_data_spec command")
answer = isc.config.ccsession.create_answer(1, "Bad module_name in get_module_spec command")
else:
answer = isc.config.ccsession.create_answer(1, "Bad get_data_spec command, argument not a dict")
answer = isc.config.ccsession.create_answer(1, "Bad get_module_spec command, argument not a dict")
else:
answer = isc.config.ccsession.create_answer(0, self.get_config_data())
answer = isc.config.ccsession.create_answer(0, self.get_config_spec())
return answer
def _handle_get_config(self, cmd):
......@@ -256,17 +256,17 @@ class ConfigManager:
return answer
def _handle_data_specification(self, spec):
def _handle_module_spec(self, spec):
# todo: validate? (no direct access to spec as
# todo: use DataDefinition class
# todo: use ModuleSpec class
# todo: error checking (like keyerrors)
answer = {}
self.set_data_spec(spec)
self.set_module_spec(spec)
# We should make one general 'spec update for module' that
# passes both specification and commands at once
self.cc.group_sendmsg({ "specification_update": [ spec.get_module_name(), spec.get_config_data() ] }, "Cmd-Ctrld")
self.cc.group_sendmsg({ "commands_update": [ spec.get_module_name(), spec.get_commands() ] }, "Cmd-Ctrld")
self.cc.group_sendmsg({ "specification_update": [ spec.get_module_name(), spec.get_config_spec() ] }, "Cmd-Ctrld")
self.cc.group_sendmsg({ "commands_update": [ spec.get_module_name(), spec.get_commands_spec() ] }, "Cmd-Ctrld")
answer = isc.config.ccsession.create_answer(0)
return answer
......@@ -276,10 +276,10 @@ class ConfigManager:
if "command" in msg:
cmd = msg["command"]
try:
if cmd[0] == "get_commands":
answer = isc.config.ccsession.create_answer(0, self.get_commands())
elif cmd[0] == "get_data_spec":
answer = self._handle_get_data_spec(cmd)
if cmd[0] == "get_commands_spec":
answer = isc.config.ccsession.create_answer(0, self.get_commands_spec())
elif cmd[0] == "get_module_spec":
answer = self._handle_get_module_spec(cmd)
elif cmd[0] == "get_config":
answer = self._handle_get_config(cmd)
elif cmd[0] == "set_config":
......@@ -293,10 +293,10 @@ class ConfigManager:
except IndexError as ie:
answer = isc.config.ccsession.create_answer(1, "Missing argument in command: " + str(ie))
raise ie
elif "data_specification" in msg:
elif "module_spec" in msg:
try:
answer = self._handle_data_specification(isc.config.DataDefinition(msg["data_specification"]))
except isc.config.DataDefinitionError as dde:
answer = self._handle_module_spec(isc.config.ModuleSpec(msg["module_spec"]))
except isc.config.ModuleSpecError as dde:
answer = isc.config.ccsession.create_answer(1, "Error in data definition: " + str(dde))
elif 'result' in msg:
# this seems wrong, might start pingpong
......
......@@ -109,10 +109,10 @@ class TestConfigManager(unittest.TestCase):
self.fake_session = FakeCCSession()
self.cm = ConfigManager(self.data_path, self.fake_session)
self.name = "TestModule"
self.spec = isc.config.data_spec_from_file(self.data_path + os.sep + "/spec2.spec")
self.spec = isc.config.module_spec_from_file(self.data_path + os.sep + "/spec2.spec")
def test_init(self):
self.assert_(self.cm.data_specs == {})
self.assert_(self.cm.module_specs == {})
self.assert_(self.cm.data_path == self.data_path)
self.assert_(self.cm.config != None)
self.assert_(self.fake_session.has_subscription("ConfigManager"))
......@@ -134,14 +134,14 @@ class TestConfigManager(unittest.TestCase):
self._handle_msg_helper({}, { 'result': [ 1, 'Unknown message format: {}']})
self._handle_msg_helper("", { 'result': [ 1, 'Unknown message format: ']})
self._handle_msg_helper({ "command": [ "badcommand" ] }, { 'result': [ 1, "Unknown command: ['badcommand']"]})
self._handle_msg_helper({ "command": [ "get_commands" ] }, { 'result': [ 0, {} ]})
self._handle_msg_helper({ "command": [ "get_data_spec" ] }, { 'result': [ 0, {} ]})
#self._handle_msg_helper({ "command": [ "get_data_spec", { "module_name": "nosuchmodule" } ] },
self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, {} ]})
self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, {} ]})
#self._handle_msg_helper({ "command": [ "get_module_spec", { "module_name": "nosuchmodule" } ] },
# {'result': [1, 'No specification for module nosuchmodule']})
self._handle_msg_helper({ "command": [ "get_data_spec", 1 ] },
{'result': [1, 'Bad get_data_spec command, argument not a dict']})
self._handle_msg_helper({ "command": [ "get_data_spec", { } ] },
{'result': [1, 'Bad module_name in get_data_spec command']})
self._handle_msg_helper({ "command": [ "get_module_spec", 1 ] },
{'result': [1, 'Bad get_module_spec command, argument not a dict']})
self._handle_msg_helper({ "command": [ "get_module_spec", { } ] },
{'result': [1, 'Bad module_name in get_module_spec command']})
self._handle_msg_helper({ "command": [ "get_config" ] }, { 'result': [ 0, { 'version': 1} ]})
self._handle_msg_helper({ "command": [ "get_config", { "module_name": "nosuchmodule" } ] },
{'result': [0, {}]})
......@@ -174,16 +174,16 @@ class TestConfigManager(unittest.TestCase):
self.assertEqual({'config_update': {'test': 124}},
self.fake_session.get_message(self.name, None))
self.assertEqual({'version': 1, 'TestModule': {'test': 124}}, self.cm.config.data)
self._handle_msg_helper({ "data_specification":
self.spec.get_definition()
self._handle_msg_helper({ "module_spec":
self.spec.get_full_spec()
},
{'result': [0]})
self._handle_msg_helper({ "data_specification":
self._handle_msg_helper({ "module_spec":
{ 'foo': 1 }
},
{'result': [1, 'Error in data definition: no module_name in data_specification']})
self._handle_msg_helper({ "command": [ "get_data_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_config_spec() } ]})
self._handle_msg_helper({ "command": [ "get_commands" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_commands() } ]})
{'result': [1, 'Error in data definition: no module_name in module_spec']})
self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_config_spec() } ]})
self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_commands_spec() } ]})
# re-add this once we have new way to propagate spec changes (1 instead of the current 2 messages)
#self.assertEqual(len(self.fake_session.message_queue), 2)
# the name here is actually wrong (and hardcoded), but needed in the current version
......
......@@ -108,9 +108,9 @@ class ConfigData:
def __init__(self, specification):
"""Initialize a ConfigData instance. If specification is not
of type DataDefinition, a ConfigDataError is raised."""
if type(specification) != isc.config.DataDefinition:
raise ConfigDataError("specification is of type " + str(type(specification)) + ", not DataDefinition")
of type ModuleSpec, a ConfigDataError is raised."""
if type(specification) != isc.config.ModuleSpec:
raise ConfigDataError("specification is of type " + str(type(specification)) + ", not ModuleSpec")
self.specification = specification
self.data = {}
......@@ -127,14 +127,13 @@ class ConfigData:
value = isc.cc.data.find_no_exc(self.data, identifier)
if value:
return value, False
spec = find_spec(self.specification.get_config_data(), identifier)
spec = find_spec(self.specification.get_config_spec(), identifier)
if spec and 'item_default' in spec:
return spec['item_default'], True
return None, False
def get_specification(self):
"""Returns the datadefinition"""
print(self.specification)
def get_module_spec(self):
"""Returns the ModuleSpec object associated with this ConfigData"""
return self.specification
def set_local_config(self, data):
......@@ -147,10 +146,10 @@ class ConfigData:
def get_full_config(self):
items = self.get_item_list(None, True)
result = []
result = {}
for item in items:
value, default = self.get_value(item)
result.append(item + ": " + str(value))
result[item] = value
return result
#def get_identifiers(self):
......@@ -174,11 +173,11 @@ class MultiConfigData:
self._local_changes = {}
def set_specification(self, spec):
if type(spec) != isc.config.DataDefinition:
if type(spec) != isc.config.ModuleSpec:
raise Exception("not a datadef")
self._specifications[spec.get_module_name()] = spec
def get_specification(self, module):
def get_module_spec(self, module):
if module in self._specifications:
return self._specifications[module]
else:
......@@ -191,7 +190,7 @@ class MultiConfigData:
identifier = identifier[1:]
module, sep, id = identifier.partition("/")
try:
return find_spec(self._specifications[module].get_config_data(), id)
return find_spec(self._specifications[module].get_config_spec(), id)
except isc.cc.data.DataNotFoundError as dnfe:
return None
......@@ -223,7 +222,7 @@ class MultiConfigData:
identifier = identifier[1:]
module, sep, id = identifier.partition("/")
try:
spec = find_spec(self._specifications[module].get_config_data(), id)
spec = find_spec(self._specifications[module].get_config_spec(), id)
if 'item_default' in spec:
return spec['item_default']
else:
......@@ -272,9 +271,9 @@ class MultiConfigData:
if identifier[0] == '/':
identifier = identifier[1:]
module, sep, id = identifier.partition('/')
spec = self.get_specification(module)
spec = self.get_module_spec(module)
if spec:
spec_part = find_spec(spec.get_config_data(), id)
spec_part = find_spec(spec.get_config_spec(), id)
print(spec_part)
if type(spec_part) == list:
for item in spec_part:
......@@ -370,7 +369,7 @@ class UIConfigData():
if module in commands and commands[module]:
cur_spec['commands'] = commands[module]
self._data.set_specification(isc.config.DataDefinition(cur_spec))
self._data.set_specification(isc.config.ModuleSpec(cur_spec))
def request_current_config(self):
config = self._conn.send_GET('/config_data')
......@@ -385,8 +384,8 @@ class UIConfigData():
return self._data.set_value(identifier, value);
def add_value(self, identifier, value_str):
data_spec = self._data.find_spec_part(identifier)
if (type(data_spec) != dict or "list_item_spec" not in data_spec):
module_spec = self._data.find_spec_part(identifier)
if (type(module_spec) != dict or "list_item_spec" not in module_spec):
raise DataTypeError(identifier + " is not a list")
value = isc.cc.data.parse_value_str(value_str)
cur_list, status = self.get_value(identifier)
......@@ -397,11 +396,11 @@ class UIConfigData():
self.set_value(identifier, cur_list)
def remove_value(self, identifier, value_str):
data_spec = find_spec(self.config.specification, identifier)
if (type(data_spec) != dict or "list_item_spec" not in data_spec):
module_spec = find_spec(self.config.specification, identifier)
if (type(module_spec) != dict or "list_item_spec" not in module_spec):
raise DataTypeError(identifier + " is not a list")
value = parse_value_str(value_str)
check_type(data_spec, [value])
check_type(module_spec, [value])
cur_list = isc.cc.data.find_no_exc(self.config_changes, identifier)
if not cur_list:
cur_list = isc.cc.data.find_no_exc(self.config.data, identifier)
......@@ -434,28 +433,28 @@ class OUIConfigData():
def __init__(self, conn):
# the specs dict contains module: configdata elements
# these should all be replaced by the new stuff
data_spec = self.get_data_specification(conn)
self.config = data_spec
self.get_config_data(conn)
module_spec = self.get_module_spec(conn)
self.config = module_spec
self.get_config_spec(conn)
self.config_changes = {}
#
self.config_
self.specs = self.get_data_specifications(conn)
self.specs = self.get_module_specs(conn)
def get_config_data(self, conn):
def get_config_spec(self, conn):
data = conn.send_GET('/config_data')
def send_changes(self, conn):
conn.send_POST('/ConfigManager/set_config', self.config_changes)
# Get latest config data
self.get_config_data(conn)
self.get_config_spec(conn)
self.config_changes = {}
def get_data_specification(self, conn):
def get_module_spec(self, conn):
return conn.send_GET('/config_spec')
def get_data_specifications(self, conn):
def get_module_specs(self, conn):
specs = {}
allspecs = conn.send_GET('/config_spec')
......@@ -551,11 +550,11 @@ class OUIConfigData():
return result
def add(self, identifier, value_str):
data_spec = find_spec(self.config.specification, identifier)
if (type(data_spec) != dict or "list_item_spec" not in data_spec):
module_spec = find_spec(self.config.specification, identifier)
if (type(module_spec) != dict or "list_item_spec" not in module_spec):
raise DataTypeError(identifier + " is not a list")
value = parse_value_str(value_str)
check_type(data_spec, [value])
check_type(module_spec, [value])
cur_list = isc.cc.data.find_no_exc(self.config_changes, identifier)
if not cur_list:
cur_list = isc.cc.data.find_no_exc(self.config.data, identifier)
......@@ -566,11 +565,11 @@ class OUIConfigData():
set(self.config_changes, identifier, cur_list)
def remove(self, identifier, value_str):
data_spec = find_spec(self.config.specification, identifier)
if (type(data_spec) != dict or "list_item_spec" not in data_spec):
module_spec = find_spec(self.config.specification, identifier)
if (type(module_spec) != dict or "list_item_spec" not in module_spec):
raise DataTypeError(identifier + " is not a list")
value = parse_value_str(value_str)
check_type(data_spec, [value])
check_type(module_spec, [value])
cur_list = isc.cc.data.find_no_exc(self.config_changes, identifier)
if not cur_list:
cur_list = isc.cc.data.find_no_exc(self.config.data, identifier)
......@@ -581,9 +580,9 @@ class OUIConfigData():
set(self.config_changes, identifier, cur_list)
def set(self, identifier, value_str):
data_spec = find_spec(self.config.specification, identifier)
module_spec = find_spec(self.config.specification, identifier)
value = parse_value_str(value_str)
check_type(data_spec, value)
check_type(module_spec, value)
set(self.config_changes, identifier, value)
def unset(self, identifier):
......
......@@ -29,8 +29,8 @@ class TestConfigData(unittest.TestCase):
else:
self.data_path = "../../../testdata"
def test_data_spec_from_file(self):
spec = isc.config.data_spec_from_file(self.data_path + os.sep + "spec1.spec")
def test_module_spec_from_file(self):
spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
cd = ConfigData(spec)
self.assertEqual(cd.specification, spec)
self.assertEqual(cd.data, {})
......
......@@ -24,31 +24,31 @@ import isc.cc.data
# file objects are passed around as _io.TextIOWrapper objects
# import that so we can check those types
class DataDefinitionError(Exception):
class ModuleSpecError(Exception):
pass
def data_spec_from_file(spec_file, check = True):
data_spec = None
def module_spec_from_file(spec_file, check = True):
module_spec = None
if hasattr(spec_file, 'read'):
data_spec = ast.literal_eval(spec_file.read(-1))
module_spec = ast.literal_eval(spec_file.read(-1))
elif type(spec_file) == str:
file = open(spec_file)
data_spec = ast.literal_eval(file.read(-1))
module_spec = ast.literal_eval(file.read(-1))
file.close()
else:
raise DataDefinitionError("spec_file not a str or file-like object")