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')
    }
Example #2
0
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_id = 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_id)

        _update_subnet_routes(context, cleaner, subnet, main_route_table)

    return True
Example #3
0
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_id = 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_id)

        _update_subnet_routes(context, cleaner, subnet, main_route_table)

    return True
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 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}
Example #6
0
    def test_delete_item(self):
        item = db_api.add_item(self.context, 'fake', {})
        db_api.delete_item(self.context, item['id'])
        item = db_api.get_item_by_id(self.context, item['id'])
        self.assertIsNone(item)

        # NOTE(ft): delete not existing item should pass quitely
        db_api.delete_item(self.context, fakes.random_ec2_id('fake'))

        item = db_api.add_item(self.context, 'fake', {})
        db_api.delete_item(self.other_context, item['id'])
        item = db_api.get_item_by_id(self.context, item['id'])
        self.assertIsNotNone(item)
Example #7
0
    def test_delete_item(self):
        item = db_api.add_item(self.context, 'fake', {})
        db_api.delete_item(self.context, item['id'])
        item = db_api.get_item_by_id(self.context, item['id'])
        self.assertIsNone(item)

        # NOTE(ft): delete not existing item should pass quitely
        db_api.delete_item(self.context, fakes.random_ec2_id('fake'))

        item = db_api.add_item(self.context, 'fake', {})
        db_api.delete_item(self.other_context, item['id'])
        item = db_api.get_item_by_id(self.context, item['id'])
        self.assertIsNotNone(item)
Example #8
0
    def test_get_item_by_id(self):
        self._setup_items()
        item_id = db_api.get_items(self.context, 'fake')[0]['id']
        other_item_id = db_api.get_items(self.other_context, 'fake')[0]['id']

        item = db_api.get_item_by_id(self.context, item_id)
        self.assertThat(item, matchers.DictMatches({'id': item_id,
                                                    'os_id': None,
                                                    'vpc_id': None}))
        item = db_api.get_item_by_id(self.context, other_item_id)
        self.assertIsNone(item)
        item = db_api.get_item_by_id(self.context, fakes.random_ec2_id('fake'))
        self.assertIsNone(item)
Example #9
0
def detach_network_interface(context, attachment_id, force=None):
    network_interface = db_api.get_item_by_id(
        context, ec2utils.change_ec2_id_kind(attachment_id, 'eni'))
    if not network_interface or 'instance_id' not in network_interface:
        raise exception.InvalidAttachmentIDNotFound(id=attachment_id)
    if network_interface['device_index'] == 0:
        raise exception.OperationNotPermitted(
            _('The network interface at device index 0 cannot be detached.'))
    neutron = clients.neutron(context)
    os_port = neutron.show_port(network_interface['os_id'])['port']
    with common.OnCrashCleaner() as cleaner:
        instance_id = network_interface['instance_id']
        device_index = network_interface['device_index']
        attach_time = network_interface['attach_time']
        delete_on_termination = network_interface['delete_on_termination']
        _detach_network_interface_item(context, network_interface)
        cleaner.addCleanup(_attach_network_interface_item, context,
                           network_interface, instance_id, device_index,
                           attach_time, delete_on_termination)
        neutron.update_port(os_port['id'],
                            {'port': {
                                'device_id': '',
                                'device_owner': ''
                            }})
    return True
Example #10
0
    def disassociate_address(self, context, public_ip=None,
                             association_id=None):
        LOG.info('Disassociating %s', association_id)
        neutron = clients.neutron(context)

        floatingips=neutron.list_floatingips(tenant_id=context.project_id)['floatingips']
        LOG.info('Existing floating ips: %s', floatingips)

        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in db_api.get_items(context,
                                                              'eipalloc')
                            if addr['public_ip'] == public_ip), None)

            if not CONF.disable_ec2_classic:
                if address and _is_address_valid(context, neutron, address):
                    msg = _('You must specify an association id when '
                            'unmapping an address from a VPC instance')
                    raise exception.InvalidParameterValue(msg)
                # NOTE(tikitavi): check the public IP exists to raise AWS
                # exception otherwise
                os_floating_ip = self.get_os_floating_ip_by_public_ip(
                    context, public_ip)
                os_ports = self.get_os_ports(context)
                os_instance_id = _get_os_instance_id(context, os_floating_ip,
                                                     os_ports)
                if os_instance_id:
                    nova = clients.nova(context)
                    nova.servers.remove_floating_ip(os_instance_id, public_ip)
                return None

            if not address:
                msg = _("The address '%(public_ip)s' does not belong to you.")
                raise exception.AuthFailure(msg % {'public_ip': public_ip})
            if 'network_interface_id' not in address:
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            association_id = ec2utils.change_ec2_id_kind(address['id'],
                                                         'eipassoc')

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        LOG.info('DB address: %s', address)
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(
                    id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                LOG.info('Disassociating %(private_ip_address)s from interface %(network_interface_id)s',
                         {'private_ip_address': private_ip_address, 'network_interface_id': network_interface_id})
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                update = neutron.update_floatingip(address['os_id'],
                                                   {'floatingip': {'port_id': None}})
                LOG.info('Neutron.update result is %s', update)
Example #11
0
def _update_routes_in_associated_subnets(context,
                                         cleaner,
                                         route_table,
                                         default_associations_only=None,
                                         update_target=None):
    if default_associations_only:
        appropriate_rtb_ids = (None, )
    else:
        vpc = db_api.get_item_by_id(context, route_table['vpc_id'])
        if vpc['route_table_id'] == route_table['id']:
            appropriate_rtb_ids = (route_table['id'], None)
        else:
            appropriate_rtb_ids = (route_table['id'], )
    neutron = clients.neutron(context)
    subnets = [
        subnet 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)
    ]
    # NOTE(ft): we need to update host routes for both host and vpn target
    # because vpn-related routes are present in host routes as well
    _update_host_routes(context, neutron, cleaner, route_table, subnets)
    if not update_target or update_target == VPN_TARGET:
        vpn_connection_api._update_vpn_routes(context, neutron, cleaner,
                                              route_table, subnets)
