Change in vdsm[master]: spec: Require newer libvirt version for el7
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: spec: Require newer libvirt version for el7
......................................................................
spec: Require newer libvirt version for el7
Libvirt 1.2.17 introduced a regression where physical volume size is
always zero. This breaks our extension logic, using:
physical - alloc < drive.watermarkLimit
As a result, we try to extend the drive on each check to next size after
0 (1GiB), spamming the logs with lvm warnings. Finally the vm is paused,
since we never extend the disk.
Libvirt 1.2.17-5 fixed this issue. We require now this version.
The issue is probably effecting also Fedora 23. We will provide a
separate patch for Fedora if needed.
Change-Id: Iea42288e779ba8a63968087d1df27e0f3665e406
Bug-Url: https://bugzilla.redhat.com/1251008
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm.spec.in
1 file changed, 2 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/34/44834/1
diff --git a/vdsm.spec.in b/vdsm.spec.in
index d17338d..cd25ee5 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -150,8 +150,8 @@
Requires: libvirt-daemon-driver-qemu
%if 0%{?rhel}
-Requires: libvirt-daemon >= 1.2.8-16.el7_1.2
-Requires: libvirt-python >= 1.2.8-7.el7_1.1
+Requires: libvirt-daemon >= 1.2.17-5.el7
+Requires: libvirt-python >= 1.2.17.el7
%endif # rhel
%if 0%{?fedora} >= 22
--
To view, visit https://gerrit.ovirt.org/44834
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iea42288e779ba8a63968087d1df27e0f3665e406
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: net: tests: test tc upper limit using iperf
by ibarkan@redhat.com
Ido Barkan has uploaded a new change for review.
Change subject: net: tests: test tc upper limit using iperf
......................................................................
net: tests: test tc upper limit using iperf
The test uses iperf to verify that the upper limit set by traffic
control is imposed over the generated client.
Change-Id: I9348a09e331195695c16862ef986df3b4abfa991
Signed-off-by: Ido Barkan <ibarkan(a)redhat.com>
---
M tests/tcTests.py
1 file changed, 49 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/49/46449/1
diff --git a/tests/tcTests.py b/tests/tcTests.py
index 4ce6cd4..05d7b62 100644
--- a/tests/tcTests.py
+++ b/tests/tcTests.py
@@ -31,12 +31,16 @@
from testlib import (VdsmTestCase as TestCaseBase, permutations,
expandPermutations)
-from testValidation import ValidateRunningAsRoot
-from nettestlib import Bridge, Dummy, Tap, vlan_device, requires_tc
+from testValidation import ValidateRunningAsRoot, slowtest
+from nettestlib import (Bridge, Dummy, Tap, vlan_device, requires_tc, veth_pair,
+ IperfServer, IperfClient, requires_iperf3,
+ bridge_device, network_namespace)
from vdsm.constants import EXT_TC
from network import tc
from network.configurators import qos
+from vdsm.ipwrapper import addrAdd, linkSet, netns_exec, netns_assign
+from vdsm.utils import running
class TestQdisc(TestCaseBase):
@@ -441,6 +445,49 @@
self.assertEqual(current_tagged_filters_flow_id,
expected_flow_ids)
+ @requires_iperf3
+ @requires_tc
+ @slowtest
+ def test_iperf_upper_limit(self):
+ # Upper limit is not an accurate measure. This is because it converges
+ # over time and depends on current machine hardware (CPU).
+ # Hence, it is hard to make hard assertions on it. The test should run
+ # at least 60 seconds (the longer the better) and the user should
+ # inspect the computed average rate and optionally the additional
+ # traffic data that was collected in client.out in order to be
+ # convinced QOS is working properly.
+ limit_kbps = 1000 # 1 Mbps (in kbps)
+ limit_bps = limit_kbps * 2 ** 10
+ server_ip = '192.0.2.1'
+ client_ip = '192.0.2.10'
+ qos_out = {'ul': {'m2': limit_kbps}, 'ls': {'m2': limit_kbps}}
+ # using a network namespace is essential since otherwise the kernel
+ # short-circuits the traffic and bypasses the veth devices and the
+ # classfull qdisc.
+ with network_namespace('server_ns') as ns, bridge_device() as bridge, \
+ veth_pair() as (server_peer, server_dev), \
+ veth_pair() as (client_dev, client_peer):
+ linkSet(server_peer, ['up'])
+ linkSet(client_peer, ['up'])
+ # iperf server and its veth peer lie in a separate network
+ # namespace
+ netns_assign(server_dev, ns)
+ bridge.addIf(server_peer)
+ bridge.addIf(client_peer)
+ linkSet(client_dev, ['up'])
+ netns_exec(ns, ['ip', 'link', 'set', 'dev', server_dev, 'up'])
+ addrAdd(client_dev, client_ip, 24)
+ netns_exec(ns, ['ip', '-4', 'addr', 'add', 'dev', server_dev,
+ '%s/24' % server_ip])
+ qos.configure_outbound(qos_out, client_peer, None)
+ with running(IperfServer(server_ip, network_ns=ns)),\
+ running(IperfClient(server_ip, client_ip, test_time=60)) \
+ as client:
+ max_rate = max([float(
+ interval['streams'][0]['bits_per_second'])/(2**10)
+ for interval in client.out['intervals']])
+ self.assertTrue(0 < max_rate < limit_kbps * 1.5)
+
def _analise_qos_and_general_assertions(self):
tc_classes = self._analise_classes()
tc_qdiscs = self._analise_qdiscs()
--
To view, visit https://gerrit.ovirt.org/46449
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9348a09e331195695c16862ef986df3b4abfa991
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ido Barkan <ibarkan(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: net: tests: support iperf3 for performance tests
by ibarkan@redhat.com
Ido Barkan has uploaded a new change for review.
Change subject: net: tests: support iperf3 for performance tests
......................................................................
net: tests: support iperf3 for performance tests
Support running iperf3 client server using context managers in an
optional network namespace. This is handy for performance testing on
a single machine. TC qos tests following patches use it.
Change-Id: I15657f8844d131c5444dd680b8de7aa1c4ec2638
Signed-off-by: Ido Barkan <ibarkan(a)redhat.com>
---
M configure.ac
M lib/vdsm/constants.py.in
M tests/nettestlib.py
3 files changed, 92 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/48/46448/1
diff --git a/configure.ac b/configure.ac
index 88817a8..1fee53c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,7 @@
AC_PATH_PROG([IFUP_PATH], [ifup], [/sbin/ifup])
AC_PATH_PROG([IONICE_PATH], [ionice], [/usr/bin/ionice])
AC_PATH_PROG([IP_PATH], [ip], [/sbin/ip])
+AC_PATH_PROG([IPERF3_PATH], [iperf3], [/usr/bin/iperf3])
AC_PATH_PROG([ISCSIADM_PATH], [iscsiadm], [/sbin/iscsiadm])
AC_PATH_PROG([KILL_PATH], [kill], [/bin/kill])
AC_PATH_PROG([LVM_PATH], [lvm], [/sbin/lvm])
diff --git a/lib/vdsm/constants.py.in b/lib/vdsm/constants.py.in
index c9dff39..d4adac9 100644
--- a/lib/vdsm/constants.py.in
+++ b/lib/vdsm/constants.py.in
@@ -117,6 +117,7 @@
EXT_IFDOWN = '@IFDOWN_PATH@'
EXT_IFUP = '@IFUP_PATH@'
EXT_IONICE = '@IONICE_PATH@'
+EXT_IPERF3 = '@IPERF3_PATH@'
EXT_ISCSIADM = '@ISCSIADM_PATH@'
EXT_TC = '@TC_PATH@'
diff --git a/tests/nettestlib.py b/tests/nettestlib.py
index c923f44..d019778 100644
--- a/tests/nettestlib.py
+++ b/tests/nettestlib.py
@@ -20,6 +20,7 @@
import errno
import fcntl
import functools
+import json
import os
import platform
import signal
@@ -28,13 +29,17 @@
from multiprocessing import Process
from nose.plugins.skip import SkipTest
+import time
-from vdsm.constants import EXT_BRCTL, EXT_TC
-from vdsm.ipwrapper import addrAdd, linkSet, linkAdd, linkDel, IPRoute2Error
+from vdsm.constants import EXT_BRCTL, EXT_TC, EXT_IPERF3
+from vdsm.ipwrapper import addrAdd, linkSet, linkAdd, linkDel, IPRoute2Error, \
+ netns_add, netns_delete
from vdsm.netlink import monitor
-from vdsm.utils import execCmd, random_iface_name
+from vdsm.utils import (execCmd, random_iface_name, pgrep, kill_and_rm_pid,
+ CommandPath)
EXT_IP = "/sbin/ip"
+_IPERF3_BINARY = CommandPath('iperf3', EXT_IPERF3)
class ExecError(RuntimeError):
@@ -237,6 +242,70 @@
raise SkipTest(message)
+class _Iperf(object):
+ @staticmethod
+ def stop():
+ pids = pgrep(_IPERF3_BINARY.name)
+ for pid in pids:
+ kill_and_rm_pid(pid, pid_file=None)
+
+
+class IperfServer(_Iperf):
+ """starts iperf as a daemon"""
+ def __init__(self, host, network_ns=None):
+ """host: the IP address for the server to listen on.
+ network_ns: an optional network namespace for the server to run in.
+ """
+ self._bind_to = host
+ self._net_ns = network_ns
+
+ def start(self):
+ cmd = [EXT_IPERF3, '--server', '--bind', self._bind_to, '--daemon']
+ if self._net_ns is not None:
+ cmd = ['ip', 'netns', 'exec', self._net_ns] + cmd
+ rc, out, err = execCmd(cmd)
+ return rc
+
+
+class IperfClient(_Iperf):
+ def __init__(self, server_ip, bind_to, test_time, threads=1):
+ """the client generate a machine readable json output that is set in
+ _raw_output upon completion, ANd can be read using the 'out' property.
+ server_ip: the ip of the corresponding iperf server
+ bind_to: IP address of the client
+ test_time: in seconds
+ """
+ self._server_ip = server_ip
+ self._bind_to = bind_to
+ self._test_time = test_time
+ self._threads = threads
+ self._raw_output = None
+
+ def start(self):
+ cmd = [EXT_IPERF3, '--client', self._server_ip,
+ '--version4', # only IPv4
+ '--time', str(self._test_time), '--parallel',
+ str(self._threads), '--bind', self._bind_to,
+ '--zerocopy', # use less cpu
+ '--json']
+ rc, self._raw_output, err = execCmd(cmd)
+ if rc == 1 and 'No route to host' in self.error:
+ time.sleep(3)
+ rc, self._raw_output, err = execCmd(cmd)
+ if rc:
+ raise Exception('iperf3 client failed: cmd=%s, rc=%s, out=%s, '
+ 'err=%s' % (' '.join(cmd), rc, self._raw_output,
+ err))
+
+ @property
+ def error(self):
+ return self.out['error']
+
+ @property
+ def out(self):
+ return json.loads(' '.join(self._raw_output))
+
+
@contextmanager
def dummy_device(prefix='dummy_', max_length=11):
dummy_interface = Dummy(prefix, max_length)
@@ -304,3 +373,21 @@
check_tc()
return f(*a, **kw)
return wrapper
+
+
+def check_iperf():
+ try:
+ execCmd([_IPERF3_BINARY.cmd, "--version"])
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise SkipTest("Cannot run %r: %s\nDo you have iperf3 installed?"
+ % (_IPERF3_BINARY.cmd, e))
+ raise
+
+
+def requires_iperf3(f):
+ @functools.wraps(f)
+ def wrapper(*a, **kw):
+ check_iperf()
+ return f(*a, **kw)
+ return wrapper
--
To view, visit https://gerrit.ovirt.org/46448
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I15657f8844d131c5444dd680b8de7aa1c4ec2638
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ido Barkan <ibarkan(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: build: Introduce --enable-gluster configuration
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: build: Introduce --enable-gluster configuration
......................................................................
build: Introduce --enable-gluster configuration
Previously building gluster package and building for RHEV were coupled
together in an ugly way. We disabled gluster package when building for
RHEV, and enabled some gluster apis only when building for RHEV.
We want to get rid of these downstream related options, but we also want
to allow downstream maintainers easy way to configure the package as
needed.
This patch decouples rhev_build and with_gluster options; To build the
vdsm-gluster package, use:
./configure --enable-gluster
To build without vdsm-gluster package, use:
./configure --disable-gluster
When gluster is enabled, supervdsm exposes all gluster apis marked
with @glusterapi decorator. Most of these apis are used when vdsm is
used to control gluster server.
When gluster is disabled, supervdsm exposes only the gluster vdsm apis
marked as with @ovirtapi. These apis are required for consuming gluster
storage.
Change-Id: I84608625e3b004c64b4928e5325d9375fb952878
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M Makefile.am
M configure.ac
M lib/vdsm/constants.py.in
M vdsm.spec.in
M vdsm/gluster/__init__.py
M vdsm/gluster/cli.py
M vdsm/supervdsmServer
7 files changed, 81 insertions(+), 67 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/08/46708/1
diff --git a/Makefile.am b/Makefile.am
index 5508094..13d49d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,6 +58,10 @@
WITH_HOOKS = --define="with_hooks 1"
endif
+if GLUSTER
+WITH_GLUSTER = --define="with_gluster 1"
+endif
+
if RHEV
RHEV_BUILD = --define="rhev_build 1"
endif
@@ -158,7 +162,7 @@
rpm: dist
rpmbuild -ta $(if $(BUILDID),--define="extra_release .$(BUILDID)") \
- $(WITH_HOOKS) $(RHEV_BUILD) $(KOJI_BUILD) $(DIST_ARCHIVES)
+ $(WITH_HOOKS) $(WITH_GLUSTER) $(RHEV_BUILD) $(KOJI_BUILD) $(DIST_ARCHIVES)
dist-hook: gen-VERSION gen-ChangeLog
.PHONY: gen-VERSION gen-ChangeLog
diff --git a/configure.ac b/configure.ac
index feb7e52..da361ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,17 @@
AM_CONDITIONAL([HOOKS], [test "${enable_hooks}" = "yes"])
AC_ARG_ENABLE(
+ [gluster],
+ [AS_HELP_STRING(
+ [--enable-gluster],
+ [build gluster package @<:@default=no@:>@]
+ )],
+ ,
+ [enable_gluster="no"]
+)
+AM_CONDITIONAL([GLUSTER], [test "${enable_gluster}" = "yes"])
+
+AC_ARG_ENABLE(
[rhev],
[AS_HELP_STRING(
[--enable-rhev],
diff --git a/lib/vdsm/constants.py.in b/lib/vdsm/constants.py.in
index e5cff54..542ad3e 100644
--- a/lib/vdsm/constants.py.in
+++ b/lib/vdsm/constants.py.in
@@ -23,7 +23,7 @@
from __future__ import absolute_import
import os
-RHEV_ENABLED = False if '@RHEV_TRUE@' else True
+GLUSTER_ENABLED = False if '@GLUSTER_TRUE@' else True
# VDSM management networks
LEGACY_MANAGEMENT_NETWORKS = ('ovirtmgmt', 'rhevm')
diff --git a/vdsm.spec.in b/vdsm.spec.in
index f93bcd6..9cc3597 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -13,6 +13,9 @@
# Glusterfs package version
%global gluster_version 3.7.1
+# Glusterfs - overridable using rpmbuild --define "with_gluster 1"
+%{!?with_gluster: %global with_gluster 0}
+
# koji build - overridable using rpmbuild --define "fedora_koji_build 1"
%{!?fedora_koji_build: %global fedora_koji_build 0}
@@ -40,11 +43,6 @@
%global _polkitdir %{_datadir}/polkit-1/rules.d
%else
%global _polkitdir %{_localstatedir}/lib/polkit-1/localauthority/10-vendor.d
-%endif
-
-# Gluster should not be shipped with RHEV
-%if ! 0%{?rhev_build}
-%global with_gluster 1
%endif
%if ! 0%{?rhel} || ! 0%{fedora_koji_build}
@@ -594,6 +592,7 @@
autoreconf -if
%endif
%configure %{?with_hooks:--enable-hooks} \
+ %{?with_gluster:--enable-gluster} \
%if 0%{?rhev_build}
--enable-rhev \
--with-smbios-manufacturer='Red Hat' \
diff --git a/vdsm/gluster/__init__.py b/vdsm/gluster/__init__.py
index fa953a1..23599fa 100644
--- a/vdsm/gluster/__init__.py
+++ b/vdsm/gluster/__init__.py
@@ -25,24 +25,24 @@
'gfapi', 'storagedev', 'api')
-def makePublic(func):
- func.superVdsm = True
+def glusterapi(func):
+ func.glusterapi = True
return func
-def makePublicRHEV(func):
- func.superVdsmRHEV = True
+def ovirtapi(func):
+ func.ovirtapi = True
return func
-def listPublicFunctions(rhev=False):
+def listPublicFunctions(gluster_enabled=True):
methods = []
for modName in MODULE_LIST:
try:
module = __import__('gluster.' + modName, fromlist=['gluster'])
for name in dir(module):
func = getattr(module, name)
- if _shouldPublish(func, rhev):
+ if _shouldPublish(func, gluster_enabled):
funcName = 'gluster%s%s' % (name[0].upper(), name[1:])
methods.append((funcName, func))
except ImportError:
@@ -50,11 +50,11 @@
return methods
-def _shouldPublish(func, rhev):
- if rhev:
- return getattr(func, 'superVdsmRHEV', False)
+def _shouldPublish(func, gluster_enabled):
+ if gluster_enabled:
+ return getattr(func, 'glusterapi', False)
else:
- return getattr(func, 'superVdsm', False)
+ return getattr(func, 'ovirtapi', False)
def safeWrite(fileName, content):
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index 8d399f0..0724b22 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -27,7 +27,7 @@
from vdsm import utils
from vdsm import netinfo
import exception as ge
-from . import makePublic, makePublicRHEV
+from . import glusterapi, ovirtapi
_glusterCommandPath = utils.CommandPath("gluster",
"/usr/sbin/gluster",
@@ -135,7 +135,7 @@
return ''
-@makePublic
+@glusterapi
def hostUUIDGet():
command = _getGlusterSystemCmd() + ["uuid", "get"]
rc, out, err = _execGluster(command)
@@ -265,7 +265,7 @@
return status
-@makePublic
+@glusterapi
def volumeStatus(volumeName, brick=None, option=None):
"""
Get volume status
@@ -472,8 +472,8 @@
return status
-@makePublic
-@makePublicRHEV
+@glusterapi
+@ovirtapi
def volumeInfo(volumeName=None, remoteServer=None):
"""
Returns:
@@ -501,7 +501,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeCreate(volumeName, brickList, replicaCount=0, stripeCount=0,
transportList=[], force=False):
command = _getGlusterVolCmd() + ["create", volumeName]
@@ -526,7 +526,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeStart(volumeName, force=False):
command = _getGlusterVolCmd() + ["start", volumeName]
if force:
@@ -538,7 +538,7 @@
return True
-@makePublic
+@glusterapi
def volumeStop(volumeName, force=False):
command = _getGlusterVolCmd() + ["stop", volumeName]
if force:
@@ -550,7 +550,7 @@
raise ge.GlusterVolumeStopFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def volumeDelete(volumeName):
command = _getGlusterVolCmd() + ["delete", volumeName]
try:
@@ -560,7 +560,7 @@
raise ge.GlusterVolumeDeleteFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def volumeSet(volumeName, option, value):
command = _getGlusterVolCmd() + ["set", volumeName, option, value]
try:
@@ -581,7 +581,7 @@
return optionList
-@makePublic
+@glusterapi
def volumeSetHelpXml():
rc, out, err = _execGluster(_getGlusterVolCmd() + ["set", 'help-xml'])
if rc:
@@ -590,7 +590,7 @@
return _parseVolumeSetHelpXml(out)
-@makePublic
+@glusterapi
def volumeReset(volumeName, option='', force=False):
command = _getGlusterVolCmd() + ['reset', volumeName]
if option:
@@ -604,7 +604,7 @@
raise ge.GlusterVolumeResetFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def volumeAddBrick(volumeName, brickList,
replicaCount=0, stripeCount=0, force=False):
command = _getGlusterVolCmd() + ["add-brick", volumeName]
@@ -622,7 +622,7 @@
raise ge.GlusterVolumeBrickAddFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def volumeRebalanceStart(volumeName, rebalanceType="", force=False):
command = _getGlusterVolCmd() + ["rebalance", volumeName]
if rebalanceType:
@@ -641,7 +641,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeRebalanceStop(volumeName, force=False):
command = _getGlusterVolCmd() + ["rebalance", volumeName, "stop"]
if force:
@@ -658,7 +658,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def _parseVolumeRebalanceRemoveBrickStatus(xmltree, mode):
"""
returns {'hosts': [{'name': NAME,
@@ -714,7 +714,7 @@
return status
-@makePublic
+@glusterapi
def volumeRebalanceStatus(volumeName):
command = _getGlusterVolCmd() + ["rebalance", volumeName, "status"]
try:
@@ -728,7 +728,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeReplaceBrickCommitForce(volumeName, existingBrick, newBrick):
command = _getGlusterVolCmd() + ["replace-brick", volumeName,
existingBrick, newBrick, "commit",
@@ -741,7 +741,7 @@
err=e.err)
-@makePublic
+@glusterapi
def volumeRemoveBrickStart(volumeName, brickList, replicaCount=0):
command = _getGlusterVolCmd() + ["remove-brick", volumeName]
if replicaCount:
@@ -758,7 +758,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeRemoveBrickStop(volumeName, brickList, replicaCount=0):
command = _getGlusterVolCmd() + ["remove-brick", volumeName]
if replicaCount:
@@ -776,7 +776,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeRemoveBrickStatus(volumeName, brickList, replicaCount=0):
command = _getGlusterVolCmd() + ["remove-brick", volumeName]
if replicaCount:
@@ -793,7 +793,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeRemoveBrickCommit(volumeName, brickList, replicaCount=0):
command = _getGlusterVolCmd() + ["remove-brick", volumeName]
if replicaCount:
@@ -807,7 +807,7 @@
err=e.err)
-@makePublic
+@glusterapi
def volumeRemoveBrickForce(volumeName, brickList, replicaCount=0):
command = _getGlusterVolCmd() + ["remove-brick", volumeName]
if replicaCount:
@@ -821,7 +821,7 @@
err=e.err)
-@makePublic
+@glusterapi
def peerProbe(hostName):
command = _getGlusterPeerCmd() + ["probe", hostName]
try:
@@ -831,7 +831,7 @@
raise ge.GlusterHostAddFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def peerDetach(hostName, force=False):
command = _getGlusterPeerCmd() + ["detach", hostName]
if force:
@@ -865,7 +865,7 @@
return hostList
-@makePublic
+@glusterapi
def peerStatus():
"""
Returns:
@@ -884,7 +884,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeProfileStart(volumeName):
command = _getGlusterVolCmd() + ["profile", volumeName, "start"]
try:
@@ -894,7 +894,7 @@
return True
-@makePublic
+@glusterapi
def volumeProfileStop(volumeName):
command = _getGlusterVolCmd() + ["profile", volumeName, "stop"]
try:
@@ -904,7 +904,7 @@
return True
-@makePublic
+@glusterapi
def volumeProfileInfo(volumeName, nfs=False):
"""
Returns:
@@ -1010,7 +1010,7 @@
return tasks
-@makePublic
+@glusterapi
def volumeTasks(volumeName="all"):
command = _getGlusterVolCmd() + ["status", volumeName, "tasks"]
try:
@@ -1023,7 +1023,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeGeoRepSessionStart(volumeName, remoteHost, remoteVolumeName,
remoteUserName=None, force=False):
if remoteUserName:
@@ -1042,7 +1042,7 @@
err=e.err)
-@makePublic
+@glusterapi
def volumeGeoRepSessionStop(volumeName, remoteHost, remoteVolumeName,
remoteUserName=None, force=False):
if remoteUserName:
@@ -1141,7 +1141,7 @@
return status
-@makePublic
+@glusterapi
def volumeGeoRepStatus(volumeName=None, remoteHost=None,
remoteVolumeName=None, remoteUserName=None):
if remoteUserName:
@@ -1165,7 +1165,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def volumeGeoRepSessionPause(volumeName, remoteHost, remoteVolumeName,
remoteUserName=None, force=False):
if remoteUserName:
@@ -1184,7 +1184,7 @@
err=e.err)
-@makePublic
+@glusterapi
def volumeGeoRepSessionResume(volumeName, remoteHost, remoteVolumeName,
remoteUserName=None, force=False):
if remoteUserName:
@@ -1216,7 +1216,7 @@
return {'geoRepConfig': config}
-@makePublic
+@glusterapi
def volumeGeoRepConfig(volumeName, remoteHost,
remoteVolumeName, optionName=None,
optionValue=None,
@@ -1244,7 +1244,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def snapshotCreate(volumeName, snapName,
snapDescription=None,
force=False):
@@ -1266,7 +1266,7 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def snapshotDelete(volumeName=None, snapName=None):
command = _getGlusterSnapshotCmd() + ["delete"]
if snapName:
@@ -1282,7 +1282,7 @@
return True
-@makePublic
+@glusterapi
def snapshotActivate(snapName, force=False):
command = _getGlusterSnapshotCmd() + ["activate", snapName]
@@ -1296,7 +1296,7 @@
raise ge.GlusterSnapshotActivateFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def snapshotDeactivate(snapName):
command = _getGlusterSnapshotCmd() + ["deactivate", snapName]
@@ -1326,7 +1326,7 @@
return snapshotRestore
-@makePublic
+@glusterapi
def snapshotRestore(snapName):
command = _getGlusterSnapshotCmd() + ["restore", snapName]
@@ -1371,7 +1371,7 @@
return {'system': systemConfig, 'volume': volumeConfig}
-@makePublic
+@glusterapi
def snapshotConfig(volumeName=None, optionName=None, optionValue=None):
command = _getGlusterSnapshotCmd() + ["config"]
if volumeName:
@@ -1491,7 +1491,7 @@
return volumes
-@makePublic
+@glusterapi
def snapshotInfo(volumeName=None):
command = _getGlusterSnapshotCmd() + ["info"]
if volumeName:
@@ -1509,7 +1509,7 @@
raise ge.GlusterXmlErrorInfoException(err=[etree.tostring(xmltree)])
-@makePublic
+@glusterapi
def executeGsecCreate():
command = _getGlusterSystemCmd() + ["execute", "gsec_create"]
rc, out, err = _execGluster(command)
@@ -1519,7 +1519,7 @@
return True
-@makePublic
+@glusterapi
def executeMountBrokerUserAdd(remoteUserName, remoteVolumeName):
command = _getGlusterSystemCmd() + ["execute", "mountbroker",
"user", remoteUserName,
@@ -1532,7 +1532,7 @@
return True
-@makePublic
+@glusterapi
def executeMountBrokerOpt(optionName, optionValue):
command = _getGlusterSystemCmd() + ["execute", "mountbroker",
"opt", optionName,
@@ -1544,7 +1544,7 @@
return True
-@makePublic
+@glusterapi
def volumeGeoRepSessionCreate(volumeName, remoteHost,
remoteVolumeName,
remoteUserName=None, force=False):
@@ -1564,7 +1564,7 @@
raise ge.GlusterGeoRepSessionCreateFailedException(rc=e.rc, err=e.err)
-@makePublic
+@glusterapi
def volumeGeoRepSessionDelete(volumeName, remoteHost, remoteVolumeName,
remoteUserName=None):
if remoteUserName:
diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer
index 9a679ee..62aa7bb 100755
--- a/vdsm/supervdsmServer
+++ b/vdsm/supervdsmServer
@@ -77,7 +77,7 @@
from vdsm.constants import METADATA_GROUP, EXT_CHOWN, \
DISKIMAGE_USER, DISKIMAGE_GROUP, \
P_LIBVIRT_VMCHANNELS, P_OVIRT_VMCONSOLES, \
- VDSM_USER, QEMU_PROCESS_USER, QEMU_PROCESS_GROUP, RHEV_ENABLED
+ VDSM_USER, QEMU_PROCESS_USER, QEMU_PROCESS_GROUP, GLUSTER_ENABLED
from storage.devicemapper import _removeMapping, _getPathsStatus
from vdsm.config import config
import mkimage
@@ -532,7 +532,7 @@
return wrapper
if _glusterEnabled:
- for name, func in listPublicFunctions(RHEV_ENABLED):
+ for name, func in listPublicFunctions(GLUSTER_ENABLED):
setattr(_SuperVdsm, name, logDecorator(bind(func)))
try:
--
To view, visit https://gerrit.ovirt.org/46708
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I84608625e3b004c64b4928e5325d9375fb952878
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: gluster: Added VDSM verb to stop gluster related processes
by shtripat@redhat.com
Shubhendu Tripathi has uploaded a new change for review.
Change subject: gluster: Added VDSM verb to stop gluster related processes
......................................................................
gluster: Added VDSM verb to stop gluster related processes
Added a verb which stops the gluster related process like
brick processes, gsyncd process.
This needs to be done as part of a host moving to maintenance
mode. as data should not be available if a host is moved to
maintenence mode for some migration etc.
Change-Id: Id686e098b323eededcf1f89de331a1d524274995
Bug-URL: https://bugzilla.redhat.com/1205724
Signed-off-by: Shubhendu Tripathi <shtripat(a)redhat.com>
---
M client/vdsClientGluster.py
M vdsm/gluster/api.py
M vdsm/gluster/apiwrapper.py
M vdsm/gluster/exception.py
M vdsm/rpc/vdsmapi-gluster-schema.json
5 files changed, 51 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/21/43821/1
diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index a4bce63..a72d4e3 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -740,6 +740,11 @@
pp.pprint(status)
return status['status']['code'], status['status']['message']
+ def do_glusterStopProcesses(self, args):
+ status = self.s.glusterStopProcesses()
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
def getGlusterCmdDict(serv):
return \
@@ -1252,5 +1257,10 @@
serv.do_glusterSnapshotScheduleReset,
('',
'Reset gluster snapshot scheduling'
+ )),
+ 'glusterStopProcesses' : (
+ serv.do_glusterStopProcesses,
+ ('',
+ 'Stop gluster processes'
))
}
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 781ab77..3467412 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -52,6 +52,12 @@
"/usr/sbin/snap_scheduler.py",
)
+_stopAllProcessesPath = utils.CommandPath(
+ "stop-all-gluster-processes.sh",
+ "/usr/share/glusterfs/scripts/stop-all-gluster-processes.sh",
+)
+
+
GLUSTER_RPM_PACKAGES = (
('glusterfs', ('glusterfs',)),
('glusterfs-fuse', ('glusterfs-fuse',)),
@@ -262,6 +268,15 @@
except (IOError, OSError) as e:
raise ge.GlusterSnapshotScheduleFlagUpdateFailedException(
err=[str(e)])
+ return True
+
+
+@makePublic
+def stopProcesses():
+ command = ["/bin/sh", _stopAllProcessesPath.cmd]
+ rc, out, err = utils.execCmd(command)
+ if rc:
+ raise ge.GlusterStopProcessesFailedException(rc)
return True
@@ -752,6 +767,10 @@
def snapshotScheduleReset(self, options=None):
self.svdsmProxy.glusterSnapshotScheduleFlagUpdate("none")
+ @exportAsVerb
+ def stopProcesses(self):
+ self.svdsmProxy.glusterStopProcesses()
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/apiwrapper.py b/vdsm/gluster/apiwrapper.py
index 4768a86..13dc859 100644
--- a/vdsm/gluster/apiwrapper.py
+++ b/vdsm/gluster/apiwrapper.py
@@ -86,6 +86,9 @@
return self._gluster.createBrick(name, mountPoint,
devList, fsType, raidParams)
+ def stopProcesses(self):
+ return self._gluster.stopProcesses()
+
class GlusterService(GlusterApiBase):
def __init__(self):
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index 17ad018..2898d3d 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -594,6 +594,12 @@
message = "Failed to disable snapshot schedule through cli"
+class GlusterStopProcessesFailedException(
+ GlusterVolumeException):
+ code = 4579
+ message = "Failed to stop gluster processes"
+
+
# geo-replication
class GlusterGeoRepException(GlusterException):
code = 4200
diff --git a/vdsm/rpc/vdsmapi-gluster-schema.json b/vdsm/rpc/vdsmapi-gluster-schema.json
index c86f43c..2853851 100644
--- a/vdsm/rpc/vdsmapi-gluster-schema.json
+++ b/vdsm/rpc/vdsmapi-gluster-schema.json
@@ -1299,6 +1299,19 @@
'returns': 'bool'}
##
+# @GlusterHost.stopProcesses:
+#
+# Stops the gluster processes on the host
+#
+# Returns:
+# Success or failure
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'GlusterHost', 'name': 'stopProcesses'},
+ 'returns': 'bool'}
+
+##
# @GlusterVolumeStatsInfo:
#
# Gluster Volumes disk usage statistics
--
To view, visit https://gerrit.ovirt.org/43821
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id686e098b323eededcf1f89de331a1d524274995
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Shubhendu Tripathi <shtripat(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: VolumeMetadata: Move imagePath and validation
by alitke@redhat.com
Adam Litke has uploaded a new change for review.
Change subject: VolumeMetadata: Move imagePath and validation
......................................................................
VolumeMetadata: Move imagePath and validation
Change-Id: I5d03085f04c92c1be68be2c0873e0545d307bdfa
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/sdm_indirection_tests.py
M vdsm/storage/blockVolume.py
M vdsm/storage/fileVolume.py
M vdsm/storage/volume.py
4 files changed, 45 insertions(+), 34 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/82/46382/1
diff --git a/tests/sdm_indirection_tests.py b/tests/sdm_indirection_tests.py
index d331b2f..6ce9df5 100644
--- a/tests/sdm_indirection_tests.py
+++ b/tests/sdm_indirection_tests.py
@@ -499,6 +499,7 @@
['imgUUID', 'e2a325e4-62be-4939-8145-72277c270e8e'],
['volUUID', '6aab5eb4-2a8b-4cb7-a0b7-bc6f61de3e18'],
['repoPath', '/rhev/data-center'],
+ ['imagePath', '/a/b'],
['voltype', None],
])
def test_property(self, prop, val):
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index df30084..2955f28 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -74,6 +74,20 @@
volume.VolumeMetadata.__init__(self, repoPath, sdUUID, imgUUID,
volUUID)
+ def validateImagePath(self):
+ """
+ Block SD supports lazy image dir creation
+ """
+ imageDir = image.ImageManifest(self.repoPath).getImageDir(self.sdUUID,
+ self.imgUUID)
+ if not os.path.isdir(imageDir):
+ try:
+ os.mkdir(imageDir, 0o755)
+ except Exception:
+ self.log.exception("Unexpected error")
+ raise se.ImagePathError(imageDir)
+ self._imagePath = imageDir
+
class BlockVolume(volume.Volume):
""" Actually represents a single volume (i.e. part of virtual disk).
@@ -336,7 +350,7 @@
"""
self.log.info("Rename volume %s as %s ", self.volUUID, newUUID)
if not self.imagePath:
- self.validateImagePath()
+ self.md.validateImagePath()
if os.path.lexists(self.getVolumePath()):
os.unlink(self.getVolumePath())
@@ -421,20 +435,6 @@
if pvolUUID != volume.BLANK_UUID:
cls.teardown(sdUUID=sdUUID, volUUID=pvolUUID, justme=False)
- def validateImagePath(self):
- """
- Block SD supports lazy image dir creation
- """
- imageDir = image.Image(self.repoPath).getImageDir(self.sdUUID,
- self.imgUUID)
- if not os.path.isdir(imageDir):
- try:
- os.mkdir(imageDir, 0o755)
- except Exception:
- self.log.error("Unexpected error", exc_info=True)
- raise se.ImagePathError(imageDir)
- self.imagePath = imageDir
-
def validateVolumePath(self):
"""
Block SD supports lazy volume link creation. Note that the volume can
@@ -442,7 +442,7 @@
An explicit prepare is required to validate that the volume is active.
"""
if not self.imagePath:
- self.validateImagePath()
+ self.md.validateImagePath()
volPath = os.path.join(self.imagePath, self.volUUID)
if not os.path.lexists(volPath):
srcPath = lvm.lvPath(self.sdUUID, self.volUUID)
diff --git a/vdsm/storage/fileVolume.py b/vdsm/storage/fileVolume.py
index 002f2c0..cfe40d0 100644
--- a/vdsm/storage/fileVolume.py
+++ b/vdsm/storage/fileVolume.py
@@ -60,6 +60,20 @@
def oop(self):
return oop.getProcessPool(self.sdUUID)
+ def validateImagePath(self):
+ """
+ Validate that the image dir exists and valid.
+ In the file volume repositories,
+ the image dir must exists after creation its first volume.
+ """
+ imageDir = image.ImageManifest(self.repoPath).getImageDir(self.sdUUID,
+ self.imgUUID)
+ if not self.oop.os.path.isdir(imageDir):
+ raise se.ImagePathError(imageDir)
+ if not self.oop.os.access(imageDir, os.R_OK | os.W_OK | os.X_OK):
+ raise se.ImagePathError(imageDir)
+ self._imagePath = imageDir
+
class FileVolume(volume.Volume):
""" Actually represents a single volume (i.e. part of virtual disk).
@@ -451,7 +465,7 @@
"""
self.log.info("Rename volume %s as %s ", self.volUUID, newUUID)
if not self.imagePath:
- self.validateImagePath()
+ self.md.validateImagePath()
volPath = os.path.join(self.imagePath, newUUID)
metaPath = self._getMetaVolumePath(volPath)
prevMetaPath = self._getMetaVolumePath()
@@ -488,20 +502,6 @@
raise
self.md.volUUID = newUUID
self.volumePath = volPath
-
- def validateImagePath(self):
- """
- Validate that the image dir exists and valid.
- In the file volume repositories,
- the image dir must exists after creation its first volume.
- """
- imageDir = image.Image(self.repoPath).getImageDir(self.sdUUID,
- self.imgUUID)
- if not self.oop.os.path.isdir(imageDir):
- raise se.ImagePathError(imageDir)
- if not self.oop.os.access(imageDir, os.R_OK | os.W_OK | os.X_OK):
- raise se.ImagePathError(imageDir)
- self.imagePath = imageDir
@classmethod
def __metaVolumePath(cls, volPath):
@@ -541,7 +541,7 @@
"""
self.log.debug("validate path for %s" % self.volUUID)
if not self.imagePath:
- self.validateImagePath()
+ self.md.validateImagePath()
volPath = os.path.join(self.imagePath, self.volUUID)
if not self.oop.fileUtils.pathExists(volPath):
raise se.VolumeDoesNotExist(self.volUUID)
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index ec82c9b..26487bd 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -134,12 +134,19 @@
self.sdUUID = sdUUID
self.imgUUID = imgUUID
self.volUUID = volUUID
+ self._imagePath = None
self.voltype = None
if not imgUUID or imgUUID == BLANK_UUID:
raise se.InvalidParameterException("imgUUID", imgUUID)
if not volUUID or volUUID == BLANK_UUID:
raise se.InvalidParameterException("volUUID", volUUID)
+
+ @property
+ def imagePath(self):
+ if self._imagePath is None:
+ self.validateImagePath()
+ return self._imagePath
class Volume(object):
@@ -148,7 +155,6 @@
def __init__(self, md):
self.md = md
self.volumePath = None
- self.imagePath = None
self.validate()
@property
@@ -168,6 +174,10 @@
return self.md.repoPath
@property
+ def imagePath(self):
+ return self.md.imagePath
+
+ @property
def voltype(self):
return self.md.voltype
@@ -181,7 +191,7 @@
"""
Validate that the volume can be accessed
"""
- self.validateImagePath()
+ self.md.validateImagePath()
self.validateVolumePath()
def __str__(self):
--
To view, visit https://gerrit.ovirt.org/46382
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d03085f04c92c1be68be2c0873e0545d307bdfa
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: VolumeMetadata: Move volumePath and validation
by alitke@redhat.com
Adam Litke has uploaded a new change for review.
Change subject: VolumeMetadata: Move volumePath and validation
......................................................................
VolumeMetadata: Move volumePath and validation
Change-Id: I5b38519df298d6e7b9a4bba2642d615976e0ea04
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/sdm_indirection_tests.py
M vdsm/storage/blockVolume.py
M vdsm/storage/fileVolume.py
M vdsm/storage/volume.py
4 files changed, 99 insertions(+), 68 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/83/46383/1
diff --git a/tests/sdm_indirection_tests.py b/tests/sdm_indirection_tests.py
index 6ce9df5..a27ff5c 100644
--- a/tests/sdm_indirection_tests.py
+++ b/tests/sdm_indirection_tests.py
@@ -500,10 +500,17 @@
['volUUID', '6aab5eb4-2a8b-4cb7-a0b7-bc6f61de3e18'],
['repoPath', '/rhev/data-center'],
['imagePath', '/a/b'],
+ ['volumePath', '/a/b/c'],
['voltype', None],
])
def test_property(self, prop, val):
self.assertEqual(getattr(self.source_inst, prop), val)
+
+ @permutations([
+ ['getVolumePath', 0],
+ ])
+ def test_common_functions(self, fn, nargs):
+ self.checker.check_call(fn, nargs)
class BlockVolumeTests(VolumeTestMixin, VdsmTestCase):
@@ -525,3 +532,9 @@
])
def test_file_property(self, prop, val):
self.assertEqual(getattr(self.source_inst, prop), val)
+
+ @permutations([
+ ['_getMetaVolumePath', 1],
+ ])
+ def test_functions(self, fn, nargs):
+ self.checker.check_call(fn, nargs)
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index 2955f28..fa26270 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -88,6 +88,21 @@
raise se.ImagePathError(imageDir)
self._imagePath = imageDir
+ def validateVolumePath(self):
+ """
+ Block SD supports lazy volume link creation. Note that the volume can
+ be still inactive.
+ An explicit prepare is required to validate that the volume is active.
+ """
+ if not self._imagePath:
+ self.validateImagePath()
+ volPath = os.path.join(self._imagePath, self.volUUID)
+ if not os.path.lexists(volPath):
+ srcPath = lvm.lvPath(self.sdUUID, self.volUUID)
+ self.log.debug("Creating symlink from %s to %s", srcPath, volPath)
+ os.symlink(srcPath, volPath)
+ self._volumePath = volPath
+
class BlockVolume(volume.Volume):
""" Actually represents a single volume (i.e. part of virtual disk).
@@ -363,7 +378,7 @@
lvm.renameLV(self.sdUUID, self.volUUID, newUUID)
self.md.volUUID = newUUID
- self.volumePath = os.path.join(self.imagePath, newUUID)
+ self.md.volumePath = os.path.join(self.imagePath, newUUID)
def getDevPath(self):
"""
@@ -434,21 +449,6 @@
if pvolUUID != volume.BLANK_UUID:
cls.teardown(sdUUID=sdUUID, volUUID=pvolUUID, justme=False)
-
- def validateVolumePath(self):
- """
- Block SD supports lazy volume link creation. Note that the volume can
- be still inactive.
- An explicit prepare is required to validate that the volume is active.
- """
- if not self.imagePath:
- self.md.validateImagePath()
- volPath = os.path.join(self.imagePath, self.volUUID)
- if not os.path.lexists(volPath):
- srcPath = lvm.lvPath(self.sdUUID, self.volUUID)
- self.log.debug("Creating symlink from %s to %s", srcPath, volPath)
- os.symlink(srcPath, volPath)
- self.volumePath = volPath
def getVolumeTag(self, tagPrefix):
return _getVolumeTag(self.sdUUID, self.volUUID, tagPrefix)
diff --git a/vdsm/storage/fileVolume.py b/vdsm/storage/fileVolume.py
index cfe40d0..94a64db 100644
--- a/vdsm/storage/fileVolume.py
+++ b/vdsm/storage/fileVolume.py
@@ -30,6 +30,7 @@
import volume
import image
import sd
+import fileSD
import misc
from misc import deprecated
import task
@@ -74,6 +75,48 @@
raise se.ImagePathError(imageDir)
self._imagePath = imageDir
+ @classmethod
+ def _metaVolumePath(cls, volPath):
+ if volPath:
+ return volPath + META_FILEEXT
+ else:
+ return None
+
+ def _getMetaVolumePath(self, vol_path=None):
+ """
+ Get the volume metadata file/link path
+ """
+ if not vol_path:
+ vol_path = self.getVolumePath()
+ return self._metaVolumePath(vol_path)
+
+ def validateMetaVolumePath(self):
+ """
+ In file volume repositories,
+ the volume metadata must exists after the image/volume is created.
+ """
+ metaVolumePath = self._getMetaVolumePath()
+ if not self.oop.fileUtils.pathExists(metaVolumePath):
+ raise se.VolumeDoesNotExist(self.volUUID)
+
+ def validateVolumePath(self):
+ """
+ In file volume repositories,
+ the volume file and the volume md must exists after
+ the image/volume is created.
+ """
+ self.log.debug("validate path for %s" % self.volUUID)
+ if not self.imagePath:
+ self.validateImagePath()
+ volPath = os.path.join(self.imagePath, self.volUUID)
+ if not self.oop.fileUtils.pathExists(volPath):
+ raise se.VolumeDoesNotExist(self.volUUID)
+
+ self._volumePath = volPath
+ domainPath = os.path.join(self.repoPath, self.sdUUID)
+ if not fileSD.FileStorageDomainManifest(domainPath).isISO():
+ self.validateMetaVolumePath()
+
class FileVolume(volume.Volume):
""" Actually represents a single volume (i.e. part of virtual disk).
@@ -109,7 +152,7 @@
raise TypeError("halfbakedVolumeRollback takes 1 or 3 "
"arguments (%d given)" % len(args))
- metaVolPath = cls.__metaVolumePath(volPath)
+ metaVolPath = cls.MetadataClass._metaVolumePath(volPath)
cls.log.info("Halfbaked volume rollback for volPath=%s", volPath)
if oop.getProcessPool(sdUUID).fileUtils.pathExists(volPath) and not \
@@ -119,7 +162,7 @@
@classmethod
def createVolumeMetadataRollback(cls, taskObj, volPath):
cls.log.info("createVolumeMetadataRollback: volPath=%s" % (volPath))
- metaPath = cls.__metaVolumePath(volPath)
+ metaPath = cls.MetadataClass._metaVolumePath(volPath)
sdUUID = getDomUuidFromVolumePath(volPath)
if oop.getProcessPool(sdUUID).os.path.lexists(metaPath):
oop.getProcessPool(sdUUID).os.unlink(metaPath)
@@ -264,7 +307,7 @@
cls.log.info("Volume rollback for volPath=%s", volPath)
procPool = oop.getProcessPool(getDomUuidFromVolumePath(volPath))
procPool.utils.rmFile(volPath)
- procPool.utils.rmFile(cls.__metaVolumePath(volPath))
+ procPool.utils.rmFile(cls.MetadataClass._metaVolumePath(volPath))
procPool.utils.rmFile(cls.__leaseVolumePath(volPath))
@deprecated # valid only for domain version < 3, see volume.setrw
@@ -339,7 +382,7 @@
@classmethod
def __putMetadata(cls, metaId, meta):
volPath, = metaId
- metaPath = cls.__metaVolumePath(volPath)
+ metaPath = cls.MetadataClass._metaVolumePath(volPath)
with open(metaPath + ".new", "w") as f:
for key, value in meta.iteritems():
@@ -501,14 +544,7 @@
if e.errno != os.errno.ENOENT:
raise
self.md.volUUID = newUUID
- self.volumePath = volPath
-
- @classmethod
- def __metaVolumePath(cls, volPath):
- if volPath:
- return volPath + META_FILEEXT
- else:
- return None
+ self.md.volumePath = volPath
@classmethod
def __leaseVolumePath(cls, vol_path):
@@ -518,12 +554,7 @@
return None
def _getMetaVolumePath(self, vol_path=None):
- """
- Get the volume metadata file/link path
- """
- if not vol_path:
- vol_path = self.getVolumePath()
- return self.__metaVolumePath(vol_path)
+ return self.md._getMetaVolumePath(vol_path)
def _getLeaseVolumePath(self, vol_path=None):
"""
@@ -532,32 +563,6 @@
if not vol_path:
vol_path = self.getVolumePath()
return self.__leaseVolumePath(vol_path)
-
- def validateVolumePath(self):
- """
- In file volume repositories,
- the volume file and the volume md must exists after
- the image/volume is created.
- """
- self.log.debug("validate path for %s" % self.volUUID)
- if not self.imagePath:
- self.md.validateImagePath()
- volPath = os.path.join(self.imagePath, self.volUUID)
- if not self.oop.fileUtils.pathExists(volPath):
- raise se.VolumeDoesNotExist(self.volUUID)
-
- self.volumePath = volPath
- if not sdCache.produce(self.sdUUID).isISO():
- self.validateMetaVolumePath()
-
- def validateMetaVolumePath(self):
- """
- In file volume repositories,
- the volume metadata must exists after the image/volume is created.
- """
- metaVolumePath = self._getMetaVolumePath()
- if not self.oop.fileUtils.pathExists(metaVolumePath):
- raise se.VolumeDoesNotExist(self.volUUID)
def getVolumeSize(self, bs=BLOCK_SIZE):
"""
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index 26487bd..c865b16 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -134,6 +134,7 @@
self.sdUUID = sdUUID
self.imgUUID = imgUUID
self.volUUID = volUUID
+ self._volumePath = None
self._imagePath = None
self.voltype = None
@@ -148,13 +149,26 @@
self.validateImagePath()
return self._imagePath
+ @property
+ def volumePath(self):
+ if self._volumePath is None:
+ self.validateVolumePath()
+ return self._volumePath
+
+ def getVolumePath(self):
+ """
+ Get the path of the volume file/link
+ """
+ if not self._volumePath:
+ raise se.VolumeAccessError(self.volUUID)
+ return self._volumePath
+
class Volume(object):
log = logging.getLogger('Storage.Volume')
def __init__(self, md):
self.md = md
- self.volumePath = None
self.validate()
@property
@@ -172,6 +186,10 @@
@property
def repoPath(self):
return self.md.repoPath
+
+ @property
+ def volumePath(self):
+ return self.md.volumePath
@property
def imagePath(self):
@@ -192,7 +210,7 @@
Validate that the volume can be accessed
"""
self.md.validateImagePath()
- self.validateVolumePath()
+ self.md.validateVolumePath()
def __str__(self):
return str(self.volUUID)
@@ -939,12 +957,7 @@
self.setParentMeta(puuid)
def getVolumePath(self):
- """
- Get the path of the volume file/link
- """
- if not self.volumePath:
- raise se.VolumeAccessError(self.volUUID)
- return self.volumePath
+ return self.md.getVolumePath()
def getVmVolumeInfo(self):
"""
--
To view, visit https://gerrit.ovirt.org/46383
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5b38519df298d6e7b9a4bba2642d615976e0ea04
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: VolumeMetadata: Move instance validation
by alitke@redhat.com
Adam Litke has uploaded a new change for review.
Change subject: VolumeMetadata: Move instance validation
......................................................................
VolumeMetadata: Move instance validation
Change-Id: I5bb27df116553f14931e9760e5968f02bd7d523b
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockVolume.py
M vdsm/storage/volume.py
2 files changed, 15 insertions(+), 15 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/84/46384/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index fa26270..26fcc3a 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -103,6 +103,13 @@
os.symlink(srcPath, volPath)
self._volumePath = volPath
+ def validate(self):
+ try:
+ lvm.getLV(self.sdUUID, self.volUUID)
+ except se.LogicalVolumeDoesNotExistError:
+ raise se.VolumeDoesNotExist(self.volUUID)
+ volume.VolumeMetadata.validate(self)
+
class BlockVolume(volume.Volume):
""" Actually represents a single volume (i.e. part of virtual disk).
@@ -115,13 +122,6 @@
volume.Volume.__init__(self, md)
self.lvmActivationNamespace = sd.getNamespace(self.sdUUID,
LVM_ACTIVATION_NAMESPACE)
-
- def validate(self):
- try:
- lvm.getLV(self.sdUUID, self.volUUID)
- except se.LogicalVolumeDoesNotExistError:
- raise se.VolumeDoesNotExist(self.volUUID)
- volume.Volume.validate(self)
def refreshVolume(self):
lvm.refreshLVs(self.sdUUID, (self.volUUID,))
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index c865b16..d8cd3fb 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -142,6 +142,7 @@
raise se.InvalidParameterException("imgUUID", imgUUID)
if not volUUID or volUUID == BLANK_UUID:
raise se.InvalidParameterException("volUUID", volUUID)
+ self.validate()
@property
def imagePath(self):
@@ -154,6 +155,13 @@
if self._volumePath is None:
self.validateVolumePath()
return self._volumePath
+
+ def validate(self):
+ """
+ Validate that the volume can be accessed
+ """
+ self.validateImagePath()
+ self.validateVolumePath()
def getVolumePath(self):
"""
@@ -169,7 +177,6 @@
def __init__(self, md):
self.md = md
- self.validate()
@property
def sdUUID(self):
@@ -204,13 +211,6 @@
clsName = cls.__name__
clsModule = cls.__module__.split(".").pop()
return clsModule, clsName
-
- def validate(self):
- """
- Validate that the volume can be accessed
- """
- self.md.validateImagePath()
- self.md.validateVolumePath()
def __str__(self):
return str(self.volUUID)
--
To view, visit https://gerrit.ovirt.org/46384
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5bb27df116553f14931e9760e5968f02bd7d523b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: vmchannel: performance enhancment. changing thread name
by emarcian@redhat.com
Eldad Marciano has uploaded a new change for review.
Change subject: vmchannel: performance enhancment. changing thread name
......................................................................
vmchannel: performance enhancment.
changing thread name
Change-Id: I8489ec3a65ed9025eb91dfc2f408450b02fd7e0c
Signed-off-by: emarcian <emarcian(a)redhat.com>
---
M vdsm/virt/vmchannels.py
1 file changed, 2 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/42/36342/1
diff --git a/vdsm/virt/vmchannels.py b/vdsm/virt/vmchannels.py
index c143162..e0b305e 100644
--- a/vdsm/virt/vmchannels.py
+++ b/vdsm/virt/vmchannels.py
@@ -167,8 +167,8 @@
events = NoIntrPoll(self._epoll.poll, 1)
if events:
for (fileno, event) in events:
- _wait_for_events = threading.Thread(name='handle_events-%s' % fileno, target=self._handle_event, args=(fileno, event))
- _wait_for_events.start()
+ _handle_event = threading.Thread(name='handle_events-%s' % fileno, target=self._handle_event, args=(fileno, event))
+ _handle_event.start()
else:
self._update_channels()
if (self._timeout is not None) and (self._timeout > 0):
--
To view, visit http://gerrit.ovirt.org/36342
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8489ec3a65ed9025eb91dfc2f408450b02fd7e0c
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Eldad Marciano <emarcian(a)redhat.com>
8 years, 6 months
Change in vdsm[master]: host stats: Collect stats from online cpu cores only
by rmohr@redhat.com
Roman Mohr has uploaded a new change for review.
Change subject: host stats: Collect stats from online cpu cores only
......................................................................
host stats: Collect stats from online cpu cores only
When a cpu goes offline while vdsm is running, the getVdsStats call still
tries to collect sampling data for this CPU and fails with an exception.
When vdsm is already running, it is enough to do something like
echo 0 > /sys/devices/system/cpu/cpu2/online
to break getVdsStats.
Change-Id: Ia9c247f9138e02a9230a0849a04cb2e1705e7fac
Signed-off-by: Roman Mohr <rmohr(a)redhat.com>
---
M tests/samplingTests.py
M tests/vmfakelib.py
M vdsm/virt/sampling.py
3 files changed, 47 insertions(+), 16 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/69/46269/4
diff --git a/tests/samplingTests.py b/tests/samplingTests.py
index 73e88b1..49b0410 100644
--- a/tests/samplingTests.py
+++ b/tests/samplingTests.py
@@ -313,34 +313,61 @@
self.assertEqual(last.id,
FakeHostSample.counter - 1)
- def testCpuCoreStats(self):
- node_id, cpu_id = 0, 0
- cpu_sample = {'user': 1.0, 'sys': 2.0}
-
- first_sample = fake.HostSample(1.0, {cpu_id: cpu_sample})
- last_sample = fake.HostSample(2.0, {cpu_id: cpu_sample})
-
+ def _monkeyPatchedFakeNumaTopology(self):
def fakeNumaTopology():
return {
- node_id: {
- 'cpus': [cpu_id]
+ 0: {
+ 'cpus': [0]
+ },
+ 1: {
+ 'cpus': [1]
}
}
+ return MonkeyPatchScope([(caps, 'getNumaTopology',
+ fakeNumaTopology)])
- expected = {
- '0': {
+ def _expectedResult(self, node_index=0):
+ return {
+ str(node_index): {
'cpuIdle': '100.00',
'cpuSys': '0.00',
'cpuUser': '0.00',
- 'nodeIndex': 0
+ 'nodeIndex': node_index
}
}
- with MonkeyPatchScope([(caps, 'getNumaTopology',
- fakeNumaTopology)]):
+ def testCpuCoreStats(self):
+ cpu_sample = {'user': 1.0, 'sys': 2.0}
+
+ first_sample = fake.HostSample(1.0, {0: cpu_sample, 1: cpu_sample})
+ last_sample = fake.HostSample(2.0, {0: cpu_sample, 1: cpu_sample})
+
+ with self._monkeyPatchedFakeNumaTopology():
+ result = sampling._get_cpu_core_stats(first_sample, last_sample)
+ self.assertEqual(result['0'], self._expectedResult()['0'])
+ self.assertEqual(result['1'], self._expectedResult(1)['1'])
+
+ def testSkipStatsOnMissingFirstSample(self):
+ cpu_sample = {'user': 1.0, 'sys': 2.0}
+
+ first_sample = fake.HostSample(1.0, {0: cpu_sample})
+ last_sample = fake.HostSample(2.0, {0: cpu_sample, 1: cpu_sample})
+
+ with self._monkeyPatchedFakeNumaTopology():
self.assertEqual(
sampling._get_cpu_core_stats(first_sample, last_sample),
- expected)
+ self._expectedResult())
+
+ def testSkipStatsOnMissingLastSample(self):
+ cpu_sample = {'user': 1.0, 'sys': 2.0}
+
+ first_sample = fake.HostSample(1.0, {0: cpu_sample, 1: cpu_sample})
+ last_sample = fake.HostSample(2.0, {0: cpu_sample})
+
+ with self._monkeyPatchedFakeNumaTopology():
+ self.assertEqual(
+ sampling._get_cpu_core_stats(first_sample, last_sample),
+ self._expectedResult())
class NumaNodeMemorySampleTests(TestCaseBase):
diff --git a/tests/vmfakelib.py b/tests/vmfakelib.py
index 99cbcb9..361919d 100644
--- a/tests/vmfakelib.py
+++ b/tests/vmfakelib.py
@@ -383,7 +383,7 @@
self._samples = samples
def getCoreSample(self, key):
- return self._samples[key]
+ return self._samples.get(key)
class HostSample(object):
diff --git a/vdsm/virt/sampling.py b/vdsm/virt/sampling.py
index 1ad9d46..b6b5bc9 100644
--- a/vdsm/virt/sampling.py
+++ b/vdsm/virt/sampling.py
@@ -691,6 +691,10 @@
for node_index, numa_node in six.iteritems(caps.getNumaTopology()):
cpu_cores = numa_node['cpus']
for cpu_core in cpu_cores:
+ # Do not try to collect cpu core data when no samples are present
+ if (not last_sample.cpuCores.getCoreSample(cpu_core) or not
+ first_sample.cpuCores.getCoreSample(cpu_core)):
+ continue
core_stat = {
'nodeIndex': int(node_index),
'cpuUser': compute_cpu_usage(cpu_core, 'user'),
--
To view, visit https://gerrit.ovirt.org/46269
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia9c247f9138e02a9230a0849a04cb2e1705e7fac
Gerrit-PatchSet: 4
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Roman Mohr <rmohr(a)redhat.com>
Gerrit-Reviewer: Francesco Romani <fromani(a)redhat.com>
Gerrit-Reviewer: Roman Mohr <rmohr(a)redhat.com>
Gerrit-Reviewer: automation(a)ovirt.org
8 years, 6 months