Associate floating IP with router interface

This change will create a dependency from a FloatingIP to a RouterInterface in
this template which interfaces with the same subnet that this FloatingIP's
port is assigned to.

It would be preferable to add the dependency based on matching FloatingIP
floating_network_id and Router external_gateway_info network, but there is
a valid use-case for the Router being external to the template, so the
dependency is matched on the internal subnet instead, which is available
from the RouterInterface property.

Change-Id: Iedff00b382b4fcda741ca5c9b4adc23b176ec48c
Closes-Bug: #1299259
This commit is contained in:
Steve Baker 2014-09-19 12:18:12 +12:00
parent 68f78c8edb
commit 5c158edac6
2 changed files with 46 additions and 2 deletions

View File

@ -14,6 +14,7 @@
from heat.engine import attributes
from heat.engine import properties
from heat.engine.resources.neutron import neutron
from heat.engine.resources.neutron import port
from heat.engine.resources.neutron import router
from heat.engine import support
@ -93,9 +94,10 @@ class FloatingIP(neutron.NeutronResource):
def add_dependencies(self, deps):
super(FloatingIP, self).add_dependencies(deps)
# depend on any RouterGateway in this template with the same
# network_id as this floating_network_id
for resource in self.stack.itervalues():
# depend on any RouterGateway in this template with the same
# network_id as this floating_network_id
if resource.has_interface('OS::Neutron::RouterGateway'):
gateway_network = resource.properties.get(
router.RouterGateway.NETWORK) or resource.properties.get(
@ -106,6 +108,31 @@ class FloatingIP(neutron.NeutronResource):
if gateway_network == floating_network:
deps += (self, resource)
# depend on any RouterInterface in this template which interfaces
# with the same subnet that this floating IP's port is assigned
# to
elif resource.has_interface('OS::Neutron::RouterInterface'):
def port_on_subnet(resource, subnet):
if not resource.has_interface('OS::Neutron::Port'):
return False
for fixed_ip in resource.properties.get(
port.Port.FIXED_IPS):
port_subnet = (
fixed_ip.properties.get(port.Port.FIXED_IP_SUBNET)
or fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
return subnet == port_subnet
return False
interface_subnet = (
resource.properties.get(router.RouterInterface.SUBNET) or
resource.properties.get(router.RouterInterface.SUBNET_ID))
for d in deps.required_by(self):
if port_on_subnet(d, interface_subnet):
deps += (self, resource)
break
def validate(self):
super(FloatingIP, self).validate()
self._validate_depr_property_required(

View File

@ -269,6 +269,13 @@ neutron_floating_template_deprecated = '''
"router": {
"Type": "OS::Neutron::Router"
},
"router_interface": {
"Type": "OS::Neutron::RouterInterface",
"Properties": {
"router_id": { "Ref" : "router" },
"subnet": "sub1234"
}
},
"gateway": {
"Type": "OS::Neutron::RouterGateway",
"Properties": {
@ -312,6 +319,13 @@ neutron_floating_template = '''
"router": {
"Type": "OS::Neutron::Router"
},
"router_interface": {
"Type": "OS::Neutron::RouterInterface",
"Properties": {
"router_id": { "Ref" : "router" },
"subnet": "sub1234"
}
},
"gateway": {
"Type": "OS::Neutron::RouterGateway",
"Properties": {
@ -1927,6 +1941,9 @@ class NeutronFloatingIPTest(HeatTestCase):
self.assertIn(stack['floating_ip'], deps)
deps = stack.dependencies[stack['router_interface']]
self.assertIn(stack['floating_ip'], deps)
fip = stack['floating_ip']
scheduler.TaskRunner(fip.create)()
self.assertEqual((fip.CREATE, fip.COMPLETE), fip.state)