Add get_minimum_version() to Service object and DB API

This gives us an easy way to query the current minimum service version
of any service (by name/binary) in the database. We can then use this
to drive policy about things like RPC versions.

Related to blueprint service-version-behavior

Change-Id: I6acec8b881c5950585e0ffb6e62804c472d371e8
This commit is contained in:
Dan Smith
2015-09-14 12:42:01 -07:00
parent 251e09ab69
commit d4e4a5f744
6 changed files with 67 additions and 6 deletions

View File

@@ -100,6 +100,12 @@ def service_get(context, service_id, use_slave=False):
use_slave=use_slave)
def service_get_minimum_version(context, binary, use_slave=False):
"""Get the minimum service version in the database."""
return IMPL.service_get_minimum_version(context, binary,
use_slave=use_slave)
def service_get_by_host_and_topic(context, host, topic):
"""Get a service by hostname and topic it listens to."""
return IMPL.service_get_by_host_and_topic(context, host, topic)

View File

@@ -440,6 +440,17 @@ def service_get(context, service_id, use_slave=False):
use_slave=use_slave)
def service_get_minimum_version(context, binary, use_slave=False):
session = get_session(use_slave=use_slave)
with session.begin():
min_version = session.query(
func.min(models.Service.version)).\
filter(models.Service.binary == binary).\
filter(models.Service.forced_down == false()).\
scalar()
return min_version
def service_get_all(context, disabled=None):
query = model_query(context, models.Service)

View File

@@ -49,7 +49,7 @@ SERVICE_VERSION = 2
# in the cluster are at the same level.
SERVICE_VERSION_HISTORY = (
# Version 0: Pre-history
None,
{'compute_rpc': '4.0'},
# Version 1: Introduction of SERVICE_VERSION
{'compute_rpc': '4.4'},
@@ -81,7 +81,8 @@ class Service(base.NovaPersistentObject, base.NovaObject,
# Version 1.16: Added version
# Version 1.17: ComputeNode version 1.13
# Version 1.18: ComputeNode version 1.14
VERSION = '1.18'
# Version 1.19: Added get_minimum_version()
VERSION = '1.19'
fields = {
'id': fields.IntegerField(read_only=True),
@@ -254,6 +255,16 @@ class Service(base.NovaPersistentObject, base.NovaObject,
def destroy(self):
db.service_destroy(self._context, self.id)
@base.remotable_classmethod
def get_minimum_version(cls, context, binary, use_slave=False):
version = db.service_get_minimum_version(context, binary,
use_slave=use_slave)
if version is None:
return 0
# NOTE(danms): Since our return value is not controlled by object
# schema, be explicit here.
return int(version)
@base.NovaObjectRegistry.register
class ServiceList(base.ObjectListBase, base.NovaObject):
@@ -275,7 +286,8 @@ class ServiceList(base.ObjectListBase, base.NovaObject):
# Version 1.14: Service version 1.16
# Version 1.15: Service version 1.17
# Version 1.16: Service version 1.18
VERSION = '1.16'
# Version 1.17: Service version 1.19
VERSION = '1.17'
fields = {
'objects': fields.ListOfObjectsField('Service'),
@@ -287,7 +299,7 @@ class ServiceList(base.ObjectListBase, base.NovaObject):
('1.6', '1.8'), ('1.7', '1.9'), ('1.8', '1.10'),
('1.9', '1.11'), ('1.10', '1.12'), ('1.11', '1.13'),
('1.12', '1.14'), ('1.13', '1.15'), ('1.14', '1.16'),
('1.15', '1.17'), ('1.16', '1.18')],
('1.15', '1.17'), ('1.16', '1.18'), ('1.17', '1.19')],
}
@base.remotable_classmethod

View File

@@ -3167,6 +3167,20 @@ class ServiceTestCase(test.TestCase, ModelsObjectComparatorMixin):
self._assertEqualObjects(service1, real_service1,
ignored_keys=['compute_node'])
def test_service_get_minimum_version(self):
self._create_service({'version': 1,
'host': 'host3',
'binary': 'compute',
'forced_down': True})
self._create_service({'version': 2,
'host': 'host1',
'binary': 'compute'})
self._create_service({'version': 3,
'host': 'host2',
'binary': 'compute'})
self.assertEqual(2, db.service_get_minimum_version(self.ctxt,
'compute'))
def test_service_get_not_found_exception(self):
self.assertRaises(exception.ServiceNotFound,
db.service_get, self.ctxt, 100500)

View File

@@ -1243,8 +1243,8 @@ object_data = {
'SecurityGroupList': '1.0-dc8bbea01ba09a2edb6e5233eae85cbc',
'SecurityGroupRule': '1.1-ae1da17b79970012e8536f88cb3c6b29',
'SecurityGroupRuleList': '1.1-674b323c9ccea02e93b1b40e7fd2091a',
'Service': '1.18-f1c6e82b5479f63e35970fe7625c3878',
'ServiceList': '1.16-b767102cba7cbed290e396114c3f86b3',
'Service': '1.19-8914320cbeb4ec29f252d72ce55d07e1',
'ServiceList': '1.17-b767102cba7cbed290e396114c3f86b3',
'TaskLog': '1.0-78b0534366f29aa3eebb01860fbe18fe',
'TaskLogList': '1.0-cc8cce1af8a283b9d28b55fcd682e777',
'Tag': '1.1-8b8d7d5b48887651a0e01241672e2963',

View File

@@ -279,6 +279,24 @@ class _TestServiceObject(object):
'1.5',
fake_service_dict['compute_node']['nova_object.version'])
@mock.patch('nova.db.service_get_minimum_version')
def test_get_minimum_version_none(self, mock_get):
mock_get.return_value = None
self.assertEqual(0,
objects.Service.get_minimum_version(self.context,
'compute'))
mock_get.assert_called_once_with(self.context, 'compute',
use_slave=False)
@mock.patch('nova.db.service_get_minimum_version')
def test_get_minimum_version(self, mock_get):
mock_get.return_value = 123
self.assertEqual(123,
objects.Service.get_minimum_version(self.context,
'compute'))
mock_get.assert_called_once_with(self.context, 'compute',
use_slave=False)
class TestServiceObject(test_objects._LocalTest,
_TestServiceObject):