Example #12
0
def associate_dhcp_options(context, dhcp_options_id, vpc_id):
    vpc = ec2utils.get_db_item(context, vpc_id)
    rollback_dhcp_options_id = vpc.get('dhcp_options_id')
    if dhcp_options_id == 'default':
        dhcp_options_id = None
        dhcp_options = None
    else:
        dhcp_options = ec2utils.get_db_item(context, dhcp_options_id)
        dhcp_options_id = dhcp_options['id']
    neutron = clients.neutron(context)
    os_ports = neutron.list_ports(tenant_id=context.project_id)['ports']
    network_interfaces = db_api.get_items(context, 'eni')
    rollback_dhcp_options_object = (
            db_api.get_item_by_id(context, rollback_dhcp_options_id)
            if dhcp_options_id is not None else
            None)
    with common.OnCrashCleaner() as cleaner:
        _associate_vpc_item(context, vpc, dhcp_options_id)
        cleaner.addCleanup(_associate_vpc_item, context, vpc,
                           rollback_dhcp_options_id)
        for network_interface in network_interfaces:
            os_port = next((p for p in os_ports
                            if p['id'] == network_interface['os_id']), None)
            if not os_port:
                continue
            _add_dhcp_opts_to_port(context, dhcp_options,
                                   network_interface, os_port, neutron)
            cleaner.addCleanup(_add_dhcp_opts_to_port, context,
                               rollback_dhcp_options_object, network_interface,
                               os_port, neutron)
    return True
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)
Example #14
0
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)
    update_target = _get_route_target(route)
    if update_target == VPN_TARGET:
        vpn_gateway = db_api.get_item_by_id(context, route['gateway_id'])
        if (not vpn_gateway or
                vpn_gateway['vpc_id'] != route_table['vpc_id']):
            update_target = None
    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)

        if update_target:
            _update_routes_in_associated_subnets(
                context, cleaner, route_table, update_target=update_target)

    return True
Example #15
0
def detach_vpn_gateway(context, vpc_id, vpn_gateway_id):
    vpn_gateway = ec2utils.get_db_item(context, vpn_gateway_id)
    if vpn_gateway['vpc_id'] != vpc_id:
        raise exception.InvalidVpnGatewayAttachmentNotFound(
            vgw_id=vpn_gateway_id, vpc_id=vpc_id)

    vpc = db_api.get_item_by_id(context, vpc_id)
    neutron = clients.neutron(context)
    remove_os_gateway_router = (
        ec2utils.get_attached_gateway(context, vpc_id, 'igw') is None)
    subnets = [subnet for subnet in db_api.get_items(context, 'subnet')
               if subnet['vpc_id'] == vpc['id']]
    with common.OnCrashCleaner() as cleaner:
        _detach_vpn_gateway_item(context, vpn_gateway)
        cleaner.addCleanup(_attach_vpn_gateway_item, context, vpn_gateway,
                           vpc_id)
        vpn_connection_api._stop_gateway_vpn_connections(
            context, neutron, cleaner, vpn_gateway)
        for subnet in subnets:
            _delete_subnet_vpnservice(context, neutron, cleaner, subnet)

        if remove_os_gateway_router:
            try:
                neutron.remove_gateway_router(vpc['os_id'])
            except neutron_exception.NotFound:
                pass

    return True
