Browse Source

renamed CCSession to ModuleCCSession
renamed UIConfigData to UICCSession
That last one is now a subclass of MultiConfigData, since half the functions it needed turned out to be nothing but passtroughs
(next is to do the same for ModuleCCSession, only that will be a subclass of ConfigData, and make the two as similar as possible, from a certain point of view they to the same, albeit from another 'direction')


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jelte-configuration@842 e5f2f494-b856-4b98-b285-d166d9295462

Jelte Jansen 15 years ago
parent
commit
275dbabd2d

+ 2 - 2
src/bin/bind10/bind10.py.in

@@ -116,7 +116,7 @@ class BoB:
             print("[XX] handling new config:")
             print("[XX] handling new config:")
             print(new_config)
             print(new_config)
         errors = []
         errors = []
-        if self.ccs.get_config_spec().get_module_spec().validate(False, new_config, errors):
+        if self.ccs.get_module_spec().validate(False, new_config, errors):
             print("[XX] new config validated")
             print("[XX] new config validated")
             self.ccs.set_config(new_config)
             self.ccs.set_config(new_config)
             answer = isc.config.ccsession.create_answer(0)
             answer = isc.config.ccsession.create_answer(0)
@@ -209,7 +209,7 @@ class BoB:
         time.sleep(1)
         time.sleep(1)
         if self.verbose:
         if self.verbose:
             print("[XX] starting ccsession")
             print("[XX] starting ccsession")
-        self.ccs = isc.config.CCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
+        self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self.ccs.start()
         self.ccs.start()
         if self.verbose:
         if self.verbose:
             print("[XX] ccsession started")
             print("[XX] ccsession started")

+ 1 - 1
src/bin/bindctl/bindcmd.py

@@ -86,7 +86,7 @@ class BindCmdInterpreter(Cmd):
                 return False
                 return False
 
 
             # Get all module information from cmd-ctrld
             # Get all module information from cmd-ctrld
-            self.config_data = isc.config.UIConfigData(self)
+            self.config_data = isc.config.UIModuleCCSession(self)
             self.update_commands()
             self.update_commands()
             self.cmdloop()
             self.cmdloop()
         except KeyboardInterrupt:
         except KeyboardInterrupt:

+ 80 - 20
src/lib/config/python/isc/config/ccsession.py

@@ -21,27 +21,28 @@
 
 
 # modeled after ccsession.h/cc 'protocol' changes here need to be
 # modeled after ccsession.h/cc 'protocol' changes here need to be
 # made there as well
 # made there as well
-"""This module provides the CCSession class, as well as a set of
+"""This module provides the ModuleCCSession class, as well as a set of
    utility functions to create and parse messages related to commands
    utility functions to create and parse messages related to commands
    and configuration"""
    and configuration"""
 
 
 from isc.cc import Session
 from isc.cc import Session
+from isc.config.config_data import ConfigData, MultiConfigData
 import isc
 import isc
 
 
-class CCSessionError(Exception): pass
+class ModuleCCSessionError(Exception): pass
 
 
 def parse_answer(msg):
 def parse_answer(msg):
     """Returns a tuple (rcode, value), where value depends on the
     """Returns a tuple (rcode, value), where value depends on the
        command that was called. If rcode != 0, value is a string
        command that was called. If rcode != 0, value is a string
        containing an error message"""
        containing an error message"""
     if 'result' not in msg:
     if 'result' not in msg:
-        raise CCSessionError("answer message does not contain 'result' element")
+        raise ModuleCCSessionError("answer message does not contain 'result' element")
     elif type(msg['result']) != list:
     elif type(msg['result']) != list:
-        raise CCSessionError("wrong result type in answer message")
+        raise ModuleCCSessionError("wrong result type in answer message")
     elif len(msg['result']) < 1:
     elif len(msg['result']) < 1:
-        raise CCSessionError("empty result list in answer message")
+        raise ModuleCCSessionError("empty result list in answer message")
     elif type(msg['result'][0]) != int:
     elif type(msg['result'][0]) != int:
-        raise CCSessionError("wrong rcode type in answer message")
+        raise ModuleCCSessionError("wrong rcode type in answer message")
     else:
     else:
         if len(msg['result']) > 1:
         if len(msg['result']) > 1:
             return msg['result'][0], msg['result'][1]
             return msg['result'][0], msg['result'][1]
