def _delete_flip(context, id, address_type): filters = {'address_type': address_type, '_deallocated': False} flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not flip: raise q_exc.FloatingIpNotFound(id=id) current_ports = flip.ports if address_type == ip_types.FLOATING: if current_ports: current_ports = [flip.ports[0]] elif address_type == ip_types.SCALING: current_ports = flip.ports context.session.begin() try: strategy_name = flip.network.get('ipam_strategy') ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name) ipam_driver.deallocate_ip_address(context, flip) if current_ports: db_api.port_disassociate_ip(context, current_ports, flip) if flip.fixed_ips: db_api.floating_ip_disassociate_all_fixed_ips(context, flip) context.session.commit() except Exception: context.session.rollback() raise try: driver = registry.DRIVER_REGISTRY.get_driver() driver.remove_floating_ip(flip) except Exception as e: LOG.error('There was an error when trying to delete the floating ip ' 'on the unicorn API. The ip has been cleaned up, but ' 'may need to be handled manually in the unicorn API. ' 'Error: %s' % e.message) # alexm: Notify from this method because we don't have the flip object # in the callers billing.notify(context, billing.IP_DISASSOC, flip)
def _delete_flip(context, id, address_type): filters = {'address_type': address_type, '_deallocated': False} flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not flip: raise q_exc.FloatingIpNotFound(id=id) current_ports = flip.ports if address_type == ip_types.FLOATING: if current_ports: current_ports = [flip.ports[0]] elif address_type == ip_types.SCALING: current_ports = flip.ports context.session.begin() try: strategy_name = flip.network.get('ipam_strategy') ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name) ipam_driver.deallocate_ip_address(context, flip) if current_ports: db_api.port_disassociate_ip(context, current_ports, flip) if flip.fixed_ips: db_api.floating_ip_disassociate_all_fixed_ips(context, flip) context.session.commit() except Exception: context.session.rollback() raise try: driver = registry.DRIVER_REGISTRY.get_driver() driver.remove_floating_ip(flip) except Exception as e: LOG.error('There was an error when trying to delete the floating ip ' 'on the unicorn API. The ip has been cleaned up, but ' 'may need to be handled manually in the unicorn API. ' 'Error: %s' % e.message) # alexm: Notify from this method because we don't have the flip object # in the callers billing.notify(context, billing.IP_DISASSOC, flip)
def deallocate_ips_by_port(self, context, port=None, **kwargs): ips_to_remove = [] for addr in port["ip_addresses"]: if "ip_address" in kwargs: ip = kwargs["ip_address"] if ip != netaddr.IPAddress(int(addr["address"])): continue # Note: only deallocate ip if this is the # only port mapped ips_to_remove.append(addr) port["ip_addresses"] = list( set(port["ip_addresses"]) - set(ips_to_remove)) # NCP-1541: We don't need to track v6 IPs the same way. Also, we can't # delete them until we've removed the FK on the assoc record first, so # we have to flush the current state of the transaction. # NOTE(mdietz): this does increase traffic to the db because we need # to flush, fetch the records again and potentially make # another trip to deallocate each IP, but keeping our # indices smaller probably provides more value than the # cost # NOTE(aquillin): For floating IPs associated with the port, we do not # want to deallocate the IP or disassociate the IP from # the tenant, instead we will disassociate floating's # fixed IP address. context.session.flush() deallocated_ips = [] flip = None for ip in ips_to_remove: if ip["address_type"] in (ip_types.FLOATING, ip_types.SCALING): flip = ip else: if len(ip["ports"]) == 0: self.deallocate_ip_address(context, ip) deallocated_ips.append(ip.id) if flip: if flip.fixed_ips and len(flip.fixed_ips) == 1: # This is a FLIP or SCIP that is only associated with one # port and fixed_ip, so we can safely just disassociate all # and remove the flip from unicorn. db_api.floating_ip_disassociate_all_fixed_ips(context, flip) # NOTE(blogan): I'm not too happy about having do another # flush but some test runs showed inconsistent state based on # SQLAlchemy caching. context.session.add(flip) context.session.flush() billing.notify(context, billing.IP_DISASSOC, flip, **kwargs) driver = registry.DRIVER_REGISTRY.get_driver() driver.remove_floating_ip(flip) elif len(flip.fixed_ips) > 1: # This is a SCIP and we need to diassociate the one fixed_ip # from the SCIP and update unicorn with the remaining # ports and fixed_ips remaining_fixed_ips = [] for fix_ip in flip.fixed_ips: if fix_ip.id in deallocated_ips: db_api.floating_ip_disassociate_fixed_ip( context, flip, fix_ip) context.session.add(flip) context.session.flush() billing.notify(context, billing.IP_DISASSOC, flip, **kwargs) else: remaining_fixed_ips.append(fix_ip) port_fixed_ips = {} for fix_ip in remaining_fixed_ips: # NOTE(blogan): Since this is the flip's fixed_ips it # should be safe to assume there is only one port # associated with it. remaining_port = fix_ip.ports[0] port_fixed_ips[remaining_port.id] = { 'port': remaining_port, 'fixed_ip': fix_ip } driver = registry.DRIVER_REGISTRY.get_driver() driver.update_floating_ip(flip, port_fixed_ips)
def deallocate_ips_by_port(self, context, port=None, **kwargs): ips_to_remove = [] for addr in port["ip_addresses"]: if "ip_address" in kwargs: ip = kwargs["ip_address"] if ip != netaddr.IPAddress(int(addr["address"])): continue # Note: only deallocate ip if this is the # only port mapped ips_to_remove.append(addr) port["ip_addresses"] = list( set(port["ip_addresses"]) - set(ips_to_remove)) # NCP-1541: We don't need to track v6 IPs the same way. Also, we can't # delete them until we've removed the FK on the assoc record first, so # we have to flush the current state of the transaction. # NOTE(mdietz): this does increase traffic to the db because we need # to flush, fetch the records again and potentially make # another trip to deallocate each IP, but keeping our # indices smaller probably provides more value than the # cost # NOTE(aquillin): For floating IPs associated with the port, we do not # want to deallocate the IP or disassociate the IP from # the tenant, instead we will disassociate floating's # fixed IP address. context.session.flush() deallocated_ips = [] flip = None for ip in ips_to_remove: if ip["address_type"] in (ip_types.FLOATING, ip_types.SCALING): flip = ip else: if len(ip["ports"]) == 0: self.deallocate_ip_address(context, ip) deallocated_ips.append(ip.id) if flip: if flip.fixed_ips and len(flip.fixed_ips) == 1: # This is a FLIP or SCIP that is only associated with one # port and fixed_ip, so we can safely just disassociate all # and remove the flip from unicorn. db_api.floating_ip_disassociate_all_fixed_ips(context, flip) # NOTE(blogan): I'm not too happy about having do another # flush but some test runs showed inconsistent state based on # SQLAlchemy caching. context.session.add(flip) context.session.flush() notify(context, 'ip.disassociate', flip) driver = registry.DRIVER_REGISTRY.get_driver() driver.remove_floating_ip(flip) elif len(flip.fixed_ips) > 1: # This is a SCIP and we need to diassociate the one fixed_ip # from the SCIP and update unicorn with the remaining # ports and fixed_ips remaining_fixed_ips = [] for fix_ip in flip.fixed_ips: if fix_ip.id in deallocated_ips: db_api.floating_ip_disassociate_fixed_ip( context, flip, fix_ip) context.session.add(flip) context.session.flush() notify(context, 'ip.disassociate', flip) else: remaining_fixed_ips.append(fix_ip) port_fixed_ips = {} for fix_ip in remaining_fixed_ips: # NOTE(blogan): Since this is the flip's fixed_ips it # should be safe to assume there is only one port # associated with it. remaining_port = fix_ip.ports[0] port_fixed_ips[remaining_port.id] = { 'port': remaining_port, 'fixed_ip': fix_ip } driver = registry.DRIVER_REGISTRY.get_driver() driver.update_floating_ip(flip, port_fixed_ips)