Change in vdsm[master]: vm: small refactor for _normalizeVdsmImg
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: vm: small refactor for _normalizeVdsmImg
......................................................................
vm: small refactor for _normalizeVdsmImg
Change-Id: Ie68292eee4b82fbe8527e3960739979cfe117dfa
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M vdsm/vm.py
1 file changed, 18 insertions(+), 17 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/57/19157/1
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 92d274e..2605f24 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -1779,25 +1779,26 @@
break
return str(idx)
- def _normalizeVdsmImg(self, drv):
- drv['reqsize'] = drv.get('reqsize', '0') # Backward compatible
- if 'device' not in drv:
- drv['device'] = 'disk'
+ def _normalizeVdsmImg(self, drive):
+ drive['device'] = drive.get('device', 'disk') # Disk by default
+ drive['reqsize'] = drive.get('reqsize', '0') # Backward compatible
- if drv['device'] == 'disk':
- res = self.cif.irs.getVolumeSize(drv['domainID'], drv['poolID'],
- drv['imageID'], drv['volumeID'])
- try:
- drv['truesize'] = res['truesize']
- drv['apparentsize'] = res['apparentsize']
- except KeyError:
- self.log.error("Unable to get volume size for %s",
- drv['volumeID'], exc_info=True)
- raise RuntimeError("Volume %s is corrupted or missing" %
- drv['volumeID'])
+ if drive['device'] == 'disk':
+ volInfo = self.cif.irs.getVolumeInfo(
+ drive['domainID'], drive['poolID'], drive['imageID'],
+ drive['volumeID'])
+
+ if volInfo.get('status', {}).get('code', -1):
+ self.log.error(
+ "Unable to get volume info for %s", drive['volumeID'])
+ raise RuntimeError(
+ "Volume %s is corrupted or missing" % drive['volumeID'])
+
+ drive['truesize'] = volInfo['info']['truesize']
+ drive['apparentsize'] = volInfo['info']['apparentsize']
else:
- drv['truesize'] = 0
- drv['apparentsize'] = 0
+ drive['truesize'] = 0
+ drive['apparentsize'] = 0
@classmethod
def _normalizeDriveSharedAttribute(self, drive):
--
To view, visit http://gerrit.ovirt.org/19157
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie68292eee4b82fbe8527e3960739979cfe117dfa
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: gluster: [WIP]Get size information of gluster volume
by avishwan@redhat.com
Aravinda VK has uploaded a new change for review.
Change subject: gluster: [WIP]Get size information of gluster volume
......................................................................
gluster: [WIP]Get size information of gluster volume
Change-Id: I358d4f3bf793ecc1a01e0592d68919d1405f6e19
Signed-off-by: Aravinda VK <avishwan(a)redhat.com>
---
M client/vdsClientGluster.py
M vdsm.spec.in
M vdsm/gluster/Makefile.am
M vdsm/gluster/__init__.py
M vdsm/gluster/api.py
A vdsm/gluster/gfapi.py
6 files changed, 100 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/22/17822/1
diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index 90af83e..644bfe3 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -424,6 +424,17 @@
pp.pprint(status)
return status['status']['code'], status['status']['message']
+ def do_glusterVolumeSize(self, args):
+ params = self._eqSplit(args)
+ try:
+ volumeName = params.get('volumeName', '')
+ except:
+ raise ValueError
+
+ status = self.s.glusterVolumeSize(volumeName)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
def getGlusterCmdDict(serv):
return \
@@ -705,4 +716,9 @@
'not set'
'(swift, glusterd, smb, memcached)'
)),
+ 'glusterVolumeSize': (
+ serv.do_glusterVolumeSize,
+ ('volumeName=<volume name>',
+ 'Returns total, available and used space status of gluster volume'
+ )),
}
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 21b3565..e49e102 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1271,6 +1271,7 @@
%doc COPYING
%{_datadir}/%{vdsm_name}/gluster/api.py*
%{_datadir}/%{vdsm_name}/gluster/vdsmapi-gluster-schema.json
+%{_datadir}/%{vdsm_name}/gluster/gfapi.py*
%{_datadir}/%{vdsm_name}/gluster/hooks.py*
%{_datadir}/%{vdsm_name}/gluster/services.py*
%endif
diff --git a/vdsm/gluster/Makefile.am b/vdsm/gluster/Makefile.am
index dd5434d..9c2989f 100644
--- a/vdsm/gluster/Makefile.am
+++ b/vdsm/gluster/Makefile.am
@@ -26,6 +26,7 @@
api.py \
cli.py \
exception.py \
+ gfapi.py \
hooks.py \
hostname.py \
services.py \
diff --git a/vdsm/gluster/__init__.py b/vdsm/gluster/__init__.py
index bec70ea..e5a2fd6 100644
--- a/vdsm/gluster/__init__.py
+++ b/vdsm/gluster/__init__.py
@@ -22,7 +22,7 @@
import tempfile
from functools import wraps
-MODULE_LIST = ('cli', 'hooks', 'services')
+MODULE_LIST = ('cli', 'hooks', 'services', 'gfapi')
def makePublic(func):
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 4bd8308..89546c1 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -287,6 +287,22 @@
status = self.svdsmProxy.glusterServicesGet(serviceNames)
return {'services': status}
+ @exportAsVerb
+ def volumeSize(self, volumeName, options=None):
+ data = self.svdsmProxy.glusterVolumeStatvfs(volumeName)
+ # f_blocks = Total number of blocks
+ # f_bfree = Total number of blocks free
+ # f_bavail = Total number of blocks available for non root user
+ # total blocks available = f_blocks - (f_bfree - f_bavail)
+ total_blocks_available = data['f_blocks'] - \
+ (data['f_bfree'] - data['f_bavail'])
+ return {
+ 'total': total_blocks_available * data.f_bsize / 1024,
+ 'free': data['f_bavail'] * data['f_bsize'] / 1024,
+ 'used': (total_blocks_available - data['f_bavail']) * \
+ data['f_bsize'] / 1024
+ }
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/gfapi.py b/vdsm/gluster/gfapi.py
new file mode 100644
index 0000000..abfdabd
--- /dev/null
+++ b/vdsm/gluster/gfapi.py
@@ -0,0 +1,65 @@
+#
+# Copyright 2013 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
+#
+from ctypes import *
+
+# import exception as ge
+from . import makePublic
+
+GLUSTER_VOL_PROTOCAL='tcp'
+GLUSTER_VOL_HOST='localhost'
+GLUSTER_VOL_PORT=24007
+
+class Stat (Structure):
+ _fields_ = [
+ ('f_bsize', c_ulong),
+ ('f_frsize', c_ulong),
+ ('f_blocks', c_ulong),
+ ('f_bfree', c_ulong),
+ ('f_bavail', c_ulong),
+ ('f_files', c_ulong),
+ ('f_ffree', c_ulong),
+ ('f_favail', c_ulong),
+ ('f_fsid', c_ulong),
+ ('f_flag', c_ulong),
+ ('f_namemax', c_ulong),
+ ('__f_spare', c_int * 6),
+ ]
+
+
+api = CDLL("libgfapi.so",RTLD_GLOBAL)
+api.glfs_statvfs.restype = c_int
+api.glfs_statvfs.argtypes = [c_void_p, c_char_p, POINTER(Stat)]
+
+@makePublic
+def volumeStatvfs(volumeId):
+ path = "/"
+ fs = api.glfs_new(volumeId)
+ api.glfs_set_volfile_server(fs,
+ GLUSTER_VOL_PROTOCAL,
+ GLUSTER_VOL_HOST,
+ GLUSTER_VOL_PORT)
+ api.glfs_init(fs)
+
+ x = Stat()
+ rc = api.glfs_statvfs(fs, path, byref(x))
+ statvfsData = {}
+ for k in x._fields_:
+ statvfsData[k[0]] = getattr(x, k[0])
+ return statvfsData
--
To view, visit http://gerrit.ovirt.org/17822
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I358d4f3bf793ecc1a01e0592d68919d1405f6e19
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Aravinda VK <avishwan(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: Add hostusbdirect hook to vdsm_hooks.
by lyarwood@redhat.com
Lee Yarwood has uploaded a new change for review.
Change subject: Add hostusbdirect hook to vdsm_hooks.
......................................................................
Add hostusbdirect hook to vdsm_hooks.
This is a slight variation of the hostusb hook. This version uses the bus and
device IDs to attach host USB device to the guest using the following libvirt XML :
<hostdev mode='subsystem' type='usb' managed='yes'>
<source>
<address bus='001' device='003'/>
</source>
</hostdev>
In the future this could be merged with the hostusb hook.
Change-Id: I00b4b03993cd7290462b0e17457892b23dd41b31
Signed-off-by: Lee Yarwood <lyarwood(a)redhat.com>
---
M configure.ac
M vdsm.spec.in
M vdsm_hooks/Makefile.am
A vdsm_hooks/hostusbdirect/Makefile.am
A vdsm_hooks/hostusbdirect/README
A vdsm_hooks/hostusbdirect/after_vm_destroy.py
A vdsm_hooks/hostusbdirect/before_vm_migrate_source.py
A vdsm_hooks/hostusbdirect/before_vm_start.py
A vdsm_hooks/hostusbdirect/sudoers.vdsm_hook_hostusbdirect
9 files changed, 262 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/28/17428/1
diff --git a/configure.ac b/configure.ac
index 0ccca95..39e31f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -225,6 +225,7 @@
vdsm_hooks/fileinject/Makefile
vdsm_hooks/floppy/Makefile
vdsm_hooks/hostusb/Makefile
+ vdsm_hooks/hostusbdirect/Makefile
vdsm_hooks/hugepages/Makefile
vdsm_hooks/isolatedprivatevlan/Makefile
vdsm_hooks/macspoof/Makefile
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 235d1db..c1b9431 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -389,6 +389,15 @@
Hook is getting vendor and product id of USB device
disconnect it from host and attach it to VM
+%package hook-hostusb-direct
+Summary: Allow attaching USB device from host by bus and device ids.
+BuildArch: noarch
+Requires: usbutils
+
+%description hook-hostusb-direct
+Hook is getting bus and device id of USB device
+disconnect it from host and attach it to VM
+
%package hook-hugepages
Summary: Huge pages enable user to handle VM with 2048KB page files.
BuildArch: noarch
diff --git a/vdsm_hooks/Makefile.am b/vdsm_hooks/Makefile.am
index 8a8d594..fb4052b 100644
--- a/vdsm_hooks/Makefile.am
+++ b/vdsm_hooks/Makefile.am
@@ -30,6 +30,7 @@
fileinject \
floppy \
hostusb \
+ hostusbdirect \
hugepages \
isolatedprivatevlan \
macspoof \
diff --git a/vdsm_hooks/hostusbdirect/Makefile.am b/vdsm_hooks/hostusbdirect/Makefile.am
new file mode 100644
index 0000000..9d0cdbc
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/Makefile.am
@@ -0,0 +1,52 @@
+#
+# Copyright 2013 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
+#
+
+EXTRA_DIST = \
+ after_vm_destroy.py \
+ before_vm_migrate_source.py \
+ before_vm_start.py \
+ sudoers.vdsm_hook_hostusbdirect
+
+install-data-hook:
+ chmod 440 $(DESTDIR)$(sysconfdir)/sudoers.d/50_vdsm_hook_hostusbdirect
+
+install-data-local: install-data-sudoers
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/before_vm_start
+ $(INSTALL_SCRIPT) $(srcdir)/before_vm_start.py \
+ $(DESTDIR)$(vdsmhooksdir)/before_vm_start/50_hostusbdirect
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/after_vm_destroy
+ $(INSTALL_SCRIPT) $(srcdir)/after_vm_destroy.py \
+ $(DESTDIR)$(vdsmhooksdir)/after_vm_destroy/50_hostusbdirect
+ $(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/before_vm_migrate_source
+ $(INSTALL_SCRIPT) $(srcdir)/before_vm_migrate_source.py \
+ $(DESTDIR)$(vdsmhooksdir)/before_vm_migrate_source/50_hostusbdirect
+
+uninstall-local: uninstall-data-sudoers
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/before_vm_start/50_hostusbdirect
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/after_vm_destroy/50_hostusbdirect
+ $(RM) $(DESTDIR)$(vdsmhooksdir)/before_vm_migrate_source/50_hostusbdirect
+
+install-data-sudoers:
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/sudoers.d
+ $(INSTALL_DATA) $(srcdir)/sudoers.vdsm_hook_hostusbdirect \
+ $(DESTDIR)$(sysconfdir)/sudoers.d/50_vdsm_hook_hostusbdirect
+
+uninstall-data-sudoers:
+ $(RM) $(DESTDIR)$(sysconfdir)/sudoers.d/50_vdsm_hook_hostusbdirect
diff --git a/vdsm_hooks/hostusbdirect/README b/vdsm_hooks/hostusbdirect/README
new file mode 100644
index 0000000..297c559
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/README
@@ -0,0 +1,18 @@
+host usb hook direct
+====================
+add hosts usb device/s to VM using bus and device ids:
+
+<hostdev mode='subsystem' type='usb'>
+ <source>
+ <address bus='001' device='003'/>
+ </source>
+</hostdev>
+
+syntax:
+ hostusbdirect=001:003&001:002
+ i.e.
+ hostusb=bus:device (can add more then one with '&' separator)
+
+Note:
+ The VM must be pinned to host and this hook will
+ fail any migration attempt.
diff --git a/vdsm_hooks/hostusbdirect/after_vm_destroy.py b/vdsm_hooks/hostusbdirect/after_vm_destroy.py
new file mode 100755
index 0000000..3882347
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/after_vm_destroy.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+
+import os
+import sys
+import traceback
+
+import hooking
+
+'''
+after_vm_destroy:
+return the original owner of the usb device
+'''
+
+HOOK_HOSTUSB_PATH = '/var/run/vdsm/hooks/hostusbdirect-permissions'
+
+
+def get_owner(devpath):
+ uid = pid = -1
+ content = ''
+
+ if not os.path.isfile(HOOK_HOSTUSB_PATH):
+ return uid, pid
+
+ f = file(HOOK_HOSTUSB_PATH, 'r')
+ for line in f:
+ if len(line) > 0 and line.split(':')[0] == devpath:
+ entry = line.split(':')
+ uid = entry[1]
+ pid = entry[2]
+ elif len(line) > 0:
+ content += line + '\n'
+
+ f.close()
+ if uid != -1:
+ f = file(HOOK_HOSTUSB_PATH, 'w')
+ f.writelines(content)
+ f.close()
+
+ return uid, pid
+
+
+def chown(bus, device):
+ devpath = '/dev/bus/usb/' + bus + '/' + device
+ uid, gid = get_owner(devpath)
+
+ owner = str(uid) + ':' + str(gid)
+ command = ['/bin/chown', owner, devpath]
+ retcode, out, err = hooking.execCmd(command, sudo=True, raw=True)
+ if retcode != 0:
+ sys.stderr.write('hostusbdirect: error chown %s to %s, err = %s\n' %
+ (devpath, owner, err))
+ sys.exit(2)
+
+
+if 'hostusbdirect' in os.environ:
+ try:
+ for usb in os.environ['hostusbdirect'].split('&'):
+ bus, device = usb.split(':')
+ chown(bus, device)
+
+ except:
+ sys.stderr.write('hostusb after_vm_destroy: [unexpected error]: %s\n' %
+ traceback.format_exc())
+ sys.exit(2)
diff --git a/vdsm_hooks/hostusbdirect/before_vm_migrate_source.py b/vdsm_hooks/hostusbdirect/before_vm_migrate_source.py
new file mode 100755
index 0000000..43a2eca
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/before_vm_migrate_source.py
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+
+import os
+import sys
+
+if 'hostusbdirect' in os.environ:
+ sys.stderr.write("hostusbdirect: can't migrate VM with host usb devices\n")
+ sys.exit(2)
diff --git a/vdsm_hooks/hostusbdirect/before_vm_start.py b/vdsm_hooks/hostusbdirect/before_vm_start.py
new file mode 100755
index 0000000..57307aa
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/before_vm_start.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+import os
+import sys
+import grp
+import pwd
+import traceback
+
+import hooking
+
+'''
+host usb hook direct
+====================
+
+syntax:
+ hostusbdirect=001:001&001:002
+ i.e.
+ hostusbdirect=bus:device (can add more then one with '&' separator)
+
+Note:
+ The VM must be pinned to host and this hook will
+ fail any migration attempt.
+'''
+
+HOOK_HOSTUSB_PATH = '/var/run/vdsm/hooks/hostusbdirect-permissions'
+
+
+def log_dev_owner(devpath, user, group):
+ entry = devpath + ":" + str(user) + ":" + str(group)
+
+ if not os.path.isdir(os.path.dirname(HOOK_HOSTUSB_PATH)):
+ os.mkdir(os.path.dirname(HOOK_HOSTUSB_PATH))
+
+ if os.path.isfile(HOOK_HOSTUSB_PATH):
+ f = file(HOOK_HOSTUSB_PATH, 'r')
+ for line in f:
+ if entry == line:
+ f.close()
+ return
+
+ f = file(HOOK_HOSTUSB_PATH, 'a')
+ f.writelines(entry)
+ f.close()
+
+
+def chown(bus, device):
+
+ devpath = '/dev/bus/usb/' + bus + '/' + device
+ stat = os.stat(devpath)
+
+ group = grp.getgrnam('qemu')
+ gid = group.gr_gid
+ user = pwd.getpwnam('qemu')
+ uid = user.pw_uid
+
+ owner = str(uid) + ':' + str(gid)
+ command = ['/bin/chown', owner, devpath]
+ retcode, out, err = hooking.execCmd(command, sudo=True, raw=True)
+ if retcode != 0:
+ sys.stderr.write('hostusbdirect: error chown %s to %s, err = %s\n' %
+ (devpath, owner, err))
+ sys.exit(2)
+
+ log_dev_owner(devpath, stat.st_uid, stat.st_gid)
+
+
+def add_devices(domxml, devices):
+ domain = domxml.getElementsByTagName('devices')[0]
+
+ for device in devices:
+ # Add the following for each device :
+ #<hostdev mode='subsystem' type='usb' managed='yes'>
+ # <source>
+ # <address bus='001' device='003'/>
+ # </source>
+ #</hostdev>
+
+ hostdev = domxml.createElement('hostdev')
+ hostdev.setAttribute('mode', 'subsystem')
+ hostdev.setAttribute('type', 'usb')
+ hostdev.setAttribute('managed', 'yes')
+
+ source = domxml.createElement('source')
+ hostdev.appendChild(source)
+
+ address = domxml.createElement('address')
+ address.setAttribute('bus', device['bus'])
+ address.setAttribute('device', device['device'])
+ source.appendChild(address)
+
+ domain.appendChild(hostdev)
+
+if 'usbhostdirect' in os.environ:
+ try:
+ domxml = hooking.read_domxml()
+ devices = []
+
+ for usb in os.environ['usbhostdirect'].split('&'):
+ bus, device = usb.split(':')
+ chown(bus, device)
+ devices.append({'bus': bus, 'device': device})
+
+ add_devices(domxml, devices)
+ hooking.write_domxml(domxml)
+ except:
+ sys.stderr.write('hostusbdirect: [unexpected error]: %s\n' %
+ traceback.format_exc())
+ sys.exit(2)
diff --git a/vdsm_hooks/hostusbdirect/sudoers.vdsm_hook_hostusbdirect b/vdsm_hooks/hostusbdirect/sudoers.vdsm_hook_hostusbdirect
new file mode 100644
index 0000000..cba601d
--- /dev/null
+++ b/vdsm_hooks/hostusbdirect/sudoers.vdsm_hook_hostusbdirect
@@ -0,0 +1 @@
+vdsm ALL=(ALL) NOPASSWD: /bin/chown
--
To view, visit http://gerrit.ovirt.org/17428
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I00b4b03993cd7290462b0e17457892b23dd41b31
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Lee Yarwood <lyarwood(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: [WIP] Implement a process to do dangerous IO in C
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: [WIP] Implement a process to do dangerous IO in C
......................................................................
[WIP] Implement a process to do dangerous IO in C
This replaces the process pool with a process that can serve multiple
requests written in C.
This implementation is much more scalable and lightweight. Should solve
bugs related to running out of helpers, logging getting suck, python
forking deadlocking, running out of memory and other things as well.
The communication between VDSM and the IOProcess is done with json
objects.
The IOProcess starts with 3 thread:
1. requestReader - reads requests from the pipe, builds a DOM
representation of it and queues it up for handling
2. responseWriter - gets response DOMs from the queue converts them to a
JSON string and send it over the pipe
3. requestHandler - pops requests from the queue and provisions threads
for handling them. Currently we I just allocate a new thread per
request. If there is ever a need to have a thread pool this is where
the load balancing is going to sit.
Each request gets the are as a JsonNode and returns a response that is a
JsonNode as well. Most exported functions are pretty trivial and are a
good example on how to write new ones.
Unlink the ProcessPoolHelper, high level commands sit of the OopWrapper
and are run from the client side instead of being implemented in C on
the IOProcess side.
Change-Id: Ie4664d5330debbe38ba33b74ebb586ac42913b4a
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M configure.ac
M tests/Makefile.am
A tests/ioprocessTests.py
A tests/outOfProcessTests.py
D tests/processPoolTests.py
M vdsm.spec.in
M vdsm/constants.py.in
M vdsm/storage/Makefile.am
M vdsm/storage/fileSD.py
M vdsm/storage/fileUtils.py
M vdsm/storage/fileVolume.py
A vdsm/storage/ioprocess.py
A vdsm/storage/ioprocess/.gitignore
A vdsm/storage/ioprocess/Makefile.am
A vdsm/storage/ioprocess/exported-functions.c
A vdsm/storage/ioprocess/exported-functions.h
A vdsm/storage/ioprocess/ioprocess.c
A vdsm/storage/ioprocess/json-dom-generator.c
A vdsm/storage/ioprocess/json-dom-generator.h
A vdsm/storage/ioprocess/json-dom-parser.c
A vdsm/storage/ioprocess/json-dom-parser.h
A vdsm/storage/ioprocess/json-dom.c
A vdsm/storage/ioprocess/json-dom.h
M vdsm/storage/misc.py
M vdsm/storage/nfsSD.py
M vdsm/storage/outOfProcess.py
D vdsm/storage/processPool.py
M vdsm/storage/sd.py
M vdsm/storage/sp.py
M vdsm/storage/task.py
30 files changed, 3,018 insertions(+), 666 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/46/3946/1
--
To view, visit http://gerrit.ovirt.org/3946
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie4664d5330debbe38ba33b74ebb586ac42913b4a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: Rescan FC when rescanning for new multipath devices
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: Rescan FC when rescanning for new multipath devices
......................................................................
Rescan FC when rescanning for new multipath devices
Change-Id: Idec939222676a24452e8825b36db68839bfd2bbc
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M lib/vdsm/utils.py
M tests/utilsTests.py
M vdsm/storage/Makefile.am
A vdsm/storage/fc.py
M vdsm/storage/multipath.py
5 files changed, 61 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/39/19539/1
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index f06cad2..e273514 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -793,6 +793,24 @@
return functools.partial(self.__call__, obj)
+def tee_async(data, outputFiles=[], append=False):
+ cmd = ["tee"]
+ if append:
+ cmd.append("--append")
+
+ cmd.extend(outputFiles)
+ proc = execCmd(cmd, sync=False)
+ proc.stdin.write(data)
+
+ def parser(rc, out, err):
+ if rc != 0:
+ raise OSError(-1, err)
+
+ return out
+
+ return AsyncProcessOperation(proc, parser)
+
+
def validateMinimalKeySet(dictionary, reqParams):
if not all(key in dictionary for key in reqParams):
raise ValueError
diff --git a/tests/utilsTests.py b/tests/utilsTests.py
index 656c121..5b83ec0 100644
--- a/tests/utilsTests.py
+++ b/tests/utilsTests.py
@@ -18,11 +18,14 @@
# Refer to the README and COPYING files for full details of the license
#
import errno
+import time
+import tempfile
+import shutil
+import os
from testrunner import VdsmTestCase as TestCaseBase
from vdsm import utils
from storage import misc
-import time
class RetryTests(TestCaseBase):
@@ -63,6 +66,33 @@
sproc.wait()
+class TeeTests(TestCaseBase):
+ def setUp(self):
+ self.dir = tempfile.mkdtemp()
+
+ def tearDown(self):
+ shutil.rmtree(self.dir)
+
+ def test(self):
+ d = self.dir
+ n = 10
+ files = []
+ for i in range(n):
+ files.append(os.path.join(d, "%d.tmp" % i))
+
+ data = "hello"
+ res = utils.tee_async(data, files).result()
+ self.assertEquals((data, None), res)
+ for fname in files:
+ with open(fname, "r") as f:
+ self.assertEquals(data, f.read())
+
+ def testError(self):
+ res, err = utils.tee_async("hello", ["/"]).result()
+ self.assertEquals(res, None)
+ self.assertNotEquals(err, None)
+
+
class CommandPathTests(TestCaseBase):
def testExisting(self):
cp = utils.CommandPath('sh', 'utter nonsense', '/bin/sh')
diff --git a/vdsm/storage/Makefile.am b/vdsm/storage/Makefile.am
index 2d3e9a6..a367c9b 100644
--- a/vdsm/storage/Makefile.am
+++ b/vdsm/storage/Makefile.am
@@ -33,6 +33,7 @@
fileSD.py \
fileUtils.py \
fileVolume.py \
+ fc.py \
fuser.py \
glusterSD.py \
glusterVolume.py \
diff --git a/vdsm/storage/fc.py b/vdsm/storage/fc.py
new file mode 100644
index 0000000..96aa710
--- /dev/null
+++ b/vdsm/storage/fc.py
@@ -0,0 +1,8 @@
+from glob import glob
+from vdsm import utils
+
+
+def rescan():
+ """Issue command to discover new ports if the fc driver supports it"""
+ # Use tee to make sure we don't do that IO directly
+ utils.tee_async("1", glob("/sys/class/fc_host/host*/issue_lip"))
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 6d6fcbd..076bfca 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -36,6 +36,7 @@
import iscsi
import supervdsm
import devicemapper
+import fc
import storage_exception as se
@@ -106,7 +107,8 @@
Should only be called from hsm._rescanDevices()
"""
- # First ask iSCSI to rescan all its sessions
+ # First ask fc and iSCSI to rescan all of their sessions
+ fc.rescan()
iscsi.rescan()
# Now let multipath daemon pick up new devices
--
To view, visit http://gerrit.ovirt.org/19539
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idec939222676a24452e8825b36db68839bfd2bbc
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: Move fencing logic out of API.py
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: Move fencing logic out of API.py
......................................................................
Move fencing logic out of API.py
API.py should not contain logic.
In this patch I also:
- Separate the `status` action to a different function because it does
something completely different from the other action and has different
logic.
- Refactor for better code reusability readability.
- Use real exception internally and have the API layer translate them to
actual exceptions.
- Don't support port strings in methods, just in the interface.
- Don't support string booleans in the methods, just in the interface.
- Added shutdownEvent to ClientIF so there is a public standard way of
inspecting vdsm shutdown.
- Make the fencing logic use betterPopen
Change-Id: I944c6548a42612f705a410fb4290215451bca035
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm.spec.in
M vdsm/API.py
M vdsm/Makefile.am
M vdsm/clientIF.py
4 files changed, 25 insertions(+), 72 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/90/7190/1
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 23afd6b..f122cb5 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -558,6 +558,7 @@
%{_datadir}/%{vdsm_name}/caps.py*
%{_datadir}/%{vdsm_name}/clientIF.py*
%{_datadir}/%{vdsm_name}/API.py*
+%{_datadir}/%{vdsm_name}/fenceAgent.py*
%{_datadir}/%{vdsm_name}/hooking.py*
%{_datadir}/%{vdsm_name}/hooks.py*
%{_datadir}/%{vdsm_name}/libvirtev.py*
diff --git a/vdsm/API.py b/vdsm/API.py
index ae04e01..5826d81 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -19,12 +19,9 @@
#
import os
-import signal
import copy
-import subprocess
import pickle
import time
-import threading
import logging
from vdsm import utils
@@ -40,6 +37,7 @@
from vdsm.define import doneCode, errCode, Kbytes, Mbytes
import caps
from vdsm.config import config
+import fenceAgent
import supervdsm
@@ -981,82 +979,32 @@
agent is one of (rsa, ilo, drac5, ipmilan, etc)
action can be one of (status, on, off, reboot)."""
- def waitForPid(p, inp):
- """ Wait until p.pid exits. Kill it if vdsm exists before. """
- try:
- p.stdin.write(inp)
- p.stdin.close()
- while p.poll() is None:
- if not self._cif._enabled:
- self.log.debug('killing fence script pid %s', p.pid)
- os.kill(p.pid, signal.SIGTERM)
- time.sleep(1)
- try:
- # improbable race: p.pid may now belong to another
- # process
- os.kill(p.pid, signal.SIGKILL)
- except:
- pass
- return
- time.sleep(1)
- self.log.debug('rc %s inp %s out %s err %s', p.returncode,
- hidePasswd(inp),
- p.stdout.read(), p.stderr.read())
- except:
- self.log.error("Error killing fence script", exc_info=True)
-
- def hidePasswd(text):
- cleantext = ''
- for line in text.splitlines(True):
- if line.startswith('passwd='):
- line = 'passwd=XXXX\n'
- cleantext += line
- return cleantext
-
self.log.debug('fenceNode(addr=%s,port=%s,agent=%s,user=%s,' +
'passwd=%s,action=%s,secure=%s,options=%s)', addr, port, agent,
username, 'XXXX', action, secure, options)
- if action not in ('status', 'on', 'off', 'reboot'):
- raise ValueError('illegal action ' + action)
+ secure = utils.tobool(secure)
+ port = int(port)
- script = constants.EXT_FENCE_PREFIX + agent
+ if action == "status":
+ try:
+ power = fenceAgent.getFenceStatus(addr, port, agent, username,
+ password, secure, options)
+
+ return {'status': doneCode,
+ 'power': power}
+
+ except fenceAgent.FenceStatusCheckError as e:
+ return {'status': {'code': 1, 'message': str(e)}}
try:
- p = subprocess.Popen([script], stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- close_fds=True)
- except OSError, e:
- if e.errno == os.errno.ENOENT:
- return errCode['fenceAgent']
- raise
+ fenceAgent.fenceNode(addr, port, agent, username, password, secure,
+ options, self._cif.shutdownEvent)
- inp = ('agent=fence_%s\nipaddr=%s\nlogin=%s\noption=%s\n' +
- 'passwd=%s\n') % (agent, addr, username, action, password)
- if port != '':
- inp += 'port=%s\n' % (port,)
- if utils.tobool(secure):
- inp += 'secure=yes\n'
- inp += options
- if action == 'status':
- out, err = p.communicate(inp)
- self.log.debug('rc %s in %s out %s err %s', p.returncode,
- hidePasswd(inp), out, err)
- if not 0 <= p.returncode <= 2:
- return {'status': {'code': 1,
- 'message': out + err}}
- message = doneCode['message']
- if p.returncode == 0:
- power = 'on'
- elif p.returncode == 2:
- power = 'off'
- else:
- power = 'unknown'
- message = out + err
- return {'status': {'code': 0, 'message': message},
- 'power': power}
- threading.Thread(target=waitForPid, args=(p, inp)).start()
- return {'status': doneCode}
+ return {'status': doneCode}
+
+ except fenceAgent.UnsupportedFencingAgentError:
+ return errCode['fenceAgent']
def ping(self):
"Ping the server. Useful for tests"
diff --git a/vdsm/Makefile.am b/vdsm/Makefile.am
index 62ba982..4a7bc57 100644
--- a/vdsm/Makefile.am
+++ b/vdsm/Makefile.am
@@ -32,6 +32,7 @@
clientIF.py \
configNetwork.py \
debugPluginClient.py \
+ fenceAgent.py \
guestIF.py \
hooking.py \
hooks.py \
@@ -52,7 +53,8 @@
tc.py \
vdsmDebugPlugin.py \
vmChannels.py \
- vm.py
+ vm.py \
+ $(NULL)
dist_vdsmpylib_PYTHON = \
__init__.py \
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index 8ba25a7..8760437 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -96,6 +96,7 @@
self.lastRemoteAccess = 0
self._memLock = threading.Lock()
self._enabled = True
+ self.shutdownEvent = threading.Event()
self._netConfigDirty = False
self._prepareMOM()
threading.Thread(target=self._recoverExistingVms,
@@ -219,6 +220,7 @@
for binding in self.bindings.values():
binding.prepareForShutdown()
self._enabled = False
+ self.shutdownEvent.set()
self.channelListener.stop()
self._hostStats.stop()
if self.mom:
--
To view, visit http://gerrit.ovirt.org/7190
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I944c6548a42612f705a410fb4290215451bca035
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: Use more fine lock for hsm.deleteImage().
by ewarszaw@redhat.com
Eduardo has uploaded a new change for review.
Change subject: Use more fine lock for hsm.deleteImage().
......................................................................
Use more fine lock for hsm.deleteImage().
When removing an image from a specific SD, lock the image in this
SD exclusively.
Related to: BZ#960952.
Change-Id: Iab04d548610cd86eb70e1fd13a29a3508778cc1d
Signed-off-by: Eduardo <ewarszaw(a)redhat.com>
---
M vdsm/storage/hsm.py
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/13/16413/1
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 5639c13..09c5404 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -1437,7 +1437,8 @@
self.getPool(spUUID) # Validates that the pool is connected. WHY?
dom = self.validateSdUUID(sdUUID)
- vars.task.getExclusiveLock(STORAGE, imgUUID)
+ imageResourcesNamespace = sd.getNamespace(sdUUID, IMAGE_NAMESPACE)
+ vars.task.getExclusiveLock(imageResourcesNamespace, imgUUID)
vars.task.getSharedLock(STORAGE, sdUUID)
allVols = dom.getAllVolumes()
volsByImg = sd.getVolsOfImage(allVols, imgUUID)
--
To view, visit http://gerrit.ovirt.org/16413
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iab04d548610cd86eb70e1fd13a29a3508778cc1d
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Eduardo <ewarszaw(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: [WIP] metaSize calculation as a module function.
by ewarszaw@redhat.com
Eduardo has uploaded a new change for review.
Change subject: [WIP] metaSize calculation as a module function.
......................................................................
[WIP] metaSize calculation as a module function.
Change-Id: If90ba75d11c4962f2e52150e5f381cd93d0e8f35
Signed-off-by: Eduardo <ewarszaw(a)redhat.com>
---
M vdsm/storage/blockSD.py
1 file changed, 23 insertions(+), 23 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/90/11690/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 9b9674e..aa4059a 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -269,6 +269,27 @@
return
+def metaSize(vgName):
+ ''' Calc the minimal meta volume size in MB'''
+ # In any case the metadata volume cannot be less than 512MB for the
+ # case of 512 bytes per volume metadata, 2K for domain metadata and
+ # extent size of 128MB. In any case we compute the right size on line.
+ vg = lvm.getVG(vgName)
+ minmetasize = (SD_METADATA_SIZE / sd.METASIZE * int(vg.extent_size) +
+ (1024 * 1024 - 1)) / (1024 * 1024)
+ metaratio = int(vg.extent_size) / sd.METASIZE
+ metasize = (int(vg.extent_count) * sd.METASIZE +
+ (1024 * 1024 - 1)) / (1024 * 1024)
+ metasize = max(minmetasize, metasize)
+ if metasize > int(vg.free) / (1024 * 1024):
+ raise se.VolumeGroupSizeError("volume group has not enough extents %s"
+ " (Minimum %s), VG may be too small" %
+ (vg.extent_count,
+ (1024 * 1024) / sd.METASIZE))
+ log.info("size %s MB (metaratio %s)" % (metasize, metaratio))
+ return metasize
+
+
class VGTagMetadataRW(object):
log = logging.getLogger("storage.Metadata.VGTagMetadataRW")
METADATA_TAG_PREFIX = "MDT_"
@@ -449,27 +470,6 @@
lvmActivationNamespace)
@classmethod
- def metaSize(cls, vgroup):
- ''' Calc the minimal meta volume size in MB'''
- # In any case the metadata volume cannot be less than 512MB for the
- # case of 512 bytes per volume metadata, 2K for domain metadata and
- # extent size of 128MB. In any case we compute the right size on line.
- vg = lvm.getVG(vgroup)
- minmetasize = (SD_METADATA_SIZE / sd.METASIZE * int(vg.extent_size) +
- (1024 * 1024 - 1)) / (1024 * 1024)
- metaratio = int(vg.extent_size) / sd.METASIZE
- metasize = (int(vg.extent_count) * sd.METASIZE +
- (1024 * 1024 - 1)) / (1024 * 1024)
- metasize = max(minmetasize, metasize)
- if metasize > int(vg.free) / (1024 * 1024):
- raise se.VolumeGroupSizeError(
- "volume group has not enough extents %s (Minimum %s), VG may "
- "be too small" % (vg.extent_count,
- (1024 * 1024) / sd.METASIZE))
- cls.log.info("size %s MB (metaratio %s)" % (metasize, metaratio))
- return metasize
-
- @classmethod
def create(cls, sdUUID, domainName, domClass, vgUUID, storageType,
version):
""" Create new storage domain
@@ -509,7 +509,7 @@
raise se.StorageDomainIsMadeFromTooManyPVs()
# Create metadata service volume
- metasize = cls.metaSize(vgName)
+ metasize = metaSize(vgName)
lvm.createLV(vgName, sd.METADATA, "%s" % (metasize))
# Create the mapping right now so the index 0 is guaranteed
# to belong to the metadata volume. Since the metadata is at
@@ -721,7 +721,7 @@
lvm.extendVG(self.sdUUID, devices, force)
self.updateMapping()
- newsize = self.metaSize(self.sdUUID)
+ newsize = metaSize(self.sdUUID)
lvm.extendLV(self.sdUUID, sd.METADATA, newsize)
def mapMetaOffset(self, vol_name, slotSize):
--
To view, visit http://gerrit.ovirt.org/11690
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If90ba75d11c4962f2e52150e5f381cd93d0e8f35
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Eduardo <ewarszaw(a)redhat.com>
8 years, 11 months
Change in vdsm[master]: [WIP]add createVm support of cputune
by lvroyce@linux.vnet.ibm.com
Royce Lv has uploaded a new change for review.
Change subject: [WIP]add createVm support of cputune
......................................................................
[WIP]add createVm support of cputune
allow engine to pass other cputune params through vm create,
createVm now uses nice to config vm share value,
this patch uses 'shares' in vmdef directly (1024 by default)
Change-Id: I76e9b9d291d4801965163774ba45d15b39a77471
Signed-off-by: Royce Lv<lvroyce(a)linux.vnet.ibm.com>
---
M vdsm/libvirtvm.py
1 file changed, 13 insertions(+), 11 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/8445/1
diff --git a/vdsm/libvirtvm.py b/vdsm/libvirtvm.py
index fd80c69..9b38a36 100644
--- a/vdsm/libvirtvm.py
+++ b/vdsm/libvirtvm.py
@@ -737,10 +737,13 @@
self.dom.appendChild(cpu)
def appendTunable(self):
- #CPU-pinning support
- # see http://www.ovirt.org/wiki/Features/Design/cpu-pinning
+ cputune = self.doc.createElement('cputune')
+ cputuneParams = {'shares':1024}
+ if 'cputune' in self.conf:
+ cputuneParam = self.conf['cputune']
if 'cpuPinning' in self.conf:
- cputune = self.doc.createElement('cputune')
+ #CPU-pinning support
+ # see http://www.ovirt.org/wiki/Features/Design/cpu-pinning
cpuPinning = self.conf.get('cpuPinning')
try:
emulatorset = cpuPinning.pop('emulator')
@@ -754,7 +757,13 @@
vcpupin.setAttribute('vcpu', cpuPin)
vcpupin.setAttribute('cpuset', cpuPinning[cpuPin])
cputune.appendChild(vcpupin)
- self.dom.appendChild(cputune)
+
+ for item in cputuneParams.keys():
+ m = self.doc.createElement(item)
+ m.appendChild(self.doc.createTextNode(cputuneParams[item]))
+ cputune.appendChild(m)
+
+ self.dom.appendChild(cputune)
def _appendAgentDevice(self, path, name):
"""
@@ -1338,13 +1347,6 @@
if self._initTimePauseCode == 'ENOSPC':
self.cont()
self.conf['pid'] = self._getPid()
-
- nice = int(self.conf.get('nice', '0'))
- nice = max(min(nice, 19), 0)
- try:
- self._dom.setSchedulerParameters({'cpu_shares': (20 - nice) * 51})
- except:
- self.log.warning('failed to set Vm niceness', exc_info=True)
def _run(self):
self.log.info("VM wrapper has started")
--
To view, visit http://gerrit.ovirt.org/8445
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I76e9b9d291d4801965163774ba45d15b39a77471
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
8 years, 11 months
Change in vdsm[master]: [WIP] VDSM <=> Engine data optimization
by Vinzenz Feenstra
Vinzenz Feenstra has uploaded a new change for review.
Change subject: [WIP] VDSM <=> Engine data optimization
......................................................................
[WIP] VDSM <=> Engine data optimization
Change-Id: Ifa0a7a86a351a8c2d891f22802a95d1fe1bc1df4
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/vm.py
M vdsm_api/vdsmapi-schema.json
4 files changed, 499 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/41/14541/1
diff --git a/vdsm/API.py b/vdsm/API.py
index ee72116..ebf331d 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -334,6 +334,66 @@
return errCode['noVM']
return v.migrateStatus()
+ def getRuntimeStats(self):
+ """
+ Retrieve runtime statistics for the specific VM
+ """
+ v = self._cif.vmContainer.get(self._UUID)
+ if not v:
+ return errCode['noVM']
+ return {
+ 'status': doneCode,
+ 'runtimeStats': {
+ self._UUID: v.getRuntimeStats().copy()}}
+
+ def getStatus(self):
+ """
+ Retrieve VM status information for the specific VM
+ """
+ v = self._cif.vmContainer.get(self._UUID)
+ if not v:
+ return errCode['noVM']
+ return {
+ 'status': doneCode,
+ 'vmStatus': {
+ self._UUID: v.getStatus().copy()}}
+
+ def getDeviceStats(self):
+ """
+ Retrieve device statistics for the specific VM
+ """
+ v = self._cif.vmcontainer.get(self._uuid)
+ if not v:
+ return errCode['noVM']
+ return {
+ 'status': doneCode,
+ 'deviceStats': {
+ self._UUID: v.getDeviceStats().copy()}}
+
+ def getConfInfo(self):
+ """
+ Retrieve configuration information for the specific VM
+ """
+ v = self._cif.vmcontainer.get(self._uuid)
+ if not v:
+ return errCode['noVM']
+ return {
+ 'status': doneCode,
+ 'info': {
+ self._UUID: v.getInfo().copy()}}
+
+ def getGuestDetails(self):
+ """
+ Retrieve guest information for the specific VM
+ """
+ v = self._cif.vmcontainer.get(self._uuid)
+ if not v:
+ return errCode['noVM']
+ return {
+ 'status': doneCode,
+ 'guestDetails': {
+ self._UUID: v.getGuestDetails().copy()}}
+
def getStats(self):
"""
Obtain statistics of the specified VM
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 9a4db12..912018c 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -314,6 +314,52 @@
vm = API.VM(vmId)
return vm.getStats()
+ def vmGetRuntimeStats(self, vmIds):
+ result = {}
+ for vmId in vmIds:
+ vm = API.VM(vmId)
+ result.update(vm.getRuntimeStats()['runtimeStats'])
+ return {
+ 'status': doneCode,
+ 'runtimeStats': result}
+
+ def vmGetStatus(self, vmIds):
+ result = {}
+ for vmId in vmIds:
+ vm = API.VM(vmId)
+ result.update(vm.getStatus()['vmStatus'])
+ return {
+ 'status': doneCode,
+ 'vmStatus': result}
+
+ def vmGetAllDeviceStats(self):
+ vms = self.getVMList()
+ result = {}
+ for vm in vms['vmList']:
+ v = API.VM(vm['vmId'])
+ result.update(v.getDeviceStats()['deviceStats'])
+ return {
+ 'status': doneCode,
+ 'deviceStats': result}
+
+ def vmGetConfInfo(self, vmIds):
+ result = {}
+ for vmId in vmIds:
+ vm = API.VM(vmId)
+ result.update(vm.getConfInfo()['vmConfInfo'])
+ return {
+ 'status': doneCode,
+ 'vmConfInfo': result}
+
+ def vmGetGuestDetails(self, vmIds):
+ result = {}
+ for vmId in vmIds:
+ vm = API.VM(vmId)
+ result.update(vm.getGuestDetails()['guestDetails'])
+ return {
+ 'status': doneCode,
+ 'guestDetails': result}
+
def getAllVmStats(self):
"""
Get statistics of all running VMs.
diff --git a/vdsm/vm.py b/vdsm/vm.py
index ddb09c8..6d57649 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -26,6 +26,7 @@
import tempfile
import pickle
from copy import deepcopy
+import json
from vdsm import utils
from vdsm.define import NORMAL, ERROR, doneCode, errCode
@@ -1115,6 +1116,65 @@
self.conf['status'] = self.lastStatus
return self.conf
+ def _hashObject(self, o):
+ return str(hash(json.dumps(o)))
+
+ def _getHashes(self, stats):
+ return {
+ 'info': self._hashObject(self._getInfo(stats)),
+ 'status': self._hashObject(self._getStatus(stats)),
+ 'guestDetals': self._hashObject(self._getGuestDetails(stats))}
+
+ def _extractKeys(self, dictObject, keys):
+ extracted = {}
+ for k in keys:
+ v = dictObject.get(k)
+ if v:
+ extracted[k] = v
+ return extracted
+
+ def getRuntimeStats(self):
+ allStats = self.getStats()
+ USED_KEYS = ('cpuSys', 'cpuUser', 'memUsage', 'elapsedTime', 'status',
+ 'statsAge')
+ stats = self._extractKeys(allStats, USED_KEYS)
+ stats['hashes'] = self._getHashes(allStats)
+ if 'hash' in allStats:
+ stats['hashes']['config'] = allStats['hash']
+ return stats
+
+ def _getStatus(self, stats):
+ USED_KEYS = ('timeOffset', 'monitorResponse', 'clientIp', 'lastLogin',
+ 'username', 'session', 'guestIPs')
+ return self._extractKeys(stats, USED_KEYS)
+
+ def getStatus(self):
+ return self._getStatus(self.getStats())
+
+ def _getDeviceStats(self, stats):
+ USED_KEYS = ('network', 'disks', 'disksUsage', 'balloonInfo',
+ 'memoryStats')
+ return self._extractKeys(stats, USED_KEYS)
+
+ def getDeviceStats(self):
+ return self._getDeviceStats(self.getStats())
+
+ def _getInfo(self, stats):
+ USED_KEYS = ('acpiEnable', 'vmType', 'guestName', 'guestOS',
+ 'kvmEnable', 'pauseCode', 'displayIp', 'displayPort',
+ 'displaySecurePort', 'pid')
+ return self._extractKeys(stats, USED_KEYS)
+
+ def getInfo(self):
+ return self._getInfo(self.getStats())
+
+ def _getGuestDetails(self, stats):
+ USED_KEYS = ('appList', 'netIfaces')
+ return self._extractKeys(stats, USED_KEYS)
+
+ def getGuestDetails(self):
+ return self._getGuestDetails(self.getStats())
+
def getStats(self):
# used by API.Vm.getStats
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 4ff8c7a..33be905 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -4850,6 +4850,339 @@
'data': {'vmID': 'UUID'},
'returns': 'VmDefinition'}
+##
+# @VmRuntimeStatsHashes:
+#
+# Hashes of several statistics and information around VMs
+#
+# @info: Hash for VmConfInfo data
+#
+# @config: Hash of the VM configuration XML
+#
+# @status: Hash of the VmStatusInfo data
+#
+# @guestDetails: Hash of the VmGuestDetails data
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmRuntimeStatsHashes',
+ 'data': { 'info': 'str', 'config': 'str', 'status': 'str',
+ 'guestDetails': 'str'}}
+
+##
+# @VmRuntimeStats:
+#
+# Frequently changed and required data around VMs
+#
+# @cpuSys: Ratio of CPU time spent by qemu on other than guest time
+#
+# @cpuUser: Ratio of CPU time spent by the guest VM
+#
+# @memUsage: The percent of memory in use by the guest
+#
+# @elapsedTime: The number of seconds that the VM has been running
+#
+# @status: The current status of the given VM
+#
+# @statsAge: The age of these statistics in seconds
+#
+# @hashes: Hashes of several statistics and information around VMs
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmRuntimeStats',
+ 'data': { 'cpuSys': 'float', 'cpuUser': 'float', 'memUsage': 'uint',
+ 'elapsedTime': 'uint', 'status': 'VmStatus', 'statsAge': 'float',
+ 'hashes': 'VmRuntimeStatsHashes'}}
+
+##
+# @VmRuntimeStatsResult:
+#
+# Union result of VmRuntimeStats or ExitedVmStats
+#
+# @exited: Indicates if the result is VmRuntimeStats or ExitedVmStats
+#
+# Since: 4.10.3
+##
+{'type': 'VmRuntimeStatsResult',
+ 'data': { 'exited': 'bool' },
+ 'union': ['VmRuntimeStats', 'ExitedVmStats']}
+
+##
+# @VmRuntimeStatsMap:
+#
+# A mapping of VM runtime statistics indexed by vm id (UUID).
+#
+# Since: 4.10.3
+##
+{'map': 'VmRuntimeStatsMap',
+ 'key': 'UUID', 'value': 'VmRuntimeStatsResult' }}
+
+
+##
+# @VM.getRuntimeStats:
+#
+# Get runtime information about a list of VMs
+#
+# @vmIDs: a list of UUIDs for VMs to query
+#
+# Returns:
+# VmRuntimeStatsMap
+#
+# Since: 4.10.3
+##
+{'command': {'class': 'VM', 'name': 'getRuntimeStats'},
+ 'data': {'vmIDs': ['UUID']},
+ 'returns': 'VmRuntimeStatsMap'}
+
+##
+# @VmStatusInfo:
+#
+# Information to the status of a VM and less frequently changed information
+#
+# @timeOffset: The time difference from host to the VM in seconds
+#
+# @monitorResponse: Indicates if the qemu monitor is responsive
+#
+# @clientIp: The IP address of the client connected to the display
+#
+# @username: the username associated with the current session
+#
+# @session: The current state of user interaction with the VM
+#
+# @guestIPs: A space separated string of assigned IPv4 addresses
+#
+# @pauseCode: Indicates the reason a VM has been paused
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmStatusInfo',
+ 'data': { 'timeOffset': 'uint', 'monitorResponse': 'int', 'clientIp': 'str',
+ 'username': 'str', 'session': 'GuestSessionState',
+ 'guestIPs': 'str', 'pauseCode': 'str'}}
+
+##
+# @VmStatusInfoResult:
+#
+# Union result of VmStatusInfo or ExitedVmStats
+#
+# @exited: Indicates if the result is VmStatusInfo or ExitedVmStats
+#
+# Since: 4.10.3
+##
+{'type': 'VmStatusInfoResult',
+ 'data': { 'exited': 'bool' },
+ 'union': ['VmStatusInfo', 'ExitedVmStats']}
+
+##
+# @VmStatusInfoMap:
+#
+# A mapping of VM status information indexed by vm id (UUID).
+#
+# Since: 4.10.3
+##
+{'map': 'VmStatusInfoMap',
+ 'key': 'UUID', 'value': 'VmStatusInfoResult'}
+
+##
+# @VM.getStatus:
+#
+# Get status information about a list of VMs
+#
+# @vmIDs: a list of UUIDs for VMs to query
+#
+# Returns:
+# VmStatusMap
+#
+# Since: 4.10.3
+##
+{'command': {'class': 'VM', 'name': 'getStatus'},
+ 'data': {'vmIDs': ['UUID']},
+ 'returns': 'VmStatusInfoMap'}
+
+##
+# @VmConfInfo:
+#
+# VM configuration information
+#
+# @acpiEnable: Indicates if ACPI is enabled inside the VM
+#
+# @displayPort: The port in use for unencrypted display data
+#
+# @displaySecurePort: The port in use for encrypted display data
+#
+# @displayType: The type of display in use
+#
+# @displayIp: The IP address to use for accessing the VM display
+#
+# @pid: The process ID of the underlying qemu process
+#
+# @vmType: The type of VM
+#
+# @kvmEnable: Indicates if KVM hardware acceleration is enabled
+#
+# @cdrom: #optional The path to an ISO image used in the VM's CD-ROM device
+#
+# @boot: #optional An alias for the type of device used to boot the VM
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmConfInfo',
+ 'data': { 'acpiEnable': 'bool', 'vmType': 'VmType',
+ 'kvmEnable': 'bool', 'displayIp': 'str', 'displayPort': 'uint',
+ 'displaySecurePort': 'uint', 'displayType': 'VmDisplayType',
+ 'pid': 'uint', '*boot': 'VmBootMode', '*cdrom': 'str'}}
+
+##
+# @VmConfInfoResult:
+#
+# Union result of VmConfInfo or ExitedVmStats
+#
+# @exited: Indicates if the result is VmConfInfo or ExitedVmStats
+#
+# Since: 4.10.3
+##
+{'type': 'VmConfInfoResult',
+ 'data': { 'exited': 'bool' },
+ 'union': ['VmConfInfo', 'ExitedVmStats']}
+
+##
+# @VmConfInfoMap:
+#
+# A mapping of VM config information indexed by vm id (UUID).
+#
+# Since: 4.10.3
+##
+{'map': 'VmConfInfoMap',
+ 'key': 'UUID', 'value': 'VmConfInfoResult' }}
+
+##
+# @VM.getConfInfo:
+#
+# Get configuration information about a list of VMs
+#
+# @vmIDs: a list of UUIDs for VMs to query
+#
+# Returns:
+# VmConfInfoMap
+#
+# Since: 4.10.3
+##
+{'command': {'class': 'VM', 'name': 'getConfInfo'},
+ 'data': {'vmIDs': ['UUID']},
+ 'returns': 'VmConfInfoMap'}
+
+##
+# @VmDeviceStats:
+#
+# VM device statistics containing information for getting statistics and SLA
+# information.
+#
+# @memoryStats: Memory statistics as reported by the guest agent
+#
+# @balloonInfo: Guest memory balloon information
+#
+# @disksUsage: Info about mounted filesystems as reported by the agent
+#
+# @network: Network bandwidth/utilization statistics
+#
+# @disks: Disk bandwidth/utilization statistics
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmDeviceStats',
+ 'data': { 'network': 'NetworkInterfaceStatsMap', 'disks': 'VmDiskStatsMap',
+ 'disksUsage': ['GuestMountInfo'], 'balloonInfo': 'BalloonInfo',
+ 'memoryStats': 'GuestMemoryStats' }}
+
+##
+# @VmDeviceStatsResult:
+#
+# Union result of VmDeviceStats or ExitedVmStats
+#
+# @exited: Indicates if the result is VmDeviceStats or ExitedVmStats
+#
+# Since: 4.10.3
+##
+{'type': 'VmDeviceStatsResult',
+ 'data': { 'exited': 'bool' },
+ 'union': ['VmDeviceStats', 'ExitedVmStats']}
+
+##
+# @VmDeviceStatsMap:
+#
+# A mapping of VM device statistics indexed by vm id (UUID).
+#
+# Since: 4.10.3
+##
+{'map': 'VmDeviceStatsMap',
+ 'key': 'UUID', 'value': 'VmDeviceStatsResult' }}
+
+##
+# @VM.getAllDeviceStats:
+#
+# Get device statistics from all VMs
+#
+# Returns:
+# VmDeviceStatsMap
+#
+# Since: 4.10.3
+##
+{'command': {'class': 'VM', 'name': 'getAllDeviceStats'},
+ 'returns': 'VmDeviceStatsMap'}
+
+##
+# @VmGuestDetails:
+#
+# Non-frequent changed details from guest OSes
+#
+# @appsList: A list of installed applications with their versions
+#
+# @netIfaces: Network device address info as reported by the agent
+#
+# Since: 4.10.3
+##
+{ 'type': 'VmGuestDetails',
+ 'data': { 'appsList': ['str'], 'netIfaces': ['GuestNetworkDeviceInfo'] }}
+
+##
+# @VmGuestDetailsResult:
+#
+# Union result of VmDeviceStats or ExitedVmStats
+#
+# @exited: Indicates if the result is VmGuestDetails or ExitedVmStats
+#
+# Since: 4.10.3
+##
+{'type': 'VmGuestDetailsResult',
+ 'data': { 'exited': 'bool' },
+ 'union': ['VmGuestDetails', 'ExitedVmStats']}
+
+##
+# @VmGuestDetailsMap:
+#
+# A mapping of detailed information of guests indexed by vm id (UUID).
+#
+# Since: 4.10.3
+##
+{'map': 'VmGuestDetailsMap',
+ 'key': 'UUID', 'value': 'VmGuestDetailsResult' }}
+
+##
+# @VM.getGuestDetails:
+#
+# Get details from the guest OS from a list of VMs
+#
+# @vmIDs: a list of UUIDs for VMs to query
+#
+# Returns:
+# VmGuestDetailsMap
+#
+# Since: 4.10.3
+##
+{'command': {'class': 'VM', 'name': 'getGuestDetails'},
+ 'data': {'vmIDs': ['UUID']},
+ 'returns': 'VmGuestDetailsMap'}
##
# @VM.getMigrationStatus:
--
To view, visit http://gerrit.ovirt.org/14541
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifa0a7a86a351a8c2d891f22802a95d1fe1bc1df4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>
8 years, 11 months