diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-02-01 23:47:11 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-02-01 23:47:11 +0000 |
| commit | b295eef98a81430079440fcaaf03c07939306d9d (patch) | |
| tree | 07077f9960ea0ea696868ecbba04597ff5c53edb | |
| parent | 6ee7c132d768e44193a6aa0ee0cc66815e7dced0 (diff) | |
| parent | 9f9b651aec7835832845e1a76a6e17b65d214f17 (diff) | |
Merge "Remove Hyper-V support"
| -rw-r--r-- | nova/tests/hyperv_unittest.py | 65 | ||||
| -rw-r--r-- | nova/virt/connection.py | 3 | ||||
| -rw-r--r-- | nova/virt/hyperv.py | 525 |
3 files changed, 0 insertions, 593 deletions
diff --git a/nova/tests/hyperv_unittest.py b/nova/tests/hyperv_unittest.py deleted file mode 100644 index d346d0a70..000000000 --- a/nova/tests/hyperv_unittest.py +++ /dev/null @@ -1,65 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2010 Cloud.com, Inc -# -# 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. -""" -Tests For Hyper-V driver -""" - -import random - -from nova import context -from nova import db -from nova import test -from nova.virt import hyperv - - -class HyperVTestCase(test.TestCase): - """Test cases for the Hyper-V driver""" - def setUp(self): - super(HyperVTestCase, self).setUp() - self.user_id = 'fake' - self.project_id = 'fake' - self.context = context.RequestContext(self.user_id, self.project_id) - self.flags(connection_type='hyperv') - - def test_create_destroy(self): - """Create a VM and destroy it""" - instance = {'internal_id': random.randint(1, 1000000), - 'memory_mb': '1024', - 'mac_address': '02:12:34:46:56:67', - 'vcpus': 2, - 'project_id': 'fake', - 'instance_type': 'm1.small'} - instance_ref = db.instance_create(self.context, instance) - - conn = hyperv.get_connection(False) - conn._create_vm(instance_ref) # pylint: disable=W0212 - found = [n for n in conn.list_instances() - if n == instance_ref['name']] - self.assertTrue(len(found) == 1) - info = conn.get_info(instance_ref['name']) - #Unfortunately since the vm is not running at this point, - #we cannot obtain memory information from get_info - self.assertEquals(info['num_cpu'], instance_ref['vcpus']) - - conn.destroy(instance_ref) - found = [n for n in conn.list_instances() - if n == instance_ref['name']] - self.assertTrue(len(found) == 0) - - def tearDown(self): - super(HyperVTestCase, self).tearDown() - self.manager.delete_project(self.project) - self.manager.delete_user(self.user) diff --git a/nova/virt/connection.py b/nova/virt/connection.py index 17e5730ba..ad9998fa2 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -26,7 +26,6 @@ from nova import log as logging from nova import utils from nova.virt import driver from nova.virt import fake -from nova.virt import hyperv from nova.virt.libvirt import connection as libvirt_conn from nova.virt import vmwareapi_conn from nova.virt import xenapi_conn @@ -67,8 +66,6 @@ def get_connection(read_only=False): conn = libvirt_conn.get_connection(read_only) elif t == 'xenapi': conn = xenapi_conn.get_connection(read_only) - elif t == 'hyperv': - conn = hyperv.get_connection(read_only) elif t == 'vmwareapi': conn = vmwareapi_conn.get_connection(read_only) else: diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py deleted file mode 100644 index 3d3427d50..000000000 --- a/nova/virt/hyperv.py +++ /dev/null @@ -1,525 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2010 Cloud.com, Inc -# -# 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. - -""" -A connection to Hyper-V . -Uses Windows Management Instrumentation (WMI) calls to interact with Hyper-V -Hyper-V WMI usage: - http://msdn.microsoft.com/en-us/library/cc723875%28v=VS.85%29.aspx -The Hyper-V object model briefly: - The physical computer and its hosted virtual machines are each represented - by the Msvm_ComputerSystem class. - - Each virtual machine is associated with a - Msvm_VirtualSystemGlobalSettingData (vs_gs_data) instance and one or more - Msvm_VirtualSystemSettingData (vmsetting) instances. For each vmsetting - there is a series of Msvm_ResourceAllocationSettingData (rasd) objects. - The rasd objects describe the settings for each device in a VM. - Together, the vs_gs_data, vmsettings and rasds describe the configuration - of the virtual machine. - - Creating new resources such as disks and nics involves cloning a default - rasd object and appropriately modifying the clone and calling the - AddVirtualSystemResources WMI method - Changing resources such as memory uses the ModifyVirtualSystemResources - WMI method - -Using the Python WMI library: - Tutorial: - http://timgolden.me.uk/python/wmi/tutorial.html - Hyper-V WMI objects can be retrieved simply by using the class name - of the WMI object and optionally specifying a column to filter the - result set. More complex filters can be formed using WQL (sql-like) - queries. - The parameters and return tuples of WMI method calls can gleaned by - examining the doc string. For example: - >>> vs_man_svc.ModifyVirtualSystemResources.__doc__ - ModifyVirtualSystemResources (ComputerSystem, ResourceSettingData[]) - => (Job, ReturnValue)' - When passing setting data (ResourceSettingData) to the WMI method, - an XML representation of the data is passed in using GetText_(1). - Available methods on a service can be determined using method.keys(): - >>> vs_man_svc.methods.keys() - vmsettings and rasds for a vm can be retrieved using the 'associators' - method with the appropriate return class. - Long running WMI commands generally return a Job (an instance of - Msvm_ConcreteJob) whose state can be polled to determine when it finishes - -""" - -import os -import time - -from nova.compute import power_state -from nova import exception -from nova import flags -from nova import log as logging -from nova.virt import driver -from nova.virt import images - -wmi = None - - -FLAGS = flags.FLAGS - - -LOG = logging.getLogger('nova.virt.hyperv') - - -HYPERV_POWER_STATE = { - 3: power_state.SHUTDOWN, - 2: power_state.RUNNING, - 32768: power_state.PAUSED, -} - - -REQ_POWER_STATE = { - 'Enabled': 2, - 'Disabled': 3, - 'Reboot': 10, - 'Reset': 11, - 'Paused': 32768, - 'Suspended': 32769, -} - - -WMI_JOB_STATUS_STARTED = 4096 -WMI_JOB_STATE_RUNNING = 4 -WMI_JOB_STATE_COMPLETED = 7 - - -def get_connection(_): - global wmi - if wmi is None: - wmi = __import__('wmi') - return HyperVConnection() - - -class HyperVConnection(driver.ComputeDriver): - def __init__(self): - super(HyperVConnection, self).__init__() - self._conn = wmi.WMI(moniker='//./root/virtualization') - self._cim_conn = wmi.WMI(moniker='//./root/cimv2') - - def init_host(self, host): - #FIXME(chiradeep): implement this - LOG.debug(_('In init host')) - pass - - def list_instances(self): - """ Return the names of all the instances known to Hyper-V. """ - vms = [v.ElementName \ - for v in self._conn.Msvm_ComputerSystem(['ElementName'])] - return vms - - def list_instances_detail(self): - # TODO(justinsb): This is a terrible implementation (1+N) - instance_infos = [] - for instance_name in self.list_instances(): - info = self.get_info(instance_name) - - state = info['state'] - - instance_info = driver.InstanceInfo(instance_name, state) - instance_infos.append(instance_info) - - return instance_infos - - def spawn(self, context, instance, image_meta, - network_info=None, block_device_info=None): - """ Create a new VM and start it.""" - vm = self._lookup(instance.name) - if vm is not None: - raise exception.InstanceExists(name=instance.name) - - #Fetch the file, assume it is a VHD file. - base_vhd_filename = os.path.join(FLAGS.instances_path, - instance.name) - vhdfile = "%s.vhd" % (base_vhd_filename) - images.fetch(instance['image_ref'], vhdfile, - instance['user_id'], instance['project_id']) - - try: - self._create_vm(instance) - - self._create_disk(instance['name'], vhdfile) - - mac_address = None - if instance['mac_addresses']: - mac_address = instance['mac_addresses'][0]['address'] - - self._create_nic(instance['name'], mac_address) - - LOG.debug(_('Starting VM %s '), instance.name) - self._set_vm_state(instance['name'], 'Enabled') - LOG.info(_('Started VM %s '), instance.name) - except Exception as exn: - LOG.exception(_('spawn vm failed: %s'), exn) - self.destroy(instance) - - def _create_vm(self, instance): - """Create a VM but don't start it. """ - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - - vs_gs_data = self._conn.Msvm_VirtualSystemGlobalSettingData.new() - vs_gs_data.ElementName = instance['name'] - (job, ret_val) = vs_man_svc.DefineVirtualSystem( - [], None, vs_gs_data.GetText_(1))[1:] - if ret_val == WMI_JOB_STATUS_STARTED: - success = self._check_job_status(job) - else: - success = (ret_val == 0) - - if not success: - raise Exception(_('Failed to create VM %s'), instance.name) - - LOG.debug(_('Created VM %s...'), instance.name) - vm = self._conn.Msvm_ComputerSystem(ElementName=instance.name)[0] - - vmsettings = vm.associators( - wmi_result_class='Msvm_VirtualSystemSettingData') - vmsetting = [s for s in vmsettings - if s.SettingType == 3][0] # avoid snapshots - memsetting = vmsetting.associators( - wmi_result_class='Msvm_MemorySettingData')[0] - #No Dynamic Memory, so reservation, limit and quantity are identical. - mem = long(str(instance['memory_mb'])) - memsetting.VirtualQuantity = mem - memsetting.Reservation = mem - memsetting.Limit = mem - - (job, ret_val) = vs_man_svc.ModifyVirtualSystemResources( - vm.path_(), [memsetting.GetText_(1)]) - LOG.debug(_('Set memory for vm %s...'), instance.name) - procsetting = vmsetting.associators( - wmi_result_class='Msvm_ProcessorSettingData')[0] - vcpus = long(instance['vcpus']) - procsetting.VirtualQuantity = vcpus - procsetting.Reservation = vcpus - procsetting.Limit = 100000 # static assignment to 100% - - (job, ret_val) = vs_man_svc.ModifyVirtualSystemResources( - vm.path_(), [procsetting.GetText_(1)]) - LOG.debug(_('Set vcpus for vm %s...'), instance.name) - - def _create_disk(self, vm_name, vhdfile): - """Create a disk and attach it to the vm""" - LOG.debug(_('Creating disk for %(vm_name)s by attaching' - ' disk file %(vhdfile)s') % locals()) - #Find the IDE controller for the vm. - vms = self._conn.MSVM_ComputerSystem(ElementName=vm_name) - vm = vms[0] - vmsettings = vm.associators( - wmi_result_class='Msvm_VirtualSystemSettingData') - rasds = vmsettings[0].associators( - wmi_result_class='MSVM_ResourceAllocationSettingData') - ctrller = [r for r in rasds - if r.ResourceSubType == 'Microsoft Emulated IDE Controller'\ - and r.Address == "0"] - #Find the default disk drive object for the vm and clone it. - diskdflt = self._conn.query( - "SELECT * FROM Msvm_ResourceAllocationSettingData \ - WHERE ResourceSubType LIKE 'Microsoft Synthetic Disk Drive'\ - AND InstanceID LIKE '%Default%'")[0] - diskdrive = self._clone_wmi_obj( - 'Msvm_ResourceAllocationSettingData', diskdflt) - #Set the IDE ctrller as parent. - diskdrive.Parent = ctrller[0].path_() - diskdrive.Address = 0 - #Add the cloned disk drive object to the vm. - new_resources = self._add_virt_resource(diskdrive, vm) - if new_resources is None: - raise Exception(_('Failed to add diskdrive to VM %s'), - vm_name) - diskdrive_path = new_resources[0] - LOG.debug(_('New disk drive path is %s'), diskdrive_path) - #Find the default VHD disk object. - vhddefault = self._conn.query( - "SELECT * FROM Msvm_ResourceAllocationSettingData \ - WHERE ResourceSubType LIKE 'Microsoft Virtual Hard Disk' AND \ - InstanceID LIKE '%Default%' ")[0] - - #Clone the default and point it to the image file. - vhddisk = self._clone_wmi_obj( - 'Msvm_ResourceAllocationSettingData', vhddefault) - #Set the new drive as the parent. - vhddisk.Parent = diskdrive_path - vhddisk.Connection = [vhdfile] - - #Add the new vhd object as a virtual hard disk to the vm. - new_resources = self._add_virt_resource(vhddisk, vm) - if new_resources is None: - raise Exception(_('Failed to add vhd file to VM %s'), - vm_name) - LOG.info(_('Created disk for %s'), vm_name) - - def _create_nic(self, vm_name, mac): - """Create a (emulated) nic and attach it to the vm""" - LOG.debug(_('Creating nic for %s '), vm_name) - #Find the vswitch that is connected to the physical nic. - vms = self._conn.Msvm_ComputerSystem(ElementName=vm_name) - extswitch = self._find_external_network() - vm = vms[0] - switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0] - #Find the default nic and clone it to create a new nic for the vm. - #Use Msvm_SyntheticEthernetPortSettingData for Windows or Linux with - #Linux Integration Components installed. - emulatednics_data = self._conn.Msvm_EmulatedEthernetPortSettingData() - default_nic_data = [n for n in emulatednics_data - if n.InstanceID.rfind('Default') > 0] - new_nic_data = self._clone_wmi_obj( - 'Msvm_EmulatedEthernetPortSettingData', - default_nic_data[0]) - #Create a port on the vswitch. - (new_port, ret_val) = switch_svc.CreateSwitchPort(vm_name, vm_name, - "", extswitch.path_()) - if ret_val != 0: - LOG.error(_('Failed creating a port on the external vswitch')) - raise Exception(_('Failed creating port for %s'), - vm_name) - ext_path = extswitch.path_() - LOG.debug(_("Created switch port %(vm_name)s on switch %(ext_path)s") - % locals()) - #Connect the new nic to the new port. - new_nic_data.Connection = [new_port] - new_nic_data.ElementName = vm_name + ' nic' - new_nic_data.Address = ''.join(mac.split(':')) - new_nic_data.StaticMacAddress = 'TRUE' - #Add the new nic to the vm. - new_resources = self._add_virt_resource(new_nic_data, vm) - if new_resources is None: - raise Exception(_('Failed to add nic to VM %s'), - vm_name) - LOG.info(_("Created nic for %s "), vm_name) - - def _add_virt_resource(self, res_setting_data, target_vm): - """Add a new resource (disk/nic) to the VM""" - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job, new_resources, ret_val) = vs_man_svc.\ - AddVirtualSystemResources([res_setting_data.GetText_(1)], - target_vm.path_()) - success = True - if ret_val == WMI_JOB_STATUS_STARTED: - success = self._check_job_status(job) - else: - success = (ret_val == 0) - if success: - return new_resources - else: - return None - - #TODO: use the reactor to poll instead of sleep - def _check_job_status(self, jobpath): - """Poll WMI job state for completion""" - #Jobs have a path of the form: - #\\WIN-P5IG7367DAG\root\virtualization:Msvm_ConcreteJob.InstanceID= - #"8A496B9C-AF4D-4E98-BD3C-1128CD85320D" - inst_id = jobpath.split('=')[1].strip('"') - jobs = self._conn.Msvm_ConcreteJob(InstanceID=inst_id) - if len(jobs) == 0: - return False - job = jobs[0] - while job.JobState == WMI_JOB_STATE_RUNNING: - time.sleep(0.1) - job = self._conn.Msvm_ConcreteJob(InstanceID=inst_id)[0] - if job.JobState != WMI_JOB_STATE_COMPLETED: - LOG.debug(_("WMI job failed: %s"), job.ErrorSummaryDescription) - return False - desc = job.Description - elap = job.ElapsedTime - LOG.debug(_("WMI job succeeded: %(desc)s, Elapsed=%(elap)s ") - % locals()) - return True - - def _find_external_network(self): - """Find the vswitch that is connected to the physical nic. - Assumes only one physical nic on the host - """ - #If there are no physical nics connected to networks, return. - bound = self._conn.Msvm_ExternalEthernetPort(IsBound='TRUE') - if len(bound) == 0: - return None - return self._conn.Msvm_ExternalEthernetPort(IsBound='TRUE')[0]\ - .associators(wmi_result_class='Msvm_SwitchLANEndpoint')[0]\ - .associators(wmi_result_class='Msvm_SwitchPort')[0]\ - .associators(wmi_result_class='Msvm_VirtualSwitch')[0] - - def _clone_wmi_obj(self, wmi_class, wmi_obj): - """Clone a WMI object""" - cl = self._conn.__getattr__(wmi_class) # get the class - newinst = cl.new() - #Copy the properties from the original. - for prop in wmi_obj._properties: - newinst.Properties_.Item(prop).Value = \ - wmi_obj.Properties_.Item(prop).Value - return newinst - - def reboot(self, instance, network_info, reboot_type): - """Reboot the specified instance.""" - vm = self._lookup(instance.name) - if vm is None: - raise exception.InstanceNotFound(instance_id=instance.id) - self._set_vm_state(instance.name, 'Reboot') - - def destroy(self, instance, network_info, block_device_info=None): - """Destroy the VM. Also destroy the associated VHD disk files""" - LOG.debug(_("Got request to destroy vm %s"), instance.name) - vm = self._lookup(instance.name) - if vm is None: - return - vm = self._conn.Msvm_ComputerSystem(ElementName=instance.name)[0] - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - #Stop the VM first. - self._set_vm_state(instance.name, 'Disabled') - vmsettings = vm.associators( - wmi_result_class='Msvm_VirtualSystemSettingData') - rasds = vmsettings[0].associators( - wmi_result_class='MSVM_ResourceAllocationSettingData') - disks = [r for r in rasds \ - if r.ResourceSubType == 'Microsoft Virtual Hard Disk'] - diskfiles = [] - #Collect disk file information before destroying the VM. - for disk in disks: - diskfiles.extend([c for c in disk.Connection]) - #Nuke the VM. Does not destroy disks. - (job, ret_val) = vs_man_svc.DestroyVirtualSystem(vm.path_()) - if ret_val == WMI_JOB_STATUS_STARTED: - success = self._check_job_status(job) - elif ret_val == 0: - success = True - if not success: - raise Exception(_('Failed to destroy vm %s') % instance.name) - #Delete associated vhd disk files. - for disk in diskfiles: - vhdfile = self._cim_conn.CIM_DataFile(Name=disk) - for vf in vhdfile: - vf.Delete() - instance_name = instance.name - LOG.debug(_("Del: disk %(vhdfile)s vm %(instance_name)s") - % locals()) - - def get_info(self, instance_name): - """Get information about the VM""" - vm = self._lookup(instance_name) - if vm is None: - raise exception.InstanceNotFound(instance_id=instance_name) - vm = self._conn.Msvm_ComputerSystem(ElementName=instance_name)[0] - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - vmsettings = vm.associators( - wmi_result_class='Msvm_VirtualSystemSettingData') - settings_paths = [v.path_() for v in vmsettings] - #See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx - summary_info = vs_man_svc.GetSummaryInformation( - [4, 100, 103, 105], settings_paths)[1] - info = summary_info[0] - state = str(HYPERV_POWER_STATE[info.EnabledState]) - memusage = str(info.MemoryUsage) - numprocs = str(info.NumberOfProcessors) - uptime = str(info.UpTime) - - LOG.debug(_("Got Info for vm %(instance_name)s: state=%(state)s," - " mem=%(memusage)s, num_cpu=%(numprocs)s," - " cpu_time=%(uptime)s") % locals()) - - return {'state': HYPERV_POWER_STATE[info.EnabledState], - 'max_mem': info.MemoryUsage, - 'mem': info.MemoryUsage, - 'num_cpu': info.NumberOfProcessors, - 'cpu_time': info.UpTime} - - def _lookup(self, i): - vms = self._conn.Msvm_ComputerSystem(ElementName=i) - n = len(vms) - if n == 0: - return None - elif n > 1: - raise Exception(_('duplicate name found: %s') % i) - else: - return vms[0].ElementName - - def _set_vm_state(self, vm_name, req_state): - """Set the desired state of the VM""" - vms = self._conn.Msvm_ComputerSystem(ElementName=vm_name) - if len(vms) == 0: - return False - (job, ret_val) = vms[0].RequestStateChange(REQ_POWER_STATE[req_state]) - success = False - if ret_val == WMI_JOB_STATUS_STARTED: - success = self._check_job_status(job) - elif ret_val == 0: - success = True - elif ret_val == 32775: - #Invalid state for current operation. Typically means it is - #already in the state requested - success = True - if success: - LOG.info(_("Successfully changed vm state of %(vm_name)s" - " to %(req_state)s") % locals()) - else: - msg = _("Failed to change vm state of %(vm_name)s" - " to %(req_state)s") % locals() - LOG.error(msg) - raise Exception(msg) - - def attach_volume(self, connection_info, instance_name, mountpoint): - vm = self._lookup(instance_name) - if vm is None: - raise exception.InstanceNotFound(instance_id=instance_name) - - def detach_volume(self, connection_info, instance_name, mountpoint): - vm = self._lookup(instance_name) - if vm is None: - raise exception.InstanceNotFound(instance_id=instance_name) - - def poll_rebooting_instances(self, timeout): - """See xenapi_conn.py implementation.""" - pass - - def poll_rescued_instances(self, timeout): - """See xenapi_conn.py implementation.""" - pass - - def poll_unconfirmed_resizes(self, resize_confirm_window): - """See xenapi_conn.py implementation.""" - pass - - def update_available_resource(self, ctxt, host): - """This method is supported only by libvirt.""" - return - - def update_host_status(self): - """See xenapi_conn.py implementation.""" - pass - - def get_host_stats(self, refresh=False): - """See xenapi_conn.py implementation.""" - pass - - def host_power_action(self, host, action): - """Reboots, shuts down or powers up the host.""" - pass - - def set_host_enabled(self, host, enabled): - """Sets the specified host's ability to accept new instances.""" - pass - - def plug_vifs(self, instance, network_info): - """Plug VIFs into networks.""" - pass - - def unplug_vifs(self, instance, network_info): - """Unplug VIFs from networks.""" - pass |
