Ejemplo n.º 1
0
    def _generate_ip(self, session, prefer_next=False):
        """Generate an IP address from the set of available addresses."""
        ip_allocations = netaddr.IPSet()
        for ipallocation in self.subnet_manager.list_allocations(session):
            ip_allocations.add(netaddr.IPAddress(ipallocation.ip_address))

        for ip_pool in self.subnet_manager.list_pools(session):
            ip_set = netaddr.IPSet()
            ip_set.add(netaddr.IPRange(ip_pool.first_ip, ip_pool.last_ip))
            av_set = ip_set.difference(ip_allocations)
            if av_set.size == 0:
                continue

            if prefer_next:
                window = 1
            else:
                # Compute a value for the selection window
                window = min(av_set.size, 10)
            ip_index = random.randint(1, window)
            candidate_ips = list(itertools.islice(av_set, ip_index))
            allocated_ip = candidate_ips[-1]
            return str(allocated_ip), ip_pool.id

        raise ipam_exc.IpAddressGenerationFailure(
            subnet_id=self.subnet_manager.neutron_id)
Ejemplo n.º 2
0
 def backend_allocate(self, address_request):
     try:
         # allocate a specific IP
         if isinstance(address_request, ipam_req.SpecificAddressRequest):
             # This handles both specific and automatic address requests
             ip_address = str(address_request.address)
             self._vcns.allocate_ipam_ip_from_pool(self._nsx_pool_id,
                                                   ip_addr=ip_address)
         else:
             # Allocate any free IP
             response = self._vcns.allocate_ipam_ip_from_pool(
                 self._nsx_pool_id)[1]
             # get the ip from the response
             root = et.fromstring(response)
             ip_address = root.find('ipAddress').text
     except vc_exc.VcnsApiException as e:
         # handle backend failures
         error_code = self._get_vcns_error_code(e)
         if error_code == constants.NSX_ERROR_IPAM_ALLOCATE_IP_USED:
             # This IP is already in use
             raise ipam_exc.IpAddressAlreadyAllocated(
                 ip=ip_address, subnet_id=self._subnet_id)
         if error_code == constants.NSX_ERROR_IPAM_ALLOCATE_ALL_USED:
             # No more IP addresses available on the pool
             raise ipam_exc.IpAddressGenerationFailure(
                 subnet_id=self._subnet_id)
         else:
             raise ipam_exc.IPAllocationFailed()
     return ip_address
Ejemplo n.º 3
0
 def backend_allocate(self, address_request):
     try:
         # allocate a specific IP
         if isinstance(address_request, ipam_req.SpecificAddressRequest):
             # This handles both specific and automatic address requests
             ip_address = str(address_request.address)
             # If this is the subnet gateway IP - no need to allocate it
             subnet = self.get_details()
             if str(subnet.gateway_ip) == ip_address:
                 LOG.info("Skip allocation of gateway-ip for pool %s",
                          self._nsx_pool_id)
                 return ip_address
         else:
             # Allocate any free IP
             ip_address = None
         response = self.nsxlib_ipam.allocate(self._nsx_pool_id,
                                              ip_addr=ip_address)
         ip_address = response['allocation_id']
     except nsx_lib_exc.ManagerError as e:
         LOG.error(
             "NSX IPAM failed to allocate ip %(ip)s of subnet "
             "%(id)s: %(e)s; code %(code)s", {
                 'e': e,
                 'ip': ip_address,
                 'id': self._subnet_id,
                 'code': e.error_code
             })
         if e.error_code == error.ERR_CODE_IPAM_POOL_EXHAUSTED:
             # No more IP addresses available on the pool
             raise ipam_exc.IpAddressGenerationFailure(
                 subnet_id=self._subnet_id)
         if e.error_code == error.ERR_CODE_IPAM_SPECIFIC_IP:
             # The NSX backend  does not support allocation of specific IPs
             # prior to version 2.0.
             msg = (_("NSX-V3 IPAM driver does not support allocation of a "
                      "specific ip %s for port") % ip_address)
             raise NotImplementedError(msg)
         if e.error_code == error.ERR_CODE_IPAM_IP_ALLOCATED:
             # This IP is already in use
             raise ipam_exc.IpAddressAlreadyAllocated(
                 ip=ip_address, subnet_id=self._subnet_id)
         if e.error_code == error.ERR_CODE_OBJECT_NOT_FOUND:
             msg = (_("NSX-V3 IPAM failed to allocate: pool %s was not "
                      "found") % self._nsx_pool_id)
             raise ipam_exc.IpamValueInvalid(message=msg)
         else:
             # another backend error
             raise ipam_exc.IPAllocationFailed()
     except Exception as e:
         LOG.error(
             "NSX IPAM failed to allocate ip %(ip)s of subnet "
             "%(id)s: %(e)s", {
                 'e': e,
                 'ip': ip_address,
                 'id': self._subnet_id
             })
         # handle unexpected failures
         raise ipam_exc.IPAllocationFailed()
     return ip_address
