Example #1
0
 def test_call_function_by_name(self):
     with MockTransaction:
         arg1 = 'a'
         arg2 = 'b'
         expect(common).func_to_call(arg1, arg2).and_return('res').once()
         assert common.call_function_by_name('neat.common.func_to_call',
                                             [arg1, arg2]) == 'res'
 def test_call_function_by_name(self):
     with MockTransaction:
         arg1 = 'a'
         arg2 = 'b'
         expect(common).func_to_call(arg1, arg2).and_return('res').once()
         assert common.call_function_by_name('neat.common.func_to_call',
                                             [arg1, arg2]) == 'res'
Example #3
0
def execute_overload(config, state, host, vm_uuids):
    """ Process an overloaded host: migrate the selected VMs from it.

1. Prepare the data about the current states of the hosts and VMs.

2. Call the function specified in the `algorithm_vm_placement_factory`
   configuration option and pass the data on the states of the hosts and VMs.

3. Call the Nova API to migrate the VMs according to the placement
   determined by the `algorithm_vm_placement_factory` algorithm.

4. Switch on the inactive hosts required to accommodate the VMs.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :param host: A host name.
     :type host: str

    :param vm_uuids: A list of VM UUIDs to migrate from the host.
     :type vm_uuids: list(str)

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started processing an overload request')
    overloaded_host = host
    hosts_cpu_total, _, hosts_ram_total = state['db'].select_host_characteristics()
    hosts_to_vms = vms_by_hosts(state['nova'], state['compute_hosts'])
    vms_last_cpu = state['db'].select_last_cpu_mhz_for_vms()
    hosts_last_cpu = state['db'].select_last_cpu_mhz_for_hosts()

    # Remove VMs from hosts_to_vms that are not in vms_last_cpu
    # These VMs are new and no data have been collected from them
    for host, vms in hosts_to_vms.items():
        for i, vm in enumerate(vms):
            if not vm in vms_last_cpu:
                del hosts_to_vms[host][i]

    hosts_cpu_usage = {}
    hosts_ram_usage = {}
    inactive_hosts_cpu = {}
    inactive_hosts_ram = {}
    for host, vms in hosts_to_vms.items():
        if vms:
            host_cpu_mhz = hosts_last_cpu[host]
            for vm in vms:
                if vm not in vms_last_cpu:
                    log.info('No data yet for VM: %s - skipping host %s', vm, host)
                    del hosts_cpu_total[host]
                    del hosts_ram_total[host]
                    if host in hosts_cpu_usage:
                        del hosts_cpu_usage[host]
                    if host in hosts_ram_usage:
                        del hosts_ram_usage[host]
                    break
                host_cpu_mhz += vms_last_cpu[vm]
            else:
                hosts_cpu_usage[host] = host_cpu_mhz
                hosts_ram_usage[host] = host_used_ram(state['nova'], host)
        else:
            inactive_hosts_cpu[host] = hosts_cpu_total[host]
            inactive_hosts_ram[host] = hosts_ram_total[host]
            del hosts_cpu_total[host]
            del hosts_ram_total[host]

    # Exclude the overloaded host
    del hosts_cpu_usage[overloaded_host]
    del hosts_cpu_total[overloaded_host]
    del hosts_ram_usage[overloaded_host]
    del hosts_ram_total[overloaded_host]

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    vms_to_migrate = vm_uuids
    vms_cpu = {}
    for vm in vms_to_migrate:
        if vm not in vms_last_cpu:
            log.info('No data yet for VM: %s - dropping the request', vm)
            log.info('Skipped an underload request')
            return state
        vms_cpu[vm] = state['db'].select_cpu_mhz_for_vm(
            vm,
            int(config['data_collector_data_length']))
    vms_ram = vms_ram_limit(state['nova'], vms_to_migrate)

    # Remove VMs that are not in vms_ram
    # These instances might have been deleted
    for i, vm in enumerate(vms_to_migrate):
        if not vm in vms_ram:
            del vms_to_migrate[i]

    for vm in vms_cpu.keys():
        if not vm in vms_ram:
            del vms_cpu[vm]

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vms_ram,
        float(config['network_migration_bandwidth']))

    if 'vm_placement' not in state:
        vm_placement_params = common.parse_parameters(
            config['algorithm_vm_placement_parameters'])
        vm_placement_state = None
        vm_placement = common.call_function_by_name(
            config['algorithm_vm_placement_factory'],
            [time_step,
             migration_time,
             vm_placement_params])
        state['vm_placement'] = vm_placement
        state['vm_placement_state'] = {}
    else:
        vm_placement = state['vm_placement']
        vm_placement_state = state['vm_placement_state']

    log.info('Started overload VM placement')
    placement, vm_placement_state = vm_placement(
        hosts_cpu_usage, hosts_cpu_total,
        hosts_ram_usage, hosts_ram_total,
        inactive_hosts_cpu, inactive_hosts_ram,
        vms_cpu, vms_ram,
        vm_placement_state)
    log.info('Completed overload VM placement')
    state['vm_placement_state'] = vm_placement_state

    if log.isEnabledFor(logging.INFO):
        log.info('Overload: obtained a new placement %s', str(placement))

    if not placement:
        log.info('Nothing to migrate')
    else:
        hosts_to_activate = list(
            set(inactive_hosts_cpu.keys()).intersection(
                set(placement.values())))
        if hosts_to_activate:
            switch_hosts_on(state['db'],
                            config['ether_wake_interface'],
                            state['host_macs'],
                            hosts_to_activate)
        log.info('Started overload VM migrations')
        migrate_vms(state['db'],
                    state['nova'],
                    config['vm_instance_directory'],
                    placement)
        log.info('Completed overload VM migrations')
    log.info('Completed processing an overload request')
    return state
Example #4
0
def execute_overload(config, state, host, vm_uuids):
    """ Process an overloaded host: migrate the selected VMs from it.

