diff --git a/apidocs/src/samples/db-get-default-instance-configuration-response-json.txt b/apidocs/src/samples/db-get-default-instance-configuration-response-json.txt index ecbc644f4e..920b516fe6 100644 --- a/apidocs/src/samples/db-get-default-instance-configuration-response-json.txt +++ b/apidocs/src/samples/db-get-default-instance-configuration-response-json.txt @@ -1,5 +1,5 @@ HTTP/1.1 200 OK Content-Type: application/json -Content-Length: 1124 +Content-Length: 1094 Date: Mon, 18 Mar 2013 19:09:17 GMT diff --git a/apidocs/src/samples/db-get-default-instance-configuration-response.json b/apidocs/src/samples/db-get-default-instance-configuration-response.json index 64b8e50f31..7fa824d7ab 100644 --- a/apidocs/src/samples/db-get-default-instance-configuration-response.json +++ b/apidocs/src/samples/db-get-default-instance-configuration-response.json @@ -2,42 +2,42 @@ "instance": { "configuration": { "basedir": "/usr", - "connect_timeout": "15", + "connect_timeout": 15, "datadir": "/var/lib/mysql/data", "default_storage_engine": "innodb", "innodb_buffer_pool_size": "150M", "innodb_data_file_path": "ibdata1:10M:autoextend", - "innodb_file_per_table": "1", + "innodb_file_per_table": 1, "innodb_log_buffer_size": "25M", "innodb_log_file_size": "50M", - "innodb_log_files_in_group": "2", + "innodb_log_files_in_group": 2, "join_buffer_size": "1M", "key_buffer_size": "50M", - "local-infile": "0", + "local-infile": 0, "max_allowed_packet": "1024K", - "max_connections": "100", + "max_connections": 100, "max_heap_table_size": "16M", - "max_user_connections": "100", + "max_user_connections": 100, "myisam-recover-options": "BACKUP,FORCE", - "open_files_limit": "512", + "open_files_limit": 512, "pid_file": "/var/run/mysqld/mysqld.pid", - "port": "3306", + "port": 3306, "query_cache_limit": "1M", "query_cache_size": "8M", - "query_cache_type": "1", + "query_cache_type": 1, "read_buffer_size": "512K", "read_rnd_buffer_size": "512K", - "server_id": "271898715", - "skip-external-locking": "1", + "server_id": 271898715, + "skip-external-locking": 1, "sort_buffer_size": "1M", - "table_definition_cache": "256", - "table_open_cache": "256", - "thread_cache_size": "4", + "table_definition_cache": 256, + "table_open_cache": 256, + "thread_cache_size": 4, "thread_stack": "192K", "tmp_table_size": "16M", "tmpdir": "/var/tmp", "user": "mysql", - "wait_timeout": "120", + "wait_timeout": 120, "performance_schema": "ON" } } diff --git a/releasenotes/notes/mysql-config-preserve-types-77b970162bf6df08.yaml b/releasenotes/notes/mysql-config-preserve-types-77b970162bf6df08.yaml new file mode 100644 index 0000000000..21c6f94e0e --- /dev/null +++ b/releasenotes/notes/mysql-config-preserve-types-77b970162bf6df08.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - Fix IniCodec to deserialize Python objects. + This also brings it in line with other codecs. + guestagent_utils.to_bytes return the byte values + as ints. + See bug 1599656 diff --git a/trove/common/stream_codecs.py b/trove/common/stream_codecs.py index 1192a04089..e038e76523 100644 --- a/trove/common/stream_codecs.py +++ b/trove/common/stream_codecs.py @@ -179,8 +179,8 @@ class IniCodec(StreamCodec): ... The above file content would be represented as: - {'section_1': {'key': 'value', 'key': 'value', ...}, - 'section_2': {'key': 'value', 'key': 'value', ...} + {'section_1': {'key': value, 'key': value, ...}, + 'section_2': {'key': value, 'key': value, ...} ... } """ @@ -190,9 +190,8 @@ class IniCodec(StreamCodec): :param default_value: Default value for keys with no value. If set, all keys are written as 'key = value'. The key is written without trailing '=' if None. - :type default_value: string + :type default_value: object """ - self._value_converter = StringConverter({default_value: None}) self._default_value = default_value self._comment_markers = comment_markers @@ -207,7 +206,8 @@ class IniCodec(StreamCodec): parser = self._init_config_parser() parser.readfp(self._pre_parse(stream)) - return {s: {k: self._value_converter.to_strings(v) + return {s: {k: + StringConverter({None: self._default_value}).to_objects(v) for k, v in parser.items(s, raw=True)} for s in parser.sections()} @@ -231,8 +231,11 @@ class IniCodec(StreamCodec): for section in sections: parser.add_section(section) for key, value in sections[section].items(): + str_val = StringConverter( + {self._default_value: None}).to_strings(value) parser.set(section, key, - self._value_converter.to_strings(value)) + str(str_val) if str_val is not None + else str_val) return parser @@ -383,6 +386,7 @@ class KeyValueCodec(PropertiesCodec): ... } """ + def __init__(self, delimiter='=', comment_markers=('#'), unpack_singletons=True, string_mappings=None): super(KeyValueCodec, self).__init__( diff --git a/trove/guestagent/common/guestagent_utils.py b/trove/guestagent/common/guestagent_utils.py index f5e6552977..dcd8894f39 100644 --- a/trove/guestagent/common/guestagent_utils.py +++ b/trove/guestagent/common/guestagent_utils.py @@ -117,6 +117,6 @@ def to_bytes(value): 'G': 1024 ** 3, }[suffix] - return str(int(round(factor * float(value)))) + return int(round(factor * float(value))) return value diff --git a/trove/tests/unittests/configuration/test_configuration_controller.py b/trove/tests/unittests/configuration/test_configuration_controller.py index ff9fa069a7..f4b76cb3f2 100644 --- a/trove/tests/unittests/configuration/test_configuration_controller.py +++ b/trove/tests/unittests/configuration/test_configuration_controller.py @@ -24,6 +24,7 @@ from trove.tests.unittests import trove_testtools class TestConfigurationParser(trove_testtools.TestCase): + def setUp(self): super(TestConfigurationParser, self).setUp() @@ -42,11 +43,12 @@ class TestConfigurationParser(trove_testtools.TestCase): d_parsed = dict(parsed) self.assertIsNotNone(d_parsed) self.assertEqual("/var/run/mysqld/mysqld.pid", d_parsed["pid-file"]) - self.assertEqual('15', d_parsed["connect_timeout"]) + self.assertEqual(15, d_parsed["connect_timeout"]) self.assertEqual('1', d_parsed["skip-external-locking"]) class TestConfigurationController(trove_testtools.TestCase): + def setUp(self): super(TestConfigurationController, self).setUp() self.controller = ConfigurationsController() @@ -179,6 +181,7 @@ class TestConfigurationController(trove_testtools.TestCase): class TestConfigurationsParameterController(trove_testtools.TestCase): + def setUp(self): super(TestConfigurationsParameterController, self).setUp() self.controller = service.ConfigurationsParameterController() diff --git a/trove/tests/unittests/guestagent/test_configuration.py b/trove/tests/unittests/guestagent/test_configuration.py index a67e5e4f74..0f514f4bb4 100644 --- a/trove/tests/unittests/guestagent/test_configuration.py +++ b/trove/tests/unittests/guestagent/test_configuration.py @@ -122,27 +122,27 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): 'value': '1.4142'}}, 1, {'Section_1': {'name': 'sqrt(2)', - 'value': '1.4142'}} + 'value': 1.4142}} ) user_overrides_v2 = ('id2', - {'Section_1': {'is_number': 'False'}}, + {'Section_1': {'is_number': False}}, 2, - {'Section_1': {'is_number': 'False'}} + {'Section_1': {'is_number': False}} ) system_overrides_v1 = ('id1', {'Section_1': {'name': 'e', - 'value': '2.7183'}}, + 'value': 2.7183}}, 1, {'Section_1': {'name': 'e', - 'value': '2.7183'}} + 'value': 2.7183}} ) system_overrides_v2 = ('id2', - {'Section_2': {'is_number': 'True'}}, + {'Section_2': {'is_number': True}}, 2, - {'Section_2': {'is_number': 'True'}} + {'Section_2': {'is_number': True}} ) self._test_import_override_strategy( @@ -153,36 +153,36 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): # single file. user_overrides_v1 = ('id1', {'Section_1': {'name': 'sqrt(2)', - 'value': '1.4142'}}, + 'value': 1.4142}}, 1, {'Section_1': {'name': 'sqrt(2)', - 'is_number': 'False', - 'value': '1.4142'}} + 'is_number': False, + 'value': 1.4142}} ) user_overrides_v2 = ('id1', - {'Section_1': {'is_number': 'False'}}, + {'Section_1': {'is_number': False}}, 1, {'Section_1': {'name': 'sqrt(2)', - 'is_number': 'False', - 'value': '1.4142'}} + 'is_number': False, + 'value': 1.4142}} ) system_overrides_v1 = ('id1', {'Section_1': {'name': 'e', - 'value': '2.7183'}}, + 'value': 2.7183}}, 1, {'Section_1': {'name': 'e', - 'value': '2.7183'}, - 'Section_2': {'is_number': 'True'}} + 'value': 2.7183}, + 'Section_2': {'is_number': True}} ) system_overrides_v2 = ('id1', - {'Section_2': {'is_number': 'True'}}, + {'Section_2': {'is_number': True}}, 1, {'Section_1': {'name': 'e', - 'value': '2.7183'}, - 'Section_2': {'is_number': 'True'}} + 'value': 2.7183}, + 'Section_2': {'is_number': True}} ) self._test_import_override_strategy( @@ -193,8 +193,8 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): def _test_import_override_strategy( self, system_overrides, user_overrides, test_multi_rev): base_config_contents = {'Section_1': {'name': 'pi', - 'is_number': 'True', - 'value': '3.1415'} + 'is_number': True, + 'value': 3.1415} } codec = IniCodec() @@ -361,21 +361,21 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): @patch.multiple(operating_system, chmod=Mock(), chown=Mock()) def _assert_get_value(self, override_strategy): base_config_contents = {'Section_1': {'name': 'pi', - 'is_number': 'True', - 'value': '3.1415'} + 'is_number': True, + 'value': 3.1415} } config_overrides_v1a = {'Section_1': {'name': 'sqrt(2)', - 'value': '1.4142'} + 'value': 1.4142} } config_overrides_v2 = {'Section_1': {'name': 'e', - 'value': '2.7183'}, + 'value': 2.7183}, 'Section_2': {'foo': 'bar'} } config_overrides_v1b = {'Section_1': {'name': 'sqrt(4)', - 'value': '2.0'} + 'value': 2.0} } codec = IniCodec() @@ -397,22 +397,22 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): # Test value before applying overrides. self.assertEqual('pi', manager.get_value('Section_1')['name']) - self.assertEqual('3.1415', manager.get_value('Section_1')['value']) + self.assertEqual(3.1415, manager.get_value('Section_1')['value']) # Test value after applying overrides. manager.apply_user_override(config_overrides_v1a, change_id='id1') self.assertEqual('sqrt(2)', manager.get_value('Section_1')['name']) - self.assertEqual('1.4142', manager.get_value('Section_1')['value']) + self.assertEqual(1.4142, manager.get_value('Section_1')['value']) manager.apply_user_override(config_overrides_v2, change_id='id2') self.assertEqual('e', manager.get_value('Section_1')['name']) - self.assertEqual('2.7183', manager.get_value('Section_1')['value']) + self.assertEqual(2.7183, manager.get_value('Section_1')['value']) self.assertEqual('bar', manager.get_value('Section_2')['foo']) # Editing change 'id1' become visible only after removing # change 'id2', which overrides 'id1'. manager.apply_user_override(config_overrides_v1b, change_id='id1') self.assertEqual('e', manager.get_value('Section_1')['name']) - self.assertEqual('2.7183', manager.get_value('Section_1')['value']) + self.assertEqual(2.7183, manager.get_value('Section_1')['value']) # Test value after removing overrides. @@ -420,35 +420,35 @@ class TestConfigurationOverrideStrategy(trove_testtools.TestCase): # removing 'id2'. manager.remove_user_override(change_id='id2') self.assertEqual('sqrt(4)', manager.get_value('Section_1')['name']) - self.assertEqual('2.0', manager.get_value('Section_1')['value']) + self.assertEqual(2.0, manager.get_value('Section_1')['value']) # Back to the base. manager.remove_user_override(change_id='id1') self.assertEqual('pi', manager.get_value('Section_1')['name']) - self.assertEqual('3.1415', manager.get_value('Section_1')['value']) + self.assertEqual(3.1415, manager.get_value('Section_1')['value']) self.assertIsNone(manager.get_value('Section_2')) # Test system overrides. manager.apply_system_override( config_overrides_v1b, change_id='id1') self.assertEqual('sqrt(4)', manager.get_value('Section_1')['name']) - self.assertEqual('2.0', manager.get_value('Section_1')['value']) + self.assertEqual(2.0, manager.get_value('Section_1')['value']) # The system values should take precedence over the user # override. manager.apply_user_override( config_overrides_v1a, change_id='id1') self.assertEqual('sqrt(4)', manager.get_value('Section_1')['name']) - self.assertEqual('2.0', manager.get_value('Section_1')['value']) + self.assertEqual(2.0, manager.get_value('Section_1')['value']) # The user values should become visible only after removing the # system change. manager.remove_system_override(change_id='id1') self.assertEqual('sqrt(2)', manager.get_value('Section_1')['name']) - self.assertEqual('1.4142', manager.get_value('Section_1')['value']) + self.assertEqual(1.4142, manager.get_value('Section_1')['value']) # Back to the base. manager.remove_user_override(change_id='id1') self.assertEqual('pi', manager.get_value('Section_1')['name']) - self.assertEqual('3.1415', manager.get_value('Section_1')['value']) + self.assertEqual(3.1415, manager.get_value('Section_1')['value']) self.assertIsNone(manager.get_value('Section_2')) diff --git a/trove/tests/unittests/guestagent/test_guestagent_utils.py b/trove/tests/unittests/guestagent/test_guestagent_utils.py index 33cabce71a..16360b883d 100644 --- a/trove/tests/unittests/guestagent/test_guestagent_utils.py +++ b/trove/tests/unittests/guestagent/test_guestagent_utils.py @@ -137,9 +137,9 @@ class TestGuestagentUtils(trove_testtools.TestCase): def test_to_bytes(self): self.assertEqual('1024', guestagent_utils.to_bytes('1024')) - self.assertEqual('1048576', guestagent_utils.to_bytes('1024K')) - self.assertEqual('1073741824', guestagent_utils.to_bytes('1024M')) - self.assertEqual('1099511627776', guestagent_utils.to_bytes('1024G')) + self.assertEqual(1048576, guestagent_utils.to_bytes('1024K')) + self.assertEqual(1073741824, guestagent_utils.to_bytes('1024M')) + self.assertEqual(1099511627776, guestagent_utils.to_bytes('1024G')) self.assertEqual('1024T', guestagent_utils.to_bytes('1024T')) self.assertEqual(1024, guestagent_utils.to_bytes(1024)) self.assertEqual('Hello!', guestagent_utils.to_bytes('Hello!')) diff --git a/trove/tests/unittests/guestagent/test_operating_system.py b/trove/tests/unittests/guestagent/test_operating_system.py index 6ddfa65af4..d61fcf737f 100644 --- a/trove/tests/unittests/guestagent/test_operating_system.py +++ b/trove/tests/unittests/guestagent/test_operating_system.py @@ -55,32 +55,23 @@ class TestOperatingSystem(trove_testtools.TestCase): def test_ini_file_codec(self): data_no_none = {"Section1": {"s1k1": 's1v1', - "s1k2": '3.1415926535'}, - "Section2": {"s2k1": '1', - "s2k2": 'True'}} + "s1k2": 3.1415926535}, + "Section2": {"s2k1": 1, + "s2k2": True}} self._test_file_codec(data_no_none, IniCodec()) data_with_none = {"Section1": {"s1k1": 's1v1', - "s1k2": '3.1415926535'}, - "Section2": {"s2k1": '1', - "s2k2": 'True', + "s1k2": 3.1415926535}, + "Section2": {"s2k1": 1, + "s2k2": True, "s2k3": None}} # Keys with None values will be written without value. self._test_file_codec(data_with_none, IniCodec()) - # Non-string values will be converted to strings. - data_with_none_as_objects = {"Section1": {"s1k1": 's1v1', - "s1k2": 3.1415926535}, - "Section2": {"s2k1": 1, - "s2k2": True, - "s2k3": None}} - self._test_file_codec(data_with_none_as_objects, IniCodec(), - expected_data=data_with_none) - # None will be replaced with 'default_value'. - default_value = '1' + default_value = 1 expected_data = guestagent_utils.update_dict( {"Section2": {"s2k3": default_value}}, dict(data_with_none)) self._test_file_codec(data_with_none, @@ -92,7 +83,11 @@ class TestOperatingSystem(trove_testtools.TestCase): "Section2": {"s2k1": '1', "s2k2": 'True'}, "Section3": {"Section4": {"s4k1": '3.1415926535', - "s4k2": None}} + "s4k2": None}}, + "Section5": {"s5k1": 1, + "s5k2": True}, + "Section6": {"Section7": {"s7k1": 3.1415926535, + "s7k2": None}} } self._test_file_codec(data, YamlCodec()) @@ -128,7 +123,11 @@ class TestOperatingSystem(trove_testtools.TestCase): "Section2": {"s2k1": '1', "s2k2": 'True'}, "Section3": {"Section4": {"s4k1": '3.1415926535', - "s4k2": None}} + "s4k2": None}}, + "Section5": {"s5k1": 1, + "s5k2": True}, + "Section6": {"Section7": {"s7k1": 3.1415926535, + "s7k2": None}} } self._test_file_codec(data, JsonCodec())