Change in vdsm[master]: testing storageTest.py as CI job.
by vvolansk@redhat.com
Vered Volansky has uploaded a new change for review.
Change subject: testing storageTest.py as CI job.
......................................................................
testing storageTest.py as CI job.
Change-Id: I4d0caab1749e075f3650c91161b473e66b19977d
Signed-off-by: Vered Volansky <vvolansk(a)redhat.com>
---
M vdsm/storage/sp.py
1 file changed, 1 insertion(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/43/23343/1
diff --git a/vdsm/storage/sp.py b/vdsm/storage/sp.py
index 0bab95d..0cb7164 100644
--- a/vdsm/storage/sp.py
+++ b/vdsm/storage/sp.py
@@ -1,6 +1,7 @@
#
# Copyright 2009-2011 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
--
To view, visit http://gerrit.ovirt.org/23343
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4d0caab1749e075f3650c91161b473e66b19977d
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vered Volansky <vvolansk(a)redhat.com>
9 years, 7 months
Change in vdsm[master]: Create GuestAgent instance in __init__ and connect later
by Vinzenz Feenstra
Vinzenz Feenstra has uploaded a new change for review.
Change subject: Create GuestAgent instance in __init__ and connect later
......................................................................
Create GuestAgent instance in __init__ and connect later
This is not only a cosmetic improvement. There are cases where we
are trying to call methods of the GuestAgent before the instance was
created. To avoid these race conditions we're creating the instance of
the guest agent already in the __init__ phase.
Change-Id: I82f7397b01bff48a3c635eee9912cc67cf722b13
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
M vdsm/guestIF.py
M vdsm/vm.py
2 files changed, 7 insertions(+), 6 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/42/26142/1
diff --git a/vdsm/guestIF.py b/vdsm/guestIF.py
index 1f8d18d..1eaa42b 100644
--- a/vdsm/guestIF.py
+++ b/vdsm/guestIF.py
@@ -108,7 +108,7 @@
MAX_MESSAGE_SIZE = 2 ** 20 # 1 MiB for now
def __init__(self, socketName, channelListener, log, user='Unknown',
- ips='', connect=True):
+ ips=''):
self.effectiveApiVersion = _IMPLICIT_API_VERSION_ZERO
self.log = log
self._socketName = socketName
@@ -128,7 +128,8 @@
self._agentTimestamp = 0
self._channelListener = channelListener
self._messageState = MessageState.NORMAL
- if connect:
+
+ def connect(self):
try:
self._prepare_socket()
except:
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 1390c6e..7fbf07a 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -2008,7 +2008,6 @@
self._volPrepareLock = threading.Lock()
self._initTimePauseCode = None
self._initTimeRTC = long(self.conf.get('timeOffset', 0))
- self.guestAgent = None
self._guestEvent = 'Powering up'
self._guestEventTime = 0
self._vmStats = None
@@ -2028,6 +2027,8 @@
self.conf['vmName'] = 'n%s' % self.id
self._guestSocketFile = self._makeChannelPath(_VMCHANNEL_DEVICE_NAME)
self._qemuguestSocketFile = self._makeChannelPath(_QEMU_GA_DEVICE_NAME)
+ self.guestAgent = guestIF.GuestAgent(
+ self._guestSocketFile, self.cif.channelListener, self.log)
self._lastXMLDesc = '<domain><uuid>%s</uuid></domain>' % self.id
self._devXmlHash = '0'
self._released = False
@@ -3128,9 +3129,8 @@
# VmStatsThread may use block devices info from libvirt.
# So, run it after you have this info
self._initVmStats()
- self.guestAgent = guestIF.GuestAgent(
- self._guestSocketFile, self.cif.channelListener, self.log,
- connect=utils.tobool(self.conf.get('vmchannel', 'true')))
+ if utils.tobool(self.conf.get('vmchannel', 'true')):
+ self.guestAgent.connect()
self._guestCpuRunning = (self._dom.info()[0] ==
libvirt.VIR_DOMAIN_RUNNING)
--
To view, visit http://gerrit.ovirt.org/26142
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I82f7397b01bff48a3c635eee9912cc67cf722b13
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: logging: Add log handler that enforces perms
by dkuznets@redhat.com
Dima Kuznetsov has uploaded a new change for review.
Change subject: logging: Add log handler that enforces perms
......................................................................
logging: Add log handler that enforces perms
This handler, extending WatchedFileHandler, given the desired uid + gid of the
log file, checks that the running process satisfies the uid + gid
requirement.
Change-Id: I0a4d7212cb311b22e4fb60ffdc45163a496a74d6
Signed-off-by: Dima Kuznetsov <dkuznets(a)redhat.com>
---
M vdsm/logUtils.py
1 file changed, 16 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/28/26728/1
diff --git a/vdsm/logUtils.py b/vdsm/logUtils.py
index 6949d44..dd16249 100644
--- a/vdsm/logUtils.py
+++ b/vdsm/logUtils.py
@@ -19,6 +19,8 @@
#
import logging
+import logging.handlers
+import os
import sys
from functools import wraps
from inspect import ismethod
@@ -163,3 +165,17 @@
raise
except:
self.handleError(record)
+
+
+class EnforcingWatchedFileHandler(logging.handlers.WatchedFileHandler):
+ def __init__(self, uid, gid, *args, **kwargs):
+ self._uid = uid
+ self._gid = gid
+ logging.handlers.WatchedFileHandler.__init__(self, *args, **kwargs)
+
+ def _open(self):
+ if (os.geteuid() != self._uid) or (os.getegid() != self._gid):
+ raise RuntimeError(
+ "Attempt to open log with incorrect credentials"
+ )
+ return logging.handlers.WatchedFileHandler._open(self)
--
To view, visit http://gerrit.ovirt.org/26728
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0a4d7212cb311b22e4fb60ffdc45163a496a74d6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dima Kuznetsov <dkuznets(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: multipath: Fix devices rescanning
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: multipath: Fix devices rescanning
......................................................................
multipath: Fix devices rescanning
When rescanning devices, we used to update ISCSI devices, and then run
multipath to update device mapping. However, we never rescanned FC
devices.
Since commit dbf2089488 (Jul 9 2013) multipath call was change to use
the -r flag, forcing a reload of the device map. This was tested to fix
a case where new lun is created on the storage server, while a host was
connected, and the new device is not available when issuing the
getDeviceList command. According to a comment on gerrit, the change was
tested for ISCSI and FC storage types, but there is no documentation of
the testing procedure. The related bug has no information about what was
tested.
We currently have two bugs related multipath rescanning:
- Bug 1078879 tell us that invoking multipath with the -r flag sometimes
triggers a segfault in the multipathd daemon. In the bug, multipath
developer suggests that as long as multipathd daemon is running,
there is no need to invoke multipath to detect new devices, and
"multipath -r really isn't useful for much of anything".
- Bug 1071654 tell us that devices rescanning is broken on FC storage
domains (although the -r flag is used). The bug suggest to use
issue_lip sysfs api, which is also recommended in the RHEL storage
administration manual.
This patch removes the -r flag, which seem to be useless currently, and
adds the missing FC rescan using the recommended sysfs api.
To be on the safe side, I left the multipath call as it was since the
first multipath commit in 2009. We will work with kernel and multipath
developers further on removing this call if it is indeed unneeded.
Bug-Url: https://bugzilla.redhat.com/1078879
Bug-Url: https://bugzilla.redhat.com/1071654
Relates-to: http://gerrit.ovirt.org/17263
Change-Id: I7699504f9771232ee0b880f9c83a51fd5b90f40e
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/hba.py
M vdsm/storage/multipath.py
M vdsm/supervdsmServer
3 files changed, 34 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/22/27122/1
diff --git a/vdsm/storage/hba.py b/vdsm/storage/hba.py
index da3feef..050bec5 100644
--- a/vdsm/storage/hba.py
+++ b/vdsm/storage/hba.py
@@ -36,6 +36,31 @@
NODE_NAME = "node_name"
+def rescan():
+ """
+ Rescan HBAs connections, updating available devices.
+
+ This operation performs a Loop Initialization Protocol (LIP) and then
+ scans the interconnect and causes the SCSI layer to be updated to reflect
+ the devices currently on the bus. A LIP is, essentially, a bus reset, and
+ will cause device addition and removal.
+
+ Bear in mind that issue_lip is an asynchronous operation. The command may
+ complete before the entire scan has completed.
+
+ Note: Must be executed as root.
+ TODO: Some drivers do not support this operation.
+ """
+ log.info("Rescanning HBAs")
+ for path in glob.glob(FC_HOST_MASK + '/issue_lip'):
+ log.debug("Issuing lip %s", path)
+ try:
+ with open(path, 'w') as f:
+ f.write('1')
+ except IOError as e:
+ logging.error("Error issuing lip: %s", e)
+
+
def getiSCSIInitiators():
"""
Get iSCSI initiator name from the default location.
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 82d435d..ba98866 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -102,12 +102,12 @@
Should only be called from hsm._rescanDevices()
"""
- # First ask iSCSI to rescan all its sessions
+ # First rescan iSCSI and FCP connections
iscsi.rescan()
+ supervdsm.getProxy().hbaRescan()
# Now let multipath daemon pick up new devices
- cmd = [constants.EXT_MULTIPATH, "-r"]
- misc.execCmd(cmd, sudo=True)
+ misc.execCmd([constants.EXT_MULTIPATH], sudo=True)
def isEnabled():
diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer
index ffcedb8..dc6f602 100755
--- a/vdsm/supervdsmServer
+++ b/vdsm/supervdsmServer
@@ -58,6 +58,8 @@
from network import sourceroutethread
from network.api import (addNetwork, delNetwork, editNetwork, setupNetworks,
setSafeNetworkConfig)
+
+from storage import hba
from network.tc import setPortMirroring, unsetPortMirroring
from storage.multipath import getScsiSerial as _getScsiSerial
from storage.iscsi import getDevIscsiInfo as _getdeviSCSIinfo
@@ -253,6 +255,10 @@
return setSafeNetworkConfig()
@logDecorator
+ def hbaRescan(self):
+ return hba.rescan()
+
+ @logDecorator
def udevTrigger(self, guid):
self.__udevReloadRules(guid)
cmd = [EXT_UDEVADM, 'trigger', '--verbose', '--action', 'change',
--
To view, visit http://gerrit.ovirt.org/27122
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7699504f9771232ee0b880f9c83a51fd5b90f40e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: Move multipath configuration to vdsm-tool configurator
by ykaplan@redhat.com
Yeela Kaplan has uploaded a new change for review.
Change subject: Move multipath configuration to vdsm-tool configurator
......................................................................
Move multipath configuration to vdsm-tool configurator
Previously multipathe is recofigured on each vdsm
service restart.
Now it will be reconfigured only on user demand.
Change-Id: I40f802477e39000c5cae01a496ac2d9f879ebfa8
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M lib/vdsm/tool/configurator.py
M lib/vdsm/utils.py
M tests/miscTests.py
M tests/utilsTests.py
M vdsm/caps.py
M vdsm/storage/hsm.py
M vdsm/storage/misc.py
M vdsm/storage/multipath.py
M vdsm/storage/sd.py
M vdsm/supervdsmServer
10 files changed, 301 insertions(+), 281 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/23/26123/1
diff --git a/lib/vdsm/tool/configurator.py b/lib/vdsm/tool/configurator.py
index 869d774..d97af61 100644
--- a/lib/vdsm/tool/configurator.py
+++ b/lib/vdsm/tool/configurator.py
@@ -21,11 +21,10 @@
import sys
import grp
import argparse
+import tempfile
-from .. import utils
+from .. import utils, constants
from . import service, expose
-from ..constants import P_VDSM_EXEC, DISKIMAGE_GROUP
-from ..constants import QEMU_PROCESS_GROUP, VDSM_GROUP
class _ModuleConfigure(object):
@@ -68,7 +67,7 @@
rc, out, err = utils.execCmd(
(
os.path.join(
- P_VDSM_EXEC,
+ constants.P_VDSM_EXEC,
'libvirt_configure.sh'
),
action,
@@ -126,7 +125,7 @@
'/usr/sbin/usermod',
'-a',
'-G',
- '%s,%s' % (QEMU_PROCESS_GROUP, VDSM_GROUP),
+ '%s,%s' % (constants.QEMU_PROCESS_GROUP, constants.VDSM_GROUP),
'sanlock'
),
raw=True,
@@ -156,7 +155,7 @@
break
else:
raise RuntimeError("Unable to find sanlock service groups")
- ret = grp.getgrnam(DISKIMAGE_GROUP)[2] in groups
+ ret = grp.getgrnam(constants.DISKIMAGE_GROUP)[2] in groups
except IOError as e:
if e.errno == os.errno.ENOENT:
sys.stdout.write("sanlock service is not running\n")
@@ -172,9 +171,149 @@
return ret
+MPATH_CONF = "/etc/multipath.conf"
+
+STRG_MPATH_CONF = (
+ "\n\n"
+ "defaults {\n"
+ " polling_interval 5\n"
+ " getuid_callout \"%(scsi_id_path)s --whitelisted "
+ "--replace-whitespace --device=/dev/%%n\"\n"
+ " no_path_retry fail\n"
+ " user_friendly_names no\n"
+ " flush_on_last_del yes\n"
+ " fast_io_fail_tmo 5\n"
+ " dev_loss_tmo 30\n"
+ " max_fds 4096\n"
+ "}\n"
+ "\n"
+ "devices {\n"
+ "device {\n"
+ " vendor \"HITACHI\"\n"
+ " product \"DF.*\"\n"
+ " getuid_callout \"%(scsi_id_path)s --whitelisted "
+ "--replace-whitespace --device=/dev/%%n\"\n"
+ "}\n"
+ "device {\n"
+ " vendor \"COMPELNT\"\n"
+ " product \"Compellent Vol\"\n"
+ " no_path_retry fail\n"
+ "}\n"
+ "}"
+)
+
+OLD_TAGS = ["# RHAT REVISION 0.2", "# RHEV REVISION 0.3",
+ "# RHEV REVISION 0.4", "# RHEV REVISION 0.5",
+ "# RHEV REVISION 0.6", "# RHEV REVISION 0.7",
+ "# RHEV REVISION 0.8", "# RHEV REVISION 0.9"]
+MPATH_CONF_TAG = "# RHEV REVISION 1.0"
+MPATH_CONF_PRIVATE_TAG = "# RHEV PRIVATE"
+
+MPATH_CONF_TEMPLATE = MPATH_CONF_TAG + STRG_MPATH_CONF
+
+MAX_CONF_COPIES = 5
+
+_scsi_id = utils.CommandPath("scsi_id",
+ "/sbin/scsi_id", # EL6
+ "/usr/lib/udev/scsi_id", # Fedora
+ "/lib/udev/scsi_id", # Ubuntu
+ )
+
+
+class MultipathModuleConfigure(_ModuleConfigure):
+
+ def __init__(self):
+ super(MultipathModuleConfigure, self).__init__()
+
+ def getName(self):
+ return 'multipath'
+
+ def getServices(self):
+ return ["multipathd"]
+
+ def configure(self):
+ """
+ Set up the multipath daemon configuration to the known and
+ supported state. The original configuration, if any, is saved
+ """
+ if os.getuid() != 0:
+ raise UserWarning("Must run as root")
+ if self.isconfigured():
+ return
+ if os.path.exists(MPATH_CONF):
+ utils.rotateFiles(
+ os.path.dirname(MPATH_CONF),
+ os.path.basename(MPATH_CONF), MAX_CONF_COPIES,
+ cp=True, persist=True)
+ with tempfile.NamedTemporaryFile() as f:
+ f.write(MPATH_CONF_TEMPLATE % {'scsi_id_path': _scsi_id.cmd})
+ f.flush()
+ cmd = [constants.EXT_CP, f.name, MPATH_CONF]
+ rc, out, err = utils.execCmd(cmd)
+
+ if rc != 0:
+ raise RuntimeError("Failed to perform Multipath config.")
+ utils.persistFile(MPATH_CONF)
+
+ # Flush all unused multipath device maps
+ utils.execCmd([constants.EXT_MULTIPATH, "-F"])
+
+ cmd = [constants.EXT_VDSM_TOOL, "service-reload", "multipathd"]
+ rc, out, err = utils.execCmd(cmd)
+ if rc != 0:
+ raise RuntimeError("Failed to reload Multipath.")
+
+
+ def isconfigured(self, *args):
+ """
+ Check the multipath daemon configuration. The configuration file
+ /etc/multipath.conf should contain private tag in form
+ "RHEV REVISION X.Y" for this check to succeed.
+ If the tag above is followed by tag "RHEV PRIVATE" the configuration
+ should be preserved at all cost.
+
+ """
+ if os.getuid() != 0:
+ raise UserWarning("Must run as root")
+
+ if os.path.exists(MPATH_CONF):
+ first = second = ''
+ with open(MPATH_CONF) as f:
+ mpathconf = [x.strip("\n") for x in f.readlines()]
+ try:
+ first = mpathconf[0]
+ second = mpathconf[1]
+ except IndexError:
+ pass
+ if MPATH_CONF_PRIVATE_TAG in second:
+ sys.stdout.write("Manual override for multipath.conf detected"
+ " - preserving current configuration")
+ if MPATH_CONF_TAG not in first:
+ sys.stdout.write("This manual override for multipath.conf "
+ "was based on downrevved template. "
+ "You are strongly advised to "
+ "contact your support representatives")
+ return True
+
+ if MPATH_CONF_TAG in first:
+ sys.stdout.write("Current revision of multipath.conf detected,"
+ " preserving")
+ return True
+
+ for tag in OLD_TAGS:
+ if tag in first:
+ sys.stdout.write("Downrev multipath.conf detected, "
+ "upgrade required")
+ return False
+
+ sys.stdout.write("multipath Defaulting to False")
+ return False
+
+
__configurers = (
LibvirtModuleConfigure(),
SanlockModuleConfigure(),
+ MultipathModuleConfigure(),
)
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index b072bd4..b6a2ecc 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -79,6 +79,15 @@
HIGH = 19
+class OSName:
+ UNKNOWN = 'unknown'
+ OVIRT = 'oVirt Node'
+ RHEL = 'RHEL'
+ FEDORA = 'Fedora'
+ RHEVH = 'RHEV Hypervisor'
+ DEBIAN = 'Debian'
+
+
class GeneralException(Exception):
code = 100
message = "General Exception"
@@ -144,6 +153,62 @@
logging.warning("Directory: %s already removed", directoryToRemove)
else:
raise
+
+
+def rotateFiles(directory, prefixName, gen, cp=False, persist=False):
+ logging.debug("dir: %s, prefixName: %s, versions: %s" %
+ (directory, prefixName, gen))
+ gen = int(gen)
+ files = os.listdir(directory)
+ files = glob.glob("%s*" % prefixName)
+ fd = {}
+ for fname in files:
+ name = fname.rsplit('.', 1)
+ try:
+ ind = int(name[1])
+ except ValueError:
+ name[0] = fname
+ ind = 0
+ except IndexError:
+ ind = 0
+ except:
+ continue
+ if ind < gen:
+ fd[ind] = {'old': fname, 'new': name[0] + '.' + str(ind + 1)}
+
+ keys = fd.keys()
+ keys.sort(reverse=True)
+ logging.debug("versions found: %s" % (keys))
+
+ for key in keys:
+ oldName = os.path.join(directory, fd[key]['old'])
+ newName = os.path.join(directory, fd[key]['new'])
+ if isOvirtNode() and persist and not cp:
+ try:
+ execCmd([constants.EXT_UNPERSIST, oldName], logErr=False,
+ sudo=True)
+ execCmd([constants.EXT_UNPERSIST, newName], logErr=False,
+ sudo=True)
+ except:
+ pass
+ try:
+ if cp:
+ execCmd([constants.EXT_CP, oldName, newName], sudo=True)
+ if isOvirtNode() and persist and not os.path.exists(newName):
+ execCmd([constants.EXT_PERSIST, newName], logErr=False,
+ sudo=True)
+
+ else:
+ os.rename(oldName, newName)
+ except:
+ pass
+ if isOvirtNode() and persist and not cp:
+ try:
+ execCmd([constants.EXT_PERSIST, newName], logErr=False,
+ sudo=True)
+ except:
+ pass
+
IPXMLRPCRequestHandler = SimpleXMLRPCRequestHandler
@@ -826,6 +891,31 @@
return functools.partial(self.__call__, obj)
+@memoized
+def getos():
+ if os.path.exists('/etc/rhev-hypervisor-release'):
+ return OSName.RHEVH
+ elif glob.glob('/etc/ovirt-node-*-release'):
+ return OSName.OVIRT
+ elif os.path.exists('/etc/fedora-release'):
+ return OSName.FEDORA
+ elif os.path.exists('/etc/redhat-release'):
+ return OSName.RHEL
+ elif os.path.exists('/etc/debian_version'):
+ return OSName.DEBIAN
+ else:
+ return OSName.UNKNOWN
+
+
+def isOvirtNode():
+ return getos() in (OSName.RHEVH, OSName.OVIRT)
+
+
+def persistFile(name):
+ if isOvirtNode():
+ execCmd([constants.EXT_PERSIST, name], sudo=True)
+
+
def validateMinimalKeySet(dictionary, reqParams):
if not all(key in dictionary for key in reqParams):
raise ValueError
diff --git a/tests/miscTests.py b/tests/miscTests.py
index fb1191b..1932a43 100644
--- a/tests/miscTests.py
+++ b/tests/miscTests.py
@@ -242,63 +242,6 @@
self.assertRaises(ValueError, misc.itmap(int, data, 0).next)
-class RotateFiles(TestCaseBase):
- def testNonExistingDir(self, persist=False):
- """
- Tests that the method fails correctly when given a non existing dir.
- """
- self.assertRaises(OSError, misc.rotateFiles, "/I/DONT/EXIST", "prefix",
- 2, persist=persist)
-
- def testEmptyDir(self, persist=False):
- """
- Test that when given an empty dir the rotator works correctly.
- """
- prefix = "prefix"
- dir = tempfile.mkdtemp()
-
- misc.rotateFiles(dir, prefix, 0, persist=persist)
-
- os.rmdir(dir)
-
- def testFullDir(self, persist=False):
- """
- Test that rotator does it's basic functionality.
- """
- #Prepare
- prefix = "prefix"
- stubContent = ('"Multiple exclamation marks", '
- 'he went on, shaking his head, '
- '"are a sure sign of a diseased mind."')
- # (C) Terry Pratchet - Small Gods
- dir = tempfile.mkdtemp()
- gen = 10
-
- expectedDirContent = []
- for i in range(gen):
- fname = "%s.txt.%d" % (prefix, i + 1)
- expectedDirContent.append("%s.txt.%d" % (prefix, i + 1))
- f = open(os.path.join(dir, fname), "wb")
- f.write(stubContent)
- f.flush()
- f.close()
-
- #Rotate
- misc.rotateFiles(dir, prefix, gen, persist=persist)
-
- #Test result
- currentDirContent = os.listdir(dir)
- expectedDirContent.sort()
- currentDirContent.sort()
- try:
- self.assertEquals(currentDirContent, expectedDirContent)
- finally:
- #Clean
- for f in os.listdir(dir):
- os.unlink(os.path.join(dir, f))
- os.rmdir(dir)
-
-
class ParseHumanReadableSize(TestCaseBase):
def testValidInput(self):
"""
diff --git a/tests/utilsTests.py b/tests/utilsTests.py
index c5b250d..1e202d2 100644
--- a/tests/utilsTests.py
+++ b/tests/utilsTests.py
@@ -22,6 +22,7 @@
import contextlib
import errno
import logging
+import tempfile
from testrunner import VdsmTestCase as TestCaseBase
from vdsm import utils
@@ -302,3 +303,60 @@
def handle(self, record):
assert self.record is None
self.record = record
+
+
+class RotateFiles(TestCaseBase):
+ def testNonExistingDir(self, persist=False):
+ """
+ Tests that the method fails correctly when given a non existing dir.
+ """
+ self.assertRaises(OSError, utils.rotateFiles, "/I/DONT/EXIST",
+ "prefix", 2, persist=persist)
+
+ def testEmptyDir(self, persist=False):
+ """
+ Test that when given an empty dir the rotator works correctly.
+ """
+ prefix = "prefix"
+ dir = tempfile.mkdtemp()
+
+ utils.rotateFiles(dir, prefix, 0, persist=persist)
+
+ os.rmdir(dir)
+
+ def testFullDir(self, persist=False):
+ """
+ Test that rotator does it's basic functionality.
+ """
+ #Prepare
+ prefix = "prefix"
+ stubContent = ('"Multiple exclamation marks", '
+ 'he went on, shaking his head, '
+ '"are a sure sign of a diseased mind."')
+ # (C) Terry Pratchet - Small Gods
+ dir = tempfile.mkdtemp()
+ gen = 10
+
+ expectedDirContent = []
+ for i in range(gen):
+ fname = "%s.txt.%d" % (prefix, i + 1)
+ expectedDirContent.append("%s.txt.%d" % (prefix, i + 1))
+ f = open(os.path.join(dir, fname), "wb")
+ f.write(stubContent)
+ f.flush()
+ f.close()
+
+ #Rotate
+ utils.rotateFiles(dir, prefix, gen, persist=persist)
+
+ #Test result
+ currentDirContent = os.listdir(dir)
+ expectedDirContent.sort()
+ currentDirContent.sort()
+ try:
+ self.assertEquals(currentDirContent, expectedDirContent)
+ finally:
+ #Clean
+ for f in os.listdir(dir):
+ os.unlink(os.path.join(dir, f))
+ os.rmdir(dir)
diff --git a/vdsm/caps.py b/vdsm/caps.py
index 4f3d6f9..cdf5e1a 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -27,7 +27,6 @@
import logging
import time
import linecache
-import glob
import libvirt
import rpm
@@ -55,14 +54,6 @@
except ImportError:
_glusterEnabled = False
-
-class OSName:
- UNKNOWN = 'unknown'
- OVIRT = 'oVirt Node'
- RHEL = 'RHEL'
- FEDORA = 'Fedora'
- RHEVH = 'RHEV Hypervisor'
- DEBIAN = 'Debian'
RNG_SOURCES = {'random': '/dev/random',
'hwrng': '/dev/hwrng'}
@@ -275,32 +266,16 @@
@utils.memoized
-def getos():
- if os.path.exists('/etc/rhev-hypervisor-release'):
- return OSName.RHEVH
- elif glob.glob('/etc/ovirt-node-*-release'):
- return OSName.OVIRT
- elif os.path.exists('/etc/fedora-release'):
- return OSName.FEDORA
- elif os.path.exists('/etc/redhat-release'):
- return OSName.RHEL
- elif os.path.exists('/etc/debian_version'):
- return OSName.DEBIAN
- else:
- return OSName.UNKNOWN
-
-
-(a)utils.memoized
def osversion():
version = release = ''
- osname = getos()
+ osname = utils.getos()
try:
- if osname == OSName.RHEVH or osname == OSName.OVIRT:
+ if osname == utils.OSName.RHEVH or osname == utils.OSName.OVIRT:
d = _parseKeyVal(file('/etc/default/version'))
version = d.get('VERSION', '')
release = d.get('RELEASE', '')
- elif osname == OSName.DEBIAN:
+ elif osname == utils.OSName.DEBIAN:
version = linecache.getline('/etc/debian_version', 1).strip("\n")
release = "" # Debian just has a version entry
else:
@@ -403,7 +378,8 @@
pkgs = {'kernel': kernelDict()}
- if getos() in (OSName.RHEVH, OSName.OVIRT, OSName.FEDORA, OSName.RHEL):
+ if utils.getos() in (utils.OSName.RHEVH, utils.OSName.OVIRT,
+ utils.OSName.FEDORA, utils.OSName.RHEL):
KEY_PACKAGES = {'qemu-kvm': ('qemu-kvm', 'qemu-kvm-rhev'),
'qemu-img': ('qemu-img', 'qemu-img-rhev'),
'vdsm': ('vdsm',),
@@ -434,7 +410,7 @@
except:
logging.error('', exc_info=True)
- elif getos() == OSName.DEBIAN and python_apt:
+ elif utils.getos() == utils.OSName.DEBIAN and python_apt:
KEY_PACKAGES = {'qemu-kvm': 'qemu-kvm', 'qemu-img': 'qemu-utils',
'vdsm': 'vdsmd', 'spice-server': 'libspice-server1',
'libvirt': 'libvirt0', 'mom': 'mom'}
@@ -454,7 +430,3 @@
logging.error('', exc_info=True)
return pkgs
-
-
-def isOvirtNode():
- return getos() in (OSName.RHEVH, OSName.OVIRT)
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 6bae0bd..0cd40f6 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -350,9 +350,6 @@
self._preparedVolumes = defaultdict(list)
- if not multipath.isEnabled():
- multipath.setupMultipath()
-
self.__validateLvmLockingType()
self.domainStateChangeCallbacks = set()
diff --git a/vdsm/storage/misc.py b/vdsm/storage/misc.py
index 48020b6..1cc73ee 100644
--- a/vdsm/storage/misc.py
+++ b/vdsm/storage/misc.py
@@ -55,7 +55,6 @@
import storage_exception as se
import fileUtils
import logUtils
-from caps import isOvirtNode
IOUSER = "vdsm"
DIRECTFLAG = "direct"
@@ -477,66 +476,6 @@
if n < 0:
raise se.InvalidParameterException(name, number)
return n
-
-
-def rotateFiles(directory, prefixName, gen, cp=False, persist=False):
- log.debug("dir: %s, prefixName: %s, versions: %s" %
- (directory, prefixName, gen))
- gen = int(gen)
- files = os.listdir(directory)
- files = glob.glob("%s*" % prefixName)
- fd = {}
- for fname in files:
- name = fname.rsplit('.', 1)
- try:
- ind = int(name[1])
- except ValueError:
- name[0] = fname
- ind = 0
- except IndexError:
- ind = 0
- except:
- continue
- if ind < gen:
- fd[ind] = {'old': fname, 'new': name[0] + '.' + str(ind + 1)}
-
- keys = fd.keys()
- keys.sort(reverse=True)
- log.debug("versions found: %s" % (keys))
-
- for key in keys:
- oldName = os.path.join(directory, fd[key]['old'])
- newName = os.path.join(directory, fd[key]['new'])
- if isOvirtNode() and persist and not cp:
- try:
- execCmd([constants.EXT_UNPERSIST, oldName], logErr=False,
- sudo=True)
- execCmd([constants.EXT_UNPERSIST, newName], logErr=False,
- sudo=True)
- except:
- pass
- try:
- if cp:
- execCmd([constants.EXT_CP, oldName, newName], sudo=True)
- if isOvirtNode() and persist and not os.path.exists(newName):
- execCmd([constants.EXT_PERSIST, newName], logErr=False,
- sudo=True)
-
- else:
- os.rename(oldName, newName)
- except:
- pass
- if isOvirtNode() and persist and not cp:
- try:
- execCmd([constants.EXT_PERSIST, newName], logErr=False,
- sudo=True)
- except:
- pass
-
-
-def persistFile(name):
- if isOvirtNode():
- execCmd([constants.EXT_PERSIST, name], sudo=True)
def parseHumanReadableSize(size):
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 29851f3..4ffcd1d 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -25,7 +25,6 @@
import os
import errno
from glob import glob
-import tempfile
import logging
import re
from collections import namedtuple
@@ -37,53 +36,11 @@
import supervdsm
import devicemapper
-import storage_exception as se
-
DEV_ISCSI = "iSCSI"
DEV_FCP = "FCP"
DEV_MIXED = "MIXED"
-MAX_CONF_COPIES = 5
-
TOXIC_CHARS = '()*+?|^$.\\'
-
-MPATH_CONF = "/etc/multipath.conf"
-
-OLD_TAGS = ["# RHAT REVISION 0.2", "# RHEV REVISION 0.3",
- "# RHEV REVISION 0.4", "# RHEV REVISION 0.5",
- "# RHEV REVISION 0.6", "# RHEV REVISION 0.7",
- "# RHEV REVISION 0.8", "# RHEV REVISION 0.9"]
-MPATH_CONF_TAG = "# RHEV REVISION 1.0"
-MPATH_CONF_PRIVATE_TAG = "# RHEV PRIVATE"
-STRG_MPATH_CONF = (
- "\n\n"
- "defaults {\n"
- " polling_interval 5\n"
- " getuid_callout \"%(scsi_id_path)s --whitelisted "
- "--replace-whitespace --device=/dev/%%n\"\n"
- " no_path_retry fail\n"
- " user_friendly_names no\n"
- " flush_on_last_del yes\n"
- " fast_io_fail_tmo 5\n"
- " dev_loss_tmo 30\n"
- " max_fds 4096\n"
- "}\n"
- "\n"
- "devices {\n"
- "device {\n"
- " vendor \"HITACHI\"\n"
- " product \"DF.*\"\n"
- " getuid_callout \"%(scsi_id_path)s --whitelisted "
- "--replace-whitespace --device=/dev/%%n\"\n"
- "}\n"
- "device {\n"
- " vendor \"COMPELNT\"\n"
- " product \"Compellent Vol\"\n"
- " no_path_retry fail\n"
- "}\n"
- "}"
-)
-MPATH_CONF_TEMPLATE = MPATH_CONF_TAG + STRG_MPATH_CONF
log = logging.getLogger("Storage.Multipath")
@@ -108,76 +65,6 @@
# Now let multipath daemon pick up new devices
cmd = [constants.EXT_MULTIPATH, "-r"]
misc.execCmd(cmd, sudo=True)
-
-
-def isEnabled():
- """
- Check the multipath daemon configuration. The configuration file
- /etc/multipath.conf should contain private tag in form
- "RHEV REVISION X.Y" for this check to succeed.
- If the tag above is followed by tag "RHEV PRIVATE" the configuration
- should be preserved at all cost.
-
- """
- if os.path.exists(MPATH_CONF):
- first = second = ''
- svdsm = supervdsm.getProxy()
- mpathconf = svdsm.readMultipathConf()
- try:
- first = mpathconf[0]
- second = mpathconf[1]
- except IndexError:
- pass
- if MPATH_CONF_PRIVATE_TAG in second:
- log.info("Manual override for multipath.conf detected - "
- "preserving current configuration")
- if MPATH_CONF_TAG not in first:
- log.warning("This manual override for multipath.conf "
- "was based on downrevved template. "
- "You are strongly advised to "
- "contact your support representatives")
- return True
-
- if MPATH_CONF_TAG in first:
- log.debug("Current revision of multipath.conf detected, "
- "preserving")
- return True
-
- for tag in OLD_TAGS:
- if tag in first:
- log.info("Downrev multipath.conf detected, upgrade required")
- return False
-
- log.debug("multipath Defaulting to False")
- return False
-
-
-def setupMultipath():
- """
- Set up the multipath daemon configuration to the known and
- supported state. The original configuration, if any, is saved
- """
- if os.path.exists(MPATH_CONF):
- misc.rotateFiles(
- os.path.dirname(MPATH_CONF),
- os.path.basename(MPATH_CONF), MAX_CONF_COPIES,
- cp=True, persist=True)
- with tempfile.NamedTemporaryFile() as f:
- f.write(MPATH_CONF_TEMPLATE % {'scsi_id_path': _scsi_id.cmd})
- f.flush()
- cmd = [constants.EXT_CP, f.name, MPATH_CONF]
- rc = misc.execCmd(cmd, sudo=True)[0]
- if rc != 0:
- raise se.MultipathSetupError()
- misc.persistFile(MPATH_CONF)
-
- # Flush all unused multipath device maps
- misc.execCmd([constants.EXT_MULTIPATH, "-F"], sudo=True)
-
- cmd = [constants.EXT_VDSM_TOOL, "service-reload", "multipathd"]
- rc = misc.execCmd(cmd, sudo=True)[0]
- if rc != 0:
- raise se.MultipathReloadError()
def deduceType(a, b):
diff --git a/vdsm/storage/sd.py b/vdsm/storage/sd.py
index 3249343..877f527 100644
--- a/vdsm/storage/sd.py
+++ b/vdsm/storage/sd.py
@@ -30,7 +30,7 @@
import resourceFactories
from resourceFactories import IMAGE_NAMESPACE, VOLUME_NAMESPACE
import resourceManager as rm
-from vdsm import constants
+from vdsm import constants, utils
import clusterlock
import outOfProcess as oop
from persistentDict import unicodeEncoder, unicodeDecoder
@@ -702,7 +702,7 @@
def setMetadata(self, newMetadata):
# Backup old md (rotate old backup files)
- misc.rotateFiles(self.mdBackupDir, self.sdUUID, self.mdBackupVersions)
+ utils.rotateFiles(self.mdBackupDir, self.sdUUID, self.mdBackupVersions)
oldMd = ["%s=%s\n" % (key, value)
for key, value in self.getMetadata().copy().iteritems()]
open(os.path.join(self.mdBackupDir, self.sdUUID),
diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer
index 59df478..a902b09 100755
--- a/vdsm/supervdsmServer
+++ b/vdsm/supervdsmServer
@@ -142,11 +142,6 @@
return _getLsBlk(*args, **kwargs)
@logDecorator
- def readMultipathConf(self):
- with open(MPATH_CONF) as f:
- return [x.strip("\n") for x in f.readlines()]
-
- @logDecorator
def getScsiSerial(self, *args, **kwargs):
return _getScsiSerial(*args, **kwargs)
--
To view, visit http://gerrit.ovirt.org/26123
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I40f802477e39000c5cae01a496ac2d9f879ebfa8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: virt: Move all guest agents related cleanup together
by Vinzenz Feenstra
Vinzenz Feenstra has uploaded a new change for review.
Change subject: virt: Move all guest agents related cleanup together
......................................................................
virt: Move all guest agents related cleanup together
This patch moves the qemu guest agent socket cleanup together
with the ovirt guest agent related cleanup.
Change-Id: I99da4b5b9dcb160974205ebbb3c6d6727415e617
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 4 insertions(+), 4 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/80/26280/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 944558e..a409752 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -2777,9 +2777,9 @@
except Exception:
pass
- def _cleanupGuestAgent(self):
+ def _cleanupGuestAgents(self):
"""
- Try to stop the guest agent and clean up its socket
+ Try to stop the guest agent and clean up all guest agent sockets
"""
try:
self.guestAgent.stop()
@@ -2787,6 +2787,7 @@
pass
self._guestSockCleanup(self._guestSocketFile)
+ self._guestSockCleanup(self._qemuguestSocketFile)
def setDownStatus(self, code, exitReasonCode, exitMessage=''):
if not exitMessage:
@@ -3073,9 +3074,8 @@
"""
self._cleanupDrives()
self._cleanupFloppy()
- self._cleanupGuestAgent()
+ self._cleanupGuestAgents()
utils.rmFile(self._recoveryFile)
- self._guestSockCleanup(self._qemuguestSocketFile)
def updateGuestCpuRunning(self):
self._guestCpuRunning = (self._dom.info()[0] ==
--
To view, visit http://gerrit.ovirt.org/26280
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I99da4b5b9dcb160974205ebbb3c6d6727415e617
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: block: add reduceStorageDomain command
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: block: add reduceStorageDomain command
......................................................................
block: add reduceStorageDomain command
Change-Id: I467fc12d3787929b9c0e35f8806402f72f493368
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/storage/blockSD.py
M vdsm/storage/hsm.py
M vdsm/storage/lvm.py
M vdsm/storage/sp.py
M vdsm/storage/storage_exception.py
M vdsm_api/vdsmapi-schema.json
9 files changed, 86 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/74/26574/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index b324eb1..ccbdb15 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -678,6 +678,15 @@
return dom['status']['code'], dom['status']['message']
return 0, ''
+ def reduceStorageDomain(self, args):
+ sdUUID = args[0]
+ spUUID = args[1]
+ devList = args[2].split(',')
+ dom = self.s.reduceStorageDomain(sdUUID, spUUID, devList)
+ if dom['status']['code']:
+ return dom['status']['code'], dom['status']['message']
+ return 0, ''
+
def discoverST(self, args):
portal = args[0].split(":")
ip = portal[0]
@@ -2067,6 +2076,11 @@
'Extend the Storage Domain by adding devices'
' devlist (list of dev GUIDs)'
)),
+ 'reduceStorageDomain': (serv.reduceStorageDomain, (
+ '<sdUUID> <spUUID> <devlist>',
+ 'Reduce the Storage Domain by removing devices devlist (list of '
+ 'dev GUIDs)'
+ )),
'discoverST': (serv.discoverST,
('ip[:port] [username password]',
'Discover the available iSCSI targetnames on a '
diff --git a/vdsm/API.py b/vdsm/API.py
index 94b39b6..af22e50 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -961,6 +961,9 @@
return self._irs.extendStorageDomain(self._UUID, spUUID, devlist,
force)
+ def reduce(self, spUUID, devlist):
+ return self._irs.reduceStorageDomain(self._UUID, spUUID, devlist)
+
def format(self, autoDetach):
return self._irs.formatStorageDomain(self._UUID, autoDetach)
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 76251f5..4def574 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -546,6 +546,10 @@
domain = API.StorageDomain(sdUUID)
return domain.extend(spUUID, devlist, force)
+ def domainReduce(self, sdUUID, spUUID, devlist, options=None):
+ domain = API.StorageDomain(sdUUID)
+ return domain.reduce(spUUID, devlist)
+
def domainFormat(self, sdUUID,
autoDetach=False, options=None):
domain = API.StorageDomain(sdUUID)
@@ -949,6 +953,7 @@
(self.domainDetach, 'detachStorageDomain'),
(self.domainDetachForced, 'forcedDetachStorageDomain'),
(self.domainExtend, 'extendStorageDomain'),
+ (self.domainReduce, 'reduceStorageDomain'),
(self.domainFormat, 'formatStorageDomain'),
(self.domainGetFileStats, 'getFileStats'),
(self.domainGetImages, 'getImagesList'),
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index f807d3e..c31bb97 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -734,6 +734,10 @@
else:
return self.getFreeMetadataSlot(slotSize)
+ def reduce(self, devlist):
+ with self._extendlock:
+ lvm.reduceVG(self.sdUUID, devlist)
+
def _getOccupiedMetadataSlots(self):
stripPrefix = lambda s, pfx: s[len(pfx):]
occupiedSlots = []
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 0ebe129..93ec28c 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -753,6 +753,14 @@
pool.extendSD(sdUUID, dmDevs, force)
@public
+ def reduceStorageDomain(self, sdUUID, spUUID, guids):
+ vars.task.getSharedLock(STORAGE, sdUUID)
+ pool = self.getPool(spUUID)
+ dmDevs = tuple(os.path.join(devicemapper.DMPATH_PREFIX, guid) for guid
+ in guids)
+ pool.reduceSD(sdUUID, dmDevs)
+
+ @public
def forcedDetachStorageDomain(self, sdUUID, spUUID, options=None):
"""Forced detach a storage domain from a storage pool.
This removes the storage domain entry in the storage pool meta-data
diff --git a/vdsm/storage/lvm.py b/vdsm/storage/lvm.py
index d36c505..4b6015e 100644
--- a/vdsm/storage/lvm.py
+++ b/vdsm/storage/lvm.py
@@ -49,7 +49,7 @@
LVM_DEFAULT_TTL = 100
PV_FIELDS = ("uuid,name,size,vg_name,vg_uuid,pe_start,pe_count,"
- "pe_alloc_count,mda_count,dev_size")
+ "pe_alloc_count,mda_count,dev_size,pv_mda_used_count")
VG_FIELDS = ("uuid,name,attr,size,free,extent_size,extent_count,free_count,"
"tags,vg_mda_size,vg_mda_free,lv_count,pv_count,pv_name")
LV_FIELDS = "uuid,name,vg_name,attr,size,seg_start_pe,devices,tags"
@@ -966,6 +966,28 @@
raise se.VolumeGroupExtendError(vgName, pvs)
+def reduceVG(vgName, devices):
+ pvs = [pdev for pdev in _normalizeargs(devices)]
+ vgpvs = _lvminfo._getVGDevs((vgName,))
+
+ for pv in pvs:
+ if pv not in vgpvs:
+ raise se.BlockDeviceActionError(
+ 'Phisical device %s not in vg %s' % (pv, vgName))
+ if int(getPV(pv).pv_mda_used_count) != 0:
+ raise se.BlockDeviceActionError(
+ 'Phisical device %s contains the lvm metadata')
+
+ cmd = ["vgreduce", vgName] + pvs
+ rc, out, err = _lvminfo.cmd(cmd, vgpvs)
+ if rc == 0:
+ _lvminfo._invalidatepvs(vgpvs)
+ _lvminfo._invalidatevgs(vgName)
+ log.debug("Cache after reducing vg %s", _lvminfo._vgs)
+ else:
+ raise se.VolumeGroupReduceError(vgName, pvs)
+
+
def chkVG(vgName):
cmd = ["vgck", vgName]
rc, out, err = _lvminfo.cmd(cmd, _lvminfo._getVGDevs((vgName, )))
diff --git a/vdsm/storage/sp.py b/vdsm/storage/sp.py
index 338232f..f4d4987 100644
--- a/vdsm/storage/sp.py
+++ b/vdsm/storage/sp.py
@@ -1862,6 +1862,10 @@
self.validatePoolSD(sdUUID)
sdCache.produce(sdUUID).extend(devlist, force)
+ def reduceSD(self, sdUUID, devlist):
+ self.validatePoolSD(sdUUID)
+ sdCache.produce(sdUUID).reduce(devlist)
+
def setSDDescription(self, sd, description):
self.validatePoolSD(sd.sdUUID)
sd.setDescription(descr=description)
diff --git a/vdsm/storage/storage_exception.py b/vdsm/storage/storage_exception.py
index b4f3b66..226508a 100644
--- a/vdsm/storage/storage_exception.py
+++ b/vdsm/storage/storage_exception.py
@@ -1504,6 +1504,13 @@
issue and how to resolve it"""
+class VolumeGroupReduceError(StorageException):
+ def __init__(self, vgname, devname):
+ self.value = "vgname=%s, devname=%s" % (vgname, devname)
+ code = 503
+ message = "Cannot reduce Volume Group"
+
+
#################################################
# SPM/HSM Exceptions
#################################################
diff --git a/vdsm_api/vdsmapi-schema.json b/vdsm_api/vdsmapi-schema.json
index 31bd869..61fc66c 100644
--- a/vdsm_api/vdsmapi-schema.json
+++ b/vdsm_api/vdsmapi-schema.json
@@ -4169,6 +4169,24 @@
'devlist': ['str'], '*force': 'bool'}}
##
+# @StorageDomain.reduce:
+#
+# Reduce a block-based Storage Domain freeing block devices that are not in
+# use (no lvm metadata and lvs).
+#
+# @storagedomainID: The UUID of the Storage Domain
+#
+# @storagepoolID: The UUID of the Storage Pool
+#
+# @devlist: An array of block device names to remove from the domain
+#
+# Since: 4.14.0
+##
+{'command': {'class': 'StorageDomain', 'name': 'reduce'},
+ 'data': {'storagedomainID': 'UUID', 'storagepoolID': 'UUID',
+ 'devlist': ['str']}}
+
+##
# @StorageDomain.format:
#
# Format a storage domain and erase all of its data.
--
To view, visit http://gerrit.ovirt.org/26574
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I467fc12d3787929b9c0e35f8806402f72f493368
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: ifcfg: Log unhandled exception for new Thread
by Maor Lipchuk
Maor Lipchuk has uploaded a new change for review.
Change subject: ifcfg: Log unhandled exception for new Thread
......................................................................
ifcfg: Log unhandled exception for new Thread
Ading a traceback log for unhandled exceptions,
when openning a new thread, so it will not die silently.
Since the log in ifcfg instance is inaccessible from the decorator,
we use the default root logger.
Change-Id: I2ce44b4586e85438898fcdcd2d62d80813caa5ba
Signed-off-by: Maor Lipchuk <mlipchuk(a)redhat.com>
---
M vdsm/netconf/ifcfg.py
1 file changed, 1 insertion(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/85/23085/1
diff --git a/vdsm/netconf/ifcfg.py b/vdsm/netconf/ifcfg.py
index 52b95b1..8431e80 100644
--- a/vdsm/netconf/ifcfg.py
+++ b/vdsm/netconf/ifcfg.py
@@ -738,6 +738,7 @@
def ifup(iface, async=False):
"Bring up an interface"
+ @utils.traceback()
def _ifup(netIf):
rc, out, err = utils.execCmd([constants.EXT_IFUP, netIf], raw=False)
--
To view, visit http://gerrit.ovirt.org/23085
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2ce44b4586e85438898fcdcd2d62d80813caa5ba
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Maor Lipchuk <mlipchuk(a)redhat.com>
9 years, 8 months
Change in vdsm[master]: Allow GZIP transport on XMLRPC
by Vinzenz Feenstra
Vinzenz Feenstra has uploaded a new change for review.
Change subject: Allow GZIP transport on XMLRPC
......................................................................
Allow GZIP transport on XMLRPC
Change-Id: Iebdaa04b17e2c1df1c1852ed536c5d6d8ec8d88b
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
M lib/vdsm/utils.py
M lib/vdsm/vdscli.py.in
2 files changed, 113 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/01/25201/1
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index b682dec..81397ef 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -37,6 +37,7 @@
import fcntl
import functools
import glob
+import gzip
import io
import itertools
import logging
@@ -44,6 +45,7 @@
import os
import platform
import pwd
+import re
import select
import shutil
import signal
@@ -148,6 +150,28 @@
raise
+##
+# Encode a string using the gzip content encoding such as specified by the
+# Content-Encoding: gzip
+# in the HTTP header, as described in RFC 1952
+#
+# @param data the unencoded data
+# @return the encoded data
+
+def gzip_encode(data):
+ """data -> gzip encoded data
+
+ Encode data using the gzip content encoding as described in RFC 1952
+ """
+ f = StringIO()
+ gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
+ gzf.write(data)
+ gzf.close()
+ encoded = f.getvalue()
+ f.close()
+ return encoded
+
+
class IPXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
if config.getboolean('vars', 'xmlrpc_http11'):
@@ -171,6 +195,26 @@
# the methods only on Python 2.6.
if sys.version_info[:2] == (2, 6):
+ def __init__(self, *args, **kwargs):
+ self.encode_threshold = 1400
+ SimpleXMLRPCRequestHandler.__init__(self, *args, **kwargs)
+
+ # a re to match a gzip Accept-Encoding
+ aepattern = re.compile(r"""
+ \s* ([^\s;]+) \s* #content-coding
+ (;\s* q \s*=\s* ([0-9\.]+))? #q
+ """, re.VERBOSE | re.IGNORECASE)
+
+ def accept_encodings(self):
+ r = {}
+ ae = self.headers.get("Accept-Encoding", "")
+ for e in ae.split(","):
+ match = self.aepattern.match(e)
+ if match:
+ v = match.group(3)
+ v = float(v) if v else 1.0
+ r[match.group(1)] = v
+ return r
def do_POST(self):
# Check that the path is legal
@@ -183,7 +227,7 @@
# We read this in chunks to avoid straining
# socket.read(); around the 10 or 15Mb mark, some platforms
# begin to have problems (bug #792570).
- max_chunk_size = 10*1024*1024
+ max_chunk_size = 10 * 1024 * 1024
size_remaining = int(self.headers["content-length"])
L = []
while size_remaining:
@@ -218,9 +262,20 @@
# got a valid XML RPC response
self.send_response(200)
self.send_header("Content-type", "text/xml")
+ pureLen = len(response)
+ if self.encode_threshold is not None:
+ if pureLen > self.encode_threshold:
+ q = self.accept_encodings().get("gzip", 0)
+ if q:
+ response = gzip_encode(response)
+ self.send_header("Content-encoding", "gzip")
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
+ import datetime
+ import re
+ with open('/tmp/rpc-stats.log', 'a') as statslog:
+ statslog.write("%s - %s - %d - %d\n" % (datetime.datetime.utcnow().isoformat(), re.search(r'(?<=<methodName>)(.+)(?=<\/methodName)', data).group(0), len(response), pureLen))
def report_404(self):
self.send_response(404)
diff --git a/lib/vdsm/vdscli.py.in b/lib/vdsm/vdscli.py.in
index 5fa7528..e9e5c26 100644
--- a/lib/vdsm/vdscli.py.in
+++ b/lib/vdsm/vdscli.py.in
@@ -19,10 +19,12 @@
# Refer to the README and COPYING files for full details of the license
#
+import gzip
import xmlrpclib
import subprocess
import os
import re
+import StringIO
import sys
from xml.parsers.expat import ExpatError
from . import SecureXMLRPCServer
@@ -34,7 +36,61 @@
d_port = '54321'
+if sys.version_info[:2] == (2, 6):
+ class GzipDecodedResponse(gzip.GzipFile if gzip else object):
+ """a file-like object to decode a response encoded with the gzip
+ method, as described in RFC 1952.
+ """
+ def __init__(self, response):
+ data = response.read()
+ with open("/tmp/client.dump", "wb") as f:
+ f.write(data)
+ self.stringio = StringIO.StringIO(data)
+ gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
+
+ def close(self):
+ gzip.GzipFile.close(self)
+ self.stringio.close()
+
+ def wrap_request(transport):
+ self = transport
+
+ def wrapped_request(host, handler, request_body, verbose=0):
+ # issue XML-RPC request
+ h = self.make_connection(host)
+ if verbose:
+ h.set_debuglevel(1)
+
+ self.send_request(h, handler, request_body)
+ self.send_host(h, host)
+ self.send_user_agent(h)
+ h.putheader("Accept-Encoding", "gzip")
+ self.send_content(h, request_body)
+
+ errcode, errmsg, headers = h.getreply()
+
+ if errcode != 200:
+ raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg,
+ headers)
+
+ try:
+ sock = h._conn.sock
+ except AttributeError:
+ sock = None
+
+ self.verbose = verbose
+ #print headers.dict
+ if headers.get('Content-encoding', '') == 'gzip':
+ return self.parse_response(GzipDecodedResponse(h.getfile()))
+ else:
+ return self._parse_response(h.getfile(), sock)
+
+ transport.request = wrapped_request
+
+
def wrap_transport(transport):
+ if sys.version_info[:2] == (2, 6):
+ wrap_request(transport)
old_parse_response = transport.parse_response
def wrapped_parse_response(*args, **kwargs):
@@ -42,7 +98,7 @@
return old_parse_response(*args, **kwargs)
except ExpatError:
sys.stderr.write('Parsing error was thrown during parsing '
- 'response when provided: {}'.format(args[1]))
+ 'response when provided: {0}'.format(args))
raise
transport.parse_response = wrapped_parse_response
return transport
--
To view, visit http://gerrit.ovirt.org/25201
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iebdaa04b17e2c1df1c1852ed536c5d6d8ec8d88b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: [WIP] lvm: Add an option to replace locking type 4
by ykaplan@redhat.com
Yeela Kaplan has uploaded a new change for review.
Change subject: [WIP] lvm: Add an option to replace locking type 4
......................................................................
[WIP] lvm: Add an option to replace locking type 4
Replace lvm locking type 4 with locking type 1
only in case of lvm cluster safe commands.
Change-Id: I9a67a7fa20145763d8ab5cdbf293a9c3eb070067
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M vdsm/storage/lvm.py
1 file changed, 13 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/23645/1
diff --git a/vdsm/storage/lvm.py b/vdsm/storage/lvm.py
index 4f3416f..932d69e 100644
--- a/vdsm/storage/lvm.py
+++ b/vdsm/storage/lvm.py
@@ -257,13 +257,15 @@
return self._extraCfg
- def _addExtraCfg(self, cmd, devices=tuple()):
+ def _addExtraCfg(self, cmd, devices=tuple(), safe):
newcmd = [constants.EXT_LVM, cmd[0]]
if devices:
conf = _buildConfig(devices)
else:
conf = self._getCachedExtraCfg()
+ if not safe:
+ conf = conf.replace("locking_type=4", "locking_type=1")
newcmd += ["--config", conf]
if len(cmd) > 1:
@@ -290,13 +292,17 @@
self._vgs = {}
self._lvs = {}
- def cmd(self, cmd, devices=tuple()):
- finalCmd = self._addExtraCfg(cmd, devices)
+ def cmd(self, cmd, devices=tuple(), safe=True):
+ """
+ Use safe as False only for lvm cluster safe commands.
+ These are cmds that don't change metadata of an existing VG.
+ """
+ finalCmd = self._addExtraCfg(cmd, devices, safe)
rc, out, err = misc.execCmd(finalCmd, sudo=True)
if rc != 0:
# Filter might be stale
self.invalidateFilter()
- newCmd = self._addExtraCfg(cmd)
+ newCmd = self._addExtraCfg(cmd, safe)
# Before blindly trying again make sure
# that the commands are not identical, because
# the devlist is sorted there is no fear
@@ -717,7 +723,7 @@
cmd.extend(("--metadatasize", metadatasize, "--metadatacopies", "2",
"--metadataignore", "y"))
cmd.extend(devices)
- rc, out, err = _lvminfo.cmd(cmd, devices)
+ rc, out, err = _lvminfo.cmd(cmd, devices, False)
return rc, out, err
@@ -929,7 +935,7 @@
# Activate the 1st PV metadata areas
cmd = ["pvchange", "--metadataignore", "n"]
cmd.append(pvs[0])
- rc, out, err = _lvminfo.cmd(cmd, tuple(pvs))
+ rc, out, err = _lvminfo.cmd(cmd, tuple(pvs), False)
if rc != 0:
raise se.PhysDevInitializationError(pvs[0])
@@ -937,7 +943,7 @@
if initialTag:
options.extend(("--addtag", initialTag))
cmd = ["vgcreate"] + options + [vgName] + pvs
- rc, out, err = _lvminfo.cmd(cmd, tuple(pvs))
+ rc, out, err = _lvminfo.cmd(cmd, tuple(pvs), False)
if rc == 0:
_lvminfo._invalidatepvs(pvs)
_lvminfo._invalidatevgs(vgName)
--
To view, visit http://gerrit.ovirt.org/23645
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9a67a7fa20145763d8ab5cdbf293a9c3eb070067
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
9 years, 9 months