Browse Source

[1901] Auto-update to new config (Init instead of Boss)

Jelte Jansen 12 years ago
parent
commit
476b3eff54

+ 47 - 15
src/lib/python/isc/config/cfgmgr.py

@@ -68,6 +68,52 @@ class ConfigManagerData:
             self.db_filename = data_path + os.sep + file_name
             self.data_path = data_path
 
+    def check_for_updates(file_config):
+        """
+        Given the parsed JSON data from the config file,
+        check whether it needs updating due to version changes.
+        Return the data with updates (or the original data if no
+        updates were necessary).
+        Even though it is at this moment not technically necessary, this
+        function makes and returns a copy of the given data.
+        """
+        config = copy.deepcopy(file_config)
+        if 'version' in config:
+            data_version = config['version']
+        else:
+            # If it is not present, assume latest or earliest?
+            data_version = 1
+
+        # For efficiency, if up-to-date, return now
+        if data_version == config_data.BIND10_CONFIG_DATA_VERSION:
+            return config
+
+        # Don't know what to do if it is more recent
+        if data_version > config_data.BIND10_CONFIG_DATA_VERSION:
+            raise ConfigManagerDataReadError("Cannot load configuration file: version %d not yet supported" % config['version'])
+        # At some point we might give up supporting older versions
+        if data_version < 1:
+            raise ConfigManagerDataReadError("Cannot load configuration file: version %d no longer supported" % config['version'])
+
+        # Ok, so we have a still-supported older version. Apply all
+        # updates
+        new_data_version = data_version
+        if new_data_version == 1:
+            # only format change, no other changes necessary
+            new_data_version = 2
+        if new_data_version == 2:
+            # 'Boss' got changed to 'Init'; If for some reason both are
+            # present, simply ignore the old one
+            if 'Boss' in config and not 'Init' in config:
+                config['Init'] = config['Boss']
+                del config['Boss']
+            new_data_version = 3
+
+        config['version'] = new_data_version
+        logger.info(CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE, data_version,
+                    new_data_version)
+        return config
+
     def read_from_file(data_path, file_name):
         """Read the current configuration found in the file file_name.
            If file_name is absolute, data_path is ignored. Otherwise
@@ -90,21 +136,7 @@ class ConfigManagerData:
             # If possible, we automatically convert to the new
             # scheme and update the configuration
             # If not, we raise an exception
-            if 'version' in file_config:
-                if file_config['version'] == config_data.BIND10_CONFIG_DATA_VERSION:
-                    config.data = file_config
-                elif file_config['version'] == 1:
-                    # only format change, no other changes necessary
-                    file_config['version'] = 2
-                    logger.info(CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE, 1, 2)
-                    config.data = file_config
-                else:
-                    if config_data.BIND10_CONFIG_DATA_VERSION > file_config['version']:
-                        raise ConfigManagerDataReadError("Cannot load configuration file: version %d no longer supported" % file_config['version'])
-                    else:
-                        raise ConfigManagerDataReadError("Cannot load configuration file: version %d not yet supported" % file_config['version'])
-            else:
-                raise ConfigManagerDataReadError("No version information in configuration file " + config.db_filename)
+            config.data = ConfigManagerData.check_for_updates(file_config)
         except IOError as ioe:
             # if IOError is 'no such file or directory', then continue
             # (raise empty), otherwise fail (raise error)

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

@@ -27,7 +27,7 @@ import copy
 
 class ConfigDataError(Exception): pass
 
-BIND10_CONFIG_DATA_VERSION = 2
+BIND10_CONFIG_DATA_VERSION = 3
 
 # Helper functions
 def spec_part_is_list(spec_part):

+ 46 - 1
src/lib/python/isc/config/tests/cfgmgr_test.py

@@ -49,6 +49,50 @@ class TestConfigManagerData(unittest.TestCase):
         self.assertEqual(self.config_manager_data.db_filename,
                          self.writable_data_path + os.sep + "b10-config.db")
 
+    def test_check_for_updates_up_to_date(self):
+        # This should automatically give an up-to-date version
+        file_config = ConfigManagerData.read_from_file(
+                        self.writable_data_path, "b10-config.db").data
+        updated_config = ConfigManagerData.check_for_updates(file_config)
+        self.assertEqual(file_config, updated_config)
+
+    def test_check_for_updates_from_1(self):
+        config = { "version": 1,
+                   "foo": "bar",
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
+    def test_check_for_updates_from_2(self):
+        # No 'Boss' present, no change (except version)
+        config = { "version": 2,
+                   "foo": "bar",
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
+        # With Boss, should be changed to 'Init'
+        config = { "version": 2,
+                   "Boss": { "some config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config = { "version": config_data.BIND10_CONFIG_DATA_VERSION,
+                   "Init": { "some config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        self.assertEqual(config, updated)
+
+        # With Boss AND Init, no change
+        config = { "version": 2,
+                   "Boss": { "some config": 1 },
+                   "Init": { "some other config": 1 },
+                   "something": [ 1, 2, 3 ] }
+        updated = ConfigManagerData.check_for_updates(config)
+        config['version'] = config_data.BIND10_CONFIG_DATA_VERSION
+        self.assertEqual(config, updated)
+
+
     def test_read_from_file(self):
         ConfigManagerData.read_from_file(self.writable_data_path, "b10-config.db")
         self.assertRaises(ConfigManagerDataEmpty,
@@ -539,7 +583,8 @@ class TestConfigManager(unittest.TestCase):
     def test_set_config_all(self):
         my_ok_answer = { 'result': [ 0 ] }
 
-        self.assertEqual({"version": 2}, self.cm.config.data)
+        self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION},
+                         self.cm.config.data)
 
         self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
         self.cm.handle_msg(ccsession.create_command(