summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2012-07-25 13:32:28 +0100
committerDaniel P. Berrange <berrange@redhat.com>2012-07-25 17:19:13 +0100
commiteb074328041b5f8b4f5a109794c54a9bd4e245ed (patch)
tree0d1da907a20f2bcde7809c855cc2c60ab1038275
parentb8aedb281f8e6cc8b1583640c31f5d52ce5e4eac (diff)
downloadnova-eb074328041b5f8b4f5a109794c54a9bd4e245ed.tar.gz
nova-eb074328041b5f8b4f5a109794c54a9bd4e245ed.tar.xz
nova-eb074328041b5f8b4f5a109794c54a9bd4e245ed.zip
Define cross-driver standardized vm_mode values
Currently the XenAPI driver allows for a 'vm_mode' parameter to be set against an instance to determine whether it is launched a paravirt or fullvirt domain. This allows the values 'pv', 'hv' and 'hvm'. The libvirt driver also needs to be extended to allow a 'vm_mode' parameter, and to facilitate deployment of heterogeneous Nova compute farms, it is desirable to have standardization of the VM mode values across all drivers. To address this, the nova.compute.vm_mode module is introduced which defines a set of constants. The constants provide four possible vm modes: - vm_mode.XEN = 'xen' - for Xen 3.0 paravirt ABI - vm_mode.HVM = 'hvm' - for native ABI - vm_mode.UML = 'uml' - for User Mode Linux paravirt ABI - vm_mode.EXE = 'exe' - for container virt executable ABI The existing 'pv' value from XenAPI is deprecated, because it is ambiguous - both Xen and UML are paravirt, and other paravirt hypervisor ABIs also exist The existing 'hv' value is also deprecated since it duplicates the other existing 'hvm' value. The 'vm_mode.get_from_instance' method will extract the vm_mode value for an instance. It normalizes the value to all lower case, translates 'hv' and 'pv' into the new values for back compat, and validates that the value matches one of the defined constants The XenAPI and libvirt drivers are then updated to use the nova.compute.vm_mode constants instead of bare strings. The test_xenapi.py test case is updated to set 'vm_mode' to exercise the new codepaths. A new test_vmmode.py case is also written to fully exercise the logic NB, previously the libvirt driver would set 'guest.os_type' to 'linux' to request Xen paravirt. This is a legacy value, with libvirt preferring the string 'xen'. So although the new code sets a different value for Xen paravirt os_type, the functional result is unchanged. DocImpact blueprint hypervisor-code-consolidation Change-Id: I23efc5dc1528b0d8472d752a8a30f55c85310b21 Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
-rw-r--r--nova/compute/vm_mode.py58
-rw-r--r--nova/tests/test_libvirt.py21
-rw-r--r--nova/tests/test_vmmode.py54
-rw-r--r--nova/tests/test_xenapi.py1
-rw-r--r--nova/virt/libvirt/driver.py9
-rw-r--r--nova/virt/xenapi/vmops.py14
6 files changed, 138 insertions, 19 deletions
diff --git a/nova/compute/vm_mode.py b/nova/compute/vm_mode.py
new file mode 100644
index 000000000..a380511a9
--- /dev/null
+++ b/nova/compute/vm_mode.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Red Hat, Inc.
+# 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.
+
+"""Possible vm modes for instances.
+
+Compute instance vm modes represent the host/guest ABI used for the
+virtual machine / container. Individual hypervisors may support
+multiple different vm modes per host. Available vm modes for a hypervisor
+driver may also vary according to the architecture it is running on.
+
+The 'vm_mode' parameter can be set against an instance to
+choose what sort of VM to boot.
+
+"""
+
+from nova import exception
+
+HVM = "hvm" # Fully virtualizated
+XEN = "xen" # Xen 3.0 paravirtualized
+UML = "uml" # User Mode Linux paravirtualized
+EXE = "exe" # Executables in containers
+
+ALL = [HVM, XEN, UML, EXE]
+
+
+def get_from_instance(instance):
+ mode = instance.vm_mode
+
+ if mode is None:
+ return None
+
+ mode = mode.lower()
+
+ # For compatibility with pre-Folsom deployments
+ if mode == "pv":
+ mode = XEN
+
+ if mode == "hv":
+ mode = HVM
+
+ if not mode in ALL:
+ raise exception.Invalid("Unknown vm mode '%s'" % mode)
+
+ return mode
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index f93c724bc..9fb739a56 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -32,6 +32,7 @@ from nova.compute import instance_types
from nova.compute import power_state
from nova.compute import rpcapi as compute_rpcapi
from nova.compute import utils as compute_utils
+from nova.compute import vm_mode
from nova.compute import vm_states
from nova import context
from nova import db
@@ -508,7 +509,7 @@ class LibvirtConnTestCase(test.TestCase):
self.assertEquals(cfg.acpi, True)
self.assertEquals(cfg.memory, 1024 * 1024 * 2)
self.assertEquals(cfg.vcpus, 1)
- self.assertEquals(cfg.os_type, "hvm")
+ self.assertEquals(cfg.os_type, vm_mode.HVM)
self.assertEquals(cfg.os_boot_dev, "hd")
self.assertEquals(cfg.os_root, None)
self.assertEquals(len(cfg.devices), 7)
@@ -552,7 +553,7 @@ class LibvirtConnTestCase(test.TestCase):
self.assertEquals(cfg.acpi, True)
self.assertEquals(cfg.memory, 1024 * 1024 * 2)
self.assertEquals(cfg.vcpus, 1)
- self.assertEquals(cfg.os_type, "hvm")
+ self.assertEquals(cfg.os_type, vm_mode.HVM)
self.assertEquals(cfg.os_boot_dev, "hd")
self.assertEquals(cfg.os_root, None)
self.assertEquals(len(cfg.devices), 8)
@@ -1363,18 +1364,22 @@ class LibvirtConnTestCase(test.TestCase):
type_uri_map = {'qemu': ('qemu:///system',
[(lambda t: t.find('.').get('type'), 'qemu'),
- (lambda t: t.find('./os/type').text, 'hvm'),
+ (lambda t: t.find('./os/type').text,
+ vm_mode.HVM),
(lambda t: t.find('./devices/emulator'), None)]),
'kvm': ('qemu:///system',
[(lambda t: t.find('.').get('type'), 'kvm'),
- (lambda t: t.find('./os/type').text, 'hvm'),
+ (lambda t: t.find('./os/type').text,
+ vm_mode.HVM),
(lambda t: t.find('./devices/emulator'), None)]),
'uml': ('uml:///system',
[(lambda t: t.find('.').get('type'), 'uml'),
- (lambda t: t.find('./os/type').text, 'uml')]),
+ (lambda t: t.find('./os/type').text,
+ vm_mode.UML)]),
'xen': ('xen:///',
[(lambda t: t.find('.').get('type'), 'xen'),
- (lambda t: t.find('./os/type').text, 'linux')]),
+ (lambda t: t.find('./os/type').text,
+ vm_mode.XEN)]),
}
for hypervisor_type in ['qemu', 'kvm', 'xen']:
@@ -2149,12 +2154,12 @@ class LibvirtConnTestCase(test.TestCase):
caps.host.cpu = cpu
guest = config.LibvirtConfigGuest()
- guest.ostype = "hvm"
+ guest.ostype = vm_mode.HVM
guest.arch = "x86_64"
caps.guests.append(guest)
guest = config.LibvirtConfigGuest()
- guest.ostype = "hvm"
+ guest.ostype = vm_mode.HVM
guest.arch = "i686"
caps.guests.append(guest)
diff --git a/nova/tests/test_vmmode.py b/nova/tests/test_vmmode.py
new file mode 100644
index 000000000..cd639478c
--- /dev/null
+++ b/nova/tests/test_vmmode.py
@@ -0,0 +1,54 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright (C) 2012 Red Hat, 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.
+
+from nova import exception
+from nova import test
+
+from nova.compute import vm_mode
+
+
+class ComputeVMModeTest(test.TestCase):
+
+ class testinstance(object):
+ def __init__(self, mode):
+ self.vm_mode = mode
+
+ def test_case(self):
+ inst = ComputeVMModeTest.testinstance("HVM")
+ mode = vm_mode.get_from_instance(inst)
+ self.assertEqual(mode, "hvm")
+
+ def test_legacy_pv(self):
+ inst = ComputeVMModeTest.testinstance("pv")
+ mode = vm_mode.get_from_instance(inst)
+ self.assertEqual(mode, "xen")
+
+ def test_legacy_hv(self):
+ inst = ComputeVMModeTest.testinstance("hv")
+ mode = vm_mode.get_from_instance(inst)
+ self.assertEqual(mode, "hvm")
+
+ def test_bogus(self):
+ inst = ComputeVMModeTest.testinstance("wibble")
+
+ self.assertRaises(exception.Invalid,
+ vm_mode.get_from_instance,
+ inst)
+
+ def test_good(self):
+ inst = ComputeVMModeTest.testinstance("hvm")
+ mode = vm_mode.get_from_instance(inst)
+ self.assertEqual(mode, "hvm")
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 9486f4144..b8315a02e 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -849,6 +849,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
'root_gb': 20,
'instance_type_id': '3', # m1.large
'os_type': 'linux',
+ 'vm_mode': 'hvm',
'architecture': 'x86-64'}
instance = db.instance_create(self.context, instance_values)
network_info = fake_network.fake_get_instance_nw_info(self.stubs,
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index e9c7754b1..d84388be0 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -57,6 +57,7 @@ from xml.dom import minidom
from nova import block_device
from nova.compute import instance_types
from nova.compute import power_state
+from nova.compute import vm_mode
from nova import context as nova_context
from nova import db
from nova import exception
@@ -1712,19 +1713,19 @@ class LibvirtDriver(driver.ComputeDriver):
{'root_device_name': '/dev/' + self.default_root_device})
if FLAGS.libvirt_type == "lxc":
- guest.os_type = "exe"
+ guest.os_type = vm_mode.EXE
guest.os_init_path = "/sbin/init"
guest.os_cmdline = "console=ttyS0"
elif FLAGS.libvirt_type == "uml":
- guest.os_type = "uml"
+ guest.os_type = vm_mode.UML
guest.os_kernel = "/usr/bin/linux"
guest.os_root = root_device_name or "/dev/ubda"
else:
if FLAGS.libvirt_type == "xen":
- guest.os_type = "linux"
+ guest.os_type = vm_mode.XEN
guest.os_root = root_device_name or "/dev/xvda"
else:
- guest.os_type = "hvm"
+ guest.os_type = vm_mode.HVM
if rescue:
if rescue.get('kernel_id'):
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 785cd614c..4a51010e6 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -31,6 +31,7 @@ import netaddr
from nova.compute import api as compute
from nova.compute import power_state
+from nova.compute import vm_mode
from nova import context as nova_context
from nova import db
from nova import exception
@@ -381,21 +382,20 @@ class VMOps(object):
disk_image_type = vm_utils.determine_disk_image_type(image_meta)
- vm_mode = instance.vm_mode and instance.vm_mode.lower()
- if vm_mode == 'pv':
+ mode = vm_mode.get_from_instance(instance)
+ if mode == vm_mode.XEN:
use_pv_kernel = True
- elif vm_mode in ('hv', 'hvm'):
+ elif mode == vm_mode.HVM:
use_pv_kernel = False
- vm_mode = 'hvm' # Normalize
else:
use_pv_kernel = vm_utils.determine_is_pv(self._session,
vdis['root']['ref'], disk_image_type, instance.os_type)
- vm_mode = use_pv_kernel and 'pv' or 'hvm'
+ mode = use_pv_kernel and vm_mode.XEN or vm_mode.HVM
- if instance.vm_mode != vm_mode:
+ if instance.vm_mode != mode:
# Update database with normalized (or determined) value
db.instance_update(nova_context.get_admin_context(),
- instance['uuid'], {'vm_mode': vm_mode})
+ instance['uuid'], {'vm_mode': mode})
vm_ref = vm_utils.create_vm(
self._session, instance, kernel_file, ramdisk_file,