Change in vdsm[master]: hsm: Return true "truesize" for block volumes
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: hsm: Return true "truesize" for block volumes
......................................................................
hsm: Return true "truesize" for block volumes
HSM.getVolumeSize() and HSM.getVolumeInfo() used to return bogus value
for "truesize" for block volumes. This evil undocumented lie was
introduced in commit commit 1cef1409b1 (BZ#551944 - VDSM: getVolumeInfo:
Actual size field is not correct for RAW sparse files) on 2010.
Now we obtain block volumes "truesize" using qemu-img info.
Change-Id: Ib1e726727ef96f26a5d04ef86c87cb18d1ef658f
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/blockSD.py
M vdsm/storage/blockVolume.py
2 files changed, 11 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/85/37785/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index caaef6b..ebde78c 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -617,7 +617,9 @@
return int(size)
- getVAllocSize = getVSize
+ def getVAllocSize(self, imgUUID, volUUID):
+ """ Returns block volume true size in bytes. """
+ return self.produceVolume(imgUUID, volUUID).getVolumeTrueSize(bs=1)
def validateCreateVolumeParams(self, volFormat, srcVolUUID,
preallocate=None):
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index 2bb9a78..99c8840 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -643,7 +643,14 @@
sdobj = sdCache.produce(sdUUID=self.sdUUID)
return int(sdobj.getVSize(self.imgUUID, self.volUUID) / bs)
- getVolumeTrueSize = getVolumeSize
+ def getVolumeTrueSize(self, bs=BLOCK_SIZE):
+ """
+ Return the volume true size in blocks
+
+ Raises qemuimg.QImgError if volume size cannot be obtained.
+ """
+ info = qemuimg.info(self.getVolumePath())
+ return int(info["virtualsize"] / bs)
def _extendSizeRaw(self, newSize):
# Since this method relies on lvm.extendLV (lvextend) when the
--
To view, visit http://gerrit.ovirt.org/37785
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib1e726727ef96f26a5d04ef86c87cb18d1ef658f
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: lvm: Update hsm.__processVGInfos() with lvm.getPV() new API
by ishaby@redhat.com
Idan Shaby has uploaded a new change for review.
Change subject: lvm: Update hsm.__processVGInfos() with lvm.getPV() new API
......................................................................
lvm: Update hsm.__processVGInfos() with lvm.getPV() new API
In change I9932b044c (lvm: Raise an exception if missing physical
volume), we changed lvm.getPV() to raise an InaccessiblePhysDev
exception when the device is no longer in lvm's cache.
This patch updates hsm.__processVGInfos() to log a warning in such a
case since if we called lvm.getPV() with a device that is no longer in
lvm's cache, we still want to get the information for the other PVs.
That is, we don't want to stop hsm.__processVGInfos() operation.
Note that blovkSD.getMetaDataMapping() also calls lvm.getPV(), but in
contrast to hsm.__processVGInfos(), we don't want
blovkSD.getMetaDataMapping() to handle InaccessiblePhysDev because it's
a part of a scenario that creates a storage domain, and we want to fail
the whole operation in case that the PV is no longer in lvm's cache.
Change-Id: I583c0493093d2c9c8bca8713df8ee123c415de7f
Bug-Url: https://bugzilla.redhat.com/1048696
Signed-off-by: Idan Shaby <ishaby(a)redhat.com>
---
M vdsm/storage/hsm.py
1 file changed, 5 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/21/38421/1
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index b92349c..bbc0f84 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -3000,7 +3000,11 @@
vgType != dev["devtype"]):
vgType = multipath.DEV_MIXED
- pvInfo = lvm.getPV(pv)
+ try:
+ pvInfo = lvm.getPV(pv)
+ except se.InaccessiblePhysDev:
+ self.log.error("PV %s no longer exists", pv)
+ continue
vgInfo['pvlist'].append(self.__fillPVDict(dev, pvInfo, vgType))
if vgType == multipath.DEV_FCP:
--
To view, visit https://gerrit.ovirt.org/38421
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I583c0493093d2c9c8bca8713df8ee123c415de7f
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Idan Shaby <ishaby(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: call stop_event_loop upon exit
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: call stop_event_loop upon exit
......................................................................
call stop_event_loop upon exit
For cleanliness, whomever starts a thread should stop it when it is no
longer needed.
Change-Id: I9ab0d9b7be976e37a89a96d2f09a353186008731
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M vdsm/vdsm
1 file changed, 1 insertion(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/32/26532/1
diff --git a/vdsm/vdsm b/vdsm/vdsm
index 652797c..fd9b3f8 100755
--- a/vdsm/vdsm
+++ b/vdsm/vdsm
@@ -81,6 +81,7 @@
signal.pause()
finally:
cif.prepareForShutdown()
+ libvirtconnection.stop_event_loop()
def run(pidfile=None):
--
To view, visit http://gerrit.ovirt.org/26532
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9ab0d9b7be976e37a89a96d2f09a353186008731
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: janitorial: vm: switch to response.error()
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: janitorial: vm: switch to response.error()
......................................................................
janitorial: vm: switch to response.error()
response.error() offers a nicer and cleaner
way to report error responses instead of the bare
errCode['something'], even when we are fine with
the default generic message.
This patch makes use of response.error() all across
vm.py.
Change-Id: I3825faf7a144ef8973dee3cb9f9f0e52fabfc039
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 62 insertions(+), 62 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/68/38268/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index e7fbcf2..cd392c7 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -1589,7 +1589,7 @@
if self.lastStatus in (vmstatus.MIGRATION_SOURCE,
vmstatus.SAVING_STATE, vmstatus.DOWN):
self.log.error('cannot cont while %s', self.lastStatus)
- return errCode['unexpected']
+ return response.error('unexpected')
self._underlyingCont()
self._setGuestCpuRunning(self._isDomainRunning(),
guestCpuLocked=True)
@@ -1638,7 +1638,7 @@
def shutdown(self, delay, message, reboot, timeout, force):
if self.lastStatus == vmstatus.DOWN:
- return errCode['noVM']
+ return response.error('noVM')
delay = int(delay)
@@ -1913,13 +1913,13 @@
try:
if self.isMigrating():
self.log.warning('vm already migrating')
- return errCode['exist']
+ return response.error('exist')
if self.hasTransientDisks():
- return errCode['transientErr']
+ return response.error('transientErr')
# while we were blocking, another migrationSourceThread could have
# taken self Down
if self._lastStatus == vmstatus.DOWN:
- return errCode['noVM']
+ return response.error('noVM')
self._migrationSourceThread = migration.SourceThread(
self, **params)
self._migrationSourceThread.start()
@@ -1940,11 +1940,11 @@
return self._migrationSourceThread.status
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_OPERATION_INVALID:
- return errCode['migCancelErr']
+ return response.error('migCancelErr')
raise
except AttributeError:
if self._dom is None:
- return errCode['migCancelErr']
+ return response.error('migCancelErr')
raise
finally:
self._guestCpuLock.release()
@@ -2317,7 +2317,7 @@
def hotplugNic(self, params):
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
nicParams = params['nic']
nic = vmdevices.network.Interface(self.conf, self.log, **nicParams)
@@ -2336,7 +2336,7 @@
nicXml = hooks.after_nic_hotplug_fail(
nicXml, self.conf, params=nic.custom)
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
return response.error('hotplugNic', e.message)
else:
# FIXME! We may have a problem here if vdsm dies right after
@@ -2524,7 +2524,7 @@
response['vmList'] = self.status()
return response
else:
- return errCode['updateDevice']
+ return response.error('updateDevice')
def updateDevice(self, params):
if params.get('deviceType') == hwclass.NIC:
@@ -2532,11 +2532,11 @@
elif params.get('deviceType') == hwclass.GRAPHICS:
return self._updateGraphicsDevice(params)
else:
- return errCode['noimpl']
+ return response.error('noimpl')
def hotunplugNic(self, params):
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
nicParams = params['nic']
@@ -2583,7 +2583,7 @@
except libvirt.libvirtError as e:
self.log.exception("Hotunplug failed")
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
# Restore NIC device in vm's conf and _devices
if nicDev:
with self._confLock:
@@ -2602,7 +2602,7 @@
def setNumberOfCpus(self, numberOfCpus):
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
self.log.debug("Setting number of cpus to : %s", numberOfCpus)
hooks.before_set_num_of_cpus()
@@ -2612,7 +2612,7 @@
except libvirt.libvirtError as e:
self.log.exception("setNumberOfCpus failed")
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
return response.error('setNumberOfCpusErr', e.message)
self.conf['smp'] = str(numberOfCpus)
@@ -2646,7 +2646,7 @@
"""
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
if not params:
self.log.error("updateVmPolicy got an empty policy.")
@@ -2710,7 +2710,7 @@
except libvirt.libvirtError as e:
self.log.exception("updateVmPolicy failed")
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
else:
return self._reportError(key='updateVmPolicyErr',
msg=e.message)
@@ -2797,7 +2797,7 @@
except libvirt.libvirtError as e:
self.log.exception("setVmIoTune failed")
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
else:
return self._reportError(key='updateIoTuneErr',
msg=e.message)
@@ -2860,7 +2860,7 @@
def hotplugDisk(self, params):
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
diskParams = params.get('drive', {})
diskParams['path'] = self.cif.prepareVolumePath(diskParams)
@@ -2873,7 +2873,7 @@
drive = vmdevices.storage.Drive(self.conf, self.log, **diskParams)
if drive.hasVolumeLeases:
- return errCode['noimpl']
+ return response.error('noimpl')
driveXml = drive.getXML().toprettyxml(encoding='utf-8')
# TODO: this is debug information. For 3.6.x we still need to
@@ -2889,7 +2889,7 @@
self.log.exception("Hotplug failed")
self.cif.teardownVolumePath(diskParams)
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
return response.error('hotplugDisk', e.message)
else:
# FIXME! We may have a problem here if vdsm dies right after
@@ -2909,7 +2909,7 @@
def hotunplugDisk(self, params):
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
diskParams = params.get('drive', {})
diskParams['path'] = self.cif.prepareVolumePath(diskParams)
@@ -2922,7 +2922,7 @@
return response.error('hotunplugDisk', "Disk not found")
if drive.hasVolumeLeases:
- return errCode['noimpl']
+ return response.error('noimpl')
driveXml = drive.getXML().toprettyxml(encoding='utf-8')
# TODO: this is debug information. For 3.6.x we still need to
@@ -2949,7 +2949,7 @@
except libvirt.libvirtError as e:
self.log.exception("Hotunplug failed")
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
- return errCode['noVM']
+ return response.error('noVM')
self._devices[hwclass.DISK].append(drive)
# Restore disk device in vm's conf and _devices
if diskDev:
@@ -3239,7 +3239,7 @@
vmDrives = {}
if self.isMigrating():
- return errCode['migInProgress']
+ return response.error('migInProgress')
for drive in snapDrives:
baseDrv, tgetDrv = _normSnapDriveParams(drive)
@@ -3260,15 +3260,15 @@
except LookupError:
# The volume we want to snapshot doesn't exist
self.log.error("The base volume doesn't exist: %s", baseDrv)
- return errCode['snapshotErr']
+ return response.error('snapshotErr')
if vmDrive.hasVolumeLeases:
self.log.error('disk %s has volume leases', vmDrive.name)
- return errCode['noimpl']
+ return response.error('noimpl')
if vmDrive.transientDisk:
self.log.error('disk %s is a transient disk', vmDrive.name)
- return errCode['transientErr']
+ return response.error('transientErr')
vmDevName = vmDrive.name
@@ -3300,7 +3300,7 @@
self.log.exception('unable to prepare the volume path for '
'disk %s', vmDevName)
_rollbackDrives(preparedDrives)
- return errCode['snapshotErr']
+ return response.error('snapshotErr')
snapType = 'block' if vmDrives[vmDevName].blockDev else 'file'
snapelem = _diskSnapshot(vmDevName, newDrives[vmDevName]["path"],
@@ -3364,7 +3364,7 @@
self.log.exception("Unable to take snapshot")
if memoryParams:
self.cif.teardownVolumePath(memoryVol)
- return errCode['snapshotErr']
+ return response.error('snapshotErr')
# We are padding the memory volume with block size of zeroes
# because qemu-img truncates files such that their size is
@@ -3439,20 +3439,20 @@
srcDrive = self._findDriveByUUIDs(srcDisk)
except LookupError:
self.log.error("Unable to find the disk for '%s'", srcDisk)
- return errCode['imageErr']
+ return response.error('imageErr')
if srcDrive.hasVolumeLeases:
- return errCode['noimpl']
+ return response.error('noimpl')
if srcDrive.transientDisk:
- return errCode['transientErr']
+ return response.error('transientErr')
try:
self._setDiskReplica(srcDrive, dstDisk)
except Exception:
self.log.error("Unable to set the replication for disk '%s' with "
"destination '%s'", srcDrive.name, dstDisk)
- return errCode['replicaErr']
+ return response.error('replicaErr')
dstDiskCopy = dstDisk.copy()
@@ -3484,7 +3484,7 @@
except Exception:
self.log.exception("Cannot complete the disk replication process")
self._delDiskReplica(srcDrive)
- return errCode['replicaErr']
+ return response.error('replicaErr')
if srcDrive.chunked:
try:
@@ -3502,16 +3502,16 @@
try:
srcDrive = self._findDriveByUUIDs(srcDisk)
except LookupError:
- return errCode['imageErr']
+ return response.error('imageErr')
if srcDrive.hasVolumeLeases:
- return errCode['noimpl']
+ return response.error('noimpl')
if srcDrive.transientDisk:
- return errCode['transientErr']
+ return response.error('transientErr')
if not srcDrive.isDiskReplicationInProgress():
- return errCode['replicaErr']
+ return response.error('replicaErr')
# Looking for the replication blockJob info (checking its presence)
blkJobInfo = self._dom.blockJobInfo(srcDrive.name, 0)
@@ -3523,12 +3523,12 @@
# Making sure that we don't have any stale information
self._delDiskReplica(srcDrive)
- return errCode['replicaErr']
+ return response.error('replicaErr')
# Checking if we reached the replication mode ("mirroring" in libvirt
# and qemu terms)
if blkJobInfo['cur'] != blkJobInfo['end']:
- return errCode['unavail']
+ return response.error('unavail')
dstDiskCopy = dstDisk.copy()
@@ -3567,7 +3567,7 @@
# There is nothing we can do at this point other than logging
self.log.exception("Unable to teardown the replication "
"destination disk")
- return errCode['changeDisk'] # Finally is evaluated
+ return response.error('changeDisk') # Finally is evaluated
else:
try:
self.cif.teardownVolumePath(diskToTeardown)
@@ -3595,7 +3595,7 @@
"Requested extension size %s for disk %s is smaller "
"than the current size %s", newSizeBytes, drive.name,
currentSize)
- return errCode['resizeErr']
+ return response.error('resizeErr')
# Uncommit the current volume size (mark as in transaction)
self.cif.irs.setVolumeSize(drive.domainID, drive.poolID,
@@ -3608,7 +3608,7 @@
self.log.exception(
"An error occurred while trying to extend the disk %s "
"to size %s", drive.name, newSizeBytes)
- return errCode['updateDevice']
+ return response.error('updateDevice')
finally:
# In all cases we want to try and fix the size in the metadata.
# Same as above, this is what libvirt would do, see BZ#963881
@@ -3650,7 +3650,7 @@
"Libvirt failed to notify the new size %s to the "
"running VM, the change will be available at the ",
"reboot", sizeRoundedBytes, exc_info=True)
- return errCode['updateDevice']
+ return response.error('updateDevice')
return {'status': doneCode, 'size': str(sizeRoundedBytes)}
@@ -3658,12 +3658,12 @@
try:
newSizeBytes = int(newSizeBytes)
except ValueError:
- return errCode['resizeErr']
+ return response.error('resizeErr')
try:
drive = self._findDriveByUUIDs(driveSpecs)
except LookupError:
- return errCode['imageErr']
+ return response.error('imageErr')
try:
if drive.format == "cow":
@@ -3673,7 +3673,7 @@
except Exception:
self.log.exception("Unable to extend disk %s to size %s",
drive.name, newSizeBytes)
- return errCode['updateDevice']
+ return response.error('updateDevice')
def _onWatchdogEvent(self, action):
def actionToString(action):
@@ -3714,7 +3714,7 @@
try:
path = self.cif.prepareVolumePath(drivespec)
except VolumeError:
- return errCode['imageErr']
+ return response.error('imageErr')
diskelem = vmxml.Element('disk', type='file', device=vmDev)
diskelem.appendChildWithArgs('source', file=path)
diskelem.appendChildWithArgs('target', dev=blockdev)
@@ -3725,7 +3725,7 @@
except Exception:
self.log.debug("updateDeviceFlags failed", exc_info=True)
self.cif.teardownVolumePath(drivespec)
- return errCode['changeDisk']
+ return response.error('changeDisk')
if vmDev in self.conf:
self.cif.teardownVolumePath(self.conf[vmDev])
@@ -3902,7 +3902,7 @@
self.conf['vmId'], exc_info=True)
if e.get_error_code() == libvirt.VIR_ERR_OPERATION_FAILED:
return self._destroyVmForceful()
- return errCode['destroyErr']
+ return response.error('destroyErr')
return {'status': doneCode}
def _destroyVmForceful(self):
@@ -3911,7 +3911,7 @@
except libvirt.libvirtError:
self.log.warning("Failed to destroy VM '%s'",
self.conf['vmId'], exc_info=True)
- return errCode['destroyErr']
+ return response.error('destroyErr')
return {'status': doneCode}
def deleteVm(self):
@@ -4673,7 +4673,7 @@
def merge(self, driveSpec, baseVolUUID, topVolUUID, bandwidth, jobUUID):
if not caps.getLiveMergeSupport():
self.log.error("Live merge is not supported on this host")
- return errCode['mergeErr']
+ return response.error('mergeErr')
bandwidth = int(bandwidth)
if jobUUID is None:
@@ -4682,14 +4682,14 @@
try:
drive = self._findDriveByUUIDs(driveSpec)
except LookupError:
- return errCode['imageErr']
+ return response.error('imageErr')
# Check that libvirt exposes full volume chain information
chains = self._driveGetActualVolumeChain([drive])
if drive['alias'] not in chains:
self.log.error("merge: libvirt does not support volume chain "
"monitoring. Unable to perform live merge.")
- return errCode['mergeErr']
+ return response.error('mergeErr')
base = top = None
for v in drive.volumeChain:
@@ -4699,10 +4699,10 @@
top = v['path']
if base is None:
self.log.error("merge: base volume '%s' not found", baseVolUUID)
- return errCode['mergeErr']
+ return response.error('mergeErr')
if top is None:
self.log.error("merge: top volume '%s' not found", topVolUUID)
- return errCode['mergeErr']
+ return response.error('mergeErr')
# If base is a shared volume then we cannot allow a merge. Otherwise
# We'd corrupt the shared volume for other users.
@@ -4710,10 +4710,10 @@
drive.imageID, baseVolUUID)
if res['status']['code'] != 0:
self.log.error("Unable to get volume info for '%s'", baseVolUUID)
- return errCode['mergeErr']
+ return response.error('mergeErr')
if res['info']['voltype'] == 'SHARED':
self.log.error("merge: Refusing to merge into a shared volume")
- return errCode['mergeErr']
+ return response.error('mergeErr')
# Indicate that we expect libvirt to maintain the relative paths of
# backing files. This is necessary to ensure that a volume chain is
@@ -4738,7 +4738,7 @@
if res['status']['code'] != 0:
self.log.error("Unable to get volume info for '%s'",
topVolUUID)
- return errCode['mergeErr']
+ return response.error('mergeErr')
topSize = int(res['info']['apparentsize'])
# Take the jobs lock here to protect the new job we are tracking from
@@ -4749,7 +4749,7 @@
'commit')
except BlockJobExistsError:
self.log.error("A block job is already active on this disk")
- return errCode['mergeErr']
+ return response.error('mergeErr')
self.log.info("Starting merge with jobUUID='%s'", jobUUID)
try:
@@ -4760,7 +4760,7 @@
except (RuntimeError, libvirt.libvirtError):
self.log.exception("Live merge failed (job: %s)", jobUUID)
self.untrackBlockJob(jobUUID)
- return errCode['mergeErr']
+ return response.error('mergeErr')
# blockCommit will cause data to be written into the base volume.
# Perform an initial extension to ensure there is enough space to
--
To view, visit https://gerrit.ovirt.org/38268
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3825faf7a144ef8973dee3cb9f9f0e52fabfc039
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: virt: let Engine start a VM on an UNKOWN OS
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: virt: let Engine start a VM on an UNKOWN OS
......................................................................
virt: let Engine start a VM on an UNKOWN OS
This superflouse validation was introduced as a "bandage" to avoid
https://bugzilla.redhat.com/716705, where Vdsm failed to recognize
VMs with "UNKOWN" os injected to their bios.
Now that we recognize VMs based on guest channels existence, we can let
Engine start a VM on whatever host it deems valid.
Backward compatibility caveat: if a VM is started on an UNKOWN os, and
then migrated to an old Vdsm (pre ovirt-3.4.2), it would be killed when
that old Vdsm is to be restarted. It's not probable that someone would
start a long-running VM on an UNKOWN platform, we may want to wait with
this patch until ovirt-3.3 is deprecated.
Change-Id: Iee7b3913e76923043daab8fb85854c3290208237
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M vdsm/API.py
1 file changed, 0 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/59/32459/1
diff --git a/vdsm/API.py b/vdsm/API.py
index 8d1bca6..d6f318f 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -237,11 +237,6 @@
vmParams['vmId'])
vmParams['volatileFloppy'] = True
- if caps.osversion()['name'] == caps.OSName.UNKNOWN:
- return {'status': {'code': errCode['createErr']
- ['status']['code'],
- 'message': 'Unknown host operating system'}}
-
if 'sysprepInf' in vmParams:
if not self._createSysprepFloppyFromInf(vmParams['sysprepInf'],
vmParams['floppy']):
--
To view, visit http://gerrit.ovirt.org/32459
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iee7b3913e76923043daab8fb85854c3290208237
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: WIP: virt: better timeout for periodic operations
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: WIP: virt: better timeout for periodic operations
......................................................................
WIP: virt: better timeout for periodic operations
Change-Id: I735d314532c6852889e3ac188651acff044888ed
WIP: TODO: Documentation pending
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M tests/periodicTests.py
M vdsm/virt/periodic.py
M vdsm/virt/utils.py
M vdsm/virt/vm.py
4 files changed, 52 insertions(+), 20 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/33/39333/1
diff --git a/tests/periodicTests.py b/tests/periodicTests.py
index 80ef09e..d22f5ce 100644
--- a/tests/periodicTests.py
+++ b/tests/periodicTests.py
@@ -204,8 +204,9 @@
VMS = defaultdict(int)
- def __init__(self, vm):
+ def __init__(self, vm, timeout):
self._vm = vm
+ self._timeout = timeout # unused
self.required = True
self.runnable = True
diff --git a/vdsm/virt/periodic.py b/vdsm/virt/periodic.py
index fe8bbc8..3159c04 100644
--- a/vdsm/virt/periodic.py
+++ b/vdsm/virt/periodic.py
@@ -33,6 +33,7 @@
from vdsm.utils import monotonic_time
from . import sampling
+from .errors import TimeoutError
# just a made up number. Maybe should be equal to number of cores?
@@ -229,7 +230,7 @@
skipped = []
for vm_id, vm_obj in vms.iteritems():
- op = self._create(vm_obj)
+ op = self._create(vm_obj, self._timeout)
if not op.required:
continue
@@ -253,8 +254,9 @@
class UpdateVolumes(object):
- def __init__(self, vm):
+ def __init__(self, vm, timeout):
self._vm = vm
+ self._timeout = timeout
@property
def required(self):
@@ -267,15 +269,16 @@
def __call__(self):
for drive in self._vm.getDiskDevices():
- # TODO: If this block (it is actually possible?)
- # we must make sure we don't overwrite good data
- # with stale old data.
- self._vm.updateDriveVolume(drive)
+ try:
+ self._vm.updateDriveVolume(drive, timeout=self._timeout)
+ except TimeoutError:
+ pass # TODO log it?
class NumaInfoMonitor(object):
- def __init__(self, vm):
+ def __init__(self, vm, timeout):
self._vm = vm
+ self._timeout = timeout
@property
def required(self):
@@ -286,12 +289,16 @@
return self._vm.isDomainReadyForCommands()
def __call__(self):
- self._vm.updateNumaInfo()
+ try:
+ self._vm.updateNumaInfo(timeout=self._timeout)
+ except TimeoutError:
+ pass # TODO log it?
class BlockjobMonitor(object):
- def __init__(self, vm):
+ def __init__(self, vm, timeout):
self._vm = vm
+ self._timeout = timeout
@property
def required(self):
@@ -307,7 +314,10 @@
return self._vm.isDomainReadyForCommands()
def __call__(self):
- self._vm.updateVmJobs()
+ try:
+ self._vm.updateVmJobs(timeout=self._timeout)
+ except TimeoutError:
+ pass # TODO log it?
class DriveWatermarkMonitor(object):
diff --git a/vdsm/virt/utils.py b/vdsm/virt/utils.py
index 60becfa..385c893 100644
--- a/vdsm/virt/utils.py
+++ b/vdsm/virt/utils.py
@@ -25,6 +25,7 @@
import threading
from vdsm.utils import monotonic_time
+from .errors import TimeoutError
def isVdsmImage(drive):
@@ -110,3 +111,14 @@
raise ItemExpired
return value
+
+
+def discard_if_blocked(timeout, func, *args):
+ start = monotonic_time()
+ res = func(*args)
+ elapsed = monotonic_time() - start
+
+ if timeout is None or elapsed <= timeout:
+ return res
+
+ raise TimeoutError
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 460d45a..eb56ed6 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -72,7 +72,7 @@
from . import vmxml
from .errors import TimeoutError
-from .utils import isVdsmImage
+from .utils import isVdsmImage, discard_if_blocked
from vmpowerdown import VmShutdown, VmReboot
_VMCHANNEL_DEVICE_NAME = 'com.redhat.rhevm.vdsm'
@@ -2652,13 +2652,16 @@
raise LookupError("No such drive: '%s'" % drive)
- def updateDriveVolume(self, vmDrive):
+ # CAN_BLOCK
+ # PERIODIC_OPERATION
+ def updateDriveVolume(self, vmDrive, timeout=None):
if not vmDrive.device == 'disk' or not isVdsmImage(vmDrive):
return
- volSize = self.cif.irs.getVolumeSize(
- vmDrive.domainID, vmDrive.poolID, vmDrive.imageID,
- vmDrive.volumeID)
+ volSize = discard_if_blocked(
+ timeout, self.cif.irs.getVolumeSize,
+ vmDrive.domainID, vmDrive.poolID,
+ vmDrive.imageID, vmDrive.volumeID)
if volSize['status']['code'] != 0:
self.log.error(
@@ -4248,8 +4251,11 @@
with self._jobsLock:
return bool(self.conf['_blockJobs'])
- def updateVmJobs(self):
- self._vmJobs = self.queryBlockJobs()
+ # CAN_BLOCK
+ # PERIODIC_OPERATION
+ def updateVmJobs(self, timeout=None):
+ self._vmJobs = discard_if_blocked(
+ timeout, self.queryBlockJobs)
def queryBlockJobs(self):
def startCleanup(job, drive, needPivot):
@@ -4576,8 +4582,11 @@
statsAge)
stats['monitorResponse'] = '-1'
- def updateNumaInfo(self):
- self._numaInfo = numaUtils.getVmNumaNodeRuntimeInfo(self)
+ # CAN_BLOCK
+ # PERIODIC_OPERATION
+ def updateNumaInfo(self, timeout=None):
+ self._numaInfo = discard_if_blocked(
+ timeout, numaUtils.getVmNumaNodeRuntimeInfo, self)
@property
def hasGuestNumaNode(self):
--
To view, visit https://gerrit.ovirt.org/39333
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I735d314532c6852889e3ac188651acff044888ed
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: virt: enable libgfapi with snapshot support
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: virt: enable libgfapi with snapshot support
......................................................................
virt: enable libgfapi with snapshot support
Change-Id: Ie0965bef605ba67297670c0bf7924f88fa3b0460
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/hsm.py
M vdsm/virt/vm.py
2 files changed, 38 insertions(+), 17 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/68/33768/1
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index cd6f4b9..bde04be 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -3225,8 +3225,7 @@
path = os.path.join(dom.domaindir, sd.DOMAIN_IMAGES, imgUUID,
volUUID)
volInfo = {'domainID': sdUUID, 'imageID': imgUUID,
- 'volumeID': volUUID, 'path': path,
- 'volType': "path"}
+ 'volumeID': volUUID, 'path': path}
leasePath, leaseOffset = dom.getVolumeLease(imgUUID, volUUID)
@@ -3237,8 +3236,8 @@
})
imgVolumesInfo.append(volInfo)
- if volUUID == leafUUID:
- leafInfo = volInfo
+
+ leafInfo = dom.produceVolume(imgUUID, volUUID).getVmVolumeInfo()
return {'path': leafPath, 'info': leafInfo,
'imgVolumesInfo': imgVolumesInfo}
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 1eebb69..af0830a 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -3821,20 +3821,43 @@
def snapshot(self, snapDrives, memoryParams):
"""Live snapshot command"""
- def _diskSnapshot(vmDev, newPath, sourceType):
+ def _diskSnapshot(vmDev, oldDrive, newDriveDict):
"""Libvirt snapshot XML"""
+ sourceType = 'file'
+ sourceAttrs = {}
+ hostAttrs = {}
+
+ # TODO: unify these with the Drive.getXML() method
+ if oldDrive.networkDev:
+ sourceType = 'network'
+ sourceAttrs.update({
+ 'name': newDriveDict['volumeInfo']['path'],
+ 'protocol': newDriveDict['volumeInfo']['protocol']})
+ hostAttrs.update({
+ 'name': newDriveDict['volumeInfo']['volfileServer'],
+ 'port': newDriveDict['volumeInfo']['volPort'],
+ 'transport': newDriveDict['volumeInfo']['volTransport']})
+ else:
+ sourceAttrs.update({'file': newDriveDict['path']})
+
+ # Libvirt versions before 1.2.2 do not understand 'type'
+ # and treat all snapshots as if they are type='file'.
+ # In order to ensure proper handling of block snapshots
+ # in modern libvirt versions, we specify type='block'
+ # and dev=path for block volumes but we always speficy
+ # the file=path for backwards compatibility.
+ if oldDrive.blockDev:
+ sourceType = 'block'
+ sourceAttrs.update({'dev': newDriveDict['path']})
disk = vmxml.Element('disk', name=vmDev, snapshot='external',
type=sourceType)
- # Libvirt versions before 1.2.2 do not understand 'type' and treat
- # all snapshots as if they are type='file'. In order to ensure
- # proper handling of block snapshots in modern libvirt versions,
- # we specify type='block' and dev=path for block volumes but we
- # always speficy the file=path for backwards compatibility.
- args = {'type': sourceType, 'file': newPath}
- if sourceType == 'block':
- args['dev'] = newPath
- disk.appendChildWithArgs('source', **args)
+
+ source = disk.appendChildWithArgs('source', **sourceAttrs)
+
+ if hostAttrs:
+ source.appendChildWithArgs('host', **hostAttrs)
+
return disk
def _normSnapDriveParams(drive):
@@ -3964,9 +3987,8 @@
_rollbackDrives(preparedDrives)
return errCode['snapshotErr']
- snapType = 'block' if vmDrives[vmDevName].blockDev else 'file'
- snapelem = _diskSnapshot(vmDevName, newDrives[vmDevName]["path"],
- snapType)
+ snapelem = _diskSnapshot(vmDevName, vmDrives[vmDevName],
+ newDrives[vmDevName])
disks.appendChild(snapelem)
snap.appendChild(disks)
--
To view, visit http://gerrit.ovirt.org/33768
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie0965bef605ba67297670c0bf7924f88fa3b0460
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: functional net test: set both bridge_opts and ethtool_opts
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: functional net test: set both bridge_opts and ethtool_opts
......................................................................
functional net test: set both bridge_opts and ethtool_opts
This test has been written in an attempt to reproduce the referred bug,
to no avail.
Bug-Url: https://bugzilla.redhat.com/1186203
Change-Id: I57dd7fa0a05e83ab37393651f23cdf9b7e08ed89
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M tests/functional/networkTests.py
1 file changed, 42 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/51/39251/1
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 8671244..81218fe 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -2394,3 +2394,45 @@
self.assertNetworkDoesntExist(NETWORK_NAME)
self.assertBondDoesntExist(BONDING_NAME, [nic])
self.vdsm_net.save_config()
+
+ @cleanupNet
+ @ValidateRunningAsRoot
+ def test_ethtool_bridge_opts(self):
+ status, msg, info = self.vdsm_net.getVdsCapabilities()
+ self.assertEqual(status, SUCCESS, msg)
+ if '30_ethtool_options' not in info['hooks']['after_network_setup']:
+ raise SkipTest('ethtool hook not installed')
+
+ def get_gso(nic):
+ GSO = 'generic-segmentation-offload:'
+ rc, out, err = execCmd(['ethtool', '-k', nic])
+ self.assertTrue(rc == 0, 'error reading gso: %s' % err)
+ for line in out:
+ if line.startswith(GSO):
+ return line[len(GSO) + 1:]
+
+ def setup_bridge_and_eth_opts(nic, priority, gso):
+ bridge_opts = {'priority': priority}
+ custom = {
+ 'bridge_opts': 'priority=' + priority,
+ 'ethtool_opts': '-K * gso ' + gso
+ }
+
+ status, msg = self.vdsm_net.setupNetworks(
+ {NETWORK_NAME: {'nic': nic, 'bridged': True,
+ 'vlan': VLAN_ID,
+ 'custom': custom}},
+ {}, NOCHK)
+ self.assertEqual(status, SUCCESS, msg)
+ self.assertNetworkExists(NETWORK_NAME, bridgeOpts=bridge_opts)
+ self.assertEqual(get_gso(nic), gso)
+
+ with dummyIf(1) as (nic, ):
+ setup_bridge_and_eth_opts(nic, '42', 'on')
+ setup_bridge_and_eth_opts(nic, '33', 'off')
+
+ status, msg = self.vdsm_net.setupNetworks(
+ {NETWORK_NAME: {'remove': True}},
+ {}, NOCHK)
+ self.assertEqual(status, SUCCESS, msg)
+ self.assertNetworkDoesntExist(NETWORK_NAME)
--
To view, visit https://gerrit.ovirt.org/39251
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I57dd7fa0a05e83ab37393651f23cdf9b7e08ed89
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: net_func_tests: Make use of TEST-NET range instead of future...
by asegurap@redhat.com
Antoni Segura Puimedon has uploaded a new change for review.
Change subject: net_func_tests: Make use of TEST-NET range instead of future reserved range
......................................................................
net_func_tests: Make use of TEST-NET range instead of future reserved range
IPv4 has, according to RFC 5737, three network ranges that are
specifically designed to be used for tests and code samples. Up
until now we were using 240.0.0.0/24 that is part of 240.0.0.0/4
which according to RFC 6890 is reserved for future use. Thus, it
is more appropriate to use one of the test networks and this patch
does just that.
Change-Id: I31ed725b3092da48723ea213ad80205961d9e65a
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
M tests/functional/networkTests.py
1 file changed, 7 insertions(+), 6 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/59/31259/1
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index f02c2bc..3afd932 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -53,16 +53,17 @@
NETWORK_NAME = 'test-network'
VLAN_ID = '27'
BONDING_NAME = 'bond0'
-IP_ADDRESS = '240.0.0.1'
-IP_NETWORK = '240.0.0.0'
-IP_ADDRESS_IN_NETWORK = '240.0.0.50'
+# Use TEST-NET network (RFC 5737)
+IP_ADDRESS = '192.0.2.1'
+IP_NETWORK = '192.0.2.0'
+IP_ADDRESS_IN_NETWORK = '192.0.2.2'
IP_CIDR = '24'
IP_NETWORK_AND_CIDR = IP_NETWORK + '/' + IP_CIDR
-IP_GATEWAY = '240.0.0.254'
+IP_GATEWAY = '192.0.2.254'
+DHCP_RANGE_FROM = '192.0.2.10'
+DHCP_RANGE_TO = '192.0.2.100'
# Current implementation converts ip to its 32 bit int representation
IP_TABLE = '4026531841'
-DHCP_RANGE_FROM = '240.0.0.10'
-DHCP_RANGE_TO = '240.0.0.100'
CUSTOM_PROPS = {'linux': 'rules', 'vdsm': 'as well'}
IPv6_ADDRESS = 'fdb3:84e5:4ff4:55e3::1/64'
--
To view, visit http://gerrit.ovirt.org/31259
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I31ed725b3092da48723ea213ad80205961d9e65a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
8 years, 10 months
Change in vdsm[master]: extra_ipv4_addrs_hook: Add a hook for configuring secondary ...
by asegurap@redhat.com
Antoni Segura Puimedon has uploaded a new change for review.
Change subject: extra_ipv4_addrs_hook: Add a hook for configuring secondary addrs
......................................................................
extra_ipv4_addrs_hook: Add a hook for configuring secondary addrs
Sometimes it might be useful to set up extra addresses for the top
network device. This patch creates an after_network_setup hook that
allows just that, thanks to the custom network properties.
Change-Id: Id465870df6274552a68f6c9c0b907a843f08bf58
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
M configure.ac
A debian/vdsm-hook-extra-ipv4-addrs.docs
A debian/vdsm-hook-extra-ipv4-addrs.install
M vdsm.spec.in
M vdsm_hooks/Makefile.am
A vdsm_hooks/extra_ipv4_addrs/Makefile.am
A vdsm_hooks/extra_ipv4_addrs/README
A vdsm_hooks/extra_ipv4_addrs/extra_ipv4_addrs.py
A vdsm_hooks/extra_ipv4_addrs/sudoers
9 files changed, 147 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/38/29738/1
diff --git a/configure.ac b/configure.ac
index d741c1b..c319196 100644
--- a/configure.ac
+++ b/configure.ac
@@ -287,6 +287,7 @@
vdsm_hooks/directlun/Makefile
vdsm_hooks/ethtool_options/Makefile
vdsm_hooks/extnet/Makefile
+ vdsm_hooks/extra_ipv4_addrs/Makefile
vdsm_hooks/fakevmstats/Makefile
vdsm_hooks/faqemu/Makefile
vdsm_hooks/fileinject/Makefile
diff --git a/debian/vdsm-hook-extra-ipv4-addrs.docs b/debian/vdsm-hook-extra-ipv4-addrs.docs
new file mode 100644
index 0000000..5ecd9c6
--- /dev/null
+++ b/debian/vdsm-hook-extra-ipv4-addrs.docs
@@ -0,0 +1 @@
+COPYING
diff --git a/debian/vdsm-hook-extra-ipv4-addrs.install b/debian/vdsm-hook-extra-ipv4-addrs.install
new file mode 100644
index 0000000..f31188d
--- /dev/null
+++ b/debian/vdsm-hook-extra-ipv4-addrs.install
@@ -0,0 +1 @@
+usr/libexec/vdsm/hooks/after_network_setup/30_extra_ipv4_addrs
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 2b67962..4fedafd 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1282,6 +1282,10 @@
%{_libexecdir}/%{vdsm_name}/hooks/after_vm_destroy/50_directlun
%{_libexecdir}/%{vdsm_name}/hooks/before_vm_migrate_destination/50_directlun
+%files hook-extra-ipv4-addrs
+%defattr(-, root, root, -)
+%{_libexecdir}/%{vdsm_name}/hooks/after_network_setup/30_extra_ipv4_addrs
+
%files hook-fakevmstats
%defattr(-, root, root, -)
%{_libexecdir}/%{vdsm_name}/hooks/after_get_all_vm_stats/10_fakevmstats
diff --git a/vdsm_hooks/Makefile.am b/vdsm_hooks/Makefile.am
index 5e4d731..e05bf84 100644
--- a/vdsm_hooks/Makefile.am
+++ b/vdsm_hooks/Makefile.am
@@ -28,6 +28,7 @@
checkimages \
directlun \
extnet \
+ extra_ipv4_addrs \
fileinject \
fakevmstats \
floppy \
diff --git a/vdsm_hooks/extra_ipv4_addrs/Makefile.am b/vdsm_hooks/extra_ipv4_addrs/Makefile.am
new file mode 100644
index 0000000..1d987fe
--- /dev/null
+++ b/vdsm_hooks/extra_ipv4_addrs/Makefile.am
@@ -0,0 +1,38 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+EXTRA_DIST = \
+ extra_ipv4_addrs.py
+
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/after_network_setup
+ $(INSTALL_SCRIPT) $(srcdir)/extra_ipv4_addrs.py \
+ $(DESTDIR)$(vdsmhooksdir)/after_network_setup/30_extra_ipv4_addrs
+
+uninstall-local:
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/after_network_setup/30_extra_ipv4_addrs
+
+install-data-sudoers:
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/sudoers.d
+ $(INSTALL_DATA) $(srcdir)/sudoers \
+ $(DESTDIR)$(sysconfdir)/sudoers.d/50_vdsm_hook_extra_ipv4_addrs
+
+uninstall-data-sudoers:
+ $(RM) $(DESTDIR)$(sysconfdir)/sudoers.d/50_vdsm_hook_extra_ipv4_addrs
diff --git a/vdsm_hooks/extra_ipv4_addrs/README b/vdsm_hooks/extra_ipv4_addrs/README
new file mode 100644
index 0000000..01e4675
--- /dev/null
+++ b/vdsm_hooks/extra_ipv4_addrs/README
@@ -0,0 +1,17 @@
+extra_ipv4_addrs vdsm hook
+=================================
+This hook allows the user to set extra ipv4 addresses for vdsm networks.
+
+Requirements:
+* oVirt-3.5
+
+Usage:
+Configure the engine to enable setting the ipv4_addrs custom property by doing:
+
+ $ engine-config -s 'UserDefinedNetworkCustomProperties=ipv4_addrs=.*' \
+ --cver='3.5'
+
+In the oVirt UI edit custom network properties and, for the key 'ipv4_addrs'
+set the extra addresses in the following format:
+
+ 'addr/prefix, addr2/prefix2, ..., addrN/prefixN'
diff --git a/vdsm_hooks/extra_ipv4_addrs/extra_ipv4_addrs.py b/vdsm_hooks/extra_ipv4_addrs/extra_ipv4_addrs.py
new file mode 100644
index 0000000..419e7bf
--- /dev/null
+++ b/vdsm_hooks/extra_ipv4_addrs/extra_ipv4_addrs.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+import sys
+import hooking
+import traceback
+
+from vdsm import ipwrapper, utils
+
+
+def test():
+ opts = {'ipv4_addrs': '192.168.234.211/24, 192.168.211.234/24'}
+
+ nets = {'brless_bonded': {'bonding': 'james', 'custom': opts,
+ 'bootproto': 'dhcp', 'STP': 'no',
+ 'bridged': 'false', 'top_dev': 'james'},
+ 'brless_nic': {'nic': 'em1', 'custom': opts, 'bootproto': 'none',
+ 'ipaddr': '192.168.23.24',
+ 'netmask': '255.255.255.0', 'bridged': 'false',
+ 'top_dev': 'em1'},
+ 'brnet': {'nic': 'em1', 'custom': opts, 'bootproto': 'none',
+ 'ipaddr': '192.168.23.24', 'netmask': '255.255.255.0',
+ 'bridged': 'true', 'top_dev': 'brnet'}}
+
+ for net, attrs in nets.items():
+ print('Top device of network %s(%r) is %s' %
+ (net, attrs, _top_dev(net, attrs)))
+
+
+def main():
+ """Read ipv4_addrs from the network 'custom' properties and apply them
+ to the network's top device"""
+ setup_nets_config = hooking.read_json()
+ for network, attrs in setup_nets_config['request']['networks'].items():
+ if 'remove' in attrs:
+ continue
+ elif 'custom' in attrs:
+ _process_network(network, attrs)
+
+
+def _process_network(network, attrs):
+ """Applies extra ipv4 addresses to the network if necessary"""
+ options = attrs['custom'].get('ipv4_addrs')
+ if options is not None:
+ top_dev = _top_dev(network, attrs)
+ addresses = options.split(', ')
+ for addr in addresses:
+ ip, prefix = addr.split('/')
+ ipwrapper.addrAdd(top_dev, ip, prefix)
+
+
+def _top_dev(network, attrs):
+ if utils.tobool(attrs.get('bridged')):
+ return network
+ else: # bridgeless
+ return attrs.get('bonding') or attrs.get('nic')
+
+
+if __name__ == '__main__':
+ try:
+ if '--test' in sys.argv:
+ test()
+ else:
+ main()
+ except:
+ hooking.exit_hook('extra ipv4 addrs hook: [unexpected error]: %s\n' %
+ traceback.format_exc())
diff --git a/vdsm_hooks/extra_ipv4_addrs/sudoers b/vdsm_hooks/extra_ipv4_addrs/sudoers
new file mode 100644
index 0000000..f996069
--- /dev/null
+++ b/vdsm_hooks/extra_ipv4_addrs/sudoers
@@ -0,0 +1 @@
+vdsm ALL=(ALL) NOPASSWD: /usr/sbin/ip, /sbin/ip, /usr/bin/ip
--
To view, visit http://gerrit.ovirt.org/29738
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id465870df6274552a68f6c9c0b907a843f08bf58
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
8 years, 11 months