From: Thomas Herve Date: Tue, 30 Apr 2013 16:44:17 +0000 (+0200) Subject: Retrieve the list of availability zones from nova in Fn::GetAZs X-Git-Tag: 2014.1~668 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=a9557085c828fdbf67fd69f5f1b4b6ef7c70c1ab;p=openstack-build%2Fheat-build.git Retrieve the list of availability zones from nova in Fn::GetAZs Fixes: bug #1096001 Change-Id: Ie5c46ae038dff4f53ba8d722e878583044bd194c --- diff --git a/heat/engine/parser.py b/heat/engine/parser.py index f5d45ce7..81c782fc 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -62,6 +62,8 @@ class Stack(object): created_time = timestamp.Timestamp(db_api.stack_get, 'created_at') updated_time = timestamp.Timestamp(db_api.stack_get, 'updated_at') + _zones = None + def __init__(self, context, stack_name, tmpl, parameters=None, stack_id=None, state=None, state_description='', timeout_mins=60, resolve_data=True, disable_rollback=True): @@ -558,14 +560,21 @@ class Stack(object): # TODO(asalkeld) if any of this fails we Should # restart the whole stack + def get_availability_zones(self): + if self._zones is None: + self._zones = [ + zone.zoneName for zone in + self.clients.nova().availability_zones.list(detailed=False)] + return self._zones + def resolve_static_data(self, snippet): - return resolve_static_data(self.t, self.parameters, snippet) + return resolve_static_data(self.t, self, self.parameters, snippet) def resolve_runtime_data(self, snippet): return resolve_runtime_data(self.t, self.resources, snippet) -def resolve_static_data(template, parameters, snippet): +def resolve_static_data(template, stack, parameters, snippet): ''' Resolve static parameters, map lookups, etc. in a template. @@ -573,13 +582,14 @@ def resolve_static_data(template, parameters, snippet): >>> template = Template(template_format.parse(template_path)) >>> parameters = Parameters('stack', template, {'KeyName': 'my_key'}) - >>> resolve_static_data(template, parameters, {'Ref': 'KeyName'}) + >>> resolve_static_data(template, None, parameters, {'Ref': 'KeyName'}) 'my_key' ''' return transform(snippet, [functools.partial(template.resolve_param_refs, parameters=parameters), - template.resolve_availability_zones, + functools.partial(template.resolve_availability_zones, + stack=stack), template.resolve_find_in_map, template.reduce_joins]) diff --git a/heat/engine/template.py b/heat/engine/template.py index 31ca9ddf..6078fed2 100644 --- a/heat/engine/template.py +++ b/heat/engine/template.py @@ -89,7 +89,7 @@ class Template(collections.Mapping): handle_find_in_map, s) @staticmethod - def resolve_availability_zones(s): + def resolve_availability_zones(s, stack): ''' looking for { "Fn::GetAZs" : "str" } ''' @@ -98,7 +98,10 @@ class Template(collections.Mapping): isinstance(value, basestring)) def handle_get_az(ref): - return ['nova'] + if stack is None: + return ['nova'] + else: + return stack.get_availability_zones() return _resolve(match_get_az, handle_get_az, s) diff --git a/heat/tests/test_autoscaling.py b/heat/tests/test_autoscaling.py index a1b937f3..8a88ede5 100644 --- a/heat/tests/test_autoscaling.py +++ b/heat/tests/test_autoscaling.py @@ -25,10 +25,12 @@ from heat.common import template_format from heat.engine.resources import autoscaling as asc from heat.engine.resources import loadbalancer from heat.engine.resources import instance +from heat.engine import clients from heat.engine import parser from heat.engine import scheduler from heat.engine.resource import Metadata from heat.openstack.common import timeutils +from heat.tests.v1_1 import fakes from heat.tests.common import HeatTestCase from heat.tests.utils import setup_dummy_db @@ -37,6 +39,9 @@ class AutoScalingTest(HeatTestCase): def setUp(self): super(AutoScalingTest, self).setUp() setup_dummy_db() + self.fc = fakes.FakeClient() + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc) def load_template(self): self.path = os.path.dirname(os.path.realpath(__file__)).\ @@ -47,6 +52,7 @@ class AutoScalingTest(HeatTestCase): return t def parse_stack(self, t): + self.m.ReplayAll() ctx = context.RequestContext.from_dict({ 'tenant': 'test_tenant', 'username': 'test_username', diff --git a/heat/tests/test_instance_group.py b/heat/tests/test_instance_group.py index 0d6764b9..c6bc46b6 100644 --- a/heat/tests/test_instance_group.py +++ b/heat/tests/test_instance_group.py @@ -25,6 +25,7 @@ from heat.common import template_format from heat.engine.resources import autoscaling as asc from heat.engine.resources import instance from heat.engine.resources import loadbalancer +from heat.engine import clients from heat.engine import parser from heat.engine import scheduler from heat.tests.common import HeatTestCase @@ -37,6 +38,8 @@ class InstanceGroupTest(HeatTestCase): self.fc = fakes.FakeClient() self.m.StubOutWithMock(loadbalancer.LoadBalancer, 'reload') setup_dummy_db() + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc) def load_template(self): self.path = os.path.dirname(os.path.realpath(__file__)).\ @@ -47,6 +50,7 @@ class InstanceGroupTest(HeatTestCase): return t def parse_stack(self, t): + self.m.ReplayAll() ctx = context.RequestContext.from_dict({ 'tenant': 'test_tenant', 'username': 'test_username', diff --git a/heat/tests/test_loadbalancer.py b/heat/tests/test_loadbalancer.py index af17b9d2..35f9782f 100644 --- a/heat/tests/test_loadbalancer.py +++ b/heat/tests/test_loadbalancer.py @@ -22,6 +22,7 @@ from heat.common import exception from heat.common import config from heat.common import context from heat.common import template_format +from heat.engine import clients from heat.engine import parser from heat.engine import scheduler from heat.engine.resources import instance @@ -50,8 +51,7 @@ class LoadBalancerTest(HeatTestCase): super(LoadBalancerTest, self).setUp() config.register_engine_opts() self.fc = fakes.FakeClient() - self.m.StubOutWithMock(lb.LoadBalancer, 'nova') - self.m.StubOutWithMock(instance.Instance, 'nova') + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') self.m.StubOutWithMock(self.fc.servers, 'create') self.m.StubOutWithMock(Metadata, '__set__') self.fkc = test_fakes.FakeKeystoneClient( @@ -96,8 +96,9 @@ class LoadBalancerTest(HeatTestCase): self.m.StubOutWithMock(wc.WaitConditionHandle, 'keystone') wc.WaitConditionHandle.keystone().MultipleTimes().AndReturn(self.fkc) - lb.LoadBalancer.nova().AndReturn(self.fc) - instance.Instance.nova().MultipleTimes().AndReturn(self.fc) + clients.OpenStackClients.nova( + "compute").MultipleTimes().AndReturn(self.fc) + clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc) self.fc.servers.create( flavor=2, image=745, key_name='test', meta=None, nics=None, name=u'test_stack.LoadBalancer.LB_instance', @@ -107,8 +108,6 @@ class LoadBalancerTest(HeatTestCase): Metadata.__set__(mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(None) - lb.LoadBalancer.nova().MultipleTimes().AndReturn(self.fc) - self.m.StubOutWithMock(wc.WaitConditionHandle, 'get_status') wc.WaitConditionHandle.get_status().AndReturn(['SUCCESS']) self.m.ReplayAll() diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index 1b1d6775..08e31685 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -18,6 +18,7 @@ import uuid from heat.common import context from heat.common import exception from heat.common import template_format +from heat.engine import clients from heat.engine import resource from heat.engine import parser from heat.engine import parameters @@ -25,6 +26,7 @@ from heat.engine import template from heat.tests.common import HeatTestCase from heat.tests.utils import setup_dummy_db +from heat.tests.v1_1 import fakes from heat.tests.utils import stack_delete_after from heat.tests import generic_resource as generic_rsrc @@ -280,6 +282,23 @@ class TemplateTest(HeatTestCase): self.assertRaises(TypeError, parser.Template.resolve_base64, dict_snippet) + def test_get_azs(self): + snippet = {"Fn::GetAZs": ""} + self.assertEqual( + parser.Template.resolve_availability_zones(snippet, None), + ["nova"]) + + def test_get_azs_with_stack(self): + snippet = {"Fn::GetAZs": ""} + stack = parser.Stack(None, 'test_stack', parser.Template({})) + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + fc = fakes.FakeClient() + clients.OpenStackClients.nova().MultipleTimes().AndReturn(fc) + self.m.ReplayAll() + self.assertEqual( + parser.Template.resolve_availability_zones(snippet, stack), + ["nova1"]) + class StackTest(HeatTestCase): def setUp(self): diff --git a/heat/tests/v1_1/fakes.py b/heat/tests/v1_1/fakes.py index 9fdf5fc9..cbccab15 100644 --- a/heat/tests/v1_1/fakes.py +++ b/heat/tests/v1_1/fakes.py @@ -821,3 +821,6 @@ class FakeHTTPClient(base_client.HTTPClient): result = {'host': 'dummy'} result.update(body) return (200, result) + + def get_os_availability_zone(self, *kw): + return (200, {"availabilityZoneInfo": [{'zoneName': 'nova1'}]})