1. Prepare the data about the current states of the hosts and VMs.

2. Call the function specified in the `algorithm_vm_placement_factory`
   configuration option and pass the data on the states of the hosts and VMs.

3. Call the Nova API to migrate the VMs according to the placement
   determined by the `algorithm_vm_placement_factory` algorithm.

4. Switch on the inactive hosts required to accommodate the VMs.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :param host: A host name.
     :type host: str

    :param vm_uuids: A list of VM UUIDs to migrate from the host.
     :type vm_uuids: list(str)

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started processing an overload request')
    overloaded_host = host
    hosts_cpu_total, _, hosts_ram_total = state['db'].select_host_characteristics()
    hosts_to_vms = vms_by_hosts(state['nova'], state['compute_hosts'])
    vms_last_cpu = state['db'].select_last_cpu_mhz_for_vms()
    hosts_last_cpu = state['db'].select_last_cpu_mhz_for_hosts()

    # Remove VMs from hosts_to_vms that are not in vms_last_cpu
    # These VMs are new and no data have been collected from them
    for host, vms in hosts_to_vms.items():
        for i, vm in enumerate(vms):
            if not vm in vms_last_cpu:
                del hosts_to_vms[host][i]

    hosts_cpu_usage = {}
    hosts_ram_usage = {}
    inactive_hosts_cpu = {}
    inactive_hosts_ram = {}
    for host, vms in hosts_to_vms.items():
        if vms:
            host_cpu_mhz = hosts_last_cpu[host]
            for vm in vms:
                if vm not in vms_last_cpu:
                    log.info('No data yet for VM: %s - skipping host %s', vm, host)
                    hosts_cpu_total.pop(host, None)
                    hosts_ram_total.pop(host, None)
                    hosts_cpu_usage.pop(host, None)
                    hosts_ram_usage.pop(host, None)
                    break
                host_cpu_mhz += vms_last_cpu[vm]
            else:
                hosts_cpu_usage[host] = host_cpu_mhz
                hosts_ram_usage[host] = host_used_ram(state['nova'], host)
        else:
            inactive_hosts_cpu[host] = hosts_cpu_total[host]
            inactive_hosts_ram[host] = hosts_ram_total[host]
            hosts_cpu_total.pop(host, None)
            hosts_ram_total.pop(host, None)

    # Exclude the overloaded host
    hosts_cpu_usage.pop(overloaded_host, None)
    hosts_cpu_total.pop(overloaded_host, None)
    hosts_ram_usage.pop(overloaded_host, None)
    hosts_ram_total.pop(overloaded_host, None)

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    vms_to_migrate = vm_uuids
    vms_cpu = {}
    for vm in vms_to_migrate:
        if vm not in vms_last_cpu:
            log.info('No data yet for VM: %s - dropping the request', vm)
            log.info('Skipped an underload request')
            return state
        vms_cpu[vm] = state['db'].select_cpu_mhz_for_vm(
            vm,
            int(config['data_collector_data_length']))
    vms_ram = vms_ram_limit(state['nova'], vms_to_migrate)

    # Remove VMs that are not in vms_ram
    # These instances might have been deleted
    for i, vm in enumerate(vms_to_migrate):
        if not vm in vms_ram:
            del vms_to_migrate[i]

    if not vms_to_migrate:
        log.info('No VMs to migrate - completed the overload request')
        return state

    for vm in vms_cpu.keys():
        if not vm in vms_ram:
            del vms_cpu[vm]

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vms_ram,
        float(config['network_migration_bandwidth']))

    if 'vm_placement' not in state:
        vm_placement_params = common.parse_parameters(
            config['algorithm_vm_placement_parameters'])
        vm_placement_state = None
        vm_placement = common.call_function_by_name(
            config['algorithm_vm_placement_factory'],
            [time_step,
             migration_time,
             vm_placement_params])
        state['vm_placement'] = vm_placement
        state['vm_placement_state'] = {}
    else:
        vm_placement = state['vm_placement']
        vm_placement_state = state['vm_placement_state']

    log.info('Started overload VM placement')
    placement, vm_placement_state = vm_placement(
        hosts_cpu_usage, hosts_cpu_total,
        hosts_ram_usage, hosts_ram_total,
        inactive_hosts_cpu, inactive_hosts_ram,
        vms_cpu, vms_ram,
        vm_placement_state)
    log.info('Completed overload VM placement')
    state['vm_placement_state'] = vm_placement_state

    if log.isEnabledFor(logging.INFO):
        log.info('Overload: obtained a new placement %s', str(placement))

    if not placement:
        log.info('Nothing to migrate')
    else:
        hosts_to_activate = list(
            set(inactive_hosts_cpu.keys()).intersection(
                set(placement.values())))
        if hosts_to_activate:
            switch_hosts_on(state['db'],
                            config['ether_wake_interface'],
                            state['host_macs'],
                            hosts_to_activate)
        log.info('Started overload VM migrations')
        migrate_vms(state['db'],
                    state['nova'],
                    config['vm_instance_directory'],
                    placement,
                    bool(config['block_migration']))
        log.info('Completed overload VM migrations')
    log.info('Completed processing an overload request')
    return state