@@ -54,28 +55,28 @@ def create_answer(rcode, arg = None):
        on what the command or option was. If rcode != 0, arg must be
        on what the command or option was. If rcode != 0, arg must be
        a string containing an error message"""
        a string containing an error message"""
     if type(rcode) != int:
     if type(rcode) != int:
-        raise CCSessionError("rcode in create_answer() must be an integer")
+        raise ModuleCCSessionError("rcode in create_answer() must be an integer")
     if rcode != 0 and type(arg) != str:
     if rcode != 0 and type(arg) != str:
-        raise CCSessionError("arg in create_answer for rcode != 0 must be a string describing the error")
+        raise ModuleCCSessionError("arg in create_answer for rcode != 0 must be a string describing the error")
     if arg != None:
     if arg != None:
         return { 'result': [ rcode, arg ] }
         return { 'result': [ rcode, arg ] }
     else:
     else:
         return { 'result': [ rcode ] }
         return { 'result': [ rcode ] }
 
 
-class CCSession:
+class ModuleCCSession:
     """This class maintains a connection to the command channel, as
     """This class maintains a connection to the command channel, as
        well as configuration options for modules. The module provides
        well as configuration options for modules. The module provides
        a specification file that contains the module name, configuration
        a specification file that contains the module name, configuration
-       options, and commands. It also gives the CCSession two callback
+       options, and commands. It also gives the ModuleCCSession two callback
        functions, one to call when there is a direct command to the
        functions, one to call when there is a direct command to the
        module, and one to update the configuration run-time. These
        module, and one to update the configuration run-time. These
        callbacks are called when 'check_command' is called on the
        callbacks are called when 'check_command' is called on the
-       CCSession"""
+       ModuleCCSession"""
        
        
     def __init__(self, spec_file_name, config_handler, command_handler):
     def __init__(self, spec_file_name, config_handler, command_handler):
-        """Initialize a CCSession. This does *NOT* send the
+        """Initialize a ModuleCCSession. This does *NOT* send the
            specification and request the configuration yet. Use start()
            specification and request the configuration yet. Use start()
-           for that once the CCSession has been initialized.
+           for that once the ModuleCCSession has been initialized.
            specfile_name is the path to the specification file
            specfile_name is the path to the specification file
            config_handler and command_handler are callback functions,
            config_handler and command_handler are callback functions,
            see set_config_handler and set_command_handler for more
            see set_config_handler and set_command_handler for more
@@ -137,8 +138,6 @@ class CCSession:
         if msg:
         if msg:
             answer = None
             answer = None
             try:
             try:
-                print("[XX] got msg: ")
-                print(msg)
                 if "config_update" in msg and self._config_handler:
                 if "config_update" in msg and self._config_handler:
                     answer = self._config_handler(msg["config_update"])
                     answer = self._config_handler(msg["config_update"])
                 if "command" in msg and self._command_handler:
                 if "command" in msg and self._command_handler:
@@ -163,11 +162,8 @@ class CCSession:
 
 
     def __send_spec(self):
     def __send_spec(self):
         """Sends the data specification to the configuration manager"""
         """Sends the data specification to the configuration manager"""
-        print("[XX] send spec for " + self._module_name + " to ConfigManager")
         self._session.group_sendmsg({ "module_spec": self._config_data.get_module_spec().get_full_spec() }, "ConfigManager")
         self._session.group_sendmsg({ "module_spec": self._config_data.get_module_spec().get_full_spec() }, "ConfigManager")
         answer, env = self._session.group_recvmsg(False)
         answer, env = self._session.group_recvmsg(False)
-        print("[XX] got answer from cfgmgr:")
-        print(answer)
         
         
     def __request_config(self):
     def __request_config(self):
         """Asks the configuration manager for the current configuration, and call the config handler if set"""
         """Asks the configuration manager for the current configuration, and call the config handler if set"""
@@ -175,11 +171,75 @@ class CCSession:
         answer, env = self._session.group_recvmsg(False)
         answer, env = self._session.group_recvmsg(False)
         rcode, value = parse_answer(answer)
         rcode, value = parse_answer(answer)
         if rcode == 0:
         if rcode == 0:
