Remove PyContracts dependency

Change-Id: I74e73a13e7efa53086bfdcfa997b115e99a13905
This commit is contained in:
LingxianKong 2015-05-04 17:27:26 +08:00
parent 7e9c515ac7
commit f8391cc9fd
7 changed files with 5 additions and 369 deletions

48
NOTICE
View File

@ -1,48 +0,0 @@
OpenStack Neat
Copyright 2012 Anton Beloglazov
This product includes software developed at the Cloud Computing and
Distributed Systems (CLOUDS) Laboratory, Department of Computing and
Information Systems, The University of Melbourne, Australia
(http://www.cloudbus.org/).
This software uses distribute, a library for working with Python
module distributions developed by Tarek Ziadé, released under the
Python Software Foundation License, and available from
https://bitbucket.org/tarek/distribute
This software uses pyqcy, a QuickCheck-like testing framework for
Python developed by Karol Kuczmarski, released under the FreeBSD
License, and available from https://github.com/Xion/pyqcy
This software uses PyContracts, a Python library for supporting Design
by Contract (DbC) developed by Andrea Censi, released under the GNU
Lesser General Public License, and available from
https://github.com/AndreaCensi/contracts
This software uses SQLAlchemy, a Python SQL toolkit and Object
Relational Mapper developed by the SQLAlchemy (trademark of Michael
Bayer) authors and contributors, released under the MIT License, and
available from http://www.sqlalchemy.org/
This software uses Bottle, a micro web-framework for Python developed
by Marcel Hellkamp, released under the MIT License, and available from
http://bottlepy.org/
This software uses Requests, a Python HTTP client library developed by
Kenneth Reitz, released under the ISC License, and available from
http://python-requests.org.
This software uses libvirt, a virtualization toolkit with Python
bindings developed by Red Hat, released under the LGPL licensem and
available from http://libvirt.org/
This software uses python-novaclient, a Python Nova API client
implementation developed by Jacob Kaplan-Moss and Rackspace -
OpenStack extensions, released under the Apache 2.0 License, and
available from https://github.com/openstack/python-novaclient
This software uses Sphinx, a documentation generator for Python
developed by Georg Brandl, released under the BSD License, and
available from http://sphinx.pocoo.org/

View File

@ -1,33 +1,16 @@
alembic>=0.7.2
pbr>=0.6,!=0.7,<1.0
eventlet>=0.15.0
PyYAML>=3.1.0
pecan>=0.8.0
WSME>=0.6
amqplib>=0.6.1 # This is not in global requirements (master branch)
argparse
Babel>=1.3
iso8601>=0.1.9
posix_ipc
croniter>=0.3.4 # MIT License
requests>=1.2.1,!=2.4.0
kombu>=2.4.8
oslo.config>=1.4.0,<1.10.0 # Apache-2.0
oslo.db>=1.0.0 # Apache-2.0
oslo.messaging>=1.4.0
oslo.utils>=1.2.0,<1.5.0 # Apache-2.0
paramiko>=1.13.0
python-cinderclient>=1.1.0
python-heatclient>=0.2.9
python-keystoneclient>=0.10.0
python-neutronclient>=2.3.6,<3
python-novaclient>=2.18.0
python-glanceclient>=0.14.0
networkx>=1.8
six>=1.7.0
SQLAlchemy>=0.9.7,<=0.9.99
stevedore>=1.0.0 # Apache-2.0
yaql==0.2.4 # This is not in global requirements
jsonschema>=2.0.0,<3.0.0
mock>=1.0
keystonemiddleware>=1.0.0
libvirt-python>=1.2.5 # LGPLv2+

View File

@ -1,32 +0,0 @@
# Copyright 2012 Anton Beloglazov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from contracts import new_contract
import collections
new_contract('deque', collections.deque)
import datetime
new_contract('datetime', datetime.datetime)
import libvirt
new_contract('virConnect', libvirt.virConnect)
new_contract('virDomain', libvirt.virDomain)
import sqlalchemy
new_contract('Table', sqlalchemy.Table)
import neat.db
new_contract('Database', neat.db.Database)

View File

@ -1,19 +0,0 @@
# Copyright 2012 Anton Beloglazov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from contracts import new_contract
new_contract('long', lambda x: isinstance(x, (int, long)))
new_contract('function', lambda x: hasattr(x, '__call__'))

View File

@ -78,15 +78,12 @@ else:
import subprocess
import time
from contracts import contract
import novaclient
from novaclient.v2 import client
from oslo_config import cfg
from oslo_log import log as logging
from terracotta import common
from terracotta.contracts_primitive import *
from terracotta.contracts_extra import *
from terracotta.utils import db_utils
@ -94,15 +91,11 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@contract
def host_mac(host):
""" Get mac address of a host.
:param host: A host name.
:type host: str
:return: The mac address of the host.
:rtype: str
"""
mac = subprocess.Popen(
("ping -c 1 {0} > /dev/null;" +
@ -116,31 +109,21 @@ def host_mac(host):
return mac
@contract
def flavors_ram(nova):
""" Get a dict of flavor IDs to the RAM limits.
:param nova: A Nova client.
:type nova: *
:return: A dict of flavor IDs to the RAM limits.
:rtype: dict(str: int)
"""
return dict((str(fl.id), fl.ram) for fl in nova.flavors.list())
@contract
def vms_ram_limit(nova, vms):
""" Get the RAM limit from the flavors of the VMs.
:param nova: A Nova client.
:type nova: *
:param vms: A list of VM UUIDs.
:type vms: list(str)
:return: A dict of VM UUIDs to the RAM limits.
:rtype: dict(str: int)
"""
flavors_to_ram = flavors_ram(nova)
vms_ram = {}
@ -153,18 +136,12 @@ def vms_ram_limit(nova, vms):
return vms_ram
@contract
def host_used_ram(nova, host):
""" Get the used RAM of the host using the Nova API.
:param nova: A Nova client.
:type nova: *
:param host: A host name.
:type host: str
:return: The used RAM of the host.
:rtype: int
"""
data = nova.hosts.get(host)
if len(data) > 2 and data[2].memory_mb != 0:
@ -172,18 +149,12 @@ def host_used_ram(nova, host):
return data[1].memory_mb
@contract
def vms_by_hosts(nova, hosts):
""" Get a map of host names to VMs using the Nova API.
:param nova: A Nova client.
:type nova: *
:param hosts: A list of host names.
:type hosts: list(str)
:return: A dict of host names to lists of VM UUIDs.
:rtype: dict(str: list(str))
"""
result = dict((host, []) for host in hosts)
for vm in nova.servers.list():
@ -191,55 +162,35 @@ def vms_by_hosts(nova, hosts):
return result
@contract
def vms_by_host(nova, host):
""" Get VMs from the specified host using the Nova API.
:param nova: A Nova client.
:type nova: *
:param host: A host name.
:type host: str
:return: A list of VM UUIDs from the specified host.
:rtype: list(str)
"""
return [str(vm.id) for vm in nova.servers.list()
if (vm_hostname(vm) == host and str(
getattr(vm, 'OS-EXT-STS:vm_state')) == 'active')]
@contract
def vm_hostname(vm):
""" Get the name of the host where VM is running.
:param vm: A Nova VM object.
:type vm: *
:return: The hostname.
:rtype: str
"""
return str(getattr(vm, 'OS-EXT-SRV-ATTR:host'))
@contract
def migrate_vms(db, nova, vm_instance_directory, placement, block_migration):
""" Synchronously live migrate a set of VMs.
:param db: The database object.
:type db: Database
:param nova: A Nova client.
:type nova: *
:param vm_instance_directory: The VM instance directory.
:type vm_instance_directory: str
:param placement: A dict of VM UUIDs to host names.
:type placement: dict(str: str)
:param block_migration: Whether to use block migration.
:type block_migration: bool
"""
retry_placement = {}
vms = placement.keys()
@ -288,24 +239,14 @@ def migrate_vms(db, nova, vm_instance_directory, placement, block_migration):
retry_placement, block_migration)
@contract
def migrate_vm(nova, vm_instance_directory, vm, host, block_migration):
""" Live migrate a VM.
:param nova: A Nova client.
:type nova: *
:param vm_instance_directory: The VM instance directory.
:type vm_instance_directory: str
:param vm: The UUID of a VM to migrate.
:type vm: str
:param host: The name of the destination host.
:type host: str
:param block_migration: Whether to use block migration.
:type block_migration: bool
"""
# To avoid problems with migration, need the following:
subprocess.call('chown -R nova:nova ' + vm_instance_directory,
@ -314,18 +255,12 @@ def migrate_vm(nova, vm_instance_directory, vm, host, block_migration):
LOG.info('Started migration of VM %s to %s', vm, host)
@contract
def switch_hosts_off(db, sleep_command, hosts):
""" Switch hosts to a low-power mode.
:param db: The database object.
:type db: Database
:param sleep_command: A Shell command to switch off a host.
:type sleep_command: str
:param hosts: A list of hosts to switch off.
:type hosts: list(str)
"""
if sleep_command:
for host in hosts:
@ -378,7 +313,6 @@ class GlobalManager(object):
dict((x, 1) for x in hosts))
@contract
def execute_underload(self, host):
""" Process an underloaded host: migrate all VMs from the host.
@ -393,10 +327,7 @@ class GlobalManager(object):
4. Switch off the host at the end of the VM migration.
: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

View File

@ -91,7 +91,6 @@ invoked, the component performs the following steps:
"""
from collections import deque
from contracts import contract
import libvirt
import os
import time
@ -100,8 +99,6 @@ from oslo_config import cfg
from oslo_log import log as logging
from terracotta import common
from terracotta.contracts_extra import *
from terracotta.contracts_primitive import *
from terracotta.openstack.common import periodic_task
from terracotta.openstack.common import threadgroup
from terracotta.utils import db_utils
@ -133,16 +130,8 @@ class Collector(periodic_task.PeriodicTasks):
context=None
)
@contract
def init_state(self):
""" Initialize a dict for storing the state of the data collector.
:param config: A config dictionary.
:type config: dict(str: *)
:return: A dict containing the initial state of the data collector.
:rtype: dict
"""
""" Initialize a dict for storing the state of the data collector."""
vir_connection = libvirt.openReadOnly(None)
if vir_connection is None:
message = 'Failed to open a connection to the hypervisor'
@ -302,28 +291,20 @@ class Collector(periodic_task.PeriodicTasks):
self.state = state
@contract
def get_previous_vms(self, path):
""" Get a list of VM UUIDs from the path.
:param path: A path to read VM UUIDs from.
:type path: str
:return: The list of VM UUIDs from the path.
:rtype: list(str)
"""
return os.listdir(path)
@contract()
def get_current_vms(self, vir_connection):
""" Get a dict of VM UUIDs to states from libvirt.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:return: The dict of VM UUIDs to states from libvirt.
:rtype: dict(str: int)
"""
vm_uuids = {}
for vm_id in vir_connection.listDomainsID():
@ -335,74 +316,50 @@ class Collector(periodic_task.PeriodicTasks):
return vm_uuids
@contract
def get_added_vms(self, previous_vms, current_vms):
""" Get a list of newly added VM UUIDs.
:param previous_vms: A list of VMs at the previous time frame.
:type previous_vms: list(str)
:param current_vms: A list of VM at the current time frame.
:type current_vms: list(str)
:return: A list of VM UUIDs added since the last time frame.
:rtype: list(str)
"""
return self.substract_lists(current_vms, previous_vms)
@contract
def get_removed_vms(self, previous_vms, current_vms):
""" Get a list of VM UUIDs removed since the last time frame.
:param previous_vms: A list of VMs at the previous time frame.
:type previous_vms: list(str)
:param current_vms: A list of VM at the current time frame.
:type current_vms: list(str)
:return: A list of VM UUIDs removed since the last time frame.
:rtype: list(str)
"""
return substract_lists(previous_vms, current_vms)
@contract
def substract_lists(self, list1, list2):
""" Return the elements of list1 that are not in list2.
:param list1: The first list.
:type list1: list
:param list2: The second list.
:type list2: list
:return: The list of element of list 1 that are not in list2.
:rtype: list
"""
return list(set(list1).difference(list2))
@contract
def cleanup_local_vm_data(self, path, vms):
""" Delete the local data related to the removed VMs.
:param path: A path to remove VM data from.
:type path: str
:param vms: A list of removed VM UUIDs.
:type vms: list(str)
"""
for vm in vms:
os.remove(os.path.join(path, vm))
@contract
def cleanup_all_local_data(self, path):
""" Delete all the local data about VMs.
:param path: A path to the local data directory.
:type path: str
"""
vm_path = common.build_local_vm_path(path)
cleanup_local_vm_data(vm_path, os.listdir(vm_path))
@ -411,21 +368,13 @@ class Collector(periodic_task.PeriodicTasks):
os.remove(host_path)
@contract
def fetch_remote_data(self, db, data_length, uuids):
""" Fetch VM data from the central DB.
:param db: The database object.
:type db: Database
:param data_length: The length of data to fetch.
:type data_length: int
:param uuids: A list of VM UUIDs to fetch data for.
:type uuids: list(str)
:return: A dictionary of VM UUIDs and the corresponding data.
:rtype: dict(str : list(int))
"""
result = dict()
for uuid in uuids:
@ -433,18 +382,12 @@ class Collector(periodic_task.PeriodicTasks):
return result
@contract
def write_vm_data_locally(self, path, data, data_length):
""" Write a set of CPU MHz values for a set of VMs.
:param path: A path to write the data to.
:type path: str
:param data: A map of VM UUIDs onto the corresponing CPU MHz history.
:type data: dict(str : list(int))
:param data_length: The maximum allowed length of the data.
:type data_length: int
"""
for uuid, values in data.items():
with open(os.path.join(path, uuid), 'w') as f:
@ -453,18 +396,12 @@ class Collector(periodic_task.PeriodicTasks):
for x in values[-data_length:]]) + '\n')
@contract
def append_vm_data_locally(self, path, data, data_length):
""" Write a CPU MHz value for each out of a set of VMs.
:param path: A path to write the data to.
:type path: str
:param data: A map of VM UUIDs onto the corresponing CPU MHz values.
:type data: dict(str : int)
:param data_length: The maximum allowed length of the data.
:type data_length: int
"""
for uuid, value in data.items():
vm_path = os.path.join(path, uuid)
@ -480,31 +417,21 @@ class Collector(periodic_task.PeriodicTasks):
f.write('\n'.join([str(x) for x in values]) + '\n')
@contract
def append_vm_data_remotely(self, db, data):
""" Submit CPU MHz values to the central database.
:param db: The database object.
:type db: Database
:param data: A map of VM UUIDs onto the corresponing CPU MHz values.
:type data: dict(str : int)
"""
db.insert_vm_cpu_mhz(data)
@contract
def append_host_data_locally(self, path, cpu_mhz, data_length):
""" Write a CPU MHz value for the host.
:param path: A path to write the data to.
:type path: str
:param cpu_mhz: A CPU MHz value.
:type cpu_mhz: int,>=0
:param data_length: The maximum allowed length of the data.
:type data_length: int
"""
if not os.access(path, os.F_OK):
with open(path, 'w') as f:
@ -518,54 +445,30 @@ class Collector(periodic_task.PeriodicTasks):
f.write('\n'.join([str(x) for x in values]) + '\n')
@contract
def append_host_data_remotely(self, db, hostname, host_cpu_mhz):
""" Submit a host CPU MHz value to the central database.
:param db: The database object.
:type db: Database
:param hostname: The host name.
:type hostname: str
:param host_cpu_mhz: An average host CPU utilization in MHz.
:type host_cpu_mhz: int,>=0
"""
db.insert_host_cpu_mhz(hostname, host_cpu_mhz)
@contract
def get_cpu_mhz(self, vir_connection, physical_core_mhz, previous_cpu_time,
previous_time, current_time, current_vms,
previous_cpu_mhz, added_vm_data):
""" Get the average CPU utilization in MHz for a set of VMs.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:param physical_core_mhz: The core frequency of the physical CPU in MHz.
:type physical_core_mhz: int
:param previous_cpu_time: A dict of previous CPU times for the VMs.
:type previous_cpu_time: dict(str : int)
:param previous_time: The previous timestamp.
:type previous_time: float
:param current_time: The previous timestamp.
:type current_time: float
:param current_vms: A list of VM UUIDs.
:type current_vms: list(str)
:param previous_cpu_mhz: A dict of VM UUIDs and previous CPU MHz.
:type previous_cpu_mhz: dict(str : int)
:param added_vm_data: A dict of VM UUIDs and the corresponding data.
:type added_vm_data: dict(str : list(int))
:return: The updated CPU times and average CPU utilization in MHz.
:rtype: tuple(dict(str : int), dict(str : int))
"""
previous_vms = previous_cpu_time.keys()
added_vms = self.get_added_vms(previous_vms, current_vms)
@ -608,18 +511,12 @@ class Collector(periodic_task.PeriodicTasks):
return previous_cpu_time, cpu_mhz
@contract
def get_cpu_time(self, vir_connection, uuid):
""" Get the CPU time of a VM specified by the UUID using libvirt.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:param uuid: The UUID of a VM.
:type uuid: str[36]
:return: The CPU time of the VM.
:rtype: int,>=0
"""
try:
domain = vir_connection.lookupByUUIDString(uuid)
@ -628,49 +525,29 @@ class Collector(periodic_task.PeriodicTasks):
return 0
@contract
def calculate_cpu_mhz(self, cpu_mhz, previous_time, current_time,
previous_cpu_time, current_cpu_time):
""" Calculate the average CPU utilization in MHz for a period of time.
:param cpu_mhz: The frequency of a core of the physical CPU in MHz.
:type cpu_mhz: int
:param previous_time: The previous time.
:type previous_time: float
:param current_time: The current time.
:type current_time: float
:param previous_cpu_time: The previous CPU time of the domain.
:type previous_cpu_time: int
:param current_cpu_time: The current CPU time of the domain.
:type current_cpu_time: int
:return: The average CPU utilization in MHz.
:rtype: int,>=0
"""
return int(cpu_mhz * float(current_cpu_time - previous_cpu_time) / \
((current_time - previous_time) * 1000000000))
@contract
def get_host_cpu_mhz(self, cpu_mhz, previous_cpu_time_total,
previous_cpu_time_busy):
""" Get the average CPU utilization in MHz for a set of VMs.
:param cpu_mhz: The total frequency of the physical CPU in MHz.
:type cpu_mhz: int
:param previous_cpu_time_total: The previous total CPU time.
:type previous_cpu_time_total: float
:param previous_cpu_time_busy: The previous busy CPU time.
:type previous_cpu_time_busy: float
:return: The current total and busy CPU time, and CPU utilization in MHz.
: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) / \
@ -687,63 +564,43 @@ class Collector(periodic_task.PeriodicTasks):
return cpu_time_total, cpu_time_busy, cpu_usage
@contract()
def get_host_cpu_time(self):
""" Get the total and busy CPU time of the host.
:return: A tuple of the total and busy CPU time.
:rtype: tuple(float, float)
"""
with open('/proc/stat', 'r') as f:
values = [float(x) for x in f.readline().split()[1:8]]
return sum(values), sum(values[0:3])
@contract()
def get_host_characteristics(self, vir_connection):
""" Get the total CPU MHz and RAM of the host.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:return: A tuple of the total CPU MHz and RAM of the host.
:rtype: tuple(int, long)
"""
info = vir_connection.getInfo()
return info[2] * info[3], info[1]
@contract()
def log_host_overload(self, db, overload_threshold, hostname,
previous_overload,
host_total_mhz, host_utilization_mhz):
""" Log to the DB whether the host is overloaded.
:param db: The database object.
:type db: Database
:param overload_threshold: The host overload threshold.
:type overload_threshold: float
:param hostname: The host name.
:type hostname: str
:param previous_overload: Whether the host has been overloaded.
:type previous_overload: int
:param host_total_mhz: The total frequency of the CPU in MHz.
:type host_total_mhz: int
:param host_utilization_mhz: The total CPU utilization in MHz.
:type host_utilization_mhz: int
:return: Whether the host is overloaded.
:rtype: int
"""
overload = overload_threshold * host_total_mhz < host_utilization_mhz
overload_int = int(overload)
if previous_overload != -1 and previous_overload != overload_int \
or previous_overload == -1:
or previous_overload == -1:
db.insert_host_overload(hostname, overload)
LOG.debug('Overload state logged: %s', str(overload))

View File

@ -100,19 +100,15 @@ local manager performs the following steps:
7. Schedule the next execution after local_manager_interval seconds.
"""
from contracts import contract
from hashlib import sha1
import libvirt
import os
import requests
import time
from oslo_config import cfg
from oslo_log import log as logging
from terracotta import common
from terracotta.contracts_primitive import *
from terracotta.contracts_extra import *
from terracotta.openstack.common import periodic_task
from terracotta.openstack.common import threadgroup
from terracotta.utils import db_utils
@ -292,15 +288,11 @@ class LocalManager(periodic_task.PeriodicTasks):
self.state = state
@contract
def get_local_vm_data(self, path):
""" Read the data about VMs from the local storage.
:param path: A path to read VM UUIDs from.
:type path: str
:return: A map of VM UUIDs onto the corresponing CPU MHz values.
:rtype: dict(str : list(int))
"""
result = {}
for uuid in os.listdir(path):
@ -309,15 +301,12 @@ class LocalManager(periodic_task.PeriodicTasks):
return result
@contract
def get_local_host_data(self, path):
""" Read the data about the host from the local storage.
:param path: A path to read the host data from.
:type path: str
:return: A history of the host CPU usage in MHz.
:rtype: list(int)
"""
if not os.access(path, os.F_OK):
return []
@ -326,18 +315,13 @@ class LocalManager(periodic_task.PeriodicTasks):
return result
@contract
def cleanup_vm_data(self, vm_data, uuids):
""" Remove records for the VMs that are not in the list of UUIDs.
:param vm_data: A map of VM UUIDs to some data.
:type vm_data: dict(str: *)
:param uuids: A list of VM UUIDs.
:type uuids: list(str)
:return: The cleaned up map of VM UUIDs to data.
:rtype: dict(str: *)
"""
for uuid, _ in vm_data.items():
if uuid not in uuids:
@ -345,18 +329,12 @@ class LocalManager(periodic_task.PeriodicTasks):
return vm_data
@contract
def get_ram(self, vir_connection, vm_ids):
""" Get the maximum RAM for a set of VM UUIDs.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:param vm_ids: A list of VM UUIDs.
:type vm_ids: list(str)
:return: The maximum RAM for the VM UUIDs.
:rtype: dict(str : long)
"""
vms_ram = {}
for uuid in vm_ids:
@ -367,18 +345,12 @@ class LocalManager(periodic_task.PeriodicTasks):
return vms_ram
@contract
def get_max_ram(self, vir_connection, uuid):
""" Get the max RAM allocated to a VM UUID using libvirt.
:param vir_connection: A libvirt connection object.
:type vir_connection: virConnect
:param uuid: The UUID of a VM.
:type uuid: str[36]
:return: The maximum RAM of the VM in MB.
:rtype: long|None
"""
try:
domain = vir_connection.lookupByUUIDString(uuid)
@ -387,22 +359,14 @@ class LocalManager(periodic_task.PeriodicTasks):
return None
@contract
def vm_mhz_to_percentage(self, vm_mhz_history, host_mhz_history,
physical_cpu_mhz):
""" Convert VM CPU utilization to the host's CPU utilization.
:param vm_mhz_history: A list of CPU utilization histories of VMs in MHz.
:type vm_mhz_history: list(list(int))
:param host_mhz_history: A history if the CPU usage by the host in MHz.
:type host_mhz_history: list(int)
:param physical_cpu_mhz: The total frequency of the physical CPU in MHz.
:type physical_cpu_mhz: int,>0
:return: The history of the host's CPU utilization in percentages.
:rtype: list(float)
"""
max_len = max(len(x) for x in vm_mhz_history)
if len(host_mhz_history) > max_len: