diff --git a/neat/locals/collector.py b/neat/locals/collector.py index 2567d44..c63f30c 100644 --- a/neat/locals/collector.py +++ b/neat/locals/collector.py @@ -508,7 +508,7 @@ def append_host_data_locally(path, cpu_mhz, data_length): :type path: str :param cpu_mhz: A CPU MHz value. - :type cpu_mhz: int + :type cpu_mhz: int,>=0 :param data_length: The maximum allowed length of the data. :type data_length: int @@ -536,7 +536,7 @@ def append_host_data_remotely(db, hostname, host_cpu_mhz): :type hostname: str :param host_cpu_mhz: An average host CPU utilization in MHz. - :type host_cpu_mhz: int + :type host_cpu_mhz: int,>=0 """ db.insert_host_cpu_mhz(hostname, host_cpu_mhz) @@ -575,8 +575,14 @@ def get_cpu_mhz(vir_connection, physical_core_mhz, previous_cpu_time, removed_vms = get_removed_vms(previous_vms, current_vms) cpu_mhz = {} + for uuid in removed_vms: + del previous_cpu_time[uuid] + for uuid, cpu_time in previous_cpu_time.items(): current_cpu_time = get_cpu_time(vir_connection, uuid) + if current_cpu_time == 0: + # libvirt error workaround + current_cpu_time = cpu_time cpu_mhz[uuid] = calculate_cpu_mhz(physical_core_mhz, previous_time, current_time, cpu_time, current_cpu_time) @@ -591,10 +597,6 @@ def get_cpu_mhz(vir_connection, physical_core_mhz, previous_cpu_time, cpu_mhz[uuid] = added_vm_data[uuid][-1] previous_cpu_time[uuid] = get_cpu_time(vir_connection, uuid) - for uuid in removed_vms: - del previous_cpu_time[uuid] - del cpu_mhz[uuid] - return previous_cpu_time, cpu_mhz @@ -609,7 +611,7 @@ def get_cpu_time(vir_connection, uuid): :type uuid: str[36] :return: The CPU time of the VM. - :rtype: number + :rtype: number,>=0 """ try: domain = vir_connection.lookupByUUIDString(uuid) @@ -639,7 +641,7 @@ def calculate_cpu_mhz(cpu_mhz, previous_time, current_time, :type current_cpu_time: number :return: The average CPU utilization in MHz. - :rtype: int + :rtype: int,>=0 """ return int(cpu_mhz * float(current_cpu_time - previous_cpu_time) / \ ((current_time - previous_time) * 1000000000)) @@ -662,10 +664,18 @@ def get_host_cpu_mhz(cpu_mhz, previous_cpu_time_total, previous_cpu_time_busy): :rtype: tuple(float, float, int) """ cpu_time_total, cpu_time_busy = get_host_cpu_time() + cpu_usage = int(cpu_mhz * (cpu_time_busy - previous_cpu_time_busy) / \ + (cpu_time_total - previous_cpu_time_total)) + if cpu_usage < 0: + raise ValueError('The host CPU usage in MHz must be >=0, but it is: ' + str(cpu_usage) + + '; cpu_mhz=' + str(cpu_mhz) + + '; previous_cpu_time_total=' + str(previous_cpu_time_total) + + '; cpu_time_total=' + str(cpu_time_total) + + '; previous_cpu_time_busy=' + str(previous_cpu_time_busy) + + '; cpu_time_busy=' + str(cpu_time_busy)) return cpu_time_total, \ cpu_time_busy, \ - int(cpu_mhz * (cpu_time_busy - previous_cpu_time_busy) / \ - (cpu_time_total - previous_cpu_time_total)) + cpu_usage @contract() diff --git a/tests/locals/test_collector.py b/tests/locals/test_collector.py index 7ac7328..443e31e 100644 --- a/tests/locals/test_collector.py +++ b/tests/locals/test_collector.py @@ -74,9 +74,9 @@ class Collector(TestCase): db = mock('db') expect(collector).init_db('db').and_return(db).once() - expect(db).update_host(hostname, - int(mhz * 0.75), - physical_cpus, + expect(db).update_host(hostname, + int(mhz * 0.75), + physical_cpus, ram).once() state = collector.init_state(config) @@ -87,7 +87,7 @@ class Collector(TestCase): assert state['previous_overload'] == -1 assert state['vir_connection'] == vir_connection assert state['hostname'] == hostname - self.assertAlmostEqual(state['host_cpu_overload_threshold'], + self.assertAlmostEqual(state['host_cpu_overload_threshold'], 0.7125, 3) assert state['physical_cpus'] == physical_cpus assert state['physical_cpu_mhz'] == mhz @@ -498,7 +498,7 @@ class Collector(TestCase): previous_cpu_time, current_cpu_time) == \ int((mhz * cpu_time / (time_period * 1000000000))) - @qc(1) + @qc def get_host_cpu_mhz( cpu_mhz=int_(min=1, max=1000), prev_total=float_(min=100, max=1000), @@ -516,6 +516,22 @@ class Collector(TestCase): busy, int(cpu_mhz * diff_busy / diff_total)) + @qc(1) + def get_host_cpu_mhz_exception(): + cpu_mhz = 1 + total = 1. + prev_total = 0. + busy = 1. + prev_busy = 2. + with MockTransaction: + expect(collector).get_host_cpu_time(). \ + and_return((total, busy)).once() + try: + collector.get_host_cpu_mhz(cpu_mhz, prev_total, prev_busy) + assert False + except ValueError: + assert True + @qc(10) def get_host_cpu_time( x=list_(of=int_(min=1, max=1000), min_length=7, max_length=7) @@ -528,7 +544,7 @@ class Collector(TestCase): expect(collector).open('/proc/stat', 'r').and_return(context).once() expect(f).readline().and_return( '1 ' + ' '.join([str(v) for v in x]) + ' 2 3').once() - assert collector.get_host_cpu_time() == (float(sum(x)), + assert collector.get_host_cpu_time() == (float(sum(x)), float(sum(x[0:3]))) @qc(10) @@ -549,29 +565,29 @@ class Collector(TestCase): db = db_utils.init_db('sqlite:///:memory:') with MockTransaction: expect(db).insert_host_overload('host', 1).once() - assert collector.log_host_overload(db, 0.9, 'host', -1, 3000, + assert collector.log_host_overload(db, 0.9, 'host', -1, 3000, [1000, 1000, 800]) with MockTransaction: expect(db).insert_host_overload('host', 0).once() - assert not collector.log_host_overload(db, 0.9, 'host', -1, 3000, + assert not collector.log_host_overload(db, 0.9, 'host', -1, 3000, [1000, 1000, 600]) with MockTransaction: expect(db).insert_host_overload('host', 1).once() - assert collector.log_host_overload(db, 0.9, 'host', 0, 3000, + assert collector.log_host_overload(db, 0.9, 'host', 0, 3000, [1000, 1000, 800]) with MockTransaction: expect(db).insert_host_overload('host', 0).once() - assert not collector.log_host_overload(db, 0.9, 'host', 1, 3000, + assert not collector.log_host_overload(db, 0.9, 'host', 1, 3000, [1000, 1000, 600]) with MockTransaction: expect(db).insert_host_overload.never() - assert collector.log_host_overload(db, 0.9, 'host', 1, 3000, + assert collector.log_host_overload(db, 0.9, 'host', 1, 3000, [1000, 1000, 800]) with MockTransaction: expect(db).insert_host_overload.never() - assert not collector.log_host_overload(db, 0.9, 'host', 0, 3000, + assert not collector.log_host_overload(db, 0.9, 'host', 0, 3000, [1000, 1000, 600])