Example #16
0
    def disassociate_address(self, context, public_ip=None,
                             association_id=None):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in db_api.get_items(context,
                                                              'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            # NOTE(ft): association_id is unused in EC2 Classic mode, but it's
            # passed there to validate its emptiness in one place
            return AddressEngineNova().disassociate_address(
                    context, public_ip=public_ip,
                    association_id=association_id)

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(
                    id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                neutron.update_floatingip(address['os_id'],
                                          {'floatingip': {'port_id': None}})
Example #17
0
def associate_dhcp_options(context, dhcp_options_id, vpc_id):
    vpc = ec2utils.get_db_item(context, vpc_id)
    rollback_dhcp_options_id = vpc.get('dhcp_options_id')
    if dhcp_options_id == 'default':
        dhcp_options_id = None
        dhcp_options = None
    else:
        dhcp_options = ec2utils.get_db_item(context, dhcp_options_id)
        dhcp_options_id = dhcp_options['id']
    neutron = clients.neutron(context)
    os_ports = neutron.list_ports(tenant_id=context.project_id)['ports']
    network_interfaces = db_api.get_items(context, 'eni')
    rollback_dhcp_options_object = (db_api.get_item_by_id(
        context, rollback_dhcp_options_id)
                                    if dhcp_options_id is not None else None)
    with common.OnCrashCleaner() as cleaner:
        _associate_vpc_item(context, vpc, dhcp_options_id)
        cleaner.addCleanup(_associate_vpc_item, context, vpc,
                           rollback_dhcp_options_id)
        for network_interface in network_interfaces:
            os_port = next(
                (p for p in os_ports if p['id'] == network_interface['os_id']),
                None)
            if not os_port:
                continue
            _add_dhcp_opts_to_port(context, dhcp_options, network_interface,
                                   os_port, neutron)
            cleaner.addCleanup(_add_dhcp_opts_to_port, context,
                               rollback_dhcp_options_object, network_interface,
                               os_port, neutron)
    return True
Example #18
0
    def disassociate_address(self,
                             context,
                             public_ip=None,
                             association_id=None):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr
                            for addr in db_api.get_items(context, 'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            # NOTE(ft): association_id is unused in EC2 Classic mode, but it's
            # passed there to validate its emptiness in one place
            return AddressEngineNova().disassociate_address(
                context, public_ip=public_ip, association_id=association_id)

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                neutron.update_floatingip(address['os_id'],
                                          {'floatingip': {
                                              'port_id': None
                                          }})
Example #19
0
    def test_add_item(self):
        new_item = {
            'os_id': fakes.random_os_id(),
            'vpc_id': fakes.random_ec2_id('fake_vpc'),
            'str_attr': 'fake_str',
            'int_attr': 1234,
            'bool_attr': True,
            'dict_attr': {
                'key1': 'val1',
                'key2': 'val2'
            },
            'list_attr': ['fake_str', 1234, True, {
                'key': 'val'
            }, []]
        }
        item = db_api.add_item(self.context, 'fake', new_item)
        self.assertIn('id', item)
        self.assertIsNotNone(item['id'])
        item_id = item.pop('id')
        self.assertTrue(validator.validate_ec2_id(item_id, '', ['fake']))
        self.assertThat(item,
                        matchers.DictMatches(new_item, orderless_lists=True))

        item = db_api.get_item_by_id(self.context, item_id)
        new_item['id'] = item_id
        self.assertThat(item,
                        matchers.DictMatches(new_item, orderless_lists=True))
Example #20
0
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)
    update_target = _get_route_target(route)
    if update_target == VPN_TARGET:
        vpn_gateway = db_api.get_item_by_id(context, route['gateway_id'])
        if (not vpn_gateway or
                vpn_gateway['vpc_id'] != route_table['vpc_id']):
            update_target = None
    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)

        if update_target:
            _update_routes_in_associated_subnets(
                context, cleaner, route_table, update_target=update_target)

    return True
 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']
Example #22
0
    def test_get_item_by_id(self):
        self._setup_items()
        item_id = db_api.get_items(self.context, 'fake')[0]['id']
        other_item_id = db_api.get_items(self.other_context, 'fake')[0]['id']

        item = db_api.get_item_by_id(self.context, item_id)
        self.assertThat(
            item,
            matchers.DictMatches({
                'id': item_id,
                'os_id': None,
                'vpc_id': None
            }))
        item = db_api.get_item_by_id(self.context, other_item_id)
        self.assertIsNone(item)
        item = db_api.get_item_by_id(self.context, fakes.random_ec2_id('fake'))
        self.assertIsNone(item)
Example #23
0
def create_subnet(context, vpc_id, cidr_block, availability_zone=None):
    vpc = ec2utils.get_db_item(context, vpc_id)
    vpc_ipnet = netaddr.IPNetwork(vpc['cidr_block'])
    subnet_ipnet = netaddr.IPNetwork(cidr_block)
    if subnet_ipnet not in vpc_ipnet:
        raise exception.InvalidSubnetRange(cidr_block=cidr_block)

    gateway_ip = str(netaddr.IPAddress(subnet_ipnet.first + 1))
    main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
    host_routes = route_table_api._get_subnet_host_routes(
        context, main_route_table, gateway_ip)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        os_network_body = {'network': {}}
        try:
            os_network = neutron.create_network(os_network_body)['network']
            cleaner.addCleanup(neutron.delete_network, os_network['id'])
            # NOTE(Alex): AWS takes 4 first addresses (.1 - .4) but for
            # OpenStack we decided not to support this as compatibility.
            os_subnet_body = {
                'subnet': {
                    'network_id': os_network['id'],
                    'ip_version': '4',
                    'cidr': cidr_block,
                    'host_routes': host_routes
                }
            }
            os_subnet = neutron.create_subnet(os_subnet_body)['subnet']
            cleaner.addCleanup(neutron.delete_subnet, os_subnet['id'])
        except neutron_exception.OverQuotaClient:
            raise exception.SubnetLimitExceeded()
        try:
            neutron.add_interface_router(vpc['os_id'],
                                         {'subnet_id': os_subnet['id']})
        except neutron_exception.BadRequest:
            raise exception.InvalidSubnetConflict(cidr_block=cidr_block)
        cleaner.addCleanup(neutron.remove_interface_router, vpc['os_id'],
                           {'subnet_id': os_subnet['id']})
        subnet = db_api.add_item(context, 'subnet', {
            'os_id': os_subnet['id'],
            'vpc_id': vpc['id']
        })
        cleaner.addCleanup(db_api.delete_item, context, subnet['id'])
        neutron.update_network(os_network['id'],
                               {'network': {
                                   'name': subnet['id']
                               }})
        neutron.update_subnet(os_subnet['id'],
                              {'subnet': {
                                  'name': subnet['id']
                              }})
    os_ports = neutron.list_ports(tenant_id=context.project_id)['ports']
    return {
        'subnet': _format_subnet(context, subnet, os_subnet, os_network,
                                 os_ports)
    }
 def assert_image_project(self, expected_project_id, image_id):
     if expected_project_id:
         context = mock.NonCallableMock(project_id=expected_project_id)
     else:
         context = self.context
     image_item = db_api.get_item_by_id(context, image_id)
     if expected_project_id:
         self.assertIsNotNone(image_item)
     else:
         self.assertIsNone(image_item)
Example #25
0
def create_subnet(context, vpc_id, cidr_block,
                  availability_zone=None):
    vpc = ec2utils.get_db_item(context, vpc_id)
    vpc_ipnet = netaddr.IPNetwork(vpc['cidr_block'])
    subnet_ipnet = netaddr.IPNetwork(cidr_block)
    if subnet_ipnet not in vpc_ipnet:
        raise exception.InvalidSubnetRange(cidr_block=cidr_block)

    main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
    (host_routes,
     gateway_ip) = route_table_api._get_subnet_host_routes_and_gateway_ip(
            context, main_route_table, cidr_block)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        # NOTE(andrey-mp): set fake name to filter networks in instance api
        os_network_body = {'network': {'name': 'subnet-0'}}
        try:
            os_network = neutron.create_network(os_network_body)['network']
            cleaner.addCleanup(neutron.delete_network, os_network['id'])
            # NOTE(Alex): AWS takes 4 first addresses (.1 - .4) but for
            # OpenStack we decided not to support this as compatibility.
            os_subnet_body = {'subnet': {'network_id': os_network['id'],
                                         'ip_version': '4',
                                         'cidr': cidr_block,
                                         'host_routes': host_routes}}
            os_subnet = neutron.create_subnet(os_subnet_body)['subnet']
            cleaner.addCleanup(neutron.delete_subnet, os_subnet['id'])
        except neutron_exception.OverQuotaClient:
            raise exception.SubnetLimitExceeded()
        try:
            neutron.add_interface_router(vpc['os_id'],
                                         {'subnet_id': os_subnet['id']})
        except neutron_exception.BadRequest:
            raise exception.InvalidSubnetConflict(cidr_block=cidr_block)
        cleaner.addCleanup(neutron.remove_interface_router,
                           vpc['os_id'], {'subnet_id': os_subnet['id']})
        subnet = db_api.add_item(context, 'subnet',
                                 {'os_id': os_subnet['id'],
                                  'vpc_id': vpc['id']})
        cleaner.addCleanup(db_api.delete_item, context, subnet['id'])
        vpn_gateway_api._start_vpn_in_subnet(context, neutron, cleaner,
                                             subnet, vpc, main_route_table)
        neutron.update_network(os_network['id'],
                               {'network': {'name': subnet['id']}})
        # NOTE(ft): In some cases we need gateway_ip to be None (see
        # _get_subnet_host_routes_and_gateway_ip). It's not set during subnet
        # creation to allow automatic configuration of the default port by
        # which subnet is attached to the router.
        neutron.update_subnet(os_subnet['id'],
                              {'subnet': {'name': subnet['id'],
                                          'gateway_ip': gateway_ip}})
    os_ports = neutron.list_ports(tenant_id=context.project_id)['ports']
    return {'subnet': _format_subnet(context, subnet, os_subnet,
                                     os_network, os_ports)}
Example #26
0
 def test_update_item_os_id(self):
     item = db_api.add_item(self.context, 'fake', {})
     item['os_id'] = 'fake_os_id'
     db_api.update_item(self.context, item)
     item = db_api.get_item_by_id(self.context, item['id'])
     self.assertThat({'os_id': 'fake_os_id'}, matchers.IsSubDictOf(item))
     item['os_id'] = 'other_fake_os_id'
     self.assertRaises(exception.EC2DBInvalidOsIdUpdate, db_api.update_item,
                       self.context, item)
     item['os_id'] = None
     self.assertRaises(exception.EC2DBInvalidOsIdUpdate, db_api.update_item,
                       self.context, item)
Example #27
0
    def release_address(self, context, public_ip, allocation_id):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in
                            db_api.get_items(context, 'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an allocation id when releasing a '
                        'VPC elastic IP address')
                raise exception.InvalidParameterValue(msg)
            os_floating_ip = self.get_os_floating_ip_by_public_ip(context,
                                                                  public_ip)
            try:
                neutron.delete_floatingip(os_floating_ip['id'])
            except neutron_exception.NotFound:
                pass
            return

        address = ec2utils.get_db_item(context, allocation_id)
        if not _is_address_valid(context, neutron, address):
            raise exception.InvalidAllocationIDNotFound(
                id=allocation_id)

        if 'network_interface_id' in address:
            if CONF.disable_ec2_classic:
                network_interface_id = address['network_interface_id']
                network_interface = db_api.get_item_by_id(context,
                                                          network_interface_id)
                default_vpc = ec2utils.check_and_create_default_vpc(context)
                if default_vpc:
                    default_vpc_id = default_vpc['id']
                if (network_interface and
                        network_interface['vpc_id'] == default_vpc_id):
                    association_id = ec2utils.change_ec2_id_kind(address['id'],
                                                                 'eipassoc')
                    self.disassociate_address(
                        context, association_id=association_id)
                else:
                    raise exception.InvalidIPAddressInUse(
                        ip_address=address['public_ip'])
            else:
                raise exception.InvalidIPAddressInUse(
                    ip_address=address['public_ip'])

        with common.OnCrashCleaner() as cleaner:
            db_api.delete_item(context, address['id'])
            cleaner.addCleanup(db_api.restore_item, context,
                               'eipalloc', address)
            try:
                neutron.delete_floatingip(address['os_id'])
            except neutron_exception.NotFound:
                pass
Example #28
0
def create_subnet(context, vpc_id, cidr_block,
                  availability_zone=None):
    vpc = ec2utils.get_db_item(context, vpc_id)
    vpc_ipnet = netaddr.IPNetwork(vpc['cidr_block'])
    subnet_ipnet = netaddr.IPNetwork(cidr_block)
    if subnet_ipnet not in vpc_ipnet:
        raise exception.InvalidSubnetRange(cidr_block=cidr_block)

    main_route_table = db_api.get_item_by_id(context, vpc['route_table_id'])
    (host_routes,
     gateway_ip) = route_table_api._get_subnet_host_routes_and_gateway_ip(
            context, main_route_table, cidr_block)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        os_network_body = {'network': {}}
        try:
            os_network = neutron.create_network(os_network_body)['network']
            cleaner.addCleanup(neutron.delete_network, os_network['id'])
            # NOTE(Alex): AWS takes 4 first addresses (.1 - .4) but for
            # OpenStack we decided not to support this as compatibility.
            os_subnet_body = {'subnet': {'network_id': os_network['id'],
                                         'ip_version': '4',
                                         'cidr': cidr_block,
                                         'host_routes': host_routes}}
            os_subnet = neutron.create_subnet(os_subnet_body)['subnet']
            cleaner.addCleanup(neutron.delete_subnet, os_subnet['id'])
        except neutron_exception.OverQuotaClient:
            raise exception.SubnetLimitExceeded()
        try:
            neutron.add_interface_router(vpc['os_id'],
                                         {'subnet_id': os_subnet['id']})
        except neutron_exception.BadRequest:
            raise exception.InvalidSubnetConflict(cidr_block=cidr_block)
        cleaner.addCleanup(neutron.remove_interface_router,
                           vpc['os_id'], {'subnet_id': os_subnet['id']})
        subnet = db_api.add_item(context, 'subnet',
                                 {'os_id': os_subnet['id'],
                                  'vpc_id': vpc['id']})
        cleaner.addCleanup(db_api.delete_item, context, subnet['id'])
        vpn_gateway_api._start_vpn_in_subnet(context, neutron, cleaner,
                                             subnet, vpc, main_route_table)
        neutron.update_network(os_network['id'],
                               {'network': {'name': subnet['id']}})
        # NOTE(ft): In some cases we need gateway_ip to be None (see
        # _get_subnet_host_routes_and_gateway_ip). It's not set during subnet
        # creation to allow automatic configuration of the default port by
        # which subnet is attached to the router.
        neutron.update_subnet(os_subnet['id'],
                              {'subnet': {'name': subnet['id'],
                                          'gateway_ip': gateway_ip}})
    os_ports = neutron.list_ports(tenant_id=context.project_id)['ports']
    return {'subnet': _format_subnet(context, subnet, os_subnet,
                                     os_network, os_ports)}
Example #29
0
    def release_address(self, context, public_ip, allocation_id):
        neutron = clients.neutron(context)
        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in
                            db_api.get_items(context, 'eipalloc')
                            if addr['public_ip'] == public_ip), None)
            if address and _is_address_valid(context, neutron, address):
                msg = _('You must specify an allocation id when releasing a '
                        'VPC elastic IP address')
                raise exception.InvalidParameterValue(msg)
            os_floating_ip = self.get_os_floating_ip_by_public_ip(context,
                                                                  public_ip)
            try:
                neutron.delete_floatingip(os_floating_ip['id'])
            except neutron_exception.NotFound:
                pass
            return

        address = ec2utils.get_db_item(context, allocation_id)
        if not _is_address_valid(context, neutron, address):
            raise exception.InvalidAllocationIDNotFound(
                id=allocation_id)

        if 'network_interface_id' in address:
            if CONF.disable_ec2_classic:
                network_interface_id = address['network_interface_id']
                network_interface = db_api.get_item_by_id(context,
                                                          network_interface_id)
                default_vpc = ec2utils.check_and_create_default_vpc(context)
                if default_vpc:
                    default_vpc_id = default_vpc['id']
                if (network_interface and
                        network_interface['vpc_id'] == default_vpc_id):
                    association_id = ec2utils.change_ec2_id_kind(address['id'],
                                                                 'eipassoc')
                    self.disassociate_address(
                        context, association_id=association_id)
                else:
                    raise exception.InvalidIPAddressInUse(
                        ip_address=address['public_ip'])
            else:
                raise exception.InvalidIPAddressInUse(
                    ip_address=address['public_ip'])

        with common.OnCrashCleaner() as cleaner:
            db_api.delete_item(context, address['id'])
            cleaner.addCleanup(db_api.restore_item, context,
                               'eipalloc', address)
            try:
                neutron.delete_floatingip(address['os_id'])
            except neutron_exception.NotFound:
                pass
