def get_details(self): """Return subnet data as a SpecificSubnetRequest""" # get the pool from the backend try: pool_details = self.nsxlib_ipam.get(self._nsx_pool_id) except Exception as e: msg = _('Failed to get details for nsx pool: %(id)s: ' '%(e)s') % { 'id': self._nsx_pool_id, 'e': e } raise ipam_exc.IpamValueInvalid(message=msg) first_range = pool_details.get('subnets', [None])[0] if not first_range: msg = _('Failed to get details for nsx pool: %(id)s') % { 'id': self._nsx_pool_id } raise ipam_exc.IpamValueInvalid(message=msg) cidr = first_range.get('cidr') gateway_ip = first_range.get('gateway_ip') pools = [] for subnet in pool_details.get('subnets', []): for ip_range in subnet.get('allocation_ranges', []): pools.append( netaddr.IPRange(ip_range.get('start'), ip_range.get('end'))) return ipam_req.SpecificSubnetRequest(self._tenant_id, self._subnet_id, cidr, gateway_ip=gateway_ip, allocation_pools=pools)
def _validate_with_subnet(self, subnet_cidr): if self.allocation_pools: if subnet_cidr.version != self.allocation_pools[0].version: raise ipam_exc.IpamValueInvalid( _("allocation_pools use the wrong ip version")) for pool in self.allocation_pools: if pool not in subnet_cidr: raise ipam_exc.IpamValueInvalid( _("allocation_pools are not in the subnet"))
def allocate_backend_pool(self, subnet_request): """Create a pool on the NSX backend and return its ID""" if subnet_request.allocation_pools: ranges = [ {'ipRangeDto': {'startAddress': netaddr.IPAddress(pool.first), 'endAddress': netaddr.IPAddress(pool.last)}} for pool in subnet_request.allocation_pools] else: ranges = [] request = {'ipamAddressPool': # max name length on backend is 255, so there is no problem here {'name': 'subnet_' + subnet_request.subnet_id, 'prefixLength': subnet_request.prefixlen, 'gateway': subnet_request.gateway_ip, 'ipRanges': ranges}} try: response = self._vcns.create_ipam_ip_pool(request) nsx_pool_id = response[1] except vc_exc.VcnsApiException as e: msg = _('Failed to create subnet IPAM: %s') % e raise ipam_exc.IpamValueInvalid(message=msg) return nsx_pool_id
def update_backend_pool(self, nsx_pool_id, subnet_request): update_args = { 'cidr': self._get_cidr_from_request(subnet_request), 'allocation_ranges': self._get_ranges_from_request(subnet_request), 'gateway_ip': subnet_request.gateway_ip } try: self.nsxlib_ipam.update(nsx_pool_id, **update_args) except nsx_lib_exc.ManagerError as e: LOG.error( "NSX IPAM failed to update pool %(id)s: " " %(e)s; code %(code)s", { 'e': e, 'id': nsx_pool_id, 'code': e.error_code }) if (e.error_code == error.ERR_CODE_IPAM_RANGE_MODIFY or e.error_code == error.ERR_CODE_IPAM_RANGE_DELETE or e.error_code == error.ERR_CODE_IPAM_RANGE_SHRUNK): # The change is not allowed: already allocated IPs out of # the new range raise ipam_exc.InvalidSubnetRequest( reason=_("Already allocated IPs outside of the updated " "pools")) except Exception as e: # unexpected error msg = _('Failed to update subnet IPAM: %s') % e raise ipam_exc.IpamValueInvalid(message=msg)
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
def _validate_with_subnet(self, subnet_cidr): if self.gateway_ip and cfg.CONF.force_gateway_on_subnet: gw_ip = netaddr.IPAddress(self.gateway_ip) if (gw_ip.version == 4 or (gw_ip.version == 6 and not gw_ip.is_link_local())): if self.gateway_ip not in subnet_cidr: raise ipam_exc.IpamValueInvalid( _("gateway_ip %s is not in the subnet") % self.gateway_ip) if self.allocation_pools: if subnet_cidr.version != self.allocation_pools[0].version: raise ipam_exc.IpamValueInvalid( _("allocation_pools use the wrong ip version")) for pool in self.allocation_pools: if pool not in subnet_cidr: raise ipam_exc.IpamValueInvalid( _("allocation_pools are not in the subnet"))
def _validate_gateway_ip_in_subnet(subnet_cidr, gateway_ip): if not gateway_ip: return if ipam_utils.check_gateway_invalid_in_subnet(subnet_cidr, gateway_ip): raise ipam_exc.IpamValueInvalid( _('Gateway IP %(gateway_ip)s cannot be allocated in CIDR ' '%(subnet_cidr)s' % { 'gateway_ip': gateway_ip, 'subnet_cidr': subnet_cidr }))
def _get_driver_for_project(self, project): plugin_type = tvd_utils.get_tvd_plugin_type_for_project(project) if not self.drivers.get(plugin_type): LOG.error( "Project %(project)s with plugin %(plugin)s has no " "support for IPAM", { 'project': project, 'plugin': plugin_type }) raise ipam_exc.IpamValueInvalid(message="IPAM driver not found") return self.drivers[plugin_type]
def allocate_backend_pool(self, subnet_request): """Create a pool on the NSX backend and return its ID""" # name/description length on backend is long, so there is no problem name = 'subnet_' + subnet_request.subnet_id description = 'OS IP pool for subnet ' + subnet_request.subnet_id try: response = self.nsxlib_ipam.create( self._get_cidr_from_request(subnet_request), allocation_ranges=self._get_ranges_from_request( subnet_request), display_name=name, description=description, gateway_ip=subnet_request.gateway_ip) nsx_pool_id = response['id'] except Exception as e: #TODO(asarfaty): handle specific errors msg = _('Failed to create subnet IPAM: %s') % e raise ipam_exc.IpamValueInvalid(message=msg) return nsx_pool_id
def _raise_update_not_supported(self): msg = _('Changing the subnet range or gateway is not supported') raise ipam_exc.IpamValueInvalid(message=msg)