Change in vdsm[master]: tests: alignmentScanTests.py is a functional test
by ykleinbe@redhat.com
Yoav Kleinberger has uploaded a new change for review.
Change subject: tests: alignmentScanTests.py is a functional test
......................................................................
tests: alignmentScanTests.py is a functional test
Since alignmentScanTests invokes actual storage code, and does not mock
it out, it should be categorized as a functional test.
Change-Id: I4e20d17c3ebee1203bb5a721ce44d5867570ce8e
Signed-off-by: Yoav Kleinberger <ykleinbe(a)redhat.com>
---
M tests/Makefile.am
M tests/functional/Makefile.am
R tests/functional/alignmentScanTests.py
3 files changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/29745/1
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4ef8f7d..f7f4f97 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,7 +23,6 @@
SUBDIRS = functional
test_modules = \
- alignmentScanTests.py \
blocksdTests.py \
bridgeTests.py \
cPopenTests.py \
diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am
index b87fdf0..4fc2cc8 100644
--- a/tests/functional/Makefile.am
+++ b/tests/functional/Makefile.am
@@ -33,6 +33,7 @@
vmRecoveryTests.py \
storageTests.py \
veth.py \
+ alignmentScanTests.py \
$(NULL)
dist_vdsmfunctests_DATA = \
diff --git a/tests/alignmentScanTests.py b/tests/functional/alignmentScanTests.py
similarity index 100%
rename from tests/alignmentScanTests.py
rename to tests/functional/alignmentScanTests.py
--
To view, visit http://gerrit.ovirt.org/29745
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4e20d17c3ebee1203bb5a721ce44d5867570ce8e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yoav Kleinberger <ykleinbe(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: tests: use 'localhost' explicitly in test
by ykleinbe@redhat.com
Yoav Kleinberger has uploaded a new change for review.
Change subject: tests: use 'localhost' explicitly in test
......................................................................
tests: use 'localhost' explicitly in test
Previously tests could on some machines (in case the machine has a
non-default hostname). Now, since we use 'localhost' explicitly, this
will not happen.
Change-Id: I89990cff46e64120262e250eee9238b49c4edee4
Signed-off-by: Yoav Kleinberger <ykleinbe(a)redhat.com>
---
M tests/functional/storageTests.py
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/28107/1
diff --git a/tests/functional/storageTests.py b/tests/functional/storageTests.py
index 80ba312..76ca91d 100644
--- a/tests/functional/storageTests.py
+++ b/tests/functional/storageTests.py
@@ -79,7 +79,8 @@
isSSL = config.getboolean('vars', 'ssl')
if isSSL and os.geteuid() != 0:
raise SkipTest("Must be root to use SSL connection to server")
- self.s = vdscli.connect(useSSL=isSSL)
+ address = 'localhost:%s' % config.get('addresses', 'management_port')
+ self.s = vdscli.connect(hostPort=address, useSSL=isSSL)
def assertVdsOK(self, vdsResult):
# code == 0 means OK
--
To view, visit http://gerrit.ovirt.org/28107
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I89990cff46e64120262e250eee9238b49c4edee4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yoav Kleinberger <ykleinbe(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: network: Inexistence of a network in libvirt should not be f...
by osvoboda@redhat.com
Ondřej Svoboda has uploaded a new change for review.
Change subject: network: Inexistence of a network in libvirt should not be fatal to us
......................................................................
network: Inexistence of a network in libvirt should not be fatal to us
vdsm-restore-net-config (with unified persistence) is called often during
functional network tests. This is a rollback scenario and connectivity
is at stake.
A network missing in libvirt is a sign of a different failure
(and we are after you, traffic control!) but it must not harm the restoration
of networking (not only) after failed tests.
Change-Id: Ia6ae4b359d543b6e3ee560a5cb021e31d037c035
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M vdsm/network/api.py
1 file changed, 3 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/88/34988/1
diff --git a/vdsm/network/api.py b/vdsm/network/api.py
index 1b09c6c..4a2b0c5 100755
--- a/vdsm/network/api.py
+++ b/vdsm/network/api.py
@@ -691,9 +691,9 @@
del libvirt_nets[network]
_netinfo.updateDevices()
elif 'remove' in networkAttrs:
- raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, "Cannot delete "
- "network %r: It doesn't exist in the "
- "system" % network)
+ logger.warning("Not deleting network {0!r}: it is unknown to "
+ "libvirtd".format(network))
+ del networks[network]
else:
networksAdded.add(network)
--
To view, visit http://gerrit.ovirt.org/34988
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia6ae4b359d543b6e3ee560a5cb021e31d037c035
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: netinfo: Replace getVlanDevice/ID in bootstrap with ipwrappe...
by osvoboda@redhat.com
Ondřej Svoboda has uploaded a new change for review.
Change subject: netinfo: Replace getVlanDevice/ID in bootstrap with ipwrapper.getLink
......................................................................
netinfo: Replace getVlanDevice/ID in bootstrap with ipwrapper.getLink
Change-Id: I4bfb0fa3c341a517bf444832d0531b05393ae4a9
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M lib/vdsm/netinfo.py
M vdsm_reg/deployUtil.py.in
2 files changed, 16 insertions(+), 16 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/60/35360/1
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 10bbecb..aaae19f 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -223,7 +223,7 @@
def vlanSpeed(vlanName):
"""Returns the vlan's underlying device speed."""
- vlanDevName = getVlanDevice(vlanName)
+ vlanDevName = _getVlanDevice(vlanName)
vlanDev = getLink(vlanDevName)
if vlanDev.isNIC():
speed = nicSpeed(vlanDevName)
@@ -328,8 +328,8 @@
nics = []
for iface in ports(bridge):
if iface in vlans():
- iface = getVlanDevice(iface)
- vlan = getVlanID(iface)
+ iface = _getVlanDevice(iface)
+ vlan = _getVlanID(iface)
if iface in bondings():
bonding = iface
nics = slaves(iface)
@@ -690,13 +690,13 @@
return any(vlan.startswith(dev + '.') for vlan in vlans())
-def getVlanDevice(vlan):
+def _getVlanDevice(vlan):
""" Return the device of the given VLAN. """
vlanLink = getLink(vlan)
return vlanLink.device
-def getVlanID(vlan):
+def _getVlanID(vlan):
""" Return the ID of the given VLAN. """
vlanLink = getLink(vlan)
return int(vlanLink.vlanid)
@@ -785,7 +785,7 @@
if iface == interface:
yield (network, None)
elif interface.startswith(iface + '.'):
- yield (network, getVlanID(interface))
+ yield (network, _getVlanID(interface))
def getBridgelessNetworksAndVlansForIface(self, iface):
""" Returns tuples of (network, vlan) connected to nic/bond """
@@ -794,11 +794,11 @@
if iface == netdict['iface']:
yield (network, None)
elif netdict['iface'].startswith(iface + '.'):
- yield (network, getVlanID(netdict['iface']))
+ yield (network, _getVlanID(netdict['iface']))
def getVlansForIface(self, iface):
for vlanDevName in self.getVlanDevsForIface(iface):
- yield getVlanID(vlanDevName)
+ yield _getVlanID(vlanDevName)
def getVlanDevsForIface(self, iface):
for v, vdict in self.vlans.iteritems():
@@ -852,8 +852,8 @@
for port in ports:
if port in self.vlans:
assert vlan is None
- nic = getVlanDevice(port)
- vlan = getVlanID(port)
+ nic = _getVlanDevice(port)
+ vlan = _getVlanID(port)
assert self.vlans[port]['iface'] == nic
port = nic
if port in self.bondings:
diff --git a/vdsm_reg/deployUtil.py.in b/vdsm_reg/deployUtil.py.in
index 2899411..5910bd7 100644
--- a/vdsm_reg/deployUtil.py.in
+++ b/vdsm_reg/deployUtil.py.in
@@ -972,21 +972,21 @@
This helper function extract the relevant parameters of the existing
RHEL interface, in order to create a managment bridge.
"""
- netinfo = vdsmImport("netinfo")
+ ipwrapper = vdsmImport("ipwrapper")
vlan = ''
bonding = ''
nic = None
try:
- vlans = netinfo.vlans()
- if mgtIface in vlans:
- nic = netinfo.getVlanDevice(mgtIface)
- vlan = netinfo.getVlanID(mgtIface)
+ link = ipwrapper.getLink(mgtIface)
+ if link.isVLAN():
+ nic = link.device
+ vlan = link.vlanid
else:
nic = mgtIface
- if nic in netinfo.bondings():
+ if ipwrapper.getLink(nic).isBOND():
logging.error(
(
"_getRHELBridgeParams Found bonding: %s."
--
To view, visit http://gerrit.ovirt.org/35360
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4bfb0fa3c341a517bf444832d0531b05393ae4a9
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: zombiereaper: Add ability to wait on process
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: zombiereaper: Add ability to wait on process
......................................................................
zombiereaper: Add ability to wait on process
This adds the ability to wait on a process with timeout in an efficient
manner.
When the process receives SIGCHLD in addition to clearing the tracked
pids it will now call poll() on requested C\Popen objects. This will
allow the called to synchronously wait for a process to exit with
timeout.
Change-Id: Idcd69b6187bc1c412c11f6cba9af431557ea7077
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M lib/vdsm/infra/zombiereaper/__init__.py
M lib/vdsm/infra/zombiereaper/tests.py
2 files changed, 79 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/55/35055/1
diff --git a/lib/vdsm/infra/zombiereaper/__init__.py b/lib/vdsm/infra/zombiereaper/__init__.py
index f85ec30..2169ffa 100644
--- a/lib/vdsm/infra/zombiereaper/__init__.py
+++ b/lib/vdsm/infra/zombiereaper/__init__.py
@@ -28,8 +28,10 @@
import os
import signal
+from threading import Condition
_trackedPids = set()
+_waited_on_procs = {}
def autoReapPID(pid):
@@ -46,6 +48,7 @@
pid, rv = os.waitpid(pid, os.WNOHANG)
if pid != 0:
_trackedPids.discard(pid)
+
except OSError:
_trackedPids.discard(pid)
@@ -54,6 +57,52 @@
for pid in _trackedPids.copy():
_tryReap(pid)
+ for proc in _waited_on_procs.keys():
+ _tryWait(proc)
+
+
+def _tryWait(proc):
+ res = None
+ err = None
+ try:
+ res = proc.poll()
+ except Exception as e:
+ err = e
+ finally:
+ try:
+ c = _waited_on_procs[proc]
+ except KeyError:
+ pass
+ else:
+ with c:
+ if c == _waited_on_procs[proc]:
+ _waited_on_procs[proc] = (res, err)
+ c.notify_all()
+
+
+def waitproc(proc, timeout=None):
+ """Wait until a process exits
+
+ Will block until the process exists or timeout (in seconds) has passed.
+ Passing None as timeout (the default) will block forever but in that case
+ it's recommended to just use the built in wait() functionality.
+ """
+ c = Condition()
+ with c:
+ if c != _waited_on_procs.setdefault(proc, c):
+ raise ValueError("proc already being tracked")
+
+ c.wait(timeout)
+ res = _waited_on_procs.pop(proc)
+ if res == c:
+ return None
+ else:
+ rv, err = res
+ if err is not None:
+ raise err
+
+ return rv
+
def registerSignalHandler():
"""
diff --git a/lib/vdsm/infra/zombiereaper/tests.py b/lib/vdsm/infra/zombiereaper/tests.py
index ee4fb02..817aa13 100644
--- a/lib/vdsm/infra/zombiereaper/tests.py
+++ b/lib/vdsm/infra/zombiereaper/tests.py
@@ -19,16 +19,17 @@
#
from time import sleep
import os
+from threading import Thread
+
+import nose.tools as nt
from .. import zombiereaper
from cpopen import CPopen
-from unittest import TestCase
-
zombiereaper.registerSignalHandler()
-class zombieReaperTests(TestCase):
+class TestZombieReaper(object):
def testProcessDiesAfterBeingTracked(self):
p = CPopen(["sleep", "1"])
zombiereaper.autoReapPID(p.pid)
@@ -36,7 +37,7 @@
sleep(4)
# Throws error because pid is not found or is not child
- self.assertRaises(OSError, os.waitpid, p.pid, os.WNOHANG)
+ nt.assert_raises(OSError, os.waitpid, p.pid, os.WNOHANG)
def testProcessDiedBeforeBeingTracked(self):
p = CPopen(["sleep", "0"])
@@ -46,4 +47,28 @@
zombiereaper.autoReapPID(p.pid)
# Throws error because pid is not found or is not child
- self.assertRaises(OSError, os.waitpid, p.pid, os.WNOHANG)
+ nt.assert_raises(OSError, os.waitpid, p.pid, os.WNOHANG)
+
+ def testWaitProc(self):
+ p = CPopen(["sleep", "1"])
+ nt.assert_is_not_none(zombiereaper.waitproc(p, 2))
+ nt.assert_is_not_none(p.returncode)
+
+ def testWaitProcCallTwice(self):
+ p = CPopen(["sleep", "3"])
+ nt.assert_is_none(zombiereaper.waitproc(p, 1))
+ nt.assert_is_not_none(zombiereaper.waitproc(p, 3))
+ nt.assert_is_not_none(p.returncode)
+
+ def testWaitProcRegisterTwice(self):
+ p = CPopen(["sleep", "2"])
+ t = Thread(
+ name="waiter",
+ target=zombiereaper.waitproc,
+ args=(p, 4),
+ )
+ t.setDaemon(True)
+ t.start()
+ sleep(1)
+ nt.assert_raises(ValueError, zombiereaper.waitproc, p, 1)
+ t.join()
--
To view, visit http://gerrit.ovirt.org/35055
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idcd69b6187bc1c412c11f6cba9af431557ea7077
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: vmxml.py, vm.py: Remove QEMU passthrough hack in ppc64
by vdelima@redhat.com
Vitor de Lima has uploaded a new change for review.
Change subject: vmxml.py, vm.py: Remove QEMU passthrough hack in ppc64
......................................................................
vmxml.py, vm.py: Remove QEMU passthrough hack in ppc64
Recent libvirt versions already include a virtual USB keyboard and
mouse in guests with graphical consoles. This patch does not include
any information about input devices in the domain XML in order to
libvirt handle the creation of these devices automatically.
Change-Id: I64d660bf7534203d5d5cdbc318ffd1429a16f954
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1122627
Signed-off-by: Vitor de Lima <vdelima(a)redhat.com>
---
M vdsm/virt/vm.py
M vdsm/virt/vmxml.py
2 files changed, 3 insertions(+), 27 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/71/33871/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 1eebb69..5b39752 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -2679,7 +2679,9 @@
_VMCHANNEL_DEVICE_NAME)
domxml._appendAgentDevice(self._qemuguestSocketFile.decode('utf-8'),
_QEMU_GA_DEVICE_NAME)
- domxml.appendInput()
+
+ if self.arch == caps.Architecture.X86_64:
+ domxml.appendInput()
if self.arch == caps.Architecture.PPC64:
domxml.appendEmulator()
@@ -2694,9 +2696,6 @@
for drive in self._devices[DISK_DEVICES][:]:
for leaseElement in drive.getLeasesXML():
domxml._devices.appendChild(leaseElement)
-
- if self.arch == caps.Architecture.PPC64:
- domxml.appendKeyboardDevice()
return domxml.toxml()
diff --git a/vdsm/virt/vmxml.py b/vdsm/virt/vmxml.py
index eb07ba9..a83adb1 100644
--- a/vdsm/virt/vmxml.py
+++ b/vdsm/virt/vmxml.py
@@ -165,14 +165,6 @@
domainAttrs = {'type': domainType}
- # Hack around libvirt issue BZ#988070, this is going to be removed as
- # soon as the domain XML format supports the specification of USB
- # keyboards
-
- if self.arch == caps.Architecture.PPC64:
- domainAttrs['xmlns:qemu'] = \
- 'http://libvirt.org/schemas/domain/qemu/1.0'
-
self.dom = Element('domain', **domainAttrs)
self.doc.appendChild(self.dom)
@@ -444,21 +436,6 @@
inputAttrs = {'type': 'mouse', 'bus': mouseBus}
self._devices.appendChildWithArgs('input', **inputAttrs)
-
- def appendKeyboardDevice(self):
- """
- Add keyboard device for ppc64 using a QEMU argument directly.
- This is a workaround to the issue BZ#988070 in libvirt
-
- <qemu:commandline>
- <qemu:arg value='-usbdevice'/>
- <qemu:arg value='keyboard'/>
- </qemu:commandline>
- """
- commandLine = Element('qemu:commandline')
- commandLine.appendChildWithArgs('qemu:arg', value='-usbdevice')
- commandLine.appendChildWithArgs('qemu:arg', value='keyboard')
- self.dom.appendChild(commandLine)
def appendEmulator(self):
emulatorPath = '/usr/bin/qemu-system-' + self.arch
--
To view, visit http://gerrit.ovirt.org/33871
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I64d660bf7534203d5d5cdbc318ffd1429a16f954
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vitor de Lima <vdelima(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: multipath: Move all calls to multipath exe to a single method
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: multipath: Move all calls to multipath exe to a single method
......................................................................
multipath: Move all calls to multipath exe to a single method
This makes the code a bit cleaner
Change-Id: I52afc07a07a925ed7572eb369deb7c203edb04cd
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm/storage/multipath.py
1 file changed, 11 insertions(+), 4 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/55/19255/1
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 924d747..c31b5c3 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -94,6 +94,10 @@
)
+def _runCmd(args):
+ return misc.execCmd([constants.EXT_MULTIPATH] + args, sudo=True)
+
+
def rescan():
"""
Forces multipath daemon to rescan the list of available devices and
@@ -108,8 +112,8 @@
supervdsm.getProxy().forceScsiScan()
# Now let multipath daemon pick up new devices
- cmd = [constants.EXT_MULTIPATH, "-r"]
- misc.execCmd(cmd, sudo=True)
+
+ _runCmd("-r")
def isEnabled():
@@ -154,6 +158,10 @@
return False
+def flushAll():
+ _runCmd("-F")
+
+
def setupMultipath():
"""
Set up the multipath daemon configuration to the known and
@@ -173,8 +181,7 @@
raise se.MultipathSetupError()
misc.persistFile(MPATH_CONF)
- # Flush all unused multipath device maps
- misc.execCmd([constants.EXT_MULTIPATH, "-F"], sudo=True)
+ flushAll()
cmd = [constants.EXT_VDSM_TOOL, "service-reload", "multipathd"]
rc = misc.execCmd(cmd, sudo=True)[0]
--
To view, visit http://gerrit.ovirt.org/19255
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I52afc07a07a925ed7572eb369deb7c203edb04cd
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: supervdsm: log actual error in ProxyCaller
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: supervdsm: log actual error in ProxyCaller
......................................................................
supervdsm: log actual error in ProxyCaller
Change-Id: Id8a1c83d2a963002d3c793398bb62679b77f5f47
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm/supervdsm.py
1 file changed, 2 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/75/35475/1
diff --git a/vdsm/supervdsm.py b/vdsm/supervdsm.py
index d6b0209..46247f2 100644
--- a/vdsm/supervdsm.py
+++ b/vdsm/supervdsm.py
@@ -37,6 +37,7 @@
class ProxyCaller(object):
+ log = logging.getLogger("supervdsm.ProxyCaller")
def __init__(self, supervdsmProxy, funcName):
self._funcName = funcName
@@ -50,6 +51,7 @@
return callMethod()
except RemoteError:
self._supervdsmProxy._connect()
+ self.log.exception("Could not call method")
raise RuntimeError(
"Broken communication with supervdsm. Failed call to %s"
% self._funcName)
--
To view, visit http://gerrit.ovirt.org/35475
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id8a1c83d2a963002d3c793398bb62679b77f5f47
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: [WIP]Java Bindings: Proton support in Java Bindings
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: [WIP]Java Bindings: Proton support in Java Bindings
......................................................................
[WIP]Java Bindings: Proton support in Java Bindings
Change-Id: I94c52e118cb63d7df84b89a9b93da7b9e477be91
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
A client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
A client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
A client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
6 files changed, 844 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/28/15428/1
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
new file mode 100644
index 0000000..35c9099
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonAuthenticator.java
@@ -0,0 +1,98 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.qpid.proton.driver.Connector;
+import org.apache.qpid.proton.engine.Sasl;
+import org.apache.qpid.proton.engine.Sasl.SaslOutcome;
+import org.apache.qpid.proton.engine.Sasl.SaslState;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.AuthenticatorType;
+
+public final class ProtonAuthenticator {
+
+ public enum AuthenticatorType {
+
+ SERVER, CLIENT
+ }
+
+ public enum ConnectionState {
+
+ AUTHENTICATING, CONNECTED, FAILED
+ }
+ private ConnectionState _state;
+ final private AuthenticatorType _authType;
+ final private Connector<?> _connector;
+
+ public ProtonAuthenticator(Connector<?> connector,
+ AuthenticatorType authType) {
+ _authType = authType;
+ setState(ConnectionState.AUTHENTICATING);
+ _connector = connector;
+ final Sasl sasl = _connector.sasl();
+ if (authType == AuthenticatorType.CLIENT) {
+ sasl.setMechanisms(new String[]{"ANONYMOUS"});
+ sasl.client();
+ }
+ }
+
+ private void setState(ConnectionState state) {
+ _state = state;
+ }
+
+ public ConnectionState getState() {
+ return _state;
+ }
+
+ public void authenticate() {
+ final Sasl sasl = _connector.sasl();
+
+ while (true) {
+ try {
+ this._connector.process();
+ } catch (IOException ex) {
+ return;
+ }
+ final SaslState state = sasl.getState();
+ switch (state) {
+ case PN_SASL_CONF:
+ if (_authType == AuthenticatorType.SERVER) {
+ sasl.setMechanisms(new String[]{"ANONYMOUS"});
+ sasl.server();
+ }
+ break;
+ case PN_SASL_STEP:
+ if (_authType == AuthenticatorType.SERVER) {
+ final String[] mechs = sasl.getRemoteMechanisms();
+ if (mechs.length < 1) {
+ sasl.done(SaslOutcome.PN_SASL_AUTH);
+ break;
+ }
+
+ final String mech = mechs[0];
+ if (mech.equals("ANONYMOUS")) {
+ sasl.done(SaslOutcome.PN_SASL_OK);
+ } else {
+ sasl.done(SaslOutcome.PN_SASL_AUTH);
+ }
+ }
+ return;
+ case PN_SASL_PASS:
+ this.setState(ConnectionState.CONNECTED);
+ return;
+ case PN_SASL_FAIL:
+ this.setState(ConnectionState.FAILED);
+ return;
+ case PN_SASL_IDLE:
+
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ public AuthenticatorType getAuthType() {
+ return _authType;
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
new file mode 100644
index 0000000..4baffbf
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonClient.java
@@ -0,0 +1,224 @@
+package org.ovirt.vdsm.reactors;
+
+import java.nio.ByteBuffer;
+import java.util.Calendar;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Future;
+
+import javax.swing.event.EventListenerList;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.MessageFactory;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
+
+public final class ProtonClient implements ReactorClient {
+ private final ProtonReactor _reactor;
+ final private Session _ssn;
+
+ private Sender _sender;
+ private Receiver _receiver;
+
+ private final int _CREDIT = 10;
+ private final ConcurrentLinkedQueue<ByteBuffer> _outbox;
+ private final EventListenerList _eventListeners;
+ private final int _deliveryTimeoutSec;
+ private final MessageFactory _msgFactory;
+
+ public ProtonClient(ProtonReactor reactor, Session session) {
+ _ssn = session;
+ _sender = null;
+ _receiver = null;
+ _outbox = new ConcurrentLinkedQueue<>();
+ _eventListeners = new EventListenerList();
+ _deliveryTimeoutSec = 60 * 3;
+ _reactor = reactor;
+ _msgFactory = new MessageFactoryImpl();
+ }
+
+ @Override
+ public void addEventListener(EventListener el) {
+ synchronized (_eventListeners) {
+ _eventListeners.add(EventListener.class, el);
+ }
+ }
+
+ @Override
+ public void removeEventListener(EventListener el) {
+ synchronized (_eventListeners) {
+ _eventListeners.remove(EventListener.class, el);
+ }
+ }
+
+ private void emitOnMessageReceived(ByteBuffer message) {
+ synchronized (_eventListeners) {
+ final Class<EventListener> cls = EventListener.class;
+ final EventListener[] els = _eventListeners.getListeners(cls);
+ for (EventListener el : els) {
+ el.onMessageReceived(this, message);
+ }
+ }
+ }
+
+ @Override
+ public void sendMessage(ByteBuffer message) {
+ _outbox.add(message);
+ _reactor.wakeup();
+ }
+
+ public void addLink(Link link) {
+ assert (link.getSession().equals(_ssn));
+
+ if (link instanceof Sender) {
+ if (_sender != null) {
+ // already have a sender
+ link.close();
+ return;
+ }
+
+ _sender = (Sender) link;
+ } else {
+ assert (link instanceof Receiver);
+ if (_receiver != null) {
+ // already have a receiver
+ link.close();
+ return;
+ }
+
+ _receiver = (Receiver) link;
+ _receiver.flow(_CREDIT);
+ }
+ link.open();
+ }
+
+ private Message _popOutgoingMessage() {
+ final ByteBuffer data = _outbox.poll();
+ if (data == null) {
+ return null;
+ }
+
+ final Section body = new Data(Binary.create(data));
+ final Message msg = _msgFactory.createMessage();
+ msg.setBody(body);
+ msg.setAddress(_sender.getTarget().toString());
+ return msg;
+ }
+
+ public void queueDeliveries() {
+ if (_sender == null) {
+ final String uuid = UUID.randomUUID().toString();
+ _sender = _ssn.sender("Sender-" + uuid);
+ }
+
+ while (_sender.getCredit() > 0) {
+ final Message m = _popOutgoingMessage();
+ if (m == null) {
+ return;
+ }
+
+ final String uuid = UUID.randomUUID().toString();
+ final Delivery d = _sender
+ .delivery(("outgoing-" + uuid).getBytes());
+ d.setContext(m);
+ }
+ }
+
+ public void processDelivery(Delivery delivery) {
+ assert (_ssn.equals(delivery.getLink().getSession()));
+
+ if (delivery.isReadable()) {
+ _processIncomingDelivery(delivery);
+ } else {
+ assert (delivery.isWritable());
+ _processOutgoingDelivery(delivery);
+ }
+ }
+
+ private void _processOutgoingDelivery(Delivery delivery) {
+ final Sender link = (Sender) delivery.getLink();
+ assert (link.equals(_sender));
+
+ final Message msg = (Message) delivery.getContext();
+ // TBD: Buffer can be reused forever. Change in case of
+ // performance issues.
+ ByteBuffer buff;
+ int i = 1;
+ int written = 0;
+ do {
+ buff = ByteBuffer.allocate(i * 4096);
+ written = msg.encode(buff.array(), 0, buff.capacity());
+ i++;
+ } while (written == buff.capacity());
+
+ link.send(buff.array(), 0, written);
+ if (link.advance()) {
+ // Attach timeout to the delivery
+ final Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.SECOND, _deliveryTimeoutSec);
+ delivery.setContext(calendar);
+ }
+ }
+
+ private void _processIncomingDelivery(Delivery delivery) {
+ int total = 0;
+ int read = 0;
+ ByteBuffer buff = ByteBuffer.allocate(4096);
+
+ while (read >= 0) {
+ total += read;
+ if (total >= buff.capacity()) {
+ final ByteBuffer buff2 = ByteBuffer
+ .allocate(buff.capacity() * 2);
+ buff2.put(buff);
+ buff = buff2;
+ }
+ read = _receiver.recv(buff.array(), total, buff.capacity() - total);
+ }
+
+ final Message msg = _msgFactory.createMessage();
+ msg.decode(buff.array(), 0, total);
+
+ assert (msg.getBody() instanceof Data);
+ final Data body = (Data) msg.getBody();
+ final ByteBuffer bb = body.getValue().asByteBuffer();
+ delivery.settle();
+ emitOnMessageReceived(bb);
+ }
+
+ @Override
+ public Future<Void> close() {
+ final Session ssn = _ssn;
+ return _reactor.queueOperation(new Callable<Void>() {
+ @Override
+ public Void call() {
+ ssn.close();
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public boolean closed() {
+ return _ssn.getLocalState().equals(EndpointState.CLOSED);
+ }
+
+ public void removeLink(Link link) {
+ if (link.equals(_sender)) {
+ _sender = null;
+ } else {
+ assert (link.equals(_receiver));
+ _receiver = null;
+ }
+ link.close();
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
new file mode 100644
index 0000000..35896f4
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonListener.java
@@ -0,0 +1,42 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+import org.apache.qpid.proton.driver.Listener;
+
+public final class ProtonListener implements ReactorListener {
+ private final EventListener _eventListener;
+ private Listener<ProtonListener> _listener;
+ private final ProtonReactor _reactor;
+
+ public ProtonListener(ProtonReactor reactor, EventListener eventListener) {
+ _eventListener = eventListener;
+ _reactor = reactor;
+ }
+
+ public void setListener(Listener<ProtonListener> l) {
+ _listener = l;
+ }
+
+ public void accept(ReactorClient client) {
+ _eventListener.onAcccept(this, client);
+ }
+
+ @Override
+ public Future<Void> close() {
+ final Listener<ProtonListener> l = _listener;
+ return _reactor.queueOperation(new Callable<Void>() {
+ @Override
+ public Void call() {
+ try {
+ l.close();
+ } catch (IOException e) {
+ // already closed
+ }
+ return null;
+ }
+ });
+ }
+}
diff --git a/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
new file mode 100644
index 0000000..b5a38b4
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/main/java/org/ovirt/vdsm/reactors/ProtonReactor.java
@@ -0,0 +1,452 @@
+package org.ovirt.vdsm.reactors;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import org.apache.qpid.proton.driver.Connector;
+import org.apache.qpid.proton.driver.Driver;
+import org.apache.qpid.proton.driver.Listener;
+import org.apache.qpid.proton.driver.impl.DriverFactoryImpl;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.engine.impl.EngineFactoryImpl;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.AuthenticatorType;
+import org.ovirt.vdsm.reactors.ProtonAuthenticator.ConnectionState;
+import org.ovirt.vdsm.util.ChainedOperation;
+import org.ovirt.vdsm.util.ReactorScheduler;
+
+public final class ProtonReactor implements Reactor {
+
+ private final Driver _driver;
+ private final ReactorScheduler _scheduler;
+ private boolean _isRunning;
+ final Object _syncRoot = new Object();
+ final ProtonReactor reactor = this;
+ private EngineFactory _engineFactory;
+
+ public boolean isRunning() {
+ return _isRunning;
+ }
+
+ public ProtonReactor() throws IOException {
+ _engineFactory = new EngineFactoryImpl();
+ _driver = new DriverFactoryImpl().createDriver();
+ _isRunning = false;
+ _scheduler = new ReactorScheduler();
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ _driver.destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // Creates a listener, returns null if failed to bind or reactor is not
+ // running;
+ @Override
+ public Future<ReactorListener> createListener(final String host,
+ final int port,
+ final ReactorListener.EventListener eventListener) {
+
+ return queueOperation(new Callable<ReactorListener>() {
+ @Override
+ public ProtonListener call() {
+
+ final ProtonListener listener = new ProtonListener(reactor, eventListener);
+ final Listener<ProtonListener> l = _driver.createListener(host,
+ port, listener);
+
+ listener.setListener(l);
+
+ if (l == null) {
+ return null;
+ }
+
+ return listener;
+ }
+ });
+ }
+
+ @Override
+ public Future<ReactorClient> createClient(final String host, final int port) {
+ final Driver driver = _driver;
+ final EngineFactory engineFactory = _engineFactory;
+
+ return queueOperation(new ChainedOperation.Operation<ReactorClient>() {
+ final private int _INIT = 1;
+ final private int _AUTHENTICATE = 2;
+ final private int _DONE = 3;
+ private int _state;
+ final private Driver _driver;
+ final private ProtonReactor _reactor;
+ private Connector<ProtonAuthenticator> _connector;
+ private ProtonAuthenticator _auth;
+ private boolean _done;
+ private boolean _cancelled;
+ private ReactorClient _result;
+ private EngineFactory _engineFactory;
+
+ {
+ _driver = driver;
+ _reactor = reactor;
+ _state = _INIT;
+ _done = false;
+ _cancelled = false;
+ _engineFactory = engineFactory;
+ }
+
+ @Override
+ public void call(final boolean cancelled) {
+ switch (_state) {
+ case _INIT:
+ if (cancelled) {
+ _cancelled = true;
+ _done = true;
+ return;
+ }
+
+ _connector = this._driver.createConnector(host, port, null);
+
+ final Connection connection = engineFactory.createConnection();
+ _connector.setConnection(connection);
+ _auth = new ProtonAuthenticator(_connector,
+ AuthenticatorType.CLIENT);
+ _connector.setContext(_auth);
+ connection.open();
+ _state = _AUTHENTICATE;
+ case _AUTHENTICATE:
+ if (cancelled) {
+ _cancelled = true;
+ _close();
+ return;
+ }
+
+ switch (_auth.getState()) {
+ case AUTHENTICATING:
+ _auth.authenticate();
+ try {
+ _connector.process();
+ } catch (IOException e) {
+ // ignore
+ }
+ return;
+ case FAILED:
+ _close();
+ return;
+ case CONNECTED:
+ // Success !
+ break;
+ }
+
+ Session ssn = _connector.getConnection().session();
+ ssn.open();
+ _result = new ProtonClient(_reactor, ssn);
+ ssn.setContext(_result);
+ _done = true;
+ _state = _DONE;
+ }
+ }
+
+ private void _close() {
+ _connector.getConnection().close();
+ _connector.close();
+ _done = true;
+ _result = null;
+ }
+
+ @Override
+ public boolean isDone() {
+ return _done;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return _cancelled;
+ }
+
+ @Override
+ public ReactorClient getResult() {
+ return _result;
+ }
+ });
+ }
+
+ // Queues operation to be run in the serving loop.
+ public <T> Future<T> queueOperation(Callable<T> cb) {
+ final FutureTask<T> task = new FutureTask<>(cb);
+ _queueFuture(task);
+ return task;
+ }
+
+ public <T> Future<T> queueOperation(ChainedOperation.Operation<T> op) {
+ final ChainedOperation<T> task = new ChainedOperation<>(op);
+ _queueFuture(task);
+ return task;
+ }
+
+ private void _queueFuture(Future<?> op) {
+ synchronized (_scheduler) {
+ _scheduler.queueFuture(op);
+ wakeup();
+ }
+ }
+
+ private void _waitEvents() {
+ _driver.doWait(0);
+ }
+
+ public void wakeup() {
+ _driver.wakeup();
+ }
+
+ @Override
+ public void serve() {
+ synchronized (_syncRoot) {
+ _isRunning = true;
+ }
+
+ while (_isRunning) {
+ //_waitEvents();
+ synchronized (_scheduler) {
+ _scheduler.performPendingOperations();
+ }
+ _acceptConnectionRequests();
+ _processConnectors();
+ }
+ }
+
+ private void _processConnectors() {
+ for (Connector<?> connector = _driver.connector(); connector != null; connector = _driver
+ .connector()) {
+ if (connector.isClosed()) {
+ connector.destroy();
+ continue;
+ }
+
+ try {
+ connector.process();
+ } catch (IOException e) {
+ continue;
+ }
+
+ final Object ctx = connector.getContext();
+ assert (ctx instanceof ProtonAuthenticator);
+
+ if (ctx instanceof ProtonAuthenticator) {
+ final ProtonAuthenticator auth = (ProtonAuthenticator) ctx;
+ ConnectionState cs = auth.getState();
+ if (cs.equals(ConnectionState.AUTHENTICATING)) {
+ auth.authenticate();
+ cs = auth.getState();
+ }
+
+ if (cs.equals(ConnectionState.CONNECTED)) {
+ if (connector.getConnection() == null) {
+ connector.setConnection(_engineFactory.createConnection());
+ }
+ _processConnector(connector);
+ }
+ }
+
+ try {
+ connector.process();
+ } catch (IOException e) {
+ continue;
+ }
+ }
+ }
+
+ private void _processConnector(Connector<?> connector) {
+ _initConnection(connector);
+ _openPendingSessions(connector);
+ _openLinks(connector);
+ _queueOutgoingDeliveries(connector);
+ _processDeliveries(connector);
+ _cleanDeliveries(connector);
+ _cleanLinks(connector);
+ _cleanSessions(connector);
+ }
+
+ private void _cleanSessions(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .of(EndpointState.CLOSED);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn
+ .next(localState, remoteState)) {
+
+ ssn.close();
+ }
+ }
+
+ private void _cleanLinks(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .of(EndpointState.CLOSED);
+
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ final ProtonClient ssn = _getClient(link.getSession());
+ ssn.removeLink(link);
+ }
+ }
+
+ private void _cleanDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ if (link instanceof Receiver) {
+ // We settle all incoming deliveries upon receive
+ continue;
+ }
+
+ Delivery d;
+ final Calendar now = Calendar.getInstance();
+ for (Iterator<Delivery> iter = link.unsettled(); iter.hasNext();) {
+ d = iter.next();
+ Object ctx = d.getContext();
+ if (!(ctx instanceof Calendar)) {
+ // Has not been sent yet
+ continue;
+ }
+
+ final Calendar timeout = (Calendar) ctx;
+ boolean remoteClosed = link.getRemoteState().equals(
+ EndpointState.CLOSED);
+ boolean timedOut = now.after(timeout);
+ if (d.remotelySettled() || timedOut || remoteClosed) {
+ d.settle();
+ d.free();
+ }
+ }
+
+ }
+
+ }
+
+ private void _processDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ for (Delivery delivery = conn.getWorkHead(); delivery != null; delivery = delivery
+ .getWorkNext()) {
+
+ final ProtonClient client = _getClient(delivery.getLink()
+ .getSession());
+ client.processDelivery(delivery);
+ }
+ }
+
+ private void _queueOutgoingDeliveries(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.ACTIVE);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn = ssn
+ .next(localState, remoteState)) {
+
+ final ProtonClient client = _getClient(ssn);
+ client.queueDeliveries();
+ }
+ }
+
+ private void _openLinks(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.UNINITIALIZED);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+ for (Link link = conn.linkHead(localState, remoteState); link != null; link = link
+ .next(localState, remoteState)) {
+
+ // configure the link
+ link.setSource(link.getRemoteSource());
+ link.setTarget(link.getRemoteTarget());
+
+ final ProtonClient client = _getClient(link.getSession());
+ client.addLink(link);
+ }
+ }
+
+ private ProtonClient _getClient(Session ssn) {
+ return (ProtonClient) ssn.getContext();
+ }
+
+ private void _openPendingSessions(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ final EnumSet<EndpointState> localState = EnumSet
+ .of(EndpointState.UNINITIALIZED);
+ final EnumSet<EndpointState> remoteState = EnumSet
+ .allOf(EndpointState.class);
+
+ for (Session ssn = conn.sessionHead(localState, remoteState); ssn != null; ssn = ssn
+ .next(localState, remoteState)) {
+
+ final ProtonClient client = new ProtonClient(this, ssn);
+ ssn.setContext(client);
+ final Object ctx = connector.getContext();
+ assert (ctx instanceof ProtonAuthenticator);
+ ProtonAuthenticator auth = (ProtonAuthenticator) ctx;
+ if (auth.getAuthType() == AuthenticatorType.SERVER) {
+ ssn.open();
+ final ProtonListener l = (ProtonListener) ctx;
+ l.accept(client);
+ } else {
+ ssn.close();
+ }
+ }
+ }
+
+ private void _initConnection(Connector<?> connector) {
+ final Connection conn = connector.getConnection();
+ if (conn.getLocalState().equals(EndpointState.UNINITIALIZED)) {
+ conn.open();
+ }
+ }
+
+ private void _acceptConnectionRequests() {
+ for (final Listener<?> l : _driver.listeners()) {
+
+ @SuppressWarnings("unchecked")
+ final Connector<ProtonAuthenticator> connector = (Connector<ProtonAuthenticator>) l
+ .accept();
+ if (connector == null) {
+ continue;
+ }
+ connector.setContext(new ProtonAuthenticator(connector,
+ AuthenticatorType.SERVER));
+ }
+ }
+
+ public void stop() {
+ synchronized (_syncRoot) {
+ _isRunning = false;
+ }
+
+ wakeup();
+ }
+}
\ No newline at end of file
diff --git a/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
new file mode 100644
index 0000000..46d9cc3
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/AmqpReactorTestHelper.java
@@ -0,0 +1,18 @@
+package org.ovirt.vdsm.jsonrpc;
+
+import java.io.IOException;
+import org.ovirt.vdsm.reactors.ProtonReactor;
+import org.ovirt.vdsm.reactors.Reactor;
+
+public class AmqpReactorTestHelper implements ReactorTestHelper {
+ @Override
+ public Reactor createReactor() throws IOException {
+ return new ProtonReactor();
+ }
+
+ @Override
+ public String getUriScheme() {
+ return "amqp";
+ }
+
+}
diff --git a/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
new file mode 100644
index 0000000..9e0c24c
--- /dev/null
+++ b/client/java/vdsm-json-rpc/src/test/java/org/ovirt/vdsm/jsonrpc/TestJsonRpcClientAMQP.java
@@ -0,0 +1,10 @@
+package org.ovirt.vdsm.jsonrpc;
+
+public class TestJsonRpcClientAMQP extends TestJsonRpcClient {
+
+ @Override
+ protected ReactorTestHelper getHelper() {
+ return new AmqpReactorTestHelper();
+ }
+
+}
--
To view, visit http://gerrit.ovirt.org/15428
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I94c52e118cb63d7df84b89a9b93da7b9e477be91
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
8 years, 8 months
Change in vdsm[master]: vdsm: expose release call to engine and via vdsClient
by Martin Polednik
Martin Polednik has uploaded a new change for review.
Change subject: vdsm: expose release call to engine and via vdsClient
......................................................................
vdsm: expose release call to engine and via vdsClient
Release would, in ideal world, always be called when VM dies.
Exposing this verbs gives users tool to force release if series
of events lead to situation that should never occur(tm).
Change-Id: I920ae8b5c82134f09a12e56a529fa3d30fd7ab53
Signed-off-by: Martin Polednik <mpolednik(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/rpc/BindingXMLRPC.py
3 files changed, 17 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/94/32394/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index 783afa6..85d00cd 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -521,6 +521,10 @@
def do_getAllVmStats(self, args):
return self.ExecAndExit(self.s.getAllVmStats())
+ def hostdevRelease(self, args):
+ device_name = args[0]
+ return self.ExecAndExit(self.s.hostdevRelease(device_name))
+
def desktopLogin(self, args):
vmId, domain, user, password = tuple(args[:4])
if len(args) > 4:
@@ -2149,6 +2153,10 @@
('',
'Get Statistics info for all existing VMs'
)),
+ 'hostdevRelease': (serv.do_hostdevRelease,
+ ('<deviceName>',
+ 'Release specified device from any VMs on the host'
+ )),
'getVGList': (serv.getVGList,
('storageType',
'List of all VGs.'
diff --git a/vdsm/API.py b/vdsm/API.py
index 8da6030..6269d72 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1296,6 +1296,10 @@
devices = hostdev.list_by_caps(self._cif.vmContainer, caps)
return {'status': doneCode, 'deviceList': devices}
+ def hostdevRelease(self, device_name):
+ hostdev.release(device_name)
+ return {'status': doneCode}
+
def getStats(self):
"""
Report host statistics.
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index 4c1ef20..bdd0886 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -487,6 +487,10 @@
api = API.Global()
return api.hostdevListByCaps(caps)
+ def hostdevRelease(self, device_name):
+ api = API.Global()
+ return api.hostdevRelease(device_name)
+
def vmGetIoTunePolicy(self, vmId):
vm = API.VM(vmId)
return vm.getIoTunePolicy()
@@ -1004,6 +1008,7 @@
(self.vmGetStats, 'getVmStats'),
(self.getAllVmStats, 'getAllVmStats'),
(self.hostdevListByCaps, 'hostdevListByCaps'),
+ (self.hostdevRelease, 'hostdevRelease'),
(self.vmMigrationCreate, 'migrationCreate'),
(self.vmDesktopLogin, 'desktopLogin'),
(self.vmDesktopLogoff, 'desktopLogoff'),
--
To view, visit http://gerrit.ovirt.org/32394
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I920ae8b5c82134f09a12e56a529fa3d30fd7ab53
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpolednik(a)redhat.com>
8 years, 9 months