-            if self._config_data.get_module_spec().validate(False, value):
+            if value != None and self._config_data.get_module_spec().validate(False, value):
                 self._config_data.set_local_config(value);
                 self._config_data.set_local_config(value);
                 if self._config_handler:
                 if self._config_handler:
                     self._config_handler(value)
                     self._config_handler(value)
         else:
         else:
             # log error
             # log error
             print("Error requesting configuration: " + value)
             print("Error requesting configuration: " + value)
-    
+
+class UIModuleCCSession(MultiConfigData):
+    """This class is used in a configuration user interface. It contains
+       specific functions for getting, displaying, and sending
+       configuration settings."""
+    def __init__(self, conn):
+        MultiConfigData.__init__(self)
+        self._conn = conn
+        self.request_specifications()
+        self.request_current_config()
+
+    def request_specifications(self):
+        # this step should be unnecessary but is the current way cmdctl returns stuff
+        # so changes are needed there to make this clean (we need a command to simply get the
+        # full specs for everything, including commands etc, not separate gets for that)
+        specs = self._conn.send_GET('/config_spec')
+        commands = self._conn.send_GET('/commands')
+        for module in specs.keys():
+            cur_spec = { 'module_name': module }
+            if module in specs and specs[module]:
+                cur_spec['config_data'] = specs[module]
+            if module in commands and commands[module]:
+                cur_spec['commands'] = commands[module]
+            
+            self.set_specification(isc.config.ModuleSpec(cur_spec))
+
+    def request_current_config(self):
+        config = self._conn.send_GET('/config_data')
+        if 'version' not in config or config['version'] != 1:
+            raise Exception("Bad config version")
+        self.set_local_config(config)
+
+    def add_value(self, identifier, value_str):
+        module_spec = self.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)
+        if not cur_list:
+            cur_list = []
+        if value not in cur_list:
+            cur_list.append(value)
+        self.set_value(identifier, cur_list)
+
+    def remove_value(self, identifier, value_str):
+        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(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)
+        if not cur_list:
+            cur_list = []
+        if value in cur_list:
+            cur_list.remove(value)
+        set(self.config_changes, identifier, cur_list)
+
+    def commit(self):
+        if self.get_local_changes():
+            self._conn.send_POST('/ConfigManager/set_config', self.get_local_changes())
+            # todo: check result
+            self.request_current_config()
+            self.clear_local_changes()

+ 2 - 2
src/lib/config/python/isc/config/cfgmgr_test.py

@@ -62,7 +62,7 @@ class TestConfigManagerData(unittest.TestCase):
 #
 #
 # We can probably use a more general version of this
 # We can probably use a more general version of this
 #
 #
-class FakeCCSession:
+class FakeModuleCCSession:
     def __init__(self):
     def __init__(self):
         self.subscriptions = {}
         self.subscriptions = {}
         # each entry is of the form [ channel, instance, message ]
         # each entry is of the form [ channel, instance, message ]
@@ -106,7 +106,7 @@ class TestConfigManager(unittest.TestCase):
 
 
     def setUp(self):
     def setUp(self):
         self.data_path = os.environ['CONFIG_TESTDATA_PATH']
         self.data_path = os.environ['CONFIG_TESTDATA_PATH']
-        self.fake_session = FakeCCSession()
+        self.fake_session = FakeModuleCCSession()
         self.cm = ConfigManager(self.data_path, self.fake_session)
         self.cm = ConfigManager(self.data_path, self.fake_session)
         self.name = "TestModule"
         self.name = "TestModule"
         self.spec = isc.config.module_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")

+ 45 - 267
src/lib/config/python/isc/config/config_data.py

@@ -14,9 +14,10 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 
 #
 #
-# Class to store configuration data and data definition
-# Used by the config manager and python modules that communicate
-# with the configuration manager
+# Classes to store configuration data and data specifications
+#
+# Used by the config manager, (python) modules, and UI's (those last
+# two through the classes in ccsession)
 #
 #
 
 
 
 
@@ -173,19 +174,23 @@ class MultiConfigData:
         self._local_changes = {}
         self._local_changes = {}
 
 
     def set_specification(self, spec):
     def set_specification(self, spec):
+        """Add or update a ModuleSpec"""
         if type(spec) != isc.config.ModuleSpec:
         if type(spec) != isc.config.ModuleSpec:
             raise Exception("not a datadef")
             raise Exception("not a datadef")
         self._specifications[spec.get_module_name()] = spec
         self._specifications[spec.get_module_name()] = spec
 
 
     def get_module_spec(self, module):
     def get_module_spec(self, module):
