예제 #1
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
예제 #2
0
def create_network_interface(context,
                             subnet_id,
                             private_ip_address=None,
                             private_ip_addresses=None,
                             secondary_private_ip_address_count=None,
                             description=None,
                             security_group_id=None):
    subnet = ec2utils.get_db_item(context, subnet_id)
    if subnet is None:
        raise exception.InvalidSubnetIDNotFound(id=subnet_id)
    neutron = clients.neutron(context)
    os_subnet = neutron.show_subnet(subnet['os_id'])['subnet']
    # NOTE(Alex): Combine and check ip addresses. Neutron will accept
    # ip_address as a parameter for specified address and subnet_id for
    # address to auto-allocate.
    # TODO(Alex): Implement better diagnostics.
    subnet_ipnet = netaddr.IPNetwork(os_subnet['cidr'])
    if not private_ip_addresses:
        private_ip_addresses = []
    if private_ip_address is not None:
        private_ip_addresses.insert(0, {
            'private_ip_address': private_ip_address,
            'primary': True
        })
    primary_ip = None
    fixed_ips = []
    for ip in private_ip_addresses:
        ip_address = netaddr.IPAddress(ip['private_ip_address'])
        if ip_address not in subnet_ipnet:
            raise exception.InvalidParameterValue(
                value=str(ip_address),
                parameter='PrivateIpAddresses',
                reason='IP address is out of the subnet range')
        if ip.get('primary', False):
            if primary_ip is not None:
                raise exception.InvalidParameterValue(
                    value=str(ip_address),
                    parameter='PrivateIpAddresses',
                    reason='More than one primary ip is supplied')
            else:
                primary_ip = str(ip_address)
                fixed_ips.insert(0, {'ip_address': primary_ip})
        else:
            fixed_ips.append({'ip_address': str(ip_address)})
    if not fixed_ips and not secondary_private_ip_address_count:
        secondary_private_ip_address_count = 1
    if secondary_private_ip_address_count is None:
        secondary_private_ip_address_count = 0
    if secondary_private_ip_address_count > 0:
        for _i in range(secondary_private_ip_address_count):
            fixed_ips.append({'subnet_id': os_subnet['id']})
    vpc = db_api.get_item_by_id(context, subnet['vpc_id'])
    vpc_id = vpc['id']
    dhcp_options_id = vpc.get('dhcp_options_id', None)
    if not security_group_id:
        default_groups = security_group_api.describe_security_groups(
            context,
            filter=[{
                'name': 'vpc-id',
                'value': [vpc_id]
            }, {
                'name': 'group-name',
                'value': ['default']
            }])['securityGroupInfo']
        security_group_id = [
            default_group['groupId'] for default_group in default_groups
        ]
    security_groups = db_api.get_items_by_ids(context, security_group_id)
    if any(security_group['vpc_id'] != vpc['id']
           for security_group in security_groups):
        msg = _('You have specified two resources that belong to '
                'different networks.')
        raise exception.InvalidGroupNotFound(msg)
    os_groups = [security_group['os_id'] for security_group in security_groups]
    with common.OnCrashCleaner() as cleaner:
        os_port_body = {
            'port': {
                'network_id': os_subnet['network_id'],
                'security_groups': os_groups
            }
        }
        os_port_body['port']['fixed_ips'] = fixed_ips
        try:
            os_port = neutron.create_port(os_port_body)['port']
        except (neutron_exception.IpAddressGenerationFailureClient,
                neutron_exception.OverQuotaClient):
            raise exception.InsufficientFreeAddressesInSubnet()
        except (neutron_exception.IpAddressInUseClient,
                neutron_exception.BadRequest) as ex:
            # NOTE(ft): AWS returns InvalidIPAddress.InUse for a primary IP
            # address, but InvalidParameterValue for secondary one.
            # 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)
        cleaner.addCleanup(neutron.delete_port, os_port['id'])
        if primary_ip is None:
            primary_ip = os_port['fixed_ips'][0]['ip_address']
        network_interface = db_api.add_item(
            context, 'eni', {
                'os_id': os_port['id'],
                'vpc_id': subnet['vpc_id'],
                'subnet_id': subnet['id'],
                'description': description,
                'private_ip_address': primary_ip
            })
        cleaner.addCleanup(db_api.delete_item, context,
                           network_interface['id'])

        network_interface_id = network_interface['id']
        neutron.update_port(os_port['id'],
                            {'port': {
                                'name': network_interface_id
                            }})
        if dhcp_options_id:
            dhcp_options._add_dhcp_opts_to_port(
                context, db_api.get_item_by_id(context, dhcp_options_id),
                network_interface, os_port)
    security_groups = security_group_api._format_security_groups_ids_names(
        context)
    return {
        'networkInterface':
        _format_network_interface(context,
                                  network_interface,
                                  os_port,
                                  security_groups=security_groups)
    }