Example #5
0
def execute_underload(config, state, host):
    """ Process an underloaded host: migrate all VMs from the host.

1. Prepare the data about the current states of the hosts and VMs.

2. Call the function specified in the `algorithm_vm_placement_factory`
   configuration option and pass the data on the states of the hosts and VMs.

3. Call the Nova API to migrate the VMs according to the placement
   determined by the `algorithm_vm_placement_factory` algorithm.

4. Switch off the host at the end of the VM migration.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :param host: A host name.
     :type host: str

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started processing an underload request')
    underloaded_host = host
    hosts_cpu_total, _, hosts_ram_total = state['db'].select_host_characteristics()

    hosts_to_vms = vms_by_hosts(state['nova'], state['compute_hosts'])
    vms_last_cpu = state['db'].select_last_cpu_mhz_for_vms()
    hosts_last_cpu = state['db'].select_last_cpu_mhz_for_hosts()

    # Remove VMs from hosts_to_vms that are not in vms_last_cpu
    # These VMs are new and no data have been collected from them
    for host, vms in hosts_to_vms.items():
        for i, vm in enumerate(vms):
            if not vm in vms_last_cpu:
                del hosts_to_vms[host][i]

    if log.isEnabledFor(logging.DEBUG):
        log.debug('hosts_to_vms: %s', str(hosts_to_vms))

    hosts_cpu_usage = {}
    hosts_ram_usage = {}
    hosts_to_keep_active = set()
    for host, vms in hosts_to_vms.items():
        if vms:
            host_cpu_mhz = hosts_last_cpu[host]
            for vm in vms:
                if vm not in vms_last_cpu:
                    log.info('No data yet for VM: %s - skipping host %s', vm, host)
                    hosts_to_keep_active.add(host)
                    hosts_cpu_total.pop(host, None)
                    hosts_ram_total.pop(host, None)
                    hosts_cpu_usage.pop(host, None)
                    hosts_ram_usage.pop(host, None)
                    break
                host_cpu_mhz += vms_last_cpu[vm]
            else:
                hosts_cpu_usage[host] = host_cpu_mhz
                hosts_ram_usage[host] = host_used_ram(state['nova'], host)
        else:
            # Exclude inactive hosts
            hosts_cpu_total.pop(host, None)
            hosts_ram_total.pop(host, None)

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    # Exclude the underloaded host
    hosts_cpu_usage.pop(underloaded_host, None)
    hosts_cpu_total.pop(underloaded_host, None)
    hosts_ram_usage.pop(underloaded_host, None)
    hosts_ram_total.pop(underloaded_host, None)

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Excluded the underloaded host %s', underloaded_host)
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    vms_to_migrate = vms_by_host(state['nova'], underloaded_host)
    vms_cpu = {}
    for vm in vms_to_migrate:
        if vm not in vms_last_cpu:
            log.info('No data yet for VM: %s - dropping the request', vm)
            log.info('Skipped an underload request')
            return state
        vms_cpu[vm] = state['db'].select_cpu_mhz_for_vm(
            vm,
            int(config['data_collector_data_length']))
    vms_ram = vms_ram_limit(state['nova'], vms_to_migrate)

    # Remove VMs that are not in vms_ram
    # These instances might have been deleted
    for i, vm in enumerate(vms_to_migrate):
        if not vm in vms_ram:
            del vms_to_migrate[i]

    if not vms_to_migrate:
        log.info('No VMs to migrate - completed the underload request')
        return state

    for vm in vms_cpu.keys():
        if not vm in vms_ram:
            del vms_cpu[vm]

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vms_ram,
        float(config['network_migration_bandwidth']))

    if 'vm_placement' not in state:
        vm_placement_params = common.parse_parameters(
            config['algorithm_vm_placement_parameters'])
        vm_placement_state = None
        vm_placement = common.call_function_by_name(
            config['algorithm_vm_placement_factory'],
            [time_step,
             migration_time,
             vm_placement_params])
        state['vm_placement'] = vm_placement
        state['vm_placement_state'] = {}
    else:
        vm_placement = state['vm_placement']
        vm_placement_state = state['vm_placement_state']

    log.info('Started underload VM placement')
    placement, vm_placement_state = vm_placement(
        hosts_cpu_usage, hosts_cpu_total,
        hosts_ram_usage, hosts_ram_total,
        {}, {},
        vms_cpu, vms_ram,
        vm_placement_state)
    log.info('Completed underload VM placement')
    state['vm_placement_state'] = vm_placement_state

    if log.isEnabledFor(logging.INFO):
        log.info('Underload: obtained a new placement %s', str(placement))

    active_hosts = hosts_cpu_total.keys()
    inactive_hosts = set(state['compute_hosts']) - set(active_hosts)
    prev_inactive_hosts = set(state['db'].select_inactive_hosts())
    hosts_to_deactivate = list(inactive_hosts
                               - prev_inactive_hosts
                               - hosts_to_keep_active)

    if not placement:
        log.info('Nothing to migrate')
        if underloaded_host in hosts_to_deactivate:
            hosts_to_deactivate.remove(underloaded_host)
    else:
        log.info('Started underload VM migrations')
        migrate_vms(state['db'],
                    state['nova'],
                    config['vm_instance_directory'],
                    placement,
                    bool(config['block_migration']))
        log.info('Completed underload VM migrations')

    if hosts_to_deactivate:
        switch_hosts_off(state['db'],
                         config['sleep_command'],
                         hosts_to_deactivate)

    log.info('Completed processing an underload request')
    return state
Example #6
0
def execute(config, state):
    """ Execute an iteration of the local manager.

