Change in vdsm[master]: virt: move Drive into vmdevices
fromani at redhat.com
fromani at redhat.com
Tue Oct 28 14:17:48 UTC 2014
Francesco Romani has uploaded a new change for review.
Change subject: virt: move Drive into vmdevices
......................................................................
virt: move Drive into vmdevices
no code changes besides import fixes.
Change-Id: Iaa7fe68e8a5b0d0d9203d0870523f988acbc46d4
Signed-off-by: Francesco Romani <fromani at redhat.com>
---
M tests/vmTests.py
M vdsm/virt/vm.py
M vdsm/virt/vmdevices.py
3 files changed, 329 insertions(+), 327 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/60/34560/1
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 3ab00a0..1d9b980 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -672,14 +672,14 @@
for driveInput, driveOutput in zip(sharedConfigs, expectedStates):
driveInput.update(driveConfig)
- drive = vm.Drive({}, self.log, **driveInput)
+ drive = vmdevices.Drive({}, self.log, **driveInput)
self.assertEqual(drive.extSharedState, driveOutput)
# Negative flow, unsupported value
driveInput.update({'shared': 'UNKNOWN-VALUE'})
with self.assertRaises(ValueError):
- drive = vm.Drive({}, self.log, **driveInput)
+ drive = vmdevices.Drive({}, self.log, **driveInput)
def testDriveXML(self):
SERIAL = '54-a672-23e5b495a9ea'
@@ -767,7 +767,7 @@
for (devConf, xml, blockDev, vmConf) in \
zip(devConfs, expectedXMLs, blockDevs, vmConfs):
- drive = vm.Drive(vmConf, self.log, **devConf)
+ drive = vmdevices.Drive(vmConf, self.log, **devConf)
# Patch Drive.blockDev to skip the block device checking.
drive._blockDev = blockDev
self.assertXML(drive.getXML(), xml % SERIAL)
@@ -799,7 +799,7 @@
for (devConf, exceptionMsg) in \
zip(devConfs, expectedExceptMsgs):
- drive = vm.Drive(vmConf, self.log, **devConf)
+ drive = vmdevices.Drive(vmConf, self.log, **devConf)
# Patch Drive.blockDev to skip the block device checking.
drive._blockDev = False
@@ -1155,7 +1155,7 @@
def testSetIoTune(self):
drives = [
- vm.Drive({
+ vmdevices.Drive({
"specParams": {
"ioTune": {
"total_bytes_sec": 9999,
@@ -1229,7 +1229,7 @@
"""
domainID = uuid.uuid4()
drives = [
- vm.Drive(
+ vmdevices.Drive(
{
"specParams": {
"ioTune": {
@@ -1249,7 +1249,7 @@
poolID=uuid.uuid4(),
volumeID=uuid.uuid4()
),
- vm.Drive(
+ vmdevices.Drive(
{
"specParams": {
"ioTune": {
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index bbf5ec2..588ad79 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -141,18 +141,6 @@
vmstatus.UP, vmstatus.WAIT_FOR_LAUNCH)
-class DRIVE_SHARED_TYPE:
- NONE = "none"
- EXCLUSIVE = "exclusive"
- SHARED = "shared"
- TRANSIENT = "transient"
-
- @classmethod
- def getAllValues(cls):
- # TODO: use introspection
- return (cls.NONE, cls.EXCLUSIVE, cls.SHARED, cls.TRANSIENT)
-
-
# These strings are representing libvirt virDomainEventType values
# http://libvirt.org/html/libvirt-libvirt.html#virDomainEventType
_EVENT_STRINGS = ("Defined",
@@ -632,311 +620,6 @@
return f
-class Drive(vmdevices.Base):
- __slots__ = ('iface', 'path', 'readonly', 'bootOrder', 'domainID',
- 'poolID', 'imageID', 'UUID', 'volumeID', 'format',
- 'propagateErrors', 'address', 'apparentsize', 'volumeInfo',
- 'index', 'name', 'optional', 'shared', 'truesize',
- 'volumeChain', 'baseVolumeID', 'serial', 'reqsize', 'cache',
- '_blockDev', 'extSharedState', 'drv', 'sgio', 'GUID',
- 'diskReplicate')
- VOLWM_CHUNK_MB = config.getint('irs', 'volume_utilization_chunk_mb')
- VOLWM_FREE_PCT = 100 - config.getint('irs', 'volume_utilization_percent')
- VOLWM_CHUNK_REPLICATE_MULT = 2 # Chunk multiplier during replication
-
- def __init__(self, conf, log, **kwargs):
- if not kwargs.get('serial'):
- self.serial = kwargs.get('imageID'[-20:]) or ''
- super(Drive, self).__init__(conf, log, **kwargs)
- # Keep sizes as int
- self.reqsize = int(kwargs.get('reqsize', '0')) # Backward compatible
- self.truesize = int(kwargs.get('truesize', '0'))
- self.apparentsize = int(kwargs.get('apparentsize', '0'))
- self.name = self._makeName()
- self.cache = config.get('vars', 'qemu_drive_cache')
-
- if self.device in ("cdrom", "floppy"):
- self._blockDev = False
- else:
- self._blockDev = None
-
- self._customize()
- self._setExtSharedState()
-
- def _setExtSharedState(self):
- # We cannot use tobool here as shared can take several values
- # (e.g. none, exclusive) that would be all mapped to False.
- shared = str(getattr(self, "shared", "false")).lower()
-
- # Backward compatibility with the old values (true, false)
- if shared == 'true':
- self.extSharedState = DRIVE_SHARED_TYPE.SHARED
- elif shared == 'false':
- if config.getboolean('irs', 'use_volume_leases'):
- self.extSharedState = DRIVE_SHARED_TYPE.EXCLUSIVE
- else:
- self.extSharedState = DRIVE_SHARED_TYPE.NONE
- elif shared in DRIVE_SHARED_TYPE.getAllValues():
- self.extSharedState = shared
- else:
- raise ValueError("Unknown shared value %s" % shared)
-
- @property
- def hasVolumeLeases(self):
- if self.extSharedState != DRIVE_SHARED_TYPE.EXCLUSIVE:
- return False
-
- for volInfo in getattr(self, "volumeChain", []):
- if "leasePath" in volInfo and "leaseOffset" in volInfo:
- return True
-
- return False
-
- def __getitem__(self, key):
- try:
- value = getattr(self, str(key))
- except AttributeError:
- raise KeyError(key)
- else:
- return value
-
- def __contains__(self, attr):
- return hasattr(self, attr)
-
- def isDiskReplicationInProgress(self):
- return hasattr(self, "diskReplicate")
-
- @property
- def volExtensionChunk(self):
- """
- Returns the volume extension chunks (used for the thin provisioning
- on block devices). The value is based on the vdsm configuration but
- can also dynamically change according to the VM needs (e.g. increase
- during a live storage migration).
- """
- if self.isDiskReplicationInProgress():
- return self.VOLWM_CHUNK_MB * self.VOLWM_CHUNK_REPLICATE_MULT
- return self.VOLWM_CHUNK_MB
-
- @property
- def watermarkLimit(self):
- """
- Returns the watermark limit, when the LV usage reaches this limit an
- extension is in order (thin provisioning on block devices).
- """
- return (self.VOLWM_FREE_PCT * self.volExtensionChunk *
- constants.MEGAB / 100)
-
- def getNextVolumeSize(self, curSize):
- """
- Returns the next volume size in megabytes. This value is based on the
- volExtensionChunk property and it's the size that should be requested
- for the next LV extension. curSize is the current size of the volume
- to be extended. For the leaf volume curSize == self.apparentsize.
- For internal volumes it is discovered by calling irs.getVolumeSize().
- """
- return (self.volExtensionChunk +
- ((curSize + constants.MEGAB - 1) / constants.MEGAB))
-
- @property
- def networkDev(self):
- try:
- return self.volumeInfo['volType'] == "network"
- except AttributeError:
- # To handle legacy and removable drives.
- return False
-
- @property
- def blockDev(self):
- if self.networkDev:
- return False
-
- if self._blockDev is None:
- try:
- self._blockDev = utils.isBlockDevice(self.path)
- except Exception:
- self.log.debug("Unable to determine if the path '%s' is a "
- "block device", self.path, exc_info=True)
- return self._blockDev
-
- @property
- def transientDisk(self):
- # Using getattr to handle legacy and removable drives.
- return getattr(self, 'shared', None) == DRIVE_SHARED_TYPE.TRANSIENT
-
- def _customize(self):
- if self.transientDisk:
- # Force the cache to be writethrough, which is qemu's default.
- # This is done to ensure that we don't ever use cache=none for
- # transient disks, since we create them in /var/run/vdsm which
- # may end up on tmpfs and don't support O_DIRECT, and qemu uses
- # O_DIRECT when cache=none and hence hotplug might fail with
- # error that one can take eternity to debug the reason behind it!
- self.cache = "writethrough"
- elif self.iface == 'virtio':
- try:
- self.cache = self.conf['custom']['viodiskcache']
- except KeyError:
- pass # Ignore if custom disk cache is missing
-
- def _makeName(self):
- devname = {'ide': 'hd', 'scsi': 'sd', 'virtio': 'vd', 'fdc': 'fd'}
- devindex = ''
-
- i = int(self.index)
- while i > 0:
- devindex = chr(ord('a') + (i % 26)) + devindex
- i /= 26
-
- return devname.get(self.iface, 'hd') + (devindex or 'a')
-
- def _checkIoTuneCategories(self, ioTuneParamsInfo):
- categories = ("bytes", "iops")
- for category in categories:
- if ioTuneParamsInfo.get('total_' + category + '_sec', 0) and \
- (ioTuneParamsInfo.get('read_' + category + '_sec', 0) or
- ioTuneParamsInfo.get('write_' + category + '_sec', 0)):
- raise ValueError('A non-zero total value and non-zero'
- ' read/write value for %s_sec can not be'
- ' set at the same time' % category)
-
- def _validateIoTuneParams(self, params):
- ioTuneParams = ('total_bytes_sec', 'read_bytes_sec',
- 'write_bytes_sec', 'total_iops_sec',
- 'write_iops_sec', 'read_iops_sec')
- for key, value in params.iteritems():
- try:
- if key in ioTuneParams:
- params[key] = int(value)
- if params[key] >= 0:
- continue
- else:
- raise Exception('parameter %s name is invalid' % key)
- except ValueError as e:
- e.args = ('an integer is required for ioTune'
- ' parameter %s' % key,) + e.args[1:]
- raise
- else:
- raise ValueError('parameter %s value should be'
- ' equal or greater than zero' % key)
-
- self._checkIoTuneCategories(params)
-
- def getLeasesXML(self):
- """
- Create domxml for the drive lease.
-
- <lease>
- <key>volumeID</key>
- <lockspace>domainID</lockspace>
- <target offset="0" path="/path/to/lease"/>
- </lease>
- """
- if not self.hasVolumeLeases:
- return # empty items generator
-
- # NOTE: at the moment we are generating the lease only for the leaf,
- # when libvirt will support shared leases this will loop over all the
- # volumes
- for volInfo in self.volumeChain[-1:]:
- lease = vmxml.Element('lease')
- lease.appendChildWithArgs('key', text=volInfo['volumeID'])
- lease.appendChildWithArgs('lockspace',
- text=volInfo['domainID'])
- lease.appendChildWithArgs('target', path=volInfo['leasePath'],
- offset=str(volInfo['leaseOffset']))
- yield lease
-
- def getXML(self):
- """
- Create domxml for disk/cdrom/floppy.
-
- <disk type='file' device='disk' snapshot='no'>
- <driver name='qemu' type='qcow2' cache='none'/>
- <source file='/path/to/image'/>
- <target dev='hda' bus='ide'/>
- <serial>54-a672-23e5b495a9ea</serial>
- </disk>
- """
- self.device = getattr(self, 'device', 'disk')
-
- source = vmxml.Element('source')
- if self.blockDev:
- deviceType = 'block'
- source.setAttrs(dev=self.path)
- elif self.networkDev:
- deviceType = 'network'
- source.setAttrs(protocol=self.volumeInfo['protocol'],
- name=self.volumeInfo['path'])
- hostAttrs = {'name': self.volumeInfo['volfileServer'],
- 'port': self.volumeInfo['volPort'],
- 'transport': self.volumeInfo['volTransport']}
- source.appendChildWithArgs('host', **hostAttrs)
- else:
- deviceType = 'file'
- sourceAttrs = {'file': self.path}
- if self.device == 'cdrom' or self.device == 'floppy':
- sourceAttrs['startupPolicy'] = 'optional'
- source.setAttrs(**sourceAttrs)
- diskelem = self.createXmlElem('disk', deviceType,
- ['device', 'address', 'sgio'])
- diskelem.setAttrs(snapshot='no')
- diskelem.appendChild(source)
-
- targetAttrs = {'dev': self.name}
- if self.iface:
- targetAttrs['bus'] = self.iface
- diskelem.appendChildWithArgs('target', **targetAttrs)
-
- if self.extSharedState == DRIVE_SHARED_TYPE.SHARED:
- diskelem.appendChildWithArgs('shareable')
- if hasattr(self, 'readonly') and utils.tobool(self.readonly):
- diskelem.appendChildWithArgs('readonly')
- elif self.device == 'floppy' and not hasattr(self, 'readonly'):
- # floppies are used only internally for sysprep, so
- # they are readonly unless explicitely stated otherwise
- diskelem.appendChildWithArgs('readonly')
- if hasattr(self, 'serial'):
- diskelem.appendChildWithArgs('serial', text=self.serial)
- if hasattr(self, 'bootOrder'):
- diskelem.appendChildWithArgs('boot', order=self.bootOrder)
-
- if self.device != 'lun' and hasattr(self, 'sgio'):
- raise ValueError("sgio attribute can be set only for LUN devices")
-
- if self.device == 'lun' and self.format == 'cow':
- raise ValueError("cow format is not supported for LUN devices")
-
- if self.device == 'disk' or self.device == 'lun':
- driverAttrs = {'name': 'qemu'}
- if self.blockDev:
- driverAttrs['io'] = 'native'
- else:
- driverAttrs['io'] = 'threads'
- if self.format == 'cow':
- driverAttrs['type'] = 'qcow2'
- elif self.format:
- driverAttrs['type'] = 'raw'
-
- driverAttrs['cache'] = self.cache
-
- if (self.propagateErrors == 'on' or
- utils.tobool(self.propagateErrors)):
- driverAttrs['error_policy'] = 'enospace'
- else:
- driverAttrs['error_policy'] = 'stop'
- diskelem.appendChildWithArgs('driver', **driverAttrs)
-
- if hasattr(self, 'specParams') and 'ioTune' in self.specParams:
- self._validateIoTuneParams(self.specParams['ioTune'])
- iotune = vmxml.Element('iotune')
- for key, value in self.specParams['ioTune'].iteritems():
- iotune.appendChildWithArgs(key, text=str(value))
- diskelem.appendChild(iotune)
-
- return diskelem
-
-
class MigrationError(Exception):
pass
@@ -963,7 +646,7 @@
log = logging.getLogger("vm.Vm")
# limit threads number until the libvirt lock will be fixed
_ongoingCreations = threading.BoundedSemaphore(4)
- DeviceMapping = ((vmdevices.DISK, Drive),
+ DeviceMapping = ((vmdevices.DISK, vmdevices.Drive),
(vmdevices.NIC, vmdevices.NetworkInterface),
(vmdevices.SOUND, vmdevices.Sound),
(vmdevices.VIDEO, vmdevices.VideoDevice),
@@ -3057,7 +2740,8 @@
return {'status': doneCode}
def _createTransientDisk(self, diskParams):
- if diskParams.get('shared', None) != DRIVE_SHARED_TYPE.TRANSIENT:
+ if (diskParams.get('shared', None) !=
+ vmdevices.DRIVE_SHARED_TYPE.TRANSIENT):
return
# FIXME: This should be replaced in future the support for transient
@@ -3102,7 +2786,7 @@
self._createTransientDisk(diskParams)
self.updateDriveIndex(diskParams)
- drive = Drive(self.conf, self.log, **diskParams)
+ drive = vmdevices.Drive(self.conf, self.log, **diskParams)
if drive.hasVolumeLeases:
return errCode['noimpl']
diff --git a/vdsm/virt/vmdevices.py b/vdsm/virt/vmdevices.py
index e6facf1..b9b2f1b 100644
--- a/vdsm/virt/vmdevices.py
+++ b/vdsm/virt/vmdevices.py
@@ -22,6 +22,7 @@
import libvirt
+from vdsm import constants
from vdsm import netinfo
from vdsm import utils
from vdsm.config import config
@@ -476,6 +477,323 @@
return bandwidth
+class DRIVE_SHARED_TYPE:
+ NONE = "none"
+ EXCLUSIVE = "exclusive"
+ SHARED = "shared"
+ TRANSIENT = "transient"
+
+ @classmethod
+ def getAllValues(cls):
+ # TODO: use introspection
+ return (cls.NONE, cls.EXCLUSIVE, cls.SHARED, cls.TRANSIENT)
+
+
+class Drive(Base):
+ __slots__ = ('iface', 'path', 'readonly', 'bootOrder', 'domainID',
+ 'poolID', 'imageID', 'UUID', 'volumeID', 'format',
+ 'propagateErrors', 'address', 'apparentsize', 'volumeInfo',
+ 'index', 'name', 'optional', 'shared', 'truesize',
+ 'volumeChain', 'baseVolumeID', 'serial', 'reqsize', 'cache',
+ '_blockDev', 'extSharedState', 'drv', 'sgio', 'GUID',
+ 'diskReplicate')
+ VOLWM_CHUNK_MB = config.getint('irs', 'volume_utilization_chunk_mb')
+ VOLWM_FREE_PCT = 100 - config.getint('irs', 'volume_utilization_percent')
+ VOLWM_CHUNK_REPLICATE_MULT = 2 # Chunk multiplier during replication
+
+ def __init__(self, conf, log, **kwargs):
+ if not kwargs.get('serial'):
+ self.serial = kwargs.get('imageID'[-20:]) or ''
+ super(Drive, self).__init__(conf, log, **kwargs)
+ # Keep sizes as int
+ self.reqsize = int(kwargs.get('reqsize', '0')) # Backward compatible
+ self.truesize = int(kwargs.get('truesize', '0'))
+ self.apparentsize = int(kwargs.get('apparentsize', '0'))
+ self.name = self._makeName()
+ self.cache = config.get('vars', 'qemu_drive_cache')
+
+ if self.device in ("cdrom", "floppy"):
+ self._blockDev = False
+ else:
+ self._blockDev = None
+
+ self._customize()
+ self._setExtSharedState()
+
+ def _setExtSharedState(self):
+ # We cannot use tobool here as shared can take several values
+ # (e.g. none, exclusive) that would be all mapped to False.
+ shared = str(getattr(self, "shared", "false")).lower()
+
+ # Backward compatibility with the old values (true, false)
+ if shared == 'true':
+ self.extSharedState = DRIVE_SHARED_TYPE.SHARED
+ elif shared == 'false':
+ if config.getboolean('irs', 'use_volume_leases'):
+ self.extSharedState = DRIVE_SHARED_TYPE.EXCLUSIVE
+ else:
+ self.extSharedState = DRIVE_SHARED_TYPE.NONE
+ elif shared in DRIVE_SHARED_TYPE.getAllValues():
+ self.extSharedState = shared
+ else:
+ raise ValueError("Unknown shared value %s" % shared)
+
+ @property
+ def hasVolumeLeases(self):
+ if self.extSharedState != DRIVE_SHARED_TYPE.EXCLUSIVE:
+ return False
+
+ for volInfo in getattr(self, "volumeChain", []):
+ if "leasePath" in volInfo and "leaseOffset" in volInfo:
+ return True
+
+ return False
+
+ def __getitem__(self, key):
+ try:
+ value = getattr(self, str(key))
+ except AttributeError:
+ raise KeyError(key)
+ else:
+ return value
+
+ def __contains__(self, attr):
+ return hasattr(self, attr)
+
+ def isDiskReplicationInProgress(self):
+ return hasattr(self, "diskReplicate")
+
+ @property
+ def volExtensionChunk(self):
+ """
+ Returns the volume extension chunks (used for the thin provisioning
+ on block devices). The value is based on the vdsm configuration but
+ can also dynamically change according to the VM needs (e.g. increase
+ during a live storage migration).
+ """
+ if self.isDiskReplicationInProgress():
+ return self.VOLWM_CHUNK_MB * self.VOLWM_CHUNK_REPLICATE_MULT
+ return self.VOLWM_CHUNK_MB
+
+ @property
+ def watermarkLimit(self):
+ """
+ Returns the watermark limit, when the LV usage reaches this limit an
+ extension is in order (thin provisioning on block devices).
+ """
+ return (self.VOLWM_FREE_PCT * self.volExtensionChunk *
+ constants.MEGAB / 100)
+
+ def getNextVolumeSize(self, curSize):
+ """
+ Returns the next volume size in megabytes. This value is based on the
+ volExtensionChunk property and it's the size that should be requested
+ for the next LV extension. curSize is the current size of the volume
+ to be extended. For the leaf volume curSize == self.apparentsize.
+ For internal volumes it is discovered by calling irs.getVolumeSize().
+ """
+ return (self.volExtensionChunk +
+ ((curSize + constants.MEGAB - 1) / constants.MEGAB))
+
+ @property
+ def networkDev(self):
+ try:
+ return self.volumeInfo['volType'] == "network"
+ except AttributeError:
+ # To handle legacy and removable drives.
+ return False
+
+ @property
+ def blockDev(self):
+ if self.networkDev:
+ return False
+
+ if self._blockDev is None:
+ try:
+ self._blockDev = utils.isBlockDevice(self.path)
+ except Exception:
+ self.log.debug("Unable to determine if the path '%s' is a "
+ "block device", self.path, exc_info=True)
+ return self._blockDev
+
+ @property
+ def transientDisk(self):
+ # Using getattr to handle legacy and removable drives.
+ return getattr(self, 'shared', None) == DRIVE_SHARED_TYPE.TRANSIENT
+
+ def _customize(self):
+ if self.transientDisk:
+ # Force the cache to be writethrough, which is qemu's default.
+ # This is done to ensure that we don't ever use cache=none for
+ # transient disks, since we create them in /var/run/vdsm which
+ # may end up on tmpfs and don't support O_DIRECT, and qemu uses
+ # O_DIRECT when cache=none and hence hotplug might fail with
+ # error that one can take eternity to debug the reason behind it!
+ self.cache = "writethrough"
+ elif self.iface == 'virtio':
+ try:
+ self.cache = self.conf['custom']['viodiskcache']
+ except KeyError:
+ pass # Ignore if custom disk cache is missing
+
+ def _makeName(self):
+ devname = {'ide': 'hd', 'scsi': 'sd', 'virtio': 'vd', 'fdc': 'fd'}
+ devindex = ''
+
+ i = int(self.index)
+ while i > 0:
+ devindex = chr(ord('a') + (i % 26)) + devindex
+ i /= 26
+
+ return devname.get(self.iface, 'hd') + (devindex or 'a')
+
+ def _checkIoTuneCategories(self, ioTuneParamsInfo):
+ categories = ("bytes", "iops")
+ for category in categories:
+ if ioTuneParamsInfo.get('total_' + category + '_sec', 0) and \
+ (ioTuneParamsInfo.get('read_' + category + '_sec', 0) or
+ ioTuneParamsInfo.get('write_' + category + '_sec', 0)):
+ raise ValueError('A non-zero total value and non-zero'
+ ' read/write value for %s_sec can not be'
+ ' set at the same time' % category)
+
+ def _validateIoTuneParams(self, params):
+ ioTuneParams = ('total_bytes_sec', 'read_bytes_sec',
+ 'write_bytes_sec', 'total_iops_sec',
+ 'write_iops_sec', 'read_iops_sec')
+ for key, value in params.iteritems():
+ try:
+ if key in ioTuneParams:
+ params[key] = int(value)
+ if params[key] >= 0:
+ continue
+ else:
+ raise Exception('parameter %s name is invalid' % key)
+ except ValueError as e:
+ e.args = ('an integer is required for ioTune'
+ ' parameter %s' % key,) + e.args[1:]
+ raise
+ else:
+ raise ValueError('parameter %s value should be'
+ ' equal or greater than zero' % key)
+
+ self._checkIoTuneCategories(params)
+
+ def getLeasesXML(self):
+ """
+ Create domxml for the drive lease.
+
+ <lease>
+ <key>volumeID</key>
+ <lockspace>domainID</lockspace>
+ <target offset="0" path="/path/to/lease"/>
+ </lease>
+ """
+ if not self.hasVolumeLeases:
+ return # empty items generator
+
+ # NOTE: at the moment we are generating the lease only for the leaf,
+ # when libvirt will support shared leases this will loop over all the
+ # volumes
+ for volInfo in self.volumeChain[-1:]:
+ lease = vmxml.Element('lease')
+ lease.appendChildWithArgs('key', text=volInfo['volumeID'])
+ lease.appendChildWithArgs('lockspace',
+ text=volInfo['domainID'])
+ lease.appendChildWithArgs('target', path=volInfo['leasePath'],
+ offset=str(volInfo['leaseOffset']))
+ yield lease
+
+ def getXML(self):
+ """
+ Create domxml for disk/cdrom/floppy.
+
+ <disk type='file' device='disk' snapshot='no'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source file='/path/to/image'/>
+ <target dev='hda' bus='ide'/>
+ <serial>54-a672-23e5b495a9ea</serial>
+ </disk>
+ """
+ self.device = getattr(self, 'device', 'disk')
+
+ source = vmxml.Element('source')
+ if self.blockDev:
+ deviceType = 'block'
+ source.setAttrs(dev=self.path)
+ elif self.networkDev:
+ deviceType = 'network'
+ source.setAttrs(protocol=self.volumeInfo['protocol'],
+ name=self.volumeInfo['path'])
+ hostAttrs = {'name': self.volumeInfo['volfileServer'],
+ 'port': self.volumeInfo['volPort'],
+ 'transport': self.volumeInfo['volTransport']}
+ source.appendChildWithArgs('host', **hostAttrs)
+ else:
+ deviceType = 'file'
+ sourceAttrs = {'file': self.path}
+ if self.device == 'cdrom' or self.device == 'floppy':
+ sourceAttrs['startupPolicy'] = 'optional'
+ source.setAttrs(**sourceAttrs)
+ diskelem = self.createXmlElem('disk', deviceType,
+ ['device', 'address', 'sgio'])
+ diskelem.setAttrs(snapshot='no')
+ diskelem.appendChild(source)
+
+ targetAttrs = {'dev': self.name}
+ if self.iface:
+ targetAttrs['bus'] = self.iface
+ diskelem.appendChildWithArgs('target', **targetAttrs)
+
+ if self.extSharedState == DRIVE_SHARED_TYPE.SHARED:
+ diskelem.appendChildWithArgs('shareable')
+ if hasattr(self, 'readonly') and utils.tobool(self.readonly):
+ diskelem.appendChildWithArgs('readonly')
+ elif self.device == 'floppy' and not hasattr(self, 'readonly'):
+ # floppies are used only internally for sysprep, so
+ # they are readonly unless explicitely stated otherwise
+ diskelem.appendChildWithArgs('readonly')
+ if hasattr(self, 'serial'):
+ diskelem.appendChildWithArgs('serial', text=self.serial)
+ if hasattr(self, 'bootOrder'):
+ diskelem.appendChildWithArgs('boot', order=self.bootOrder)
+
+ if self.device != 'lun' and hasattr(self, 'sgio'):
+ raise ValueError("sgio attribute can be set only for LUN devices")
+
+ if self.device == 'lun' and self.format == 'cow':
+ raise ValueError("cow format is not supported for LUN devices")
+
+ if self.device == 'disk' or self.device == 'lun':
+ driverAttrs = {'name': 'qemu'}
+ if self.blockDev:
+ driverAttrs['io'] = 'native'
+ else:
+ driverAttrs['io'] = 'threads'
+ if self.format == 'cow':
+ driverAttrs['type'] = 'qcow2'
+ elif self.format:
+ driverAttrs['type'] = 'raw'
+
+ driverAttrs['cache'] = self.cache
+
+ if (self.propagateErrors == 'on' or
+ utils.tobool(self.propagateErrors)):
+ driverAttrs['error_policy'] = 'enospace'
+ else:
+ driverAttrs['error_policy'] = 'stop'
+ diskelem.appendChildWithArgs('driver', **driverAttrs)
+
+ if hasattr(self, 'specParams') and 'ioTune' in self.specParams:
+ self._validateIoTuneParams(self.specParams['ioTune'])
+ iotune = vmxml.Element('iotune')
+ for key, value in self.specParams['ioTune'].iteritems():
+ iotune.appendChildWithArgs(key, text=str(value))
+ diskelem.appendChild(iotune)
+
+ return diskelem
+
+
def initLegacyConf(conf):
conf['displayPort'] = Graphics.LIBVIRT_PORT_AUTOSELECT
conf['displaySecurePort'] = Graphics.LIBVIRT_PORT_AUTOSELECT
--
To view, visit http://gerrit.ovirt.org/34560
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaa7fe68e8a5b0d0d9203d0870523f988acbc46d4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani at redhat.com>
More information about the vdsm-patches
mailing list