Example #30
0
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)

        rollback_route_table_id = vpc['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_vpc_item(context, vpc, route_table['id'])
            cleaner.addCleanup(_associate_vpc_item, context, vpc,
                               rollback_route_table_id)

            _update_routes_in_associated_subnets(
                context, cleaner, route_table, default_associations_only=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)

        rollback_route_table_id = subnet['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_subnet_item(context, subnet, route_table['id'])
            cleaner.addCleanup(_associate_subnet_item, context, subnet,
                               rollback_route_table_id)

            _update_subnet_routes(context, cleaner, subnet, route_table)

    return {'newAssociationId': association_id}
Example #31
0
    def disassociate_address(self, context, public_ip=None,
                             association_id=None):
        neutron = clients.neutron(context)

        if public_ip:
            # TODO(ft): implement search in DB layer
            address = next((addr for addr in db_api.get_items(context,
                                                              'eipalloc')
                            if addr['public_ip'] == public_ip), None)

            if not CONF.disable_ec2_classic:
                if address and _is_address_valid(context, neutron, address):
                    msg = _('You must specify an association id when '
                            'unmapping an address from a VPC instance')
                    raise exception.InvalidParameterValue(msg)
                # NOTE(tikitavi): check the public IP exists to raise AWS
                # exception otherwise
                os_floating_ip = self.get_os_floating_ip_by_public_ip(
                    context, public_ip)
                os_ports = self.get_os_ports(context)
                os_instance_id = _get_os_instance_id(context, os_floating_ip,
                                                     os_ports)
                if os_instance_id:
                    nova = clients.nova(context)
                    nova.servers.remove_floating_ip(os_instance_id, public_ip)
                return None

            if not address:
                msg = _("The address '%(public_ip)s' does not belong to you.")
                raise exception.AuthFailure(msg % {'public_ip': public_ip})
            if 'network_interface_id' not in address:
                msg = _('You must specify an association id when unmapping '
                        'an address from a VPC instance')
                raise exception.InvalidParameterValue(msg)
            association_id = ec2utils.change_ec2_id_kind(address['id'],
                                                         'eipassoc')

        address = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(association_id, 'eipalloc'))
        if address is None or not _is_address_valid(context, neutron, address):
            raise exception.InvalidAssociationIDNotFound(
                    id=association_id)
        if 'network_interface_id' in address:
            with common.OnCrashCleaner() as cleaner:
                network_interface_id = address['network_interface_id']
                private_ip_address = address['private_ip_address']
                _disassociate_address_item(context, address)
                cleaner.addCleanup(_associate_address_item, context, address,
                                   network_interface_id, private_ip_address)

                neutron.update_floatingip(address['os_id'],
                                          {'floatingip': {'port_id': None}})
Example #32
0
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)

        rollback_route_table_id = vpc['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_vpc_item(context, vpc, route_table['id'])
            cleaner.addCleanup(_associate_vpc_item, context, vpc,
                               rollback_route_table_id)

            _update_routes_in_associated_subnets(
                context, cleaner, route_table, default_associations_only=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)

        rollback_route_table_id = subnet['route_table_id']
        with common.OnCrashCleaner() as cleaner:
            _associate_subnet_item(context, subnet, route_table['id'])
            cleaner.addCleanup(_associate_subnet_item, context, subnet,
                               rollback_route_table_id)

            _update_subnet_routes(context, cleaner, subnet, route_table)

    return {'newAssociationId': association_id}
Example #33
0
 def test_update_item(self):
     item = db_api.add_item(self.context, 'fake', {'key': 'val1',
                                                   'key1': 'val'})
     item['key'] = 'val2'
     item.pop('key1')
     item['key2'] = 'val'
     item_id = item['id']
     db_api.update_item(self.context, item)
     item = db_api.get_item_by_id(self.context, item_id)
     self.assertThat(item, matchers.DictMatches({'id': item_id,
                                                 'os_id': None,
                                                 'vpc_id': None,
                                                 'key': 'val2',
                                                 'key2': 'val'}))
Example #34
0
 def test_update_item_os_id(self):
     item = db_api.add_item(self.context, 'fake', {})
     item['os_id'] = 'fake_os_id'
     db_api.update_item(self.context, item)
     item = db_api.get_item_by_id(self.context, item['id'])
     self.assertThat({'os_id': 'fake_os_id'},
                     matchers.IsSubDictOf(item))
     item['os_id'] = 'other_fake_os_id'
     self.assertRaises(exception.EC2DBInvalidOsIdUpdate,
                       db_api.update_item,
                       self.context, item)
     item['os_id'] = None
     self.assertRaises(exception.EC2DBInvalidOsIdUpdate,
                       db_api.update_item,
                       self.context, item)
Example #35
0
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)
Example #36
0
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)
Example #37
0
def disable_vgw_route_propagation(context, route_table_id, gateway_id):
    route_table = ec2utils.get_db_item(context, route_table_id)
    if gateway_id not in route_table.get('propagating_gateways', []):
        return True
    vpn_gateway = db_api.get_item_by_id(context, gateway_id)

    with common.OnCrashCleaner() as cleaner:
        _remove_propagation_from_route_table_item(context, route_table,
                                                  gateway_id)
        cleaner.addCleanup(_append_propagation_to_route_table_item,
                           context, route_table, gateway_id)

        if vpn_gateway and vpn_gateway['vpc_id'] == route_table['vpc_id']:
            _update_routes_in_associated_subnets(context, cleaner, route_table,
                                                 update_target=VPN_TARGET)
    return True
