From a15fa17efc9d0b0a92bce9665cb3c95a4790d3eb Mon Sep 17 00:00:00 2001 From: melanie witt Date: Wed, 25 Jun 2014 04:33:40 +0000 Subject: [PATCH] object-ify availability_zones This change converts availability_zones to use the Aggregate and Service objects instead of direct database access. Related to blueprint compute-manager-objects-juno Change-Id: I2ec7373f063ed728dde2af3b7c8259f4391885bc --- nova/availability_zones.py | 40 +++++++++++++++---- .../compute/contrib/test_availability_zone.py | 16 ++++---- nova/tests/objects/test_service.py | 14 +++++-- 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/nova/availability_zones.py b/nova/availability_zones.py index 12b99409c94e..a9483192da6b 100644 --- a/nova/availability_zones.py +++ b/nova/availability_zones.py @@ -15,9 +15,11 @@ """Availability zone helper functions.""" +import collections + from oslo.config import cfg -from nova import db +from nova import objects from nova.openstack.common import memorycache # NOTE(vish): azs don't change that often, so cache them for an hour to @@ -61,11 +63,34 @@ def _make_cache_key(host): return "azcache-%s" % host.encode('utf-8') +def _build_metadata_by_host(aggregates, hosts=None): + if hosts and not isinstance(hosts, set): + hosts = set(hosts) + metadata = collections.defaultdict(set) + for aggregate in aggregates: + for host in aggregate.hosts: + if hosts and host not in hosts: + continue + metadata[host].add(aggregate.metadata.values()[0]) + return metadata + + +def _build_metadata_by_key(aggregates): + metadata = collections.defaultdict(set) + for aggregate in aggregates: + for key, value in aggregate.metadata.iteritems(): + metadata[key].add(value) + return metadata + + def set_availability_zones(context, services): # Makes sure services isn't a sqlalchemy object services = [dict(service.iteritems()) for service in services] - metadata = db.aggregate_host_get_by_metadata_key(context, - key='availability_zone') + hosts = set([service['host'] for service in services]) + aggregates = objects.AggregateList.get_by_metadata_key(context, + 'availability_zone', hosts=hosts) + metadata = _build_metadata_by_host(aggregates, hosts=hosts) + # gather all of the availability zones associated with a service host for service in services: az = CONF.internal_service_availability_zone if service['topic'] == "compute": @@ -85,8 +110,9 @@ def get_host_availability_zone(context, host, conductor_api=None): metadata = conductor_api.aggregate_metadata_get_by_host( context, host, key='availability_zone') else: - metadata = db.aggregate_metadata_get_by_host( - context, host, key='availability_zone') + aggregates = objects.AggregateList.get_by_host(context, host, + key='availability_zone') + metadata = _build_metadata_by_key(aggregates) if 'availability_zone' in metadata: az = list(metadata['availability_zone'])[0] else: @@ -114,7 +140,7 @@ def get_availability_zones(context, get_only_available=False, :param with_hosts: whether to return hosts part of the AZs :type with_hosts: bool """ - enabled_services = db.service_get_all(context, False) + enabled_services = objects.ServiceList.get_all(context, disabled=False) enabled_services = set_availability_zones(context, enabled_services) available_zones = [] @@ -130,7 +156,7 @@ def get_availability_zones(context, get_only_available=False, available_zones = list(_available_zones.items()) if not get_only_available: - disabled_services = db.service_get_all(context, True) + disabled_services = objects.ServiceList.get_all(context, disabled=True) disabled_services = set_availability_zones(context, disabled_services) not_available_zones = [] azs = available_zones if not with_hosts else dict(available_zones) diff --git a/nova/tests/api/openstack/compute/contrib/test_availability_zone.py b/nova/tests/api/openstack/compute/contrib/test_availability_zone.py index e8d3adf5be60..4d0515f4a4f7 100644 --- a/nova/tests/api/openstack/compute/contrib/test_availability_zone.py +++ b/nova/tests/api/openstack/compute/contrib/test_availability_zone.py @@ -25,18 +25,20 @@ from nova import servicegroup from nova import test from nova.tests.api.openstack import fakes from nova.tests import matchers +from nova.tests.objects import test_service def fake_service_get_all(context, disabled=None): def __fake_service(binary, availability_zone, created_at, updated_at, host, disabled): - return {'binary': binary, - 'availability_zone': availability_zone, - 'available_zones': availability_zone, - 'created_at': created_at, - 'updated_at': updated_at, - 'host': host, - 'disabled': disabled} + return dict(test_service.fake_service, + binary=binary, + availability_zone=availability_zone, + available_zones=availability_zone, + created_at=created_at, + updated_at=updated_at, + host=host, + disabled=disabled) if disabled: return [__fake_service("nova-compute", "zone-2", diff --git a/nova/tests/objects/test_service.py b/nova/tests/objects/test_service.py index 365c298dd297..4fdfe0c9625c 100644 --- a/nova/tests/objects/test_service.py +++ b/nova/tests/objects/test_service.py @@ -16,6 +16,7 @@ import mock from nova import db from nova import exception +from nova.objects import aggregate from nova.objects import service from nova.openstack.common import timeutils from nova.tests.objects import test_compute_node @@ -163,12 +164,17 @@ class _TestServiceObject(object): def test_get_all_with_az(self): self.mox.StubOutWithMock(db, 'service_get_all') - self.mox.StubOutWithMock(db, 'aggregate_host_get_by_metadata_key') + self.mox.StubOutWithMock(aggregate.AggregateList, + 'get_by_metadata_key') db.service_get_all(self.context, disabled=None).AndReturn( [dict(fake_service, topic='compute')]) - db.aggregate_host_get_by_metadata_key( - self.context, key='availability_zone').AndReturn( - {fake_service['host']: ['test-az']}) + agg = aggregate.Aggregate() + agg.name = 'foo' + agg.metadata = {'availability_zone': 'test-az'} + agg.create(self.context) + agg.hosts = [fake_service['host']] + aggregate.AggregateList.get_by_metadata_key(self.context, + 'availability_zone', hosts=set(agg.hosts)).AndReturn([agg]) self.mox.ReplayAll() services = service.ServiceList.get_all(self.context, set_zones=True) self.assertEqual(1, len(services))