libvirt: Enable custom video RAM setting

hw_video_ram can be provided via the image properties in Glance.
The value should be provided in MB.
hw_video_ram will be honoured, during an instance creation,
only if a coresponding hw_video:ram_max_mb value has been set in the flavor's
extra_specs and it's higher than the requested amount in hw_video_ram.

    glance image-update \
       --property hw_video_model=qxl \
       --property hw_video_ram=64 \
       [image]

DocImpact
Partially implements blueprint libvirt-video-driver-selection

Change-Id: I125cdc2afa27986ead9a81d925125a6a3ecce145
This commit is contained in:
Vladik Romanovsky 2014-01-22 23:06:42 -05:00
parent 17aa741aee
commit f5a102cc90
4 changed files with 106 additions and 3 deletions

View File

@ -127,6 +127,7 @@ CONF.import_opt('default_ephemeral_format', 'nova.virt.driver')
MAX_USERDATA_SIZE = 65535
QUOTAS = quota.QUOTAS
RO_SECURITY_GROUPS = ['default']
VIDEO_RAM = 'hw_video:ram_max_mb'
def check_instance_state(vm_state=None, task_state=(None,),
@ -336,7 +337,8 @@ class API(base.Base):
# Determine requested cores and ram
req_cores = max_count * instance_type['vcpus']
req_ram = max_count * instance_type['memory_mb']
vram_mb = int(instance_type.get('extra_specs', {}).get(VIDEO_RAM, 0))
req_ram = max_count * (instance_type['memory_mb'] + vram_mb)
# Check the quota
try:
@ -355,7 +357,8 @@ class API(base.Base):
headroom['cores'] // instance_type['vcpus'])
if instance_type['memory_mb']:
allowed = min(allowed,
headroom['ram'] // instance_type['memory_mb'])
headroom['ram'] // (instance_type['memory_mb'] +
vram_mb))
# Convert to the appropriate exception message
if allowed <= 0:
@ -1567,7 +1570,9 @@ class API(base.Base):
pass
else:
instance_vcpus = old_inst_type['vcpus']
instance_memory_mb = old_inst_type['memory_mb']
vram_mb = int(old_inst_type['extra_specs']
.get(VIDEO_RAM, 0))
instance_memory_mb = (old_inst_type['memory_mb'] + vram_mb)
LOG.debug(_("going to delete a resizing instance"))
reservations = QUOTAS.reserve(context,

View File

@ -1511,3 +1511,8 @@ class InvalidVideoMode(Invalid):
class RngDeviceNotExist(Invalid):
msg_fmt = _("The provided RNG device path: (%(path)s) is not "
"present on the host.")
class RequestedVRamTooHigh(NovaException):
msg_fmt = _("The requested amount of video memory %(req_vram)d is higher"
"than the maximum allowed by flavor %(max_vram)d.")

View File

@ -1323,6 +1323,90 @@ class LibvirtConnTestCase(test.TestCase):
self.assertEqual(cfg.devices[7].type, "unix")
self.assertEqual(cfg.devices[7].target_name, "org.qemu.guest_agent.0")
def test_get_guest_config_with_video_driver_vram(self):
self.flags(vnc_enabled=False)
self.flags(virt_type='kvm', group='libvirt')
self.flags(enabled=True,
agent_enabled=True,
group='spice')
instance_type = flavor_obj.Flavor.get_by_id(self.context, 5)
instance_type.extra_specs = {'hw_video:ram_max_mb': "100"}
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = db.instance_create(self.context, self.test_instance)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref)
image_meta = {"properties": {"hw_video_model": "qxl",
"hw_video_ram": "64"}}
with mock.patch.object(flavor_obj.Flavor, 'get_by_id',
return_value=instance_type):
cfg = conn.get_guest_config(instance_ref, [],
image_meta, disk_info)
self.assertEqual(len(cfg.devices), 7)
self.assertIsInstance(cfg.devices[0],
vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(cfg.devices[1],
vconfig.LibvirtConfigGuestDisk)
self.assertIsInstance(cfg.devices[2],
vconfig.LibvirtConfigGuestSerial)
self.assertIsInstance(cfg.devices[3],
vconfig.LibvirtConfigGuestSerial)
self.assertIsInstance(cfg.devices[4],
vconfig.LibvirtConfigGuestChannel)
self.assertIsInstance(cfg.devices[5],
vconfig.LibvirtConfigGuestGraphics)
self.assertIsInstance(cfg.devices[6],
vconfig.LibvirtConfigGuestVideo)
self.assertEqual(cfg.devices[5].type, "spice")
self.assertEqual(cfg.devices[6].type, "qxl")
self.assertEqual(cfg.devices[6].vram, 64)
def test_video_driver_flavor_limit_not_set(self):
self.flags(virt_type='kvm', group='libvirt')
self.flags(enabled=True,
agent_enabled=True,
group='spice')
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = db.instance_create(self.context, self.test_instance)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref)
image_meta = {"properties": {"hw_video_model": "qxl",
"hw_video_ram": "64"}}
self.assertRaises(exception.RequestedVRamTooHigh,
conn.get_guest_config,
instance_ref,
[],
image_meta,
disk_info)
def test_video_driver_ram_above_flavor_limit(self):
self.flags(virt_type='kvm', group='libvirt')
self.flags(enabled=True,
agent_enabled=True,
group='spice')
instance_type = flavor_obj.Flavor.get_by_id(self.context, 5)
instance_type.extra_specs = {'hw_video:ram_max_mb': "50"}
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = db.instance_create(self.context, self.test_instance)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref)
image_meta = {"properties": {"hw_video_model": "qxl",
"hw_video_ram": "64"}}
with mock.patch.object(flavor_obj.Flavor, 'get_by_id',
return_value=instance_type):
self.assertRaises(exception.RequestedVRamTooHigh,
conn.get_guest_config,
instance_ref,
[],
image_meta,
disk_info)
def test_get_guest_config_without_qga_through_image_meta(self):
self.flags(virt_type='kvm', group='libvirt')

View File

@ -3277,6 +3277,15 @@ class LibvirtDriver(driver.ComputeDriver):
if (video.type not in VALID_VIDEO_DEVICES):
raise exception.InvalidVideoMode(model=video.type)
# Set video memory, only if the flavor's limit is set
video_ram = int(img_meta_prop.get('hw_video_ram', 0))
max_vram = int(flavor.extra_specs
.get('hw_video:ram_max_mb', 0))
if video_ram > max_vram:
raise exception.RequestedVRamTooHigh(req_vram=video_ram,
max_vram=max_vram)
if max_vram and video_ram:
video.vram = video_ram
guest.add_device(video)
# Qemu guest agent only support 'qemu' and 'kvm' hypervisor