Example #38
0
def disable_vgw_route_propagation(context, route_table_id, gateway_id):
    route_table = ec2utils.get_db_item(context, route_table_id)
    if gateway_id not in route_table.get('propagating_gateways', []):
        return True
    vpn_gateway = db_api.get_item_by_id(context, gateway_id)

    with common.OnCrashCleaner() as cleaner:
        _remove_propagation_from_route_table_item(context, route_table,
                                                  gateway_id)
        cleaner.addCleanup(_append_propagation_to_route_table_item,
                           context, route_table, gateway_id)

        if vpn_gateway and vpn_gateway['vpc_id'] == route_table['vpc_id']:
            _update_routes_in_associated_subnets(context, cleaner, route_table,
                                                 update_target=VPN_TARGET)
    return True
Example #39
0
def _reset_vpn_connections(context,
                           neutron,
                           cleaner,
                           vpn_gateway,
                           subnets=None,
                           route_tables=None,
                           vpn_connections=None):
    if not vpn_gateway['vpc_id']:
        return
    # TODO(ft): implement search filters in DB api
    vpn_connections = (vpn_connections or [
        vpn for vpn in db_api.get_items(context, 'vpn')
        if vpn['vpn_gateway_id'] == vpn_gateway['id']
    ])
    if not vpn_connections:
        return
    subnets = (subnets or [
        subnet for subnet in db_api.get_items(context, 'subnet')
        if subnet['vpc_id'] == vpn_gateway['vpc_id']
    ])
    if not subnets:
        return
    vpc = db_api.get_item_by_id(context, vpn_gateway['vpc_id'])
    customer_gateways = {
        cgw['id']: cgw
        for cgw in db_api.get_items(context, 'cgw')
    }
    route_tables = route_tables or db_api.get_items(context, 'rtb')
    route_tables = {
        rtb['id']: rtb
        for rtb in route_tables if rtb['vpc_id'] == vpc['id']
    }
    route_tables_cidrs = {}
    for subnet in subnets:
        route_table_id = subnet.get('route_table_id', vpc['route_table_id'])
        if route_table_id not in route_tables_cidrs:
            route_tables_cidrs[route_table_id] = (_get_route_table_vpn_cidrs(
                route_tables[route_table_id], vpn_gateway, vpn_connections))
        cidrs = route_tables_cidrs[route_table_id]
        for vpn_conn in vpn_connections:
            if vpn_conn['id'] in cidrs:
                _set_subnet_vpn(
                    context, neutron, cleaner, subnet, vpn_conn,
                    customer_gateways[vpn_conn['customer_gateway_id']],
                    cidrs[vpn_conn['id']])
            else:
                _delete_subnet_vpn(context, neutron, cleaner, subnet, vpn_conn)