+        """Returns the ModuleSpec for the module with the given name"""
         if module in self._specifications:
         if module in self._specifications:
             return self._specifications[module]
             return self._specifications[module]
         else:
         else:
             return None
             return None
 
 
     def find_spec_part(self, identifier):
     def find_spec_part(self, identifier):
-        """returns the specification for the item at the given
-           identifier, or None if not found"""
+        """Returns the specification for the item at the given
+           identifier, or None if not found. The first part of the
+           identifier (up to the first /) is interpreted as the module
+           name."""
         if identifier[0] == '/':
         if identifier[0] == '/':
             identifier = identifier[1:]
             identifier = identifier[1:]
         module, sep, id = identifier.partition("/")
         module, sep, id = identifier.partition("/")
@@ -194,30 +199,52 @@ class MultiConfigData:
         except isc.cc.data.DataNotFoundError as dnfe:
         except isc.cc.data.DataNotFoundError as dnfe:
             return None
             return None
 
 
-    def set_current_config(self, config):
+    # this function should only be called by __request_config
+    def __set_current_config(self, config):
+        """Replace the full current config values."""
         self._current_config = config
         self._current_config = config
 
 
     def get_current_config(self):
     def get_current_config(self):
-        """The current config is a dict where the first level is
+        """Returns the current configuration as it is known by the
+           configuration manager. It is a dict where the first level is
            the module name, and the value is the config values for
            the module name, and the value is the config values for
            that module"""
            that module"""
         return self._current_config
         return self._current_config
         
         
     def get_local_changes(self):
     def get_local_changes(self):
+        """Returns the local config changes, i.e. those that have not
+           been committed yet and are not known by the configuration
+           manager or the modules."""
         return self._local_changes
         return self._local_changes
 
 
     def clear_local_changes(self):
     def clear_local_changes(self):
+        """Reverts all local changes"""
         self._local_changes = {}
         self._local_changes = {}
 
 
     def get_local_value(self, identifier):
     def get_local_value(self, identifier):
+        """Returns a specific local (uncommitted) configuration value,
+           as specified by the identifier. If the local changes do not
+           contain a new setting for this identifier, or if the
+           identifier cannot be found, None is returned. See
+           get_value() for a general way to find a configuration value
+           """
         return isc.cc.data.find_no_exc(self._local_changes, identifier)
         return isc.cc.data.find_no_exc(self._local_changes, identifier)
         
         
     def get_current_value(self, identifier):
     def get_current_value(self, identifier):
-        """Returns the current non-default value, or None if not set"""
+        """Returns the current non-default value as known by the
+           configuration manager, or None if it is not set.
+           See get_value() for a general way to find a configuration
+           value
+        """
         return isc.cc.data.find_no_exc(self._current_config, identifier)
         return isc.cc.data.find_no_exc(self._current_config, identifier)
         
         
     def get_default_value(self, identifier):
     def get_default_value(self, identifier):
-        """returns the default value, or None if there is no default"""
+        """Returns the default value for the given identifier as
+           specified by the module specification, or None if there is
+           no default or the identifier could not be found.
+           See get_value() for a general way to find a configuration
+           value
+        """
         if identifier[0] == '/':
         if identifier[0] == '/':
             identifier = identifier[1:]
             identifier = identifier[1:]
         module, sep, id = identifier.partition("/")
         module, sep, id = identifier.partition("/")
@@ -231,10 +258,12 @@ class MultiConfigData:
             return None
             return None
 
 
     def get_value(self, identifier):
     def get_value(self, identifier):
-        """Returns a tuple containing value,status. Status is either
-           LOCAL, CURRENT, DEFAULT or NONE, corresponding to the
-           source of the value (local change, current setting, default
-           as specified by the specification, or not found at all)."""
+        """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)."""
         value = self.get_local_value(identifier)
         value = self.get_local_value(identifier)
         if value:
         if value:
             return value, self.LOCAL
             return value, self.LOCAL
@@ -253,8 +282,8 @@ class MultiConfigData:
            value: value of the entry if it is a string, int, double or bool
            value: value of the entry if it is a string, int, double or bool
            modified: true if the value is a local change
            modified: true if the value is a local change
            default: true if the value has been changed
            default: true if the value has been changed
