Change in vdsm[master]: cache: Replace utils.memoized with cache.memoized()
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: cache: Replace utils.memoized with cache.memoized()
......................................................................
cache: Replace utils.memoized with cache.memoized()
Repalce users of utils.memoized with cache.memoized() and remove
utils.memoized. No behavior change is expected.
Change-Id: I12e2f2919cf92ff7d0758d70e2ed40523d66174f
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M lib/vdsm/netinfo.py
M lib/vdsm/utils.py
M tests/vmApiTests.py
M vdsm/caps.py
M vdsm/dmidecodeUtil.py
M vdsm/ppc64HardwareInfo.py
M vdsm/supervdsmServer
M vdsm/virt/sampling.py
8 files changed, 30 insertions(+), 51 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/10/34710/1
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index d2ef90b..8c56863 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -43,7 +43,7 @@
from .ipwrapper import routeShowGateways
from . import libvirtconnection
from .netconfpersistence import RunningConfig
-from .utils import memoized
+from .cache import memoized
from .netlink import link as nl_link
from .netlink import addr as nl_addr
from .netlink import route as nl_route
@@ -395,7 +395,7 @@
return paddr
-@memoized
+@memoized()
def _getAllDefaultBondingOptions():
"""
Return default options per mode, in a dictionary of dictionaries. All keys
@@ -405,7 +405,7 @@
return json.loads(defaults.read())
-@memoized
+@memoized()
def _getDefaultBondingOptions(mode=None):
"""
Return default options for the given mode. If it is None, return options
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index feb4079..131145c 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -51,6 +51,7 @@
import vdsm.infra.zombiereaper as zombiereaper
from cpopen import CPopen
+from . import cache
from . import constants
# Buffsize is 1K because I tested it on some use cases and 1K was fastest. If
@@ -828,32 +829,6 @@
fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
-class memoized(object):
- """
- Decorator that caches a function's return value each time it is called.
- If called later with the same arguments, the cached value is returned, and
- not re-evaluated. There is no support for uncachable arguments.
-
- Adaptation from http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
- """
- def __init__(self, func):
- self.func = func
- self.cache = {}
- functools.update_wrapper(self, func)
-
- def __call__(self, *args):
- try:
- return self.cache[args]
- except KeyError:
- value = self.func(*args)
- self.cache[args] = value
- return value
-
- def __get__(self, obj, objtype):
- """Support instance methods."""
- return functools.partial(self.__call__, obj)
-
-
def validateMinimalKeySet(dictionary, reqParams):
if not all(key in dictionary for key in reqParams):
raise ValueError
@@ -993,7 +968,7 @@
sys.exit(-3)
-@memoized
+(a)cache.memoized()
def isOvirtNode():
return (os.path.exists('/etc/rhev-hypervisor-release') or
bool(glob.glob('/etc/ovirt-node-*-release')))
diff --git a/tests/vmApiTests.py b/tests/vmApiTests.py
index eb89fb1..4f940cf 100644
--- a/tests/vmApiTests.py
+++ b/tests/vmApiTests.py
@@ -25,14 +25,14 @@
from virt import vmexitreason
from vdsm import define
from testlib import VdsmTestCase as TestCaseBase
-from vdsm import utils
+from vdsm import cache
from rpc import vdsmapi
import vmfakelib as fake
class TestSchemaCompliancyBase(TestCaseBase):
- @utils.memoized
+ @cache.memoized()
def _getAPI(self):
testPath = os.path.realpath(__file__)
dirName = os.path.split(testPath)[0]
diff --git a/vdsm/caps.py b/vdsm/caps.py
index dba9b5b..6e261d8 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -40,6 +40,7 @@
import dsaversion
from vdsm import netinfo
import hooks
+from vdsm import cache
from vdsm import utils
import storage.hba
from network.configurators import qos
@@ -218,12 +219,12 @@
ENABLED = 1
-(a)utils.memoized
+(a)cache.memoized()
def _getCapsXMLStr():
return libvirtconnection.get().getCapabilities()
-(a)utils.memoized
+(a)cache.memoized()
def _getCpuTopology(capabilities):
if capabilities is None:
capabilities = _getCapsXMLStr()
@@ -277,7 +278,7 @@
return None
-(a)utils.memoized
+(a)cache.memoized()
def _getLiveSnapshotSupport(arch, capabilities=None):
if capabilities is None:
capabilities = _getCapsXMLStr()
@@ -294,7 +295,7 @@
return None
-(a)utils.memoized
+(a)cache.memoized()
def getLiveMergeSupport():
"""
Determine if libvirt provides the necessary features to enable live merge.
@@ -318,7 +319,7 @@
return True
-(a)utils.memoized
+(a)cache.memoized()
def getNumaTopology():
capabilities = _getCapsXMLStr()
caps = minidom.parseString(capabilities)
@@ -369,7 +370,7 @@
return memDict
-(a)utils.memoized
+(a)cache.memoized()
def getNumaNodeDistance():
nodeDistance = {}
retcode, out, err = utils.execCmd(['numactl', '--hardware'])
@@ -385,7 +386,7 @@
return nodeDistance
-(a)utils.memoized
+(a)cache.memoized()
def getAutoNumaBalancingInfo():
retcode, out, err = utils.execCmd(['sysctl', '-n', '-e',
'kernel.numa_balancing'])
@@ -399,7 +400,7 @@
return AutoNumaBalancingStatus.UNKNOWN
-(a)utils.memoized
+(a)cache.memoized()
def _getEmulatedMachines(arch, capabilities=None):
if capabilities is None:
capabilities = _getCapsXMLStr()
@@ -461,7 +462,7 @@
return allModels
-(a)utils.memoized
+(a)cache.memoized()
def _getCompatibleCpuModels():
c = libvirtconnection.get()
allModels = _getAllCpuModels()
@@ -532,7 +533,7 @@
return kdumpStatus
-(a)utils.memoized
+(a)cache.memoized()
def getos():
if os.path.exists('/etc/rhev-hypervisor-release'):
return OSName.RHEVH
@@ -550,7 +551,7 @@
return OSName.UNKNOWN
-(a)utils.memoized
+(a)cache.memoized()
def osversion():
version = release = ''
@@ -700,7 +701,7 @@
return info
-(a)utils.memoized
+(a)cache.memoized()
def _getVersionInfo():
if not hasattr(libvirt, 'VIR_MIGRATE_ABORT_ON_ERROR'):
return _dropVersion('3.4',
diff --git a/vdsm/dmidecodeUtil.py b/vdsm/dmidecodeUtil.py
index add2526..f0c72fa 100644
--- a/vdsm/dmidecodeUtil.py
+++ b/vdsm/dmidecodeUtil.py
@@ -18,7 +18,7 @@
# Refer to the README and COPYING files for full details of the license
#
-from vdsm import utils
+from vdsm import cache
# This function gets dict and returns new dict that includes only string
@@ -35,7 +35,7 @@
return ret
-(a)utils.memoized
+(a)cache.memoized()
def getAllDmidecodeInfo():
import dmidecode
@@ -45,7 +45,7 @@
return myLeafDict
-(a)utils.memoized
+(a)cache.memoized()
def getHardwareInfoStructure():
dmiInfo = getAllDmidecodeInfo()
sysStruct = {}
diff --git a/vdsm/ppc64HardwareInfo.py b/vdsm/ppc64HardwareInfo.py
index 23f7388..1a89639 100644
--- a/vdsm/ppc64HardwareInfo.py
+++ b/vdsm/ppc64HardwareInfo.py
@@ -16,6 +16,7 @@
# Refer to the README and COPYING files for full details of the license
#
+from vdsm import cache
from vdsm import utils
import os
@@ -31,7 +32,7 @@
return 'unavailable'
-(a)utils.memoized
+(a)cache.memoized()
def getHardwareInfoStructure():
infoStructure = {'systemSerialNumber': 'unavailable',
'systemFamily': 'unavailable',
@@ -59,7 +60,7 @@
return infoStructure
-(a)utils.memoized
+(a)cache.memoized()
def getCpuTopology(capabilities):
topology = {}
diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer
index c6c139b..aba32fb 100755
--- a/vdsm/supervdsmServer
+++ b/vdsm/supervdsmServer
@@ -51,6 +51,7 @@
except ImportError:
_glusterEnabled = False
+from vdsm import cache
from vdsm import utils
from vdsm.tool import restore_nets
from parted_utils import getDevicePartedInfo as _getDevicePartedInfo
@@ -378,7 +379,7 @@
raise OSError(errno.EINVAL, "Could not reload-rules for device "
"%s" % guid)
- @utils.memoized
+ @cache.memoized()
def __udevVersion(self):
cmd = [EXT_UDEVADM, '--version']
rc, out, err = utils.execCmd(cmd)
diff --git a/vdsm/virt/sampling.py b/vdsm/virt/sampling.py
index 6bb4211..b1c3db6 100644
--- a/vdsm/virt/sampling.py
+++ b/vdsm/virt/sampling.py
@@ -30,6 +30,7 @@
import errno
import re
+from vdsm import cache
from vdsm import utils
from vdsm import netinfo
from vdsm.ipwrapper import getLinks
@@ -524,7 +525,7 @@
if not self._stopEvent.isSet():
self._log.error("Error while sampling stats", exc_info=True)
- @utils.memoized
+ @cache.memoized()
def _boot_time(self):
# Try to get boot time only once, if N/A just log the error and never
# include it in the response.
--
To view, visit http://gerrit.ovirt.org/34710
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I12e2f2919cf92ff7d0758d70e2ed40523d66174f
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: [WIP]fencenode: split fenceNode into its own module
by ykaplan@redhat.com
Yeela Kaplan has uploaded a new change for review.
Change subject: [WIP]fencenode: split fenceNode into its own module
......................................................................
[WIP]fencenode: split fenceNode into its own module
Change-Id: I7bd5e7246cf6da21e355849014a8fc71d5edbde6
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M debian/vdsm-python.install
M lib/vdsm/Makefile.am
A lib/vdsm/fencenode.py
M vdsm.spec.in
M vdsm/API.py
5 files changed, 120 insertions(+), 80 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/97/43597/1
diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index d9402c3..901edb6 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -10,6 +10,7 @@
./usr/lib/python2.7/dist-packages/vdsm/exception.py
./usr/lib/python2.7/dist-packages/vdsm/executor.py
./usr/lib/python2.7/dist-packages/vdsm/ipwrapper.py
+./usr/lib/python2.7/dist-packages/vdsm/fencenode.py
./usr/lib/python2.7/dist-packages/vdsm/jsonrpcvdscli.py
./usr/lib/python2.7/dist-packages/vdsm/libvirtconnection.py
./usr/lib/python2.7/dist-packages/vdsm/netconfpersistence.py
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index 95e236f..875507c 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -30,6 +30,7 @@
exception.py \
executor.py \
ipwrapper.py \
+ fencenode.py \
jsonrpcvdscli.py \
libvirtconnection.py \
netconfpersistence.py \
diff --git a/lib/vdsm/fencenode.py b/lib/vdsm/fencenode.py
new file mode 100644
index 0000000..3456b2f
--- /dev/null
+++ b/lib/vdsm/fencenode.py
@@ -0,0 +1,100 @@
+#
+# Copyright 2015 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
+#
+
+import logging
+import os
+import signal
+
+import utils
+import constants
+from define import doneCode, errCode
+
+
+(a)utils.traceback(on=logging.name)
+def fence(script, data):
+ # non-status actions are sent asyncronously. deathSignal is set to
+ # make sure that no stray fencing scripts are left behind if Vdsm
+ # crashes.
+ rc, out, err = utils.execCmd(
+ [script], deathSignal=signal.SIGTERM, data=data)
+ logging.debug('rc %s data %s out %s err %s', rc,
+ hidePasswd(data), out, err)
+ return rc, out, err
+
+
+def hidePasswd(text):
+ cleantext = ''
+ for line in text.splitlines(True):
+ if line.startswith('passwd='):
+ line = 'passwd=XXXX\n'
+ cleantext += line
+ return cleantext
+
+
+def fenceNode(addr, port, agent, username, password, action,
+ secure=False, options='', policy=None):
+
+ logging.debug('fenceNode(addr=%s,port=%s,agent=%s,user=%s,passwd=%s,'
+ 'action=%s,secure=%s,options=%s,policy=%s)',
+ addr, port, agent, username, password, action, secure,
+ options, policy)
+
+ if action not in ('status', 'on', 'off', 'reboot'):
+ raise ValueError('illegal action ' + action)
+
+ script = constants.EXT_FENCE_PREFIX + agent
+
+ data = ('agent=fence_%s\nipaddr=%s\nlogin=%s\naction=%s\n'
+ 'passwd=%s\n') % (agent, addr, username, action, password.value)
+ if port != '':
+ data += 'port=%s\n' % (port,)
+ if utils.tobool(secure):
+ data += 'secure=yes\n'
+ data += options
+
+ try:
+ rc, out, err = fence(script, data)
+ except OSError as e:
+ if e.errno == os.errno.ENOENT:
+ return errCode['fenceAgent']
+ raise
+
+ logging.debug('rc %s data %s out %s err %s',
+ rc, hidePasswd(data), out, err)
+
+ if not 0 <= rc <= 2:
+ return {'status': {'code': 1,
+ 'message': out + err}}
+
+ message = doneCode['message']
+ if action == 'status':
+ if rc == 0:
+ power = 'on'
+ elif rc == 2:
+ power = 'off'
+ else:
+ power = 'unknown'
+ message = out + err
+ return {'status': {'code': 0, 'message': message},
+ 'power': power}
+ if rc != 0:
+ message = out + err
+ return {'status': {'code': rc, 'message': message},
+ 'power': 'unknown', 'operationStatus': 'initiated'}
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 966a974..9e69162 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1071,6 +1071,7 @@
%{python_sitelib}/%{vdsm_name}/exception.py*
%{python_sitelib}/%{vdsm_name}/executor.py*
%{python_sitelib}/%{vdsm_name}/ipwrapper.py*
+%{python_sitelib}/%{vdsm_name}/fencenode.py*
%{python_sitelib}/%{vdsm_name}/jsonrpcvdscli.py*
%{python_sitelib}/%{vdsm_name}/libvirtconnection.py*
%{python_sitelib}/%{vdsm_name}/netinfo.py*
diff --git a/vdsm/API.py b/vdsm/API.py
index 0a93d2a..0719926 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -21,8 +21,6 @@
# pylint: disable=R0904
from contextlib import contextmanager
-import os
-import signal
import six
import sys
import time
@@ -38,6 +36,7 @@
from clientIF import clientIF
from vdsm import netinfo
from vdsm import constants
+from vdsm import fencenode
import storage.misc
import storage.clusterlock
import storage.volume
@@ -1187,6 +1186,11 @@
APIBase.__init__(self)
# General Host functions
+ def ping(self):
+ "Ping the server. Useful for tests"
+ updateTimestamp()
+ return {'status': doneCode}
+
def fenceNode(self, addr, port, agent, username, password, action,
secure=False, options='', policy=None):
"""Send a fencing command to a remote node.
@@ -1194,44 +1198,24 @@
agent is one of (rsa, ilo, drac5, ipmilan, etc)
action can be one of (status, on, off, reboot)."""
- @utils.traceback(on=self.log.name)
- def fence(script, inp):
- # non-status actions are sent asyncronously. deathSignal is set to
- # make sure that no stray fencing scripts are left behind if Vdsm
- # crashes.
- rc, out, err = utils.execCmd(
- [script], deathSignal=signal.SIGTERM,
- data=inp)
- self.log.debug('rc %s inp %s out %s err %s', rc,
- hidePasswd(inp), out, err)
- return rc, out, err
-
- def hidePasswd(text):
- cleantext = ''
- for line in text.splitlines(True):
- if line.startswith('passwd='):
- line = 'passwd=XXXX\n'
- cleantext += line
- return cleantext
-
def should_fence(policy):
# skip fence execution if map of storage domains with host id is
# entered and at least one storage domain connection from host is
# alive
if policy is None:
- self.log.debug('No policy specified')
+ logging.debug('No policy specified')
return True
hostIdMap = policy.get('storageDomainHostIdMap')
if not hostIdMap:
- self.log.warning('Invalid policy specified')
+ logging.warning('Invalid policy specified')
return True
result = self._irs.getHostLeaseStatus(hostIdMap)
- if result['status']['code'] != 0:
- self.log.error(
- "Error getting host lease status, error code '%s'",
- result['status']['code'])
+ rc = result['status']['code']
+ if rc != 0:
+ logging.error(
+ "Error getting host lease status, error code '%s'", rc)
return True
# HOST_STATUS_LIVE means that host renewed its lease in last 80
@@ -1239,65 +1223,18 @@
# fencing, even when it's unreachable from engine
for sd, status in result['domains'].iteritems():
if status == storage.clusterlock.HOST_STATUS_LIVE:
- self.log.debug("Host has live lease on '%s'", sd)
+ logging.debug("Host has live lease on '%s'", sd)
return False
- self.log.debug("Host doesn't have any live lease")
+ logging.debug("Host doesn't have any live lease")
return True
- self.log.debug('fenceNode(addr=%s,port=%s,agent=%s,user=%s,passwd=%s,'
- 'action=%s,secure=%s,options=%s,policy=%s)',
- addr, port, agent, username, password, action, secure,
- options, policy)
-
- if action not in ('status', 'on', 'off', 'reboot'):
- raise ValueError('illegal action ' + action)
-
if action != 'status' and not should_fence(policy):
- self.log.debug("Skipping execution of action '%s'", action)
+ logging.debug("Skipping execution of action '%s'", action)
return {'status': doneCode, 'operationStatus': 'skipped'}
- script = constants.EXT_FENCE_PREFIX + agent
-
- inp = ('agent=fence_%s\nipaddr=%s\nlogin=%s\naction=%s\n'
- 'passwd=%s\n') % (agent, addr, username, action, password.value)
- if port != '':
- inp += 'port=%s\n' % (port,)
- if utils.tobool(secure):
- inp += 'secure=yes\n'
- inp += options
-
- try:
- rc, out, err = fence(script, inp)
- except OSError as e:
- if e.errno == os.errno.ENOENT:
- return errCode['fenceAgent']
- raise
- self.log.debug('rc %s in %s out %s err %s', rc,
- hidePasswd(inp), out, err)
- if not 0 <= rc <= 2:
- return {'status': {'code': 1,
- 'message': out + err}}
- message = doneCode['message']
- if action == 'status':
- if rc == 0:
- power = 'on'
- elif rc == 2:
- power = 'off'
- else:
- power = 'unknown'
- message = out + err
- return {'status': {'code': 0, 'message': message},
- 'power': power}
- if rc != 0:
- message = out + err
- return {'status': {'code': rc, 'message': message},
- 'power': 'unknown', 'operationStatus': 'initiated'}
-
- def ping(self):
- "Ping the server. Useful for tests"
- updateTimestamp()
- return {'status': doneCode}
+ return fencenode.fenceNode(addr, port, agent, username, password,
+ action, secure, options, policy)
def getCapabilities(self):
"""
--
To view, visit https://gerrit.ovirt.org/43597
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7bd5e7246cf6da21e355849014a8fc71d5edbde6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: wip: tests: change testing framework to pytest
by igoihman@redhat.com
Irit Goihman has uploaded a new change for review.
Change subject: wip: tests: change testing framework to pytest
......................................................................
wip: tests: change testing framework to pytest
Change-Id: Ife527b9274c31a72b57da9b958a1dd2f9f1e5ea0
Signed-off-by: Irit Goihman <igoihman(a)redhat.com>
---
A tests/pytest.ini
M tests/testrunner.py
2 files changed, 4 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/17/60217/1
diff --git a/tests/pytest.ini b/tests/pytest.ini
new file mode 100644
index 0000000..521a323
--- /dev/null
+++ b/tests/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+python_files = *tests.py *test.py *Test.py *Tests.py
diff --git a/tests/testrunner.py b/tests/testrunner.py
index 27f6f7e..38d970e 100644
--- a/tests/testrunner.py
+++ b/tests/testrunner.py
@@ -26,6 +26,7 @@
import pthreading
pthreading.monkey_patch()
+import pytest
import warnings
import logging
@@ -85,4 +86,4 @@
# Mock panic() calls for tests
panic.panic = panicMock
- testlib.run()
+ pytest.main()
--
To view, visit https://gerrit.ovirt.org/60217
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ife527b9274c31a72b57da9b958a1dd2f9f1e5ea0
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Irit Goihman <igoihman(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: qemuimg: Memoize _supports_qcow2_compat
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: qemuimg: Memoize _supports_qcow2_compat
......................................................................
qemuimg: Memoize _supports_qcow2_compat
We used to run qemu-img twice when creating or converting qcow2 images.
The first run check if qemu-img supports the qcow2 "comapt" option, and
the second run uses the result to format the qemu-img command.
Now we run qemu-img once for "create" and "convert" to learn about its
capabilities, and use the cached value on the next runs. If qemu-img
executable is modified, we drop the cache, in case a new version was
installed with different capabilities.
Change-Id: Ic63f5e8c06993df8e4066bf7ac2dabfb4b4bdbfb
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M lib/vdsm/qemuimg.py
M tests/qemuimgTests.py
2 files changed, 8 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/11/34711/1
diff --git a/lib/vdsm/qemuimg.py b/lib/vdsm/qemuimg.py
index cf428b2..f295acc 100644
--- a/lib/vdsm/qemuimg.py
+++ b/lib/vdsm/qemuimg.py
@@ -23,6 +23,7 @@
import signal
from . import utils
+from . import cache
_qemuimg = utils.CommandPath("qemu-img",
"/usr/bin/qemu-img",) # Fedora, EL6
@@ -221,6 +222,7 @@
raise QImgError(rc, out, err)
+(a)cache.memoized(cache.file_validator(_qemuimg.cmd))
def _supports_qcow2_compat(command):
"""
qemu-img "create" and "convert" commands support a "compat" option in
diff --git a/tests/qemuimgTests.py b/tests/qemuimgTests.py
index 813a497..a642374 100644
--- a/tests/qemuimgTests.py
+++ b/tests/qemuimgTests.py
@@ -118,6 +118,9 @@
class CreateTests(TestCaseBase):
+ def setUp(self):
+ qemuimg._supports_qcow2_compat.invalidate()
+
def test_no_format(self):
def create(cmd, **kw):
expected = [QEMU_IMG, 'create', 'image']
@@ -161,6 +164,9 @@
class ConvertTests(TestCaseBase):
+ def setUp(self):
+ qemuimg._supports_qcow2_compat.invalidate()
+
def test_no_format(self):
def convert(cmd, **kw):
expected = [QEMU_IMG, 'convert', '-t', 'none', 'src', 'dst']
--
To view, visit http://gerrit.ovirt.org/34711
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic63f5e8c06993df8e4066bf7ac2dabfb4b4bdbfb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: functional tests: fix supervdsmServer test
by igoihman@redhat.com
Irit Goihman has uploaded a new change for review.
Change subject: functional tests: fix supervdsmServer test
......................................................................
functional tests: fix supervdsmServer test
supervdsmServer dropPrivileges function is switching root user to
a non privileged user but not switching the user back to root so
other tests which require root user in order to run keep failing.
it's not possible to switch to root from non privileged user so
dropPrivileges is done in a child process and the switch back in
the child exit.
Change-Id: I8c7e381809261cf330ef4f19c3fec5cd38254b1b
Signed-off-by: Irit Goihman <igoihman(a)redhat.com>
---
M tests/functional/supervdsmFuncTests.py
1 file changed, 25 insertions(+), 15 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/02/61902/1
diff --git a/tests/functional/supervdsmFuncTests.py b/tests/functional/supervdsmFuncTests.py
index 8710924..b2f3669 100644
--- a/tests/functional/supervdsmFuncTests.py
+++ b/tests/functional/supervdsmFuncTests.py
@@ -25,7 +25,6 @@
class TestSuperVdsmRemotly(TestCaseBase):
-
def dropPrivileges(self):
vdsm_uid, vdsm_gid = getpwnam(VDSM_USER)[2:4:]
os.setgroups([])
@@ -34,21 +33,32 @@
@testValidation.ValidateRunningAsRoot
def testPingCall(self):
- self.dropPrivileges()
- proxy = supervdsm.getProxy()
- self.assertTrue(proxy.ping())
+ pid = os.fork()
+ if pid == 0:
+ try:
+ self.dropPrivileges()
+ proxy = supervdsm.getProxy()
+ self.assertTrue(proxy.ping())
+ finally:
+ os._exit(0)
+ os.waitpid(pid, 0)
# This requires environment with tmpfs mounted to /sys/kernel/mm/ksm
@testValidation.ValidateRunningAsRoot
def testKsmAction(self):
- self.dropPrivileges()
- proxy = supervdsm.getProxy()
- ksmParams = {"run": 0,
- "merge_across_nodes": 1,
- "sleep_millisecs": 0xffff,
- "pages_to_scan": 0xffff}
- proxy.ksmTune(ksmParams)
-
- for k, v in ksmParams.iteritems():
- self.assertEqual(str(v),
- open("/sys/kernel/mm/ksm/%s" % k, "r").read())
+ pid = os.fork()
+ if pid == 0:
+ try:
+ self.dropPrivileges()
+ proxy = supervdsm.getProxy()
+ ksmParams = {"run": 0,
+ "merge_across_nodes": 1,
+ "sleep_millisecs": 0xffff,
+ "pages_to_scan": 0xffff}
+ proxy.ksmTune(ksmParams)
+ for k, v in ksmParams.iteritems():
+ self.assertEqual(
+ str(v), open("/sys/kernel/mm/ksm/%s" % k, "r").read())
+ finally:
+ os._exit(0)
+ os.waitpid(pid, 0)
--
To view, visit https://gerrit.ovirt.org/61902
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8c7e381809261cf330ef4f19c3fec5cd38254b1b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Irit Goihman <igoihman(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: network: ifup: shorten name of the thread
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: network: ifup: shorten name of the thread
......................................................................
network: ifup: shorten name of the thread
We shorten the name of the thread optionally used by
the _ifup() function, to make it fit in 15 ASCII chars,
a limit given by pthreads.
Change-Id: I2e59d97c16850521f4c45339677ee43c9f9bdd1e
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/network/configurators/ifcfg.py
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/17/62617/1
diff --git a/lib/vdsm/network/configurators/ifcfg.py b/lib/vdsm/network/configurators/ifcfg.py
index 6b60ee0..b1cfe8b 100644
--- a/lib/vdsm/network/configurators/ifcfg.py
+++ b/lib/vdsm/network/configurators/ifcfg.py
@@ -862,7 +862,7 @@
iface.ipv6.dhcpv6):
# wait for dhcp in another thread, so vdsm won't get stuck (BZ#498940)
t = concurrent.thread(_exec_ifup,
- name='ifup-waiting-on-dhcp',
+ name='dhcpwait/%s' % iface,
args=(iface, cgroup))
t.start()
else:
--
To view, visit https://gerrit.ovirt.org/62617
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2e59d97c16850521f4c45339677ee43c9f9bdd1e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: network: dhclient: shorten name of the thread
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: network: dhclient: shorten name of the thread
......................................................................
network: dhclient: shorten name of the thread
We shorten the name of the DhcpClient worker thread to
make it fit in 15 ASCII chars, a limit given by pthreads.
Change-Id: Id413830191bebec9f17d8845e791ee66cdbcd2d9
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/network/ip/dhclient.py
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/16/62616/1
diff --git a/lib/vdsm/network/ip/dhclient.py b/lib/vdsm/network/ip/dhclient.py
index 3d4d4d3..4da5162 100644
--- a/lib/vdsm/network/ip/dhclient.py
+++ b/lib/vdsm/network/ip/dhclient.py
@@ -74,7 +74,7 @@
return self._dhclient()
else:
t = concurrent.thread(self._dhclient,
- name='vdsm-dhclient-%s' % self.iface)
+ name='dhclient/%s' % self.iface)
t.start()
def shutdown(self):
--
To view, visit https://gerrit.ovirt.org/62616
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id413830191bebec9f17d8845e791ee66cdbcd2d9
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: network: switch to concurrent.thread()
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: network: switch to concurrent.thread()
......................................................................
network: switch to concurrent.thread()
This patch:
1. replaces good usages of threading.Thread() with
more modern concurrent.thread()
2. replaces bad usages of threading.Thread() - inheritance
with composition, leveraging concurrent.thread()
there are no intended changes in behaviour.
Change-Id: Ie7918a6762b35000b02187a0356273e40bba57a8
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/network/configurators/ifcfg.py
M lib/vdsm/network/ip/dhclient.py
2 files changed, 7 insertions(+), 8 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/59/61459/1
diff --git a/lib/vdsm/network/configurators/ifcfg.py b/lib/vdsm/network/configurators/ifcfg.py
index e9f67e1..9168e05 100644
--- a/lib/vdsm/network/configurators/ifcfg.py
+++ b/lib/vdsm/network/configurators/ifcfg.py
@@ -29,7 +29,6 @@
import re
import selinux
import shutil
-import threading
import uuid
import six
@@ -39,6 +38,7 @@
from vdsm.config import config
from vdsm import commands
from vdsm import cmdutils
+from vdsm import concurrent
from vdsm import constants
from vdsm import dsaversion
from vdsm import hooks
@@ -846,9 +846,9 @@
if not iface.blockingdhcp and (iface.ipv4.bootproto == 'dhcp' or
iface.ipv6.dhcpv6):
# wait for dhcp in another thread, so vdsm won't get stuck (BZ#498940)
- t = threading.Thread(target=_exec_ifup, name='ifup-waiting-on-dhcp',
- args=(iface, cgroup))
- t.daemon = True
+ t = concurrent.thread(_exec_ifup,
+ name='ifup-waiting-on-dhcp',
+ args=(iface, cgroup))
t.start()
else:
if not iface.master and (iface.ipv4 or iface.ipv6):
diff --git a/lib/vdsm/network/ip/dhclient.py b/lib/vdsm/network/ip/dhclient.py
index 318217c..f67a876 100644
--- a/lib/vdsm/network/ip/dhclient.py
+++ b/lib/vdsm/network/ip/dhclient.py
@@ -24,9 +24,9 @@
import logging
import os
import subprocess
-import threading
from vdsm import cmdutils
+from vdsm import concurrent
from vdsm.network import errors as ne
from vdsm.network import netinfo
from vdsm.commands import execCmd
@@ -73,9 +73,8 @@
if blocking:
return self._dhclient()
else:
- t = threading.Thread(target=self._dhclient, name='vdsm-dhclient-%s'
- % self.iface)
- t.daemon = True
+ t = concurrent.thread(self._dhclient,
+ name='vdsm-dhclient-%s' % self.iface)
t.start()
def shutdown(self):
--
To view, visit https://gerrit.ovirt.org/61459
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie7918a6762b35000b02187a0356273e40bba57a8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: sdm: Jobs may be run only when status=pending
by alitke@redhat.com
Adam Litke has uploaded a new change for review.
Change subject: sdm: Jobs may be run only when status=pending
......................................................................
sdm: Jobs may be run only when status=pending
An SDM Job begins its lifecycle in pending state and at some point a scheduler
will call its run() method to run it. The job should not run from any state
other than pending. If a job was aborted while waiting to be executed we
should print a message and return. If the job is in any other state we have a
bug and an exception should be raised.
Change-Id: I601f6db19527635c1a00c3a4c2910eac4ac5371b
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/storage_sdm_api_test.py
M vdsm/storage/sdm/api/base.py
2 files changed, 32 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/38/61138/1
diff --git a/tests/storage_sdm_api_test.py b/tests/storage_sdm_api_test.py
index c8d93d2..3306c30 100644
--- a/tests/storage_sdm_api_test.py
+++ b/tests/storage_sdm_api_test.py
@@ -21,6 +21,7 @@
import uuid
from testlib import VdsmTestCase
+from testlib import expandPermutations, permutations
from sdmtestlib import wait_for_job
from vdsm import jobs
@@ -30,6 +31,7 @@
from storage.sdm.api import base
+@expandPermutations
class ApiBaseTests(VdsmTestCase):
def run_job(self, job):
@@ -58,6 +60,20 @@
self.assertEqual(jobs.STATUS.FAILED, job.status)
self.assertIsInstance(job.error, exception.VdsmException)
+ def test_run_aborted_job(self):
+ job = TestingJob()
+ job.abort()
+ job.run()
+ self.assertEqual(jobs.STATUS.ABORTED, job.status)
+
+ @permutations((
+ (jobs.STATUS.DONE,), (jobs.STATUS.RUNNING,), (jobs.STATUS.FAILED,)
+ ))
+ def test_run_from_invalid_state(self, status):
+ job = TestingJob()
+ job.set_status(status)
+ self.assertRaises(base.CannotRunJob, job.run)
+
class TestingJob(base.Job):
@@ -66,6 +82,12 @@
super(TestingJob, self).__init__(job_id, 'testing_job', 'host_id')
self.exception = exception
+ def set_status(self, value):
+ self._status = value
+
+ def _abort(self):
+ pass
+
def _run(self):
assert(self.status == jobs.STATUS.RUNNING)
assert(vars.job_id == self.id)
diff --git a/vdsm/storage/sdm/api/base.py b/vdsm/storage/sdm/api/base.py
index a342300..eb88f35 100644
--- a/vdsm/storage/sdm/api/base.py
+++ b/vdsm/storage/sdm/api/base.py
@@ -27,6 +27,10 @@
from vdsm.storage.threadlocal import vars
+class CannotRunJob(Exception):
+ pass
+
+
class Job(jobs.Job):
_JOB_TYPE = "storage"
log = logging.getLogger('storage.sdmjob')
@@ -37,6 +41,12 @@
self.host_id = host_id
def run(self):
+ if self._status == jobs.STATUS.ABORTED:
+ self.log.info("Job id=%s aborted while pending", self.id)
+ return
+ if self._status != jobs.STATUS.PENDING:
+ raise CannotRunJob("Job id=%s cannot be started from %r status",
+ self.id, self.status)
self._status = jobs.STATUS.RUNNING
vars.job_id = self.id
try:
--
To view, visit https://gerrit.ovirt.org/61138
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I601f6db19527635c1a00c3a4c2910eac4ac5371b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
7 years, 7 months
Change in vdsm[master]: wip: copy_data take resource locks
by alitke@redhat.com
Adam Litke has uploaded a new change for review.
Change subject: wip: copy_data take resource locks
......................................................................
wip: copy_data take resource locks
Change-Id: I1b008c38dab5478f13175659bd2103e994802cf7
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/storage_sdm_copy_data_test.py
M vdsm/storage/sdm/api/copy_data.py
2 files changed, 72 insertions(+), 13 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/53/61353/1
diff --git a/tests/storage_sdm_copy_data_test.py b/tests/storage_sdm_copy_data_test.py
index def8934..8d40cd6 100644
--- a/tests/storage_sdm_copy_data_test.py
+++ b/tests/storage_sdm_copy_data_test.py
@@ -49,6 +49,7 @@
rm = FakeResourceManager()
with MonkeyPatchScope([
(storage.sdm.api.copy_data, 'sdCache', env.sdcache),
+ (storage.sdm.api.copy_data, 'rmanager', rm),
(blockVolume, 'rmanager', rm),
]):
src_vols = make_qemu_chain(env, self.SIZE, src_fmt,
diff --git a/vdsm/storage/sdm/api/copy_data.py b/vdsm/storage/sdm/api/copy_data.py
index aff0185..269a10f 100644
--- a/vdsm/storage/sdm/api/copy_data.py
+++ b/vdsm/storage/sdm/api/copy_data.py
@@ -29,8 +29,12 @@
from storage import volume
from storage.sdc import sdCache
+from storage import resourceManager as rm
+from storage.resourceFactories import IMAGE_NAMESPACE
from . import base
+
+rmanager = rm.ResourceManager.getInstance()
class Job(base.Job):
@@ -55,20 +59,20 @@
self._operation.abort()
def _run(self):
- # TODO: LOCKING!
- with self._source.prepare(), self._dest.prepare(writable=True):
- # Do not start copying if we have already been aborted
- if self._status == jobs.STATUS.ABORTED:
- return
+ with protected_endpoints(self._source, self._dest):
+ with self._source.prepare(), self._dest.prepare(writable=True):
+ # Do not start copying if we have already been aborted
+ if self._status == jobs.STATUS.ABORTED:
+ return
- self._operation = qemuimg.convert(
- self._source.path,
- self._dest.path,
- srcFormat=self._source.qemu_format,
- dstFormat=self._dest.qemu_format,
- backing=self._dest.backing_path,
- backingFormat=self._dest.backing_qemu_format)
- self._operation.wait_for_completion()
+ self._operation = qemuimg.convert(
+ self._source.path,
+ self._dest.path,
+ srcFormat=self._source.qemu_format,
+ dstFormat=self._dest.qemu_format,
+ backing=self._dest.backing_path,
+ backingFormat=self._dest.backing_qemu_format)
+ self._operation.wait_for_completion()
def _create_endpoint(params):
@@ -79,6 +83,60 @@
raise ValueError("Invalid or unsupported endpoint %r" % params)
+class protected_endpoints(object):
+
+ def __init__(self, src, dest):
+ self._domain_locks = self._get_domain_locks((src, dest))
+ self._image_locks = self._get_image_locks(src, dest)
+ self._held_locks = list()
+
+ def __enter__(self):
+ try:
+ for lock in self._domain_locks + self._image_locks:
+ rmanager.acquireResource(lock.ns, lock.name, lock.mode)
+ self._held_locks.insert(0, lock)
+ except:
+ self._release()
+ raise
+
+ def __exit__(self, type, value, tb):
+ self._release()
+
+ def _get_domain_locks(self, endpoints):
+ locks = set()
+ for endpoint in endpoints:
+ if isinstance(endpoint, CopyDataDivEndpoint):
+ lock = LockInfo(sc.STORAGE, endpoint.sd_id, rm.LockType.shared)
+ locks.add(lock)
+ return sorted(locks)
+
+ def _get_image_locks(self, src, dest):
+ locks = []
+ if isinstance(src, CopyDataDivEndpoint):
+ lock = LockInfo(IMAGE_NAMESPACE, src.img_id, rm.LockType.shared)
+ locks.append(lock)
+ if isinstance(dest, CopyDataDivEndpoint):
+ lock = LockInfo(IMAGE_NAMESPACE, dest.img_id,
+ rm.LockType.exclusive)
+ locks.append(lock)
+ return sorted(locks)
+
+ def _release(self):
+ for lock in self._held_locks:
+ rmanager.releaseResource(lock.ns, lock.name)
+
+
+class LockInfo(object):
+
+ def __init__(self, ns, name, mode):
+ self.ns = ns
+ self.name = name
+ self.mode = mode
+
+ def __cmp__(self, other):
+ return cmp(self.ns + self.name, other.ns + other.name)
+
+
class CopyDataDivEndpoint(properties.Owner):
sd_id = properties.UUID(required=True)
img_id = properties.UUID(required=True)
--
To view, visit https://gerrit.ovirt.org/61353
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1b008c38dab5478f13175659bd2103e994802cf7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
7 years, 7 months