Remove PyContracts dependency
Change-Id: I74e73a13e7efa53086bfdcfa997b115e99a13905
This commit is contained in:
parent
7e9c515ac7
commit
f8391cc9fd
48
NOTICE
48
NOTICE
@ -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/
|
@ -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+
|
||||
|
@ -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)
|
@ -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__'))
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user