-           Throws DataNotFoundError if the identifier is bad
            TODO: use the consts for those last ones
            TODO: use the consts for those last ones
+           Throws DataNotFoundError if the identifier is bad
         """
         """
         result = []
         result = []
         if not identifier:
         if not identifier:
@@ -327,8 +356,8 @@ class MultiConfigData:
     def set_value(self, identifier, value):
     def set_value(self, identifier, value):
         """Set the local value at the given identifier to value"""
         """Set the local value at the given identifier to value"""
         spec_part = self.find_spec_part(identifier)
         spec_part = self.find_spec_part(identifier)
-        if check_type(spec_part, value):
-            isc.cc.data.set(self._local_changes, identifier, value)
+        check_type(spec_part, value)
+        isc.cc.data.set(self._local_changes, identifier, value)
  
  
     def get_config_item_list(self, identifier = None):
     def get_config_item_list(self, identifier = None):
         """Returns a list of strings containing the item_names of
         """Returns a list of strings containing the item_names of
@@ -343,254 +372,3 @@ class MultiConfigData:
             return self._specifications.keys()
             return self._specifications.keys()
 
 
     
     
-class UIConfigData():
-    """This class is used in a configuration user interface. It contains
-       specific functions for getting, displaying, and sending
-       configuration settings."""
-    def __init__(self, conn):
-        self._conn = conn
-        self._data = MultiConfigData()
-        self.request_specifications()
-        self.request_current_config()
-        a,b = self._data.get_value("/Boss/some_string")
-
-    def request_specifications(self):
-        # this step should be unnecessary but is the current way cmdctl returns stuff
-        # so changes are needed there to make this clean (we need a command to simply get the
-        # full specs for everything, including commands etc, not separate gets for that)
-        specs = self._conn.send_GET('/config_spec')
-        commands = self._conn.send_GET('/commands')
-        #print(specs)
-        #print(commands)
-        for module in specs.keys():
-            cur_spec = { 'module_name': module }
-            if module in specs and specs[module]:
-                cur_spec['config_data'] = specs[module]
-            if module in commands and commands[module]:
-                cur_spec['commands'] = commands[module]
-            
-            self._data.set_specification(isc.config.ModuleSpec(cur_spec))
-
-    def request_current_config(self):
-        config = self._conn.send_GET('/config_data')
-        if 'version' not in config or config['version'] != 1:
-            raise Exception("Bad config version")
-        self._data.set_current_config(config)
-
-    def get_value(self, identifier):
-        return self._data.get_value(identifier)
-
-    def set_value(self, identifier, value):
-        return self._data.set_value(identifier, value);
-    
-    def add_value(self, identifier, value_str):
-        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)
-        if not cur_list:
-            cur_list = []
-        if value not in cur_list:
-            cur_list.append(value)
-        self.set_value(identifier, cur_list)
-
-    def remove_value(self, identifier, value_str):
-        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(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)
-        if not cur_list:
-            cur_list = []
-        if value in cur_list:
-            cur_list.remove(value)
-        set(self.config_changes, identifier, cur_list)
-
-    def get_value_maps(self, identifier = None):
-        return self._data.get_value_maps(identifier)
-
-    def get_local_changes(self):
-        return self._data.get_local_changes()
-
-    def commit(self):
-        self._conn.send_POST('/ConfigManager/set_config', self._data.get_local_changes())
-        # todo: check result
-        self.request_current_config()
-        self._data.clear_local_changes()
-
-    def get_config_item_list(self, identifier = None):
-        return self._data.get_config_item_list(identifier)
-
-# remove
-class OUIConfigData():
-    """This class is used in a configuration user interface. It contains
-       specific functions for getting, displaying, and sending
-       configuration settings."""
-    def __init__(self, conn):
-        # the specs dict contains module: configdata elements
-        # these should all be replaced by the new stuff
-        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_module_specs(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_spec(conn)
-        self.config_changes = {}
-
-    def get_module_spec(self, conn):
-        return conn.send_GET('/config_spec')
-
-    def get_module_specs(self, conn):
-        specs = {}
-        allspecs = conn.send_GET('/config_spec')
-        
-
-    def set(self, identifier, value):
-        # check against definition
-        spec = find_spec(identifier)
-        check_type(spec, value)
-        set(self.config_changes, identifier, value)
-
-    def get_value(self, identifier):
-        """Returns a three-tuple, where the first item is the value
-           (or None), the second is a boolean specifying whether
-           the value is the default value, and the third is a boolean
-           specifying whether the value is an uncommitted change"""
-        value = isc.cc.data.find_no_exc(self.config_changes, identifier)
-        if value:
-            return value, False, True
-        value, default = self.config.get_value(identifier)
-        if value:
-            return value, default, False
-        return None, False, False
-
-    def get_value_map_single(self, identifier, entry):
-        """Returns a single entry for a value_map, where the value is
-           not a part of a bigger map"""
-        result_part = {}
-        result_part['name'] = entry['item_name']
-        result_part['type'] = entry['item_type']
-        value, default, modified = self.get_value(identifier)
-        # should we check type and only set int, double, bool and string here?
-        result_part['value'] = value
-        result_part['default'] = default
-        result_part['modified'] = modified
-        return result_part
-
-    def get_value_map(self, identifier, entry):
-        """Returns a single entry for a value_map, where the value is
-           a part of a bigger map"""
-        result_part = {}
-        result_part['name'] = entry['item_name']
-        result_part['type'] = entry['item_type']
-        value, default, modified = self.get_value(identifier + "/" + entry['item_name'])
-        # should we check type and only set int, double, bool and string here?
-        result_part['value'] = value
-        result_part['default'] = default
-        result_part['modified'] = modified
-        return result_part
-
-    def get_value_maps(self, identifier = None):
-        """Returns a list of maps, containing the following values:
-           name: name of the entry (string)
-           type: string containing the type of the value (or 'module')
-           value: value of the entry if it is a string, int, double or bool
-           modified: true if the value is a local change
-           default: true if the value has been changed
-           Throws DataNotFoundError if the identifier is bad
-        """
-        spec = find_spec(self.config, identifier)
-        result = []
-        if type(spec) == dict:
-            # either the top-level list of modules or a spec map
-            if 'item_name' in spec:
-                result_part = self.get_value_map_single(identifier, spec)
-                if result_part['type'] == "list":
-                    values = self.get_value(identifier)[0]
-                    if values:
-                        for value in values:
-                            result_part2 = {}
-                            li_spec = spec['list_item_spec']
-                            result_part2['name'] = li_spec['item_name']
-                            result_part2['value'] = value
-                            result_part2['type'] = li_spec['item_type']
-                            result_part2['default'] = False
-                            result_part2['modified'] = False
-                            result.append(result_part2)
-                else:
-                    result.append(result_part)
-                
-            else:
-                for name in spec:
-                    result_part = {}
-                    result_part['name'] = name
-                    result_part['type'] = "module"
-                    result_part['value'] = None
-                    result_part['default'] = False
-                    result_part['modified'] = False
-                    result.append(result_part)
-        elif type(spec) == list:
-            for entry in spec:
-                if type(entry) == dict and 'item_name' in entry:
-                    result.append(self.get_value_map(identifier, entry))
-        return result
-
-    def add(self, identifier, value_str):
-        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(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)
-        if not cur_list:
-            cur_list = []
-        if value not in cur_list:
-            cur_list.append(value)
-        set(self.config_changes, identifier, cur_list)
-
-    def remove(self, identifier, value_str):
-        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(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)
-        if not cur_list:
-            cur_list = []
-        if value in cur_list:
-            cur_list.remove(value)
-        set(self.config_changes, identifier, cur_list)
-
-    def set(self, identifier, value_str):
-        module_spec = find_spec(self.config.specification, identifier)
-        value = parse_value_str(value_str)
-        check_type(module_spec, value)
-        set(self.config_changes, identifier, value)
-
-    def unset(self, identifier):
-        # todo: check whether the value is optional?
-        unset(self.config_changes, identifier)
-
-    def revert(self):
-        self.config_changes = {}
-
-    def commit(self, conn):
-        self.send_changes(conn)

+ 1 - 1
src/lib/config/python/isc/config/config_data_test.py

@@ -14,7 +14,7 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 
 #
 #
-# Tests for the ConfigData and UIConfigData classes
+# Tests for the ConfigData and MultiConfigData classes
 #
 #
 
 
 import unittest
 import unittest