97e72e40d0
merged from Ifb5cb05b9cc2b8758d5a8e34f7792470a73d7c40 PEP-0274 introduced dict comprehensions to replace dict constructor with a sequence of length-2 sequences, these are benefits copied from [1]: The dictionary constructor approach has two distinct disadvantages from the proposed syntax though. First, it isn't as legible as a dict comprehension. Second, it forces the programmer to create an in-core list object first, which could be expensive. Nova dropped python 2.6 support, we can leverage this now. There is deep dive about PEP-0274[2] and basic tests about performance[3]. Note: This commit doesn't handle dict constructor with kwagrs. This commit also adds a hacking rule. [1]http://legacy.python.org/dev/peps/pep-0274/ [2]http://doughellmann.com/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2.html [3]http://paste.openstack.org/show/154798/ Change-Id: I1bc53e335b6c291da5c54f067f9fdfd5da6b2902
551 lines
24 KiB
Python
551 lines
24 KiB
Python
# Copyright 2014
|
|
# The Cloudscaling Group, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import collections
|
|
import copy
|
|
|
|
import netaddr
|
|
from novaclient import exceptions as nova_exception
|
|
|
|
from ec2api.api import clients
|
|
from ec2api.api import common
|
|
from ec2api.api import ec2utils
|
|
from ec2api.db import api as db_api
|
|
from ec2api import exception
|
|
from ec2api.i18n import _
|
|
|
|
|
|
Validator = common.Validator
|
|
|
|
|
|
def create_route_table(context, vpc_id):
|
|
vpc = ec2utils.get_db_item(context, vpc_id)
|
|
route_table = _create_route_table(context, vpc)
|
|
return {'routeTable': _format_route_table(context, route_table,
|
|
is_main=False)}
|
|
|
|
|
|
def create_route(context, route_table_id, destination_cidr_block,
|
|
gateway_id=None, instance_id=None,
|
|
network_interface_id=None,
|
|
vpc_peering_connection_id=None):
|
|
return _set_route(context, route_table_id, destination_cidr_block,
|
|
gateway_id, instance_id, network_interface_id,
|
|
vpc_peering_connection_id, False)
|
|
|
|
|
|
def replace_route(context, route_table_id, destination_cidr_block,
|
|
gateway_id=None, instance_id=None,
|
|
network_interface_id=None,
|
|
vpc_peering_connection_id=None):
|
|
return _set_route(context, route_table_id, destination_cidr_block,
|
|
gateway_id, instance_id, network_interface_id,
|
|
vpc_peering_connection_id, True)
|
|
|
|
|
|
def delete_route(context, route_table_id, destination_cidr_block):
|
|
route_table = ec2utils.get_db_item(context, route_table_id)
|
|
for route_index, route in enumerate(route_table['routes']):
|
|
if route['destination_cidr_block'] != destination_cidr_block:
|
|
continue
|
|
if route.get('gateway_id', 0) is None:
|
|
msg = _('cannot remove local route %(destination_cidr_block)s '
|
|
'in route table %(route_table_id)s')
|
|
msg = msg % {'route_table_id': route_table_id,
|
|
'destination_cidr_block': destination_cidr_block}
|
|
raise exception.InvalidParameterValue(msg)
|
|
break
|
|
else:
|
|
raise exception.InvalidRouteNotFound(
|
|
route_table_id=route_table_id,
|
|
destination_cidr_block=destination_cidr_block)
|
|
rollback_route_table_state = copy.deepcopy(route_table)
|
|
del route_table['routes'][route_index]
|
|
with common.OnCrashCleaner() as cleaner:
|
|
db_api.update_item(context, route_table)
|
|
cleaner.addCleanup(db_api.update_item, context,
|
|
rollback_route_table_state)
|
|
|
|
_update_routes_in_associated_subnets(context, route_table, cleaner,
|
|
rollback_route_table_state)
|
|
|
|
return True
|
|
|
|
|
|
def associate_route_table(context, route_table_id, subnet_id):
|
|
route_table = ec2utils.get_db_item(context, route_table_id)
|
|
subnet = ec2utils.get_db_item(context, subnet_id)
|
|
if route_table['vpc_id'] != subnet['vpc_id']:
|
|
msg = _('Route table %(rtb_id)s and subnet %(subnet_id)s belong to '
|
|
'different networks')
|
|
msg = msg % {'rtb_id': route_table_id,
|
|
'subnet_id': subnet_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
if 'route_table_id' in subnet:
|
|
msg = _('The specified association for route table %(rtb_id)s '
|
|
'conflicts with an existing association')
|
|
msg = msg % {'rtb_id': route_table_id}
|
|
raise exception.ResourceAlreadyAssociated(msg)
|
|
|
|
vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
|
|
main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
|
|
with common.OnCrashCleaner() as cleaner:
|
|
_associate_subnet_item(context, subnet, route_table['id'])
|
|
cleaner.addCleanup(_disassociate_subnet_item, context, subnet)
|
|
|
|
_update_subnet_host_routes(
|
|
context, subnet, route_table,
|
|
cleaner=cleaner, rollback_route_table_object=main_route_table)
|
|
|
|
return {'associationId': ec2utils.change_ec2_id_kind(subnet['id'],
|
|
'rtbassoc')}
|
|
|
|
|
|
def replace_route_table_association(context, association_id, route_table_id):
|
|
route_table = ec2utils.get_db_item(context, route_table_id)
|
|
if route_table['vpc_id'] == ec2utils.change_ec2_id_kind(association_id,
|
|
'vpc'):
|
|
vpc = db_api.get_item_by_id(
|
|
context, ec2utils.change_ec2_id_kind(association_id, 'vpc'))
|
|
if vpc is None:
|
|
raise exception.InvalidAssociationIDNotFound(
|
|
id=association_id)
|
|
|
|
rollabck_route_table_object = db_api.get_item_by_id(
|
|
context, vpc['route_table_id'])
|
|
with common.OnCrashCleaner() as cleaner:
|
|
_associate_vpc_item(context, vpc, route_table['id'])
|
|
cleaner.addCleanup(_associate_vpc_item, context, vpc,
|
|
rollabck_route_table_object['id'])
|
|
|
|
# NOTE(ft): this can cause unnecessary update of subnets, which are
|
|
# associated with the route table
|
|
_update_routes_in_associated_subnets(
|
|
context, route_table, cleaner,
|
|
rollabck_route_table_object, is_main=True)
|
|
else:
|
|
subnet = db_api.get_item_by_id(
|
|
context, ec2utils.change_ec2_id_kind(association_id, 'subnet'))
|
|
if subnet is None or 'route_table_id' not in subnet:
|
|
raise exception.InvalidAssociationIDNotFound(
|
|
id=association_id)
|
|
if subnet['vpc_id'] != route_table['vpc_id']:
|
|
msg = _('Route table association %(rtbassoc_id)s and route table '
|
|
'%(rtb_id)s belong to different networks')
|
|
msg = msg % {'rtbassoc_id': association_id,
|
|
'rtb_id': route_table_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
|
|
rollabck_route_table_object = db_api.get_item_by_id(
|
|
context, subnet['route_table_id'])
|
|
with common.OnCrashCleaner() as cleaner:
|
|
_associate_subnet_item(context, subnet, route_table['id'])
|
|
cleaner.addCleanup(_associate_subnet_item, context, subnet,
|
|
rollabck_route_table_object['id'])
|
|
|
|
_update_subnet_host_routes(
|
|
context, subnet, route_table, cleaner=cleaner,
|
|
rollback_route_table_object=rollabck_route_table_object)
|
|
|
|
return {'newAssociationId': association_id}
|
|
|
|
|
|
def disassociate_route_table(context, association_id):
|
|
subnet = db_api.get_item_by_id(
|
|
context, ec2utils.change_ec2_id_kind(association_id, 'subnet'))
|
|
if not subnet:
|
|
vpc = db_api.get_item_by_id(
|
|
context, ec2utils.change_ec2_id_kind(association_id, 'vpc'))
|
|
if vpc is None:
|
|
raise exception.InvalidAssociationIDNotFound(
|
|
id=association_id)
|
|
msg = _('Cannot disassociate the main route table association '
|
|
'%(rtbassoc_id)s') % {'rtbassoc_id': association_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
if 'route_table_id' not in subnet:
|
|
raise exception.InvalidAssociationIDNotFound(
|
|
id=association_id)
|
|
|
|
rollback_route_table_object = db_api.get_item_by_id(
|
|
context, subnet['route_table_id'])
|
|
vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
|
|
main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
|
|
with common.OnCrashCleaner() as cleaner:
|
|
_disassociate_subnet_item(context, subnet)
|
|
cleaner.addCleanup(_associate_subnet_item, context, subnet,
|
|
rollback_route_table_object['id'])
|
|
|
|
_update_subnet_host_routes(
|
|
context, subnet, main_route_table, cleaner=cleaner,
|
|
rollback_route_table_object=rollback_route_table_object)
|
|
|
|
return True
|
|
|
|
|
|
def delete_route_table(context, route_table_id):
|
|
route_table = ec2utils.get_db_item(context, route_table_id)
|
|
vpc = db_api.get_item_by_id(context, route_table['vpc_id'])
|
|
_delete_route_table(context, route_table['id'], vpc)
|
|
return True
|
|
|
|
|
|
class RouteTableDescriber(common.TaggableItemsDescriber,
|
|
common.NonOpenstackItemsDescriber):
|
|
|
|
KIND = 'rtb'
|
|
FILTER_MAP = {'association.route-table-association-id': (
|
|
['associationSet', 'routeTableAssociationId']),
|
|
'association.route-table-id': ['associationSet',
|
|
'routeTableId'],
|
|
'association.subnet-id': ['associationSet', 'subnetId'],
|
|
'association.main': ['associationSet', 'main'],
|
|
'route-table-id': 'routeTableId',
|
|
'route.destination-cidr-block': ['routeSet',
|
|
'destinationCidrBlock'],
|
|
'route.gateway-id': ['routeSet', 'gatewayId'],
|
|
'route.instance-id': ['routeSet', 'instanceId'],
|
|
'route.origin': ['routeSet', 'origin'],
|
|
'route.state': ['routeSet', 'state'],
|
|
'vpc-id': 'vpcId'}
|
|
|
|
def format(self, route_table):
|
|
return _format_route_table(
|
|
self.context, route_table,
|
|
associated_subnet_ids=self.associations[route_table['id']],
|
|
is_main=(self.vpcs[route_table['vpc_id']]['route_table_id'] ==
|
|
route_table['id']),
|
|
gateways=self.gateways,
|
|
network_interfaces=self.network_interfaces)
|
|
|
|
def get_db_items(self):
|
|
associations = collections.defaultdict(list)
|
|
for subnet in db_api.get_items(self.context, 'subnet'):
|
|
if 'route_table_id' in subnet:
|
|
associations[subnet['route_table_id']].append(subnet['id'])
|
|
self.associations = associations
|
|
vpcs = db_api.get_items(self.context, 'vpc')
|
|
self.vpcs = {vpc['id']: vpc for vpc in vpcs}
|
|
gateways = db_api.get_items(self.context, 'igw')
|
|
self.gateways = {igw['id']: igw for igw in gateways}
|
|
# TODO(ft): scan route tables to get only used instances and
|
|
# network interfaces to reduce DB and Nova throughput
|
|
network_interfaces = db_api.get_items(self.context, 'eni')
|
|
self.network_interfaces = {eni['id']: eni
|
|
for eni in network_interfaces}
|
|
return super(RouteTableDescriber, self).get_db_items()
|
|
|
|
|
|
def describe_route_tables(context, route_table_id=None, filter=None):
|
|
formatted_route_tables = RouteTableDescriber().describe(
|
|
context, ids=route_table_id, filter=filter)
|
|
return {'routeTableSet': formatted_route_tables}
|
|
|
|
|
|
def _create_route_table(context, vpc):
|
|
route_table = {'vpc_id': vpc['id'],
|
|
'routes': [{'destination_cidr_block': vpc['cidr_block'],
|
|
'gateway_id': None}]}
|
|
route_table = db_api.add_item(context, 'rtb', route_table)
|
|
return route_table
|
|
|
|
|
|
def _delete_route_table(context, route_table_id, vpc=None, cleaner=None):
|
|
def get_associated_subnets():
|
|
return [s for s in db_api.get_items(context, 'subnet')
|
|
if s.get('route_table_id') == route_table_id]
|
|
|
|
if (vpc and route_table_id == vpc['route_table_id'] or
|
|
len(get_associated_subnets()) > 0):
|
|
msg = _("The routeTable '%(rtb_id)s' has dependencies and cannot "
|
|
"be deleted.") % {'rtb_id': route_table_id}
|
|
raise exception.DependencyViolation(msg)
|
|
if cleaner:
|
|
route_table = db_api.get_item_by_id(context, route_table_id)
|
|
db_api.delete_item(context, route_table_id)
|
|
if cleaner and route_table:
|
|
cleaner.addCleanup(db_api.restore_item, context, 'rtb', route_table)
|
|
|
|
|
|
def _set_route(context, route_table_id, destination_cidr_block,
|
|
gateway_id, instance_id, network_interface_id,
|
|
vpc_peering_connection_id, do_replace):
|
|
route_table = ec2utils.get_db_item(context, route_table_id)
|
|
vpc = db_api.get_item_by_id(context, route_table['vpc_id'])
|
|
vpc_ipnet = netaddr.IPNetwork(vpc['cidr_block'])
|
|
route_ipnet = netaddr.IPNetwork(destination_cidr_block)
|
|
if route_ipnet in vpc_ipnet:
|
|
msg = _('Cannot create a more specific route for '
|
|
'%(destination_cidr_block)s than local route '
|
|
'%(vpc_cidr_block)s in route table %(rtb_id)s')
|
|
msg = msg % {'rtb_id': route_table_id,
|
|
'destination_cidr_block': destination_cidr_block,
|
|
'vpc_cidr_block': vpc['cidr_block']}
|
|
raise exception.InvalidParameterValue(msg)
|
|
|
|
obj_param_count = len([p for p in (gateway_id, network_interface_id,
|
|
instance_id, vpc_peering_connection_id)
|
|
if p is not None])
|
|
if obj_param_count != 1:
|
|
msg = _('The request must contain exactly one of gatewayId, '
|
|
'networkInterfaceId, vpcPeeringConnectionId or instanceId')
|
|
if obj_param_count == 0:
|
|
raise exception.MissingParameter(msg)
|
|
else:
|
|
raise exception.InvalidParameterCombination(msg)
|
|
|
|
rollabck_route_table_state = copy.deepcopy(route_table)
|
|
if do_replace:
|
|
route_count = len(route_table['routes'])
|
|
route_table['routes'] = [
|
|
r for r in route_table['routes']
|
|
if r['destination_cidr_block'] != destination_cidr_block]
|
|
if route_count == len(route_table['routes']):
|
|
msg = _("There is no route defined for "
|
|
"'%(destination_cidr_block)s' in the route table. "
|
|
"Use CreateRoute instead.")
|
|
msg = msg % {'destination_cidr_block': destination_cidr_block}
|
|
raise exception.InvalidParameterValue(msg)
|
|
|
|
if gateway_id:
|
|
gateway = ec2utils.get_db_item(context, gateway_id)
|
|
if gateway.get('vpc_id') != route_table['vpc_id']:
|
|
msg = _('Route table %(rtb_id)s and network gateway %(igw_id)s '
|
|
'belong to different networks')
|
|
msg = msg % {'rtb_id': route_table_id,
|
|
'igw_id': gateway_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
route = {'gateway_id': gateway['id']}
|
|
elif network_interface_id:
|
|
network_interface = ec2utils.get_db_item(context, network_interface_id)
|
|
if network_interface['vpc_id'] != route_table['vpc_id']:
|
|
msg = _('Route table %(rtb_id)s and interface %(eni_id)s '
|
|
'belong to different networks')
|
|
msg = msg % {'rtb_id': route_table_id,
|
|
'eni_id': network_interface_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
route = {'network_interface_id': network_interface['id']}
|
|
elif instance_id:
|
|
# TODO(ft): implement search in DB layer
|
|
network_interfaces = [eni for eni in db_api.get_items(context, 'eni')
|
|
if eni.get('instance_id') == instance_id]
|
|
if len(network_interfaces) == 0:
|
|
msg = _("Invalid value '%(i_id)s' for instance ID. "
|
|
"Instance is not in a VPC.")
|
|
msg = msg % {'i_id': instance_id}
|
|
raise exception.InvalidParameterValue(msg)
|
|
elif len(network_interfaces) > 1:
|
|
raise exception.InvalidInstanceId(instance_id=instance_id)
|
|
network_interface = network_interfaces[0]
|
|
if network_interface['vpc_id'] != route_table['vpc_id']:
|
|
msg = _('Route table %(rtb_id)s and interface %(eni_id)s '
|
|
'belong to different networks')
|
|
msg = msg % {'rtb_id': route_table_id,
|
|
'eni_id': network_interface['id']}
|
|
raise exception.InvalidParameterValue(msg)
|
|
route = {'network_interface_id': network_interface['id']}
|
|
else:
|
|
raise exception.InvalidRequest('Parameter VpcPeeringConnectionId is '
|
|
'not supported by this implementation')
|
|
route['destination_cidr_block'] = destination_cidr_block
|
|
|
|
if do_replace:
|
|
idempotent_call = False
|
|
else:
|
|
old_route = next((r for r in route_table['routes']
|
|
if r['destination_cidr_block'] ==
|
|
destination_cidr_block), None)
|
|
idempotent_call = old_route == route
|
|
if old_route and not idempotent_call:
|
|
raise exception.RouteAlreadyExists(
|
|
destination_cidr_block=destination_cidr_block)
|
|
|
|
if not idempotent_call:
|
|
route_table['routes'].append(route)
|
|
|
|
with common.OnCrashCleaner() as cleaner:
|
|
db_api.update_item(context, route_table)
|
|
cleaner.addCleanup(db_api.update_item, context,
|
|
rollabck_route_table_state)
|
|
_update_routes_in_associated_subnets(context, route_table, cleaner,
|
|
rollabck_route_table_state)
|
|
|
|
return True
|
|
|
|
|
|
def _format_route_table(context, route_table, is_main=False,
|
|
associated_subnet_ids=[],
|
|
gateways={},
|
|
network_interfaces={}):
|
|
vpc_id = route_table['vpc_id']
|
|
ec2_route_table = {'routeTableId': route_table['id'],
|
|
'vpcId': vpc_id,
|
|
'routeSet': [],
|
|
# NOTE(ft): AWS returns empty tag set for a route table
|
|
# if no tag exists
|
|
'tagSet': []}
|
|
# TODO(ft): refactor to get Nova instances outside of this function
|
|
nova = clients.nova(context)
|
|
for route in route_table['routes']:
|
|
origin = ('CreateRouteTable'
|
|
if route.get('gateway_id', 0) is None else
|
|
'CreateRoute')
|
|
ec2_route = {'destinationCidrBlock': route['destination_cidr_block'],
|
|
'origin': origin}
|
|
if 'gateway_id' in route:
|
|
gateway_id = route['gateway_id']
|
|
if gateway_id is None:
|
|
state = 'active'
|
|
ec2_gateway_id = 'local'
|
|
else:
|
|
gateway = gateways.get(gateway_id)
|
|
state = ('active'
|
|
if gateway and gateway.get('vpc_id') == vpc_id else
|
|
'blackhole')
|
|
ec2_gateway_id = gateway_id
|
|
ec2_route.update({'gatewayId': ec2_gateway_id,
|
|
'state': state})
|
|
else:
|
|
network_interface_id = route['network_interface_id']
|
|
network_interface = network_interfaces.get(network_interface_id)
|
|
instance_id = (network_interface.get('instance_id')
|
|
if network_interface else
|
|
None)
|
|
state = 'blackhole'
|
|
if instance_id:
|
|
instance = db_api.get_item_by_id(context, instance_id)
|
|
if instance:
|
|
try:
|
|
os_instance = nova.servers.get(instance['os_id'])
|
|
if os_instance and os_instance.status == 'ACTIVE':
|
|
state = 'active'
|
|
except nova_exception.NotFound:
|
|
pass
|
|
ec2_route.update({'instanceId': instance_id,
|
|
'instanceOwnerId': context.project_id})
|
|
ec2_route.update({'networkInterfaceId': network_interface_id,
|
|
'state': state})
|
|
ec2_route_table['routeSet'].append(ec2_route)
|
|
|
|
associations = []
|
|
if is_main:
|
|
associations.append({
|
|
'routeTableAssociationId': ec2utils.change_ec2_id_kind(vpc_id,
|
|
'rtbassoc'),
|
|
'routeTableId': route_table['id'],
|
|
'main': True})
|
|
for subnet_id in associated_subnet_ids:
|
|
associations.append({
|
|
'routeTableAssociationId': ec2utils.change_ec2_id_kind(subnet_id,
|
|
'rtbassoc'),
|
|
'routeTableId': route_table['id'],
|
|
'subnetId': subnet_id,
|
|
'main': False})
|
|
if associations:
|
|
ec2_route_table['associationSet'] = associations
|
|
|
|
return ec2_route_table
|
|
|
|
|
|
def _update_routes_in_associated_subnets(context, route_table, cleaner,
|
|
rollabck_route_table_object,
|
|
is_main=None):
|
|
if is_main is None:
|
|
vpc = db_api.get_item_by_id(context, route_table['vpc_id'])
|
|
is_main = vpc['route_table_id'] == route_table['id']
|
|
if is_main:
|
|
appropriate_rtb_ids = (route_table['id'], None)
|
|
else:
|
|
appropriate_rtb_ids = (route_table['id'],)
|
|
router_objects = _get_router_objects(context, route_table)
|
|
neutron = clients.neutron(context)
|
|
for subnet in db_api.get_items(context, 'subnet'):
|
|
if (subnet['vpc_id'] == route_table['vpc_id'] and
|
|
subnet.get('route_table_id') in appropriate_rtb_ids):
|
|
_update_subnet_host_routes(
|
|
context, subnet, route_table, cleaner=cleaner,
|
|
rollback_route_table_object=rollabck_route_table_object,
|
|
router_objects=router_objects, neutron=neutron)
|
|
|
|
|
|
def _update_subnet_host_routes(context, subnet, route_table, cleaner=None,
|
|
rollback_route_table_object=None,
|
|
router_objects=None, neutron=None):
|
|
neutron = neutron or clients.neutron(context)
|
|
os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
|
|
gateway_ip = str(netaddr.IPAddress(
|
|
netaddr.IPNetwork(os_subnet['cidr']).first + 1))
|
|
host_routes = _get_subnet_host_routes(context, route_table, gateway_ip,
|
|
router_objects)
|
|
neutron.update_subnet(subnet['os_id'],
|
|
{'subnet': {'host_routes': host_routes}})
|
|
if cleaner and rollback_route_table_object:
|
|
cleaner.addCleanup(_update_subnet_host_routes, context, subnet,
|
|
rollback_route_table_object)
|
|
|
|
|
|
def _get_router_objects(context, route_table):
|
|
return dict((route['gateway_id'],
|
|
db_api.get_item_by_id(context, route['gateway_id']))
|
|
if route.get('gateway_id') else
|
|
(route['network_interface_id'],
|
|
db_api.get_item_by_id(context, route['network_interface_id']))
|
|
for route in route_table['routes']
|
|
if route.get('gateway_id') or 'network_interface_id' in route)
|
|
|
|
|
|
def _get_subnet_host_routes(context, route_table, gateway_ip,
|
|
router_objects=None):
|
|
def get_nexthop(route):
|
|
if 'gateway_id' in route:
|
|
gateway_id = route['gateway_id']
|
|
if gateway_id:
|
|
gateway = (router_objects[route['gateway_id']]
|
|
if router_objects else
|
|
db_api.get_item_by_id(context, gateway_id))
|
|
if (not gateway or
|
|
gateway.get('vpc_id') != route_table['vpc_id']):
|
|
return '127.0.0.1'
|
|
return gateway_ip
|
|
network_interface = (
|
|
router_objects[route['network_interface_id']]
|
|
if router_objects else
|
|
db_api.get_item_by_id(context, route['network_interface_id']))
|
|
if not network_interface:
|
|
return '127.0.0.1'
|
|
return network_interface['private_ip_address']
|
|
|
|
host_routes = [{'destination': route['destination_cidr_block'],
|
|
'nexthop': get_nexthop(route)}
|
|
for route in route_table['routes']]
|
|
if not any(r['destination'] == '0.0.0.0/0' for r in host_routes):
|
|
host_routes.append({'destination': '0.0.0.0/0',
|
|
'nexthop': '127.0.0.1'})
|
|
|
|
return host_routes
|
|
|
|
|
|
def _associate_subnet_item(context, subnet, route_table_id):
|
|
subnet['route_table_id'] = route_table_id
|
|
db_api.update_item(context, subnet)
|
|
|
|
|
|
def _disassociate_subnet_item(context, subnet):
|
|
subnet.pop('route_table_id')
|
|
db_api.update_item(context, subnet)
|
|
|
|
|
|
def _associate_vpc_item(context, vpc, route_table_id):
|
|
vpc['route_table_id'] = route_table_id
|
|
db_api.update_item(context, vpc)
|