summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlessandro Pilotti <ap@pilotti.it>2012-10-31 19:38:55 +0200
committerAlessandro Pilotti <ap@pilotti.it>2012-10-31 19:38:55 +0200
commit80fb666fa276b78e87590bb06d3b932eeef48e0e (patch)
tree7ee044f0605c32d005bb9598a353bfb9d7def115
parent3157a42744a58083278146279de52416f2d84a4a (diff)
downloadnova-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.gzbin0 -> 290 bytes
-rw-r--r--nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gzbin0 -> 888 bytes
-rw-r--r--nova/tests/test_hypervapi.py10
-rw-r--r--nova/virt/hyperv/driver.py10
-rw-r--r--nova/virt/hyperv/hostops.py169
-rw-r--r--nova/virt/hyperv/vmops.py107
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
new file mode 100644
index 000000000..805931bbb
--- /dev/null
+++ b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_shutil.p.gz
Binary files differ
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
new file mode 100644
index 000000000..e9852d038
--- /dev/null
+++ b/nova/tests/hyperv/stubs/test_hypervapi.HyperVAPITestCase.test_get_host_stats_wmi.p.gz
Binary files differ
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.