def _update_flip(context, flip_id, ip_type, requested_ports):
<EOL>notifications = {<EOL>billing.IP_ASSOC: set(),<EOL>billing.IP_DISASSOC: set()<EOL>}<EOL>context.session.begin()<EOL>try:<EOL><INDENT>flip = db_api.floating_ip_find(context, id=flip_id, scope=db_api.ONE)<EOL>if not flip:<EOL><INDENT>if ip_type == ip_types.SCALING:<EOL><INDENT>raise q_exc.ScalingIpNotFound(id=flip_id)<EOL><DEDENT>raise q_exc.FloatingIpNotFound(id=flip_id)<EOL><DEDENT>current_ports = flip.ports<EOL>req_port_ids = [request_port.get('<STR_LIT>')<EOL>for request_port in requested_ports]<EOL>curr_port_ids = [curr_port.id for curr_port in current_ports]<EOL>added_port_ids = [port_id for port_id in req_port_ids<EOL>if port_id and port_id not in curr_port_ids]<EOL>removed_port_ids = [port_id for port_id in curr_port_ids<EOL>if port_id not in req_port_ids]<EOL>remaining_port_ids = set(curr_port_ids) - set(removed_port_ids)<EOL>if (ip_type == ip_types.FLOATING and curr_port_ids and<EOL>curr_port_ids == req_port_ids):<EOL><INDENT>d = dict(flip_id=flip_id, port_id=curr_port_ids[<NUM_LIT:0>])<EOL>raise q_exc.PortAlreadyAssociatedToFloatingIp(**d)<EOL><DEDENT>if (ip_type == ip_types.FLOATING and<EOL>not curr_port_ids and not req_port_ids):<EOL><INDENT>raise q_exc.FloatingIpUpdateNoPortIdSupplied()<EOL><DEDENT>flip_subnet = v._make_subnet_dict(flip.subnet)<EOL>for added_port_id in added_port_ids:<EOL><INDENT>port = _get_port(context, added_port_id)<EOL>nw = port.network<EOL>nw_ports = v._make_ports_list(nw.ports)<EOL>fixed_ips = [ip.get('<STR_LIT>') for p in nw_ports<EOL>for ip in p.get('<STR_LIT>')]<EOL>gw_ip = flip_subnet.get('<STR_LIT>')<EOL>if gw_ip in fixed_ips:<EOL><INDENT>port_with_gateway_ip = None<EOL>for port in nw_ports:<EOL><INDENT>for ip in port.get('<STR_LIT>'):<EOL><INDENT>if gw_ip in ip.get('<STR_LIT>'):<EOL><INDENT>port_with_gateway_ip = port<EOL>break<EOL><DEDENT><DEDENT><DEDENT>port_id = port_with_gateway_ip.get('<STR_LIT:id>')<EOL>network_id = port_with_gateway_ip.get('<STR_LIT>')<EOL>raise q_exc.FixedIpAllocatedToGatewayIp(port_id=port_id,<EOL>network_id=network_id)<EOL><DEDENT><DEDENT>port_fixed_ips = {}<EOL>for port_id in remaining_port_ids:<EOL><INDENT>port = db_api.port_find(context, id=port_id, scope=db_api.ONE)<EOL>fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id)<EOL>port_fixed_ips[port_id] = {'<STR_LIT:port>': port, '<STR_LIT>': fixed_ip}<EOL><DEDENT>for port_id in removed_port_ids:<EOL><INDENT>port = db_api.port_find(context, id=port_id, scope=db_api.ONE)<EOL>flip = db_api.port_disassociate_ip(context, [port], flip)<EOL>notifications[billing.IP_DISASSOC].add(flip)<EOL>fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id)<EOL>if fixed_ip:<EOL><INDENT>flip = db_api.floating_ip_disassociate_fixed_ip(<EOL>context, flip, fixed_ip)<EOL><DEDENT><DEDENT>for port_id in added_port_ids:<EOL><INDENT>port = db_api.port_find(context, id=port_id, scope=db_api.ONE)<EOL>if not port:<EOL><INDENT>raise n_exc.PortNotFound(port_id=port_id)<EOL><DEDENT>if any(ip for ip in port.ip_addresses<EOL>if (ip.get('<STR_LIT>') == ip_types.FLOATING)):<EOL><INDENT>raise q_exc.PortAlreadyContainsFloatingIp(port_id=port_id)<EOL><DEDENT>if any(ip for ip in port.ip_addresses<EOL>if (ip.get('<STR_LIT>') == ip_types.SCALING)):<EOL><INDENT>raise q_exc.PortAlreadyContainsScalingIp(port_id=port_id)<EOL><DEDENT>fixed_ip = _get_next_available_fixed_ip(port)<EOL>LOG.info('<STR_LIT>' % fixed_ip)<EOL>if not fixed_ip:<EOL><INDENT>raise q_exc.NoAvailableFixedIpsForPort(port_id=port_id)<EOL><DEDENT>port_fixed_ips[port_id] = {'<STR_LIT:port>': port, '<STR_LIT>': fixed_ip}<EOL>flip = db_api.port_associate_ip(context, [port], flip, [port_id])<EOL>notifications[billing.IP_ASSOC].add(flip)<EOL>flip = db_api.floating_ip_associate_fixed_ip(context, flip,<EOL>fixed_ip)<EOL><DEDENT>flip_driver = registry.DRIVER_REGISTRY.get_driver()<EOL>if not remaining_port_ids and not added_port_ids:<EOL><INDENT>flip_driver.remove_floating_ip(flip)<EOL><DEDENT>elif added_port_ids and not curr_port_ids:<EOL><INDENT>flip_driver.register_floating_ip(flip, port_fixed_ips)<EOL><DEDENT>else:<EOL><INDENT>flip_driver.update_floating_ip(flip, port_fixed_ips)<EOL><DEDENT>context.session.commit()<EOL><DEDENT>except Exception:<EOL><INDENT>context.session.rollback()<EOL>raise<EOL><DEDENT>for notif_type, flip_set in notifications.iteritems():<EOL><INDENT>for flip in flip_set:<EOL><INDENT>billing.notify(context, notif_type, flip)<EOL><DEDENT><DEDENT>context.session.refresh(flip)<EOL>return flip<EOL>
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