1. Read the data on resource usage by the VMs running on the host from
   the <local_data_directory>/vm directory.

2. Call the function specified in the algorithm_underload_detection
   configuration option and pass the data on the resource usage by the
   VMs, as well as the frequency of the CPU as arguments.

3. If the host is underloaded, send a request to the REST API of the
   global manager and pass a list of the UUIDs of all the VMs
   currently running on the host in the vm_uuids parameter, as well as
   the reason for migration as being 0.

4. If the host is not underloaded, call the function specified in the
   algorithm_overload_detection configuration option and pass the data
   on the resource usage by the VMs, as well as the frequency of the
   host's CPU as arguments.

5. If the host is overloaded, call the function specified in the
   algorithm_vm_selection configuration option and pass the data on
   the resource usage by the VMs, as well as the frequency of the
   host's CPU as arguments

6. If the host is overloaded, send a request to the REST API of the
   global manager and pass a list of the UUIDs of the VMs selected by
   the VM selection algorithm in the vm_uuids parameter, as well as
   the reason for migration as being 1.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started an iteration')
    vm_path = common.build_local_vm_path(config['local_data_directory'])
    vm_cpu_mhz = get_local_vm_data(vm_path)
    vm_ram = get_ram(state['vir_connection'], vm_cpu_mhz.keys())
    vm_cpu_mhz = cleanup_vm_data(vm_cpu_mhz, vm_ram.keys())

    if not vm_cpu_mhz:
        if log.isEnabledFor(logging.INFO):
            log.info('The host is idle')
        log.info('Skipped an iteration')
        return state

    host_path = common.build_local_host_path(config['local_data_directory'])
    host_cpu_mhz = get_local_host_data(host_path)

    host_cpu_utilization = vm_mhz_to_percentage(
        vm_cpu_mhz.values(),
        host_cpu_mhz,
        state['physical_cpu_mhz_total'])
    if log.isEnabledFor(logging.DEBUG):
        log.debug('The total physical CPU Mhz: %s', str(state['physical_cpu_mhz_total']))
        log.debug('VM CPU MHz: %s', str(vm_cpu_mhz))
        log.debug('Host CPU MHz: %s', str(host_cpu_mhz))
        log.debug('CPU utilization: %s', str(host_cpu_utilization))

    if not host_cpu_utilization:
        log.info('Not enough data yet - skipping to the next iteration')
        log.info('Skipped an iteration')
        return state

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vm_ram, float(config['network_migration_bandwidth']))

    if 'underload_detection' not in state:
        underload_detection_params = common.parse_parameters(
            config['algorithm_underload_detection_parameters'])
        underload_detection = common.call_function_by_name(
            config['algorithm_underload_detection_factory'],
            [time_step,
             migration_time,
             underload_detection_params])
        state['underload_detection'] = underload_detection
        state['underload_detection_state'] = {}

        overload_detection_params = common.parse_parameters(
            config['algorithm_overload_detection_parameters'])
        overload_detection = common.call_function_by_name(
            config['algorithm_overload_detection_factory'],
            [time_step,
             migration_time,
             overload_detection_params])
        state['overload_detection'] = overload_detection
        state['overload_detection_state'] = {}

        vm_selection_params = common.parse_parameters(
            config['algorithm_vm_selection_parameters'])
        vm_selection = common.call_function_by_name(
            config['algorithm_vm_selection_factory'],
            [time_step,
             migration_time,
             vm_selection_params])
        state['vm_selection'] = vm_selection
        state['vm_selection_state'] = {}
    else:
        underload_detection = state['underload_detection']
        overload_detection = state['overload_detection']
        vm_selection = state['vm_selection']

    if log.isEnabledFor(logging.INFO):
        log.info('Started underload detection')
    underload, state['underload_detection_state'] = underload_detection(
        host_cpu_utilization, state['underload_detection_state'])
    if log.isEnabledFor(logging.INFO):
        log.info('Completed underload detection')

    if log.isEnabledFor(logging.INFO):
        log.info('Started overload detection')
    overload, state['overload_detection_state'] = overload_detection(
        host_cpu_utilization, state['overload_detection_state'])
    if log.isEnabledFor(logging.INFO):
        log.info('Completed overload detection')

    if underload:
        if log.isEnabledFor(logging.INFO):
            log.info('Underload detected')
        try:
            r = requests.put('http://' + config['global_manager_host'] +
                             ':' + config['global_manager_port'],
                             {'username': state['hashed_username'],
                              'password': state['hashed_password'],
                              'time': time.time(),
                              'host': state['hostname'],
                              'reason': 0})
            if log.isEnabledFor(logging.INFO):
                log.info('Received response: [%s] %s',
                         r.status_code, r.content)
        except requests.exceptions.ConnectionError:
            log.exception('Exception at underload request:')

    else:
        if overload:
            if log.isEnabledFor(logging.INFO):
                log.info('Overload detected')

            log.info('Started VM selection')
            vm_uuids, state['vm_selection_state'] = vm_selection(
                vm_cpu_mhz, vm_ram, state['vm_selection_state'])
            log.info('Completed VM selection')

            if log.isEnabledFor(logging.INFO):
                log.info('Selected VMs to migrate: %s', str(vm_uuids))
            try:
                r = requests.put('http://' + config['global_manager_host'] +
                                 ':' + config['global_manager_port'],
                                 {'username': state['hashed_username'],
                                  'password': state['hashed_password'],
                                  'time': time.time(),
                                  'host': state['hostname'],
                                  'reason': 1,
                                  'vm_uuids': ','.join(vm_uuids)})
                if log.isEnabledFor(logging.INFO):
                    log.info('Received response: [%s] %s',
                             r.status_code, r.content)
            except requests.exceptions.ConnectionError:
                log.exception('Exception at overload request:')
        else:
            if log.isEnabledFor(logging.INFO):
                log.info('No underload or overload detected')

    if log.isEnabledFor(logging.INFO):
        log.info('Completed an iteration')

    return state