Example #40
0
def create_vpn_connection_route(context, vpn_connection_id,
                                destination_cidr_block):
    vpn_connection = ec2utils.get_db_item(context, vpn_connection_id)
    if destination_cidr_block in vpn_connection['cidrs']:
        return True
    neutron = clients.neutron(context)
    vpn_gateway = db_api.get_item_by_id(context,
                                        vpn_connection['vpn_gateway_id'])
    with common.OnCrashCleaner() as cleaner:
        _add_cidr_to_vpn_connection_item(context, vpn_connection,
                                         destination_cidr_block)
        cleaner.addCleanup(_remove_cidr_from_vpn_connection_item,
                           context, vpn_connection, destination_cidr_block)

        _reset_vpn_connections(context, neutron, cleaner,
                               vpn_gateway, vpn_connections=[vpn_connection])

    return True
Example #41
0
def deregister_image(context, image_id):
    os_image = ec2utils.get_os_image(context, image_id)
    if not os_image:
        image = db_api.get_item_by_id(context, image_id)
        if image.get('state') != 'failed':
            # TODO(ft): figure out corresponding AWS error
            raise exception.IncorrectState(
                reason='Image is still being created')
    else:
        _check_owner(context, os_image)

        glance = clients.glance(context)
        try:
            glance.images.delete(os_image.id)
        except glance_exception.HTTPNotFound:
            pass
    db_api.delete_item(context, image_id)
    return True
Example #42
0
def deregister_image(context, image_id):
    os_image = ec2utils.get_os_image(context, image_id)
    if not os_image:
        image = db_api.get_item_by_id(context, image_id)
        if image.get('state') != 'failed':
            # TODO(ft): figure out corresponding AWS error
            raise exception.IncorrectState(
                reason='Image is still being created')
    else:
        _check_owner(context, os_image)

        glance = clients.glance(context)
        try:
            glance.images.delete(os_image.id)
        except glance_exception.HTTPNotFound:
            pass
    db_api.delete_item(context, image_id)
    return True