Ejemplo n.º 4
0
    def allocate_ip_from_pool(self, subnet_id, allocation_pools, mac,
                              port_id=None, port_tenant_id=None,
                              device_id=None, device_owner=None):
        hostname = uuidutils.generate_uuid()

        port_tenant_name = self.ib_cxt.get_tenant_name(port_tenant_id)
        ea_ip_address = eam.get_ea_for_ip(self.ib_cxt.user_id,
                                          port_tenant_id,
                                          port_tenant_name,
                                          self.ib_cxt.network,
                                          port_id,
                                          device_id,
                                          device_owner)

        dns_view = self.ib_cxt.mapping.dns_view
        zone_auth = self.pattern_builder.get_zone_name(
            is_external=self.ib_cxt.network_is_external)
        allocated_ip = None

        ip_alloc = (self.ib_cxt.dhcp_port_ip_alloc
                    if device_owner == n_const.DEVICE_OWNER_DHCP
                    else self.ib_cxt.ip_alloc)
        for pool in allocation_pools:
            first_ip = pool['start']
            last_ip = pool['end']
            try:
                allocated_ip = ip_alloc.allocate_ip_from_range(
                    self.ib_cxt.mapping.network_view,
                    dns_view,
                    zone_auth,
                    hostname,
                    mac,
                    first_ip,
                    last_ip,
                    ea_ip_address)
                if allocated_ip:
                    break
            except ib_exc.InfobloxCannotAllocateIp as err:
                LOG.info("Failed to allocate IP from range (%s-%s)"
                         "with error: %r." % (first_ip, last_ip, err))
                continue

            except ib_exc.InfobloxCannotCreateObject as err:
                LOG.info("Failed to create IP from range (%s-%s)"
                         "with error: %r." % (first_ip, last_ip, err))
                continue

        if allocated_ip:
            LOG.info('IP address allocated on Infoblox NIOS: %s',
                     allocated_ip)
            if device_owner == n_const.DEVICE_OWNER_DHCP:
                self.ib_cxt.update_nameservers(allocated_ip)
        else:
            LOG.info("All IPs from subnet %(subnet_id)s allocated",
                     {'subnet_id': subnet_id})
            raise ipam_exc.IpAddressGenerationFailure(subnet_id=subnet_id)

        return allocated_ip
Ejemplo n.º 5
0
    def create_vmipreservation(self, address_request, vsdclient, is_l2,
                               nuage_id):
        ip_type = self._get_ip_type()
        try:
            ipv4_address = ipv6_address = None
            if isinstance(address_request, ipam_req.SpecificAddressRequest):
                # This handles both specific and automatic address requests
                # Check availability of requested IP
                ip_address = str(address_request.address)
                self._verify_ip(self._context, ip_address)
                if ip_type == 'IPV4':
                    ipv4_address = ip_address
                else:
                    ipv6_address = ip_address

                vsdclient.create_vm_ip_reservation(is_l2,
                                                   nuage_id,
                                                   ip_type=ip_type,
                                                   ipv4_address=ipv4_address,
                                                   ipv6_address=ipv6_address)

            else:
                # Calculate allocation pools
                allocation_pools = self.subnet_manager.list_pools(
                    self._context)
                ipreservation = vsdclient.create_vm_ip_reservation(
                    is_l2,
                    nuage_id,
                    ip_type=ip_type,
                    allocation_pools=allocation_pools)
                if ip_type == 'IPV4':
                    ipv4_address = ip_address = ipreservation['ipv4_address']
                else:
                    ipv4_address = ip_address = ipreservation['ipv6_address']
        except restproxy.RESTProxyError as e:
            if e.vsd_code == vsd_constants.VSD_DUPLICATE_VMIPRESERVATION:
                reason = ('The requested ip address is already reserved '
                          'on VSD by another entity.')
                raise ipam_exc.InvalidAddressRequest(reason=reason)
            if e.vsd_code == vsd_constants.VSD_SUBNET_FULL:
                raise ipam_exc.IpAddressGenerationFailure(
                    subnet_id=self._subnet_id)
            elif e.vsd_code == vsd_constants.VSD_IP_IN_USE_ERR_CODE:
                raise ipam_exc.InvalidAddressRequest(reason=str(e))
            raise

        def rollback(db_api_conn):
            vsdclient.delete_vm_ip_reservation(is_l2, nuage_id, ipv4_address,
                                               ipv6_address)

        event.listen(self._context.session, "after_rollback", rollback)
        return ip_address
