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'
|
||||
|
||||
def _vpc_route_tables(self):
|
||||
def _vpc_route_tables(self, ignore_errors=False):
|
||||
for res in six.itervalues(self.stack):
|
||||
if (res.has_interface('AWS::EC2::RouteTable') and
|
||||
res.properties.get(route_table.RouteTable.VPC_ID) ==
|
||||
self.properties.get(self.VPC_ID)):
|
||||
yield res
|
||||
if res.has_interface('AWS::EC2::RouteTable'):
|
||||
try:
|
||||
vpc_id = self.properties[self.VPC_ID]
|
||||
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):
|
||||
super(VPCGatewayAttachment, self).add_dependencies(deps)
|
||||
|
@ -114,7 +122,9 @@ class VPCGatewayAttachment(resource.Resource):
|
|||
# VpcId as this VpcId.
|
||||
# All route tables must exist before gateway attachment
|
||||
# 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)
|
||||
|
||||
def handle_create(self):
|
||||
|
|
|
@ -19,6 +19,7 @@ from heat.common.i18n import _
|
|||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine.resources.openstack.neutron import neutron
|
||||
from heat.engine.resources.openstack.neutron import router
|
||||
from heat.engine import support
|
||||
|
||||
|
||||
|
@ -65,16 +66,29 @@ class ExtraRoute(neutron.NeutronResource):
|
|||
# depend on any RouterInterface in this template with the same
|
||||
# router_id as this router_id
|
||||
if resource.has_interface('OS::Neutron::RouterInterface'):
|
||||
router_id = self.properties[self.ROUTER_ID]
|
||||
dep_router_id = resource.properties['router']
|
||||
try:
|
||||
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:
|
||||
deps += (self, resource)
|
||||
# depend on any RouterGateway in this template with the same
|
||||
# router_id as this router_id
|
||||
elif (resource.has_interface('OS::Neutron::RouterGateway') and
|
||||
resource.properties['router_id'] ==
|
||||
self.properties['router_id']):
|
||||
deps += (self, resource)
|
||||
elif resource.has_interface('OS::Neutron::RouterGateway'):
|
||||
try:
|
||||
router_id = self.properties[self.ROUTER_ID]
|
||||
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):
|
||||
router_id = self.properties.get(self.ROUTER_ID)
|
||||
|
|
|
@ -203,7 +203,12 @@ class FloatingIP(neutron.NeutronResource):
|
|||
if not resource.has_interface('OS::Neutron::Port'):
|
||||
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:
|
||||
# During create we have only unresolved value for
|
||||
# functions, so can not use None value for building
|
||||
|
@ -214,15 +219,24 @@ class FloatingIP(neutron.NeutronResource):
|
|||
if subnet is None:
|
||||
return True
|
||||
|
||||
p_net = (resource.properties.get(port.Port.NETWORK) or
|
||||
resource.properties.get(port.Port.NETWORK_ID))
|
||||
try:
|
||||
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:
|
||||
network = self.client().show_network(p_net)['network']
|
||||
return subnet in network['subnets']
|
||||
else:
|
||||
for fixed_ip in 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
|
||||
for fixed_ip in fixed_ips:
|
||||
port_subnet = (fixed_ip.get(port.Port.FIXED_IP_SUBNET) or
|
||||
fixed_ip.get(port.Port.FIXED_IP_SUBNET_ID))
|
||||
if subnet == port_subnet:
|
||||
|
@ -244,10 +258,16 @@ class FloatingIP(neutron.NeutronResource):
|
|||
# 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(
|
||||
router.RouterGateway.NETWORK_ID)
|
||||
floating_network = self.properties[self.FLOATING_NETWORK]
|
||||
try:
|
||||
gateway_network = (
|
||||
resource.properties.get(router.RouterGateway.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:
|
||||
deps += (self, resource)
|
||||
|
||||
|
@ -260,12 +280,17 @@ class FloatingIP(neutron.NeutronResource):
|
|||
# this template with the same network_id as this
|
||||
# floating_network_id
|
||||
elif resource.has_interface('OS::Neutron::Router'):
|
||||
gateway = resource.properties.get(
|
||||
router.Router.EXTERNAL_GATEWAY)
|
||||
try:
|
||||
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:
|
||||
gateway_network = gateway.get(
|
||||
router.Router.EXTERNAL_GATEWAY_NETWORK)
|
||||
floating_network = self.properties[self.FLOATING_NETWORK]
|
||||
if gateway_network == floating_network:
|
||||
deps += (self, resource)
|
||||
|
||||
|
|
|
@ -422,8 +422,13 @@ class Port(neutron.NeutronResource):
|
|||
# the ports in that network.
|
||||
for res in six.itervalues(self.stack):
|
||||
if res.has_interface('OS::Neutron::Subnet'):
|
||||
dep_network = res.properties.get(subnet.Subnet.NETWORK)
|
||||
network = self.properties[self.NETWORK]
|
||||
try:
|
||||
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:
|
||||
deps += (self, res)
|
||||
|
||||
|
|
|
@ -265,7 +265,12 @@ class Router(neutron.NeutronResource):
|
|||
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)
|
||||
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:
|
||||
deps += (self, res)
|
||||
|
||||
|
@ -633,16 +638,26 @@ class RouterGateway(neutron.NeutronResource):
|
|||
# depend on any RouterInterface in this template with the same
|
||||
# router_id as this router_id
|
||||
if resource.has_interface('OS::Neutron::RouterInterface'):
|
||||
dep_router_id = resource.properties[RouterInterface.ROUTER]
|
||||
router_id = self.properties[self.ROUTER_ID]
|
||||
try:
|
||||
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:
|
||||
deps += (self, resource)
|
||||
# depend on any subnet in this template with the same network_id
|
||||
# as this network_id, as the gateway implicitly creates a port
|
||||
# on that subnet
|
||||
if resource.has_interface('OS::Neutron::Subnet'):
|
||||
dep_network = resource.properties[subnet.Subnet.NETWORK]
|
||||
network = self.properties[self.NETWORK]
|
||||
try:
|
||||
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:
|
||||
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
|
||||
# to so all subnets in a network should be created before
|
||||
# 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:
|
||||
return
|
||||
for res in six.itervalues(self.stack):
|
||||
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
|
||||
# network. If that's the case, be safe and add it as a
|
||||
# dependency.
|
||||
|
|
Loading…
Reference in New Issue