def execute(self, ctx=None): """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. """ LOG.info('Started an iteration') state = self.state vm_path = common.build_local_vm_path(CONF.local_data_directory) vm_cpu_mhz = self.get_local_vm_data(vm_path) vm_ram = self.get_ram(state['vir_connection'], vm_cpu_mhz.keys()) vm_cpu_mhz = self.cleanup_vm_data(vm_cpu_mhz, vm_ram.keys()) if not vm_cpu_mhz: LOG.info('Skipped an iteration') return host_path = common.build_local_host_path(CONF.local_data_directory) host_cpu_mhz = self.get_local_host_data(host_path) host_cpu_utilization = self.vm_mhz_to_percentage( vm_cpu_mhz.values(), host_cpu_mhz, state['physical_cpu_mhz_total']) 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 time_step = CONF.data_collector_interval migration_time = common.calculate_migration_time( vm_ram, CONF.network_migration_bandwidth) if 'underload_detection' not in state: underload_detection_params = common.parse_parameters( CONF.local_manager.algorithm_underload_detection_parameters) underload_detection = common.call_function_by_name( CONF.local_manager.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( CONF.local_manager.algorithm_overload_detection_parameters) overload_detection = common.call_function_by_name( CONF.local_manager.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( CONF.local_manager.algorithm_vm_selection_parameters) vm_selection = common.call_function_by_name( CONF.local_manager.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'] LOG.info('Started underload detection') underload, state['underload_detection_state'] = underload_detection( host_cpu_utilization, state['underload_detection_state']) LOG.info('Completed underload detection') LOG.info('Started overload detection') overload, state['overload_detection_state'] = overload_detection( host_cpu_utilization, state['overload_detection_state']) LOG.info('Completed overload detection') if underload: LOG.info('Underload detected') # TODO(xylan): send rpc message to global manager else: if overload: 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') LOG.info('Selected VMs to migrate: %s', str(vm_uuids)) # TODO(xylan): send rpc message to global manager else: LOG.info('No underload or overload detected') LOG.info('Completed an iteration') self.state = state
def execute_overload(self, 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. """ LOG.info('Started processing an overload request') overloaded_host = host hosts_cpu_total, _, hosts_ram_total = self.state[ 'db'].select_host_characteristics() hosts_to_vms = vms_by_hosts(state['nova'], self.state['compute_hosts']) vms_last_cpu = self.state['db'].select_last_cpu_mhz_for_vms() hosts_last_cpu = self.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(self.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) 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 self.state vms_cpu[vm] = self.state['db'].select_cpu_mhz_for_vm( vm, CONF.data_collector_data_length) vms_ram = vms_ram_limit(self.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 self.state for vm in vms_cpu.keys(): if not vm in vms_ram: del vms_cpu[vm] time_step = CONF.data_collector_interval migration_time = common.calculate_migration_time( vms_ram, CONF.network_migration_bandwidth) if 'vm_placement' not in state: vm_placement_params = common.parse_parameters( CONF.global_manager.algorithm_vm_placement_parameters) vm_placement_state = None vm_placement = common.call_function_by_name( CONF.global_manager.algorithm_vm_placement_factory, [time_step, migration_time, vm_placement_params]) self.state['vm_placement'] = vm_placement self.state['vm_placement_state'] = {} else: vm_placement = self.state['vm_placement'] vm_placement_state = self.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') self.state['vm_placement_state'] = vm_placement_state 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: self.switch_hosts_on(hosts_to_activate) LOG.info('Started overload VM migrations') migrate_vms(self.state['db'], self.state['nova'], CONF.global_manager.vm_instance_directory, placement, CONF.global_manager.block_migration) LOG.info('Completed overload VM migrations') LOG.info('Completed processing an overload request') return state
def execute(self, ctx=None): """ 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. """ LOG.info('Started an iteration') state = self.state vm_path = common.build_local_vm_path(CONF.local_data_directory) vm_cpu_mhz = self.get_local_vm_data(vm_path) vm_ram = self.get_ram(state['vir_connection'], vm_cpu_mhz.keys()) vm_cpu_mhz = self.cleanup_vm_data(vm_cpu_mhz, vm_ram.keys()) if not vm_cpu_mhz: LOG.info('Skipped an iteration') return host_path = common.build_local_host_path(CONF.local_data_directory) host_cpu_mhz = self.get_local_host_data(host_path) host_cpu_utilization = self.vm_mhz_to_percentage( vm_cpu_mhz.values(), host_cpu_mhz, state['physical_cpu_mhz_total']) 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 time_step = CONF.data_collector_interval migration_time = common.calculate_migration_time( vm_ram, CONF.network_migration_bandwidth) if 'underload_detection' not in state: underload_detection_params = common.parse_parameters( CONF.local_manager.algorithm_underload_detection_parameters) underload_detection = common.call_function_by_name( CONF.local_manager.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( CONF.local_manager.algorithm_overload_detection_parameters) overload_detection = common.call_function_by_name( CONF.local_manager.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( CONF.local_manager.algorithm_vm_selection_parameters) vm_selection = common.call_function_by_name( CONF.local_manager.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'] LOG.info('Started underload detection') underload, state['underload_detection_state'] = underload_detection( host_cpu_utilization, state['underload_detection_state']) LOG.info('Completed underload detection') LOG.info('Started overload detection') overload, state['overload_detection_state'] = overload_detection( host_cpu_utilization, state['overload_detection_state']) LOG.info('Completed overload detection') if underload: LOG.info('Underload detected') # TODO(xylan): send rpc message to global manager else: if overload: 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') LOG.info('Selected VMs to migrate: %s', str(vm_uuids)) # TODO(xylan): send rpc message to global manager else: LOG.info('No underload or overload detected') LOG.info('Completed an iteration') self.state = state
def execute_overload(self, 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. """ LOG.info('Started processing an overload request') overloaded_host = host hosts_cpu_total, _, hosts_ram_total = self.state[ 'db'].select_host_characteristics() hosts_to_vms = vms_by_hosts(self.state['nova'], self.state['compute_hosts']) vms_last_cpu = self.state['db'].select_last_cpu_mhz_for_vms() hosts_last_cpu = self.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 vm not 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( self.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) 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 self.state vms_cpu[vm] = self.state['db'].select_cpu_mhz_for_vm( vm, CONF.data_collector_data_length) vms_ram = vms_ram_limit(self.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 vm not in vms_ram: del vms_to_migrate[i] if not vms_to_migrate: LOG.info('No VMs to migrate - completed the overload request') return self.state for vm in vms_cpu.keys(): if vm not in vms_ram: del vms_cpu[vm] time_step = CONF.data_collector_interval migration_time = common.calculate_migration_time( vms_ram, CONF.network_migration_bandwidth) if 'vm_placement' not in self.state: vm_placement_params = common.parse_parameters( CONF.global_manager.algorithm_vm_placement_parameters) vm_placement_state = None vm_placement = common.call_function_by_name( CONF.global_manager.algorithm_vm_placement_factory, [time_step, migration_time, vm_placement_params]) self.state['vm_placement'] = vm_placement self.state['vm_placement_state'] = {} else: vm_placement = self.state['vm_placement'] vm_placement_state = self.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') self.state['vm_placement_state'] = vm_placement_state 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: self.switch_hosts_on(hosts_to_activate) LOG.info('Started overload VM migrations') migrate_vms(self.state['db'], self.state['nova'], CONF.global_manager.vm_instance_directory, placement, CONF.global_manager.block_migration) LOG.info('Completed overload VM migrations') LOG.info('Completed processing an overload request') return self.state