'Associates a floating IP with a fixed IP.
Makes sure everything makes sense then calls _associate_floating_ip,
rpc\'ing to correct host if i\'m not it.
Access to the floating_address is verified but access to the
fixed_address is not verified. This assumes that the calling
side has already verified that the fixed_address is legal by
checking access to the instance.'

@messaging.expected_exceptions(exception.FloatingIpNotFoundForAddress)
def associate_floating_ip(self, context, floating_address, fixed_address, affect_auto_assigned=False):

    floating_ip = objects.FloatingIP.get_by_address(context, floating_address)
    if ((not affect_auto_assigned) and floating_ip.auto_assigned):
        return
    self._floating_ip_owned_by_project(context, floating_ip)
    orig_instance_uuid = None
    if floating_ip.fixed_ip_id:
        fixed_ip = floating_ip.fixed_ip
        if (str(fixed_ip.address) == fixed_address):
            return
        orig_instance_uuid = fixed_ip.instance_uuid
        self.disassociate_floating_ip(context, floating_address)
    fixed_ip = objects.FixedIP.get_by_address(context, fixed_address)
    network = objects.Network.get_by_id(context.elevated(), fixed_ip.network_id)
    if network.multi_host:
        instance = objects.Instance.get_by_uuid(context, fixed_ip.instance_uuid)
        host = instance.host
    else:
        host = network.host
    interface = floating_ip.interface
    if (host == self.host):
        self._associate_floating_ip(context, floating_address, fixed_address, interface, fixed_ip.instance_uuid)
    else:
        self.network_rpcapi._associate_floating_ip(context, floating_address, fixed_address, interface, host, fixed_ip.instance_uuid)
    return orig_instance_uuid
