Ensure update config function can handle new headers

The linked bug occurred due to a new header for the config file being in
the upgraded charm, but not in the previous version of the charm.  As
the config file is read, updated, and then written, new headings in the
INI file would crash the charm code with a KeyError.

This patch just sets the header and parameter if it is missing.

Closes-Bug: #1927981
Change-Id: I18a6a4143ee0a1144eade5caa50611b802cba28a
This commit is contained in:
Alex Kavanagh 2021-06-28 20:01:40 +01:00
parent 4a181df851
commit 114fb08051
2 changed files with 35 additions and 1 deletions

View File

@ -635,7 +635,12 @@ class MySQLRouterCharm(charms_openstack.charm.OpenStackCharm):
config.read(self.mysqlrouter_conf)
for heading in parameters.keys():
for param in parameters[heading].keys():
config[heading][param] = parameters[heading][param]
# BUG LP#1927981 - heading may not exist during a charm upgrade
# Handle missing heading via direct assignment in except.
try:
config[heading][param] = parameters[heading][param]
except KeyError:
config[heading] = {param: parameters[heading][param]}
ch_core.hookenv.log("Writing {}".format(
self.mysqlrouter_conf))
with open(self.mysqlrouter_conf, 'w') as configfile:

View File

@ -661,6 +661,35 @@ class TestMySQLRouterCharm(test_utils.PatchHelper):
_mock_config_parser.write.assert_called_once_with(
self.mock_open()().__enter__())
def test_update_config_parameters_missing_heading(self):
# test fix for Bug LP#1927981
class FakeConfigParser(dict):
def read(*args, **kwargs):
pass
def write(*args, **kwargs):
pass
current_config = {"DEFAULT": {"client_ssl_mode": "NONE"}}
fake_config = FakeConfigParser(current_config)
self.patch_object(mysql_router.configparser, "ConfigParser",
return_value=fake_config)
# metadata_cache:jujuCluster didn't exist in the previous config so the
# header needs to be created (c.f. BUG LP#1927981)
_params = {
"DEFAULT": {"client_ssl_mode": "PREFERRED"},
"metadata_cache:jujuCluster": {"thing": "a-thing"},
}
mrc = mysql_router.MySQLRouterCharm()
# should not throw a key error.
mrc.update_config_parameters(_params)
self.assertIn('metadata_cache:jujuCluster', fake_config)
self.assertEqual(fake_config['metadata_cache:jujuCluster'],
{"thing": "a-thing"})
def test_config_changed(self):
_config_data = {
"ttl": '5',