Change in vdsm[master]: GuestIF Refactoring
by Vinzenz Feenstra
Vinzenz Feenstra has uploaded a new change for review.
Change subject: GuestIF Refactoring
......................................................................
GuestIF Refactoring
Change-Id: Ib357d770a26ef1dc80b89a32bf6808551a7d622d
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
M vdsm/guestIF.py
1 file changed, 114 insertions(+), 76 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/18/24618/1
diff --git a/vdsm/guestIF.py b/vdsm/guestIF.py
index 229a55d..96ad68c 100644
--- a/vdsm/guestIF.py
+++ b/vdsm/guestIF.py
@@ -39,6 +39,115 @@
union(set(range(0x86, 0x9F + 1)))
+class UnknownMessageError(Exception):
+ def __init__(self, message, args):
+ Exception.__init__(self, 'Unknown or unsupported guest agent message '
+ '"%s" received with args "%s"' % (message,
+ str(args)))
+
+
+class MessageHandler(object):
+ def __init__(self, agent):
+ self.log = agent.log
+ self._agent = agent
+
+ def __call__(self, message, args):
+ handler = self.getattr(self, message.replace('-', '_'), None)
+ if handler:
+ handler(args)
+ else:
+ raise UnknownMessageError(message, args)
+
+ def applications(self, args):
+ self._agent.guestInfo['appsList'] = args['applications']
+
+ def fqdn(self, args):
+ self._agent.guestInfo['guestFQDN'] = args['fqdn']
+
+ def host_name(self, args):
+ self._agent.guestInfo['guestName'] = args['name']
+
+ def os_version(self, args):
+ self._agent.guestInfo['guestOs'] = args['version']
+
+ def session_lock(self, args):
+ self.agent.guestInfo['session'] = 'Locked'
+
+ def session_logoff(self, args):
+ self.agent.guestInfo['session'] = 'LoggedOff'
+
+ def session_logon(self, args):
+ self.agent.guestInfo['session'] = 'UserLoggedOn'
+
+ def session_unlock(self, args):
+ self.agent.guestInfo['session'] = 'Active'
+
+ def session_shutdown(self, args):
+ self.log.debug('Guest system shuts down')
+
+ def session_startup(self, args):
+ self.log.debug('Guest system started or restarted')
+
+ def uninstalled(self, args):
+ self.log.debug('Guest agent was uninstalled')
+ self._agent.guestInfo['appsList'] = []
+
+ def heartbeat(self, args):
+ self._agent.guestStatus = 'Up'
+ self._agent.guestInfo['memUsage'] = int(args['free-ram'])
+ # ovirt-guest-agent reports the following fields in 'memory-stat':
+ # 'mem_total', 'mem_free', 'mem_unused', 'swap_in', 'swap_out',
+ # 'pageflt' and 'majflt'
+ if 'memory-stat' in args:
+ for (k, v) in args['memory-stat'].iteritems():
+ # Convert the value to string since 64-bit integer is not
+ # supported in XMLRPC
+ self._agent.guestInfo['memoryStats'][k] = str(v)
+
+ if 'apiVersion' in args:
+ # The guest agent supports API Versioning
+ self._agent._handleAPIVersion(args['apiVersion'])
+ elif self._agent.effectiveApiVersion != _IMPLICIT_API_VERSION_ZERO:
+ # Older versions of the guest agent (before the introduction
+ # of API versioning) do not report this field
+ # Disable the API if not already disabled (e.g. after
+ # downgrade of the guest agent)
+ self.log.debug("API versioning no longer reported by guest.")
+ self._agent.effectiveApiVersion = _IMPLICIT_API_VERSION_ZERO
+
+ def network_interfaces(self, args):
+ interfaces = []
+ old_ips = ''
+ for iface in args['interfaces']:
+ iface['inet'] = iface.get('inet', [])
+ iface['inet6'] = iface.get('inet6', [])
+ interfaces.append(iface)
+ # Provide the old information which includes
+ # only the IP addresses.
+ old_ips += ' '.join(iface['inet']) + ' '
+ self._agent.guestInfo['netIfaces'] = interfaces
+ self._agent.guestInfo['guestIPs'] = old_ips.strip()
+
+ def active_user(self, args):
+ currentUser = args['name']
+ if ((currentUser != self._agent.guestInfo['username']) and
+ not (currentUser == 'Unknown' and
+ self._agent.guestInfo['username'] == 'None')):
+ self._agent.guestInfo['username'] = currentUser
+ self._agent.guestInfo['lastLogin'] = time.time()
+ self.log.debug("username: %s", repr(self.guestInfo['username']))
+
+ def disks_usage(self, args):
+ disks = []
+ for disk in args['disks']:
+ # Converting to string because XML-RPC doesn't support 64-bit
+ # integers.
+ disk['total'] = str(disk['total'])
+ disk['used'] = str(disk['used'])
+ disks.append(disk)
+ self._agent.guestInfo['disksUsage'] = disks
+
+
def _filterXmlChars(u):
"""
The set of characters allowed in XML documents is described in
@@ -109,6 +218,7 @@
def __init__(self, socketName, channelListener, log, user='Unknown',
ips='', connect=True):
+ self.handler = MessageHandler(self)
self.effectiveApiVersion = _IMPLICIT_API_VERSION_ZERO
self.log = log
self._socketName = socketName
@@ -223,82 +333,10 @@
self.log.log(logging.TRACE, "Guest's message %s: %s", message, args)
if self.guestStatus is None:
self.guestStatus = 'Up'
- if message == 'heartbeat':
- self.guestStatus = 'Up'
- self.guestInfo['memUsage'] = int(args['free-ram'])
- # ovirt-guest-agent reports the following fields in 'memory-stat':
- # 'mem_total', 'mem_free', 'mem_unused', 'swap_in', 'swap_out',
- # 'pageflt' and 'majflt'
- if 'memory-stat' in args:
- for (k, v) in args['memory-stat'].iteritems():
- # Convert the value to string since 64-bit integer is not
- # supported in XMLRPC
- self.guestInfo['memoryStats'][k] = str(v)
-
- if 'apiVersion' in args:
- # The guest agent supports API Versioning
- self._handleAPIVersion(args['apiVersion'])
- elif self.effectiveApiVersion != _IMPLICIT_API_VERSION_ZERO:
- # Older versions of the guest agent (before the introduction
- # of API versioning) do not report this field
- # Disable the API if not already disabled (e.g. after
- # downgrade of the guest agent)
- self.log.debug("API versioning no longer reported by guest.")
- self.effectiveApiVersion = _IMPLICIT_API_VERSION_ZERO
- elif message == 'host-name':
- self.guestInfo['guestName'] = args['name']
- elif message == 'os-version':
- self.guestInfo['guestOs'] = args['version']
- elif message == 'network-interfaces':
- interfaces = []
- old_ips = ''
- for iface in args['interfaces']:
- iface['inet'] = iface.get('inet', [])
- iface['inet6'] = iface.get('inet6', [])
- interfaces.append(iface)
- # Provide the old information which includes
- # only the IP addresses.
- old_ips += ' '.join(iface['inet']) + ' '
- self.guestInfo['netIfaces'] = interfaces
- self.guestInfo['guestIPs'] = old_ips.strip()
- elif message == 'applications':
- self.guestInfo['appsList'] = args['applications']
- elif message == 'active-user':
- currentUser = args['name']
- if ((currentUser != self.guestInfo['username']) and
- not (currentUser == 'Unknown' and
- self.guestInfo['username'] == 'None')):
- self.guestInfo['username'] = currentUser
- self.guestInfo['lastLogin'] = time.time()
- self.log.debug("username: %s", repr(self.guestInfo['username']))
- elif message == 'session-logon':
- self.guestInfo['session'] = "UserLoggedOn"
- elif message == 'session-lock':
- self.guestInfo['session'] = "Locked"
- elif message == 'session-unlock':
- self.guestInfo['session'] = "Active"
- elif message == 'session-logoff':
- self.guestInfo['session'] = "LoggedOff"
- elif message == 'uninstalled':
- self.log.debug("RHEV agent was uninstalled.")
- self.guestInfo['appsList'] = []
- elif message == 'session-startup':
- self.log.debug("Guest system is started or restarted.")
- elif message == 'fqdn':
- self.guestInfo['guestFQDN'] = args['fqdn']
- elif message == 'session-shutdown':
- self.log.debug("Guest system shuts down.")
- elif message == 'disks-usage':
- disks = []
- for disk in args['disks']:
- # Converting to string because XML-RPC doesn't support 64-bit
- # integers.
- disk['total'] = str(disk['total'])
- disk['used'] = str(disk['used'])
- disks.append(disk)
- self.guestInfo['disksUsage'] = disks
- else:
- self.log.error('Unknown message type %s', message)
+ try:
+ self.handler(message, args)
+ except UnknownMessageError as e:
+ self.log.error(e)
def stop(self):
self._stopped = True
--
To view, visit http://gerrit.ovirt.org/24618
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib357d770a26ef1dc80b89a32bf6808551a7d622d
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>
7 years, 5 months
Change in vdsm[master]: [WIP]vdsm: add support for S3/S4 suspend calls
by mpoledni@redhat.com
Martin Polednik has uploaded a new change for review.
Change subject: [WIP]vdsm: add support for S3/S4 suspend calls
......................................................................
[WIP]vdsm: add support for S3/S4 suspend calls
Change-Id: Ic30016c5cd555f5771dde8db3f1340e1c11b3da7
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/guestIF.py
M vdsm_api/vdsmapi-schema.json
4 files changed, 58 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/89/19389/1
diff --git a/vdsm/API.py b/vdsm/API.py
index 37bb908..96119ed 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -296,6 +296,20 @@
else:
return errCode['nonresp']
+ def desktopSuspend(self, mode):
+ """
+ Sleep the guest operating system
+ """
+ try:
+ v = self._cif.vmContainer[self._UUID]
+ except KeyError:
+ return errCode['noVM']
+ v.guestAgent.desktopSuspend(mode)
+ if v.guestAgent.isResponsive():
+ return {'status': doneCode}
+ else:
+ return errCode['nonresp']
+
def desktopSendHcCommand(self, message):
"""
Send a command to the guest agent (depricated).
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index fb65ad4..046bb0c 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -352,6 +352,10 @@
vm = API.VM(vmId)
return vm.desktopLogoff(force)
+ def vmDesktopSuspend(self, vmId, mode):
+ vm = API.VM(vmId)
+ return vm.desktopSuspend(mode)
+
def vmDesktopLock(self, vmId):
vm = API.VM(vmId)
return vm.desktopLock()
@@ -836,6 +840,7 @@
(self.vmMigrationCreate, 'migrationCreate'),
(self.vmDesktopLogin, 'desktopLogin'),
(self.vmDesktopLogoff, 'desktopLogoff'),
+ (self.vmDesktopSuspend, 'desktopSuspend'),
(self.vmDesktopLock, 'desktopLock'),
(self.vmDesktopSendHcCommand, 'sendHcCmdToDesktop'),
(self.vmHibernate, 'hibernate'),
diff --git a/vdsm/guestIF.py b/vdsm/guestIF.py
index 6f09ef1..2bb654b 100644
--- a/vdsm/guestIF.py
+++ b/vdsm/guestIF.py
@@ -299,6 +299,15 @@
except:
self.log.error("desktopLogoff failed", exc_info=True)
+ def desktopSuspend(self, mode):
+ try:
+ self.log.debug('desktopSleep called')
+ cmds = ('guest-suspend-ram', 'guest-suspend-hybrid',
+ 'guest-suspend-disk')
+ self._forward(cmds['mode'], {'success_response': 'yes'})
+ except:
+ self.log.debug('desktopSleep failed', exc_info=True)
+
def desktopShutdown(self, timeout, msg):
try:
self.log.debug("desktopShutdown called")
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 27c12c1..bc54041 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -5079,6 +5079,36 @@
'data': {'vmID': 'UUID', 'force': 'bool'}}
##
+# @guestSuspendMode
+#
+# Enumeration of supported suspend modes
+#
+# @ram: S3 sleep
+#
+# @disk: S4 sleep
+#
+# @hybrid: Combination of @ram and @disk
+#
+# Since: 4.12.0
+##
+{'enum': 'guestSuspendMode', 'data': ['ram', 'disk', 'hybrid']}
+
+
+##
+# @VM.desktopSuspend:
+#
+# Suspend the guest operating system
+#
+# @vmID: The UUID of the VM
+#
+# @mode: Type of suspension
+#
+# Since: 4.12.0
+##
+{'command': {'class': 'VM', 'name': 'desktopSuspend'},
+ 'data': {'vmID': 'UUID', 'mode': 'guestSuspendMode'}}
+
+##
# @VM.desktopSendHcCommand:
#
# Send an arbitrary command to the guest agent.
--
To view, visit http://gerrit.ovirt.org/19389
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic30016c5cd555f5771dde8db3f1340e1c11b3da7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpoledni(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: vdsm: add support for hot(un)plug of pci-passthrough devices
by mpoledni@redhat.com
Martin Polednik has uploaded a new change for review.
Change subject: vdsm: add support for hot(un)plug of pci-passthrough devices
......................................................................
vdsm: add support for hot(un)plug of pci-passthrough devices
Hot(un)plug ability for pci-passthrough devices is extremely important
in order to allow for hotunplugging/migrating/hotplugging workflow as VM
cannot be migrated with pci device attached.
This patch implements the ability adding new API verbs: hotplugHostdev
and hotunplugHostdev, which attempts to append/remove the device from
domain XML and reports back the state.
Change-Id: I8fbf4a1d62789d9404e5977eb7eb01b17a1a43fb
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/vm.py
M vdsm_api/vdsmapi-schema.json
5 files changed, 166 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/23/22523/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index d549500..f00180e 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -245,6 +245,14 @@
params = {'vmId': args[0], 'drive': drive}
return self.ExecAndExit(self.s.hotunplugDisk(params))
+ def hotplugHostdev(self, args):
+ params = {'vmId': args[0], 'hostdevName': args[1]}
+ return self.ExecAndExit(self.s.hotplugNic(params))
+
+ def hotunplugHostdev(self, args):
+ params = {'vmId': args[0], 'hostdevName': args[2]}
+ return self.ExecAndExit(self.s.hotunplugNic(params))
+
def do_changeCD(self, args):
vmId = args[0]
file = self._parseDriveSpec(args[1])
diff --git a/vdsm/API.py b/vdsm/API.py
index 44d5817..51eb506 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -456,6 +456,40 @@
return curVm.hotunplugDisk(params)
+ def hotplugHostdev(self, params):
+ try:
+ utils.validateMinimalKeySet(params, ('vmId', 'hostdevName'))
+ except ValueError:
+ self.log.error('Missing one of required parameters: vmId, '
+ 'hostdevName')
+ return {'status': {'code': errCode['MissParam']['status']['code'],
+ 'message': 'Missing one of required '
+ 'parameters: vmId, hostdevName'}}
+ try:
+ curVm = self._cif.vmContainer[self._UUID]
+ except KeyError:
+ self.log.warning("vm %s doesn't exist", self._UUID)
+ return errCode['noVM']
+
+ return curVm.hotplugHostdev(params)
+
+ def hotunplugHostdev(self, params):
+ try:
+ utils.validateMinimalKeySet(params, ('vmId', 'hostdevName'))
+ except ValueError:
+ self.log.error('Missing one of required parameters: vmId, '
+ 'hostdevName')
+ return {'status': {'code': errCode['MissParam']['status']['code'],
+ 'message': 'Missing one of required '
+ 'parameters: vmId, hostdevName'}}
+ try:
+ curVm = self._cif.vmContainer[self._UUID]
+ except KeyError:
+ self.log.warning("vm %s doesn't exist", self._UUID)
+ return errCode['noVM']
+
+ return curVm.hotunplugHostdev(params)
+
def migrate(self, params):
"""
Migrate a VM to a remote host.
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 5bcd84c..847ceaf 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -279,6 +279,14 @@
vm = API.VM(params['vmId'])
return vm.hotunplugNic(params)
+ def vmHotplugHostdev(self, params):
+ vm = API.VM(params['vmId'])
+ return vm.hotplugHostdev(params)
+
+ def vmHotunplugHostdev(self, params):
+ vm = API.VM(params['vmId'])
+ return vm.hotunplugHostdev(params)
+
def vmUpdateDevice(self, vmId, params):
vm = API.VM(vmId)
return vm.vmUpdateDevice(params)
@@ -861,6 +869,8 @@
(self.vmHotunplugDisk, 'hotunplugDisk'),
(self.vmHotplugNic, 'hotplugNic'),
(self.vmHotunplugNic, 'hotunplugNic'),
+ (self.vmHotplugHostdev, 'hotplugHostdev'),
+ (self.vmHotunplugHostdev, 'hotunplugHostdev'),
(self.vmUpdateDevice, 'vmUpdateDevice'))
def getIrsMethods(self):
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 90a6c0d..224bf7b 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -3183,6 +3183,84 @@
return {'status': doneCode, 'vmList': self.status()}
+ def hotplugHostdev(self, params):
+ hostdevName = params['hostdevName']
+ hostdev = HostDevice(self.conf, self.log, **hostdevName)
+ hostdevXML = hostdev.getXML().toprettyxml(encoding='utf-8')
+ hostdev._deviceXML = hostdevXML
+ self.log.debug("Hotplug hostdev xml: %s", hostdevXML)
+
+ try:
+ self._dom.attachDevice(hostdevXML)
+ except libvirt.libvirtError as e:
+ self.log.error("Hotplug failed", exc_info=True)
+ if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
+ return errCode['noVM']
+ return {'status': {'code': errCode['hotplugNic']['status']['code'],
+ 'message': e.message}}
+ else:
+ # FIXME! We may have a problem here if vdsm dies right after
+ # we sent command to libvirt and before save conf. In this case
+ # we will gather almost all needed info about this NIC from
+ # the libvirt during recovery process.
+ self._devices[HOSTDEV_DEVICES].append(hostdev)
+ with self._confLock:
+ self.conf['devices'].append(hostdev)
+ self.saveState()
+
+ return {'status': doneCode, 'vmList': self.status()}
+
+ def hotunplugHostdev(self, params):
+ hostdevName = params['hostdevName']
+
+ # Find hostdev object in vm's hostdev list
+ hostdev = None
+ for dev in self._devices[HOSTDEV_DEVICES][:]:
+ if dev.name == hostdevName:
+ hostdev = dev
+ break
+
+ if hostdev:
+ hostdevXML = hostdev.getXML().toprettyxml(encoding='utf-8')
+ self.log.debug("Hotunplug hostdev xml: %s", hostdevXML)
+ self._devices[HOSTDEV_DEVICES].remove(hostdev)
+ else:
+ self.log.error("Hotunplug hostdev failed - hostdev not found: %s",
+ hostdevName)
+ return {'status': {'code': errCode['hotunplugNic']
+ ['status']['code'],
+ 'message': "NIC not found"}}
+
+ hostdevDev = None
+ for dev in self.conf['devices'][:]:
+ if (dev['type'] == HOSTDEV_DEVICES and
+ dev['name'] == hostdevName):
+ hostdevDev = dev
+ with self._confLock:
+ self.conf['devices'].remove(dev)
+ break
+
+ self.saveState()
+
+ try:
+ self._dom.detachDevice(hostdevXML)
+ except libvirt.libvirtError as e:
+ self.log.error("Hotunplug failed", exc_info=True)
+ if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
+ return errCode['noVM']
+ # Restore hostdev device in vm's conf and _devices
+ if hostdevDev:
+ with self._confLock:
+ self.conf['devices'].append(hostdevDev)
+ if hostdev:
+ self._devices[HOSTDEV_DEVICES].append(hostdev)
+ self.saveState()
+ return {
+ 'status': {'code': errCode['hotunplugNic']['status']['code'],
+ 'message': e.message}}
+
+ return {'status': doneCode, 'vmList': self.status()}
+
def _lookupDeviceByAlias(self, devType, alias):
for dev in self._devices[devType][:]:
if dev.alias == alias:
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 1d4e499..85f2b28 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -5793,6 +5793,42 @@
'returns': 'VmDefinition'}
##
+# @VM.hotplugHostdev:
+#
+# Add a new host device to a running VM.
+#
+# @vmID: The UUID of the VM
+#
+# @hostdevName: The name of host's device
+#
+# Returns:
+# The VM definition, as updated
+#
+# Since: 4.14.0
+##
+{'command': {'class': 'VM', 'name': 'hotplugHostdev'},
+ 'data': {'vmID': 'UUID', 'hostdevName': 'str'},
+ 'returns': 'VmDefinition'}
+
+##
+# @VM.hotunplugHostdev:
+#
+# Remove a host device from a running VM.
+#
+# @vmID: The UUID of the VM
+#
+# @hostdevName: The name of host's device
+#
+# Returns:
+# The VM definition, as updated
+#
+# Since: 4.14.0
+##
+{'command': {'class': 'VM', 'name': 'hotunplugHostdev'},
+ 'data': {'vmID': 'UUID', 'hostdevName': 'str'},
+ 'returns': 'VmDefinition'}
+
+##
# @MigrateMode:
#
# An enumeration of VM migration modes.
--
To view, visit http://gerrit.ovirt.org/22523
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8fbf4a1d62789d9404e5977eb7eb01b17a1a43fb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpoledni(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: image: unify the prezeroing optimizations
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: image: unify the prezeroing optimizations
......................................................................
image: unify the prezeroing optimizations
The same prezeroing optimization logic was used in multiple places, this
patch unifies it in __optimizedCreateVolume.
Change-Id: I0fd90f85e9debf98bcac07d1b8d4b38c319c33f2
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/image.py
1 file changed, 43 insertions(+), 45 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/04/8504/1
diff --git a/vdsm/storage/image.py b/vdsm/storage/image.py
index e86d94c..19ab078 100644
--- a/vdsm/storage/image.py
+++ b/vdsm/storage/image.py
@@ -454,6 +454,37 @@
except Exception:
self.log.error("Unexpected error", exc_info=True)
+ def __optimizedCreateVolume(self, domain, imgUUID, size, apparentSize,
+ volFormat, preallocate, diskType, volUUID, desc, srcImgUUID,
+ srcVolUUID):
+ # To avoid 'prezeroing' preallocated volume on NFS domain,
+ # we create the target volume with minimal size and after
+ # that we'll change its metadata back to the original size.
+ if (volFormat == volume.COW_FORMAT
+ or preallocate == volume.SPARSE_VOL):
+ volTmpSize = size
+ else:
+ volTmpSize = TEMPORARY_VOLUME_SIZE
+
+ domain.createVolume(imgUUID, volTmpSize, volFormat, preallocate,
+ diskType, volUUID, desc, srcImgUUID, srcVolUUID)
+ newVolume = domain.produceVolume(imgUUID, volUUID)
+
+ if volFormat == volume.RAW_FORMAT:
+ extendSize = size
+ else:
+ extendSize = apparentSize
+
+ # Extend volume (for LV only) size to the actual size
+ newVolume.extend((extendSize + 511) / 512)
+
+ # Change destination volume metadata back to the original
+ # size. Heavy operation, do it only if necessary.
+ if volTmpSize != size:
+ newVolume.setSize(size)
+
+ return newVolume
+
def _createTargetImage(self, destDom, srcSdUUID, imgUUID):
# Before actual data copying we need perform several operation
# such as: create all volumes, create fake template if needed, ...
@@ -500,34 +531,12 @@
# find out src volume parameters
volParams = srcVol.getVolumeParams(bs=1)
- # To avoid 'prezeroing' preallocated volume on NFS domain,
- # we create the target volume with minimal size and after
- # that w'll change its metadata back to the original size.
- if (volParams['volFormat'] == volume.COW_FORMAT
- or volParams['prealloc'] == volume.SPARSE_VOL):
- volTmpSize = volParams['size']
- else:
- volTmpSize = TEMPORARY_VOLUME_SIZE # in sectors (10M)
-
- destDom.createVolume(imgUUID=imgUUID, size=volTmpSize,
- volFormat=volParams['volFormat'],
- preallocate=volParams['prealloc'],
- diskType=volParams['disktype'],
- volUUID=srcVol.volUUID,
- desc=volParams['descr'],
- srcImgUUID=pimg,
- srcVolUUID=volParams['parent'])
-
- dstVol = destDom.produceVolume(imgUUID=imgUUID,
- volUUID=srcVol.volUUID)
-
- # Extend volume (for LV only) size to the actual size
- dstVol.extend((volParams['apparentsize'] + 511) / 512)
-
- # Change destination volume metadata back to the original
- # size.
- if volTmpSize != volParams['size']:
- dstVol.setSize(volParams['size'])
+ dstVol = self.__optimizedCreateVolume(
+ destDom, imgUUID, volParams['size'],
+ volParams['apparentsize'], volParams['volFormat'],
+ volParams['prealloc'], volParams['disktype'],
+ srcVol.volUUID, volParams['descr'], srcImgUUID=pimg,
+ srcVolUUID=volParams['parent'])
dstChain.append(dstVol)
except se.StorageException:
@@ -760,25 +769,14 @@
self.log.info("delete image %s on domain %s before overwriting", dstImgUUID, dstSdUUID)
self.delete(dstSdUUID, dstImgUUID, postZero, force=True)
- # To avoid 'prezeroing' preallocated volume on NFS domain,
- # we create the target volume with minimal size and after that w'll change
- # its metadata back to the original size.
- tmpSize = TEMPORARY_VOLUME_SIZE # in sectors (10M)
- destDom.createVolume(imgUUID=dstImgUUID, size=tmpSize,
- volFormat=dstVolFormat, preallocate=volParams['prealloc'],
- diskType=volParams['disktype'], volUUID=dstVolUUID, desc=descr,
- srcImgUUID=volume.BLANK_UUID, srcVolUUID=volume.BLANK_UUID)
+ dstVol = self.__optimizedCreateVolume(
+ destDom, dstImgUUID, volParams['size'],
+ volParams['apparentsize'], dstVolFormat,
+ volParams['prealloc'], volParams['disktype'],
+ dstVolUUID, descr, volume.BLANK_UUID,
+ volume.BLANK_UUID)
- dstVol = sdCache.produce(dstSdUUID).produceVolume(imgUUID=dstImgUUID, volUUID=dstVolUUID)
- # For convert to 'raw' we need use the virtual disk size instead of apparent size
- if dstVolFormat == volume.RAW_FORMAT:
- newsize = volParams['size']
- else:
- newsize = volParams['apparentsize']
- dstVol.extend(newsize)
dstPath = dstVol.getVolumePath()
- # Change destination volume metadata back to the original size.
- dstVol.setSize(volParams['size'])
except se.StorageException, e:
self.log.error("Unexpected error", exc_info=True)
raise
--
To view, visit http://gerrit.ovirt.org/8504
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0fd90f85e9debf98bcac07d1b8d4b38c319c33f2
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: [wip] sdcache: avoid extra refresh due samplingmethod
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: [wip] sdcache: avoid extra refresh due samplingmethod
......................................................................
[wip] sdcache: avoid extra refresh due samplingmethod
In order to avoid an extra iscsi rescan (symptomatic of samplingmethod)
an additional lock has been introduced to queue the requests when the
storage is flagged as stale.
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=870768
Change-Id: If178a8eaeb94f1dfe9e0957036dde88f6a22829c
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/sdc.py
1 file changed, 25 insertions(+), 26 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/74/9274/1
diff --git a/vdsm/storage/sdc.py b/vdsm/storage/sdc.py
index f2f4534..978e3fa 100644
--- a/vdsm/storage/sdc.py
+++ b/vdsm/storage/sdc.py
@@ -62,32 +62,27 @@
STORAGE_UPDATED = 0
STORAGE_STALE = 1
- STORAGE_REFRESHING = 2
def __init__(self, storage_repo):
- self._syncroot = threading.Condition()
+ self._syncDomain = threading.Condition()
+ self._syncRefresh = threading.Lock()
self.__domainCache = {}
self.__inProgress = set()
self.__staleStatus = self.STORAGE_STALE
self.storage_repo = storage_repo
def invalidateStorage(self):
- with self._syncroot:
- self.__staleStatus = self.STORAGE_STALE
+ self.log.debug("The storages have been invalidated")
+ self.__staleStatus = self.STORAGE_STALE
@misc.samplingmethod
def refreshStorage(self):
- self.__staleStatus = self.STORAGE_REFRESHING
-
+ # We need to set the __staleStatus value at the beginning because we
+ # want to keep track of the future invalidateStorage calls that might
+ # arrive during the rescan procedure.
+ self.__staleStatus = self.STORAGE_UPDATED
multipath.rescan()
lvm.invalidateCache()
-
- # If a new invalidateStorage request came in after the refresh
- # started then we cannot flag the storages as updated (force a
- # new rescan later).
- with self._syncroot:
- if self.__staleStatus == self.STORAGE_REFRESHING:
- self.__staleStatus = self.STORAGE_UPDATED
def produce(self, sdUUID):
domain = DomainProxy(self, sdUUID)
@@ -98,7 +93,7 @@
return domain
def _realProduce(self, sdUUID):
- with self._syncroot:
+ with self._syncDomain:
while True:
domain = self.__domainCache.get(sdUUID)
@@ -109,25 +104,29 @@
self.__inProgress.add(sdUUID)
break
- self._syncroot.wait()
+ self._syncDomain.wait()
try:
- # If multiple calls reach this point and the storage is not
- # updated the refreshStorage() sampling method is called
- # serializing (and eventually grouping) the requests.
- if self.__staleStatus != self.STORAGE_UPDATED:
- self.refreshStorage()
+ # Here we cannot take full advantage of the refreshStorage
+ # samplingmethod since we might be scheduling an unneeded
+ # extra rescan. We need an additional lock (_syncRefresh)
+ # to make sure that __staleStatus is taken in account
+ # (without affecting all the other external refreshStorage
+ # calls as it would be if we move this check there).
+ with self._syncRefresh:
+ if self.__staleStatus != self.STORAGE_UPDATED:
+ self.refreshStorage()
domain = self._findDomain(sdUUID)
- with self._syncroot:
+ with self._syncDomain:
self.__domainCache[sdUUID] = domain
return domain
finally:
- with self._syncroot:
+ with self._syncDomain:
self.__inProgress.remove(sdUUID)
- self._syncroot.notifyAll()
+ self._syncDomain.notifyAll()
def _findDomain(self, sdUUID):
import blockSD
@@ -162,16 +161,16 @@
return uuids
def refresh(self):
- with self._syncroot:
+ with self._syncDomain:
lvm.invalidateCache()
self.__domainCache.clear()
def manuallyAddDomain(self, domain):
- with self._syncroot:
+ with self._syncDomain:
self.__domainCache[domain.sdUUID] = domain
def manuallyRemoveDomain(self, sdUUID):
- with self._syncroot:
+ with self._syncDomain:
try:
del self.__domainCache[sdUUID]
except KeyError:
--
To view, visit http://gerrit.ovirt.org/9274
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If178a8eaeb94f1dfe9e0957036dde88f6a22829c
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: sp: load dumped tasks when recovering
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: sp: load dumped tasks when recovering
......................................................................
sp: load dumped tasks when recovering
Change-Id: I1cd2ea34c2013870b213d8baa471248adabfbbe3
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/sp.py
1 file changed, 1 insertion(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/02/26902/1
diff --git a/vdsm/storage/sp.py b/vdsm/storage/sp.py
index 338232f..e6a6bd0 100644
--- a/vdsm/storage/sp.py
+++ b/vdsm/storage/sp.py
@@ -288,8 +288,6 @@
self.log.error("Backup domain validation failed",
exc_info=True)
- self.taskMng.loadDumpedTasks(self.tasksDir)
-
self.spmRole = SPM_ACQUIRED
# Once setSecure completes we are running as SPM
@@ -322,6 +320,7 @@
# Restore tasks is last because tasks are spm ops (spm has to
# be started)
+ self.taskMng.loadDumpedTasks(self.tasksDir)
self.taskMng.recoverDumpedTasks()
self.log.debug("ended.")
--
To view, visit http://gerrit.ovirt.org/26902
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1cd2ea34c2013870b213d8baa471248adabfbbe3
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: task: support task id in client request
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: task: support task id in client request
......................................................................
task: support task id in client request
Change-Id: Ib5034e6c3466d5a663699d4f924975b7e067c768
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/BindingXMLRPC.py
M vdsm/clientIF.py
M vdsm/storage/dispatcher.py
3 files changed, 16 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/09/26809/1
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 76251f5..d449088 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -98,6 +98,7 @@
Create xml-rpc server over http or https.
"""
HTTP_HEADER_FLOWID = "FlowID"
+ HTTP_HEADER_TASKID = "TaskID"
threadLocal = self.cif.threadLocal
@@ -200,6 +201,7 @@
def parse_request(self):
r = basehandler.parse_request(self)
threadLocal.flowID = self.headers.get(HTTP_HEADER_FLOWID)
+ threadLocal.taskID = self.headers.get(HTTP_HEADER_TASKID)
return r
def finish(self):
@@ -207,6 +209,7 @@
threadLocal.client = None
threadLocal.server = None
threadLocal.flowID = None
+ threadLocal.taskID = None
if sys.version_info[:2] == (2, 6):
# Override BaseHTTPServer.BaseRequestHandler implementation to
@@ -246,6 +249,10 @@
fmt += " flowID [%s]"
logargs.append(self.cif.threadLocal.flowID)
+ if getattr(self.cif.threadLocal, 'taskID', None) is not None:
+ fmt += " taskID [%s]"
+ logargs.append(self.cif.threadLocal.taskID)
+
self.log.debug(fmt, *logargs)
try:
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index eac7950..21e3c71 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -99,6 +99,7 @@
self.channelListener.start()
self.threadLocal = threading.local()
self.threadLocal.client = ''
+ self.irs.setClientThreadLocal(self.threadLocal)
except:
self.log.error('failed to init clientIF, '
'shutting down storage dispatcher')
diff --git a/vdsm/storage/dispatcher.py b/vdsm/storage/dispatcher.py
index 6586492..3e2bf0a 100644
--- a/vdsm/storage/dispatcher.py
+++ b/vdsm/storage/dispatcher.py
@@ -45,10 +45,14 @@
self.storage_repository = config.get('irs', 'repository')
self._exposeFunctions(obj)
self.log.info("Starting StorageDispatcher...")
+ self._clientThreadLocal = None
@property
def ready(self):
return getattr(self._obj, 'ready', True)
+
+ def setClientThreadLocal(self, clientThreadLocal):
+ self._clientThreadLocal = clientThreadLocal
def _exposeFunctions(self, obj):
for funcName in dir(obj):
@@ -66,7 +70,10 @@
@wraps(func)
def wrapper(*args, **kwargs):
try:
- ctask = task.Task(id=None, name=name)
+ ctaskid = getattr(self._clientThreadLocal, 'taskID', None)
+ if ctaskid is not None:
+ self.log.info('using client requested taskID %s', ctaskid)
+ ctask = task.Task(id=ctaskid, name=name)
try:
response = self.STATUS_OK.copy()
result = ctask.prepare(func, *args, **kwargs)
--
To view, visit http://gerrit.ovirt.org/26809
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib5034e6c3466d5a663699d4f924975b7e067c768
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: volume: prepare only one volume on clone
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: volume: prepare only one volume on clone
......................................................................
volume: prepare only one volume on clone
When we are cloning a volume we need only
Change-Id: Idc009fac4dc1a258537b0ffb15bd627680d79330
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/storage/volume.py
1 file changed, 3 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/20/26920/1
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index e1d3fc7..a36914f 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -271,7 +271,7 @@
wasleaf = True
self.setInternal()
try:
- self.prepare(rw=False)
+ self.prepare(rw=False, justme=True)
dst_path = os.path.join(dst_image_dir, dst_volUUID)
self.log.debug('cloning volume %s to %s', self.volumePath,
dst_path)
@@ -283,15 +283,15 @@
qemuimg.create(dst_path, backing=parent,
format=fmt2str(volFormat),
backingFormat=fmt2str(self.getFormat()))
- self.teardown(self.sdUUID, self.volUUID)
except Exception as e:
self.log.exception('cannot clone volume %s to %s',
self.volumePath, dst_path)
# FIXME: might race with other clones
if wasleaf:
self.setLeaf()
- self.teardown(self.sdUUID, self.volUUID)
raise se.CannotCloneVolume(self.volumePath, dst_path, str(e))
+ finally:
+ self.teardown(self.sdUUID, self.volUUID, justme=True)
def _shareLease(self, dstImgPath):
"""
--
To view, visit http://gerrit.ovirt.org/26920
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idc009fac4dc1a258537b0ffb15bd627680d79330
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: [WIP] BZ#844656 Release the lock during _findDomain
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: [WIP] BZ#844656 Release the lock during _findDomain
......................................................................
[WIP] BZ#844656 Release the lock during _findDomain
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
Change-Id: I8088d5fe716a3a08c3e5cef2d2d9a654ee96f60a
---
M vdsm/storage/sdc.py
1 file changed, 21 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/22/6822/1
--
To view, visit http://gerrit.ovirt.org/6822
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8088d5fe716a3a08c3e5cef2d2d9a654ee96f60a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 5 months
Change in vdsm[master]: get the status of core dump
by shaohef@linux.vnet.ibm.com
ShaoHe Feng has uploaded a new change for review.
Change subject: get the status of core dump
......................................................................
get the status of core dump
Change-Id: I5d552db4dbd88762950ec5a113a25c13b73319c8
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/vm.py
M vdsm_api/vdsmapi-schema.json
M vdsm_cli/vdsClient.py
5 files changed, 36 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/31/11131/1
diff --git a/vdsm/API.py b/vdsm/API.py
index c5f7d40..6b4663a 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -302,6 +302,15 @@
return errCode['noVM']
return v.dumpCancel()
+ def dumpStatus(self):
+ """
+ Report status of a currently outgoing core dump process.
+ """
+ v = self._cif.vmContainer.get(self._UUID)
+ if not v:
+ return errCode['noVM']
+ return v.dumpStatus()
+
def desktopLock(self):
"""
Lock user session in guest operating system using guest agent.
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 17d97b1..b1f22fd 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -219,6 +219,10 @@
vm = API.VM(vmId)
return vm.dumpCancel()
+ def vmCoreDumpStatus(self, vmId):
+ vm = API.VM(vmId)
+ return vm.dumpStatus()
+
def vmReset(self, vmId):
vm = API.VM(vmId)
return vm.reset()
@@ -769,6 +773,7 @@
(self.vmCont, 'cont'),
(self.vmCoreDump, 'coreDump'),
(self.vmCoreDumpCancel, 'dumpCancel'),
+ (self.vmCoreDumpStatus, 'dumpStatus'),
(self.vmSnapshot, 'snapshot'),
(self.vmMerge, 'merge'),
(self.vmMergeStatus, 'mergeStatus'),
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 0a40e97..5d9c0d9 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -1371,3 +1371,6 @@
return reportError(msg=e.message)
finally:
self._guestCpuLock.release()
+
+ def dumpStatus(self):
+ return self._doCoredumpThread.getStat()
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 39d1cba..e96f01f 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -5484,6 +5484,16 @@
{'command': {'class': 'VM', 'name': 'dumpCancel'}}
##
+# @VM.dumpStatus:
+#
+# Reports the state of the currently core dump process
+#
+# Since: 4.10.4
+#
+##
+{'command': {'class': 'VM', 'name': 'dumpStatus'}}
+
+##
# @VM.monitorCommand:
#
# Send a command to the qemu monitor.
diff --git a/vdsm_cli/vdsClient.py b/vdsm_cli/vdsClient.py
index 32ad348..7edc674 100644
--- a/vdsm_cli/vdsClient.py
+++ b/vdsm_cli/vdsClient.py
@@ -1674,6 +1674,11 @@
response = self.s.dumpCancel(vmId)
return response['status']['code'], response['status']['message']
+ def do_dumpStat(self, args):
+ vmId = args[0]
+ response = self.s.dumpStatus(vmId)
+ return response['status']['code'], response['status']['message']
+
def coreDump(self, args):
dumpParams = {'crash': False,
'live': False,
@@ -2422,6 +2427,10 @@
('<vmId>',
'cancel machine core dump'
)),
+ 'coreDumpStatus': (serv.do_dumpStat,
+ ('<vmId>',
+ 'Check the progress of current core dump'
+ )),
'coreDump': (serv.coreDump,
('<vmId> <file> [live=<True|False>] '
'[crash=<True|False>] [bypass-cache=<True|False>] '
--
To view, visit http://gerrit.ovirt.org/11131
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d552db4dbd88762950ec5a113a25c13b73319c8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
8 years, 5 months