diff options
author | Alessandro Pilotti <ap@pilotti.it> | 2012-10-31 19:38:55 +0200 |
---|---|---|
committer | Alessandro Pilotti <ap@pilotti.it> | 2012-10-31 19:38:55 +0200 |
commit | 80fb666fa276b78e87590bb06d3b932eeef48e0e (patch) | |
tree | 7ee044f0605c32d005bb9598a353bfb9d7def115 | |
parent | 3157a42744a58083278146279de52416f2d84a4a (diff) | |
download | nova-80fb666fa276b78e87590bb06d3b932eeef48e0e.tar.gz nova-80fb666fa276b78e87590bb06d3b932eeef48e0e.tar.xz nova-80fb666fa276b78e87590bb06d3b932eeef48e0e.zip |
Fixes hypervisor based image filtering on Hyper-V
Fixes Bug #1073547
Nova scheduler's ImagePropertiesFilter based filtering requires the
"supported_instances" stat returned by the driver's get_host_stats method.
This fix implements the get_host_stats method, providing also some
refactoring in the process by adding a HostOps class.
Change-Id: Ia6e73eb3e8ff0be028854fe4fd6d8e305fa1d504
-rw-r--r-- | nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_shutil.p.gz | bin | 0 -> 290 bytes | |||
-rw-r--r-- | nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gz | bin | 0 -> 888 bytes | |||
-rw-r--r-- | nova/tests/test_hypervapi.py | 10 | ||||
-rw-r--r-- | nova/virt/hyperv/driver.py | 10 | ||||
-rw-r--r-- | nova/virt/hyperv/hostops.py | 169 | ||||
-rw-r--r-- | nova/virt/hyperv/vmops.py | 107 |
6 files changed, 184 insertions, 112 deletions
diff --git a/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_shutil.p.gz b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_shutil.p.gz Binary files differnew file mode 100644 index 000000000..805931bbb --- /dev/null +++ b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_shutil.p.gz diff --git a/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gz b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gz Binary files differnew file mode 100644 index 000000000..e9852d038 --- /dev/null +++ b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gz diff --git a/nova/tests/test_hypervapi.py b/nova/tests/test_hypervapi.py index 0ae65feaf..e3f9fde4c 100644 --- a/nova/tests/test_hypervapi.py +++ b/nova/tests/test_hypervapi.py @@ -103,6 +103,7 @@ class HyperVAPITestCase(basetestcase.BaseTestCase): # Modules in which the mocks are going to be injected from nova.virt.hyperv import baseops + from nova.virt.hyperv import hostops from nova.virt.hyperv import livemigrationops from nova.virt.hyperv import snapshotops from nova.virt.hyperv import vmops @@ -112,6 +113,7 @@ class HyperVAPITestCase(basetestcase.BaseTestCase): modules_to_test = [ driver_hyperv, baseops, + hostops, vmops, vmutils, volumeops, @@ -157,6 +159,14 @@ class HyperVAPITestCase(basetestcase.BaseTestCase): self.assertEquals(dic['hypervisor_hostname'], platform.node()) + def test_get_host_stats(self): + dic = self._conn.get_host_stats(True) + + self.assertEquals(dic['disk_total'], + dic['disk_used'] + dic['disk_available']) + self.assertEquals(dic['host_memory_total'], + dic['host_memory_overhead'] + dic['host_memory_free']) + def test_list_instances(self): num_vms = self._hypervutils.get_vm_count() instances = self._conn.list_instances() diff --git a/nova/virt/hyperv/driver.py b/nova/virt/hyperv/driver.py index 04514ebab..3f43ca0a6 100644 --- a/nova/virt/hyperv/driver.py +++ b/nova/virt/hyperv/driver.py @@ -63,6 +63,7 @@ Using the Python WMI library: from nova.openstack.common import log as logging from nova.virt import driver +from nova.virt.hyperv import hostops from nova.virt.hyperv import livemigrationops from nova.virt.hyperv import snapshotops from nova.virt.hyperv import vmops @@ -75,6 +76,7 @@ class HyperVDriver(driver.ComputeDriver): def __init__(self): super(HyperVDriver, self).__init__() + self._hostops = hostops.HostOps() self._volumeops = volumeops.VolumeOps() self._vmops = vmops.VMOps(self._volumeops) self._snapshotops = snapshotops.SnapshotOps() @@ -121,15 +123,13 @@ class HyperVDriver(driver.ComputeDriver): pass def get_available_resource(self): - return self._vmops.get_available_resource() + return self._hostops.get_available_resource() def get_host_stats(self, refresh=False): - """See xenapi_conn.py implementation.""" - return {} + return self._hostops.get_host_stats(refresh) def host_power_action(self, host, action): - """Reboots, shuts down or powers up the host.""" - pass + return self._hostops.host_power_action(host, action) def set_host_enabled(self, host, enabled): """Sets the specified host's ability to accept new instances.""" diff --git a/nova/virt/hyperv/hostops.py b/nova/virt/hyperv/hostops.py new file mode 100644 index 000000000..b2a025e0c --- /dev/null +++ b/nova/virt/hyperv/hostops.py @@ -0,0 +1,169 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Cloudbase Solutions Srl +# All Rights Reserved. +# +# 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. + +""" +Management class for host operations. +""" +import multiprocessing +import platform + +from nova.openstack.common import log as logging +from nova.virt.hyperv import baseops + +LOG = logging.getLogger(__name__) + + +class HostOps(baseops.BaseOps): + def __init__(self): + super(HostOps, self).__init__() + self._stats = None + + def _get_vcpu_total(self): + """Get vcpu number of physical computer. + :returns: the number of cpu core. + """ + # On certain platforms, this will raise a NotImplementedError. + try: + return multiprocessing.cpu_count() + except NotImplementedError: + LOG.warn(_("Cannot get the number of cpu, because this " + "function is not implemented for this platform. " + "This error can be safely ignored for now.")) + return 0 + + def _get_memory_mb_total(self): + """Get the total memory size(MB) of physical computer. + :returns: the total amount of memory(MB). + """ + total_kb = self._conn_cimv2.query( + "SELECT TotalVisibleMemorySize FROM win32_operatingsystem")[0]\ + .TotalVisibleMemorySize + total_mb = long(total_kb) / 1024 + return total_mb + + def _get_local_gb_total(self): + """Get the total hdd size(GB) of physical computer. + :returns: + The total amount of HDD(GB). + Note that this value shows a partition where + NOVA-INST-DIR/instances mounts. + """ + #TODO(jordanrinke): This binds to C only right now, + #need to bind to instance dir + total_kb = self._conn_cimv2.query( + "SELECT Size FROM win32_logicaldisk WHERE DriveType=3")[0].Size + total_gb = long(total_kb) / (1024 ** 3) + return total_gb + + def _get_vcpu_used(self): + """ Get vcpu usage number of physical computer. + :returns: The total number of vcpu that currently used. + """ + #TODO(jordanrinke) figure out a way to count assigned VCPUs + total_vcpu = 0 + return total_vcpu + + def _get_memory_mb_used(self): + """Get the free memory size(MB) of physical computer. + :returns: the total usage of memory(MB). + """ + total_kb = self._conn_cimv2.query( + "SELECT FreePhysicalMemory FROM win32_operatingsystem")[0]\ + .FreePhysicalMemory + total_mb = long(total_kb) / 1024 + + return total_mb + + def _get_local_gb_used(self): + """Get the free hdd size(GB) of physical computer. + :returns: + The total usage of HDD(GB). + Note that this value shows a partition where + NOVA-INST-DIR/instances mounts. + """ + #TODO(jordanrinke): This binds to C only right now, + #need to bind to instance dir + total_kb = self._conn_cimv2.query( + "SELECT FreeSpace FROM win32_logicaldisk WHERE DriveType=3")[0]\ + .FreeSpace + total_gb = long(total_kb) / (1024 ** 3) + return total_gb + + def _get_hypervisor_version(self): + """Get hypervisor version. + :returns: hypervisor version (ex. 12003) + """ + version = self._conn_cimv2.Win32_OperatingSystem()[0]\ + .Version.replace('.', '') + LOG.info(_('Windows version: %s ') % version) + return version + + def get_available_resource(self): + """Retrieve resource info. + + This method is called when nova-compute launches, and + as part of a periodic task. + + :returns: dictionary describing resources + + """ + LOG.info(_('get_available_resource called')) + + # TODO(alexpilotti) implemented cpu_info + dic = {'vcpus': self._get_vcpu_total(), + 'memory_mb': self._get_memory_mb_total(), + 'local_gb': self._get_local_gb_total(), + 'vcpus_used': self._get_vcpu_used(), + 'memory_mb_used': self._get_memory_mb_used(), + 'local_gb_used': self._get_local_gb_used(), + 'hypervisor_type': "hyperv", + 'hypervisor_version': self._get_hypervisor_version(), + 'hypervisor_hostname': platform.node(), + 'cpu_info': 'unknown'} + + return dic + + def _update_stats(self): + LOG.debug(_("Updating host stats")) + + data = {} + data["disk_total"] = self._get_local_gb_total() + data["disk_used"] = self._get_local_gb_used() + data["disk_available"] = data["disk_total"] - data["disk_used"] + data["host_memory_total"] = self._get_memory_mb_total() + data["host_memory_overhead"] = self._get_memory_mb_used() + data["host_memory_free"] = \ + data["host_memory_total"] - data["host_memory_overhead"] + data["host_memory_free_computed"] = data["host_memory_free"] + data["supported_instances"] = \ + [('i686', 'hyperv', 'hvm'), + ('x86_64', 'hyperv', 'hvm')] + + self._stats = data + + def get_host_stats(self, refresh=False): + """Return the current state of the host. If 'refresh' is + True, run the update first.""" + LOG.info(_("get_host_stats called")) + + if refresh or not self._stats: + self._update_stats() + return self._stats + + def host_power_action(self, host, action): + """Reboots, shuts down or powers up the host.""" + pass diff --git a/nova/virt/hyperv/vmops.py b/nova/virt/hyperv/vmops.py index 92d9a408a..e248fd37d 100644 --- a/nova/virt/hyperv/vmops.py +++ b/nova/virt/hyperv/vmops.py @@ -18,9 +18,7 @@ """ Management class for basic VM operations. """ -import multiprocessing import os -import platform import uuid from nova import db @@ -475,111 +473,6 @@ class VMOps(baseops.BaseOps): LOG.error(msg) raise vmutils.HyperVException(msg) - def _get_vcpu_total(self): - """Get vcpu number of physical computer. - :returns: the number of cpu core. - """ - # On certain platforms, this will raise a NotImplementedError. - try: - return multiprocessing.cpu_count() - except NotImplementedError: - LOG.warn(_("Cannot get the number of cpu, because this " - "function is not implemented for this platform. " - "This error can be safely ignored for now.")) - return 0 - - def _get_memory_mb_total(self): - """Get the total memory size(MB) of physical computer. - :returns: the total amount of memory(MB). - """ - total_kb = self._conn_cimv2.query( - "SELECT TotalVisibleMemorySize FROM win32_operatingsystem")[0]\ - .TotalVisibleMemorySize - total_mb = long(total_kb) / 1024 - return total_mb - - def _get_local_gb_total(self): - """Get the total hdd size(GB) of physical computer. - :returns: - The total amount of HDD(GB). - Note that this value shows a partition where - NOVA-INST-DIR/instances mounts. - """ - #TODO(jordanrinke): This binds to C only right now, - #need to bind to instance dir - total_kb = self._conn_cimv2.query( - "SELECT Size FROM win32_logicaldisk WHERE DriveType=3")[0].Size - total_gb = long(total_kb) / (1024 ** 3) - return total_gb - - def _get_vcpu_used(self): - """ Get vcpu usage number of physical computer. - :returns: The total number of vcpu that currently used. - """ - #TODO(jordanrinke) figure out a way to count assigned VCPUs - total_vcpu = 0 - return total_vcpu - - def _get_memory_mb_used(self): - """Get the free memory size(MB) of physical computer. - :returns: the total usage of memory(MB). - """ - total_kb = self._conn_cimv2.query( - "SELECT FreePhysicalMemory FROM win32_operatingsystem")[0]\ - .FreePhysicalMemory - total_mb = long(total_kb) / 1024 - - return total_mb - - def _get_local_gb_used(self): - """Get the free hdd size(GB) of physical computer. - :returns: - The total usage of HDD(GB). - Note that this value shows a partition where - NOVA-INST-DIR/instances mounts. - """ - #TODO(jordanrinke): This binds to C only right now, - #need to bind to instance dir - total_kb = self._conn_cimv2.query( - "SELECT FreeSpace FROM win32_logicaldisk WHERE DriveType=3")[0]\ - .FreeSpace - total_gb = long(total_kb) / (1024 ** 3) - return total_gb - - def _get_hypervisor_version(self): - """Get hypervisor version. - :returns: hypervisor version (ex. 12003) - """ - version = self._conn_cimv2.Win32_OperatingSystem()[0]\ - .Version.replace('.', '') - LOG.info(_('Windows version: %s ') % version) - return version - - def get_available_resource(self): - """Retrieve resource info. - - This method is called when nova-compute launches, and - as part of a periodic task. - - :returns: dictionary describing resources - - """ - LOG.info(_('get_available_resource called')) - - # TODO(alexpilotti) implemented cpu_info - dic = {'vcpus': self._get_vcpu_total(), - 'memory_mb': self._get_memory_mb_total(), - 'local_gb': self._get_local_gb_total(), - 'vcpus_used': self._get_vcpu_used(), - 'memory_mb_used': self._get_memory_mb_used(), - 'local_gb_used': self._get_local_gb_used(), - 'hypervisor_type': "hyperv", - 'hypervisor_version': self._get_hypervisor_version(), - 'hypervisor_hostname': platform.node(), - 'cpu_info': 'unknown'} - - return dic - def _cache_image(self, fn, target, fname, cow=False, Size=None, *args, **kwargs): """Wrapper for a method that creates an image that caches the image. |