Make os-availability-zones know about cells
This removes the direct-to-object listing of Service objects by the availability zone routines. Instead, it implements a cell-scanning approach in HostAPI and uses that for consistent behavior. The modified behavior of service_get_all() in HostAPI was originally in another patch, but is moved here because of dependency sequencing. The HostAPI patch later in this series uses this as well. Related to blueprint cells-aware-api Change-Id: I65c2b436bef8837c0e10a5e502e9cd598d9aa0c3
This commit is contained in:
@@ -16,8 +16,8 @@ from nova.api.openstack.compute.schemas import availability_zone as schema
|
|||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova import availability_zones
|
from nova import availability_zones
|
||||||
|
from nova import compute
|
||||||
import nova.conf
|
import nova.conf
|
||||||
from nova import objects
|
|
||||||
from nova.policies import availability_zone as az_policies
|
from nova.policies import availability_zone as az_policies
|
||||||
from nova import servicegroup
|
from nova import servicegroup
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ class AvailabilityZoneController(wsgi.Controller):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(AvailabilityZoneController, self).__init__()
|
super(AvailabilityZoneController, self).__init__()
|
||||||
self.servicegroup_api = servicegroup.API()
|
self.servicegroup_api = servicegroup.API()
|
||||||
|
self.host_api = compute.HostAPI()
|
||||||
|
|
||||||
def _get_filtered_availability_zones(self, zones, is_available):
|
def _get_filtered_availability_zones(self, zones, is_available):
|
||||||
result = []
|
result = []
|
||||||
@@ -62,8 +63,9 @@ class AvailabilityZoneController(wsgi.Controller):
|
|||||||
availability_zones.get_availability_zones(ctxt)
|
availability_zones.get_availability_zones(ctxt)
|
||||||
|
|
||||||
# Available services
|
# Available services
|
||||||
enabled_services = objects.ServiceList.get_all(context, disabled=False,
|
enabled_services = self.host_api.service_get_all(
|
||||||
set_zones=True)
|
context, {'disabled': False}, set_zones=True, all_cells=True)
|
||||||
|
|
||||||
zone_hosts = {}
|
zone_hosts = {}
|
||||||
host_services = {}
|
host_services = {}
|
||||||
api_services = ('nova-osapi_compute', 'nova-ec2', 'nova-metadata')
|
api_services = ('nova-osapi_compute', 'nova-ec2', 'nova-metadata')
|
||||||
|
@@ -120,8 +120,12 @@ def get_availability_zones(context, get_only_available=False,
|
|||||||
:param with_hosts: whether to return hosts part of the AZs
|
:param with_hosts: whether to return hosts part of the AZs
|
||||||
:type with_hosts: bool
|
:type with_hosts: bool
|
||||||
"""
|
"""
|
||||||
enabled_services = objects.ServiceList.get_all(context, disabled=False,
|
# NOTE(danms): Avoid circular import
|
||||||
set_zones=True)
|
from nova import compute
|
||||||
|
hostapi = compute.HostAPI()
|
||||||
|
|
||||||
|
enabled_services = hostapi.service_get_all(
|
||||||
|
context, {'disabled': False}, set_zones=True, all_cells=True)
|
||||||
|
|
||||||
available_zones = []
|
available_zones = []
|
||||||
for (zone, host) in [(service['availability_zone'], service['host'])
|
for (zone, host) in [(service['availability_zone'], service['host'])
|
||||||
@@ -136,8 +140,8 @@ def get_availability_zones(context, get_only_available=False,
|
|||||||
available_zones = list(_available_zones.items())
|
available_zones = list(_available_zones.items())
|
||||||
|
|
||||||
if not get_only_available:
|
if not get_only_available:
|
||||||
disabled_services = objects.ServiceList.get_all(context, disabled=True,
|
disabled_services = hostapi.service_get_all(
|
||||||
set_zones=True)
|
context, {'disabled': True}, set_zones=True, all_cells=True)
|
||||||
not_available_zones = []
|
not_available_zones = []
|
||||||
azs = available_zones if not with_hosts else dict(available_zones)
|
azs = available_zones if not with_hosts else dict(available_zones)
|
||||||
zones = [(service['availability_zone'], service['host'])
|
zones = [(service['availability_zone'], service['host'])
|
||||||
|
@@ -4325,20 +4325,36 @@ class HostAPI(base.Base):
|
|||||||
payload)
|
payload)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def service_get_all(self, context, filters=None, set_zones=False):
|
def service_get_all(self, context, filters=None, set_zones=False,
|
||||||
|
all_cells=False):
|
||||||
"""Returns a list of services, optionally filtering the results.
|
"""Returns a list of services, optionally filtering the results.
|
||||||
|
|
||||||
If specified, 'filters' should be a dictionary containing services
|
If specified, 'filters' should be a dictionary containing services
|
||||||
attributes and matching values. Ie, to get a list of services for
|
attributes and matching values. Ie, to get a list of services for
|
||||||
the 'compute' topic, use filters={'topic': 'compute'}.
|
the 'compute' topic, use filters={'topic': 'compute'}.
|
||||||
|
|
||||||
|
If all_cells=True, then scan all cells and merge the results.
|
||||||
"""
|
"""
|
||||||
if filters is None:
|
if filters is None:
|
||||||
filters = {}
|
filters = {}
|
||||||
disabled = filters.pop('disabled', None)
|
disabled = filters.pop('disabled', None)
|
||||||
if 'availability_zone' in filters:
|
if 'availability_zone' in filters:
|
||||||
set_zones = True
|
set_zones = True
|
||||||
services = objects.ServiceList.get_all(context, disabled,
|
|
||||||
set_zones=set_zones)
|
# NOTE(danms): Eventually this all_cells nonsense should go away
|
||||||
|
# and we should always iterate over the cells. However, certain
|
||||||
|
# callers need the legacy behavior for now.
|
||||||
|
if all_cells:
|
||||||
|
load_cells()
|
||||||
|
services = []
|
||||||
|
for cell in CELLS:
|
||||||
|
with nova_context.target_cell(context, cell):
|
||||||
|
cell_services = objects.ServiceList.get_all(
|
||||||
|
context, disabled, set_zones=set_zones)
|
||||||
|
services.extend(cell_services)
|
||||||
|
else:
|
||||||
|
services = objects.ServiceList.get_all(context, disabled,
|
||||||
|
set_zones=set_zones)
|
||||||
ret_services = []
|
ret_services = []
|
||||||
for service in services:
|
for service in services:
|
||||||
for key, val in filters.items():
|
for key, val in filters.items():
|
||||||
|
@@ -546,7 +546,13 @@ class HostAPI(compute_api.HostAPI):
|
|||||||
"""Returns the result of calling "uptime" on the target host."""
|
"""Returns the result of calling "uptime" on the target host."""
|
||||||
return self.cells_rpcapi.get_host_uptime(context, host_name)
|
return self.cells_rpcapi.get_host_uptime(context, host_name)
|
||||||
|
|
||||||
def service_get_all(self, context, filters=None, set_zones=False):
|
def service_get_all(self, context, filters=None, set_zones=False,
|
||||||
|
all_cells=False):
|
||||||
|
"""Get all services.
|
||||||
|
|
||||||
|
Note that this is the cellsv1 variant, which means we ignore the
|
||||||
|
"all_cells" parameter.
|
||||||
|
"""
|
||||||
if filters is None:
|
if filters is None:
|
||||||
filters = {}
|
filters = {}
|
||||||
if 'availability_zone' in filters:
|
if 'availability_zone' in filters:
|
||||||
|
@@ -173,6 +173,17 @@ class ComputeHostAPITestCase(test.TestCase):
|
|||||||
|
|
||||||
_do_test()
|
_do_test()
|
||||||
|
|
||||||
|
def test_service_get_all_cells(self):
|
||||||
|
cells = objects.CellMappingList.get_all(self.ctxt)
|
||||||
|
for cell in cells:
|
||||||
|
with context.target_cell(self.ctxt, cell):
|
||||||
|
objects.Service(context=self.ctxt,
|
||||||
|
binary='nova-compute',
|
||||||
|
host='host-%s' % cell.uuid).create()
|
||||||
|
services = self.host_api.service_get_all(self.ctxt, all_cells=True)
|
||||||
|
self.assertEqual(sorted(['host-%s' % cell.uuid for cell in cells]),
|
||||||
|
sorted([svc.host for svc in services]))
|
||||||
|
|
||||||
def test_service_get_all_no_zones(self):
|
def test_service_get_all_no_zones(self):
|
||||||
services = [dict(test_service.fake_service,
|
services = [dict(test_service.fake_service,
|
||||||
id=1, topic='compute', host='host1'),
|
id=1, topic='compute', host='host1'),
|
||||||
@@ -338,6 +349,10 @@ class ComputeHostAPICellsTestCase(ComputeHostAPITestCase):
|
|||||||
self.flags(cell_type='api', group='cells')
|
self.flags(cell_type='api', group='cells')
|
||||||
super(ComputeHostAPICellsTestCase, self).setUp()
|
super(ComputeHostAPICellsTestCase, self).setUp()
|
||||||
|
|
||||||
|
@testtools.skip('cellsv1 does not use this')
|
||||||
|
def test_service_get_all_cells(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_service_get_all_no_zones(self):
|
def test_service_get_all_no_zones(self):
|
||||||
services = [
|
services = [
|
||||||
cells_utils.ServiceProxy(
|
cells_utils.ServiceProxy(
|
||||||
|
Reference in New Issue
Block a user