Make get_capabilities look for clusters
Currently get_capabilities accepts only host as a service identifier and fails when it cannot find a service with such host property. In A/A deployment, it should accept cluster_name as well, because get_capabilities addresses backend and not individual host. This commit fixes this up by making the call seek for available services using both host and cluster_name properties. Although it's an API change, it doesn't need a new microversion, because it falls under "Did we silently fail to do what is asked?" category. Change-Id: If7bca131c84fc997da8ad277eccd134e8ca4b316 Closes-Bug: 1660990
This commit is contained in:
parent
c4ea8f598d
commit
7401d0d098
@ -44,16 +44,18 @@ class CapabilitiesController(wsgi.Controller):
|
|||||||
"""Return capabilities list of given backend."""
|
"""Return capabilities list of given backend."""
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
authorize(context, 'capabilities')
|
authorize(context, 'capabilities')
|
||||||
filters = {'host': id, 'binary': 'cinder-volume'}
|
filters = {'host_or_cluster': id, 'binary': 'cinder-volume'}
|
||||||
service = objects.ServiceList.get_all(context, filters)
|
services = objects.ServiceList.get_all(context, filters)
|
||||||
if not service:
|
if not services:
|
||||||
msg = (_("Can't find service: %s") % id)
|
msg = (_("Can't find service: %s") % id)
|
||||||
raise exception.NotFound(msg)
|
raise exception.NotFound(msg)
|
||||||
|
topic = services[0].service_topic_queue
|
||||||
try:
|
try:
|
||||||
capabilities = self.volume_api.get_capabilities(context, id, False)
|
capabilities = self.volume_api.get_capabilities(context, topic,
|
||||||
|
False)
|
||||||
except oslo_messaging.MessagingTimeout:
|
except oslo_messaging.MessagingTimeout:
|
||||||
raise exception.RPCTimeout(service=id)
|
raise exception.RPCTimeout(service=topic)
|
||||||
return self._view_builder.summary(req, capabilities, id)
|
return self._view_builder.summary(req, capabilities, topic)
|
||||||
|
|
||||||
|
|
||||||
class Capabilities(extensions.ExtensionDescriptor):
|
class Capabilities(extensions.ExtensionDescriptor):
|
||||||
|
@ -117,7 +117,9 @@ def service_get(context, service_id=None, backend_match_level=None, **filters):
|
|||||||
def service_get_all(context, backend_match_level=None, **filters):
|
def service_get_all(context, backend_match_level=None, **filters):
|
||||||
"""Get all services that match the criteria.
|
"""Get all services that match the criteria.
|
||||||
|
|
||||||
A possible filter is is_up=True and it will filter nodes that are down.
|
A possible filter is is_up=True and it will filter nodes that are down,
|
||||||
|
as well as host_or_cluster, that lets you look for services using both
|
||||||
|
of these properties.
|
||||||
|
|
||||||
:param filters: Filters for the query in the form of key/value arguments.
|
:param filters: Filters for the query in the form of key/value arguments.
|
||||||
:param backend_match_level: 'pool', 'backend', or 'host' for host and
|
:param backend_match_level: 'pool', 'backend', or 'host' for host and
|
||||||
|
@ -449,8 +449,9 @@ def _clustered_bool_field_filter(query, field_name, filter_value):
|
|||||||
|
|
||||||
|
|
||||||
def _service_query(context, session=None, read_deleted='no', host=None,
|
def _service_query(context, session=None, read_deleted='no', host=None,
|
||||||
cluster_name=None, is_up=None, backend_match_level=None,
|
cluster_name=None, is_up=None, host_or_cluster=None,
|
||||||
disabled=None, frozen=None, **filters):
|
backend_match_level=None, disabled=None, frozen=None,
|
||||||
|
**filters):
|
||||||
filters = _clean_filters(filters)
|
filters = _clean_filters(filters)
|
||||||
if filters and not is_valid_model_filters(models.Service, filters):
|
if filters and not is_valid_model_filters(models.Service, filters):
|
||||||
return None
|
return None
|
||||||
@ -467,6 +468,13 @@ def _service_query(context, session=None, read_deleted='no', host=None,
|
|||||||
if cluster_name:
|
if cluster_name:
|
||||||
query = query.filter(_filter_host(models.Service.cluster_name,
|
query = query.filter(_filter_host(models.Service.cluster_name,
|
||||||
cluster_name, backend_match_level))
|
cluster_name, backend_match_level))
|
||||||
|
if host_or_cluster:
|
||||||
|
query = query.filter(or_(
|
||||||
|
_filter_host(models.Service.host, host_or_cluster,
|
||||||
|
backend_match_level),
|
||||||
|
_filter_host(models.Service.cluster_name, host_or_cluster,
|
||||||
|
backend_match_level),
|
||||||
|
))
|
||||||
|
|
||||||
query = _clustered_bool_field_filter(query, 'disabled', disabled)
|
query = _clustered_bool_field_filter(query, 'disabled', disabled)
|
||||||
query = _clustered_bool_field_filter(query, 'frozen', frozen)
|
query = _clustered_bool_field_filter(query, 'frozen', frozen)
|
||||||
|
@ -70,13 +70,13 @@ class CapabilitiesAPITest(test.TestCase):
|
|||||||
@mock.patch('cinder.volume.rpcapi.VolumeAPI.get_capabilities',
|
@mock.patch('cinder.volume.rpcapi.VolumeAPI.get_capabilities',
|
||||||
rpcapi_get_capabilities)
|
rpcapi_get_capabilities)
|
||||||
def test_capabilities_summary(self, mock_services):
|
def test_capabilities_summary(self, mock_services):
|
||||||
mock_services.return_value = [{'name': 'fake'}]
|
mock_services.return_value = [{'name': 'fake', 'host': 'fake_host'}]
|
||||||
req = fakes.HTTPRequest.blank('/fake/capabilities/fake')
|
req = fakes.HTTPRequest.blank('/fake/capabilities/fake')
|
||||||
req.environ['cinder.context'] = self.ctxt
|
req.environ['cinder.context'] = self.ctxt
|
||||||
res = self.controller.show(req, 'fake')
|
res = self.controller.show(req, 'fake')
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'namespace': 'OS::Storage::Capabilities::fake',
|
'namespace': 'OS::Storage::Capabilities::fake_host',
|
||||||
'vendor_name': 'OpenStack',
|
'vendor_name': 'OpenStack',
|
||||||
'volume_backend_name': 'lvm',
|
'volume_backend_name': 'lvm',
|
||||||
'pool_name': 'pool',
|
'pool_name': 'pool',
|
||||||
|
@ -277,6 +277,18 @@ class DBAPIServiceTestCase(BaseTest):
|
|||||||
real = db.service_get_all(self.ctxt, cluster_name='cluster')
|
real = db.service_get_all(self.ctxt, cluster_name='cluster')
|
||||||
self._assertEqualListsOfObjects(expected, real)
|
self._assertEqualListsOfObjects(expected, real)
|
||||||
|
|
||||||
|
def test_service_get_all_by_host_or_cluster(self):
|
||||||
|
values = [
|
||||||
|
{'host': 'host1', 'cluster_name': 'cluster'},
|
||||||
|
{'host': 'host2', 'cluster_name': 'host1'},
|
||||||
|
{'host': 'host3', 'cluster_name': 'cluster@backend'},
|
||||||
|
{'host': 'host4', 'cluster_name': 'cluster2'},
|
||||||
|
]
|
||||||
|
services = [utils.create_service(self.ctxt, vals) for vals in values]
|
||||||
|
expected = services[0:2]
|
||||||
|
real = db.service_get_all(self.ctxt, host_or_cluster='host1')
|
||||||
|
self._assertEqualListsOfObjects(expected, real)
|
||||||
|
|
||||||
def test_service_get_by_args_not_found_exception(self):
|
def test_service_get_by_args_not_found_exception(self):
|
||||||
self.assertRaises(exception.ServiceNotFound,
|
self.assertRaises(exception.ServiceNotFound,
|
||||||
db.service_get,
|
db.service_get,
|
||||||
|
Loading…
Reference in New Issue
Block a user