Merge "Add support for PostgreSQL 13 and above."
This commit is contained in:
commit
e074043b0f
@ -0,0 +1,11 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes support for PostgreSQL v13 and above.
|
||||
Sets the `wal_keep_size` or `wal_keep_segments` in the instance
|
||||
configuration file depending on the version in the data store version name.
|
||||
The version number is parsed from the Datastore Version name and is exposed
|
||||
to the database instance configuration templates to allow the the use of
|
||||
conditional based on the version.
|
||||
|
||||
`Story 2008285 <https://storyboard.openstack.org/#!/story/2008285>`__
|
@ -17,6 +17,8 @@
|
||||
from oslo_config import cfg as oslo_config
|
||||
from oslo_log import log as logging
|
||||
|
||||
from semantic_version import Version
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import configurations
|
||||
from trove.common import exception
|
||||
@ -69,15 +71,20 @@ class SingleInstanceConfigTemplate(object):
|
||||
'name': self.datastore_version.datastore_name,
|
||||
'manager': self.datastore_version.manager,
|
||||
'version': self.datastore_version.name,
|
||||
'semantic_version': self._parse_datastore_version(),
|
||||
}
|
||||
self.instance_id = instance_id
|
||||
|
||||
def get_template(self):
|
||||
patterns = ['{name}/{version}/{template_name}',
|
||||
'{name}/{major}.{minor}/{template_name}',
|
||||
'{name}/{major}/{template_name}',
|
||||
'{name}/{template_name}',
|
||||
'{manager}/{template_name}']
|
||||
context = self.datastore_dict.copy()
|
||||
context['template_name'] = self.template_name
|
||||
context['major'] = str(context['semantic_version'].major)
|
||||
context['minor'] = str(context['semantic_version'].minor)
|
||||
names = [name.format(**context) for name in patterns]
|
||||
return ENV.select_template(names)
|
||||
|
||||
@ -115,6 +122,24 @@ class SingleInstanceConfigTemplate(object):
|
||||
"""
|
||||
return abs(hash(self.instance_id) % (2 ** 31))
|
||||
|
||||
def _parse_datastore_version(self):
|
||||
"""
|
||||
Attempt to parse a version from the DatastoreVersion name.
|
||||
Returns version 0.0.0 if unable to parse.
|
||||
|
||||
:return: A Version instance.
|
||||
"""
|
||||
try:
|
||||
return Version.coerce(self.datastore_version.version or
|
||||
self.datastore_version.name)
|
||||
except ValueError:
|
||||
LOG.warning('Unable to parse a version number from datastore '
|
||||
'version name "%s" or "%s"',
|
||||
self.datastore_version.name,
|
||||
self.datastore_version.version)
|
||||
# TODO(adrianjarvis) define default version for each datastore
|
||||
return Version(major=0, minor=0, patch=0)
|
||||
|
||||
|
||||
def _validate_datastore(datastore_manager):
|
||||
try:
|
||||
|
@ -297,7 +297,11 @@ restore_command = 'cp /var/lib/postgresql/data/wal_archive/%f "%p"' # command t
|
||||
|
||||
#max_wal_senders = 10 # max number of walsender processes
|
||||
# (change requires restart)
|
||||
{% if datastore.semantic_version.major >= 13 %}
|
||||
wal_keep_size = 80 # in MB = wal_keep_segments x wal_keep_size
|
||||
{% else %}
|
||||
wal_keep_segments = 5 # in logfile segments; 0 disables
|
||||
{% endif %}
|
||||
# (Trove default)
|
||||
#wal_sender_timeout = 60s # in milliseconds; 0 disables
|
||||
|
||||
|
@ -906,6 +906,12 @@
|
||||
"min": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "wal_keep_size",
|
||||
"restart_required": true,
|
||||
"min": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "wal_log_hints",
|
||||
"restart_required": true,
|
||||
|
@ -12,12 +12,26 @@
|
||||
import re
|
||||
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from semantic_version import Version
|
||||
|
||||
from trove.common import template
|
||||
from trove.common.utils import ENV
|
||||
from trove.datastore.models import DatastoreVersion
|
||||
from trove.tests.unittests import trove_testtools
|
||||
|
||||
|
||||
def mock_datastore_version(datastore_name='MySQL', name='mysql-5.7',
|
||||
manager='mysql', version=''):
|
||||
datastore = Mock(spec=DatastoreVersion)
|
||||
datastore.datastore_name = datastore_name
|
||||
datastore.name = name
|
||||
datastore.manager = manager
|
||||
datastore.version = version
|
||||
return datastore
|
||||
|
||||
|
||||
class TemplateTest(trove_testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(TemplateTest, self).setUp()
|
||||
@ -58,10 +72,7 @@ class TemplateTest(trove_testtools.TestCase):
|
||||
self.server_id)
|
||||
|
||||
def test_single_instance_config_rendering(self):
|
||||
datastore = Mock(spec=DatastoreVersion)
|
||||
datastore.datastore_name = 'MySql'
|
||||
datastore.name = 'mysql-5.7'
|
||||
datastore.manager = 'mysql'
|
||||
datastore = mock_datastore_version()
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
@ -70,10 +81,9 @@ class TemplateTest(trove_testtools.TestCase):
|
||||
|
||||
def test_renderer_discovers_special_config(self):
|
||||
"""Finds our special config file for the version 'mysql-test'."""
|
||||
datastore = Mock(spec=DatastoreVersion)
|
||||
datastore.datastore_name = 'mysql'
|
||||
datastore.name = 'mysql-test'
|
||||
datastore.manager = 'mysql'
|
||||
datastore = mock_datastore_version(name='mysql-test',
|
||||
manager='mysql',
|
||||
datastore_name='mysql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
@ -81,21 +91,106 @@ class TemplateTest(trove_testtools.TestCase):
|
||||
{'ram': 0}, self.server_id)
|
||||
|
||||
def test_replica_source_config_rendering(self):
|
||||
datastore = Mock(spec=DatastoreVersion)
|
||||
datastore.datastore_name = 'MySql'
|
||||
datastore.name = 'mysql-5.7'
|
||||
datastore.manager = 'mysql'
|
||||
datastore = mock_datastore_version()
|
||||
config = template.ReplicaSourceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertTrue(self._find_in_template(config.render(), "log_bin"))
|
||||
|
||||
def test_replica_config_rendering(self):
|
||||
datastore = Mock(spec=DatastoreVersion)
|
||||
datastore.datastore_name = 'MySql'
|
||||
datastore.name = 'mysql-5.7'
|
||||
datastore.manager = 'mysql'
|
||||
datastore = mock_datastore_version()
|
||||
config = template.ReplicaConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertTrue(self._find_in_template(config.render(), "relay_log"))
|
||||
|
||||
def test_replica_config_rendering_mysql_v8(self):
|
||||
datastore = mock_datastore_version(name='8.0')
|
||||
config = template.ReplicaConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertTrue(self._find_in_template(config.render(),
|
||||
"binlog_format"))
|
||||
|
||||
def test_config_postgresql_pre_v13_sets_wal_keep_segments(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='12.17',
|
||||
manager='postgresql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertTrue(
|
||||
self._find_in_template(config.render(), "wal_keep_segments"))
|
||||
self.assertIsNone(
|
||||
self._find_in_template(config.render(), "wal_keep_size"))
|
||||
|
||||
def test_config_postgresql_post_v12_sets_wal_keep_size(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='13.2',
|
||||
manager='postgresql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertTrue(
|
||||
self._find_in_template(config.render(), "wal_keep_size"))
|
||||
self.assertIsNone(
|
||||
self._find_in_template(config.render(), "wal_keep_segments"))
|
||||
|
||||
def test_parse_version_name_missing_release_number(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='test',
|
||||
manager='postgresql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertEqual(Version(major=0, minor=0, patch=0),
|
||||
config._parse_datastore_version())
|
||||
|
||||
def test_parse_version_release_part_of_name(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='test-12.17',
|
||||
manager='postgresql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertEqual(Version(major=0, minor=0, patch=0),
|
||||
config._parse_datastore_version())
|
||||
|
||||
def test_parse_version_name_with_prefix(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='16.1-test',
|
||||
manager='postgresql')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertEqual(Version(major=16, minor=1, patch=0,
|
||||
prerelease=('test',)),
|
||||
config._parse_datastore_version())
|
||||
|
||||
def test_parse_version_prefer_version_if_set(self):
|
||||
datastore = mock_datastore_version(datastore_name='PostgreSQL',
|
||||
name='test',
|
||||
manager='postgresql',
|
||||
version='16.1')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
self.assertEqual(Version(major=16, minor=1, patch=0,
|
||||
),
|
||||
config._parse_datastore_version())
|
||||
|
||||
def test_template_paths(self):
|
||||
datastore = mock_datastore_version(name='5.7.9')
|
||||
config = template.SingleInstanceConfigTemplate(datastore,
|
||||
self.flavor_dict,
|
||||
self.server_id)
|
||||
with patch.object(ENV, 'select_template') as select_template_mock:
|
||||
config.get_template()
|
||||
select_template_mock.assert_called_with(
|
||||
['MySQL/5.7.9/config.template',
|
||||
'MySQL/5.7/config.template',
|
||||
'MySQL/5/config.template',
|
||||
'MySQL/config.template',
|
||||
'mysql/config.template'
|
||||
]
|
||||
)
|
||||
|
@ -817,9 +817,17 @@ class BuiltInstanceTasksTest(trove_testtools.TestCase):
|
||||
# this is used during the final check of whether the resize successful
|
||||
db_instance.server_status = 'HEALTHY'
|
||||
self.db_instance = db_instance
|
||||
datastore_version = MagicMock(
|
||||
spec=datastore_models.DatastoreVersion)
|
||||
datastore_version.id = '1'
|
||||
datastore_version.name = '5.7'
|
||||
datastore_version.version = '5.7'
|
||||
datastore_version.datastore_id = 'id-1'
|
||||
datastore_version.manager = 'mysql'
|
||||
datastore_version.datastore_name = 'mysql'
|
||||
self.dm_dv_load_by_uuid_patch = patch.object(
|
||||
datastore_models.DatastoreVersion, 'load_by_uuid', MagicMock(
|
||||
return_value=datastore_models.DatastoreVersion(db_instance)))
|
||||
return_value=datastore_version))
|
||||
self.dm_dv_load_by_uuid_mock = self.dm_dv_load_by_uuid_patch.start()
|
||||
self.addCleanup(self.dm_dv_load_by_uuid_patch.stop)
|
||||
self.dm_ds_load_patch = patch.object(
|
||||
|
Loading…
x
Reference in New Issue
Block a user