def validate_static_ip(self, ip): """Validates that the requested IP address is acceptable for allocation in this `Subnet` (assuming it has not already been allocated). Raises `StaticIPAddressUnavailable` if the address is not acceptable. Does not consider whether or not the IP address is already allocated, only whether or not it is in the proper network and range. :raises StaticIPAddressUnavailable: If the IP address specified is not available for allocation. """ if ip not in self.get_ipnetwork(): raise StaticIPAddressOutOfRange( "%s is not within subnet CIDR: %s" % (ip, self.cidr)) for iprange in self.get_reserved_maasipset(): if ip in iprange: raise StaticIPAddressUnavailable( "%s is within the reserved range from %s to %s" % (ip, IPAddress(iprange.first), IPAddress(iprange.last))) for iprange in self.get_dynamic_maasipset(): if ip in iprange: raise StaticIPAddressUnavailable( "%s is within the dynamic range from %s to %s" % (ip, IPAddress(iprange.first), IPAddress(iprange.last)))
def allocate_new( self, subnet=None, alloc_type=IPADDRESS_TYPE.AUTO, user=None, requested_address=None, exclude_addresses=None, ): """Return a new StaticIPAddress. :param subnet: The subnet from which to allocate the address. :param alloc_type: What sort of IP address to allocate in the range of choice in IPADDRESS_TYPE. :param user: If providing a user, the alloc_type must be IPADDRESS_TYPE.USER_RESERVED. Conversely, if the alloc_type is IPADDRESS_TYPE.USER_RESERVED the user must also be provided. AssertionError is raised if these conditions are not met. :param requested_address: Optional IP address that the caller wishes to use instead of being allocated one at random. :param exclude_addresses: A list of addresses which MUST NOT be used. All IP parameters can be strings or netaddr.IPAddress. """ # This check for `alloc_type` is important for later on. We rely on # detecting IntegrityError as a sign than an IP address is already # taken, and so we must first eliminate all other possible causes. self._verify_alloc_type(alloc_type, user) if subnet is None: if requested_address: subnet = Subnet.objects.get_best_subnet_for_ip( requested_address) else: raise StaticIPAddressOutOfRange( "Could not find an appropriate subnet.") if requested_address is None: requested_address = subnet.get_next_ip_for_allocation( exclude_addresses=exclude_addresses) return self._attempt_allocation_of_free_address(requested_address, alloc_type, user=user, subnet=subnet) else: requested_address = IPAddress(requested_address) # Circular imports. from maasserver.models import StaticIPAddress if (StaticIPAddress.objects.filter( ip=str(requested_address)).exclude( alloc_type=IPADDRESS_TYPE.DISCOVERED).count() > 0): raise StaticIPAddressUnavailable( "The IP address %s is already in use." % requested_address) subnet.validate_static_ip(requested_address) return self._attempt_allocation(requested_address, alloc_type, user=user, subnet=subnet)