[svn] commit: r865 - in /branches/jelte-configuration/src/lib/config/python/isc/config: ccsession.py cfgmgr.py cfgmgr_test.py
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Feb 18 10:11:15 UTC 2010
Author: jelte
Date: Thu Feb 18 10:11:15 2010
New Revision: 865
Log:
documentation and tests for configuration manager
Modified:
branches/jelte-configuration/src/lib/config/python/isc/config/ccsession.py
branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr.py
branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr_test.py
Modified: branches/jelte-configuration/src/lib/config/python/isc/config/ccsession.py
==============================================================================
--- branches/jelte-configuration/src/lib/config/python/isc/config/ccsession.py (original)
+++ branches/jelte-configuration/src/lib/config/python/isc/config/ccsession.py Thu Feb 18 10:11:15 2010
@@ -21,9 +21,20 @@
# modeled after ccsession.h/cc 'protocol' changes here need to be
# made there as well
-"""This module provides the ModuleCCSession and UICCSession classes,
+"""Classes and functions for handling configuration and commands
+
+ This module provides the ModuleCCSession and UICCSession classes,
as well as a set of utility functions to create and parse messages
- related to commands and configuration"""
+ related to commands and configuration
+
+ Modules should use the ModuleCCSession class to connect to the
+ configuration manager, and receive updates and commands from
+ other modules.
+
+ Configuration user interfaces should use the UICCSession to connect
+ to b10-cmdctl, and receive and send configuration and commands
+ through that to the configuration manager.
+"""
from isc.cc import Session
from isc.config.config_data import ConfigData, MultiConfigData
Modified: branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr.py
==============================================================================
--- branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr.py (original)
+++ branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr.py Thu Feb 18 10:11:15 2010
@@ -13,9 +13,11 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# This is the main class for the b10-cfgmgr daemon
-#
+"""This is the BIND 10 configuration manager, run by b10-cfgmgr.
+
+ It stores the system configuration, and sends updates of the
+ configuration to the modules that need them.
+"""
import isc
import signal
@@ -25,12 +27,19 @@
from isc.cc import data
class ConfigManagerDataReadError(Exception):
+ """This exception is thrown when there is an error while reading
+ the current configuration on startup."""
pass
class ConfigManagerDataEmpty(Exception):
+ """This exception is thrown when the currently stored configuration
+ is not found, or appears empty."""
pass
class ConfigManagerData:
+ """This class hold the actual configuration information, and
+ reads it from and writes it to persistent storage"""
+
CONFIG_VERSION = 1
def __init__(self, data_path, file_name = "b10-config.db"):
@@ -42,11 +51,6 @@
self.data['version'] = ConfigManagerData.CONFIG_VERSION
self.data_path = data_path
self.db_filename = data_path + os.sep + file_name
-
- def set_data_definition(self, module_name, module_data_definition):
- """Set the data definition for the given module name."""
- #self.zones[module_name] = module_data_definition
- self.data_definitions[module_name] = module_data_definition
def read_from_file(data_path, file_name = "b10-config.db"):
"""Read the current configuration found in the file at
@@ -106,10 +110,11 @@
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.module_specs
- #self.commands = {}
- self.data_definitions = {}
-
+ """Initialize the configuration manager. The data_path string
+ is the path to the directory where the configuration is
+ stored (in <data_path>/b10-config.db). Session is an optional
+ cc-channel session. If this is not given, a new one is
+ created"""
self.data_path = data_path
self.module_specs = {}
self.config = ConfigManagerData(data_path)
@@ -126,15 +131,23 @@
self.cc.group_sendmsg({"running": "configmanager"}, "Boss")
def set_module_spec(self, spec):
- #data_def = isc.config.ModuleSpec(spec)
+ """Adds a ModuleSpec"""
self.module_specs[spec.get_module_name()] = spec
+ def remove_module_spec(self, module_name):
+ """Removes the full ModuleSpec for the given module_name.
+ Does nothing if the module was not present."""
+ if module_name in self.module_specs:
+ del self.module_specs[module_name]
+
def get_module_spec(self, module_name):
+ """Returns the full ModuleSpec for the module with the given
+ module_name"""
if module_name in self.module_specs:
return self.module_specs[module_name]
def get_config_spec(self, name = None):
- """Returns a dict containing 'module_name': config_data for
+ """Returns a dict containing 'module_name': config_spec for
all modules. If name is specified, only that module will
be included"""
config_data = {}
@@ -147,7 +160,7 @@
return config_data
def get_commands_spec(self, name = None):
- """Returns a dict containing 'module_name': commands_dict for
+ """Returns a dict containing 'module_name': commands_spec for
all modules. If name is specified, only that module will
be included"""
commands = {}
@@ -174,6 +187,7 @@
self.config.write_to_file()
def _handle_get_module_spec(self, cmd):
+ """Private function that handles the 'get_module_spec' command"""
answer = {}
if len(cmd) > 1:
if type(cmd[1]) == dict:
@@ -189,6 +203,7 @@
return answer
def _handle_get_config(self, cmd):
+ """Private function that handles the 'get_config' command"""
answer = {}
if len(cmd) > 1:
if type(cmd[1]) == dict:
@@ -209,6 +224,7 @@
return answer
def _handle_set_config(self, cmd):
+ """Private function that handles the 'set_config' command"""
answer = None
if len(cmd) == 3:
# todo: use api (and check the data against the definition?)
@@ -257,6 +273,7 @@
return answer
def _handle_module_spec(self, spec):
+ """Private function that handles the 'module_spec' command"""
# todo: validate? (no direct access to spec as
# todo: use ModuleSpec class
# todo: error checking (like keyerrors)
@@ -271,7 +288,7 @@
return answer
def handle_msg(self, msg):
- """Handle a direct command"""
+ """Handle a command from the cc channel to the configuration manager"""
answer = {}
if "command" in msg:
cmd = msg["command"]
@@ -306,6 +323,7 @@
return answer
def run(self):
+ """Runs the configuration manager."""
self.running = True
while (self.running):
msg, env = self.cc.group_recvmsg(False)
@@ -314,10 +332,3 @@
self.cc.group_reply(env, answer)
else:
self.running = False
-
-cm = None
-
-def signal_handler(signal, frame):
- global cm
- if cm:
- cm.running = False
Modified: branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr_test.py
==============================================================================
--- branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr_test.py (original)
+++ branches/jelte-configuration/src/lib/config/python/isc/config/cfgmgr_test.py Thu Feb 18 10:11:15 2010
@@ -35,9 +35,6 @@
self.assertEqual(self.config_manager_data.db_filename,
self.data_path + os.sep + "b10-config.db")
- def test_set_data_definition(self):
- pass
-
def test_read_from_file(self):
ConfigManagerData.read_from_file(self.data_path)
self.assertRaises(ConfigManagerDataEmpty,
@@ -59,6 +56,21 @@
new_config = ConfigManagerData(self.data_path, output_file_name)
self.assertEqual(self.config_manager_data, new_config)
+ def test_equality(self):
+ # tests the __eq__ function. Equality is only defined
+ # by equality of the .data element. If data_path or db_filename
+ # are different, but the contents are the same, it's still
+ # considered equal
+ cfd1 = ConfigManagerData(self.data_path)
+ cfd2 = ConfigManagerData(self.data_path)
+ self.assertEqual(cfd1, cfd2)
+ cfd2.data_path = "some/unknown/path"
+ self.assertEqual(cfd1, cfd2)
+ cfd2.db_filename = "bad_file.name"
+ self.assertEqual(cfd1, cfd2)
+ cfd2.data['test'] = { 'a': [ 1, 2, 3]}
+ self.assertNotEqual(cfd1, cfd2)
+
#
# We can probably use a more general version of this
#
@@ -126,6 +138,71 @@
# this one is actually wrong, but 'current status quo'
self.assertEqual(msg, {"running": "configmanager"})
+ def test_set_module_spec(self):
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+
+ def test_remove_module_spec(self):
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ self.cm.remove_module_spec(module_spec.get_module_name())
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+
+ def test_get_module_spec(self):
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ module_spec2 = self.cm.get_module_spec(module_spec.get_module_name())
+ self.assertEqual(module_spec, module_spec2)
+
+ def test_get_config_spec(self):
+ config_spec = self.cm.get_config_spec()
+ self.assertEqual(config_spec, {})
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ config_spec = self.cm.get_config_spec()
+ self.assertEqual(config_spec, { 'Spec1': None })
+ self.cm.remove_module_spec('Spec1')
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ config_spec = self.cm.get_config_spec()
+ self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
+
+ def test_get_commands_spec(self):
+ commands_spec = self.cm.get_commands_spec()
+ self.assertEqual(commands_spec, {})
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ commands_spec = self.cm.get_commands_spec()
+ self.assertEqual(commands_spec, { 'Spec1': None })
+ self.cm.remove_module_spec('Spec1')
+ module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
+ self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
+ self.cm.set_module_spec(module_spec)
+ self.assert_(module_spec.get_module_name() in self.cm.module_specs)
+ commands_spec = self.cm.get_commands_spec()
+ self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
+
+ def test_read_config(self):
+ self.assertEqual(self.cm.config.data, {'version': 1})
+ self.cm.read_config()
+ self.assertEqual(self.cm.config.data, {'TestModule': {'test': 124}, 'version': 1})
+
+ def test_write_config(self):
+ # tested in ConfigManagerData tests
+ pass
+
def _handle_msg_helper(self, msg, expected_answer):
answer = self.cm.handle_msg(msg)
self.assertEqual(expected_answer, answer)
More information about the bind10-changes
mailing list