Example #7
0
def execute(config, state):
    """ Execute an iteration of the local manager.

1. Read the data on resource usage by the VMs running on the host from
   the <local_data_directory>/vm directory.

2. Call the function specified in the algorithm_underload_detection
   configuration option and pass the data on the resource usage by the
   VMs, as well as the frequency of the CPU as arguments.

3. If the host is underloaded, send a request to the REST API of the
   global manager and pass a list of the UUIDs of all the VMs
   currently running on the host in the vm_uuids parameter, as well as
   the reason for migration as being 0.

4. If the host is not underloaded, call the function specified in the
   algorithm_overload_detection configuration option and pass the data
   on the resource usage by the VMs, as well as the frequency of the
   host's CPU as arguments.

5. If the host is overloaded, call the function specified in the
   algorithm_vm_selection configuration option and pass the data on
   the resource usage by the VMs, as well as the frequency of the
   host's CPU as arguments

6. If the host is overloaded, send a request to the REST API of the
   global manager and pass a list of the UUIDs of the VMs selected by
   the VM selection algorithm in the vm_uuids parameter, as well as
   the reason for migration as being 1.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started an iteration')
    vm_path = common.build_local_vm_path(config['local_data_directory'])
    vm_cpu_mhz = get_local_vm_data(vm_path)
    vm_ram = get_ram(state['vir_connection'], vm_cpu_mhz.keys())
    vm_cpu_mhz = cleanup_vm_data(vm_cpu_mhz, vm_ram.keys())

    if not vm_cpu_mhz:
        if log.isEnabledFor(logging.INFO):
            log.info('The host is idle')
        log.info('Skipped an iteration')
        return state

    host_path = common.build_local_host_path(config['local_data_directory'])
    host_cpu_mhz = get_local_host_data(host_path)

    host_cpu_utilization = vm_mhz_to_percentage(
        vm_cpu_mhz.values(),
        host_cpu_mhz,
        state['physical_cpu_mhz_total'])
    if log.isEnabledFor(logging.DEBUG):
        log.debug('The total physical CPU Mhz: %s', str(state['physical_cpu_mhz_total']))
        log.debug('VM CPU MHz: %s', str(vm_cpu_mhz))
        log.debug('Host CPU MHz: %s', str(host_cpu_mhz))
        log.debug('CPU utilization: %s', str(host_cpu_utilization))

    if not host_cpu_utilization:
        log.info('Not enough data yet - skipping to the next iteration')
        log.info('Skipped an iteration')
        return state

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vm_ram, float(config['network_migration_bandwidth']))

    if 'underload_detection' not in state:
        underload_detection_params = common.parse_parameters(
            config['algorithm_underload_detection_parameters'])
        underload_detection = common.call_function_by_name(
            config['algorithm_underload_detection_factory'],
            [time_step,
             migration_time,
             underload_detection_params])
        state['underload_detection'] = underload_detection
        state['underload_detection_state'] = {}

        overload_detection_params = common.parse_parameters(
            config['algorithm_overload_detection_parameters'])
        overload_detection = common.call_function_by_name(
            config['algorithm_overload_detection_factory'],
            [time_step,
             migration_time,
             overload_detection_params])
        state['overload_detection'] = overload_detection
        state['overload_detection_state'] = {}

        vm_selection_params = common.parse_parameters(
            config['algorithm_vm_selection_parameters'])
        vm_selection = common.call_function_by_name(
            config['algorithm_vm_selection_factory'],
            [time_step,
             migration_time,
             vm_selection_params])
        state['vm_selection'] = vm_selection
        state['vm_selection_state'] = {}
    else:
        underload_detection = state['underload_detection']
        overload_detection = state['overload_detection']
        vm_selection = state['vm_selection']

    if log.isEnabledFor(logging.INFO):
        log.info('Started underload detection')
    underload, state['underload_detection_state'] = underload_detection(
        host_cpu_utilization, state['underload_detection_state'])
    if log.isEnabledFor(logging.INFO):
        log.info('Completed underload detection')

    if log.isEnabledFor(logging.INFO):
        log.info('Started overload detection')
    overload, state['overload_detection_state'] = overload_detection(
        host_cpu_utilization, state['overload_detection_state'])
    if log.isEnabledFor(logging.INFO):
        log.info('Completed overload detection')

    if underload:
        if log.isEnabledFor(logging.INFO):
            log.info('Underload detected')
        try:
            r = requests.put('http://' + config['global_manager_host'] +
                             ':' + config['global_manager_port'],
                             {'username': state['hashed_username'],
                              'password': state['hashed_password'],
                              'time': time.time(),
                              'host': state['hostname'],
                              'reason': 0})
            if log.isEnabledFor(logging.INFO):
                log.info('Received response: [%s] %s',
                         r.status_code, r.content)
        except requests.exceptions.ConnectionError:
            log.exception('Exception at underload request:')

    else:
        if overload:
            if log.isEnabledFor(logging.INFO):
                log.info('Overload detected')

            log.info('Started VM selection')
            vm_uuids, state['vm_selection_state'] = vm_selection(
                vm_cpu_mhz, vm_ram, state['vm_selection_state'])
            log.info('Completed VM selection')

            if log.isEnabledFor(logging.INFO):
                log.info('Selected VMs to migrate: %s', str(vm_uuids))
            try:
                r = requests.put('http://' + config['global_manager_host'] +
                                 ':' + config['global_manager_port'],
                                 {'username': state['hashed_username'],
                                  'password': state['hashed_password'],
                                  'time': time.time(),
                                  'host': state['hostname'],
                                  'reason': 1,
                                  'vm_uuids': ','.join(vm_uuids)})
                if log.isEnabledFor(logging.INFO):
                    log.info('Received response: [%s] %s',
                             r.status_code, r.content)
            except requests.exceptions.ConnectionError:
                log.exception('Exception at overload request:')
        else:
            if log.isEnabledFor(logging.INFO):
                log.info('No underload or overload detected')

    if log.isEnabledFor(logging.INFO):
        log.info('Completed an iteration')

    return state
Example #8
0
def execute_underload(config, state, host):
    """ Process an underloaded host: migrate all VMs from the host.