Example #43
0
def delete_subnet(context, subnet_id):
    subnet = ec2utils.get_db_item(context, subnet_id)
    vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
    network_interfaces = network_interface_api.describe_network_interfaces(
        context, filter=[{
            'name': 'subnet-id',
            'value': [subnet_id]
        }])['networkInterfaceSet']
    if network_interfaces:
        msg = _("The subnet '%(subnet_id)s' has dependencies and "
                "cannot be deleted.") % {
                    'subnet_id': subnet_id
                }
        raise exception.DependencyViolation(msg)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, subnet['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'subnet', subnet)
        vpn_gateway_api._stop_vpn_in_subnet(context, neutron, cleaner, subnet)
        try:
            neutron.remove_interface_router(vpc['os_id'],
                                            {'subnet_id': subnet['os_id']})
        except neutron_exception.NotFound:
            pass
        cleaner.addCleanup(neutron.add_interface_router, vpc['os_id'],
                           {'subnet_id': subnet['os_id']})
        try:
            os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
        except neutron_exception.NotFound:
            pass
        else:
            try:
                neutron.delete_network(os_subnet['network_id'])
            except neutron_exception.NetworkInUseClient as ex:
                LOG.warning(
                    _('Failed to delete network %(os_id)s during '
                      'deleting Subnet %(id)s. Reason: %(reason)s'), {
                          'id': subnet['id'],
                          'os_id': os_subnet['network_id'],
                          'reason': ex.message
                      })

    return True
Example #44
0
def assign_private_ip_addresses(context,
                                network_interface_id,
                                private_ip_address=None,
                                secondary_private_ip_address_count=None,
                                allow_reassignment=False):
    # TODO(Alex): allow_reassignment is not supported at the moment
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    subnet = db_api.get_item_by_id(context, network_interface['subnet_id'])
    neutron = clients.neutron(context)
    os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
    os_port = neutron.show_port(network_interface['os_id'])['port']
    subnet_ipnet = netaddr.IPNetwork(os_subnet['cidr'])
    fixed_ips = os_port['fixed_ips'] or []
    if private_ip_address is not None:
        for ip_address in private_ip_address:
            if netaddr.IPAddress(ip_address) not in subnet_ipnet:
                raise exception.InvalidParameterValue(
                    value=str(ip_address),
                    parameter='PrivateIpAddress',
                    reason='IP address is out of the subnet range')
            fixed_ips.append({'ip_address': str(ip_address)})
    elif secondary_private_ip_address_count > 0:
        for _i in range(secondary_private_ip_address_count):
            fixed_ips.append({'subnet_id': os_subnet['id']})
    try:
        neutron.update_port(os_port['id'], {'port': {'fixed_ips': fixed_ips}})
    except neutron_exception.IpAddressGenerationFailureClient:
        raise exception.InsufficientFreeAddressesInSubnet()
    except neutron_exception.IpAddressInUseClient:
        msg = _('Some of %(addresses)s is assigned, but move is not '
                'allowed.') % {
                    'addresses': private_ip_address
                }
        raise exception.InvalidParameterValue(msg)
    except neutron_exception.BadRequest as ex:
        # NOTE(ft):AWS returns PrivateIpAddressLimitExceeded, but Neutron does
        # general InvalidInput (converted to BadRequest) in the same case.
        msg = _('Specified network interface parameters are invalid. '
                'Reason: %(reason)s') % {
                    'reason': ex.message
                }
        raise exception.InvalidParameterValue(msg)
    return True
Example #45
0
    def test_add_item_id(self):
        os_id = fakes.random_os_id()
        item_id = db_api.add_item_id(self.context, 'fake', os_id)
        self.assertTrue(validator.validate_ec2_id(item_id, '', ['fake']))
        item = db_api.get_item_by_id(self.context, item_id)
        self.assertIsNone(item)
        item = db_api.add_item(self.context, 'fake', {'os_id': os_id})
        self.assertThat(item, matchers.DictMatches({'id': item_id,
                                                    'os_id': os_id,
                                                    'vpc_id': None}))
        # NOTE(ft): add os_id when item exists
        item_id = db_api.add_item_id(self.context, 'fake', os_id)
        self.assertEqual(item_id, item['id'])

        # NOTE(ft): add os_id when id exists
        os_id = fakes.random_os_id()
        item_id1 = db_api.add_item_id(self.context, 'fake', os_id)
        item_id2 = db_api.add_item_id(self.context, 'fake', os_id)
        self.assertEqual(item_id1, item_id2)
Example #46
0
def get_db_item(context, ec2_id, expected_kind=None):
    """Get an DB item, raise AWS compliant exception if it's not found.

        Args:
            context (RequestContext): The request context.
            ec2_id (str): The ID of the requested item.
            expected_kind (str): The expected kind of the requested item.
                It should be specified for a kind of ec2_id to be validated,
                if you need it.

        Returns:
            The DB item.
    """
    item = db_api.get_item_by_id(context, ec2_id)
    if (item is None or
            expected_kind and get_ec2_id_kind(ec2_id) != expected_kind):
        kind = expected_kind or get_ec2_id_kind(ec2_id)
        params = {'id': ec2_id}
        raise NOT_FOUND_EXCEPTION_MAP[kind](**params)
    return item
Example #47
0
def delete_vpn_connection_route(context, vpn_connection_id,
                                destination_cidr_block):
    vpn_connection = ec2utils.get_db_item(context, vpn_connection_id)
    if destination_cidr_block not in vpn_connection['cidrs']:
        raise exception.InvalidRouteNotFound(
            _('The specified route %(destination_cidr_block)s does not exist')
            % {'destination_cidr_block': destination_cidr_block})
    neutron = clients.neutron(context)
    vpn_gateway = db_api.get_item_by_id(context,
                                        vpn_connection['vpn_gateway_id'])
    with common.OnCrashCleaner() as cleaner:
        _remove_cidr_from_vpn_connection_item(context, vpn_connection,
                                              destination_cidr_block)
        cleaner.addCleanup(_add_cidr_to_vpn_connection_item,
                           context, vpn_connection, destination_cidr_block)

        _reset_vpn_connections(context, neutron, cleaner,
                               vpn_gateway, vpn_connections=[vpn_connection])

    return True
Example #48
0
 def test_update_item(self):
     item = db_api.add_item(self.context, 'fake', {
         'key': 'val1',
         'key1': 'val'
     })
     item['key'] = 'val2'
     item.pop('key1')
     item['key2'] = 'val'
     item_id = item['id']
     db_api.update_item(self.context, item)
     item = db_api.get_item_by_id(self.context, item_id)
     self.assertThat(
         item,
         matchers.DictMatches({
             'id': item_id,
             'os_id': None,
             'vpc_id': None,
             'key': 'val2',
             'key2': 'val'
         }))
Example #49
0
    def test_add_item(self):
        new_item = {'os_id': fakes.random_os_id(),
                    'vpc_id': fakes.random_ec2_id('fake_vpc'),
                    'str_attr': 'fake_str',
                    'int_attr': 1234,
                    'bool_attr': True,
                    'dict_attr': {'key1': 'val1',
                                  'key2': 'val2'},
                    'list_attr': ['fake_str', 1234, True, {'key': 'val'}, []]}
        item = db_api.add_item(self.context, 'fake', new_item)
        self.assertIn('id', item)
        self.assertIsNotNone(item['id'])
        item_id = item.pop('id')
        self.assertTrue(validator.validate_ec2_id(item_id, '', ['fake']))
        self.assertThat(item, matchers.DictMatches(new_item,
                                                   orderless_lists=True))

        item = db_api.get_item_by_id(self.context, item_id)
        new_item['id'] = item_id
        self.assertThat(item, matchers.DictMatches(new_item,
                                                   orderless_lists=True))
Example #50
0
def _update_routes_in_associated_subnets(context, cleaner, route_table,
                                         default_associations_only=None,
                                         update_target=None):
    if default_associations_only:
        appropriate_rtb_ids = (None,)
    else:
        vpc = db_api.get_item_by_id(context, route_table['vpc_id'])
        if vpc['route_table_id'] == route_table['id']:
            appropriate_rtb_ids = (route_table['id'], None)
        else:
            appropriate_rtb_ids = (route_table['id'],)
    neutron = clients.neutron(context)
    subnets = [subnet 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)]
    # NOTE(ft): we need to update host routes for both host and vpn target
    # because vpn-related routes are present in host routes as well
    _update_host_routes(context, neutron, cleaner, route_table, subnets)
    if not update_target or update_target == VPN_TARGET:
        vpn_connection_api._update_vpn_routes(context, neutron, cleaner,
                                              route_table, subnets)
Example #51
0
def assign_private_ip_addresses(context, network_interface_id,
                                private_ip_address=None,
                                secondary_private_ip_address_count=None,
                                allow_reassignment=False):
    # TODO(Alex): allow_reassignment is not supported at the moment
    network_interface = ec2utils.get_db_item(context, network_interface_id)
    subnet = db_api.get_item_by_id(context, network_interface['subnet_id'])
    neutron = clients.neutron(context)
    os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
    os_port = neutron.show_port(network_interface['os_id'])['port']
    subnet_ipnet = netaddr.IPNetwork(os_subnet['cidr'])
    fixed_ips = os_port['fixed_ips'] or []
    if private_ip_address is not None:
        for ip_address in private_ip_address:
            if netaddr.IPAddress(ip_address) not in subnet_ipnet:
                raise exception.InvalidParameterValue(
                    value=str(ip_address),
                    parameter='PrivateIpAddress',
                    reason='IP address is out of the subnet range')
            fixed_ips.append({'ip_address': str(ip_address)})
    elif secondary_private_ip_address_count > 0:
        for _i in range(secondary_private_ip_address_count):
            fixed_ips.append({'subnet_id': os_subnet['id']})
    try:
        neutron.update_port(os_port['id'],
                            {'port': {'fixed_ips': fixed_ips}})
    except neutron_exception.IpAddressGenerationFailureClient:
        raise exception.NetworkInterfaceLimitExceeded(
                    subnet_id=subnet['id'])
    except neutron_exception.IpAddressInUseClient:
        msg = _('Some of %(addresses)s is assigned, but move is not '
                'allowed.') % {'addresses': private_ip_address}
        raise exception.InvalidParameterValue(msg)
    except neutron_exception.BadRequest as ex:
        # NOTE(ft):AWS returns PrivateIpAddressLimitExceeded, but Neutron does
        # general InvalidInput (converted to BadRequest) in the same case.
        msg = _('Specified network interface parameters are invalid. '
                'Reason: %(reason)s') % {'reason': ex.message}
        raise exception.InvalidParameterValue(msg)
    return True
