Francesco Romani has uploaded a new change for review.
Change subject: migration: move progress update into an helper
......................................................................
migration: move progress update into an helper
Streamline migration.SourceThread.getStat() by moving
responsabilities in helper functions, in order
to make the code easier to follow.
Let's start with the progress reporting and tracking.
Change-Id: Ie9707fcc492a394f8d7aebd57482c44b7b5a703d
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/migration.py
1 file changed, 6 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/97/42797/1
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 415cdc1..6f7631a 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -114,9 +114,7 @@
else:
res = utils.picklecopy(self._last_error)
- if self._monitorThread is not None:
- # fetch migration status from the monitor thread
- self._progress = self._monitorThread.progress
+ self._updateStatus()
res['progress'] = self._progress
@@ -126,6 +124,11 @@
return res
+ def _updateStatus(self):
+ if self._monitorThread is not None:
+ # we need to report monotonic progress
+ self._progress = self._monitorThread.progress
+
def _createClient(self, port):
sslctx = sslutils.create_ssl_context()
client_socket = utils.create_connected_socket(
--
To view, visit https://gerrit.ovirt.org/42797
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie9707fcc492a394f8d7aebd57482c44b7b5a703d
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Francesco Romani has uploaded a new change for review.
Change subject: migration: de-entangle migration stat reporting
......................................................................
migration: de-entangle migration stat reporting
migration.SourceThread has very entangled and messy
status reporting. One single field is in charge to
track migration status, including progress, errors
and so forth.
This leads to code hard to follow and to change.
As first step to clean up the mess, we split
the migration status tracking (e.g. progress
while running, stats when done) from last error tracking.
Change-Id: I6d745bacddf80c54354a2f7ec2d290dfd3b12d03
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/migration.py
1 file changed, 14 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/96/42796/1
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 99af017..415cdc1 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -89,6 +89,7 @@
config.get('vars', 'migration_downtime')
self._autoConverge = autoConverge
self._compressed = compressed
+ self._last_error = None
self._last_status = {
'status': {
'code': 0,
@@ -107,16 +108,23 @@
"""
Get the status of the migration.
"""
+
+ if self._last_error is None:
+ res = utils.picklecopy(self._last_status)
+ else:
+ res = utils.picklecopy(self._last_error)
+
if self._monitorThread is not None:
# fetch migration status from the monitor thread
self._progress = self._monitorThread.progress
- self._last_status['progress'] = self._progress
+
+ res['progress'] = self._progress
stat = self._vm._dom.jobStats(libvirt.VIR_DOMAIN_JOB_STATS_COMPLETED)
if 'downtime_net' in stat:
- self._last_status['downtime'] = stat['downtime_net']
+ res['downtime'] = stat['downtime_net']
- return self._last_status
+ return res
def _createClient(self, port):
sslctx = sslutils.create_ssl_context()
@@ -197,8 +205,7 @@
self._vm.lastStatus = vmstatus.MIGRATION_SOURCE
def _recover(self, message):
- if not response.is_failure(self._last_status):
- self._last_status = response.error('migrateErr')
+ self._last_error = response.error('migrateErr')
self.log.error(message)
if not self.hibernating:
try:
@@ -288,7 +295,7 @@
self._finishSuccessfully()
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_OPERATION_ABORTED:
- self._last_status = response.error(
+ self._last_error = response.error(
'migCancelErr',
message='Migration canceled')
raise
@@ -326,7 +333,7 @@
destCreationTime)
if response.is_failure(result):
- self._last_status = result
+ self._last_error = result
raise RuntimeError('migration destination error: ' +
result['status']['message'])
if config.getboolean('vars', 'ssl'):
--
To view, visit https://gerrit.ovirt.org/42796
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6d745bacddf80c54354a2f7ec2d290dfd3b12d03
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Francesco Romani has uploaded a new change for review.
Change subject: migration: return plain response on error
......................................................................
migration: return plain response on error
We should add extra status fields only when migration
is OK (either doing OK or completed OK).
It makes no sense to do that on error, as the fields
are meaningless.
TODO: make sure there aren't legacy constraints and
Engine unexpectedly relies on those fields being present
on error.
In that case I'll mark them REQUIRED_FOR in the error path
and leave them alone until 4.0
Change-Id: Ifafa5de4db317ed0e2f735eca6d944042e19c4e1
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/migration.py
1 file changed, 5 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/99/42799/1
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 6ea4357..8cdfc10 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -111,12 +111,12 @@
if self._last_error is None:
res = utils.picklecopy(self._last_status)
+
+ self._updateStatus()
+
+ return self._addMigrationFields(res)
else:
- res = utils.picklecopy(self._last_error)
-
- self._updateStatus()
-
- return self._addMigrationFields(res)
+ return utils.picklecopy(self._last_error)
def _updateStatus(self):
if self._monitorThread is not None:
--
To view, visit https://gerrit.ovirt.org/42799
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifafa5de4db317ed0e2f735eca6d944042e19c4e1
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Francesco Romani has uploaded a new change for review.
Change subject: migration: add helper to add status field
......................................................................
migration: add helper to add status field
In the case the migration is correctly progressing,
or if it succesfully completed, we need to report
extra status fields to Engine in a succesfull
response.
This patch extracts the code which does that from
getStat to an helper method, to make the code more
self-describing.
Change-Id: I047705e2f45221ad3a7527ca6b018dc6d0f3368e
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/migration.py
1 file changed, 12 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/98/42798/1
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 6f7631a..6ea4357 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -116,6 +116,18 @@
self._updateStatus()
+ return self._addMigrationFields(res)
+
+ def _updateStatus(self):
+ if self._monitorThread is not None:
+ # we need to report monotonic progress
+ self._progress = self._monitorThread.progress
+
+ def _addMigrationFields(self, res):
+ """
+ Adds migration-status specific fields, required
+ by schema, to a plain response object.
+ """
res['progress'] = self._progress
stat = self._vm._dom.jobStats(libvirt.VIR_DOMAIN_JOB_STATS_COMPLETED)
@@ -123,11 +135,6 @@
res['downtime'] = stat['downtime_net']
return res
-
- def _updateStatus(self):
- if self._monitorThread is not None:
- # we need to report monotonic progress
- self._progress = self._monitorThread.progress
def _createClient(self, port):
sslctx = sslutils.create_ssl_context()
--
To view, visit https://gerrit.ovirt.org/42798
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I047705e2f45221ad3a7527ca6b018dc6d0f3368e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Francesco Romani has uploaded a new change for review.
Change subject: migration: build new reason on success
......................................................................
migration: build new reason on success
There is no need to cache successfull responses,
it is cleaner and safer to build them on the fly
when requested.
We should only cache errors, and only because SourceThread
is orchestrating DowntimeThread and MonitorThread.
Change-Id: Ic42b70be6f5a5406e23916e16a678dd8caf0f500
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/virt/migration.py
1 file changed, 30 insertions(+), 10 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/00/42800/1
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 8cdfc10..0e6a024 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -53,6 +53,20 @@
VIR_MIGRATE_PARAM_GRAPHICS_URI = 'graphics_uri'
+class MigrationStatus(object):
+ IN_PROGRESS = 'Migration in progress'
+ COMPLETED = 'Migration done'
+ SAVESTATE_DONE = 'SaveState done'
+ CANCELED = 'Migration process cancelled'
+
+
+class MigrationAbortReason(object):
+ UNKNOWN = 0, # no further detail available.
+ CLIENT = 1
+ MAX_TIME = 2
+ STALLED = 3
+
+
class SourceThread(threading.Thread):
"""
A thread that takes care of migration on the source vdsm.
@@ -90,10 +104,7 @@
self._autoConverge = autoConverge
self._compressed = compressed
self._last_error = None
- self._last_status = {
- 'status': {
- 'code': 0,
- 'message': 'Migration in progress'}}
+ self._last_status = MigrationStatus.IN_PROGRESS
self._progress = 0
threading.Thread.__init__(self)
self._preparingMigrationEvt = True
@@ -107,13 +118,23 @@
def getStat(self):
"""
Get the status of the migration.
+
+ TODO: this method is troublesome. We are *lying*, we
+ are *not* compliant to the schema and we know it.
+ The problem is that we cannot change the return value
+ to conform to schema and to cleanup things, for
+ legacy constraings.
"""
if self._last_error is None:
- res = utils.picklecopy(self._last_status)
+ res = response.success(message=self._last_status)
self._updateStatus()
+ # this uglyness is REQUIRED_FOR: Engine 3.x
+ # TODO when we can break compatibility:
+ # refactor and cleanup. Schema is already
+ # much better, too bad we cannot comply.
return self._addMigrationFields(res)
else:
return utils.picklecopy(self._last_error)
@@ -232,7 +253,7 @@
self._progress = 100
if not self.hibernating:
self._vm.setDownStatus(NORMAL, vmexitreason.MIGRATION_SUCCEEDED)
- self._last_status['status']['message'] = 'Migration done'
+ self._last_status = MigrationStatus.COMPLETED
else:
# don't pickle transient params
for ignoreParam in ('displayIp', 'display', 'pid'):
@@ -247,7 +268,7 @@
self._vm.cif.teardownVolumePath(self._dstparams)
self._vm.setDownStatus(NORMAL, vmexitreason.SAVE_STATE_SUCCEEDED)
- self._last_status['status']['message'] = 'SaveState done'
+ self._last_status = MigrationStatus.SAVESTATE_DONE
def _patchConfigForLegacy(self):
"""
@@ -421,9 +442,8 @@
if not self._preparingMigrationEvt:
raise
else:
- self._last_status['status']['message'] = \
- 'Migration process cancelled'
- return self._last_status
+ self._last_status = MigrationStatus.CANCELED
+ return response.success(message=self._last_status)
def exponential_downtime(downtime, steps):
--
To view, visit https://gerrit.ovirt.org/42800
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic42b70be6f5a5406e23916e16a678dd8caf0f500
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Jakub Niedermertl has uploaded a new change for review.
Change subject: storage: Hidden files filtered form listings of storage domains
......................................................................
storage: Hidden files filtered form listings of storage domains
Listing of files in storage domain (FileStorageDomain#getFileList) now
returns only non-hidden files (not starting with '.'). It allows to
avoid various auxiliary hidden files like '.keep'. It is especially
useful in context of ISO doman that stores files for various purposes.
Change-Id: I0eebd8b9fe98c41df686330858b3292fa37ba245
Bug-Url: https://bugzilla.redhat.com/1259279
Signed-off-by: Jakub Niedermertl <jniederm(a)redhat.com>
---
M vdsm/storage/fileSD.py
M vdsm/storage/hsm.py
2 files changed, 11 insertions(+), 6 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/45645/1
diff --git a/vdsm/storage/fileSD.py b/vdsm/storage/fileSD.py
index 5c9aa6d..85140ac 100644
--- a/vdsm/storage/fileSD.py
+++ b/vdsm/storage/fileSD.py
@@ -421,12 +421,15 @@
def getFileList(self, pattern, caseSensitive):
"""
- Returns a list of all files in the domain filtered according to
- extension.
+ Returns a list of all visible (not starting with '.') files in the
+ domain filtered according to extension.
"""
basedir = self.getIsoDomainImagesDir()
filesList = self.oop.simpleWalk(basedir)
+ nonHiddenFilesRE = '.*/[^.][^/]*$'
+ filesList = [x for x in filesList if re.match(nonHiddenFilesRE, x)]
+
if pattern != '*':
if caseSensitive:
filesList = fnmatch.filter(filesList, pattern)
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 82f4426..7674209 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -2305,8 +2305,8 @@
def getFileStats(self, sdUUID, pattern='*', caseSensitive=False,
options=None):
"""
- Returns statistics of all files in the domain filtered according to
- pattern.
+ Returns statistics of all visible (not starting with '.') files in
+ the domain filtered according to pattern.
:param sdUUID: The UUID of the storage domain you want to query.
:type sdUUID: UUID
@@ -2333,7 +2333,8 @@
@public
def getIsoList(self, spUUID, extension='iso', options=None):
"""
- Gets a list of all ISO/Floppy volumes in a storage pool.
+ Gets a list of all visible (not starting with '.') ISO/Floppy volumes
+ in a storage pool.
:param spUUID: The UUID of the storage pool you want to query.
:type spUUID: UUID
@@ -2361,7 +2362,8 @@
@public
def getFloppyList(self, spUUID, options=None):
"""
- Gets a list of all Floppy volumes if a storage pool.
+ Gets a list of all visible (not starting with '.') Floppy volumes of
+ a storage pool.
:param spUUID: The UUID of the storage pool you want to query.
:type spUUID: UUID
--
To view, visit https://gerrit.ovirt.org/45645
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0eebd8b9fe98c41df686330858b3292fa37ba245
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Jakub Niedermertl <jniederm(a)redhat.com>
Hello Fred Rolland, Allon Mureinik,
I'd like you to do a code review. Please visit
https://gerrit.ovirt.org/46651
to review the following change.
Change subject: lvm: Check if device in VG before extend
......................................................................
lvm: Check if device in VG before extend
Before extending a VG, VDSM needs to check that none of
the additional devices are not already part of the VG.
Without this protection, LVM will create a new PV with the
same device. After extending VG, its metadata will updated
with new PV. As a result, the VG will be partial.
pvs output after creating new PV with same device:
# pvs
WARNING: Device for PV 2fDjgH-TeKA-1Vy2-NMMv-GB9n-op0w-g2Nyrd not
found or rejected by a filter.
PV
/dev/mapper/360014054bf6dd7d14fd40c9ac3b5dbe8
unknown device
Change-Id: Ifec2503094d6a0ecdd32e5e62f9c01a1469145f3
Backport-To: 3.6
Bug-Url: https://bugzilla.redhat.com/1265907
Signed-off-by: Fred Rolland <frolland(a)redhat.com>
Reviewed-on: https://gerrit.ovirt.org/45946
Continuous-Integration: Jenkins CI
Reviewed-by: Allon Mureinik <amureini(a)redhat.com>
Reviewed-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/lvm.py
1 file changed, 7 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/51/46651/1
diff --git a/vdsm/storage/lvm.py b/vdsm/storage/lvm.py
index aa3c04b..7f2adf1 100644
--- a/vdsm/storage/lvm.py
+++ b/vdsm/storage/lvm.py
@@ -962,6 +962,13 @@
pvs = [_fqpvname(pdev) for pdev in _normalizeargs(devices)]
_checkpvsblksize(pvs, getVGBlockSizes(vgName))
vg = _lvminfo.getVg(vgName)
+
+ member_pvs = set(vg.pv_name).intersection(pvs)
+ if member_pvs:
+ log.error("Cannot extend vg %s: pvs already belong to vg %s",
+ vg.name, member_pvs)
+ raise se.VolumeGroupExtendError(vgName, pvs)
+
# Format extension PVs as all the other already in the VG
_initpvs(pvs, int(vg.vg_mda_size) / 2 ** 20, force)
--
To view, visit https://gerrit.ovirt.org/46651
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifec2503094d6a0ecdd32e5e62f9c01a1469145f3
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5
Gerrit-Owner: Freddy Rolland <frolland(a)redhat.com>
Gerrit-Reviewer: Allon Mureinik <amureini(a)redhat.com>
Gerrit-Reviewer: Fred Rolland <frolland(a)redhat.com>
Hello Dan Kenigsberg,
I'd like you to do a code review. Please visit
https://gerrit.ovirt.org/43149
to review the following change.
Change subject: network: allow custom bondOption
......................................................................
network: allow custom bondOption
Allow 'custom' in bond options. This value will be accepted by
Bond.validateOptions method but it will not be passed to configurator.
Thanks to this patch, users will be allowed to pass custom properties
to setupNetworks hooks.
This path was reverted in past because of malfunction, now it should
work, there is a new test for sure.
Change-Id: I9ace532d959bc3195a8a92b4536bdc0062bc7d1d
Signed-off-by: Petr Horáček <phoracek(a)redhat.com>
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1234867
Reviewed-on: https://gerrit.ovirt.org/40882
Reviewed-by: Dan Kenigsberg <danken(a)redhat.com>
Continuous-Integration: Dan Kenigsberg <danken(a)redhat.com>
---
M lib/vdsm/netinfo.py
M tests/functional/networkTests.py
M vdsm/network/models.py
3 files changed, 37 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/49/43149/1
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 01f25c7..987a40c 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -73,8 +73,9 @@
_BONDING_FAILOVER_MODES = frozenset(('1', '3'))
_BONDING_LOADBALANCE_MODES = frozenset(('0', '2', '4', '5', '6'))
_EXCLUDED_BONDING_ENTRIES = frozenset((
- 'slaves', 'active_slave', 'mii_status', 'queue_id', 'ad_aggregator',
- 'ad_num_ports', 'ad_actor_key', 'ad_partner_key', 'ad_partner_mac'
+ 'slaves', 'active_slave', 'mii_status', 'queue_id', 'ad_aggregator',
+ 'ad_num_ports', 'ad_actor_key', 'ad_partner_key', 'ad_partner_mac',
+ 'custom'
))
_IFCFG_ZERO_SUFFIXED = frozenset(
('IPADDR0', 'GATEWAY0', 'PREFIX0', 'NETMASK0'))
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 37979ba..3a3d6f9 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -2337,3 +2337,22 @@
self.assertNetworkDoesntExist(NETWORK_NAME)
self.assertBondDoesntExist(BONDING_NAME, [nic])
self.vdsm_net.save_config()
+
+ @cleanupNet
+ @ValidateRunningAsRoot
+ def test_setupNetworks_bond_with_custom_option(self):
+ with dummyIf(2) as nics:
+ status, msg = self.setupNetworks(
+ {},
+ {BONDING_NAME: {'nics': nics,
+ 'options': 'custom=foo mode=balance-rr'}},
+ NOCHK, test_kernel_config=False)
+ self.assertEqual(status, SUCCESS, msg)
+ self.assertBondExists(BONDING_NAME, nics)
+ opts = self.vdsm_net.config.bonds.get(BONDING_NAME).get('options')
+ self.assertEquals(opts, 'mode=balance-rr')
+
+ status, msg = self.setupNetworks(
+ {}, {BONDING_NAME: {'remove': True}}, NOCHK)
+ self.assertEqual(status, SUCCESS, msg)
+ self.assertBondDoesntExist(BONDING_NAME, nics)
diff --git a/vdsm/network/models.py b/vdsm/network/models.py
index 9608937..aacf462 100644
--- a/vdsm/network/models.py
+++ b/vdsm/network/models.py
@@ -235,9 +235,23 @@
_netinfo=_netinfo))
return slaves
+ @staticmethod
+ def remove_custom_option(options):
+ """ 'custom' property should not be exposed to configurator, it is
+ only for purpose of hooks """
+ d_opts = dict(opt.split('=', 1) for opt in options.split())
+ if d_opts.pop('custom', None) is not None:
+ options = ' '.join(['%s=%s' % (key, value)
+ for key, value in d_opts.items()])
+ return options
+
@classmethod
def objectivize(cls, name, configurator, options, nics, mtu, _netinfo,
destroyOnMasterRemoval=None):
+
+ if options:
+ options = cls.remove_custom_option(options)
+
if nics: # New bonding or edit bonding.
slaves = cls._objectivizeSlaves(name, configurator, _nicSort(nics),
mtu, _netinfo)
@@ -299,7 +313,7 @@
for option in bondingOptions.split():
key, _ = option.split('=', 1)
- if key not in defaults:
+ if key not in defaults and key != 'custom':
raise ConfigNetworkError(ne.ERR_BAD_BONDING, '%r is not a '
'valid bonding option' % key)
--
To view, visit https://gerrit.ovirt.org/43149
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9ace532d959bc3195a8a92b4536bdc0062bc7d1d
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5
Gerrit-Owner: Petr Horáček <phoracek(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>