1. Prepare the data about the current states of the hosts and VMs.

2. Call the function specified in the `algorithm_vm_placement_factory`
   configuration option and pass the data on the states of the hosts and VMs.

3. Call the Nova API to migrate the VMs according to the placement
   determined by the `algorithm_vm_placement_factory` algorithm.

4. Switch off the host at the end of the VM migration.

    :param config: A config dictionary.
     :type config: dict(str: *)

    :param state: A state dictionary.
     :type state: dict(str: *)

    :param host: A host name.
     :type host: str

    :return: The updated state dictionary.
     :rtype: dict(str: *)
    """
    log.info('Started processing an underload request')
    underloaded_host = host
    hosts_cpu_total, _, hosts_ram_total = state[
        'db'].select_host_characteristics()

    hosts_to_vms = vms_by_hosts(state['nova'], state['compute_hosts'])
    vms_last_cpu = state['db'].select_last_cpu_mhz_for_vms()
    hosts_last_cpu = state['db'].select_last_cpu_mhz_for_hosts()

    # Remove VMs from hosts_to_vms that are not in vms_last_cpu
    # These VMs are new and no data have been collected from them
    for host, vms in hosts_to_vms.items():
        for i, vm in enumerate(vms):
            if not vm in vms_last_cpu:
                del hosts_to_vms[host][i]

    if log.isEnabledFor(logging.DEBUG):
        log.debug('hosts_to_vms: %s', str(hosts_to_vms))

    hosts_cpu_usage = {}
    hosts_ram_usage = {}
    hosts_to_keep_active = set()
    for host, vms in hosts_to_vms.items():
        if vms:
            host_cpu_mhz = hosts_last_cpu[host]
            for vm in vms:
                if vm not in vms_last_cpu:
                    log.info('No data yet for VM: %s - skipping host %s', vm,
                             host)
                    hosts_to_keep_active.add(host)
                    del hosts_cpu_total[host]
                    del hosts_ram_total[host]
                    if host in hosts_cpu_usage:
                        del hosts_cpu_usage[host]
                    if host in hosts_ram_usage:
                        del hosts_ram_usage[host]
                    break
                host_cpu_mhz += vms_last_cpu[vm]
            else:
                hosts_cpu_usage[host] = host_cpu_mhz
                hosts_ram_usage[host] = host_used_ram(state['nova'], host)
        else:
            # Exclude inactive hosts
            del hosts_cpu_total[host]
            del hosts_ram_total[host]

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    # Exclude the underloaded host
    del hosts_cpu_usage[underloaded_host]
    del hosts_cpu_total[underloaded_host]
    del hosts_ram_usage[underloaded_host]
    del hosts_ram_total[underloaded_host]

    if log.isEnabledFor(logging.DEBUG):
        log.debug('Excluded the underloaded host %s', underloaded_host)
        log.debug('Host CPU usage: %s', str(hosts_last_cpu))
        log.debug('Host total CPU usage: %s', str(hosts_cpu_usage))

    vms_to_migrate = vms_by_host(state['nova'], underloaded_host)
    vms_cpu = {}
    for vm in vms_to_migrate:
        if vm not in vms_last_cpu:
            log.info('No data yet for VM: %s - dropping the request', vm)
            log.info('Skipped an underload request')
            return state
        vms_cpu[vm] = state['db'].select_cpu_mhz_for_vm(
            vm, int(config['data_collector_data_length']))
    vms_ram = vms_ram_limit(state['nova'], vms_to_migrate)

    # Remove VMs that are not in vms_ram
    # These instances might have been deleted
    for i, vm in enumerate(vms_to_migrate):
        if not vm in vms_ram:
            del vms_to_migrate[i]

    for vm in vms_cpu.keys():
        if not vm in vms_ram:
            del vms_cpu[vm]

    time_step = int(config['data_collector_interval'])
    migration_time = common.calculate_migration_time(
        vms_ram, float(config['network_migration_bandwidth']))

    if 'vm_placement' not in state:
        vm_placement_params = common.parse_parameters(
            config['algorithm_vm_placement_parameters'])
        vm_placement_state = None
        vm_placement = common.call_function_by_name(
            config['algorithm_vm_placement_factory'],
            [time_step, migration_time, vm_placement_params])
        state['vm_placement'] = vm_placement
        state['vm_placement_state'] = {}
    else:
        vm_placement = state['vm_placement']
        vm_placement_state = state['vm_placement_state']

    log.info('Started underload VM placement')
    placement, vm_placement_state = vm_placement(
        hosts_cpu_usage, hosts_cpu_total, hosts_ram_usage, hosts_ram_total, {},
        {}, vms_cpu, vms_ram, vm_placement_state)
    log.info('Completed underload VM placement')
    state['vm_placement_state'] = vm_placement_state

    if log.isEnabledFor(logging.INFO):
        log.info('Underload: obtained a new placement %s', str(placement))

    active_hosts = hosts_cpu_total.keys()
    inactive_hosts = set(state['compute_hosts']) - set(active_hosts)
    prev_inactive_hosts = set(state['db'].select_inactive_hosts())
    hosts_to_deactivate = list(inactive_hosts - prev_inactive_hosts -
                               hosts_to_keep_active)

    if not placement:
        log.info('Nothing to migrate')
        if underloaded_host in hosts_to_deactivate:
            hosts_to_deactivate.remove(underloaded_host)
    else:
        log.info('Started underload VM migrations')
        migrate_vms(state['db'], state['nova'],
                    config['vm_instance_directory'], placement)
        log.info('Completed underload VM migrations')

    if hosts_to_deactivate:
        switch_hosts_off(state['db'], config['sleep_command'],
                         hosts_to_deactivate)

    log.info('Completed processing an underload request')
    return state