Example #52
0
def _reset_vpn_connections(context, neutron, cleaner, vpn_gateway,
                           subnets=None, route_tables=None,
                           vpn_connections=None):
    if not vpn_gateway['vpc_id']:
        return
    # TODO(ft): implement search filters in DB api
    vpn_connections = (vpn_connections or
                       [vpn for vpn in db_api.get_items(context, 'vpn')
                        if vpn['vpn_gateway_id'] == vpn_gateway['id']])
    if not vpn_connections:
        return
    subnets = (subnets or
               [subnet for subnet in db_api.get_items(context, 'subnet')
                if subnet['vpc_id'] == vpn_gateway['vpc_id']])
    if not subnets:
        return
    vpc = db_api.get_item_by_id(context, vpn_gateway['vpc_id'])
    customer_gateways = {cgw['id']: cgw
                         for cgw in db_api.get_items(context, 'cgw')}
    route_tables = route_tables or db_api.get_items(context, 'rtb')
    route_tables = {rtb['id']: rtb
                    for rtb in route_tables
                    if rtb['vpc_id'] == vpc['id']}
    route_tables_cidrs = {}
    for subnet in subnets:
        route_table_id = subnet.get('route_table_id', vpc['route_table_id'])
        if route_table_id not in route_tables_cidrs:
            route_tables_cidrs[route_table_id] = (
                _get_route_table_vpn_cidrs(route_tables[route_table_id],
                                           vpn_gateway, vpn_connections))
        cidrs = route_tables_cidrs[route_table_id]
        for vpn_conn in vpn_connections:
            if vpn_conn['id'] in cidrs:
                _set_subnet_vpn(
                    context, neutron, cleaner, subnet, vpn_conn,
                    customer_gateways[vpn_conn['customer_gateway_id']],
                    cidrs[vpn_conn['id']])
            else:
                _delete_subnet_vpn(context, neutron, cleaner, subnet, vpn_conn)
Example #53
0
def delete_subnet(context, subnet_id):
    subnet = ec2utils.get_db_item(context, subnet_id)
    vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
    network_interfaces = network_interface_api.describe_network_interfaces(
        context,
        filter=[{'name': 'subnet-id',
                 'value': [subnet_id]}])['networkInterfaceSet']
    if network_interfaces:
        msg = _("The subnet '%(subnet_id)s' has dependencies and "
                "cannot be deleted.") % {'subnet_id': subnet_id}
        raise exception.DependencyViolation(msg)
    neutron = clients.neutron(context)
    with common.OnCrashCleaner() as cleaner:
        db_api.delete_item(context, subnet['id'])
        cleaner.addCleanup(db_api.restore_item, context, 'subnet', subnet)
        vpn_gateway_api._stop_vpn_in_subnet(context, neutron, cleaner, subnet)
        try:
            neutron.remove_interface_router(vpc['os_id'],
                                            {'subnet_id': subnet['os_id']})
        except neutron_exception.NotFound:
            pass
        cleaner.addCleanup(neutron.add_interface_router,
                           vpc['os_id'],
                           {'subnet_id': subnet['os_id']})
        try:
            os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
        except neutron_exception.NotFound:
            pass
        else:
            try:
                neutron.delete_network(os_subnet['network_id'])
            except neutron_exception.NetworkInUseClient as ex:
                LOG.warning(_('Failed to delete network %(os_id)s during '
                              'deleting Subnet %(id)s. Reason: %(reason)s'),
                            {'id': subnet['id'],
                             'os_id': os_subnet['network_id'],
                             'reason': ex.message})

    return True
def detach_network_interface(context, attachment_id, force=None):
    network_interface = db_api.get_item_by_id(
            context, ec2utils.change_ec2_id_kind(attachment_id, 'eni'))
    if not network_interface or 'instance_id' not in network_interface:
        raise exception.InvalidAttachmentIDNotFound(id=attachment_id)
    if network_interface['device_index'] == 0:
        raise exception.OperationNotPermitted(
            _('The network interface at device index 0 cannot be detached.'))
    neutron = clients.neutron(context)
    os_port = neutron.show_port(network_interface['os_id'])['port']
    with common.OnCrashCleaner() as cleaner:
        instance_id = network_interface['instance_id']
        device_index = network_interface['device_index']
        attach_time = network_interface['attach_time']
        delete_on_termination = network_interface['delete_on_termination']
        _detach_network_interface_item(context, network_interface)
        cleaner.addCleanup(_attach_network_interface_item,
                           context, network_interface, instance_id,
                           device_index, attach_time, delete_on_termination)
        neutron.update_port(os_port['id'],
                            {'port': {'device_id': '',
                                      'device_owner': ''}})
    return True
Example #55
0
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
Example #56
0
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_index, old_route = next(
            ((i, r) for i, r in enumerate(route_table['routes'])
             if r['destination_cidr_block'] == destination_cidr_block),
            (None, None))
        if route_index is None:
            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)
        else:
            del route_table['routes'][route_index]

    if gateway_id:
        gateway = ec2utils.get_db_item(context, gateway_id)
        if gateway.get('vpc_id') != route_table['vpc_id']:
            if ec2utils.get_ec2_id_kind(gateway_id) == 'vgw':
                raise exception.InvalidGatewayIDNotFound(id=gateway['id'])
            else:  # igw
                raise exception.InvalidParameterValue(
                    _('Route table %(rtb_id)s and network gateway %(igw_id)s '
                      'belong to different networks') %
                    {'rtb_id': route_table_id,
                     'igw_id': gateway_id})
        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
    update_target = _get_route_target(route)

    if do_replace:
        idempotent_call = False
        old_target = _get_route_target(old_route)
        if old_target != update_target:
            update_target = None
    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, cleaner, route_table,
                                             update_target=update_target)

    return True
Example #57
0
def _format_route_table(context, route_table, is_main=False,
                        associated_subnet_ids=[],
                        gateways={},
                        network_interfaces={},
                        vpn_connections_by_gateway_id={}):
    vpc_id = route_table['vpc_id']
    ec2_route_table = {
        'routeTableId': route_table['id'],
        'vpcId': vpc_id,
        'routeSet': [],
        'propagatingVgwSet': [
            {'gatewayId': vgw_id}
            for vgw_id in route_table.get('propagating_gateways', [])],
        # 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)

    for vgw_id in route_table.get('propagating_gateways', []):
        vgw = gateways.get(vgw_id)
        if vgw and vgw_id in vpn_connections_by_gateway_id:
            cidrs = set()
            vpn_connections = vpn_connections_by_gateway_id[vgw_id]
            for vpn_connection in vpn_connections:
                cidrs.update(vpn_connection['cidrs'])
            state = 'active' if vgw['vpc_id'] == vpc_id else 'blackhole'
            for cidr in cidrs:
                ec2_route = {'gatewayId': vgw_id,
                             'destinationCidrBlock': cidr,
                             'state': state,
                             'origin': 'EnableVgwRoutePropagation'}
                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