Change in vdsm[master]: virt: migration: use contextmanager for monitor
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: virt: migration: use contextmanager for monitor
......................................................................
virt: migration: use contextmanager for monitor
This patch factors the MigrationMonitorThread
control in a context manager to make code
clearer and less cluttered.
Change-Id: Ie7fcd0bedf4f30cc0bcab03339322df1fc5434e8
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M vdsm/migration.py
1 file changed, 13 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/78/25978/1
diff --git a/vdsm/migration.py b/vdsm/migration.py
index 8c33f1e..73d29e8 100644
--- a/vdsm/migration.py
+++ b/vdsm/migration.py
@@ -18,6 +18,7 @@
# Refer to the README and COPYING files for full details of the license
#
+from contextlib import contextmanager
import pickle
import threading
import time
@@ -255,6 +256,17 @@
self._recover(str(e))
self.log.error("Failed to migrate", exc_info=True)
+ @contextmanager
+ def migrationMonitor(self, startTime):
+ self._monitorThread = MigrationMonitorThread(self._vm,
+ startTime,
+ int(self._downtime))
+ self._monitorThread.start()
+ try:
+ yield
+ finally:
+ self._monitorThread.stop()
+
def _startUnderlyingMigration(self, startTime):
if self._mode == 'file':
hooks.before_vm_hibernate(self._vm._dom.XMLDesc(0), self._vm.conf)
@@ -293,12 +305,7 @@
self._vm.log.debug('starting migration to %s '
'with miguri %s', duri, muri)
- self._monitorThread = MigrationMonitorThread(self._vm,
- startTime,
- int(self._downtime))
- self._monitorThread.start()
-
- try:
+ with self.migrationMonitor(startTime):
if ('qxl' in self._vm.conf['display'] and
self._vm.conf.get('clientIp')):
SPICE_MIGRATION_HANDOVER_TIME = 120
@@ -322,9 +329,6 @@
None, maxBandwidth)
else:
self._raiseAbortError()
-
- finally:
- self._monitorThread.stop()
def stop(self):
# if its locks we are before the migrateToURI2()
--
To view, visit http://gerrit.ovirt.org/25978
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie7fcd0bedf4f30cc0bcab03339322df1fc5434e8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
9 years, 10 months
Change in vdsm[master]: network: Reset bonding options we did not modify to defaults...
by osvoboda@redhat.com
Ondřej Svoboda has uploaded a new change for review.
Change subject: network: Reset bonding options we did not modify to defaults (WIP)
......................................................................
network: Reset bonding options we did not modify to defaults (WIP)
This is an attempt to have bonds configured with exactly
the options that were requested.
The handling of mode 4 options (if they are options at all?)
is yet to be investigated. I suspect the also belong to the set
of run-time values we should not even report as bonding options.
Change-Id: I884b7436e12df9dc8572694f886a3c7eb32de200
Bug-Url: https://bugzilla.redhat.com/987813
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M vdsm/network/models.py
1 file changed, 37 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/74/26374/1
diff --git a/vdsm/network/models.py b/vdsm/network/models.py
index ced0a30..a44c24c 100644
--- a/vdsm/network/models.py
+++ b/vdsm/network/models.py
@@ -190,6 +190,41 @@
def __repr__(self):
return 'Bond(%s: %r)' % (self.name, self.slaves)
+ def _confOptions(self):
+ return [option.split('=', 1) for option in self.options.split(' ')]
+
+ def replaceCurrentOptsWithDefaults(self):
+ '''
+ Any active non-default value not touched by options being currently
+ set is added so it is explicitly reset to its default.
+
+ This is intended to make sure no other options than those we modified
+ have non-default values.
+ '''
+ activeOpts = netinfo._getBondingOptions(self.name)
+
+ defaults, defaultMode = netinfo._getDefaultBondingOptions()
+ mode = (activeOpts['mode'][-1] if 'mode' in activeOpts
+ else defaultMode[-1])
+ defaults = defaults[mode]
+
+ confOpts = dict(self._confOptions())
+
+ for key in activeOpts:
+ if key not in confOpts:
+ logging.error('Clearing pre-existing non-default %s option'
+ ' (%s=%s)', self.name, key, activeOpts[key])
+
+ if key in defaults:
+ activeOpts[key] = defaults[key][-1]
+ else:
+ logging.error('No default value found! '
+ 'The mode is %s.', mode)
+ activeOpts[key] = ''
+
+ activeOpts.update(confOpts)
+ return netinfo._bondOptsForIfcfg(activeOpts)
+
def configure(self, **opts):
# When the bond is up and we are not changing the configuration that
# is already applied in any way, we can skip the configuring.
@@ -203,10 +238,11 @@
frozenset(netinfo.slaves(self.name))):
return
+ self.options = self.resetUnwantedOptions()
self.configurator.configureBond(self, **opts)
def areOptionsApplied(self):
- confOpts = [option.split('=', 1) for option in self.options.split(' ')]
+ confOpts = self._confOpts()
activeOpts = netinfo.bondOpts(self.name,
(name for name, value in confOpts))
return all(value in activeOpts[name] for name, value in confOpts)
--
To view, visit http://gerrit.ovirt.org/26374
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I884b7436e12df9dc8572694f886a3c7eb32de200
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: sd: fix volume path returned by linkBCImage
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: sd: fix volume path returned by linkBCImage
......................................................................
sd: fix volume path returned by linkBCImage
In a previous commit (c072945 One shot prepare) we involuntarily
changed the path used for virtual machine images from:
/rhev/data-center/<spUUID>/<sdUUID>/images/<imgUUID>/<volUUID>
to:
/rhev/data-center/mnt/blockSD/<sdUUID>/images/<imgUUID>/<volUUID>
This patch reverts to the previous path in order to minimize the
differences between different versions of vdsm that could lead to
live migration issues, e.g.
libvirtError: invalid argument: invalid path ... not assigned to
domain
Change-Id: Iea497b574d9a9a7e0e9b8e234e2bd9b9d983a60c
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1059482
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/blockSD.py
M vdsm/storage/fileSD.py
M vdsm/storage/sd.py
3 files changed, 8 insertions(+), 4 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/15/24315/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 5179c5a..587e617 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -1053,8 +1053,7 @@
return rems
def linkBCImage(self, imgPath, imgUUID):
- dst = os.path.join(self.mountpoint, self.sdUUID, sd.DOMAIN_IMAGES,
- imgUUID)
+ dst = self.getLinkBCImagePath(imgUUID)
try:
os.symlink(imgPath, dst)
except OSError as e:
diff --git a/vdsm/storage/fileSD.py b/vdsm/storage/fileSD.py
index 180a43f..0f52718 100644
--- a/vdsm/storage/fileSD.py
+++ b/vdsm/storage/fileSD.py
@@ -422,8 +422,8 @@
for k, v in volumes.iteritems())
def linkBCImage(self, imgPath, imgUUID):
- return os.path.join(self.mountpoint, self.sdUUID, sd.DOMAIN_IMAGES,
- imgUUID)
+ # Nothing to do here other than returning the path
+ return self.getLinkBCImagePath(imgUUID)
def createImageLinks(self, srcImgPath, imgUUID):
"""
diff --git a/vdsm/storage/sd.py b/vdsm/storage/sd.py
index c9738e0..fd4c9db 100644
--- a/vdsm/storage/sd.py
+++ b/vdsm/storage/sd.py
@@ -25,6 +25,7 @@
from collections import namedtuple
import codecs
+import image
import storage_exception as se
import misc
import resourceFactories
@@ -643,6 +644,10 @@
# If it has a repo we don't have multiple domains. Assume single pool
return os.path.join(self.storage_repository, self.getPools()[0])
+ def getLinkBCImagePath(self, imgUUID):
+ return image.Image(self._getRepoPath()) \
+ .getImageDir(self.sdUUID, imgUUID)
+
def getIsoDomainImagesDir(self):
"""
Get 'images' directory from Iso domain
--
To view, visit http://gerrit.ovirt.org/24315
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iea497b574d9a9a7e0e9b8e234e2bd9b9d983a60c
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: vdsm-tool: Change upgrade mechanism
by dkuznets@redhat.com
Dima Kuznetsov has uploaded a new change for review.
Change subject: vdsm-tool: Change upgrade mechanism
......................................................................
vdsm-tool: Change upgrade mechanism
The upgrade decorator is a mechanism within vdsm-tool to allow commands
to only run once. It has flags to override, but being a function
decorator, it did not have any direct access to command line arguments
and did access via sys.argv[2:].
There is a patch that will be sent that will add flags to vdsm-tool and
will make break upgrade and its argument parsing. I'm proposing to
change the upgrade from being a decorated function, to a class deriving
from Upgrade with apply() method. This way args can be passed to the
upgrade code (via ctor), and deriving class and extend the argument
parser, this way, we'll also get a nice usage for upgrade commands:
$ vdsm-tool some-upgrade --help
Usage:
vdsm-tool [...]
Options:
[general upgrade options, e.g. --run-again]
[specific upgrade options]
Change-Id: I6e1d28570dedfeff9fe60624b1db72d8cadf136a
Signed-off-by: Dima Kuznetsov <dkuznets(a)redhat.com>
---
M lib/vdsm/tool/unified_persistence.py
M lib/vdsm/tool/upgrade.py
M lib/vdsm/tool/upgrade_300_networks.py
3 files changed, 61 insertions(+), 114 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/93/27193/1
diff --git a/lib/vdsm/tool/unified_persistence.py b/lib/vdsm/tool/unified_persistence.py
index 3d4c8ab..10cdc41 100644
--- a/lib/vdsm/tool/unified_persistence.py
+++ b/lib/vdsm/tool/unified_persistence.py
@@ -23,7 +23,7 @@
from ..netconfpersistence import RunningConfig
from ..netinfo import NetInfo, getIfaceCfg, getDefaultGateway
from . import expose
-from .upgrade import upgrade
+from .upgrade import Upgrade
UPGRADE_NAME = 'upgrade-unified-persistence'
@@ -36,7 +36,6 @@
# bootproto = 'dhcp' if there's a lease on the NIC at the moment of upgrade
-@upgrade(UPGRADE_NAME)
def run():
networks, bondings = _getNetInfo()
logging.debug('%s upgrade persisting networks %s and bondings %s',
@@ -156,6 +155,13 @@
return config.get('vars', 'net_persistence') == 'unified'
+class UpgradeUnifiedPersistence(Upgrade):
+ def run(self):
+ if isNeeded():
+ run()
+ return 0
+
+
@expose(UPGRADE_NAME)
def unified_persistence(*args):
"""
@@ -164,6 +170,4 @@
persistence model is set as unified in /usr/lib64/python2.X/site-packages/
vdsm/config.py
"""
- if isNeeded():
- return run()
- return 0
+ return UpgradeUnifiedPersistence(*args).apply()
diff --git a/lib/vdsm/tool/upgrade.py b/lib/vdsm/tool/upgrade.py
index 2e19701..822a24d 100644
--- a/lib/vdsm/tool/upgrade.py
+++ b/lib/vdsm/tool/upgrade.py
@@ -18,58 +18,31 @@
#
import argparse
-from functools import wraps
import logging
import logging.config
-from logging.handlers import SysLogHandler
import os
-import sys
-from ..constants import (P_VDSM_LOG, P_VDSM_LIB, P_VDSM_CONF, VDSM_USER,
- VDSM_GROUP)
+from ..constants import P_VDSM_LIB
from ..utils import touchFile
-
-sys.path.append("/usr/share/vdsm")
-from storage.fileUtils import chown
class Upgrade(object):
"""
- Code that needs to be run exactly once can use this class as
- a general, simplistic mechanism. Usage:
+ This is a parent class to define upgrades, it defines its own argument
+ parser and allows any subclass extend it, the subclass is to define run()
+ method that will be called if needed upon upgrade.apply().
- with Upgrade('someUpgrade') as upgrade:
- if upgrade.isNeeded():
- runSomeCode()
- upgrade.seal()
-
- Upgrade as a context manager automatically redirects logging
- to the upgrade log. It also supplies the isNeeded and seal methods.
- To call isNeeded and seal automatically use this module's upgrade
- decorator.
+ upgrade.apply() parses the arguments, checks if upgrade should run,
+ and upon successful completion calls upgrade.seal() that marks upgrade as
+ done, to avoid executing it again.
"""
- def __init__(self, upgradeName):
+ def __init__(self, upgradeName, *args):
self._upgradeName = upgradeName
self._upgradeFilePath = os.path.join(P_VDSM_LIB,
'upgrade', self._upgradeName)
- try:
- # First load normal VDSM loggers, then the upgrade logger.
- # This will override VDSM's root logger but will keep the other
- # loggers intact. During an upgrade we add the update handler
- # to all loggers.
- logging.config.fileConfig(P_VDSM_CONF + 'logger.conf',
- disable_existing_loggers=False)
- logging.config.fileConfig(P_VDSM_CONF + 'upgrade.logger.conf',
- disable_existing_loggers=False)
- chown(
- os.path.join(P_VDSM_LOG, 'upgrade.log'),
- VDSM_USER,
- VDSM_GROUP)
- except Exception:
- logging.getLogger('upgrade').addHandler(SysLogHandler('/dev/log'))
- logging.exception("Could not init proper logging")
- finally:
- self.log = logging.getLogger('upgrade')
+ self.log = logging.getLogger('upgrade')
+ self._arg_parser = self._upgrade_argparser()
+ self._args = args
def isNeeded(self):
return not os.path.exists(self._upgradeFilePath)
@@ -86,72 +59,32 @@
self.log.debug("Upgrade %s successfully performed",
self._upgradeName)
- def _attachUpgradeLog(self):
- self._editOtherLoggers(logging.Logger.addHandler)
+ def _upgrade_argparser(self):
+ parser = argparse.ArgumentParser('vdsm-tool %s' % self._upgradeName)
+ parser.add_argument(
+ '--run-again',
+ dest='runAgain',
+ default=False,
+ action='store_true',
+ help='Run the upgrade again, even if it was ran before',
+ )
+ return parser
- def _detachUpgradeLog(self):
- self._editOtherLoggers(logging.Logger.removeHandler)
+ def run(self):
+ pass
- def _editOtherLoggers(self, edit):
- """
- add/remove upgrade handler to/from all non-upgrade loggers
- """
- loggers = dict(logging.Logger.manager.loggerDict.items() +
- [('root', logging.getLogger())])
- for name, logger in loggers.iteritems():
- if name != 'upgrade':
- for handler in logging.getLogger('upgrade').handlers:
- try:
- edit(logger, handler) # Call logger.edit(handler)
- except TypeError:
- pass
-
- def __enter__(self):
- """
- All logging will *also* be output to the upgrade log during
- the scope of this Upgrade.
- """
- self._attachUpgradeLog()
- return self
-
- def __exit__(self, type, value, traceback):
- self._detachUpgradeLog()
-
-
-def _parse_args(upgradeName):
- parser = argparse.ArgumentParser('vdsm-tool %s' % upgradeName)
- parser.add_argument(
- '--run-again',
- dest='runAgain',
- default=False,
- action='store_true',
- help='Run the upgrade again, even if it was ran before',
- )
- return parser.parse_args(sys.argv[2:])
-
-
-def upgrade(upgradeName):
- """
- Used as a decorator for upgrades. Runs the upgrade with an Upgrade
- context manager (documented above). Automatically calls isNeeded and seal
- as needed.
- """
- def decorator(f):
- @wraps(f)
- def wrapper(*args, **kwargs):
- with Upgrade(upgradeName) as upgrade:
- cliArguments = _parse_args(upgradeName)
- if cliArguments.runAgain or upgrade.isNeeded():
- upgrade.log.debug("Running upgrade %s", upgradeName)
- try:
- f(*args, **kwargs)
- except Exception:
- upgrade.log.exception("Failed to run %s",
- upgradeName)
- return 1
- else:
- upgrade.seal()
-
- return 0
- return wrapper
- return decorator
+ def apply(self):
+ res = self._arg_parser.parse_known_args(self._args)
+ self._parsed_ns = res[0]
+ self._parsed_args = res[1]
+ if self.isNeeded() or self._parsed_ns.runAgain:
+ self.log.debug("Running upgrade %s", self._upgradeName)
+ try:
+ self.run()
+ except Exception:
+ self.log.exception("Failed to run %s",
+ self._upgradeName)
+ return 1
+ else:
+ self.seal()
+ return 0
diff --git a/lib/vdsm/tool/upgrade_300_networks.py b/lib/vdsm/tool/upgrade_300_networks.py
index 95d4e17..250b04d 100644
--- a/lib/vdsm/tool/upgrade_300_networks.py
+++ b/lib/vdsm/tool/upgrade_300_networks.py
@@ -24,7 +24,7 @@
from vdsm import netinfo
from vdsm.constants import LEGACY_MANAGEMENT_NETWORKS
from vdsm.tool import expose
-from vdsm.tool.upgrade import upgrade
+from vdsm.tool.upgrade import Upgrade
sys.path.append("/usr/share/vdsm")
from network.configurators import ifcfg
@@ -42,7 +42,6 @@
return not managementNetwork() and managementBridge()
-@upgrade(UPGRADE_NAME)
def run(networks, bridges):
configWriter = ifcfg.ConfigWriter()
@@ -61,6 +60,18 @@
configWriter.removeLibvirtNetwork(network, skipBackup=True)
+class Upgrade300Networks(Upgrade):
+ def __init__(self, networks, bridges, *args):
+ Upgrade.__init__(self, *args)
+ self._networks = networks
+ self._bridges = bridges
+
+ def run(self):
+ if isNeeded(self._networks, self._bridges):
+ run(self._networks, self._bridges)
+ return 0
+
+
@expose(UPGRADE_NAME)
def upgrade_networks(*args):
"""
@@ -73,5 +84,4 @@
networks = netinfo.networks()
bridges = netinfo.bridges()
- if isNeeded(networks, bridges):
- run(networks, bridges)
+ return Upgrade300Networks(networks, bridges, *args).apply()
--
To view, visit http://gerrit.ovirt.org/27193
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6e1d28570dedfeff9fe60624b1db72d8cadf136a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dima Kuznetsov <dkuznets(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: Adding skiptests for LibvirtModuleConfigureTests
by ybronhei@redhat.com
Yaniv Bronhaim has uploaded a new change for review.
Change subject: Adding skiptests for LibvirtModuleConfigureTests
......................................................................
Adding skiptests for LibvirtModuleConfigureTests
We're getting repeated segmentation fault on jenkins job. Until solving
the issue, keeping branch tests stable.
Change-Id: I95cb5178af8f718dd3f0a1d72e74962a898983a6
Signed-off-by: Yaniv Bronhaim <ybronhei(a)redhat.com>
---
M tests/toolTests.py
1 file changed, 7 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/75/26775/1
diff --git a/tests/toolTests.py b/tests/toolTests.py
index 2fc8c61..86197ac 100644
--- a/tests/toolTests.py
+++ b/tests/toolTests.py
@@ -21,6 +21,7 @@
from vdsm import utils
import monkeypatch
from unittest import TestCase
+from nose.plugins.skip import SkipTest
import tempfile
import os
@@ -160,6 +161,9 @@
self.assertFalse(libvirtConfigure.isconfigured())
def testLibvirtConfigureToSSLTrue(self):
+ # skip test after getting repeated seg fault in jenkins jobs
+ raise SkipTest("Skipping failed test")
+
libvirtConfigure = configurator.LibvirtModuleConfigure(test_env)
self._setConfig('LCONF', 'empty')
self._setConfig('VDSM_CONF_FILE', 'withssl')
@@ -168,6 +172,9 @@
self.assertTrue(libvirtConfigure.isconfigured())
def testLibvirtConfigureToSSLFalse(self):
+ # skip test after getting repeated seg fault in jenkins jobs
+ raise SkipTest("Skipping failed test")
+
libvirtConfigure = configurator.LibvirtModuleConfigure(test_env)
self._setConfig('LCONF', 'empty')
self._setConfig('VDSM_CONF_FILE', 'withnossl')
--
To view, visit http://gerrit.ovirt.org/26775
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I95cb5178af8f718dd3f0a1d72e74962a898983a6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yaniv Bronhaim <ybronhei(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: WIP virt: use (c)ElementTree to process XML
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: WIP virt: use (c)ElementTree to process XML
......................................................................
WIP virt: use (c)ElementTree to process XML
this let the virt internal machinery to use (c)ElementTree
instead of minidom. The main driver is performance,
however a nice side effects is the API is a little bit nicer.
This patch is still very much Work In Progress and still
needs quite a lot of polishing and, most likely, to be
split up.
Change-Id: I7874026acf52b869b8329f433d5833530e0d02e0
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/compat.py
M tests/vmTests.py
M vdsm/virt/vm.py
M vdsm/virt/xmldom.py
4 files changed, 226 insertions(+), 282 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/56/26856/1
diff --git a/lib/vdsm/compat.py b/lib/vdsm/compat.py
index 26c558e..a59a034 100644
--- a/lib/vdsm/compat.py
+++ b/lib/vdsm/compat.py
@@ -24,3 +24,10 @@
except ImportError: # py3
import pickle
pickle # yep, this is needed twice.
+
+try:
+ import xml.etree.cElementTree as ET
+ ET # make pyflakes happy
+except ImportError: # py3
+ import xml.etree.ElementTree as ET
+ ET # once again, needed twice.
diff --git a/tests/vmTests.py b/tests/vmTests.py
index d655286..20b1007 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -61,36 +61,43 @@
def assertXML(self, element, expectedXML, path=None):
if path is None:
- converted = element.toprettyxml()
+ converted = ET.tostring(element, encoding='utf-8', method='xml')
else:
- elem = ET.fromstring(element.toprettyxml())
- converted = re.sub(' />', '/>',
- ET.tostring(elem.find("./%s" % path)))
- self.assertEqual(re.sub('\n\s*', ' ', converted).strip(' '),
- re.sub('\n\s*', ' ', expectedXML).strip(' '))
+ converted = ET.tostring(element.find("./%s" % path))
+ self._assertEqualXML(converted, expectedXML)
- def assertXMLNone(self, element, path):
- elem = ET.fromstring(element.toprettyxml())
- converted = elem.find("./%s" % path)
- self.assertEqual(converted, None)
+ def _minimizeXML(self, xml):
+ xml = xml.strip()
+ xml = re.sub('\n\s*', ' ', xml)
+ xml = re.sub(' />', '/>', xml)
+ xml = re.sub('>\s*', '>', xml)
+ return xml
+
+ def _assertEqualXML(self, output, expected):
+ out = self._minimizeXML(output)
+ exp = self._minimizeXML(expected)
+ if out != exp:
+ for i, pair in enumerate(zip(out, exp)):
+ if pair[0] != pair[-1]:
+ caret = '%s^' % ('-' * i)
+ break
+ print out
+ print exp
+ print caret
+ self.assertEqual(out, exp)
def assertBuildCmdLine(self, confToDom):
- oldVdsmRun = constants.P_VDSM_RUN
- constants.P_VDSM_RUN = tempfile.mkdtemp()
- try:
- for conf, expectedXML in confToDom:
+ with namedTemporaryDir() as tmpDir:
+ with MonkeyPatchScope([(constants, 'P_VDSM_RUN', tmpDir + '/')]):
+ for conf, expectedXML in confToDom:
- expectedXML = expectedXML % conf
+ expectedXML = expectedXML % conf
- testVm = vm.Vm(self, conf)
+ testVm = vm.Vm(self, conf)
- output = testVm._buildCmdLine()
+ output = testVm._buildCmdLine()
- self.assertEqual(re.sub('\n\s*', ' ', output.strip(' ')),
- re.sub('\n\s*', ' ', expectedXML.strip(' ')))
- finally:
- shutil.rmtree(constants.P_VDSM_RUN)
- constants.P_VDSM_RUN = oldVdsmRun
+ self._assertEqualXML(output, expectedXML)
def testDomXML(self):
expectedXML = """
@@ -519,10 +526,11 @@
'custom': {'queues': '7'}}
self.conf['custom'] = {'vhost': 'ovirtmgmt:true', 'sndbuf': '0'}
iface = vm.NetworkInterfaceDevice(self.conf, self.log, **dev)
- originalBandwidth = iface.getXML().getElementsByTagName('bandwidth')[0]
+ originalBandwidth = iface.getXML().find('bandwidth')
self.assertXML(originalBandwidth, originalBwidthXML)
- self.assertXML(iface.paramsToBandwidthXML(NEW_OUT, originalBandwidth),
- updatedBwidthXML)
+ updatedBandwidth = iface.paramsToBandwidthXML(
+ NEW_OUT, originalBandwidth)
+ self.assertXML(updatedBandwidth, updatedBwidthXML)
def testControllerXML(self):
devConfs = [
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index a68f101..75924b3 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -484,7 +484,7 @@
ctrl = self.createXmlElem('controller', self.device,
['index', 'model', 'master', 'address'])
if self.device == 'virtio-serial':
- ctrl.setAttrs(index='0', ports='16')
+ xmldom.setattrs(ctrl, index='0', ports='16')
return ctrl
@@ -502,7 +502,7 @@
if 'ram' in self.specParams:
sourceAttrs['ram'] = self.specParams['ram']
- video.appendChildWithArgs('model', type=self.device, **sourceAttrs)
+ xmldom.appendElement(video, 'model', type=self.device, **sourceAttrs)
return video
@@ -514,7 +514,7 @@
Create domxml for sound device
"""
sound = self.createXmlElem('sound', None, ['address'])
- sound.setAttrs(model=self.device)
+ sound.set('model', self.device)
return sound
@@ -588,46 +588,48 @@
</interface>
"""
iface = self.createXmlElem('interface', self.device, ['address'])
- iface.appendChildWithArgs('mac', address=self.macAddr)
- iface.appendChildWithArgs('model', type=self.nicModel)
- iface.appendChildWithArgs('source', bridge=self.network)
+ xmldom.appendElement(iface, 'mac', address=self.macAddr)
+ xmldom.appendElement(iface, 'model', type=self.nicModel)
+ xmldom.appendElement(iface, 'source', bridge=self.network)
if hasattr(self, 'filter'):
- iface.appendChildWithArgs('filterref', filter=self.filter)
+ xmldom.appendElement(iface, 'filterref', filter=self.filter)
if hasattr(self, 'linkActive'):
- iface.appendChildWithArgs('link', state='up'
- if utils.tobool(self.linkActive)
- else 'down')
+ xmldom.appendElement(iface, 'link',
+ state='up'
+ if utils.tobool(self.linkActive)
+ else 'down')
if hasattr(self, 'bootOrder'):
- iface.appendChildWithArgs('boot', order=self.bootOrder)
+ xmldom.appendElement(iface, 'boot', order=self.bootOrder)
if self.driver:
- iface.appendChildWithArgs('driver', **self.driver)
+ xmldom.appendElement(iface, 'driver', self.driver)
if self.sndbufParam:
- tune = iface.appendChildWithArgs('tune')
- tune.appendChildWithArgs('sndbuf', text=self.sndbufParam)
+ tune = xmldom.appendElement(iface, 'tune')
+ xmldom.appendElement(tune, 'sndbuf').text=self.sndbufParam
if hasattr(self, 'specParams'):
if 'inbound' in self.specParams or 'outbound' in self.specParams:
- iface.appendChild(self.paramsToBandwidthXML(self.specParams))
+ iface.append(self.paramsToBandwidthXML(self.specParams))
return iface
def paramsToBandwidthXML(self, specParams, oldBandwidth=None):
"""Returns a valid libvirt xml dom element object."""
bandwidth = self.createXmlElem('bandwidth', None)
- old = {} if oldBandwidth is None else dict(
- (elem.nodeName, elem) for elem in oldBandwidth.childNodes)
+ if oldBandwidth is None:
+ oldBandwidth = xmldom.Element('bandwidth')
for key in ('inbound', 'outbound'):
elem = specParams.get(key)
if elem is None: # Use the old setting if present
- if key in old:
- bandwidth.appendChild(old[key])
+ value = oldBandwidth.find(key)
+ if value is not None:
+ bandwidth.append(value)
elif elem:
# Convert the values to string for adding them to the XML def
attrs = dict((key, str(value)) for key, value in elem.items())
- bandwidth.appendChildWithArgs(key, **attrs)
+ xmldom.appendElement(bandwidth, key, attrs)
return bandwidth
@@ -836,12 +838,13 @@
# when libvirt will support shared leases this will loop over all the
# volumes
for volInfo in self.volumeChain[-1:]:
- lease = xmldom.XMLElement('lease')
- lease.appendChildWithArgs('key', text=volInfo['volumeID'])
- lease.appendChildWithArgs('lockspace',
- text=volInfo['domainID'])
- lease.appendChildWithArgs('target', path=volInfo['leasePath'],
- offset=str(volInfo['leaseOffset']))
+ lease = xmldom.Element('lease')
+ xmldom.appendElement(lease, 'key').text=volInfo['volumeID']
+ xmldom.appendElement(lease, 'lockspace').text=\
+ text=volInfo['domainID']
+ xmldom.appendElement(lease, 'target',
+ path=volInfo['leasePath'],
+ offset=str(volInfo['leaseOffset']))
yield lease
def getXML(self):
@@ -857,42 +860,43 @@
"""
self.device = getattr(self, 'device', 'disk')
- source = xmldom.XMLElement('source')
+ source = xmldom.Element('source')
if self.blockDev:
deviceType = 'block'
- source.setAttrs(dev=self.path)
+ source.set('dev', self.path)
elif self.networkDev:
deviceType = 'network'
- source.setAttrs(protocol=self.volumeInfo['protocol'],
+ xmldom.setattrs(source,
+ 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)
+ xmldom.appendElement(source, 'host', hostAttrs)
else:
deviceType = 'file'
sourceAttrs = {'file': self.path}
if self.device == 'cdrom' or self.device == 'floppy':
sourceAttrs['startupPolicy'] = 'optional'
- source.setAttrs(**sourceAttrs)
+ xmldom.setattrs(source, sourceAttrs)
diskelem = self.createXmlElem('disk', deviceType,
['device', 'address', 'sgio'])
- diskelem.setAttrs(snapshot='no')
- diskelem.appendChild(source)
+ diskelem.set('snapshot', 'no')
+ diskelem.append(source)
targetAttrs = {'dev': self.name}
if self.iface:
targetAttrs['bus'] = self.iface
- diskelem.appendChildWithArgs('target', **targetAttrs)
+ xmldom.appendElement(diskelem, 'target', targetAttrs)
if self.extSharedState == DRIVE_SHARED_TYPE.SHARED:
- diskelem.appendChildWithArgs('shareable')
+ xmldom.appendElement(diskelem, 'shareable')
if hasattr(self, 'readonly') and utils.tobool(self.readonly):
- diskelem.appendChildWithArgs('readonly')
+ xmldom.appendElement(diskelem, 'readonly')
if hasattr(self, 'serial'):
- diskelem.appendChildWithArgs('serial', text=self.serial)
+ xmldom.appendElement(diskelem, 'serial').text=self.serial
if hasattr(self, 'bootOrder'):
- diskelem.appendChildWithArgs('boot', order=self.bootOrder)
+ xmldom.appendElement(diskelem, 'boot', order=self.bootOrder)
if self.device != 'lun' and hasattr(self, 'sgio'):
raise ValueError("sgio attribute can be set only for LUN devices")
@@ -918,19 +922,18 @@
driverAttrs['error_policy'] = 'enospace'
else:
driverAttrs['error_policy'] = 'stop'
- diskelem.appendChildWithArgs('driver', **driverAttrs)
+ xmldom.appendElement(diskelem, 'driver', driverAttrs)
elif self.device == 'floppy':
if (self.path and
not utils.getUserPermissions(constants.QEMU_PROCESS_USER,
self.path)['write']):
- diskelem.appendChildWithArgs('readonly')
+ xmldom.appendElement(diskelem, 'readonly')
if hasattr(self, 'specParams') and 'ioTune' in self.specParams:
self._validateIoTuneParams()
- iotune = xmldom.XMLElement('iotune')
+ iotune = xmldom.appendElement(diskelem, 'iotune')
for key, value in self.specParams['ioTune'].iteritems():
- iotune.appendChildWithArgs(key, text=str(value))
- diskelem.appendChild(iotune)
+ xmldom.appendElement(iotune, key).text=str(value)
return diskelem
@@ -947,9 +950,8 @@
function='0x0'/>
</memballoon>
"""
- m = self.createXmlElem(self.device, None, ['address'])
- m.setAttrs(model=self.specParams['model'])
- return m
+ balloon = self.createXmlElem(self.device, None, ['address'])
+ return xmldom.setattrs(balloon, model=self.specParams['model'])
class WatchdogDevice(VmDevice):
@@ -970,10 +972,10 @@
function='0x0'/>
</watchdog>
"""
- m = self.createXmlElem(self.type, None, ['address'])
- m.setAttrs(model=self.specParams.get('model', 'i6300esb'),
- action=self.specParams.get('action', 'none'))
- return m
+ dev = self.createXmlElem(self.type, None, ['address'])
+ return xmldom.setattrs(dev,
+ model=self.specParams.get('model', 'i6300esb'),
+ action=self.specParams.get('action', 'none'))
class SmartCardDevice(VmDevice):
@@ -991,8 +993,7 @@
sourceAttrs = {'mode': self.specParams['mode']}
if sourceAttrs['mode'] != 'host':
sourceAttrs['type'] = self.specParams['type']
- card.setAttrs(**sourceAttrs)
- return card
+ return xmldom.setattrs(card, sourceAttrs)
class TpmDevice(VmDevice):
@@ -1009,11 +1010,11 @@
</tpm>
"""
tpm = self.createXmlElem(self.device, None)
- tpm.setAttrs(model=self.specParams['model'])
- backend = tpm.appendChildWithArgs('backend',
+ tpm.set('model', self.specParams['model'])
+ backend = xmldom.appendElement(tpm, 'backend',
type=self.specParams['mode'])
- backend.appendChildWithArgs('device',
- path=self.specParams['path'])
+ xmldom.appendElement(backend, 'device',
+ path=self.specParams['path'])
return tpm
@@ -1047,12 +1048,11 @@
if 'period' in self.specParams:
rateAttrs['period'] = self.specParams['period']
- rng.appendChildWithArgs('rate', None, **rateAttrs)
+ xmldom.appendElement(rng, 'rate', rateAttrs)
# <backend... /> element
- rng.appendChildWithArgs('backend',
- caps.RNG_SOURCES[self.specParams['source']],
- model='random')
+ xmldom.appendElement(rng, 'backend', model='random').text=\
+ caps.RNG_SOURCES[self.specParams['source']]
return rng
@@ -1065,12 +1065,12 @@
Create domxml for a console device.
<console type='pty'>
- <target type='virtio' port='0'/>
+ <target type='irtio' port='0'/>
</console>
"""
- m = self.createXmlElem('console', 'pty')
- m.appendChildWithArgs('target', type='virtio', port='0')
- return m
+ console = self.createXmlElem('console', 'pty')
+ xmldom.appendElement(console, 'target', type='virtio', port='0')
+ return console
class MigrationError(Exception):
@@ -2134,14 +2134,15 @@
for devType in self._devices:
for dev in self._devices[devType]:
- deviceXML = dev.getXML().toxml(encoding='utf-8')
+ xmlDev = dev.getXML()
+ deviceXML = dev.toXML()
if getattr(dev, "custom", {}):
deviceXML = hooks.before_device_create(
deviceXML, self.conf, dev.custom)
dev._deviceXML = deviceXML
- domxml._devices.appendChild(xmldom.parse(deviceXML).firstChild)
+ domxml._devices.append(xmlDev)
def _buildCmdLine(self):
domxml = xmldom._DomXML(self.conf, self.log, self.arch)
@@ -2550,24 +2551,22 @@
def setLinkAndNetwork(self, dev, conf, linkValue, networkValue, custom,
specParams=None):
vnicXML = dev.getXML()
- source = vnicXML.getElementsByTagName('source')[0]
- source.setAttribute('bridge', networkValue)
- try:
- link = vnicXML.getElementsByTagName('link')[0]
- except IndexError:
- link = xmldom.XMLElement('link')
- vnicXML.appendChildWithArgs(link)
- link.setAttribute('state', linkValue)
+ source = vnicXML.find('source')
+ source.set('bridge', networkValue)
+ link = vnicXML.find('link')
+ if link is None:
+ link = xmldom.appendElement(vnicXML, 'link')
+ link.set('state', linkValue)
if (specParams and
('inbound' in specParams or 'outbound' in specParams)):
- oldBandwidths = vnicXML.getElementsByTagName('bandwidth')
- oldBandwidth = oldBandwidths[0] if len(oldBandwidths) else None
+ oldBandwidth = vnicXML.find('bandwidth')
newBandwidth = dev.paramsToBandwidthXML(specParams, oldBandwidth)
if oldBandwidth is None:
- vnicXML.appendChild(newBandwidth)
+ vnicXML.append(newBandwidth)
else:
- vnicXML.replaceChild(newBandwidth, oldBandwidth)
- vnicStrXML = vnicXML.toprettyxml(encoding='utf-8')
+ vnicXML.remove(oldBandwidth)
+ vnicXML.append(newBandwidth)
+ vnicStrXML = vnicXML.toXML()
try:
try:
vnicStrXML = hooks.before_update_device(vnicStrXML, self.conf,
@@ -2586,7 +2585,7 @@
# Rollback link and network.
self.log.debug('Rolling back link and net for: %s', dev.alias,
exc_info=True)
- self._dom.updateDeviceFlags(vnicXML.toxml(encoding='utf-8'),
+ self._dom.updateDeviceFlags(vnicXML.toXML(),
libvirt.VIR_DOMAIN_AFFECT_LIVE)
raise
else:
diff --git a/vdsm/virt/xmldom.py b/vdsm/virt/xmldom.py
index ea1387c..e15c2ca 100644
--- a/vdsm/virt/xmldom.py
+++ b/vdsm/virt/xmldom.py
@@ -25,6 +25,7 @@
import xml.dom.minidom
# vdsm imports
+from vdsm.compat import ET
from vdsm import constants
from vdsm import netinfo
from vdsm import utils
@@ -32,6 +33,10 @@
# local imports
# In future those should be imported via ..
import caps
+
+
+Element = ET.Element # FIXME
+appendElement = ET.SubElement
def is_node(xmlNode):
@@ -71,34 +76,6 @@
return self._hash or '0'
-class XMLElement(object):
-
- def __init__(self, tagName, text=None, **attrs):
- self._elem = xml.dom.minidom.Document().createElement(tagName)
- self.setAttrs(**attrs)
- if text is not None:
- self.appendTextNode(text)
-
- def __getattr__(self, name):
- return getattr(self._elem, name)
-
- def setAttrs(self, **attrs):
- for attrName, attrValue in attrs.iteritems():
- self._elem.setAttribute(attrName, attrValue)
-
- def appendTextNode(self, text):
- textNode = xml.dom.minidom.Document().createTextNode(text)
- self._elem.appendChild(textNode)
-
- def appendChild(self, element):
- self._elem.appendChild(element)
-
- def appendChildWithArgs(self, childName, text=None, **attrs):
- child = XMLElement(childName, text, **attrs)
- self._elem.appendChild(child)
- return child
-
-
class _DomXML:
def __init__(self, conf, log, arch):
"""
@@ -123,8 +100,6 @@
self.arch = arch
- self.doc = xml.dom.minidom.Document()
-
if utils.tobool(self.conf.get('kvmEnable', 'true')):
domainType = 'kvm'
else:
@@ -140,29 +115,22 @@
domainAttrs['xmlns:qemu'] = \
'http://libvirt.org/schemas/domain/qemu/1.0'
- self.dom = XMLElement('domain', **domainAttrs)
- self.doc.appendChild(self.dom)
-
- self.dom.appendChildWithArgs('name', text=self.conf['vmName'])
- self.dom.appendChildWithArgs('uuid', text=self.conf['vmId'])
+ self.dom = ET.Element('domain', domainAttrs)
+ appendElement(self.dom, 'name').text=self.conf['vmName']
+ appendElement(self.dom, 'uuid').text=self.conf['vmId']
memSizeKB = str(int(self.conf.get('memSize', '256')) * 1024)
- self.dom.appendChildWithArgs('memory', text=memSizeKB)
- self.dom.appendChildWithArgs('currentMemory', text=memSizeKB)
- vcpu = self.dom.appendChildWithArgs('vcpu', text=self._getMaxVCpus())
- vcpu.setAttrs(**{'current': self._getSmp()})
+ appendElement(self.dom, 'memory').text=memSizeKB
+ appendElement(self.dom, 'currentMemory').text=memSizeKB
+ appendElement(self.dom, 'vcpu', current=self._getSmp()).text=self._getMaxVCpus()
memSizeGuaranteedKB = str(1024 * int(
self.conf.get('memGuaranteedSize', '0')
))
- memtune = XMLElement('memtune')
- self.dom.appendChild(memtune)
+ memtune = appendElement(self.dom, 'memtune')
+ appendElement(memtune, 'min_guarantee').text=memSizeGuaranteedKB
- memtune.appendChildWithArgs('min_guarantee',
- text=memSizeGuaranteedKB)
-
- self._devices = XMLElement('devices')
- self.dom.appendChild(self._devices)
+ self._devices = appendElement(self.dom, 'devices')
def appendClock(self):
"""
@@ -173,15 +141,13 @@
</clock>
"""
- m = XMLElement('clock', offset='variable',
- adjustment=str(self.conf.get('timeOffset', 0)))
- m.appendChildWithArgs('timer', name='rtc', tickpolicy='catchup')
- m.appendChildWithArgs('timer', name='pit', tickpolicy='delay')
-
+ clock = appendElement(self.dom, 'clock',
+ offset='variable',
+ adjustment=str(self.conf.get('timeOffset', 0)))
+ appendElement(clock, 'timer', name='rtc', tickpolicy='catchup')
+ appendElement(clock, 'timer', name='pit', tickpolicy='delay')
if self.arch == caps.Architecture.X86_64:
- m.appendChildWithArgs('timer', name='hpet', present='no')
-
- self.dom.appendChild(m)
+ appendElement(clock, 'timer', name='hpet', present='no')
def appendOs(self):
"""
@@ -197,35 +163,33 @@
</os>
"""
- oselem = XMLElement('os')
- self.dom.appendChild(oselem)
+ os = appendElement(self.dom, 'os')
DEFAULT_MACHINES = {caps.Architecture.X86_64: 'pc',
caps.Architecture.PPC64: 'pseries'}
machine = self.conf.get('emulatedMachine', DEFAULT_MACHINES[self.arch])
- oselem.appendChildWithArgs('type', text='hvm', arch=self.arch,
- machine=machine)
+ appendElement(os, 'type', arch=self.arch, machine=machine).text='hvm'
qemu2libvirtBoot = {'a': 'fd', 'c': 'hd', 'd': 'cdrom', 'n': 'network'}
for c in self.conf.get('boot', ''):
- oselem.appendChildWithArgs('boot', dev=qemu2libvirtBoot[c])
+ appendElement(os, 'boot', dev=qemu2libvirtBoot[c])
if self.conf.get('initrd'):
- oselem.appendChildWithArgs('initrd', text=self.conf['initrd'])
+ appendElement(os, 'initrd').text=self.conf['initrd']
if self.conf.get('kernel'):
- oselem.appendChildWithArgs('kernel', text=self.conf['kernel'])
+ appendElement(os, 'kernel').text=self.conf['kernel']
if self.conf.get('kernelArgs'):
- oselem.appendChildWithArgs('cmdline', text=self.conf['kernelArgs'])
+ appendElement(os, 'cmdline').text=self.conf['kernelArgs']
if self.arch == caps.Architecture.X86_64:
- oselem.appendChildWithArgs('smbios', mode='sysinfo')
+ appendElement(os, 'smbios', mode='sysinfo')
if utils.tobool(self.conf.get('bootMenuEnable', False)):
- oselem.appendChildWithArgs('bootmenu', enable='yes')
+ appendElement(os, 'bootmenu', enable='yes')
def appendSysinfo(self, osname, osversion, serialNumber):
"""
@@ -246,20 +210,15 @@
</sysinfo>
"""
- sysinfoelem = XMLElement('sysinfo', type='smbios')
- self.dom.appendChild(sysinfoelem)
+ sysinfo = appendElement(self.dom, 'sysinfo', type='smbios')
+ syselem = appendElement(sysinfo, 'system')
- syselem = XMLElement('system')
- sysinfoelem.appendChild(syselem)
-
- def appendEntry(k, v):
- syselem.appendChildWithArgs('entry', text=v, name=k)
-
- appendEntry('manufacturer', constants.SMBIOS_MANUFACTURER)
- appendEntry('product', osname)
- appendEntry('version', osversion)
- appendEntry('serial', serialNumber)
- appendEntry('uuid', self.conf['vmId'])
+ appendElement(syselem, 'entry', name='manufacturer').text=\
+ constants.SMBIOS_MANUFACTURER
+ appendElement(syselem, 'entry', name='product').text=osname
+ appendElement(syselem, 'entry', name='version').text=osversion
+ appendElement(syselem, 'entry', name='serial').text=serialNumber
+ appendElement(syselem, 'entry', name='uuid').text=self.conf['vmId']
def appendFeatures(self):
"""
@@ -272,8 +231,8 @@
"""
if utils.tobool(self.conf.get('acpiEnable', 'true')):
- features = self.dom.appendChildWithArgs('features')
- features.appendChildWithArgs('acpi')
+ features = appendElement(self.dom, 'features')
+ appendElement(features, 'acpi')
def appendCpu(self):
"""
@@ -287,20 +246,20 @@
</cpu>
"""
- cpu = XMLElement('cpu')
+ cpu = ET.Element('cpu')
- if self.arch in (caps.Architecture.X86_64):
- cpu.setAttrs(match='exact')
+ if self.arch == caps.Architecture.X86_64:
+ cpu.set('match', 'exact')
features = self.conf.get('cpuType', 'qemu64').split(',')
model = features[0]
if model == 'hostPassthrough':
- cpu.setAttrs(mode='host-passthrough')
+ cpu.set('mode', 'host-passthrough')
elif model == 'hostModel':
- cpu.setAttrs(mode='host-model')
+ cpu.set('mode', 'host-model')
else:
- cpu.appendChildWithArgs('model', text=model)
+ appendElement(cpu, 'model').text=model
# This hack is for backward compatibility as the libvirt
# does not allow 'qemu64' guest on intel hardware
@@ -317,39 +276,39 @@
featureAttrs['policy'] = 'require'
elif feature[0] == '-':
featureAttrs['policy'] = 'disable'
- cpu.appendChildWithArgs('feature', **featureAttrs)
+
+ appendElement(cpu, 'feature', featureAttrs)
if ('smpCoresPerSocket' in self.conf or
'smpThreadsPerCore' in self.conf):
maxVCpus = int(self._getMaxVCpus())
cores = int(self.conf.get('smpCoresPerSocket', '1'))
threads = int(self.conf.get('smpThreadsPerCore', '1'))
- cpu.appendChildWithArgs('topology',
- sockets=str(maxVCpus / cores / threads),
- cores=str(cores), threads=str(threads))
+ appendElement(cpu, 'topology',
+ sockets=str(maxVCpus / cores / threads),
+ cores=str(cores), threads=str(threads))
# CPU-pinning support
# see http://www.ovirt.org/wiki/Features/Design/cpu-pinning
if 'cpuPinning' in self.conf:
- cputune = XMLElement('cputune')
+ cputune = appendElement(self.dom, 'cputune')
cpuPinning = self.conf.get('cpuPinning')
- for cpuPin in cpuPinning.keys():
- cputune.appendChildWithArgs('vcpupin', vcpu=cpuPin,
- cpuset=cpuPinning[cpuPin])
- self.dom.appendChild(cputune)
+ for vcpu, cpuset in cpuPinning.items():
+ appendElement(cputune, 'vcpupin',
+ vcpu=vcpu, cpuset=cpuset)
# Guest numa topology support
# see http://www.ovirt.org/Features/NUMA_and_Virtual_NUMA
if 'guestNumaNodes' in self.conf:
- numa = XMLElement('numa')
+ numa = appendElement(cpu, 'numa')
guestNumaNodes = self.conf.get('guestNumaNodes')
for vmCell in guestNumaNodes:
- numa.appendChildWithArgs('cell',
- cpus=vmCell['cpus'],
- memory=str(vmCell['memory']))
- cpu.appendChild(numa)
+ appendElement(numa, 'cell',
+ cpus=vmCell['cpus'],
+ memory=str(vmCell['memory']))
- self.dom.appendChild(cpu)
+ self.dom.append(cpu)
+
# Guest numatune support
def appendNumaTune(self):
@@ -363,12 +322,11 @@
if 'numaTune' in self.conf:
numaTune = self.conf.get('numaTune')
- if 'nodeset' in numaTune.keys():
+ if 'nodeset' in numaTune:
mode = numaTune.get('mode', 'strict')
- numatune = XMLElement('numatune')
- numatune.appendChildWithArgs('memory', mode=mode,
- nodeset=numaTune['nodeset'])
- self.dom.appendChild(numatune)
+ numatune = appendElement(self.dom, 'numatune')
+ appendElement(numatune, 'memory',
+ mode=mode, nodeset=numaTune['nodeset'])
def _appendAgentDevice(self, path, name):
"""
@@ -377,10 +335,9 @@
<source mode='bind' path='/tmp/socket'/>
</channel>
"""
- channel = XMLElement('channel', type='unix')
- channel.appendChildWithArgs('target', type='virtio', name=name)
- channel.appendChildWithArgs('source', mode='bind', path=path)
- self._devices.appendChild(channel)
+ channel = appendElement(self._devices, 'channel', type='unix')
+ appendElement(channel, 'target', type='virtio', name=name)
+ appendElement(channel, 'source', mode='bind', path=path)
def appendInput(self):
"""
@@ -397,7 +354,7 @@
mouseBus = 'ps2'
inputAttrs = {'type': 'mouse', 'bus': mouseBus}
- self._devices.appendChildWithArgs('input', **inputAttrs)
+ appendElement(self._devices, 'input', inputAttrs)
def appendKeyboardDevice(self):
"""
@@ -409,10 +366,9 @@
<qemu:arg value='keyboard'/>
</qemu:commandline>
"""
- commandLine = XMLElement('qemu:commandline')
- commandLine.appendChildWithArgs('qemu:arg', value='-usbdevice')
- commandLine.appendChildWithArgs('qemu:arg', value='keyboard')
- self.dom.appendChild(commandLine)
+ commandLine = appendElement(self.dom, 'qemu:commandline')
+ appendElement(commandLine, 'qemu:arg', value='-usbdevice')
+ appendElement(commandLine, 'qemu:arg', value='keyboard')
def appendGraphics(self):
"""
@@ -442,43 +398,56 @@
graphicsAttrs['passwd'] = '*****'
graphicsAttrs['passwdValidTo'] = '1970-01-01T00:00:01'
- graphics = XMLElement('graphics', **graphicsAttrs)
+ graphics = appendElement(self._devices, 'graphics', graphicsAttrs)
if 'qxl' in self.conf['display']:
if self.conf.get('spiceSecureChannels'):
for channel in self.conf['spiceSecureChannels'].split(','):
- graphics.appendChildWithArgs('channel', name=channel[1:],
- mode='secure')
+ appendElement(graphics, 'channel',
+ name=channel[1:], mode='secure')
- vmc = XMLElement('channel', type='spicevmc')
- vmc.appendChildWithArgs('target', type='virtio',
- name='com.redhat.spice.0')
- self._devices.appendChild(vmc)
+ vmc = appendElement(self._devices, 'channel', type='spicevmc')
+ appendElement(vmc, 'target',
+ type='virtio', name='com.redhat.spice.0')
if self.conf.get('displayNetwork'):
- graphics.appendChildWithArgs('listen', type='network',
- network=netinfo.LIBVIRT_NET_PREFIX +
- self.conf.get('displayNetwork'))
+ appendElement(graphics, 'listen',
+ type='network',
+ network=netinfo.LIBVIRT_NET_PREFIX +
+ self.conf.get('displayNetwork'))
else:
- graphics.setAttrs(listen='0')
-
- self._devices.appendChild(graphics)
+ graphics.set('listen', '0')
def appendEmulator(self):
- emulatorPath = '/usr/bin/qemu-system-' + self.arch
+ appendElement(self._devices, 'emulator').text=\
+ '/usr/bin/qemu-system-%s' % self.arch
- emulator = XMLElement('emulator', text=emulatorPath)
-
- self._devices.appendChild(emulator)
+ def appendDevice(self, dev):
+ self._devices.append(dev.getXML())
def toxml(self):
- return self.doc.toprettyxml(encoding='utf-8')
+ # FIXME
+ return '<?xml version="1.0" encoding="utf-8"?>' + \
+ tostring(self.dom)
def _getSmp(self):
return self.conf.get('smp', '1')
def _getMaxVCpus(self):
return self.conf.get('maxVCpus', self._getSmp())
+
+
+def tostring(element):
+ return ET.tostring(element, encoding='utf-8', method='xml')
+
+
+def setattrs(element, attrs=None, **kwargs):
+ if attrs is None:
+ attrs = {}
+ attrs.update(kwargs)
+ for attrName, attrValue in attrs.items():
+ element.set(attrName, attrValue)
+ return element
class XMLRepresentable(object):
@@ -488,10 +457,10 @@
Create domxml device element according to passed in params
"""
elemAttrs = {}
- element = XMLElement(elemType)
+ element = ET.Element(elemType)
if deviceType:
- elemAttrs['type'] = deviceType
+ element.set('type', deviceType)
for attrName in attributes:
if not hasattr(self, attrName):
@@ -499,11 +468,10 @@
attr = getattr(self, attrName)
if isinstance(attr, dict):
- element.appendChildWithArgs(attrName, **attr)
+ ET.SubElement(element, attrName, attr)
else:
- elemAttrs[attrName] = attr
+ element.set(attrName, attr)
- element.setAttrs(**elemAttrs)
return element
def getXML(self):
@@ -512,43 +480,5 @@
"""
return self.createXmlElem(self.type, self.device, ['address'])
-
-# A little unrelated hack to make xml.dom.minidom.Document.toprettyxml()
-# not wrap Text node with whitespace.
-# until http://bugs.python.org/issue4147 is accepted
-def __hacked_writexml(self, writer, indent="", addindent="", newl=""):
-
- # copied from xml.dom.minidom.Element.writexml and hacked not to wrap Text
- # nodes with whitespace.
-
- # indent = current indentation
- # addindent = indentation to add to higher levels
- # newl = newline string
- writer.write(indent + "<" + self.tagName)
-
- attrs = self._get_attributes()
- a_names = attrs.keys()
- a_names.sort()
-
- for a_name in a_names:
- writer.write(" %s=\"" % a_name)
- # _write_data(writer, attrs[a_name].value) # replaced
- xml.dom.minidom._write_data(writer, attrs[a_name].value)
- writer.write("\"")
- if self.childNodes:
- # added special handling of Text nodes
- if (len(self.childNodes) == 1 and
- isinstance(self.childNodes[0], xml.dom.minidom.Text)):
- writer.write(">")
- self.childNodes[0].writexml(writer)
- writer.write("</%s>%s" % (self.tagName, newl))
- else:
- writer.write(">%s" % (newl))
- for node in self.childNodes:
- node.writexml(writer, indent + addindent, addindent, newl)
- writer.write("%s</%s>%s" % (indent, self.tagName, newl))
- else:
- writer.write("/>%s" % (newl))
-
-
-xml.dom.minidom.Element.writexml = __hacked_writexml
+ def toXML(self):
+ return tostring(self.getXML())
--
To view, visit http://gerrit.ovirt.org/26856
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7874026acf52b869b8329f433d5833530e0d02e0
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: utilsTests: Avoiding returning in the middle of the method
by vvolansk@redhat.com
Vered Volansky has uploaded a new change for review.
Change subject: utilsTests: Avoiding returning in the middle of the method
......................................................................
utilsTests: Avoiding returning in the middle of the method
In RollbackContextTest there are some tests which returns in the first
except. This patch avoids that.
Change-Id: I877f65569f4304bdd4160bb9f84facf261e568e8
Signed-off-by: Vered Volansky <vvolansk(a)redhat.com>
---
M tests/utilsTests.py
1 file changed, 7 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/86/22886/1
diff --git a/tests/utilsTests.py b/tests/utilsTests.py
index bf27f30..7ce15dc 100644
--- a/tests/utilsTests.py
+++ b/tests/utilsTests.py
@@ -334,9 +334,8 @@
rollback.prependDefer(self._callDef)
except Exception:
self.assertEquals(self._called, 2)
- return
-
- self.fail("Exception was not raised")
+ else:
+ self.fail("Exception was not raised")
def testFirstException(self):
"""
@@ -353,11 +352,10 @@
rollback.prependDefer(self._callDef)
except RuntimeError:
self.assertEquals(self._called, 3)
- return
except Exception:
self.fail("Wrong exception was raised")
-
- self.fail("Exception was not raised")
+ else:
+ self.fail("Exception was not raised")
def testKeyErrorException(self):
"""
@@ -368,8 +366,8 @@
with utils.RollbackContext():
{}['aKey']
except KeyError:
- return
+ pass
except Exception:
self.fail("Wrong exception was raised")
-
- self.fail("Exception was not raised")
+ else:
+ self.fail("Exception was not raised")
--
To view, visit http://gerrit.ovirt.org/22886
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I877f65569f4304bdd4160bb9f84facf261e568e8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vered Volansky <vvolansk(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: [WIP]ioprocess implementation
by ykaplan@redhat.com
Yeela Kaplan has uploaded a new change for review.
Change subject: [WIP]ioprocess implementation
......................................................................
[WIP]ioprocess implementation
Change-Id: I132129315c73e880d998a13f84e822a9d4fec2a6
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M lib/vdsm/config.py.in
M vdsm/storage/outOfProcess.py
2 files changed, 14 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/67/26967/1
diff --git a/lib/vdsm/config.py.in b/lib/vdsm/config.py.in
index 437327b..63b4f70 100644
--- a/lib/vdsm/config.py.in
+++ b/lib/vdsm/config.py.in
@@ -294,7 +294,7 @@
('use_volume_leases', 'false',
'Whether to use the volume leases or not.'),
- ('oop_impl', 'rfh',
+ ('oop_impl', 'ioprocess',
'Whether to use RFH or ioprocess implementation for oop.'),
]),
diff --git a/vdsm/storage/outOfProcess.py b/vdsm/storage/outOfProcess.py
index fbd35fd..d6a43be 100644
--- a/vdsm/storage/outOfProcess.py
+++ b/vdsm/storage/outOfProcess.py
@@ -96,13 +96,25 @@
fullName)
+class _ioprocessGlob(object):
+ def __init__(self, iop):
+ self._iop = iop
+
+ def glob(self, pattern):
+ return self._iop.glob(pattern)
+
+
class _IOProcWrapper(object):
def __init(self, _oop, ioproc):
self._oop = _oop
self._iop = ioproc
+ self.glob = _ioprocessGlob(self._iop)
def __getattr__(self, name):
- return self._oop.__getattr__(name)
+ if name in self.__dict__:
+ return self.name
+ else:
+ return self._oop.__getattr__(name)
def OopWrapper(procPool, ioproc=None):
--
To view, visit http://gerrit.ovirt.org/26967
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I132129315c73e880d998a13f84e822a9d4fec2a6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: oop: Add an option to configure oop implementation
by ykaplan@redhat.com
Yeela Kaplan has uploaded a new change for review.
Change subject: oop: Add an option to configure oop implementation
......................................................................
oop: Add an option to configure oop implementation
The final goal is to replace remoteFileHandler implementation
for outOfProcess with ioprocess.
We will do this in a series of steps
The first step is to add an option to manually configure
which one of the two implementations is to be used:
rfh or ioproc.
Change-Id: Ibd756afd43d23631dc7ed4bac64bec9a81b358b4
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M lib/vdsm/config.py.in
M vdsm/storage/hsm.py
M vdsm/storage/outOfProcess.py
3 files changed, 43 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/76/26576/1
diff --git a/lib/vdsm/config.py.in b/lib/vdsm/config.py.in
index 591f268..437327b 100644
--- a/lib/vdsm/config.py.in
+++ b/lib/vdsm/config.py.in
@@ -293,6 +293,9 @@
('use_volume_leases', 'false',
'Whether to use the volume leases or not.'),
+
+ ('oop_impl', 'rfh',
+ 'Whether to use RFH or ioprocess implementation for oop.'),
]),
# Section: [addresses]
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 9040d79..5cca39a 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -360,6 +360,8 @@
self.__validateLvmLockingType()
+ oop.setDefaultImpl(config.get('irs', 'oop_impl'))
+
self.domainStateChangeCallbacks = set()
# cleanStorageRepoitory uses tasksDir value, this must be assigned
diff --git a/vdsm/storage/outOfProcess.py b/vdsm/storage/outOfProcess.py
index f3777a9..9897752 100644
--- a/vdsm/storage/outOfProcess.py
+++ b/vdsm/storage/outOfProcess.py
@@ -19,29 +19,45 @@
#
import types
+from ioprocess import IOProcess
+
from vdsm.config import config
import threading
from functools import partial
from remoteFileHandler import RemoteFileHandlerPool
+RFH = 'rfh'
+IOPROC = 'ioprocess'
+OOP_IMPL = RFH
+
DEFAULT_TIMEOUT = config.getint("irs", "process_pool_timeout")
HELPERS_PER_DOMAIN = config.getint("irs", "process_pool_max_slots_per_domain")
-_poolsLock = threading.Lock()
-_pools = {}
+_procLock = threading.Lock()
+_proc = {}
+
+
+def setDefaultImpl(impl):
+ global OOP_IMPL
+ OOP_IMPL = impl
def getProcessPool(clientName):
try:
- return _pools[clientName]
+ return _proc[clientName][OOP_IMPL]
except KeyError:
- with _poolsLock:
- if clientName not in _pools:
- _pools[clientName] = OopWrapper(
+ with _procLock:
+ if clientName not in _proc:
+ _proc[clientName][RFH] = OopWrapper(
RemoteFileHandlerPool(HELPERS_PER_DOMAIN))
+ if "Global" not in _proc:
+ _proc["Global"][IOPROC] = OopWrapper(
+ RemoteFileHandlerPool(HELPERS_PER_DOMAIN),
+ IOProcess(DEFAULT_TIMEOUT))
+ _proc[clientName][IOPROC] = _proc["Global"][IOPROC]
- return _pools[clientName]
+ return _proc[clientName][OOP_IMPL]
def getGlobalProcPool():
@@ -76,10 +92,23 @@
fullName)
-def OopWrapper(procPool):
- return _ModuleWrapper("oop", procPool, DEFAULT_TIMEOUT,
+class _IOProcWrapper(object):
+ def __init(self, _oop, ioproc):
+ self._oop = _oop
+ self._iop = ioproc
+
+ def __getattr__(self, name):
+ return self._oop.__getattr__(name)
+
+
+def OopWrapper(procPool, ioproc=None):
+ _oop = _ModuleWrapper("oop", procPool, DEFAULT_TIMEOUT,
(("os",
("path",)),
"glob",
"fileUtils",
"utils"))
+ if ioproc is None:
+ return _oop
+ else:
+ return _IOProcWrapper(_oop, ioproc)
--
To view, visit http://gerrit.ovirt.org/26576
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibd756afd43d23631dc7ed4bac64bec9a81b358b4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
9 years, 11 months
Change in vdsm[master]: vm: spice support to agent file transfer disable
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: vm: spice support to agent file transfer disable
......................................................................
vm: spice support to agent file transfer disable
Spice has agent based file transfer support.
This option can be disabled in QEMU, and libvirt has support
to pass this flag to the underlying QEMU.
This patch expose this capability in VDSM, in the VM definition,
implementing the VDSM part of bz983019.
The new parameter is optional and enabled by default for backward
compatibility.
No XML changes are produced at all unless the new parameter is
specified.
Change-Id: I8cde372e6bf2f46b2ceac4e8660b5b05f02aaccb
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M tests/vmTests.py
M vdsm/vm.py
M vdsm_api/vdsmapi-schema.json
3 files changed, 40 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/70/23270/1
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 6215041..2594dc2 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -304,6 +304,20 @@
<channel mode="secure" name="playback"/>
<channel mode="secure" name="record"/>
<channel mode="secure" name="display"/>
+ </graphics>""",
+
+ """
+ <graphics autoport="yes" listen="0" passwd="*****"
+ passwdValidTo="1970-01-01T00:00:01" port="-1"
+ tlsPort="-1" type="spice">
+ <filetransfer enable="no"/>
+ </graphics>""",
+
+ """
+ <graphics autoport="yes" listen="0" passwd="*****"
+ passwdValidTo="1970-01-01T00:00:01" port="-1"
+ tlsPort="-1" type="spice">
+ <channel mode="secure" name="main"/>
</graphics>"""]
spiceChannelXML = """
@@ -317,7 +331,13 @@
{'display': 'qxl', 'displayPort': '-1', 'displaySecurePort': '-1',
'spiceSecureChannels':
- "smain,sinputs,scursor,splayback,srecord,sdisplay"}]
+ "smain,sinputs,scursor,splayback,srecord,sdisplay"},
+
+ {'display': 'qxl', 'displayPort': '-1', 'displaySecurePort': '-1',
+ 'fileTransferEnable': 'false'},
+
+ {'display': 'qxl', 'displayPort': '-1', 'displaySecurePort': '-1',
+ 'fileTransferEnable': 'true', 'spiceSecureChannels': "smain"}]
for vmConf, xml in zip(vmConfs, expectedXMLs):
vmConf.update(self.conf)
diff --git a/vdsm/vm.py b/vdsm/vm.py
index bd5f6d5..ed11d82 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -1186,6 +1186,12 @@
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
</channel>
+
+ or
+
+ <graphics autoport="yes" port="5910" tlsPort="5890" type="spice">
+ <filetransfer enable='no'/>
+ </graphics>
"""
graphicsAttrs = {'port': self.conf['displayPort'], 'autoport': 'yes'}
if self.conf['display'] == 'vnc':
@@ -1208,6 +1214,10 @@
graphics.appendChildWithArgs('channel', name=channel[1:],
mode='secure')
+ if not utils.tobool(self.conf.get('fileTransferEnable', True)):
+ filetransfer = XMLElement('filetransfer', enable='no')
+ graphics.appendChild(filetransfer)
+
vmc = XMLElement('channel', type='spicevmc')
vmc.appendChildWithArgs('target', type='virtio',
name='com.redhat.spice.0')
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 564180a..3b258b2 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -2804,6 +2804,10 @@
#
# @emulatedMachine: #optional The machine specification being emulated
#
+# @fileTransferEnable: #optional Specify if file transfer is enabled.
+# Currently relevant for @qxl devices only.
+# (new in version 4.14.0)
+#
# @keyboardLayout: #optional The keyboard layout string (eg. 'en-us')
#
# @kvmEnable: Indicates if KVM hardware acceleration is enabled
@@ -2854,10 +2858,11 @@
'*cpuType': 'str', '*custom': 'StringMap', '*devices': ['VmDevice'],
'display': 'VmDisplayType', 'displayIp': 'str',
'displayPort': 'int', 'displaySecurePort': 'int',
- '*emulatedMachine': 'str', '*keyboardLayout': 'str',
- 'kvmEnable': 'bool', '*maxVCpus': 'uint', 'memSize': 'uint',
- 'memGuaranteedSize': 'uint', 'nicModel': 'str', 'nice': 'int',
- '*pauseCode': 'str', 'pid': 'uint', 'smp': 'uint', '*smpCoresPerSocket': 'uint',
+ '*emulatedMachine': 'str', '*fileTransferEnable': 'bool',
+ '*keyboardLayout': 'str', 'kvmEnable': 'bool',
+ '*maxVCpus': 'uint', 'memSize': 'uint', 'memGuaranteedSize': 'uint',
+ 'nicModel': 'str', 'nice': 'int', '*pauseCode': 'str', 'pid': 'uint',
+ 'smp': 'uint', '*smpCoresPerSocket': 'uint',
'*smpThreadsPerCore': 'uint', 'status': 'VmStatus',
'timeOffset': 'uint', 'transparentHugePages': 'bool',
'vmId': 'UUID', 'vmName': 'str', 'vmType': 'VmType',
--
To view, visit http://gerrit.ovirt.org/23270
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8cde372e6bf2f46b2ceac4e8660b5b05f02aaccb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
9 years, 11 months