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, 7 months
Change in vdsm[master]: fencing: Make getHostLeaseStatus API public
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: fencing: Make getHostLeaseStatus API public
......................................................................
fencing: Make getHostLeaseStatus API public
Getting host lease status will allow engine to make smarter decisions
when a host is non-responsive by using a proxy host to get the
non-responsive host status.
See http://pastebin.com/KqqeAdSu for example output from this API.
Change-Id: I415c1fee6256bf8d4e03ee542cc58e193162e9b8
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/rpc/BindingXMLRPC.py
M vdsm/rpc/Bridge.py
M vdsm/rpc/vdsmapi-schema.json
5 files changed, 62 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/57/29157/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index 2c09b28..aea1503 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -1760,6 +1760,18 @@
status = self.s.stopMonitoringDomain(sdUUID)
return status['status']['code'], status['status']['message']
+ def getHostLeaseStatus(self, args):
+ domains = {}
+ for pair in args:
+ sdUUID, hostId = pair.split('=', 1)
+ domains[sdUUID] = int(hostId)
+ response = self.s.getHostLeaseStatus(domains)
+ if response['status']['code']:
+ print "Cannot get host storage liveliness"
+ return response['status']['code'], response['status']['message']
+ pp.pprint(response['domains'])
+ return 0, ''
+
def snapshot(self, args):
vmUUID, sdUUID, imgUUID, baseVolUUID, volUUID = args
@@ -2579,6 +2591,11 @@
('<sdUUID>',
'Stop monitoring SD: sdUUID'
)),
+ 'getHostLeaseStatus': (serv.getHostLeaseStatus,
+ ('<sdUUID>=<hostId> [<sdUUID>=<hostId>] ...',
+ 'Returns host lease status for hostId on '
+ 'each domain.'
+ )),
'snapshot': (serv.snapshot,
('<vmId> <sdUUID> <imgUUID> <baseVolUUID> <volUUID>',
'Take a live snapshot'
diff --git a/vdsm/API.py b/vdsm/API.py
index e739294..0b44459 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1497,6 +1497,9 @@
def stopMonitoringDomain(self, sdUUID):
return self._irs.stopMonitoringDomain(sdUUID)
+ def getHostLeaseStatus(self, domains):
+ return self._irs.getHostLeaseStatus(domains)
+
def getLVMVolumeGroups(self, storageType=None):
return self._irs.getVGList(storageType)
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index c1c7490..a06a3b4 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -917,6 +917,10 @@
api = API.Global()
return api.stopMonitoringDomain(sdUUID)
+ def getHostLeaseStatus(self, domains, options=None):
+ api = API.Global()
+ return api.getHostLeaseStatus(domains)
+
def vgsGetList(self, storageType=None, options=None):
api = API.Global()
return api.getLVMVolumeGroups(storageType)
@@ -1070,6 +1074,7 @@
(self.storageRepoGetStats, 'repoStats'),
(self.startMonitoringDomain, 'startMonitoringDomain'),
(self.stopMonitoringDomain, 'stopMonitoringDomain'),
+ (self.getHostLeaseStatus, 'getHostLeaseStatus'),
(self.vgsGetList, 'getVGList'),
(self.devicesGetList, 'getDeviceList'),
(self.devicesGetVisibility, 'getDevicesVisibility'),
diff --git a/vdsm/rpc/Bridge.py b/vdsm/rpc/Bridge.py
index 7e898de..ba700d1 100644
--- a/vdsm/rpc/Bridge.py
+++ b/vdsm/rpc/Bridge.py
@@ -349,6 +349,7 @@
'Host_getStorageRepoStats': {'ret': Host_getStorageRepoStats_Ret},
'Host_startMonitoringDomain': {},
'Host_stopMonitoringDomain': {},
+ 'Host_getHostLeaseStatus': {'ret': 'domains'},
'Host_getVMList': {'call': Host_getVMList_Call, 'ret': Host_getVMList_Ret},
'Host_getVMFullList': {'call': Host_getVMFullList_Call, 'ret': 'vmList'},
'Host_getAllVmStats': {'ret': 'statsList'},
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index 0c8a6f6..7617185 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -2052,6 +2052,42 @@
'returns': ''}
##
+# @HostIdMap:
+#
+# A mapping of hostId indexed by domain UUID.
+#
+# Since: 4.15.0
+##
+{'map': 'HostIdMap',
+ 'key': 'UUID', 'value': 'int'}
+
+##
+# @HostLeaseStatusMap:
+#
+# A mapping of status codes indexed by domain UUID.
+#
+# Since: 4.15.0
+##
+{'map': 'HostLeaseStatusMap',
+ 'key': 'UUID', 'value': 'str'}
+
+##
+# @Host.getHostLeaseStatus:
+#
+# Returns host status for for specified domains
+#
+# @domains: A mapping of hostId indexed by domain UUID
+#
+# Returns:
+# Host status code for each domain
+#
+# Since: 4.15.0
+##
+{'command': {'class': 'Host', 'name': 'getHostLeaseStatus'},
+ 'data': {'domains': 'HostIdMap'}
+ 'returns': {'domains': 'HostLeaseStatusMap'}}
+
+##
# @VmStatus:
#
# An enumeration of possible virtual machine statuses.
--
To view, visit http://gerrit.ovirt.org/29157
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I415c1fee6256bf8d4e03ee542cc58e193162e9b8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
7 years, 7 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, 6 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, 6 months
Change in vdsm[master]: vdsmcli: Add a contrib command line client alternative
by asegurap@redhat.com
Antoni Segura Puimedon has uploaded a new change for review.
Change subject: vdsmcli: Add a contrib command line client alternative
......................................................................
vdsmcli: Add a contrib command line client alternative
This command line client is built by hand for the convenience of
developers and requires the click library:
pip install click
It easily supports commands and subcommands. For example:
vdsmcli network
is a command and 'show' and 'add' are its subcommands.
Examples:
toniel602 ~ # vdsmcli network show -k nics -k networks
============================================= Nics
eth6
eth5
eth4
eth3
eth2
eth1
============================================= Networks
foo
or
toniel602 ~ # vdsmcli --verbode --pprint network show -k networks
============================================= Networks
===============
foo
===============
{'addr': '',
'bootproto4': 'none',
'bridged': False,
'gateway': '',
'iface': 'bond42',
'interface': 'bond42',
'ipv6addrs': ['2620:52:0:223c:201:a4ff:feac:8796/64',
'fe80::201:a4ff:feac:8796/64'],
'ipv6gateway': 'fe80:52:0:223c::3fe',
'mtu': '1500',
'netmask': ''}
addition
toniel602 ~ # ./cvdsm.py -v -p network add foo --bridgeless --nic eth4
--nic eth5 --bond bond42
Networks: {u'foo': {'bonding': u'bond42', 'bridged': False}}
Bonds: {u'bond42': {'nics': (u'eth4', u'eth5')}}
Succeeded. Done
One could extend it with a vm command so that it was easy to do:
vdsmcli vm hotplug 34f5f608-91ed-48d1-af31-c3a3d788678e nic --mac 00:11:22:33:44:55 --model virtio
Change-Id: Ie5574b2b34f0b7b2174e9da0c4487f812ff20f5b
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
A contrib/vdsmcli.py
1 file changed, 113 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/52/28152/1
diff --git a/contrib/vdsmcli.py b/contrib/vdsmcli.py
new file mode 100644
index 0000000..2255201
--- /dev/null
+++ b/contrib/vdsmcli.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python2
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+"""This is a command line client for vdsm."""
+
+from pprint import pformat
+
+import click
+
+from vdsm import netinfo, vdscli
+
+_NET_DEVICE_TYPES = ('networks', 'bridges', 'vlans', 'bondings', 'nics')
+
+
+class Options(object):
+ def __init__(self, verbose=None, pprint=None):
+ self.verbose = verbose
+ self.pprint = pprint
+
+
+(a)click.group()
+(a)click.option('-v', '--verbose', is_flag=True)
+(a)click.option('-p', '--pprint', is_flag=True)
+(a)click.pass_context
+def cli(ctx, verbose, pprint):
+ ctx.obj = Options(verbose, pprint)
+
+
+(a)cli.group()
+(a)click.pass_obj
+def network(options):
+ """Network actions and information displaying."""
+ pass
+
+
+(a)network.command(help='Configure network')
+(a)click.pass_obj
+(a)click.option('--bridged/--bridgeless', default=True)
+(a)click.option('--vlan', default=None, type=click.INT)
+(a)click.option('--bond', default=None)
+(a)click.option('--bond-opts', default=None)
+(a)click.option('--nic', multiple=True)
+(a)click.argument('name')
+(a)click.argument('extra_attributes', required=False, nargs=-1)
+def add(options, bridged, vlan, bond, bond_opts, nic, name, extra_attributes):
+ conn = vdscli.connect()
+ networks = {name: {'bridged': bridged}}
+ if vlan:
+ networks[name]['vlan'] = vlan
+ if len(nic) == 1:
+ networks[name]['nic'] = nic[0]
+ if bond:
+ networks[name]['bonding'] = bond
+ bonds = {bond: {'nics': nic}}
+ if bond_opts:
+ bonds[bond]['options'] = bond_opts
+ else:
+ bonds = {}
+
+ for key, value in (elem.split('=') for elem in extra_attributes):
+ networks[name][key] = value
+
+ if options.verbose:
+ click.echo('Networks: %s' % (pformat(networks) if options.pprint else
+ networs))
+ click.echo('Bonds: %s' % (pformat(bonds) if options.pprint else bonds))
+ result = conn.setupNetworks(networks, bonds, {'connectivityCheck': False})
+ code = result['status']['code']
+ message = result['status']['message']
+ click.echo('%s. %s' % ('Succeeded' if code == 0 else 'Failed', message))
+
+
+(a)network.command(help='show network and net device information')
+(a)click.pass_obj
+(a)click.option('--kind', '-k', multiple=True, type=click.Choice(
+ _NET_DEVICE_TYPES))
+def show(options, kind):
+ if not kind:
+ kind = ('networks',)
+ conn = vdscli.connect()
+ info = netinfo.NetInfo(conn.getVdsCapabilities()['info'])
+ for k in kind:
+ click.echo('')
+ click.echo('=' * 45, nl=False)
+ click.echo(' ' + k[0].upper() + k[1:])
+ for name, attrs in getattr(info, k).iteritems():
+ if options.verbose:
+ click.echo('=' * 15)
+ click.echo(name)
+ if options.verbose:
+ click.echo('=' * 15)
+ click.echo(pformat(attrs) if options.pprint else attrs)
+ click.echo('')
+
+
+if __name__ == '__main__':
+ cli()
--
To view, visit http://gerrit.ovirt.org/28152
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie5574b2b34f0b7b2174e9da0c4487f812ff20f5b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: volume: support multi line metadata values
by laravot@redhat.com
Liron Ar has uploaded a new change for review.
Change subject: volume: support multi line metadata values
......................................................................
volume: support multi line metadata values
Currently when creating the metadata dict it's assumed that each value
can be in a single line only while it's not necessarily true.
Change-Id: Ib03152b852294f7b69a8734c2aa1206ea2c1fabe
Signed-off-by: Liron Aravot <laravot(a)redhat.com>
---
M vdsm/storage/blockVolume.py
M vdsm/storage/volume.py
2 files changed, 12 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/93/28493/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index d448e00..d7cf020 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -580,7 +580,6 @@
self.log.error(e, exc_info=True)
raise se.VolumeMetadataReadError("%s: %s" % (metaId, e))
-
def setMetadata(self, meta, metaId=None):
"""
Set the meta data hash as the new meta data of the Volume
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index aed932e..bfc1ff1 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -814,19 +814,27 @@
"""
pass
-
def metadata2dict(self, meta):
out = {}
+ key = None
+ value = None
+
+ def put(key, value):
+ out[key.strip()] = "\n".join(value).strip()
+
for l in meta:
if l.startswith("EOF"):
- return out
+ break
if l.find("=") < 0:
+ value.append(l)
continue
+ if key:
+ put(key, value)
key, value = l.split("=")
- out[key.strip()] = value.strip()
+ value = [value]
+ put(key, value)
return out
-
def metadata2info(self, meta):
return {
--
To view, visit http://gerrit.ovirt.org/28493
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib03152b852294f7b69a8734c2aa1206ea2c1fabe
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Liron Ar <laravot(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: volume: move metadata dict creation to volume.py
by laravot@redhat.com
Liron Ar has uploaded a new change for review.
Change subject: volume: move metadata dict creation to volume.py
......................................................................
volume: move metadata dict creation to volume.py
Change-Id: I26c495d437fe327a4029fe1dae087d182ba6611b
Signed-off-by: Liron Aravot <laravot(a)redhat.com>
---
M vdsm/storage/blockVolume.py
M vdsm/storage/fileVolume.py
M vdsm/storage/volume.py
3 files changed, 16 insertions(+), 19 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/92/28492/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index 81331fa..d448e00 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -574,20 +574,12 @@
try:
meta = misc.readblock(lvm.lvPath(vgname, sd.METADATA),
offs * VOLUME_METASIZE, VOLUME_METASIZE)
- out = {}
- for l in meta:
- if l.startswith("EOF"):
- return out
- if l.find("=") < 0:
- continue
- key, value = l.split("=")
- out[key.strip()] = value.strip()
+ return self.metadata2dict(meta)
except Exception as e:
self.log.error(e, exc_info=True)
raise se.VolumeMetadataReadError("%s: %s" % (metaId, e))
- return out
def setMetadata(self, meta, metaId=None):
"""
diff --git a/vdsm/storage/fileVolume.py b/vdsm/storage/fileVolume.py
index 654818e..6b655b8 100644
--- a/vdsm/storage/fileVolume.py
+++ b/vdsm/storage/fileVolume.py
@@ -294,20 +294,11 @@
try:
f = self.oop.directReadLines(metaPath)
- out = {}
- for l in f:
- if l.startswith("EOF"):
- return out
- if l.find("=") < 0:
- continue
- key, value = l.split("=")
- out[key.strip()] = value.strip()
+ return self.metadata2dict(f)
except Exception as e:
self.log.error(e, exc_info=True)
raise se.VolumeMetadataReadError("%s: %s" % (metaId, e))
-
- return out
@classmethod
def __putMetadata(cls, metaId, meta):
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index 3a5ed8e..aed932e 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -814,6 +814,20 @@
"""
pass
+
+ def metadata2dict(self, meta):
+ out = {}
+ for l in meta:
+ if l.startswith("EOF"):
+ return out
+ if l.find("=") < 0:
+ continue
+ key, value = l.split("=")
+ out[key.strip()] = value.strip()
+
+ return out
+
+
def metadata2info(self, meta):
return {
"uuid": self.volUUID,
--
To view, visit http://gerrit.ovirt.org/28492
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I26c495d437fe327a4029fe1dae087d182ba6611b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Liron Ar <laravot(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: xen: libvirtconnection: connect to xen, if it is available
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: xen: libvirtconnection: connect to xen, if it is available
......................................................................
xen: libvirtconnection: connect to xen, if it is available
Change-Id: I6cc6474b012d900fe3c5e1dab7a1e3e815ae01c3
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M lib/vdsm/libvirtconnection.py
1 file changed, 6 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/50/28350/1
diff --git a/lib/vdsm/libvirtconnection.py b/lib/vdsm/libvirtconnection.py
index b1332db..983287f 100644
--- a/lib/vdsm/libvirtconnection.py
+++ b/lib/vdsm/libvirtconnection.py
@@ -29,6 +29,7 @@
from . import constants, utils
log = logging.getLogger()
+XEN = os.path.exists('/proc/xen')
class _EventLoop:
@@ -124,7 +125,7 @@
libvirt.VIR_ERR_INTERNAL_ERROR,
libvirt.VIR_ERR_NO_CONNECT,
libvirt.VIR_ERR_INVALID_CONN)
- if edom in EDOMAINS and ecode in ECODES:
+ if not XEN and edom in EDOMAINS and ecode in ECODES:
try:
__connections.get(id(target)).pingLibvirt()
except libvirt.libvirtError as e:
@@ -148,7 +149,10 @@
conn = __connections.get(id(target))
if not conn:
log.debug('trying to connect libvirt')
- conn = _open_qemu_connection()
+ if XEN:
+ conn = libvirt.open('xen:///')
+ else:
+ conn = _open_qemu_connection()
__connections[id(target)] = conn
setattr(conn, 'pingLibvirt', getattr(conn, 'getLibVersion'))
--
To view, visit http://gerrit.ovirt.org/28350
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6cc6474b012d900fe3c5e1dab7a1e3e815ae01c3
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: xen: use qemu connection, as compareCPU is unavailable via xen
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: xen: use qemu connection, as compareCPU is unavailable via xen
......................................................................
xen: use qemu connection, as compareCPU is unavailable via xen
This patch is required until compareCPU is implemented by libvirt's xenlight
driver.
Change-Id: Ib86a325910aa57847fef194d7c4bd7c7854e2852
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M vdsm/caps.py
1 file changed, 4 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/51/28351/1
diff --git a/vdsm/caps.py b/vdsm/caps.py
index a4caa13..a27f582 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -368,7 +368,10 @@
@utils.memoized
def _getCompatibleCpuModels():
- c = libvirtconnection.get()
+ if libvirtconnection.XEN:
+ c = libvirtconnection._open_qemu_connection()
+ else:
+ c = libvirtconnection.get()
allModels = _getAllCpuModels()
def compatible(model, vendor):
--
To view, visit http://gerrit.ovirt.org/28351
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib86a325910aa57847fef194d7c4bd7c7854e2852
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: xen: do not attempt to read underlying device info
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: xen: do not attempt to read underlying device info
......................................................................
xen: do not attempt to read underlying device info
Xen's device information is quite different than what Vdsm currently
expects and needs. They lack bus address, alias, and driver.
With this patch, Vdsm-on-Xen does not even attempt to read this
information, which means that it would not be able to inract with the
underlying devices.
This is a hack which I do not expect getting into Vdsm proper. Much
deeper refactoring is required to handle Xen devices.
Change-Id: Ifae785c5caa2e37fb8968ead570502e935f7900f
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/52/28352/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 21662bc..6a0d035 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -2921,7 +2921,8 @@
raise Exception('destroy() called before Vm started')
self._getUnderlyingVmInfo()
- self._getUnderlyingVmDevicesInfo()
+ if not libvirtconnection.XEN:
+ self._getUnderlyingVmDevicesInfo()
self._updateAgentChannels()
# Currently there is no protection agains mirroring a network twice,
--
To view, visit http://gerrit.ovirt.org/28352
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifae785c5caa2e37fb8968ead570502e935f7900f
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 6 months