Ignore property errors in implicit dependencies
Implicit dependencies are calculated before resources are validated. Therefore, any error getting a property that occurs during processing on implicit dependencies will be raised without any of the context of which resource is in error. By ignoring such property errors in implicit dependency calculations, we can defer the error handling until the actual resource validation and thus give the user an error message they can actually use. Change-Id: If7e0e8fd46b1b06a29cdd89743635ed32a9392e7 Closes-Bug: #1708209
This commit is contained in:
parent
a322a299c6
commit
b50df6b1fc
|
@ -101,12 +101,20 @@ class VPCGatewayAttachment(resource.Resource):
|
||||||
|
|
||||||
default_client_name = 'neutron'
|
default_client_name = 'neutron'
|
||||||
|
|
||||||
def _vpc_route_tables(self):
|
def _vpc_route_tables(self, ignore_errors=False):
|
||||||
for res in six.itervalues(self.stack):
|
for res in six.itervalues(self.stack):
|
||||||
if (res.has_interface('AWS::EC2::RouteTable') and
|
if res.has_interface('AWS::EC2::RouteTable'):
|
||||||
res.properties.get(route_table.RouteTable.VPC_ID) ==
|
try:
|
||||||
self.properties.get(self.VPC_ID)):
|
vpc_id = self.properties[self.VPC_ID]
|
||||||
yield res
|
rt_vpc_id = res.properties.get(
|
||||||
|
route_table.RouteTable.VPC_ID)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
if ignore_errors:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
if rt_vpc_id == vpc_id:
|
||||||
|
yield res
|
||||||
|
|
||||||
def add_dependencies(self, deps):
|
def add_dependencies(self, deps):
|
||||||
super(VPCGatewayAttachment, self).add_dependencies(deps)
|
super(VPCGatewayAttachment, self).add_dependencies(deps)
|
||||||
|
@ -114,7 +122,9 @@ class VPCGatewayAttachment(resource.Resource):
|
||||||
# VpcId as this VpcId.
|
# VpcId as this VpcId.
|
||||||
# All route tables must exist before gateway attachment
|
# All route tables must exist before gateway attachment
|
||||||
# as attachment happens to routers (not VPCs)
|
# as attachment happens to routers (not VPCs)
|
||||||
for route_tbl in self._vpc_route_tables():
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
for route_tbl in self._vpc_route_tables(ignore_errors=True):
|
||||||
deps += (self, route_tbl)
|
deps += (self, route_tbl)
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
|
|
|
@ -19,6 +19,7 @@ from heat.common.i18n import _
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
from heat.engine import properties
|
from heat.engine import properties
|
||||||
from heat.engine.resources.openstack.neutron import neutron
|
from heat.engine.resources.openstack.neutron import neutron
|
||||||
|
from heat.engine.resources.openstack.neutron import router
|
||||||
from heat.engine import support
|
from heat.engine import support
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,16 +66,29 @@ class ExtraRoute(neutron.NeutronResource):
|
||||||
# depend on any RouterInterface in this template with the same
|
# depend on any RouterInterface in this template with the same
|
||||||
# router_id as this router_id
|
# router_id as this router_id
|
||||||
if resource.has_interface('OS::Neutron::RouterInterface'):
|
if resource.has_interface('OS::Neutron::RouterInterface'):
|
||||||
router_id = self.properties[self.ROUTER_ID]
|
try:
|
||||||
dep_router_id = resource.properties['router']
|
router_id = self.properties[self.ROUTER_ID]
|
||||||
|
dep_router_id = resource.properties.get(
|
||||||
|
router.RouterInterface.ROUTER)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if dep_router_id == router_id:
|
if dep_router_id == router_id:
|
||||||
deps += (self, resource)
|
deps += (self, resource)
|
||||||
# depend on any RouterGateway in this template with the same
|
# depend on any RouterGateway in this template with the same
|
||||||
# router_id as this router_id
|
# router_id as this router_id
|
||||||
elif (resource.has_interface('OS::Neutron::RouterGateway') and
|
elif resource.has_interface('OS::Neutron::RouterGateway'):
|
||||||
resource.properties['router_id'] ==
|
try:
|
||||||
self.properties['router_id']):
|
router_id = self.properties[self.ROUTER_ID]
|
||||||
deps += (self, resource)
|
dep_router_id = resource.properties.get(
|
||||||
|
router.RouterGateway.ROUTER_ID)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
|
if dep_router_id == router_id:
|
||||||
|
deps += (self, resource)
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
router_id = self.properties.get(self.ROUTER_ID)
|
router_id = self.properties.get(self.ROUTER_ID)
|
||||||
|
|
|
@ -203,7 +203,12 @@ class FloatingIP(neutron.NeutronResource):
|
||||||
if not resource.has_interface('OS::Neutron::Port'):
|
if not resource.has_interface('OS::Neutron::Port'):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
fixed_ips = resource.properties.get(port.Port.FIXED_IPS)
|
try:
|
||||||
|
fixed_ips = resource.properties.get(port.Port.FIXED_IPS)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation, where
|
||||||
|
# we can report them in their proper context.
|
||||||
|
return False
|
||||||
if not fixed_ips:
|
if not fixed_ips:
|
||||||
# During create we have only unresolved value for
|
# During create we have only unresolved value for
|
||||||
# functions, so can not use None value for building
|
# functions, so can not use None value for building
|
||||||
|
@ -214,15 +219,24 @@ class FloatingIP(neutron.NeutronResource):
|
||||||
if subnet is None:
|
if subnet is None:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
p_net = (resource.properties.get(port.Port.NETWORK) or
|
try:
|
||||||
resource.properties.get(port.Port.NETWORK_ID))
|
p_net = (resource.properties.get(port.Port.NETWORK) or
|
||||||
|
resource.properties.get(port.Port.NETWORK_ID))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
return False
|
||||||
if p_net:
|
if p_net:
|
||||||
network = self.client().show_network(p_net)['network']
|
network = self.client().show_network(p_net)['network']
|
||||||
return subnet in network['subnets']
|
return subnet in network['subnets']
|
||||||
else:
|
else:
|
||||||
for fixed_ip in resource.properties.get(
|
try:
|
||||||
port.Port.FIXED_IPS):
|
fixed_ips = resource.properties.get(port.Port.FIXED_IPS)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
return False
|
||||||
|
for fixed_ip in fixed_ips:
|
||||||
port_subnet = (fixed_ip.get(port.Port.FIXED_IP_SUBNET) or
|
port_subnet = (fixed_ip.get(port.Port.FIXED_IP_SUBNET) or
|
||||||
fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
|
fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
|
||||||
if subnet == port_subnet:
|
if subnet == port_subnet:
|
||||||
|
@ -244,10 +258,16 @@ class FloatingIP(neutron.NeutronResource):
|
||||||
# depend on any RouterGateway in this template with the same
|
# depend on any RouterGateway in this template with the same
|
||||||
# network_id as this floating_network_id
|
# network_id as this floating_network_id
|
||||||
if resource.has_interface('OS::Neutron::RouterGateway'):
|
if resource.has_interface('OS::Neutron::RouterGateway'):
|
||||||
gateway_network = resource.properties.get(
|
try:
|
||||||
router.RouterGateway.NETWORK) or resource.properties.get(
|
gateway_network = (
|
||||||
router.RouterGateway.NETWORK_ID)
|
resource.properties.get(router.RouterGateway.NETWORK)
|
||||||
floating_network = self.properties[self.FLOATING_NETWORK]
|
or resource.properties.get(
|
||||||
|
router.RouterGateway.NETWORK_ID))
|
||||||
|
floating_network = self.properties[self.FLOATING_NETWORK]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if gateway_network == floating_network:
|
if gateway_network == floating_network:
|
||||||
deps += (self, resource)
|
deps += (self, resource)
|
||||||
|
|
||||||
|
@ -260,12 +280,17 @@ class FloatingIP(neutron.NeutronResource):
|
||||||
# this template with the same network_id as this
|
# this template with the same network_id as this
|
||||||
# floating_network_id
|
# floating_network_id
|
||||||
elif resource.has_interface('OS::Neutron::Router'):
|
elif resource.has_interface('OS::Neutron::Router'):
|
||||||
gateway = resource.properties.get(
|
try:
|
||||||
router.Router.EXTERNAL_GATEWAY)
|
gateway = resource.properties.get(
|
||||||
|
router.Router.EXTERNAL_GATEWAY)
|
||||||
|
floating_network = self.properties[self.FLOATING_NETWORK]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if gateway:
|
if gateway:
|
||||||
gateway_network = gateway.get(
|
gateway_network = gateway.get(
|
||||||
router.Router.EXTERNAL_GATEWAY_NETWORK)
|
router.Router.EXTERNAL_GATEWAY_NETWORK)
|
||||||
floating_network = self.properties[self.FLOATING_NETWORK]
|
|
||||||
if gateway_network == floating_network:
|
if gateway_network == floating_network:
|
||||||
deps += (self, resource)
|
deps += (self, resource)
|
||||||
|
|
||||||
|
|
|
@ -422,8 +422,13 @@ class Port(neutron.NeutronResource):
|
||||||
# the ports in that network.
|
# the ports in that network.
|
||||||
for res in six.itervalues(self.stack):
|
for res in six.itervalues(self.stack):
|
||||||
if res.has_interface('OS::Neutron::Subnet'):
|
if res.has_interface('OS::Neutron::Subnet'):
|
||||||
dep_network = res.properties.get(subnet.Subnet.NETWORK)
|
try:
|
||||||
network = self.properties[self.NETWORK]
|
dep_network = res.properties.get(subnet.Subnet.NETWORK)
|
||||||
|
network = self.properties[self.NETWORK]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if dep_network == network:
|
if dep_network == network:
|
||||||
deps += (self, res)
|
deps += (self, res)
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,12 @@ class Router(neutron.NeutronResource):
|
||||||
external_gw_net = external_gw.get(self.EXTERNAL_GATEWAY_NETWORK)
|
external_gw_net = external_gw.get(self.EXTERNAL_GATEWAY_NETWORK)
|
||||||
for res in six.itervalues(self.stack):
|
for res in six.itervalues(self.stack):
|
||||||
if res.has_interface('OS::Neutron::Subnet'):
|
if res.has_interface('OS::Neutron::Subnet'):
|
||||||
subnet_net = res.properties.get(subnet.Subnet.NETWORK)
|
try:
|
||||||
|
subnet_net = res.properties.get(subnet.Subnet.NETWORK)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if subnet_net == external_gw_net:
|
if subnet_net == external_gw_net:
|
||||||
deps += (self, res)
|
deps += (self, res)
|
||||||
|
|
||||||
|
@ -633,16 +638,26 @@ class RouterGateway(neutron.NeutronResource):
|
||||||
# depend on any RouterInterface in this template with the same
|
# depend on any RouterInterface in this template with the same
|
||||||
# router_id as this router_id
|
# router_id as this router_id
|
||||||
if resource.has_interface('OS::Neutron::RouterInterface'):
|
if resource.has_interface('OS::Neutron::RouterInterface'):
|
||||||
dep_router_id = resource.properties[RouterInterface.ROUTER]
|
try:
|
||||||
router_id = self.properties[self.ROUTER_ID]
|
dep_router_id = resource.properties[RouterInterface.ROUTER]
|
||||||
|
router_id = self.properties[self.ROUTER_ID]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if dep_router_id == router_id:
|
if dep_router_id == router_id:
|
||||||
deps += (self, resource)
|
deps += (self, resource)
|
||||||
# depend on any subnet in this template with the same network_id
|
# depend on any subnet in this template with the same network_id
|
||||||
# as this network_id, as the gateway implicitly creates a port
|
# as this network_id, as the gateway implicitly creates a port
|
||||||
# on that subnet
|
# on that subnet
|
||||||
if resource.has_interface('OS::Neutron::Subnet'):
|
if resource.has_interface('OS::Neutron::Subnet'):
|
||||||
dep_network = resource.properties[subnet.Subnet.NETWORK]
|
try:
|
||||||
network = self.properties[self.NETWORK]
|
dep_network = resource.properties[subnet.Subnet.NETWORK]
|
||||||
|
network = self.properties[self.NETWORK]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
if dep_network == network:
|
if dep_network == network:
|
||||||
deps += (self, resource)
|
deps += (self, resource)
|
||||||
|
|
||||||
|
|
|
@ -1157,12 +1157,22 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
|
||||||
# It is not known which subnet a server might be assigned
|
# It is not known which subnet a server might be assigned
|
||||||
# to so all subnets in a network should be created before
|
# to so all subnets in a network should be created before
|
||||||
# the servers in that network.
|
# the servers in that network.
|
||||||
nets = self.properties[self.NETWORKS]
|
try:
|
||||||
|
nets = self.properties[self.NETWORKS]
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
return
|
||||||
if not nets:
|
if not nets:
|
||||||
return
|
return
|
||||||
for res in six.itervalues(self.stack):
|
for res in six.itervalues(self.stack):
|
||||||
if res.has_interface('OS::Neutron::Subnet'):
|
if res.has_interface('OS::Neutron::Subnet'):
|
||||||
subnet_net = res.properties.get(subnet.Subnet.NETWORK)
|
try:
|
||||||
|
subnet_net = res.properties.get(subnet.Subnet.NETWORK)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
# Properties errors will be caught later in validation,
|
||||||
|
# where we can report them in their proper context.
|
||||||
|
continue
|
||||||
# Be wary of the case where we do not know a subnet's
|
# Be wary of the case where we do not know a subnet's
|
||||||
# network. If that's the case, be safe and add it as a
|
# network. If that's the case, be safe and add it as a
|
||||||
# dependency.
|
# dependency.
|
||||||
|
|
Loading…
Reference in New Issue