Xavi Francisco has uploaded a new change for review.
Change subject: vm: Modify and save state after hotunplugging the disk
......................................................................
vm: Modify and save state after hotunplugging the disk
The rationale behind this patch is to modify the way the hotunplug
process is executed. Now when the hotunplug command is called we first
remove the disk from the internal state and after that the libvirt
hotunplug command is executed.The problem with that approach is
that if VDSM restarts between the modification of the internal
state and the actual unplugging of the disk, the disk never gets
unplugged leaving the system in an inconsistent state.
This patch solves the issue by executing the modification of the
internal state after the actual unplugging has successfully happened.
This state is later saved so if either the disk has been unplugged or
not VDSM is able to recover its state in case of a restart.
Change-Id: I5169fa16591283de33aa82c5730626bfd5d3eaf5
Signed-off-by: Xavi Francisco <xfrancis(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 12 insertions(+), 20 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/87/28187/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index bd670b9..1eb2adc 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -3449,20 +3449,6 @@
driveXml = drive.getXML().toprettyxml(encoding='utf-8')
self.log.debug("Hotunplug disk xml: %s", driveXml)
# Remove found disk from vm's drives list
- if isVdsmImage(drive):
- self.sdIds.remove(drive.domainID)
- self._devices[DISK_DEVICES].remove(drive)
- # Find and remove disk device from vm's conf
- diskDev = None
- for dev in self.conf['devices'][:]:
- if (dev['type'] == DISK_DEVICES and
- dev['path'] == drive.path):
- with self._confLock:
- self.conf['devices'].remove(dev)
- diskDev = dev
- break
-
- self.saveState()
hooks.before_disk_hotunplug(driveXml, self.conf,
params=drive.custom)
@@ -3472,19 +3458,25 @@
self.log.error("Hotunplug failed", exc_info=True)
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
return errCode['noVM']
- self._devices[DISK_DEVICES].append(drive)
- # Restore disk device in vm's conf and _devices
- if diskDev:
- with self._confLock:
- self.conf['devices'].append(diskDev)
- self.saveState()
return {
'status': {'code': errCode['hotunplugDisk']['status']['code'],
'message': e.message}}
else:
+ if isVdsmImage(drive):
+ self.sdIds.remove(drive.domainID)
+ self._devices[DISK_DEVICES].remove(drive)
+ # Find and remove disk device from vm's conf
+ for dev in self.conf['devices'][:]:
+ if (dev['type'] == DISK_DEVICES and
+ dev['path'] == drive.path):
+ with self._confLock:
+ self.conf['devices'].remove(dev)
+ break
hooks.after_disk_hotunplug(driveXml, self.conf,
params=drive.custom)
self._cleanupDrives(drive)
+ finally:
+ self.saveState()
return {'status': doneCode, 'vmList': self.status()}
--
To view, visit http://gerrit.ovirt.org/28187
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5169fa16591283de33aa82c5730626bfd5d3eaf5
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Xavi Francisco <xfrancis(a)redhat.com>
Yoav Kleinberger has uploaded a new change for review.
Change subject: tests: use 'localhost' explicitly in test
......................................................................
tests: use 'localhost' explicitly in test
Previously tests could on some machines (in case the machine has a
non-default hostname). Now, since we use 'localhost' explicitly, this
will not happen.
Change-Id: I89990cff46e64120262e250eee9238b49c4edee4
Signed-off-by: Yoav Kleinberger <ykleinbe(a)redhat.com>
---
M tests/functional/storageTests.py
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/28107/1
diff --git a/tests/functional/storageTests.py b/tests/functional/storageTests.py
index 80ba312..76ca91d 100644
--- a/tests/functional/storageTests.py
+++ b/tests/functional/storageTests.py
@@ -79,7 +79,8 @@
isSSL = config.getboolean('vars', 'ssl')
if isSSL and os.geteuid() != 0:
raise SkipTest("Must be root to use SSL connection to server")
- self.s = vdscli.connect(useSSL=isSSL)
+ address = 'localhost:%s' % config.get('addresses', 'management_port')
+ self.s = vdscli.connect(hostPort=address, useSSL=isSSL)
def assertVdsOK(self, vdsResult):
# code == 0 means OK
--
To view, visit http://gerrit.ovirt.org/28107
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I89990cff46e64120262e250eee9238b49c4edee4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yoav Kleinberger <ykleinbe(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: vm: Require format attribute for drives
......................................................................
vm: Require format attribute for drives
We have seen sampling errors where a drive has no "format" attribute.
These errors spam the system logs, and does not help to debug the real
issue - why the required format attribute is not set?
This patch ensure that a drive cannot be created without a format
attribute, avoding log spam by sampling errors, and hopefully revealing
the real reason for this bug.
One broken test creating a drive without a format was fixed and new test
ensure that creating drive without a format raises.
Change-Id: I01ab1e071ecb76f383cc6dc7d99782e10cc90136
Relates-To: http://gerrit.ovirt.org/22551
Relates-To: https://bugzilla.redhat.com/994534
Relates-To: http://lists.ovirt.org/pipermail/users/2014-February/021007.html
Bug-Url: https://bugzilla.redhat.com/1055437
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M tests/vmTests.py
M vdsm/vm.py
2 files changed, 28 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/34/24234/1
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 1e0a3f6..724d458 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -449,6 +449,18 @@
redir = vm.RedirDevice(self.conf, self.log, **dev)
self.assertXML(redir.getXML(), redirXML)
+ def testDriveRequiredParameters(self):
+ # TODO: It is not clear what are the other required parameters, and it
+ # the parameters depend on the type of drive. We probbaly need bigger
+ # test here that test many combinations.
+ # Currently this test only missing "format" attribute.
+ conf = {'index': '2', 'propagateErrors': 'off', 'iface': 'ide',
+ 'name': 'hdc', 'device': 'cdrom', 'path': '/tmp/fedora.iso',
+ 'type': 'disk', 'readonly': 'True', 'shared': 'none',
+ 'serial': '54-a672-23e5b495a9ea'}
+ self.assertRaises(vm.InvalidDeviceParameters, vm.Drive, {}, self.log,
+ **conf)
+
def testDriveSharedStatus(self):
sharedConfigs = [
# Backward compatibility
@@ -470,7 +482,8 @@
'exclusive', 'shared', 'none', 'transient',
]
- driveConfig = {'index': '0', 'iface': 'virtio', 'device': 'disk'}
+ driveConfig = {'index': '0', 'iface': 'virtio', 'device': 'disk',
+ 'format': 'raw'}
for driveInput, driveOutput in zip(sharedConfigs, expectedStates):
driveInput.update(driveConfig)
diff --git a/vdsm/vm.py b/vdsm/vm.py
index aae8bd6..b7151b1 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -80,6 +80,10 @@
SMARTCARD_DEVICES = 'smartcard'
+class InvalidDeviceParameters(Exception):
+ """ Raised when creating device with invalid parameters """
+
+
def isVdsmImage(drive):
"""
Tell if drive looks like a vdsm image
@@ -1438,6 +1442,9 @@
VOLWM_CHUNK_REPLICATE_MULT = 2 # Chunk multiplier during replication
def __init__(self, conf, log, **kwargs):
+ if 'format' not in kwargs:
+ raise InvalidDeviceParameters('"format" attribute is required:'
+ ' %r' % kwargs)
if not kwargs.get('serial'):
self.serial = kwargs.get('imageID'[-20:]) or ''
VmDevice.__init__(self, conf, log, **kwargs)
@@ -3108,8 +3115,13 @@
for devType, devClass in self.DeviceMapping:
for dev in devices[devType]:
- self._devices[devType].append(devClass(self.conf, self.log,
- **dev))
+ try:
+ drive = devClass(self.conf, self.log, **dev)
+ except InvalidDeviceParameters as e:
+ self.log.error('Ignoring device with invalid parameters:'
+ ' %s', e, exc_info=True)
+ else:
+ self._devices[devType].append(drive)
# We should set this event as a last part of drives initialization
self._pathsPreparedEvent.set()
--
To view, visit http://gerrit.ovirt.org/24234
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I01ab1e071ecb76f383cc6dc7d99782e10cc90136
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: resourceManager: Keep resource state if registerResource fails
......................................................................
resourceManager: Keep resource state if registerResource fails
Previous code was increasing resource activeUsers counter, but
exceptions raised after that caused the method to fail, leaving a locked
resources that nobody can release. Such locked resource may lead to
failure of any pool operation, making the host non-operational, and
requiring a restart of vdsm.
The failure in the field was caused by Python logging bug, raising
OSError when message was logged when log file was rotated. However, such
failure can happen everywhere, and locking code must be written in such
way that failure would never leave a resource locked.
This patch ensure that resource is added and activeUsers counter is
increased only if everything else was fine.
Since simulating logging error is hard, the tests monkeypatch the
RequestRef class to simulate a failure. This is little ugly, depending
on internal implementation detail, but I could not find a cleaner way.
Change-Id: I16abf41ebc8a8a99b292d38c945074752254a34b
Relates-To: https://bugzilla.redhat.com/1065650
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M tests/resourceManagerTests.py
M vdsm/storage/resourceManager.py
2 files changed, 50 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/84/25284/1
diff --git a/tests/resourceManagerTests.py b/tests/resourceManagerTests.py
index 01b0669..e2b6461 100644
--- a/tests/resourceManagerTests.py
+++ b/tests/resourceManagerTests.py
@@ -29,6 +29,7 @@
import storage.resourceManager as resourceManager
from testrunner import VdsmTestCase as TestCaseBase
from testValidation import slowtest, stresstest
+import monkeypatch
class NullResourceFactory(resourceManager.SimpleResourceFactory):
@@ -209,6 +210,32 @@
ex.__class__.__name__)
self.fail("Managed to access an attribute not exposed by wrapper")
+
+ def testRegisterResourceFailureExclusive(self):
+ # This regeisterion must fail
+ with monkeypatch.MonkeyPatchScope(
+ [(resourceManager, 'RequestRef', FakeRequestRef)]):
+ self.assertRaises(Failure, self.manager.registerResource, "string",
+ "test", resourceManager.LockType.exclusive, None)
+
+ # And it should not leave a locked resource
+ with self.manager.acquireResource("string", "test",
+ resourceManager.LockType.exclusive,
+ 0):
+ pass
+
+ def testRegisterResourceFailureShared(self):
+ # This regeisterion must fail
+ with monkeypatch.MonkeyPatchScope(
+ [(resourceManager, 'RequestRef', FakeRequestRef)]):
+ self.assertRaises(Failure, self.manager.registerResource, "string",
+ "test", resourceManager.LockType.shared, None)
+
+ # And it should not leave a locked resource
+ with self.manager.acquireResource("string", "test",
+ resourceManager.LockType.exclusive,
+ 0):
+ pass
def testAccessAttributeNotExposedByRequestRef(self):
resources = []
@@ -705,3 +732,14 @@
except:
resourceManager.ResourceManager._instance = None
raise
+
+# Helpers
+
+
+class Failure(Exception):
+ """ Unique exception for testing """
+
+
+def FakeRequestRef(*a, **kw):
+ """ Used to simulate failures when registering a resource """
+ raise Failure()
diff --git a/vdsm/storage/resourceManager.py b/vdsm/storage/resourceManager.py
index 1be1450..ce144cf 100644
--- a/vdsm/storage/resourceManager.py
+++ b/vdsm/storage/resourceManager.py
@@ -559,23 +559,25 @@
if len(resource.queue) == 0 and \
resource.currentLock == LockType.shared and \
request.lockType == LockType.shared:
- resource.activeUsers += 1
self._log.debug("Resource '%s' found in shared state "
"and queue is empty, Joining current "
"shared lock (%d active users)",
- fullName, resource.activeUsers)
+ fullName, resource.activeUsers + 1)
request.grant()
+ ref = RequestRef(request)
contextCleanup.defer(request.emit,
ResourceRef(namespace, name,
resource.realObj,
request.reqID))
- return RequestRef(request)
+ resource.activeUsers += 1
+ return ref
- resource.queue.insert(0, request)
self._log.debug("Resource '%s' is currently locked, "
"Entering queue (%d in queue)",
- fullName, len(resource.queue))
- return RequestRef(request)
+ fullName, len(resource.queue) + 1)
+ ref = RequestRef(request)
+ resource.queue.insert(0, request)
+ return ref
# TODO : Creating the object inside the namespace lock causes
# the entire namespace to lock and might cause
@@ -592,19 +594,20 @@
contextCleanup.defer(request.cancel)
return RequestRef(request)
- resource = resources[name] = ResourceManager.ResourceInfo(
- obj, namespace, name)
+ resource = ResourceManager.ResourceInfo(obj, namespace, name)
resource.currentLock = request.lockType
resource.activeUsers += 1
self._log.debug("Resource '%s' is free. Now locking as '%s' "
"(1 active user)", fullName, request.lockType)
request.grant()
+ ref = RequestRef(request)
contextCleanup.defer(request.emit,
ResourceRef(namespace, name,
resource.realObj,
request.reqID))
- return RequestRef(request)
+ resources[name] = resource
+ return ref
def releaseResource(self, namespace, name):
# WARN : unlike in resource acquire the user now has the request
--
To view, visit http://gerrit.ovirt.org/25284
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I16abf41ebc8a8a99b292d38c945074752254a34b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
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>
Francesco Romani has uploaded a new change for review.
Change subject: virt: graphdev: support headless VM
......................................................................
virt: graphdev: support headless VM
This patch add support for headless VMs, aka VMs without
a graphic device.
Noteworthy side effects of this patch:
* It is now possible to create a VM without any display
(aka headless VM), and they are supported.
* The input 'display' parameter of the Vm.create API is
no longer mandatory
* In the API schema, the display* parameters are now
marked as optional, even though Engine is expected to still
send them in the near/medium term.
* setTicket and the internally used _reviveTicket can now
fail if they are invoked against a VM without graphic devices.
Change-Id: Iafeb0bebfb43c089614127d94c054175c111ce54
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M tests/functional/virtTests.py
M tests/vmTests.py
M vdsm/API.py
M vdsm/virt/vm.py
M vdsm_api/vdsmapi-schema.json
5 files changed, 117 insertions(+), 72 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/46/27846/1
diff --git a/tests/functional/virtTests.py b/tests/functional/virtTests.py
index a074e62..9a25850 100644
--- a/tests/functional/virtTests.py
+++ b/tests/functional/virtTests.py
@@ -225,6 +225,14 @@
self._waitForStartup(vm, VM_MINIMAL_UPTIME)
@requireKVM
+ def testHeadlessVm(self):
+ customization = {'vmId': '77777777-ffff-3333-bbbb-222222222222',
+ 'vmName': 'testHeadlessVm'}
+
+ with RunningVm(self.vdsm, customization) as vm:
+ self._waitForStartup(vm, VM_MINIMAL_UPTIME)
+
+ @requireKVM
@permutations([['localfs'], ['iscsi'], ['nfs']])
def testVmWithStorage(self, backendType):
disk = storage.StorageTest()
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 69d5643..4022dfb 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -1077,6 +1077,11 @@
devs = fake.buildConfDevices()
self.assertTrue(devs['graphics'])
+ def testGraphicDeviceHeadless(self):
+ with FakeVM(self.conf) as fake:
+ devs = fake.buildConfDevices()
+ self.assertFalse(devs['graphics'])
+
def testGraphicsDeviceMixed(self):
"""
if proper Graphics Devices are supplied, display* params must be
diff --git a/vdsm/API.py b/vdsm/API.py
index 14e7bae..4747be1 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -200,7 +200,7 @@
self.log.error("Error restoring VM parameters",
exc_info=True)
- requiredParams = ['vmId', 'memSize', 'display']
+ requiredParams = ['vmId', 'memSize']
for param in requiredParams:
if param not in vmParams:
self.log.error('Missing required parameter %s' % (param))
@@ -252,11 +252,6 @@
'No space on /tmp?'}}
return errCode['createErr']
- if not vm.GraphicsDevice.isSupportedDisplayType(vmParams):
- return {'status': {'code': errCode['createErr']
- ['status']['code'],
- 'message': 'Unknown display type %s' %
- vmParams.get('display')}}
if 'nicModel' not in vmParams:
vmParams['nicModel'] = config.get('vars', 'nic_model')
return self._cif.createVm(vmParams)
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index a547a5e..5d08cea 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -1344,10 +1344,6 @@
'main', 'display', 'inputs', 'cursor', 'playback',
'record', 'smartcard', 'usbredir')
- @staticmethod
- def isSupportedDisplayType(vmParams):
- return vmParams.get('display') in ('vnc', 'qxl', 'qxlnc')
-
def __init__(self, conf, log, **kwargs):
super(GraphicsDevice, self).__init__(conf, log, **kwargs)
self.port = self.LIBVIRT_PORT_AUTOSELECT
@@ -1840,8 +1836,8 @@
if len(devices[device]) > 1:
raise ValueError("only a single %s device is "
"supported" % device)
- if len(devices[GRAPHICS_DEVICES]) != 1:
- raise ValueError("one graphics device is required")
+ if len(devices[GRAPHICS_DEVICES]) > 1:
+ raise ValueError("only one graphics device is supported")
def getConfController(self):
"""
@@ -1866,12 +1862,16 @@
devType = DEFAULT_VIDEOS[self.arch]
elif self.hasSpice:
devType = 'qxl'
+ else:
+ devType = None
- monitors = int(self.conf.get('spiceMonitors', '1'))
- vram = '65536' if (monitors <= 2) else '32768'
- for idx in range(monitors):
- vcards.append({'type': VIDEO_DEVICES, 'specParams': {'vram': vram},
- 'device': devType})
+ if devType:
+ monitors = int(self.conf.get('spiceMonitors', '1'))
+ vram = '65536' if (monitors <= 2) else '32768'
+ for idx in range(monitors):
+ vcards.append({'type': VIDEO_DEVICES,
+ 'specParams': {'vram': vram},
+ 'device': devType})
return vcards
@@ -1885,13 +1885,18 @@
for oldName, newName in GraphicsDevice.LEGACY_MAP.iteritems()
if oldName in conf)
- return [{
- 'type': GRAPHICS_DEVICES,
- 'device': (
- 'spice'
- if self.conf['display'] in ('qxl', 'qxlnc')
- else 'vnc'),
- 'specParams': makeSpecParams(self.conf)}]
+ graphDevs = []
+
+ if 'display' in self.conf:
+ graphDevs.append({
+ 'type': GRAPHICS_DEVICES,
+ 'device': (
+ 'spice'
+ if self.conf['display'] in ('qxl', 'qxlnc')
+ else 'vnc'),
+ 'specParams': makeSpecParams(self.conf)})
+
+ return graphDevs
def getConfSound(self):
"""
@@ -2520,10 +2525,6 @@
return self._getExitedVmStats()
stats = {
- 'displayPort': self.conf['displayPort'],
- 'displaySecurePort': self.conf['displaySecurePort'],
- 'displayType': self.conf['display'],
- 'displayIp': self.conf['displayIp'],
'pid': self.conf['pid'],
'vmType': self.conf['vmType'],
'kvmEnable': self._kvmEnable,
@@ -2534,6 +2535,8 @@
stats['cdrom'] = self.conf['cdrom']
if 'boot' in self.conf:
stats['boot'] = self.conf['boot']
+
+ stats.update(self._getGraphicsStats())
decStats = {}
try:
@@ -2602,6 +2605,16 @@
'exitReason': self.conf['exitReason']}
if 'timeOffset' in self.conf:
stats['timeOffset'] = self.conf['timeOffset']
+ return stats
+
+ def _getGraphicsStats(self):
+ stats = {}
+ if 'display' in self.conf:
+ stats['displayType'] = self.conf['display']
+ stats['displayPort'] = self.conf['displayPort']
+ stats['displaySecurePort'] = self.conf['displaySecurePort']
+ stats['displayIp'] = self.conf['displayIp']
+ # else headless VM
return stats
def isMigrating(self):
@@ -4266,8 +4279,13 @@
return {'status': doneCode, 'vmList': self.status()}
def setTicket(self, otp, seconds, connAct, params):
- graphics = _domParseStr(self._dom.XMLDesc(0)).childNodes[0]. \
- getElementsByTagName('graphics')[0]
+ try:
+ graphics = _domParseStr(self._dom.XMLDesc(0)).childNodes[0]. \
+ getElementsByTagName('graphics')[0]
+ except IndexError:
+ return {
+ 'status': {'code': errCode['ticketErr']['status']['code'],
+ 'message': 'no graphics devices configured'}}
graphics.setAttribute('passwd', otp)
if int(seconds) > 0:
validto = time.strftime('%Y-%m-%dT%H:%M:%S',
@@ -4288,9 +4306,13 @@
def _reviveTicket(self, newlife):
"""Revive an existing ticket, if it has expired or about to expire"""
- graphics = _domParseStr(
- self._dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)). \
- childNodes[0].getElementsByTagName('graphics')[0]
+ try:
+ graphics = _domParseStr(
+ self._dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)). \
+ childNodes[0].getElementsByTagName('graphics')[0]
+ except IndexError:
+ self.log.error('no graphics devices configured')
+ return
validto = max(time.strptime(graphics.getAttribute('passwdValidTo'),
'%Y-%m-%dT%H:%M:%S'),
time.gmtime(time.time() + newlife))
@@ -4855,19 +4877,20 @@
device of each type (sdl, vnc, spice) is supported
"""
graphicsXml = _domParseStr(self._lastXMLDesc).childNodes[0]. \
- getElementsByTagName('devices')[0].getElementsByTagName('graphics')[0]
+ getElementsByTagName('devices')[0].getElementsByTagName('graphics')
- graphicsType = graphicsXml.getAttribute('type')
- for dev in self.conf['devices']:
- if dev.get('device') == graphicsType:
- port = graphicsXml.getAttribute('port')
- if port:
- dev['port'] = port
- tlsPort = graphicsXml.getAttribute('tlsPort')
- if tlsPort:
- dev['tlsPort'] = tlsPort
- self._updateLegacyConf(dev)
- break
+ for gxml in graphicsXml:
+ graphicsType = gxml.getAttribute('type')
+
+ for dev in self.conf['devices']:
+ if dev.get('device') == graphicsType:
+ port = gxml.getAttribute('port')
+ if port:
+ dev['port'] = port
+ tlsPort = gxml.getAttribute('tlsPort')
+ if tlsPort:
+ dev['tlsPort'] = tlsPort
+ self._updateLegacyConf(dev)
def _getUnderlyingNetworkInterfaceInfo(self):
"""
@@ -5051,11 +5074,12 @@
return True
def _initLegacyConf(self):
- self.conf['displayPort'] = GraphicsDevice.LIBVIRT_PORT_AUTOSELECT
- self.conf['displaySecurePort'] = \
- GraphicsDevice.LIBVIRT_PORT_AUTOSELECT
- self.conf['displayIp'] = _getNetworkIp(
- self.conf.get('displayNetwork'))
+ if 'display' in self.conf:
+ self.conf['displayPort'] = GraphicsDevice.LIBVIRT_PORT_AUTOSELECT
+ self.conf['displaySecurePort'] = \
+ GraphicsDevice.LIBVIRT_PORT_AUTOSELECT
+ self.conf['displayIp'] = _getNetworkIp(
+ self.conf.get('displayNetwork'))
def _updateLegacyConf(self, dev):
self.conf['display'] = 'qxl' if dev['device'] == 'spice' else 'vnc'
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index a9332ee..64d4179 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -3175,13 +3175,17 @@
#
# @devices: #optional An array of VM devices present
#
-# @display: The type of display
+# @display: #optional The type of display
+# (made optional in version 4.15.0)
#
-# @displayIp: The IP address to use for accessing the VM display
+# @displayIp: #optional The IP address to use for accessing the VM display
+# (made optional in version 4.15.0)
#
-# @displayPort: The port in use for unencrypted display data
+# @displayPort: #optional The port in use for unencrypted display data
+# (made optional in version 4.15.0)
#
-# @displaySecurePort: The port in use for encrypted display data
+# @displaySecurePort: #optional The port in use for encrypted display data
+# (made optional in version 4.15.0)
#
# @emulatedMachine: #optional The machine specification being emulated
#
@@ -3235,8 +3239,8 @@
{'type': 'VmDefinition',
'data': {'acpiEnable': 'bool', 'clientIp': 'str', 'cpuShares': 'str',
'*cpuType': 'str', '*custom': 'StringMap', '*devices': ['VmDevice'],
- 'display': 'VmDisplayType', 'displayIp': 'str',
- 'displayPort': 'int', 'displaySecurePort': 'int',
+ '*display': 'VmDisplayType', '*displayIp': 'str',
+ '*displayPort': 'int', '*displaySecurePort': 'int',
'*emulatedMachine': 'str', '*keyboardLayout': 'str',
'kvmEnable': 'bool', '*maxVCpus': 'uint', 'memSize': 'uint',
'memGuaranteedSize': 'uint', 'nicModel': 'str', 'nice': 'int',
@@ -3264,7 +3268,8 @@
#
# @devices: #optional An array of VM devices requested
#
-# @display: The type of display
+# @display: #optional The type of display
+# (made optional in version 4.15.0)
#
# @kvmEnable: Indicates if KVM hardware acceleration is enabled
#
@@ -3300,7 +3305,7 @@
{'type': 'VmParameters',
'data': {'acpiEnable': 'bool', '*bootMenuEnable': 'bool',
'*cpuShares': 'str', '*custom': 'StringMap', '*devices': ['VmDevice'],
- 'display': 'VmDisplayType', 'kvmEnable': 'bool', 'memSize': 'uint',
+ '*display': 'VmDisplayType', 'kvmEnable': 'bool', 'memSize': 'uint',
'nice': 'int', 'smp': 'uint', '*smpCoresPerSocket': 'uint',
'*smpThreadsPerCore': 'uint', 'timeOffset': 'uint',
'transparentHugePages': 'bool', 'vmId': 'UUID', 'vmName': 'str',
@@ -3347,7 +3352,8 @@
#
# @devices: An array of VM devices requested
#
-# @display: The type of display
+# @display: #optional The type of display
+# (made optional in version 4.15.0)
#
# @kvmEnable: Indicates if KVM hardware acceleration is enabled
#
@@ -3372,7 +3378,8 @@
#
# @memGuaranteedSize: The amount of memory guaranteed to the VM in MB
#
-# @displaySecurePort: The port in use for encrypted display data
+# @displaySecurePort: #optional The port in use for encrypted display data
+# (made optional in version 4.15.0)
#
# @spiceSecureChannels: Secure space channels comma separated
#
@@ -3394,11 +3401,13 @@
# @guestFQDN: Fully qualified domain name of the guest OS. (Reported
# by the guest agent)
#
-# @displayIp: The IP address to use for accessing the VM display
+# @displayIp: #optional The IP address to use for accessing the VM display
+# (made optional in version 4.15.0)
#
# @keyboardLayout: The keyboard layout string (eg. 'en-us')
#
-# @displayPort: The port in use for unencrypted display data
+# @displayPort: #optional The port in use for unencrypted display data
+# (made optional in version 4.15.0)
#
# @guestIPs: A space separated string of assigned IPv4 addresses
#
@@ -3416,15 +3425,15 @@
##
{'type': 'VMFullInfo',
'data': {'acpiEnable': 'bool', 'custom': 'StringMap', 'devices': ['VmDevice'],
- 'display': 'VmDisplayType', 'kvmEnable': 'bool', 'memSize': 'uint',
+ '*display': 'VmDisplayType', 'kvmEnable': 'bool', 'memSize': 'uint',
'nice': 'int', 'smp': 'uint', 'smpCoresPerSocket': 'uint',
'timeOffset': 'uint', 'transparentHugePages': 'bool', 'vmId': 'UUID',
'vmName': 'str', 'vmType': 'VmType', 'memGuaranteedSize': 'uint',
- 'displaySecurePort': 'uint', 'spiceSecureChannels': 'str',
+ '*displaySecurePort': 'uint', 'spiceSecureChannels': 'str',
'username': 'str', 'emulatedMachine': 'str', 'pid': 'uint',
'spiceSslCipherSuite': 'str', 'cpuType': 'str', 'pauseCode': 'str',
- 'guestFQDN': 'str', 'displayIp': 'str', 'keyboardLayout': 'str',
- 'displayPort': 'uint', 'guestIPs': 'str', 'smartcardEnable': 'bool',
+ 'guestFQDN': 'str', '*displayIp': 'str', 'keyboardLayout': 'str',
+ '*displayPort': 'uint', 'guestIPs': 'str', 'smartcardEnable': 'bool',
'nicModel': 'VmInterfaceDeviceModel', 'pitReinjection': 'bool',
'status': 'str', 'clientIp': 'str'}}
@@ -6016,13 +6025,17 @@
#
# Statistics for a running virtual machine.
#
-# @displayPort: The port in use for unencrypted display data
+# @displayPort: #optional The port in use for unencrypted display data
+# (made optional in version 4.15.0)
#
-# @displaySecurePort: The port in use for encrypted display data
+# @displaySecurePort: #optional The port in use for encrypted display data
+# (made optional in version 4.15.0)
#
-# @displayType: The type of display in use
+# @displayType: #optional The type of display in use
+# (made optional in version 4.15.0)
#
-# @displayIp: The IP address to use for accessing the VM display
+# @displayIp: #optional The IP address to use for accessing the VM display
+# (made optional in version 4.15.0)
#
# @pid: The process ID of the underlying qemu process
#
@@ -6089,8 +6102,8 @@
# Since: 4.10.0
##
{'type': 'RunningVmStats',
- 'data': {'displayPort': 'uint', 'displaySecurePort': 'uint',
- 'displayType': 'VmDisplayType', 'displayIp': 'str', 'pid': 'uint',
+ 'data': {'*displayPort': 'uint', '*displaySecurePort': 'uint',
+ '*displayType': 'VmDisplayType', '*displayIp': 'str', 'pid': 'uint',
'vmType': 'VmType', 'kvmEnable': 'bool',
'network': 'NetworkInterfaceStatsMap',
'disks': 'VmDiskStatsMap', 'monitorResponse': 'int',
--
To view, visit http://gerrit.ovirt.org/27846
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iafeb0bebfb43c089614127d94c054175c111ce54
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>