Nir Soffer has uploaded a new change for review.
Change subject: build: Disable tests during build
......................................................................
build: Disable tests during build
Tests are needed for development, not for building a package. This
allows us to use latest and greatest development tools, which are not
available in brew or koji.
Since we install nose using pip, remove the build requires - we don't
need now nose to build rpms.
Change-Id: I9e3589c365166f934f117b53c65cea4b90db3516
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm.spec.in
1 file changed, 0 insertions(+), 6 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/66/63966/1
diff --git a/vdsm.spec.in b/vdsm.spec.in
index f234b09..c7f6dde 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -62,7 +62,6 @@
BuildRequires: python2-devel
BuildRequires: python-mock
BuildRequires: python-netaddr
-BuildRequires: python-nose
BuildRequires: python-six >= 1.9.0
BuildRequires: rpm-build
@@ -95,10 +94,8 @@
%if 0%{?with_python3}
%if 0%{?rhel}
-BuildRequires: python34-nose
BuildRequires: python34-six
%else # fedora
-BuildRequires: python3-nose
BuildRequires: python3-six
BuildRequires: python3-netaddr
BuildRequires: python3-yaml
@@ -781,9 +778,6 @@
# Install the libvirt hook for cleaning up the XML
install -Dm 0755 vdsm/virt/libvirt-hook.sh \
%{buildroot}%{_sysconfdir}/libvirt/hooks/qemu
-
-%check
-make tests
%pre
# Force standard locale behavior (English)
--
To view, visit https://gerrit.ovirt.org/63966
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9e3589c365166f934f117b53c65cea4b90db3516
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: utils: Wait for terminated process
......................................................................
utils: Wait for terminated process
utils.terminating was not waiting for a terminated process, passing the
process to zombiereaper. This behavior may be disastrous storage and
mostly unwanted for other code.
When we run a child process touching shared storage, we must wait for
the child process. If we kill the child process without waiting, engine
may start the same operation on another host, while the original child
process is still running, possibly in interruptible state, trying to
write to storage.
To avoid this issue, we always invoke wait() after killing the process.
Special code that do not want to wait for the child process should not
use this context manager.
Change-Id: Ida04e2c7ba092efdc2927ed9f460b0098ba2ad94
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M lib/vdsm/utils.py
M tests/utilsTests.py
2 files changed, 7 insertions(+), 34 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/24/65324/1
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index a428c8e..e5c28b8 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -738,8 +738,7 @@
if proc.poll() is None:
logging.debug('Terminating process pid=%d' % proc.pid)
proc.kill()
- if proc.poll() is None:
- zombiereaper.autoReapPID(proc.pid)
+ proc.wait()
except Exception:
logging.exception('Failed to kill process %d' % proc.pid)
diff --git a/tests/utilsTests.py b/tests/utilsTests.py
index 388a65d..6ff85d4 100644
--- a/tests/utilsTests.py
+++ b/tests/utilsTests.py
@@ -42,9 +42,8 @@
from vdsm import cmdutils
from vdsm import commands
from vdsm import panic
-from vdsm.common import zombiereaper
-from monkeypatch import MonkeyPatch, MonkeyPatchScope
+from monkeypatch import MonkeyPatch
from vmTestsData import VM_STATUS_DUMP
from monkeypatch import Patch
from testlib import forked, online_cpus, namedTemporaryDir
@@ -83,22 +82,11 @@
self.patch.revert()
-def wait_for_removal(path, timeout, wait=0.1):
- deadline = utils.monotonic_time() + timeout
- while True:
- if not os.path.exists(path):
- return True
- if utils.monotonic_time() > deadline:
- return False
- time.sleep(wait)
-
-
class TerminatingTests(TestCaseBase):
def setUp(self):
self.proc = commands.execCmd([EXT_SLEEP, "2"], sync=False)
self.kill_proc = self.proc.kill
- self.reaped = set()
def tearDown(self):
if self.proc.poll() is None:
@@ -108,8 +96,7 @@
def test_terminating(self):
with utils.terminating(self.proc):
self.assertIsNone(self.proc.poll())
- proc_path = "/proc/%d" % self.proc.pid
- self.assertTrue(wait_for_removal(proc_path, timeout=1))
+ self.assertEqual(self.proc.returncode, -signal.SIGKILL)
def test_terminating_with_kill_exception(self):
class FakeKillError(Exception):
@@ -118,24 +105,11 @@
def fake_kill():
raise FakeKillError("fake kill exception")
- with MonkeyPatchScope([(zombiereaper,
- 'autoReapPID',
- self.reaped.add
- )]):
- self.proc.kill = fake_kill
- with utils.terminating(self.proc):
- self.assertIsNone(self.proc.poll())
- self.assertTrue(self.proc.pid not in self.reaped)
+ self.proc.kill = fake_kill
+ with utils.terminating(self.proc):
+ self.assertIsNone(self.proc.poll())
- def test_terminating_with_infected_kill(self):
- with MonkeyPatchScope([(zombiereaper,
- 'autoReapPID',
- self.reaped.add
- )]):
- self.proc.kill = lambda: None
- with utils.terminating(self.proc):
- self.assertIsNone(self.proc.poll())
- self.assertTrue(self.proc.pid in self.reaped)
+ self.assertIsNone(self.proc.returncode)
class RetryTests(TestCaseBase):
--
To view, visit https://gerrit.ovirt.org/65324
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ida04e2c7ba092efdc2927ed9f460b0098ba2ad94
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: readme: Fix build status url
......................................................................
readme: Fix build status url
Previously we pointed to Nir's private fork, now that oVirt's github is
triggering builds we should point to the correct builds.
Change-Id: If40bda074383ffa1c4626bb7e68a6035cf7039e3
Signed-off-by: Nir Soffer <nirsof(a)gmail.com>
---
M README.md
1 file changed, 2 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/04/65904/1
diff --git a/README.md b/README.md
index e253d3a..d3ba4c8 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Vdsm: Virtual Desktop Server Manager
-[![Build Status](https://travis-ci.org/nirs/vdsm.svg?branch=master)]
-(https://travis-ci.org/nirs/vdsm)
+[![Build Status](https://travis-ci.org/oVirt/vdsm.svg?branch=master)]
+(https://travis-ci.org/oVirt/vdsm)
The Vdsm service exposes an API for managing virtualization
hosts running the KVM hypervisor technology. Vdsm manages and monitors
--
To view, visit https://gerrit.ovirt.org/65904
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If40bda074383ffa1c4626bb7e68a6035cf7039e3
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Milan Zamazal has uploaded a new change for review.
Change subject: virt: Make DomainDescriptor use XML helpers
......................................................................
virt: Make DomainDescriptor use XML helpers
We are going to stop using xml.dom.minidom and to use xml.etree instead.
XML processing is currently spread across several places and we use both
minidom and etree, so we must be careful with the conversion. The
overall strategy is as follows:
1. Create XML helpers abstracting common XML operations.
2. Use the helpers everywhere where minidom is currently used. Avoid
using minidom anywhere outside the XML helpers.
3. Switch from minidom to etree in the XML helpers.
We avoid using XML directly in many places as a side effect. It is
debatable whether it is a good or bad thing. If we decide it is a good
thing, we may want to replace direct etree base XML processing with the
helpers as well in a followup patch series. If we decide it is a bad
thing, we can unfold the helpers in a followup patch series (note we
need the helpers as an intermediate step and can't avoid them from the
beginning). Keeping status quo after this series is also an option.
There's also duplicate XML code and processing present in some places,
especially in core devices. We keep it duplicated as it is in this
series, in order not to mix etree conversion with refactoring. Device
XML processing refactoring is planned in a followup patch series.
This patch implements the first step of the whole process. It converts
DomainDescriptor class from minidom to XML helpers. The reason for this
start is that DomainDescriptor class is simple while it requires most of
the needed XML helpers. So we can start with a small change of the
existent code while becoming equipped with a nice set XML helpers for
the following, perhaps more complicated, patches.
Change-Id: Ib169735936d19171ff8b8d127666d7258c308f34
Signed-off-by: Milan Zamazal <mzamazal(a)redhat.com>
---
M tests/vmXmlTests.py
M vdsm/virt/domain_descriptor.py
M vdsm/virt/vm.py
M vdsm/virt/vmxml.py
4 files changed, 216 insertions(+), 23 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/69/55769/9
diff --git a/tests/vmXmlTests.py b/tests/vmXmlTests.py
index c3e8f05..3051c63 100644
--- a/tests/vmXmlTests.py
+++ b/tests/vmXmlTests.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
#
# Copyright 2014, 2016 Red Hat, Inc.
#
@@ -26,7 +27,7 @@
from virt import vmxml
from testlib import VdsmTestCase as TestCaseBase
-from testlib import permutations, expandPermutations
+from testlib import XMLTestCase, permutations, expandPermutations
import vmfakelib as fake
@@ -59,6 +60,58 @@
@expandPermutations
+class TestVmXmlHelpers(XMLTestCase):
+
+ _XML = u'''<?xml version="1.0" ?>
+ <topelement>
+ <hello lang="english">hello</hello>
+ <hello cyrillic="yes" lang="русский">здра́вствуйте</hello>
+ <bye>good bye<hello lang="čeština">dobrý den</hello></bye>
+ <empty/>
+ </topelement>
+ '''
+
+ def setUp(self):
+ self._dom = vmxml.parse_xml(self._XML)
+
+ def test_import_export(self):
+ xml = vmxml.export_xml(self._dom)
+ self.assertXMLEqual(xml, self._XML)
+
+ @permutations([[None, 'topelement', 1],
+ ['topelement', 'topelement', 1],
+ [None, 'hello', 3],
+ ['topelement', 'bye', 1],
+ [None, 'none', 0]])
+ def test_find_all(self, start_tag, tag, number):
+ dom = self._dom
+ if start_tag is not None:
+ dom = vmxml.find_first(self._dom, 'topelement')
+ elements = vmxml.find_all(dom, tag)
+ matches = [vmxml.tag(e) == tag for e in elements]
+ self.assertTrue(all(matches))
+ self.assertEqual(len(matches), number)
+
+ def test_find_first_not_found(self):
+ self.assertRaises(vmxml.NotFound, vmxml.find_first, self._dom, 'none')
+
+ @permutations([['hello', 'lang', 'english'],
+ ['hello', 'none', ''],
+ ['none', 'lang', ''],
+ ])
+ def test_find_attr(self, tag, attribute, result):
+ value = vmxml.find_attr(self._dom, tag, attribute)
+ self.assertEqual(value, result)
+
+ @permutations([['hello', 'hello'],
+ ['empty', '']])
+ def test_text(self, tag, result):
+ element = vmxml.find_first(self._dom, tag)
+ text = vmxml.text(element)
+ self.assertEqual(text, result)
+
+
+@expandPermutations
class TestDomainDescriptor(VmXmlTestCase):
@permutations([[cpuarch.X86_64], [cpuarch.PPC64]])
diff --git a/vdsm/virt/domain_descriptor.py b/vdsm/virt/domain_descriptor.py
index 2c2057f..c6f84cd 100644
--- a/vdsm/virt/domain_descriptor.py
+++ b/vdsm/virt/domain_descriptor.py
@@ -17,16 +17,16 @@
#
# Refer to the README and COPYING files for full details of the license
#
-import xml.dom.minidom
+from . import vmxml
class DomainDescriptor(object):
def __init__(self, xmlStr):
self._xml = xmlStr
- self._dom = xml.dom.minidom.parseString(xmlStr)
- self._devices = self._first_element_by_tag_name('devices')
- self._devices_hash = hash(self._devices.toxml()
+ self._dom = vmxml.parse_xml(xmlStr)
+ self._devices = vmxml.find_first(self._dom, 'devices', None)
+ self._devices_hash = hash(vmxml.export_xml(self._devices)
if self._devices is not None else '')
@classmethod
@@ -42,31 +42,22 @@
return self._devices
def get_device_elements(self, tagName):
- return self._devices.getElementsByTagName(tagName)
+ return vmxml.find_all(self._devices, tagName)
@property
def devices_hash(self):
return self._devices_hash
def all_channels(self):
- for channel in self.get_device_elements('channel'):
- try:
- name = channel.getElementsByTagName('target')[0].\
- getAttribute('name')
- path = channel.getElementsByTagName('source')[0].\
- getAttribute('path')
- except IndexError:
- continue
- else:
+ for channel in vmxml.find_all(self._devices, 'channel'):
+ name = vmxml.find_attr(channel, 'target', 'name')
+ path = vmxml.find_attr(channel, 'source', 'path')
+ if name and path:
yield name, path
-
- def _first_element_by_tag_name(self, tagName):
- elements = self._dom.childNodes[0].getElementsByTagName(tagName)
- return elements[0] if elements else None
def get_memory_size(self):
"""
Return the vm memory from xml in MiB
"""
- memory = self._first_element_by_tag_name("memory")
- return int(memory.firstChild.nodeValue) // 1024 if memory else None
+ memory = vmxml.find_first(self._dom, "memory")
+ return (int(vmxml.text(memory)) // 1024 if memory else None)
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index e24a90a..2b9e03e 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -3761,8 +3761,8 @@
use updateDevice to select the device.
"""
try:
- graphics = self._domain.get_device_elements('graphics')[0]
- except IndexError:
+ graphics = next(self._domain.get_device_elements('graphics'))
+ except StopIteration:
return response.error('ticketErr',
'no graphics devices configured')
return self._setTicketForGraphicDev(
diff --git a/vdsm/virt/vmxml.py b/vdsm/virt/vmxml.py
index b868a25..02927d9 100644
--- a/vdsm/virt/vmxml.py
+++ b/vdsm/virt/vmxml.py
@@ -33,6 +33,155 @@
_BOOT_MENU_TIMEOUT = 10000 # milliseconds
+_UNSPECIFIED = object()
+
+
+class NotFound(Exception):
+ """
+ Raised when vmxml helpers can't find some requested entity.
+ """
+ pass
+
+
+def parse_xml(xml_string):
+ """
+ Parse given XML string to DOM element and return the element.
+
+ :param xml_string: XML string to parse
+ :type xml_string: str
+ :returns: DOM element created by parsing `xml_string`
+ :rtype: DOM element
+
+ """
+ return xml.dom.minidom.parseString(xml_string)
+
+
+def export_xml(element):
+ """
+ Export given DOM element to XML string.
+
+ :param element: DOM element to export
+ :type element: DOM element
+ :returns: XML corresponding to `element` content
+ :rtype: basestring
+
+ """
+ return element.toxml(encoding='UTF-8')
+
+
+def find_all(element, tag_):
+ """
+ Return an iterator over all DOM elements with given `tag`.
+
+ `element` may is included in the result if it is of `tag`.
+
+ :param element: DOM element to be searched for given `tag`
+ :type element: DOM element
+ :param tag: tag to look for
+ :type tag: basestring
+ :returns: all elements with given `tag`
+ :rtype: sequence of DOM elements
+
+ """
+ if isinstance(element, xml.dom.minidom.Element) and \
+ tag(element) == tag_:
+ yield element
+ for elt in element.getElementsByTagName(tag_):
+ yield elt
+
+
+def find_first(element, tag, default=_UNSPECIFIED):
+ """
+ Find the first DOM element with the given tag.
+
+ :param element: DOM element to be searched for given `tag`
+ :type element: DOM element
+ :param tag: tag to look for
+ :type tag: basestring
+ :param default: any object to return when no element with `tag` is found;
+ if not given then `NotFound` is raised in such a case
+ :returns: the matching element or default
+ :raises: NotFound -- when no element with `tag` is found and `default` is
+ not given
+
+ """
+ try:
+ return next(find_all(element, tag))
+ except StopIteration:
+ if default is _UNSPECIFIED:
+ raise NotFound((element, tag,))
+ else:
+ return default
+
+
+def find_attr(element, tag, attribute):
+ """
+ Find `attribute` value of the first DOM element with `tag`.
+
+ :param element: DOM element to be searched for given `tag`
+ :type element: DOM element
+ :param tag: tag to look for
+ :type tag: basestring
+ :param attribute: attribute name to look for
+ :type attribute: basestring
+ :returns: the attribute value or an empty string if no element with given
+ tag is found or the found element doesn't contain `attribute`
+ :rtype: basestring
+
+ """
+ try:
+ subelement = find_first(element, tag)
+ except NotFound:
+ return ''
+ return attr(subelement, attribute)
+
+
+def tag(element):
+ """
+ Return tag of the given DOM element.
+
+ :param element: element to get the tag of
+ :type element: DOM element
+ :returns: tag of the element
+ :rtype: basestring
+
+ """
+ return element.tagName
+
+
+def attr(element, attribute):
+ """
+ Return attribute values of `element`.
+
+ :param element: the element to look the attributes in
+ :type element: DOM element
+ :param attribute: attribute name to look for
+ :type attribute: basestring
+ :returns: the corresponding attribute value or empty string (if no element
+ with `tag` or exists or `attribute` is not present)
+ :rtype: basestring
+
+ """
+ # Minidom returns unicodes, except for empty strings.
+ return element.getAttribute(attribute)
+
+
+def text(element):
+ """
+ Return text of the given DOM element.
+
+ :param element: element to get the text from
+ :type element: DOM element
+ :returns: text of the element (empty string if it the element doesn't
+ contain any text)
+ :rtype: basestring
+
+ """
+ child_node = element.firstChild
+ if child_node is None:
+ return ''
+ return child_node.nodeValue
+
def has_channel(domXML, name):
domObj = etree.fromstring(domXML)
--
To view, visit https://gerrit.ovirt.org/55769
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib169735936d19171ff8b8d127666d7258c308f34
Gerrit-PatchSet: 9
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Milan Zamazal <mzamazal(a)redhat.com>
Gerrit-Reviewer: Francesco Romani <fromani(a)redhat.com>
Gerrit-Reviewer: Martin Polednik <mpolednik(a)redhat.com>
Gerrit-Reviewer: Milan Zamazal <mzamazal(a)redhat.com>
Gerrit-Reviewer: Nir Soffer <nsoffer(a)redhat.com>
Gerrit-Reviewer: gerrit-hooks <automation(a)ovirt.org>