diff -Nru heat-5.0.1/debian/changelog heat-5.0.1/debian/changelog --- heat-5.0.1/debian/changelog 2016-04-20 08:40:31.000000000 -0300 +++ heat-5.0.1/debian/changelog 2016-05-09 17:16:54.000000000 -0300 @@ -1,3 +1,10 @@ +heat (1:5.0.1-0ubuntu3) wily; urgency=medium + + * Fix nested stacks validation (LP: #1579891) + - d/p/Fix-Translate-properties-before-update.patch + + -- Felipe Reyes Mon, 09 May 2016 11:39:35 -0300 + heat (1:5.0.1-0ubuntu2) wily; urgency=medium * Enable Ceilometer client to work with Keystone API v3 (LP: #1525800): diff -Nru heat-5.0.1/debian/patches/Fix-Translate-properties-before-update.patch heat-5.0.1/debian/patches/Fix-Translate-properties-before-update.patch --- heat-5.0.1/debian/patches/Fix-Translate-properties-before-update.patch 1969-12-31 21:00:00.000000000 -0300 +++ heat-5.0.1/debian/patches/Fix-Translate-properties-before-update.patch 2016-05-09 11:39:31.000000000 -0300 @@ -0,0 +1,711 @@ +From 6c913f05f1f2bf270d3c35e3431318885971ffc4 Mon Sep 17 00:00:00 2001 +From: Thomas Herve +Date: Thu, 14 Apr 2016 09:06:39 +0000 +Subject: [PATCH] Fix Translate properties before update + +This fixes the backport done at 4d4936691b00378eb8326ce2ff72af2f121ac5aa +to contain all the changes in the original patch. + +Change-Id: Id4b752cf4b431c05c330b3e95629fd488c52063f +Closes-Bug: #1518676 +--- + .../resources/openstack/neutron/floatingip.py | 3 +- + .../resources/openstack/neutron/loadbalancer.py | 3 +- + .../resources/openstack/neutron/network_gateway.py | 3 +- + heat/engine/resources/openstack/neutron/neutron.py | 17 ----- + heat/engine/resources/openstack/neutron/port.py | 6 +- + heat/engine/resources/openstack/neutron/router.py | 61 +++++++++-------- + heat/engine/resources/openstack/neutron/subnet.py | 3 +- + .../resources/openstack/neutron/vpnservice.py | 15 +++-- + heat/tests/neutron/test_neutron.py | 27 -------- + heat/tests/neutron/test_neutron_network_gateway.py | 70 ++++++++++---------- + heat/tests/neutron/test_neutron_router.py | 76 +++++++--------------- + heat/tests/neutron/test_neutron_vpnservice.py | 8 ++- + heat/tests/nova/test_server.py | 41 ------------ + 13 files changed, 102 insertions(+), 231 deletions(-) + +--- a/heat/engine/resources/openstack/neutron/floatingip.py ++++ b/heat/engine/resources/openstack/neutron/floatingip.py +@@ -60,6 +60,7 @@ + properties.Schema.STRING, + _('Network to allocate floating IP from.'), + support_status=support.SupportStatus(version='2014.2'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.network') + ], +@@ -203,8 +204,6 @@ + + def validate(self): + super(FloatingIP, self).validate() +- self._validate_depr_property_required( +- self.properties, self.FLOATING_NETWORK, self.FLOATING_NETWORK_ID) + # fixed_ip_address cannot be specified without a port_id + if self.properties[self.PORT_ID] is None and self.properties[ + self.FIXED_IP_ADDRESS] is not None: +--- a/heat/engine/resources/openstack/neutron/loadbalancer.py ++++ b/heat/engine/resources/openstack/neutron/loadbalancer.py +@@ -238,6 +238,7 @@ + _('The subnet for the port on which the members ' + 'of the pool will be connected.'), + support_status=support.SupportStatus(version='2014.2'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.subnet') + ] +@@ -402,8 +403,6 @@ + res = super(Pool, self).validate() + if res: + return res +- self._validate_depr_property_required( +- self.properties, self.SUBNET, self.SUBNET_ID) + session_p = self.properties[self.VIP].get(self.VIP_SESSION_PERSISTENCE) + if session_p is None: + # session persistence is not configured, skip validation +--- a/heat/engine/resources/openstack/neutron/network_gateway.py ++++ b/heat/engine/resources/openstack/neutron/network_gateway.py +@@ -115,6 +115,7 @@ + 'The internal network to connect on ' + 'the network gateway.'), + support_status=support.SupportStatus(version='2014.2'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.network') + ], +@@ -170,8 +171,6 @@ + connections = self.properties[self.CONNECTIONS] + + for connection in connections: +- self._validate_depr_property_required( +- connection, self.NETWORK, self.NETWORK_ID) + segmentation_type = connection[self.SEGMENTATION_TYPE] + segmentation_id = connection.get(self.SEGMENTATION_ID) + +--- a/heat/engine/resources/openstack/neutron/neutron.py ++++ b/heat/engine/resources/openstack/neutron/neutron.py +@@ -17,7 +17,6 @@ + + from heat.common import exception + from heat.common.i18n import _ +-from heat.engine import properties as properties_module + from heat.engine import resource + + +@@ -56,22 +55,6 @@ + return '%s not allowed in value_specs' % k + + @staticmethod +- def _validate_depr_property_required(properties, prop_key, depr_prop_key): +- if isinstance(properties, properties_module.Properties): +- prop_value = properties.data.get(prop_key) +- depr_prop_value = properties.data.get(depr_prop_key) +- else: +- prop_value = properties.get(prop_key) +- depr_prop_value = properties.get(depr_prop_key) +- +- if prop_value and depr_prop_value: +- raise exception.ResourcePropertyConflict(prop_key, +- depr_prop_key) +- if not prop_value and not depr_prop_value: +- raise exception.PropertyUnspecifiedError(prop_key, +- depr_prop_key) +- +- @staticmethod + def prepare_properties(properties, name): + ''' + Prepares the property values so that they can be passed directly to +--- a/heat/engine/resources/openstack/neutron/port.py ++++ b/heat/engine/resources/openstack/neutron/port.py +@@ -94,6 +94,7 @@ + 'update, the port will be replaced') % + {'fixed_ips': FIXED_IPS, 'subnet': FIXED_IP_SUBNET}, + support_status=support.SupportStatus(version='2014.2'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.network') + ], +@@ -322,11 +323,6 @@ + ) + ] + +- def validate(self): +- super(Port, self).validate() +- self._validate_depr_property_required(self.properties, +- self.NETWORK, self.NETWORK_ID) +- + def add_dependencies(self, deps): + super(Port, self).add_dependencies(deps) + # Depend on any Subnet in this template with the same +--- a/heat/engine/resources/openstack/neutron/router.py ++++ b/heat/engine/resources/openstack/neutron/router.py +@@ -178,9 +178,7 @@ + external_gw_net = external_gw.get(self.EXTERNAL_GATEWAY_NETWORK) + for res in six.itervalues(self.stack): + if res.has_interface('OS::Neutron::Subnet'): +- subnet_net = res.properties.get( +- subnet.Subnet.NETWORK) or res.properties.get( +- subnet.Subnet.NETWORK_ID) ++ subnet_net = res.properties.get(subnet.Subnet.NETWORK) + if subnet_net == external_gw_net: + deps += (self, res) + +@@ -269,6 +267,7 @@ + ROUTER: properties.Schema( + properties.Schema.STRING, + _('The router.'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.router') + ], +@@ -337,35 +336,30 @@ + properties.TranslationRule( + props, + properties.TranslationRule.REPLACE, ++ [self.PORT], ++ value_path=[self.PORT_ID] ++ ), ++ properties.TranslationRule( ++ props, ++ properties.TranslationRule.REPLACE, ++ [self.ROUTER], ++ value_path=[self.ROUTER_ID] ++ ), ++ properties.TranslationRule( ++ props, ++ properties.TranslationRule.REPLACE, + [self.SUBNET], + value_path=[self.SUBNET_ID] + ) + ] + +- @staticmethod +- def _validate_deprecated_keys(props, key, deprecated_key): +- value = props.get(key) +- deprecated_value = props.get(deprecated_key) +- if value and deprecated_value: +- raise exception.ResourcePropertyConflict(key, +- deprecated_key) +- if value is None and deprecated_value is None: +- return False +- return True +- + def validate(self): + """Validate any of the provided params.""" + super(RouterInterface, self).validate() + +- prop_subnet_exists = self._validate_deprecated_keys( +- self.properties, self.SUBNET, self.SUBNET_ID) +- if not self._validate_deprecated_keys( +- self.properties, self.ROUTER, self.ROUTER_ID): +- raise exception.PropertyUnspecifiedError(self.ROUTER, +- self.ROUTER_ID) ++ prop_subnet_exists = self.properties.get(self.SUBNET) is not None + +- prop_port_exists = self._validate_deprecated_keys( +- self.properties, self.PORT, self.PORT_ID) ++ prop_port_exists = self.properties.get(self.PORT) is not None + + if prop_subnet_exists and prop_port_exists: + raise exception.ResourcePropertyConflict(self.SUBNET, +@@ -377,7 +371,7 @@ + + def handle_create(self): + router_id = self.client_plugin().resolve_router( +- dict(self.properties), self.ROUTER, self.ROUTER_ID) ++ dict(self.properties), self.ROUTER, 'router_id') + key = 'subnet_id' + value = self.client_plugin().resolve_subnet( + dict(self.properties), self.SUBNET, key) +@@ -453,10 +447,15 @@ + + } + +- def validate(self): +- super(RouterGateway, self).validate() +- self._validate_depr_property_required( +- self.properties, self.NETWORK, self.NETWORK_ID) ++ def translation_rules(self, props): ++ return [ ++ properties.TranslationRule( ++ props, ++ properties.TranslationRule.REPLACE, ++ [self.NETWORK], ++ value_path=[self.NETWORK_ID] ++ ) ++ ] + + def add_dependencies(self, deps): + super(RouterGateway, self).add_dependencies(deps) +@@ -465,7 +464,7 @@ + # router_id as this router_id + if resource.has_interface('OS::Neutron::RouterInterface'): + dep_router_id = resource.properties.get( +- RouterInterface.ROUTER_ID) ++ RouterInterface.ROUTER) + router_id = self.properties[self.ROUTER_ID] + if dep_router_id == router_id: + deps += (self, resource) +@@ -474,10 +473,8 @@ + # on that subnet + if resource.has_interface('OS::Neutron::Subnet'): + dep_network = resource.properties.get( +- subnet.Subnet.NETWORK) or resource.properties.get( +- subnet.Subnet.NETWORK_ID) +- network = self.properties[ +- self.NETWORK] or self.properties[self.NETWORK_ID] ++ subnet.Subnet.NETWORK) ++ network = self.properties[self.NETWORK] + if dep_network == network: + deps += (self, resource) + +--- a/heat/engine/resources/openstack/neutron/subnet.py ++++ b/heat/engine/resources/openstack/neutron/subnet.py +@@ -81,6 +81,7 @@ + NETWORK: properties.Schema( + properties.Schema.STRING, + _('The ID of the attached network.'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.network') + ], +@@ -268,8 +269,6 @@ + + def validate(self): + super(Subnet, self).validate() +- self._validate_depr_property_required(self.properties, +- self.NETWORK, self.NETWORK_ID) + ra_mode = self.properties[self.IPV6_RA_MODE] + address_mode = self.properties[self.IPV6_ADDRESS_MODE] + if (self.properties[self.IP_VERSION] == 4) and ( +--- a/heat/engine/resources/openstack/neutron/vpnservice.py ++++ b/heat/engine/resources/openstack/neutron/vpnservice.py +@@ -76,6 +76,7 @@ + properties.Schema.STRING, + _('Subnet in which the vpn service will be created.'), + support_status=support.SupportStatus(version='2014.2'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.subnet') + ] +@@ -97,6 +98,7 @@ + properties.Schema.STRING, + _('The router to which the vpn service will be inserted.'), + support_status=support.SupportStatus(version='2015.1'), ++ required=True, + constraints=[ + constraints.CustomConstraint('neutron.router') + ] +@@ -143,19 +145,18 @@ + properties.TranslationRule.REPLACE, + [self.SUBNET], + value_path=[self.SUBNET_ID] ++ ), ++ properties.TranslationRule( ++ props, ++ properties.TranslationRule.REPLACE, ++ [self.ROUTER], ++ value_path=[self.ROUTER_ID] + ) + ] + + def _show_resource(self): + return self.client().show_vpnservice(self.resource_id)['vpnservice'] + +- def validate(self): +- super(VPNService, self).validate() +- self._validate_depr_property_required( +- self.properties, self.SUBNET, self.SUBNET_ID) +- self._validate_depr_property_required( +- self.properties, self.ROUTER, self.ROUTER_ID) +- + def handle_create(self): + props = self.prepare_properties( + self.properties, +--- a/heat/tests/neutron/test_neutron.py ++++ b/heat/tests/neutron/test_neutron.py +@@ -18,11 +18,9 @@ + + from heat.common import exception + from heat.engine.clients.os import neutron +-from heat.engine.hot import functions + from heat.engine import properties + from heat.engine.resources.openstack.neutron import net + from heat.engine.resources.openstack.neutron import neutron as nr +-from heat.engine.resources.openstack.neutron import subnet + from heat.engine import rsrc_defn + from heat.tests import common + from heat.tests import utils +@@ -50,31 +48,6 @@ + self.assertEqual(msg, nr.NeutronResource.validate_properties(p)) + vs.pop(key) + +- def test_validate_depr_properties_required_both(self): +- data = {'network_id': '1234', +- 'network': 'abc'} +- p = properties.Properties(subnet.Subnet.properties_schema, data) +- self.assertRaises(exception.ResourcePropertyConflict, +- nr.NeutronResource._validate_depr_property_required, +- p, 'network', 'network_id') +- +- def test_validate_depr_properties_required_neither(self): +- data = {} +- p = properties.Properties(subnet.Subnet.properties_schema, data) +- self.assertRaises(exception.PropertyUnspecifiedError, +- nr.NeutronResource._validate_depr_property_required, +- p, 'network', 'network_id') +- +- def test_validate_depr_properties_required_with_refs(self): +- funct = functions.GetParam(mock.Mock(), +- 'get_param', 'private_subnet_id') +- data = {'network_id': funct} +- p = properties.Properties(subnet.Subnet.properties_schema, data, +- resolver=lambda d: None) +- # no assert, as we are looking for no exception. +- nr.NeutronResource._validate_depr_property_required( +- p, 'network', 'network_id') +- + def test_prepare_properties(self): + data = {'admin_state_up': False, + 'value_specs': {'router:external': True}} +--- a/heat/tests/neutron/test_neutron_network_gateway.py ++++ b/heat/tests/neutron/test_neutron_network_gateway.py +@@ -339,15 +339,15 @@ + neutronclient.Client.disconnect_network_gateway( + u'ed4c03b9-8251-4c09-acc4-e59ee9e6aa37', { + 'network_id': u'6af055d3-26f6-48dd-a597-7611d7e58d35', +- 'segmentation_id': 10, +- 'segmentation_type': u'vlan' ++ 'segmentation_id': 0, ++ 'segmentation_type': u'flat' + } + ).AndRaise(qe.NeutronClientException(status_code=404)) + + neutronclient.Client.connect_network_gateway( + u'ed4c03b9-8251-4c09-acc4-e59ee9e6aa37', { + 'network_id': u'6af055d3-26f6-48dd-a597-7611d7e58d35', +- 'segmentation_id': 0, ++ 'segmentation_id': 1, + 'segmentation_type': u'flat' + } + ).AndReturn({ +@@ -361,8 +361,8 @@ + neutronclient.Client.disconnect_network_gateway( + u'ed4c03b9-8251-4c09-acc4-e59ee9e6aa37', { + 'network_id': u'6af055d3-26f6-48dd-a597-7611d7e58d35', +- 'segmentation_id': 10, +- 'segmentation_type': u'vlan' ++ 'segmentation_id': 1, ++ 'segmentation_type': u'flat' + } + ).AndReturn(None) + +@@ -372,7 +372,7 @@ + + neutronclient.Client.create_network_gateway({ + 'network_gateway': { +- 'name': u'NetworkGateway', ++ 'name': u'NetworkGatewayUpdate', + 'devices': [{'id': u'e52148ca-7db9-4ec3-abe6-2c7c0ff316eb', + 'interface_name': u'breth2'}] + } +@@ -393,8 +393,8 @@ + neutronclient.Client.connect_network_gateway( + u'ed4c03b9-8251-4c09-acc4-e59ee9e6aa37', { + 'network_id': u'6af055d3-26f6-48dd-a597-7611d7e58d35', +- 'segmentation_id': 10, +- 'segmentation_type': u'vlan' ++ 'segmentation_id': 1, ++ 'segmentation_type': u'flat' + } + ).AndReturn({ + 'connection_info': { +@@ -411,7 +411,7 @@ + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + + # update name +- snippet_for_update = rsrc_defn.ResourceDefinition( ++ snippet_for_update1 = rsrc_defn.ResourceDefinition( + rsrc.name, + rsrc.type(), + { +@@ -424,17 +424,14 @@ + 'segmentation_type': 'vlan', + 'segmentation_id': 10}] + }) +- prop_diff = {'name': u'NetworkGatewayUpdate'} +- self.assertIsNone(rsrc.handle_update(snippet_for_update, +- mox.IgnoreArg(), +- prop_diff)) ++ scheduler.TaskRunner(rsrc.update, snippet_for_update1)() + + # update connections +- snippet_for_update = rsrc_defn.ResourceDefinition( ++ snippet_for_update2 = rsrc_defn.ResourceDefinition( + rsrc.name, + rsrc.type(), + { +- 'name': u'NetworkGateway', ++ 'name': u'NetworkGatewayUpdate', + 'devices': [{ + 'id': u'e52148ca-7db9-4ec3-abe6-2c7c0ff316eb', + 'interface_name': u'breth1'}], +@@ -443,27 +440,32 @@ + 'segmentation_type': u'flat', + 'segmentation_id': 0}] + }) +- prop_diff = { +- 'connections': [{ +- 'network': u'6af055d3-26f6-48dd-a597-7611d7e58d35', +- 'segmentation_type': u'flat', +- 'segmentation_id': 0}] +- } +- self.assertIsNone(rsrc.handle_update(snippet_for_update, +- mox.IgnoreArg(), +- prop_diff)) ++ scheduler.TaskRunner(rsrc.update, snippet_for_update2, ++ snippet_for_update1)() + + # update connections once more +- self.assertIsNone(rsrc.handle_update(snippet_for_update, +- mox.IgnoreArg(), +- prop_diff)) ++ snippet_for_update3 = rsrc_defn.ResourceDefinition( ++ rsrc.name, ++ rsrc.type(), ++ { ++ 'name': u'NetworkGatewayUpdate', ++ 'devices': [{ ++ 'id': u'e52148ca-7db9-4ec3-abe6-2c7c0ff316eb', ++ 'interface_name': u'breth1'}], ++ 'connections': [{ ++ 'network': u'6af055d3-26f6-48dd-a597-7611d7e58d35', ++ 'segmentation_type': u'flat', ++ 'segmentation_id': 1}] ++ }) ++ scheduler.TaskRunner(rsrc.update, snippet_for_update3, ++ snippet_for_update2)() + + # update devices +- snippet_for_update = rsrc_defn.ResourceDefinition( ++ snippet_for_update4 = rsrc_defn.ResourceDefinition( + rsrc.name, + rsrc.type(), + { +- 'name': u'NetworkGateway', ++ 'name': u'NetworkGatewayUpdate', + 'devices': [{ + 'id': u'e52148ca-7db9-4ec3-abe6-2c7c0ff316eb', + 'interface_name': u'breth2'}], +@@ -472,14 +474,8 @@ + 'segmentation_type': u'vlan', + 'segmentation_id': 10}] + }) +- prop_diff = { +- 'devices': [{ +- 'id': u'e52148ca-7db9-4ec3-abe6-2c7c0ff316eb', +- 'interface_name': u'breth2'}] +- } +- self.assertIsNone(rsrc.handle_update(snippet_for_update, +- mox.IgnoreArg(), +- prop_diff)) ++ scheduler.TaskRunner(rsrc.update, snippet_for_update4, ++ snippet_for_update3)() + + self.m.VerifyAll() + +--- a/heat/tests/neutron/test_neutron_router.py ++++ b/heat/tests/neutron/test_neutron_router.py +@@ -21,7 +21,6 @@ + + from heat.common import exception + from heat.common import template_format +-from heat.engine import properties + from heat.engine.resources.openstack.neutron import router + from heat.engine import rsrc_defn + from heat.engine import scheduler +@@ -438,12 +437,6 @@ + self.assertIn(stack['floating_ip'], required_by) + + def test_router_interface(self): +- self._test_router_interface() +- +- def test_router_interface_depr_router(self): +- self._test_router_interface(resolve_router=False) +- +- def _test_router_interface(self, resolve_router=True): + neutronclient.Client.add_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} +@@ -461,13 +454,12 @@ + router_key = 'router_id' + self.stub_SubnetConstraint_validate() + self.stub_RouterConstraint_validate() +- if resolve_router: +- neutronV20.find_resourceid_by_name_or_id( +- mox.IsA(neutronclient.Client), +- 'router', +- '3e46229d-8fce-4733-819a-b5fe630550f8' +- ).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8') +- router_key = 'router' ++ neutronV20.find_resourceid_by_name_or_id( ++ mox.IsA(neutronclient.Client), ++ 'router', ++ '3e46229d-8fce-4733-819a-b5fe630550f8' ++ ).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8') ++ router_key = 'router' + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'subnet', +@@ -491,6 +483,11 @@ + self.stub_RouterConstraint_validate() + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), ++ 'router', ++ '3e46229d-8fce-4733-819a-b5fe630550f8', ++ ).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8') ++ neutronV20.find_resourceid_by_name_or_id( ++ mox.IsA(neutronclient.Client), + 'subnet', + '91e47a57-7508-46fe-afc9-fc454e8580e1' + ).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1') +@@ -530,24 +527,22 @@ + self.m.VerifyAll() + + def test_router_interface_with_port(self): +- self._test_router_interface_with_port() +- +- def test_router_interface_with_deprecated_port(self): +- self._test_router_interface_with_port(resolve_port=False) +- +- def _test_router_interface_with_port(self, resolve_port=True): + port_key = 'port_id' + neutronclient.Client.add_interface_router( + 'ae478782-53c0-4434-ab16-49900c88016c', + {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + ).AndReturn(None) +- if resolve_port: +- port_key = 'port' +- neutronV20.find_resourceid_by_name_or_id( +- mox.IsA(neutronclient.Client), +- 'port', +- '9577cafd-8e98-4059-a2e6-8a771b4d318e' +- ).AndReturn('9577cafd-8e98-4059-a2e6-8a771b4d318e') ++ neutronV20.find_resourceid_by_name_or_id( ++ mox.IsA(neutronclient.Client), ++ 'router', ++ 'ae478782-53c0-4434-ab16-49900c88016c' ++ ).AndReturn('ae478782-53c0-4434-ab16-49900c88016c') ++ port_key = 'port' ++ neutronV20.find_resourceid_by_name_or_id( ++ mox.IsA(neutronclient.Client), ++ 'port', ++ '9577cafd-8e98-4059-a2e6-8a771b4d318e' ++ ).AndReturn('9577cafd-8e98-4059-a2e6-8a771b4d318e') + + neutronclient.Client.remove_interface_router( + 'ae478782-53c0-4434-ab16-49900c88016c', +@@ -861,30 +856,3 @@ + rsrc = self.create_router(t, stack, 'router') + self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) + self.m.VerifyAll() +- +- def test_validate_depr_keys_required_both(self): +- data = {'router_id': '1234', +- 'router': 'abc'} +- p = properties.Properties(router.RouterInterface.properties_schema, +- data) +- self.assertRaises( +- exception.ResourcePropertyConflict, +- router.RouterInterface._validate_deprecated_keys, +- p, 'router', 'router_id') +- +- def test_validate_depr_keys_required_neither(self): +- data = {} +- p = properties.Properties(router.RouterInterface.properties_schema, +- data) +- +- res = router.RouterInterface._validate_deprecated_keys( +- p, 'router', 'router_id') +- self.assertFalse(res) +- +- def test_validate_depr_keys_required_one(self): +- data = {'router_id': ''} +- p = properties.Properties(router.RouterInterface.properties_schema, +- data) +- res = router.RouterInterface._validate_deprecated_keys( +- p, 'router', 'router_id') +- self.assertTrue(res) +--- a/heat/tests/neutron/test_neutron_vpnservice.py ++++ b/heat/tests/neutron/test_neutron_vpnservice.py +@@ -164,9 +164,6 @@ + def test_create(self): + self._test_create() + +- def test_create_router_id(self): +- self._test_create(resolve_router=False) +- + def _test_create(self, resolve_neutron=True, resolve_router=True): + rsrc = self.create_vpnservice(resolve_neutron, resolve_router) + self.m.ReplayAll() +@@ -177,6 +174,11 @@ + def test_create_failed(self): + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), ++ 'router', ++ 'rou123' ++ ).MultipleTimes().AndReturn('rou123') ++ neutronV20.find_resourceid_by_name_or_id( ++ mox.IsA(neutronclient.Client), + 'subnet', + 'sub123' + ).MultipleTimes().AndReturn('sub123') +--- a/heat/tests/nova/test_server.py ++++ b/heat/tests/nova/test_server.py +@@ -3538,47 +3538,6 @@ + self.assertEqual((server.UPDATE, server.COMPLETE), server.state) + self.m.VerifyAll() + +- def test_server_update_networks_with_uuid(self): +- return_server = self.fc.servers.list()[1] +- return_server.id = '5678' +- +- self.patchobject(neutronclient.Client, 'create_port', +- return_value={'port': {'id': 'abcd1234'}}) +- +- server = self._create_test_server(return_server, 'networks_update') +- +- old_networks = [ +- {'network': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}] +- new_networks = [ +- {'uuid': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}] +- +- server.t['Properties']['networks'] = old_networks +- update_template = copy.deepcopy(server.t) +- update_template['Properties']['networks'] = new_networks +- +- self._stub_glance_for_update() +- self.m.StubOutWithMock(self.fc.servers, 'get') +- self.fc.servers.get('5678').MultipleTimes().AndReturn(return_server) +- +- self.m.StubOutWithMock(return_server, 'interface_list') +- +- poor_interfaces = [ +- self.create_fake_iface('95e25541-d26a-478d-8f36-ae1c8f6b74dc', +- 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', +- '11.12.13.14') +- ] +- +- return_server.interface_list().AndReturn(poor_interfaces) +- +- self.stub_NetworkConstraint_validate() +- self.patchobject(neutron.NeutronClientPlugin, 'resolve_network', +- return_value='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa') +- self.m.ReplayAll() +- +- scheduler.TaskRunner(server.update, update_template)() +- self.assertEqual((server.UPDATE, server.COMPLETE), server.state) +- self.m.VerifyAll() +- + def test_server_update_networks_with_empty_list(self): + return_server = self.fc.servers.list()[1] + return_server.id = '5678' diff -Nru heat-5.0.1/debian/patches/series heat-5.0.1/debian/patches/series --- heat-5.0.1/debian/patches/series 2016-04-20 08:40:31.000000000 -0300 +++ heat-5.0.1/debian/patches/series 2016-05-09 11:39:22.000000000 -0300 @@ -5,3 +5,4 @@ #default-log-dir.patch fixup-assert-regex.patch enable-ceilometer-client-to-work-with-keystone-api-v3.patch +Fix-Translate-properties-before-update.patch