def get_floatingip(context, id, fields=None): """Retrieve a floating IP. :param context: neutron api request context. :param id: The UUID of the floating IP. :param fields: a list of strings that are valid keys in a floating IP dictionary as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Only these fields will be returned. :returns: Dictionary containing details for the floating IP. If values are declared in the fields parameter, then only those keys will be present. """ LOG.info('get_floatingip %s for tenant %s' % (id, context.tenant_id)) filters = {'address_type': ip_types.FLOATING, '_deallocated': False} floating_ip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not floating_ip: raise q_exc.FloatingIpNotFound(id=id) return v._make_floating_ip_dict(floating_ip)
def get_floatingips(context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): """Retrieve a list of floating ips. :param context: neutron api request context. :param filters: a dictionary with keys that are valid keys for a floating ip as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Values in this dictionary are an iterable containing values that will be used for an exact match comparison for that value. Each result returned by this function will have matched one of the values for each key in filters. :param fields: a list of strings that are valid keys in a floating IP dictionary as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Only these fields will be returned. :returns: List of floating IPs that are accessible to the tenant who submits the request (as indicated by the tenant id of the context) as well as any filters. """ LOG.info("get_floatingips for tenant %s filters %s fields %s" % (context.tenant_id, filters, fields)) if filters is None: filters = {} filters["_deallocated"] = False filters["address_type"] = ip_types.FLOATING floating_ips = db_api.floating_ip_find(context, scope=db_api.ALL, **filters) return [v._make_floating_ip_dict(flip) for flip in floating_ips]
def get_floatingip(context, id, fields=None): """Retrieve a floating IP. :param context: neutron api request context. :param id: The UUID of the floating IP. :param fields: a list of strings that are valid keys in a floating IP dictionary as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Only these fields will be returned. :returns: Dictionary containing details for the floating IP. If values are declared in the fields parameter, then only those keys will be present. """ LOG.info('get_floatingip %s for tenant %s' % (id, context.tenant_id)) filters = {'address_type': ip_types.FLOATING, '_deallocated': False} floating_ip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not floating_ip: raise qex.FloatingIpNotFound(id=id) return v._make_floating_ip_dict(floating_ip)
def get_floatingips(context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): """Retrieve a list of floating ips. :param context: neutron api request context. :param filters: a dictionary with keys that are valid keys for a floating ip as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Values in this dictionary are an iterable containing values that will be used for an exact match comparison for that value. Each result returned by this function will have matched one of the values for each key in filters. :param fields: a list of strings that are valid keys in a floating IP dictionary as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. Only these fields will be returned. :returns: List of floating IPs that are accessible to the tenant who submits the request (as indicated by the tenant id of the context) as well as any filters. """ LOG.info('get_floatingips for tenant %s filters %s fields %s' % (context.tenant_id, filters, fields)) if filters is None: filters = {} filters['_deallocated'] = False filters['address_type'] = ip_types.FLOATING floating_ips = db_api.floating_ip_find(context, scope=db_api.ALL, **filters) return [v._make_floating_ip_dict(flip) for flip in floating_ips]
def delete_floatingip(context, id): """deallocate a floating IP. :param context: neutron api request context. :param id: id of the floating ip """ LOG.info('delete_floatingip %s for tenant %s' % (id, context.tenant_id)) filters = {'address_type': ip_types.FLOATING, '_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 current_port = None if current_ports and len(current_ports) > 0: current_port = current_ports[0] 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_port: flip = db_api.port_disassociate_ip(context, [current_port], flip) if flip.fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip(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)
def delete_floatingip(context, id): """deallocate a floating IP. :param context: neutron api request context. :param id: id of the floating ip """ LOG.info('delete_floatingip %s for tenant %s' % (id, context.tenant_id)) filters = {'address_type': ip_types.FLOATING, '_deallocated': False} flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not flip: raise qex.FloatingIpNotFound(id=id) current_ports = flip.ports current_port = None if current_ports and len(current_ports) > 0: current_port = current_ports[0] 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_port: flip = db_api.port_disassociate_ip(context, [current_port], flip) if flip.fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip(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)
def delete_floatingip(context, id): LOG.info("delete_floatingip %s for tenant %s" % (id, context.tenant_id)) filters = {"address_type": ip_types.FLOATING, "_deallocated": False} floating_ip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not floating_ip: raise quark_exceptions.FloatingIpNotFound(id=id) driver_type = CONF.QUARK.default_floating_ip_driver driver = registry.DRIVER_REGISTRY.get_driver(driver_type) driver.remove_floating_ip(floating_ip) strategy_name = floating_ip.network.get("ipam_strategy") ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name) ipam_driver.deallocate_ip_address(context, floating_ip)
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_floatingip(context, id): """deallocate a floating IP. :param context: neutron api request context. :param id: id of the floating ip """ LOG.info('delete_floatingip %s for tenant %s' % (id, context.tenant_id)) filters = {'address_type': ip_types.FLOATING, '_deallocated': False} flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters) if not flip: raise qex.FloatingIpNotFound(id=id) current_ports = flip.ports current_port = None if current_ports and len(current_ports) > 0: current_port = current_ports[0] with context.session.begin(): 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_port: flip = db_api.port_disassociate_ip(context, [current_port], flip) if flip.fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip(context, flip) db_api.ip_address_deallocate(context, flip) if flip.fixed_ip: driver = registry.DRIVER_REGISTRY.get_driver() driver.remove_floating_ip(flip)
def update_floatingip(context, id, content): """Update an existing floating IP. :param context: neutron api request context. :param id: id of the floating ip :param content: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. :returns: Dictionary containing details for the new floating IP. If values are declared in the fields parameter, then only those keys will be present. """ LOG.info('update_floatingip %s for tenant %s and body %s' % (id, context.tenant_id, content)) if 'port_id' not in content: raise exceptions.BadRequest(resource='floating_ip', msg='port_id is required.') port_id = content.get('port_id') port = None fixed_ip = None current_port = None context.session.begin() try: flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE) if not flip: raise qex.FloatingIpNotFound(id=id) current_ports = flip.ports if current_ports and len(current_ports) > 0: current_port = current_ports[0] if not port_id and not current_port: raise qex.FloatingIpUpdateNoPortIdSupplied() if port_id: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) if not port: raise exceptions.PortNotFound(port_id=port_id) if any(ip for ip in port.ip_addresses if (ip.get('address_type') == ip_types.FLOATING)): raise qex.PortAlreadyContainsFloatingIp(port_id=port_id) if current_port and current_port.id == port_id: d = dict(flip_id=id, port_id=port_id) raise qex.PortAlreadyAssociatedToFloatingIp(**d) fixed_ip = _get_next_available_fixed_ip(port) LOG.info('new fixed ip: %s' % fixed_ip) if not fixed_ip: raise qex.NoAvailableFixedIpsForPort(port_id=port_id) LOG.info('current ports: %s' % current_ports) if current_port: flip = db_api.port_disassociate_ip(context, [current_port], flip) if flip.fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip(context, flip) if port: flip = db_api.port_associate_ip(context, [port], flip, [port_id]) flip = db_api.floating_ip_associate_fixed_ip(context, flip, fixed_ip) flip_driver = registry.DRIVER_REGISTRY.get_driver() if port: if current_port: flip_driver.update_floating_ip(flip, port, fixed_ip) else: flip_driver.register_floating_ip(flip, port, fixed_ip) else: flip_driver.remove_floating_ip(flip) context.session.commit() except (qex.RegisterFloatingIpFailure, qex.RemoveFloatingIpFailure): context.session.rollback() raise # Note(alanquillin) The ports parameters on the model is not # properly getting cleaned up when removed. Manually cleaning them up. # Need to fix the db api to correctly update the model. if not port: flip.ports = [] return v._make_floating_ip_dict(flip, port_id)
def _update_flip(context, flip_id, ip_type, requested_ports): """Update a flip based IPAddress :param context: neutron api request context. :param flip_id: id of the flip or scip :param ip_type: ip_types.FLOATING | ip_types.SCALING :param requested_ports: dictionary of the structure: {"port_id": "<id of port>", "fixed_ip": "<fixed ip address>"} :return: quark.models.IPAddress """ # This list will hold flips that require notifications. # Using sets to avoid dups, if any. notifications = { billing.IP_ASSOC: set(), billing.IP_DISASSOC: set() } context.session.begin() try: flip = db_api.floating_ip_find(context, id=flip_id, scope=db_api.ONE) if not flip: if ip_type == ip_types.SCALING: raise q_exc.ScalingIpNotFound(id=flip_id) raise q_exc.FloatingIpNotFound(id=flip_id) current_ports = flip.ports # Determine what ports are being removed, being added, and remain req_port_ids = [request_port.get('port_id') for request_port in requested_ports] curr_port_ids = [curr_port.id for curr_port in current_ports] added_port_ids = [port_id for port_id in req_port_ids if port_id and port_id not in curr_port_ids] removed_port_ids = [port_id for port_id in curr_port_ids if port_id not in req_port_ids] remaining_port_ids = set(curr_port_ids) - set(removed_port_ids) # Validations just for floating ip types if (ip_type == ip_types.FLOATING and curr_port_ids and curr_port_ids == req_port_ids): d = dict(flip_id=flip_id, port_id=curr_port_ids[0]) raise q_exc.PortAlreadyAssociatedToFloatingIp(**d) if (ip_type == ip_types.FLOATING and not curr_port_ids and not req_port_ids): raise q_exc.FloatingIpUpdateNoPortIdSupplied() # Validate that GW IP is not in use on the NW. flip_subnet = v._make_subnet_dict(flip.subnet) for added_port_id in added_port_ids: port = _get_port(context, added_port_id) nw = port.network nw_ports = v._make_ports_list(nw.ports) fixed_ips = [ip.get('ip_address') for p in nw_ports for ip in p.get('fixed_ips')] gw_ip = flip_subnet.get('gateway_ip') if gw_ip in fixed_ips: port_with_gateway_ip = None for port in nw_ports: for ip in port.get('fixed_ips'): if gw_ip in ip.get('ip_address'): port_with_gateway_ip = port break port_id = port_with_gateway_ip.get('id') network_id = port_with_gateway_ip.get('network_id') raise q_exc.FixedIpAllocatedToGatewayIp(port_id=port_id, network_id=network_id) port_fixed_ips = {} # Keep the ports and fixed ips that have not changed for port_id in remaining_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id) port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip} # Disassociate the ports and fixed ips from the flip that were # associated to the flip but are not anymore for port_id in removed_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) flip = db_api.port_disassociate_ip(context, [port], flip) notifications[billing.IP_DISASSOC].add(flip) fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id) if fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip( context, flip, fixed_ip) # Validate the new ports with the flip and associate the new ports # and fixed ips with the flip for port_id in added_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) if not port: raise n_exc.PortNotFound(port_id=port_id) if any(ip for ip in port.ip_addresses if (ip.get('address_type') == ip_types.FLOATING)): raise q_exc.PortAlreadyContainsFloatingIp(port_id=port_id) if any(ip for ip in port.ip_addresses if (ip.get('address_type') == ip_types.SCALING)): raise q_exc.PortAlreadyContainsScalingIp(port_id=port_id) fixed_ip = _get_next_available_fixed_ip(port) LOG.info('new fixed ip: %s' % fixed_ip) if not fixed_ip: raise q_exc.NoAvailableFixedIpsForPort(port_id=port_id) port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip} flip = db_api.port_associate_ip(context, [port], flip, [port_id]) notifications[billing.IP_ASSOC].add(flip) flip = db_api.floating_ip_associate_fixed_ip(context, flip, fixed_ip) flip_driver = registry.DRIVER_REGISTRY.get_driver() # If there are not any remaining ports and no new ones are being added, # remove the floating ip from unicorn if not remaining_port_ids and not added_port_ids: flip_driver.remove_floating_ip(flip) # If new ports are being added but there previously was not any ports, # then register a new floating ip with the driver because it is # assumed it does not exist elif added_port_ids and not curr_port_ids: flip_driver.register_floating_ip(flip, port_fixed_ips) else: flip_driver.update_floating_ip(flip, port_fixed_ips) context.session.commit() except Exception: context.session.rollback() raise # Send notifications for possible associate/disassociate events for notif_type, flip_set in notifications.iteritems(): for flip in flip_set: billing.notify(context, notif_type, flip) # NOTE(blogan): ORM does not seem to update the model to the real state # of the database, so I'm doing an explicit refresh for now. context.session.refresh(flip) return flip
def _get_ips_by_type(context, ip_type, filters=None, fields=None): filters = filters or {} filters['_deallocated'] = False filters['address_type'] = ip_type ips = db_api.floating_ip_find(context, scope=db_api.ALL, **filters) return ips
def update_floatingip(context, id, content): """Update an existing floating IP. :param context: neutron api request context. :param id: id of the floating ip :param content: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. :returns: Dictionary containing details for the new floating IP. If values are declared in the fields parameter, then only those keys will be present. """ LOG.info('update_floatingip %s for tenant %s and body %s' % (id, context.tenant_id, content)) if 'port_id' not in content: raise exceptions.BadRequest(resource='floating_ip', msg='port_id is required.') port_id = content.get('port_id') port = None fixed_ip = None current_port = None with context.session.begin(): flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE) if not flip: raise qex.FloatingIpNotFound(id=id) current_ports = flip.ports if current_ports and len(current_ports) > 0: current_port = current_ports[0] if not port_id and not current_port: raise qex.FloatingIPUpdateNoPortIdSupplied() if port_id: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) if not port: raise exceptions.PortNotFound(port_id=port_id) if current_port and current_port.id == port_id: d = dict(flip_id=id, port_id=port_id) raise qex.PortAlreadyAssociatedToFloatingIP(**d) fixed_ip = _get_next_available_fixed_ip(port) LOG.info('new fixed ip: %s' % fixed_ip) if not fixed_ip: raise qex.NoAvailableFixedIPsForPort(port_id=port_id) LOG.info('current ports: %s' % current_ports) if current_port: flip = db_api.port_disassociate_ip(context, [current_port], flip) if flip.fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip(context, flip) if port: flip = db_api.port_associate_ip(context, [port], flip, [port_id]) flip = db_api.floating_ip_associate_fixed_ip(context, flip, fixed_ip) flip_driver = registry.DRIVER_REGISTRY.get_driver() if port: if current_port: flip_driver.update_floating_ip(flip, port, fixed_ip) else: flip_driver.register_floating_ip(flip, port, fixed_ip) else: flip_driver.remove_floating_ip(flip) # Note(alanquillin) The ports parameters on the model is not # properly getting cleaned up when removed. Manually cleaning them up. # Need to fix the db api to correctly update the model. if not port: flip.ports = [] return v._make_floating_ip_dict(flip)
def _update_flip(context, flip_id, ip_type, requested_ports): """Update a flip based IPAddress :param context: neutron api request context. :param flip_id: id of the flip or scip :param ip_type: ip_types.FLOATING | ip_types.SCALING :param requested_ports: dictionary of the structure: {"port_id": "<id of port>", "fixed_ip": "<fixed ip address>"} :return: quark.models.IPAddress """ # This list will hold flips that require notifications. # Using sets to avoid dups, if any. notifications = {billing.IP_ASSOC: set(), billing.IP_DISASSOC: set()} context.session.begin() try: flip = db_api.floating_ip_find(context, id=flip_id, scope=db_api.ONE) if not flip: if ip_type == ip_types.SCALING: raise q_exc.ScalingIpNotFound(id=flip_id) raise q_exc.FloatingIpNotFound(id=flip_id) current_ports = flip.ports # Determine what ports are being removed, being added, and remain req_port_ids = [ request_port.get('port_id') for request_port in requested_ports ] curr_port_ids = [curr_port.id for curr_port in current_ports] added_port_ids = [ port_id for port_id in req_port_ids if port_id and port_id not in curr_port_ids ] removed_port_ids = [ port_id for port_id in curr_port_ids if port_id not in req_port_ids ] remaining_port_ids = set(curr_port_ids) - set(removed_port_ids) # Validations just for floating ip types if (ip_type == ip_types.FLOATING and curr_port_ids and curr_port_ids == req_port_ids): d = dict(flip_id=flip_id, port_id=curr_port_ids[0]) raise q_exc.PortAlreadyAssociatedToFloatingIp(**d) if (ip_type == ip_types.FLOATING and not curr_port_ids and not req_port_ids): raise q_exc.FloatingIpUpdateNoPortIdSupplied() # Validate that GW IP is not in use on the NW. flip_subnet = v._make_subnet_dict(flip.subnet) for added_port_id in added_port_ids: port = _get_port(context, added_port_id) nw = port.network nw_ports = v._make_ports_list(nw.ports) fixed_ips = [ ip.get('ip_address') for p in nw_ports for ip in p.get('fixed_ips') ] gw_ip = flip_subnet.get('gateway_ip') if gw_ip in fixed_ips: port_with_gateway_ip = None for port in nw_ports: for ip in port.get('fixed_ips'): if gw_ip in ip.get('ip_address'): port_with_gateway_ip = port break port_id = port_with_gateway_ip.get('id') network_id = port_with_gateway_ip.get('network_id') raise q_exc.FixedIpAllocatedToGatewayIp(port_id=port_id, network_id=network_id) port_fixed_ips = {} # Keep the ports and fixed ips that have not changed for port_id in remaining_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id) port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip} # Disassociate the ports and fixed ips from the flip that were # associated to the flip but are not anymore for port_id in removed_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) flip = db_api.port_disassociate_ip(context, [port], flip) notifications[billing.IP_DISASSOC].add(flip) fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id) if fixed_ip: flip = db_api.floating_ip_disassociate_fixed_ip( context, flip, fixed_ip) # Validate the new ports with the flip and associate the new ports # and fixed ips with the flip for port_id in added_port_ids: port = db_api.port_find(context, id=port_id, scope=db_api.ONE) if not port: raise n_exc.PortNotFound(port_id=port_id) if any(ip for ip in port.ip_addresses if (ip.get('address_type') == ip_types.FLOATING)): raise q_exc.PortAlreadyContainsFloatingIp(port_id=port_id) if any(ip for ip in port.ip_addresses if (ip.get('address_type') == ip_types.SCALING)): raise q_exc.PortAlreadyContainsScalingIp(port_id=port_id) fixed_ip = _get_next_available_fixed_ip(port) LOG.info('new fixed ip: %s' % fixed_ip) if not fixed_ip: raise q_exc.NoAvailableFixedIpsForPort(port_id=port_id) port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip} flip = db_api.port_associate_ip(context, [port], flip, [port_id]) notifications[billing.IP_ASSOC].add(flip) flip = db_api.floating_ip_associate_fixed_ip( context, flip, fixed_ip) flip_driver = registry.DRIVER_REGISTRY.get_driver() # If there are not any remaining ports and no new ones are being added, # remove the floating ip from unicorn if not remaining_port_ids and not added_port_ids: flip_driver.remove_floating_ip(flip) # If new ports are being added but there previously was not any ports, # then register a new floating ip with the driver because it is # assumed it does not exist elif added_port_ids and not curr_port_ids: flip_driver.register_floating_ip(flip, port_fixed_ips) else: flip_driver.update_floating_ip(flip, port_fixed_ips) context.session.commit() except Exception: context.session.rollback() raise # Send notifications for possible associate/disassociate events for notif_type, flip_set in notifications.iteritems(): for flip in flip_set: billing.notify(context, notif_type, flip) # NOTE(blogan): ORM does not seem to update the model to the real state # of the database, so I'm doing an explicit refresh for now. context.session.refresh(flip) return flip