Ejemplo n.º 6
0
 def _try_generate_ip(self, session):
     """Generate an IP address from availability ranges."""
     ip_range = self.subnet_manager.get_first_range(session)
     if not ip_range:
         LOG.debug("All IPs from subnet %(subnet_id)s allocated",
                   {'subnet_id': self.subnet_manager.neutron_id})
         raise ipam_exc.IpAddressGenerationFailure(
             subnet_id=self.subnet_manager.neutron_id)
     # A suitable range was found. Return IP address.
     ip_address = ip_range['first_ip']
     LOG.debug("Allocated IP - %(ip_address)s from range "
               "[%(first_ip)s; %(last_ip)s]",
               {'ip_address': ip_address,
                'first_ip': ip_address,
                'last_ip': ip_range['last_ip']})
     return ip_address, ip_range['allocation_pool_id']
Ejemplo n.º 7
0
    def _generate_ips(self, context, prefer_next=False, num_addresses=1):
        """Generate a set of IPs from the set of available addresses."""
        ip_allocations = netaddr.IPSet()
        for ipallocation in self.subnet_manager.list_allocations(context):
            ip_allocations.add(ipallocation.ip_address)

        for ip_pool in self.subnet_manager.list_pools(context):
            ip_set = netaddr.IPSet()
            ip_set.add(netaddr.IPRange(ip_pool.first_ip, ip_pool.last_ip))
            av_set = ip_set.difference(ip_allocations)
            if av_set.size == 0:
                continue

            if av_set.size < num_addresses:
                # Not enough addresses in pool to perform validation
                # TODO(njohnston): How to handle when there are enough IPs but
                # not enough in a single pool to satisfy the request?
                continue

            if prefer_next:
                allocated_ip_pool = list(
                    itertools.islice(av_set, num_addresses))
                return [
                    str(allocated_ip) for allocated_ip in allocated_ip_pool
                ]

            window = min(av_set.size, MAX_WIN)

            # NOTE(gryf): If there is more than one address, make the window
            # bigger, so that are chances to fulfill demanded amount of IPs.
            if num_addresses > 1:
                window = min(av_set.size, num_addresses * MULTIPLIER,
                             MAX_WIN_MULTI)

            if window < num_addresses:
                continue
            else:
                # Maximize randomness by using the random module's built in
                # sampling function
                av_ips = list(itertools.islice(av_set, 0, window))
                allocated_ip_pool = random.sample(av_ips, num_addresses)
            return [str(allocated_ip) for allocated_ip in allocated_ip_pool]

        raise ipam_exc.IpAddressGenerationFailure(
            subnet_id=self.subnet_manager.neutron_id)
Ejemplo n.º 8
0
    def _generate_ips(self, context, prefer_next=False, num_addresses=1):
        """Generate a set of IPs from the set of available addresses."""
        allocated_ips = []
        requested_num_addresses = num_addresses

        allocations = self.subnet_manager.list_allocations(context)
        # It is better not to use 'netaddr.IPSet.add',
        # because _compact_single_network in 'IPSet.add'
        # is quite time consuming.
        ip_allocations = netaddr.IPSet([
            netaddr.IPAddress(allocation.ip_address)
            for allocation in allocations
        ])

        for ip_pool in self.subnet_manager.list_pools(context):
            ip_set = netaddr.IPSet()
            ip_set.add(netaddr.IPRange(ip_pool.first_ip, ip_pool.last_ip))
            av_set = ip_set.difference(ip_allocations)
            if av_set.size == 0:
                continue

            if av_set.size < requested_num_addresses:
                # All addresses of the address pool are allocated
                # for the first time and the remaining addresses
                # will be allocated in the next address pools.
                allocated_num_addresses = av_set.size
            else:
                # All expected addresses can be assigned in this loop.
                allocated_num_addresses = requested_num_addresses

            if prefer_next:
                allocated_ip_pool = list(
                    itertools.islice(av_set, allocated_num_addresses))
                allocated_ips.extend(
                    [str(allocated_ip) for allocated_ip in allocated_ip_pool])

                requested_num_addresses -= allocated_num_addresses
                if requested_num_addresses:
                    # More addresses need to be allocated in the next loop.
                    continue
                return allocated_ips

            window = min(av_set.size, MAX_WIN)

            # NOTE(gryf): If there is more than one address, make the window
            # bigger, so that are chances to fulfill demanded amount of IPs.
            if allocated_num_addresses > 1:
                window = min(av_set.size, allocated_num_addresses * MULTIPLIER,
                             MAX_WIN_MULTI)

            if window < allocated_num_addresses:
                continue
            # Maximize randomness by using the random module's built in
            # sampling function
            av_ips = list(itertools.islice(av_set, 0, window))
            allocated_ip_pool = random.sample(av_ips, allocated_num_addresses)
            allocated_ips.extend(
                [str(allocated_ip) for allocated_ip in allocated_ip_pool])

            requested_num_addresses -= allocated_num_addresses
            if requested_num_addresses:
                # More addresses need to be allocated in the next loop.
                continue

            return allocated_ips

        raise ipam_exc.IpAddressGenerationFailure(
            subnet_id=self.subnet_manager.neutron_id)