Change in vdsm[master]: netinfo: report DHCP on devices only when configured (like f...
by osvoboda@redhat.com
Ondřej Svoboda has uploaded a new change for review.
Change subject: netinfo: report DHCP on devices only when configured (like for networks)
......................................................................
netinfo: report DHCP on devices only when configured (like for networks)
As reporting of DHCP relies on reading of dhclient lease files, it is not
reliable when a network is reconfigured to static addressing: unused leases
indicate dhclient presence hours after it has been stopped (expiration time
is usually in hours or days).
The false indication has already been fixed for networks, now even their
respective devices adhere to configuration to stop false positives.
A year and half ago it was suggested first to rely on cmdlines on running
dhclients (where network device is the last parameter for all network
configurators). This fix is just a hacky, though little bandaid for the 3.6
release. A proper fix will be considered for the 4.0 branch.
testSetupNetworksAddDelDhcp now checks that DHCP stops being reported
on a network device, in addition to its network.
Change-Id: I2b17b0c66e3a0fc8c5ada62d166d9a2b92513033
Bug-Url: https://bugzilla.redhat.com/1184497
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M lib/vdsm/netinfo.py
M tests/functional/networkTests.py
2 files changed, 52 insertions(+), 33 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/04/45504/1
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 9a12177..9cb39c3 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -510,6 +510,14 @@
return data
+def _netinfo_by_device(networks):
+ netinfo_by_device = {}
+ for net_attrs in networks.itervalues():
+ device = net_attrs['iface']
+ netinfo_by_device[device] = net_attrs
+ return netinfo_by_device
+
+
def _bridgeinfo(link):
return {'ports': ports(link.name),
'stp': bridge_stp_state(link.name),
@@ -548,7 +556,7 @@
return {'iface': link.device, 'vlanid': link.vlanid}
-def _devinfo(link, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces):
+def _devinfo(link, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces, net_attrs):
gateway = _get_gateway(routes, link.name)
ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
link.name, ipaddrs, gateway)
@@ -558,8 +566,9 @@
'ipv6addrs': ipv6addrs,
'gateway': gateway,
'ipv6gateway': _get_gateway(routes, link.name, family=6),
- 'dhcpv4': link.name in dhcpv4_ifaces,
- 'dhcpv6': link.name in dhcpv6_ifaces,
+ 'dhcpv4': _dhcp_used(link.name, dhcpv4_ifaces, net_attrs),
+ 'dhcpv6': _dhcp_used(link.name, dhcpv6_ifaces, net_attrs,
+ family=6),
'mtu': str(link.mtu),
'netmask': ipv4netmask}
if 'BOOTPROTO' not in info['cfg']:
@@ -754,6 +763,8 @@
else:
d['networks'] = vdsmnets
+ netinfo_by_device = _netinfo_by_device(d['networks'])
+
for dev in (link for link in getLinks() if not link.isHidden()):
if dev.isBRIDGE():
devinfo = d['bridges'][dev.name] = _bridgeinfo(dev)
@@ -766,7 +777,8 @@
else:
continue
devinfo.update(_devinfo(dev, routes, ipaddrs, dhcpv4_ifaces,
- dhcpv6_ifaces))
+ dhcpv6_ifaces,
+ netinfo_by_device.get(dev.name, None)))
if dev.isBOND():
_bondOptsCompat(devinfo)
_bondCustomOpts(dev, devinfo, running_config)
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 1873222..41fd6d0 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -2043,6 +2043,37 @@
@cleanupNet
@RequireVethMod
def testSetupNetworksAddDelDhcp(self, bridged, families):
+ def _assert_applied(network_name, requested, reported):
+ self.assertNetworkExists(network_name)
+ reported_network = reported.networks[network_name]
+
+ if requested['bridged']:
+ self.assertEqual(reported_network['cfg']['BOOTPROTO'],
+ requested['bootproto'])
+ reported_devices = reported.bridges
+ device_name = network_name
+ else:
+ reported_devices = reported.nics
+ device_name = requested['nic']
+ self.assertIn(device_name, reported_devices)
+ reported_device = reported_devices[device_name]
+
+ requested_dhcpv4 = requested['bootproto'] == 'dhcp'
+ self.assertEqual(reported_network['dhcpv4'], requested_dhcpv4)
+ self.assertEqual(reported_network['dhcpv6'], requested['dhcpv6'])
+
+ self.assertEqual(reported_device['cfg']['BOOTPROTO'],
+ requested['bootproto'])
+ self.assertEqual(reported_device['dhcpv4'], requested_dhcpv4)
+ self.assertEqual(reported_device['dhcpv6'], requested['dhcpv6'])
+
+ if requested_dhcpv4:
+ self.assertEqual(reported_network['gateway'], IP_GATEWAY)
+ # TODO: source routing not ready for IPv6
+ ip_addr = reported_network['addr']
+ self.assertSourceRoutingConfiguration(device_name,
+ ip_addr)
+
with veth.pair() as (left, right):
veth.setIP(left, IP_ADDRESS, IP_CIDR)
veth.setIP(left, IPv6_ADDRESS, IPv6_CIDR, 6)
@@ -2058,42 +2089,18 @@
try:
status, msg = self.setupNetworks(network, {}, NOCHK)
self.assertEqual(status, SUCCESS, msg)
- self.assertNetworkExists(NETWORK_NAME)
- test_net = self.vdsm_net.netinfo.networks[NETWORK_NAME]
- self.assertEqual(test_net['dhcpv4'], dhcpv4)
- self.assertEqual(test_net['dhcpv6'], dhcpv6)
-
- if bridged:
- self.assertEqual(test_net['cfg']['BOOTPROTO'],
- bootproto)
- devs = self.vdsm_net.netinfo.bridges
- device_name = NETWORK_NAME
- else:
- devs = self.vdsm_net.netinfo.nics
- device_name = right
-
- self.assertIn(device_name, devs)
- net_attrs = devs[device_name]
- self.assertEqual(net_attrs['cfg']['BOOTPROTO'], bootproto)
- self.assertEqual(net_attrs['dhcpv4'], dhcpv4)
- self.assertEqual(net_attrs['dhcpv6'], dhcpv6)
-
- if dhcpv4:
- self.assertEqual(test_net['gateway'], IP_GATEWAY)
- # TODO: source routing not ready for IPv6
- ip_addr = test_net['addr']
- self.assertSourceRoutingConfiguration(device_name,
- ip_addr)
+ _assert_applied(NETWORK_NAME, network,
+ self.vdsm_net.netinfo)
# Do not report DHCP from (typically still valid) leases
network[NETWORK_NAME]['bootproto'] = 'none'
network[NETWORK_NAME]['dhcpv6'] = False
status, msg = self.setupNetworks(network, {}, NOCHK)
self.assertEqual(status, SUCCESS, msg)
- test_net = self.vdsm_net.netinfo.networks[NETWORK_NAME]
- self.assertEqual(test_net['dhcpv4'], False)
- self.assertEqual(test_net['dhcpv6'], False)
+
+ _assert_applied(NETWORK_NAME, network,
+ self.vdsm_net.netinfo)
network = {NETWORK_NAME: {'remove': True}}
status, msg = self.setupNetworks(network, {}, NOCHK)
--
To view, visit https://gerrit.ovirt.org/45504
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2b17b0c66e3a0fc8c5ada62d166d9a2b92513033
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: network: ifcfg: synchronous ifup
by phoracek@redhat.com
Petr Horáček has uploaded a new change for review.
Change subject: network: ifcfg: synchronous ifup
......................................................................
network: ifcfg: synchronous ifup
Change-Id: I0c90a556f5fc52c1b8e675986ac39b6032ca0197
Signed-off-by: Petr Horáček <phoracek(a)redhat.com>
---
M vdsm/network/configurators/ifcfg.py
1 file changed, 63 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/66/37366/1
diff --git a/vdsm/network/configurators/ifcfg.py b/vdsm/network/configurators/ifcfg.py
index 65e02b5..785c7f2 100644
--- a/vdsm/network/configurators/ifcfg.py
+++ b/vdsm/network/configurators/ifcfg.py
@@ -18,6 +18,7 @@
#
from __future__ import absolute_import
+from contextlib import contextmanager
import glob
import logging
import os
@@ -36,13 +37,14 @@
from vdsm import netinfo
from vdsm import utils
from vdsm.netconfpersistence import RunningConfig
+from vdsm.netlink import monitor
if utils.isOvirtNode():
from ovirt.node.utils import fs as node_fs
from . import Configurator, dhclient, getEthtoolOpts, libvirt
from ..errors import ConfigNetworkError, ERR_FAILED_IFUP
-from ..models import Nic, Bridge, IpConfig
+from ..models import Nic, Bridge, IpConfig, NetDevice
from ..sourceroute import StaticSourceRoute, DynamicSourceRoute
import dsaversion # TODO: Make parent package import when vdsm is a package
@@ -89,13 +91,13 @@
if bridge.port:
bridge.port.configure(**opts)
self._addSourceRoute(bridge)
- ifup(bridge.name, bridge.ipConfig.async)
+ ifup(bridge, bridge.ipConfig.async)
def configureVlan(self, vlan, **opts):
self.configApplier.addVlan(vlan, **opts)
vlan.device.configure(**opts)
self._addSourceRoute(vlan)
- ifup(vlan.name, vlan.ipConfig.async)
+ ifup(vlan, vlan.ipConfig.async)
def configureBond(self, bond, **opts):
self.configApplier.addBonding(bond, **opts)
@@ -105,7 +107,7 @@
for slave in bond.slaves:
slave.configure(**opts)
self._addSourceRoute(bond)
- ifup(bond.name, bond.ipConfig.async)
+ ifup(bond, bond.ipConfig.async)
if self.unifiedPersistence:
self.runningConfig.setBonding(
bond.name, {'options': bond.options,
@@ -142,11 +144,11 @@
if slave.name in nicsToAdd:
ifdown(slave.name) # nics must be down to join a bond
self.configApplier.addNic(slave)
- ifup(slave.name)
+ ifup(slave)
if bondIfcfgWritten:
ifdown(bond.name)
- ifup(bond.name)
+ ifup(bond)
if self.unifiedPersistence:
self.runningConfig.setBonding(
bond.name, {'options': bond.options,
@@ -158,7 +160,7 @@
if nic.bond is None:
if not netinfo.isVlanned(nic.name):
ifdown(nic.name)
- ifup(nic.name, nic.ipConfig.async)
+ ifup(nic, nic.ipConfig.async)
def removeBridge(self, bridge):
DynamicSourceRoute.addInterfaceTracking(bridge)
@@ -216,7 +218,7 @@
if to_be_removed:
self.configApplier.removeNic(nic.name)
if nic.name in netinfo.nics():
- ifup(nic.name)
+ ifup(nic)
else:
logging.warning('host interface %s missing', nic.name)
else:
@@ -804,7 +806,8 @@
def ifup(iface, async=False):
- "Bring up an interface"
+ """Bring up an interface. Parameter iface could be iface's name or
+ a NetDevice object."""
def _ifup(netIf):
rc, out, err = utils.execCmd([constants.EXT_IFUP, netIf], raw=False)
@@ -815,17 +818,68 @@
return rc, out, err
if async:
+ iface = iface.name if isinstance(iface, NetDevice) else iface
+
# wait for dhcp in another thread,
# so vdsm won't get stuck (BZ#498940)
t = threading.Thread(target=_ifup, name='ifup-waiting-on-dhcp',
args=(iface,))
t.daemon = True
t.start()
+ elif isinstance(iface, NetDevice) and iface.master is None:
+ # TEMP NOTE: ip could be None or IpConfig(IPv4(None,...),
+ # IPv6(None,...)...)
+ if iface.ip and (iface.ip.ipv4.address or iface.ip.ipv6.address):
+ # TEMP NOTE: we have to call setupNetworks with IPv6 addr, prefix
+ # included
+ if iface.ip.ipv6.address:
+ expected_event = {'event': 'new_addr', 'label': iface.name,
+ 'address': iface.ip.ipv6.address}
+ elif iface.ip.ipv4.address:
+ prefix = _netmask2prefix(iface.ip.ipv4.netmask)
+ expected_event = {'event': 'new_addr', 'label': iface.name,
+ 'address': iface.ip.ipv4.address + '/' + prefix}
+ else:
+ expected_event = {'event': 'new_addr', 'label': iface.name}
+
+ with _event_sniffer(expected_event):
+ rc, out, err = _ifup(iface.name)
+ return rc
else:
rc, out, err = _ifup(iface)
return rc
+def _netmask2prefix(netmask):
+ netmask = [int(octet) for octet in netmask]
+ return sum([sum([int(i) for i in list(bin(octet)[2:])])
+ for octet in netmask])
+
+
+@contextmanager
+def _event_sniffer(expected_event, timeout=10):
+ mon = monitor.Monitor(groups=('link', 'ipv4-ifaddr', 'ipv6-ifaddr'),
+ timeout=timeout)
+ mon.start()
+ try:
+ yield
+ finally:
+ try:
+ for event in mon:
+ if _is_subdict(expected_event, event):
+ mon.stop()
+ except monitor.MonitorError as e:
+ if e[0] == monitor.E_TIMEOUT:
+ logging.error('Expected event "%s" was not caught within the '
+ 'given timeout.', expected_event)
+ else:
+ raise
+
+
+def _is_subdict(subset, superset):
+ return all(item in superset.items() for item in subset.items())
+
+
def configuredPorts(nets, bridge):
"""Returns the list of ports a bridge has"""
ports = []
--
To view, visit http://gerrit.ovirt.org/37366
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0c90a556f5fc52c1b8e675986ac39b6032ca0197
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Petr Horáček <phoracek(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: net: fix test_setupNetworks_on_external_bond
by phoracek@redhat.com
Petr Horáček has uploaded a new change for review.
Change subject: net: fix test_setupNetworks_on_external_bond
......................................................................
net: fix test_setupNetworks_on_external_bond
In this test we manualy write slave names to bond's BONDING_SLAVES file.
Unfortunately, when we try to enslave a nic in UNKNOWN state (left by
a previous test), action explodes with
'IOError: [Errno 1] Operation not permitted'.
Now we set nics explicitly down before enslaving.
Change-Id: Ia29761aa2ec920db4485bf704926b67e0d9851b9
Signed-off-by: Petr Horáček <phoracek(a)redhat.com>
---
M tests/functional/networkTests.py
1 file changed, 1 insertion(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/15/45715/1
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 1873222..c2778bc 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -2625,6 +2625,7 @@
try:
with open(BONDING_SLAVES % BONDING_NAME, 'w') as f:
for nic in nics:
+ linkSet(nic, ['down'])
f.write('+%s\n' % nic)
status, msg = self.setupNetworks(
{NETWORK_NAME:
--
To view, visit https://gerrit.ovirt.org/45715
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia29761aa2ec920db4485bf704926b67e0d9851b9
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Petr Horáček <phoracek(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: lib: pthread: {get,set}affinity support
by fromani@redhat.com
Francesco Romani has uploaded a new change for review.
Change subject: lib: pthread: {get,set}affinity support
......................................................................
lib: pthread: {get,set}affinity support
To improve the performance of VDSM, it can be worth
pinning all pyrhon threads on one core.
This makes sense because of the cpython's GIL, if the
threads jumps from one core to another, we will get
all the disadvantages (cache invalidations) without
any benefit.
This patch prepares the ground exposing get/set affinity
functions on VDSM.
https://bugzilla.redhat.com/1247075
Change-Id: Ie1544ec372095599b39b9ef124a4426a6e73fd4e
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/pthread.py
M tests/pthreadTests.py
2 files changed, 203 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/82/45282/1
diff --git a/lib/vdsm/pthread.py b/lib/vdsm/pthread.py
index 851afd1..059d632 100644
--- a/lib/vdsm/pthread.py
+++ b/lib/vdsm/pthread.py
@@ -20,7 +20,9 @@
from __future__ import absolute_import
import ctypes
+import itertools
import logging
+import multiprocessing
import threading
@@ -50,6 +52,31 @@
logging.warning(
'pthread_{set,get}name_np unavailable. '
'System thread names will not be set.')
+
+
+_pthread_setaffinity_np_proto = ctypes.CFUNCTYPE(
+ ctypes.c_int, ctypes.c_ulong, ctypes.c_size_t, ctypes.c_void_p)
+_pthread_getaffinity_np_proto = ctypes.CFUNCTYPE(
+ ctypes.c_int, ctypes.c_ulong, ctypes.c_size_t, ctypes.c_void_p)
+
+
+try:
+ _pthread_setaffinity_np = _pthread_setaffinity_np_proto(
+ ('pthread_setaffinity_np', _LIBPTHREAD))
+
+ _pthread_getaffinity_np = _pthread_getaffinity_np_proto(
+ ('pthread_getaffinity_np', _LIBPTHREAD))
+
+except AttributeError:
+ def _pthread_setaffinity_np(ident, cpusetsize, cpuset):
+ raise RuntimeError("setaffinity not available")
+
+ def _pthread_getaffinity_np(ident, cpusetsize, cpuset):
+ raise RuntimeError("getaffinity not available")
+
+ logging.warning(
+ 'pthread_{set,get}affinity_np unavailable. '
+ 'CPU affinity for threads will not be set.')
def setname(name):
@@ -88,3 +115,149 @@
thread = threading.current_thread()
_pthread_getname_np(thread.ident, buf, bufsize)
return buf.value
+
+
+def setaffinity(cpuset):
+ cpu_bitset = cpuset.to_bits()
+
+ thread = threading.current_thread()
+ ret = _pthread_setaffinity_np(
+ thread.ident,
+ ctypes.sizeof(cpu_bitset),
+ ctypes.byref(cpu_bitset))
+ if ret < 0:
+ raise RuntimeError("pthread_set_affinity_np failed err=%i", ret)
+
+
+def getaffinity():
+ cpu_bitset = _CPUBitSet()
+
+ thread = threading.current_thread()
+ ret = _pthread_getaffinity_np(
+ thread.ident,
+ ctypes.sizeof(cpu_bitset),
+ ctypes.byref(cpu_bitset))
+ if ret < 0:
+ raise RuntimeError("pthread_get_affinity_np failed err=%i", ret)
+
+ return CPUSet.from_bits(cpu_bitset)
+
+
+class CPUSet(object):
+
+ @classmethod
+ def from_bits(cls, cpu_bitset):
+ obj = cls()
+ obj._cpus = _cpu_bitset_to_set(cpu_bitset)
+ return obj
+
+ @classmethod
+ def from_str(cls, indexes):
+ obj = cls()
+ obj._cpus = _indexes_str_to_set(indexes)
+ return obj
+
+ def __init__(self):
+ """
+ Do not call directly, use from_* functions instead!
+ """
+ self._cpus = set()
+
+ def to_bits(self):
+ return _indexes_set_to_bitset(self.cpus)
+
+ def to_str(self):
+ return _indexes_set_to_str(self._cpus)
+
+ __str__ = to_str
+
+ # for test/debug purposes
+ def to_set(self):
+ return self._cpus
+
+
+# namedtuple is unfit: we need mutability
+class _Group(object):
+
+ __slots__ = ('first', 'last')
+
+ def __init__(self, first, last):
+ self.first = first
+ self.last = last
+
+ def __str__(self):
+ if self.first == self.last:
+ return '%d' % (self.first)
+ else:
+ return '%d-%d' % (self.first, self.last)
+
+ def adjacent(self, value):
+ return self.last == value - 1
+
+ def expand_right(self, value):
+ self.last = value
+
+
+# CAUTION: on x86_64 the CPU_SET macro is mapped on
+# unsigned long, which is uint64 under linux ABI.
+# hence, we need at least one c_uint64 here.
+
+class _CPUBitSet(ctypes.Structure):
+ # TODO: adjust the size dinamycally?
+ # TODO: check all the cpus are addressable?
+ _fields_ = [("bits", ctypes.c_uint64 * 8)]
+
+
+def _group_consecutive(indexes):
+ # TODO: improve algorhytm. This one is bad.
+ items = []
+ for index in sorted(indexes):
+ if items and items[-1].adjacent(index):
+ items[-1].expand_right(index)
+ else:
+ items.append(_Group(index, index))
+ return items
+
+
+def _cpu_bitset_to_set(cpu_bitset):
+ # TODO: improve algorhytm. This one is bad.
+ cpu_idx, cpus = 0, set()
+
+ for i in xrange(len(cpu_bitset.bits)):
+ mask = cpu_bitset.bits[i]
+ while mask:
+ if mask & 1:
+ cpus.add(cpu_idx)
+ cpu_idx += 1
+ mask = mask >> 1
+
+ return cpus
+
+
+def _indexes_set_to_str(cpus):
+ return ','.join(str(pair)
+ for pair in _group_consecutive(cpus))
+
+
+def _indexes_set_to_bitset(cpus):
+ bitset = _CPUBitSet()
+ segment_size = ctypes.sizeof(bitset[0]) * 8 # TODO
+ for cpu_idx in cpus:
+ bitset[cpu_idx / segment_size] |= (
+ 1 << (cpu_idx % segment_size))
+ return bitset
+
+
+def _indexes_str_to_set(indexes):
+ cpus = set()
+
+ for cpu in indexes.split(','):
+ if '-' in cpu:
+ begin_str, end_str = cpu.split('-')
+ begin, end = int(begin_str), int(end_str)
+ for idx in range(begin, end+1):
+ cpus.add(idx)
+ else:
+ cpus.add(int(cpu))
+
+ return cpus
diff --git a/tests/pthreadTests.py b/tests/pthreadTests.py
index 598e544..a487350 100644
--- a/tests/pthreadTests.py
+++ b/tests/pthreadTests.py
@@ -22,6 +22,7 @@
from vdsm import pthread
+from testlib import expandPermutations, permutations
from testlib import VdsmTestCase as TestCaseBase
@@ -68,3 +69,32 @@
self.assertEqual(parent_name, pthread.getname())
self.done.set()
+
+
+@expandPermutations
+class CPUSetTests(TestCaseBase):
+
+ @permutations([['0', set((0,))],
+ ['0,1', set((0,1))],
+ ['0,1,2,3', set((0,1,2,3))],
+ ['0-1', set((0,1))],
+ ['0-3', set((0,1,2,3))],
+ ['0,2-3', set((0,2,3))],
+ ['0,1-3', set((0,1,2,3))],
+ ['0-2,3', set((0,1,2,3))]])
+ def test_from_str(self, given, expected):
+ cpus = pthread.CPUSet.from_str(given)
+ self.assertEqual(cpus.to_set(), expected)
+
+
+ @permutations([['0', '0'],
+ ['0,1', '0-1'],
+ ['0,1,2,3', '0-3'],
+ ['0-1', '0-1'],
+ ['0-3', '0-3'],
+ ['0,2-3', '0,2-3'],
+ ['0,1-3', '0-3'],
+ ['0-2,3', '0-3']])
+ def test_str_round_trip(self, given, expected):
+ cpus = pthread.CPUSet.from_str(given)
+ self.assertEqual(cpus.to_str(), expected)
--
To view, visit https://gerrit.ovirt.org/45282
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie1544ec372095599b39b9ef124a4426a6e73fd4e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
8 years, 7 months
Change in vdsm[ovirt-3.6]: hsm: Support checkStatus param in getDeviceList
by frolland@redhat.com
Hello Fred Rolland, Allon Mureinik,
I'd like you to do a code review. Please visit
https://gerrit.ovirt.org/45759
to review the following change.
Change subject: hsm: Support checkStatus param in getDeviceList
......................................................................
hsm: Support checkStatus param in getDeviceList
In order to populate the 'status' field, the getDeviceList
verb perform a create PV test. This operation is expensive, and in
setups with large number of devices it will cause performance issue.
However, the 'status' field is not always needed. This patch
add an optional 'checkStatus' boolean parameter to getDeviceList.
By default it will be True to keep same behavior as before.
If specified as False, the PV create test will be skipped and the
'status' field will be populated as 'unknown'.
The flow before this patch was:
- Engine calls getDeviceList, VDSM perform status check for each
devices, possibly times out
- User select a few devices (typically one)
- Engine warn user about used devices
The flow with this patch:
- Engine calls getDeviceList, skipping status check
- User select a few devices (typically one)
- Engine calls getDeviceList, checking status only for selected
- Engine warn user about used devices
On a setup of 100 ISCSI devices, the command took 3s without
the PV create test against 58s with the test.
real 0m2.987s
user 0m0.263s
sys 0m0.028s
real 0m57.769s
user 0m0.265s
sys 0m0.024s
Examples:
getDeviceList
return all devices
getDeviceList FCP
return only FCP devices
getDeviceList FCP True
return only FCP devices and perform PV create test
getDeviceList ISCSI False guid1 guid2
return info for guid1 and guid2, assuming ISCSI type
without performing PV create test
Change-Id: Ic28954708f2fd7c7b721aa7f9a0fb6e1a6019597
Bug-Url: https://bugzilla.redhat.com/1217401
Signed-off-by: Fred Rolland <frolland(a)redhat.com>
Reviewed-on: https://gerrit.ovirt.org/45093
Continuous-Integration: Jenkins CI
Reviewed-by: Nir Soffer <nsoffer(a)redhat.com>
Reviewed-by: Allon Mureinik <amureini(a)redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/rpc/bindingxmlrpc.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/storage/hsm.py
5 files changed, 77 insertions(+), 29 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/59/45759/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index ce40974..cda9b81 100755
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -732,8 +732,12 @@
def getDeviceList(self, args):
if len(args) == 0:
res = self.s.getDeviceList()
+ elif len(args) == 1:
+ res = self.s.getDeviceList(args[0])
else:
- res = self.s.getDeviceList(args[0], args[1:])
+ # 'checkStatus' arg should be last
+ res = self.s.getDeviceList(args[0], args[2:],
+ utils.tobool(args[1]))
if res['status']['code']:
return res['status']['code'], res['status']['message']
@@ -2277,16 +2281,22 @@
)),
'getDeviceList': (serv.getDeviceList,
('[storageType]',
+ '[checkStatus]',
'[<devlist>]',
'List of all block devices (optionally - matching '
- 'storageType, optionally - of each device listed).',
+ 'storageType, optionally - check device status'
+ 'optionally - of each device listed).',
' getDeviceList',
' return all devices',
' getDeviceList FCP',
' return only FCP devices',
- ' getDeviceList ISCSI guid1 guid2',
+ ' getDeviceList FCP True',
+ ' return only FCP devices and perform ',
+ ' PV creation test',
+ ' getDeviceList ISCSI False guid1 guid2',
' return info for guid1 and guid2',
- ' , assuming ISCSI type'
+ ' , assuming ISCSI type and skip PV ',
+ ' creation test'
)),
'getDevicesVisibility': (serv.getDevicesVisibility,
('<devlist>',
diff --git a/vdsm/API.py b/vdsm/API.py
index b122424..7582852 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1679,8 +1679,8 @@
def getLVMVolumeGroups(self, storageType=None):
return self._irs.getVGList(storageType)
- def getDeviceList(self, storageType=None, guids=()):
- return self._irs.getDeviceList(storageType, guids)
+ def getDeviceList(self, storageType=None, guids=(), checkStatus=True):
+ return self._irs.getDeviceList(storageType, guids, checkStatus)
def getDevicesVisibility(self, guidList):
return self._irs.getDevicesVisibility(guidList)
diff --git a/vdsm/rpc/bindingxmlrpc.py b/vdsm/rpc/bindingxmlrpc.py
index 7f1da4f..4c69b32 100644
--- a/vdsm/rpc/bindingxmlrpc.py
+++ b/vdsm/rpc/bindingxmlrpc.py
@@ -1029,9 +1029,10 @@
api = API.Global()
return api.getLVMVolumeGroups(storageType)
- def devicesGetList(self, storageType=None, guids=(), options=None):
+ def devicesGetList(self, storageType=None, guids=(),
+ checkStatus=True, options=None):
api = API.Global()
- res = api.getDeviceList(storageType, guids)
+ res = api.getDeviceList(storageType, guids, checkStatus)
return unprotect_passwords(res)
def devicesGetVisibility(self, guids, options=None):
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index 034359a..e443bcd 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -1417,6 +1417,26 @@
'initiatorname': 'str', '*username': 'str', '*password': 'str'}}
##
+# @BlockDeviceStatus:
+#
+# Enumeration of possible status for a block device.
+#
+# @free: The device is free
+#
+# @used: The device is in use.
+# A device will be considered used on the following cases:
+# - a PV exists on this device and is part of a VG
+# - a partition table is found on the device
+# - The device may have a mounted file system
+#
+# @unknown: The device status is unknown
+# (new in version 4.17.5)
+#
+# Since: 4.10.0
+##
+{'enum': 'BlockDeviceStatus', 'data': ['free', 'used', 'unknown']}
+
+##
# @BlockDeviceInfo:
#
# Block device information.
@@ -1451,6 +1471,8 @@
# @pvsize: The LVM physical volume size (in bytes)
# (new in version 4.17)
#
+# @status: The device status (free/used/unknown)
+#
# Since: 4.10.0
#
# Notes: The value of @serial may be dependent on the current host so this
@@ -1468,7 +1490,7 @@
'pathstatus': ['BlockDevicePathInfo'],
'pathlist': ['IscsiSessionInfo'], 'logicalblocksize': 'uint',
'physicalblocksize': 'uint', 'partitioned': 'bool',
- 'pvsize': 'uint'}}
+ 'pvsize': 'uint', 'status': 'BlockDeviceStatus'}}
##
# @Host.getDeviceList:
@@ -1480,6 +1502,9 @@
# @guids: #optional Only return info on specific list of block device
# GUIDs (new in version 4.17)
#
+# @checkStatus: #optional Indicates if device status should be checked
+# (new in version 4.17.5)
+#
# Returns:
# An array of @BlockDeviceInfo
#
@@ -1487,7 +1512,8 @@
##
{'command': {'class': 'Host', 'name': 'getDeviceList'},
'data': {'*storageType': 'BlockDeviceType',
- '*guids': ['str']},
+ '*guids': ['str'],
+ '*checkStatus': 'bool'},
'returns': ['BlockDeviceInfo']}
##
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 10409dd..191cf61 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -1957,7 +1957,8 @@
masterVersion, leaseParams)
@public
- def getDeviceList(self, storageType=None, guids=(), options={}):
+ def getDeviceList(self, storageType=None, guids=(), checkStatus=True,
+ options={}):
"""
List all Block Devices.
@@ -1965,6 +1966,12 @@
:type storageType: Some enum?
:param guids: List of device GUIDs to retrieve info.
:type guids: list
+ :param checkStatus: if true the status will be checked for the given
+ devices. This operation is an expensive operation
+ and should be used only with specific devices
+ using the guids argument.The default is True for
+ backward compatibility.
+ :type checkStatus: bool
:param options: ?
:returns: Dict containing a list of all the devices of the storage
@@ -1972,10 +1979,11 @@
:rtype: dict
"""
vars.task.setDefaultException(se.BlockDeviceActionError())
- devices = self._getDeviceList(storageType=storageType, guids=guids)
+ devices = self._getDeviceList(storageType=storageType, guids=guids,
+ checkStatus=checkStatus)
return dict(devList=devices)
- def _getDeviceList(self, storageType=None, guids=()):
+ def _getDeviceList(self, storageType=None, guids=(), checkStatus=True):
sdCache.refreshStorage()
typeFilter = lambda dev: True
if storageType:
@@ -2028,24 +2036,27 @@
'pathlist': dev.get("connections", []),
'logicalblocksize': dev.get("logicalblocksize", ""),
'physicalblocksize': dev.get("physicalblocksize", "")}
+ if not checkStatus:
+ devInfo["status"] = "unknown"
devices.append(devInfo)
- # Look for devices that will probably fail if pvcreated.
- devNamesToPVTest = tuple(dev["GUID"] for dev in devices)
- unusedDevs, usedDevs = lvm.testPVCreate(
- devNamesToPVTest, metadataSize=blockSD.VG_METADATASIZE)
- # Assuming that unusables v unusables = None
- free = tuple(os.path.basename(d) for d in unusedDevs)
- used = tuple(os.path.basename(d) for d in usedDevs)
- for dev in devices:
- guid = dev['GUID']
- if guid in free:
- dev['status'] = "free"
- elif guid in used:
- dev['status'] = "used"
- else:
- raise KeyError("pvcreate response foresight is "
- "can not be determined for %s", dev)
+ if checkStatus:
+ # Look for devices that will probably fail if pvcreated.
+ devNamesToPVTest = tuple(dev["GUID"] for dev in devices)
+ unusedDevs, usedDevs = lvm.testPVCreate(
+ devNamesToPVTest, metadataSize=blockSD.VG_METADATASIZE)
+ # Assuming that unusables v unusables = None
+ free = tuple(os.path.basename(d) for d in unusedDevs)
+ used = tuple(os.path.basename(d) for d in usedDevs)
+ for dev in devices:
+ guid = dev['GUID']
+ if guid in free:
+ dev['status'] = "free"
+ elif guid in used:
+ dev['status'] = "used"
+ else:
+ raise KeyError("pvcreate response foresight is "
+ "can not be determined for %s", dev)
return devices
--
To view, visit https://gerrit.ovirt.org/45759
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic28954708f2fd7c7b721aa7f9a0fb6e1a6019597
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.6
Gerrit-Owner: Freddy Rolland <frolland(a)redhat.com>
Gerrit-Reviewer: Allon Mureinik <amureini(a)redhat.com>
Gerrit-Reviewer: Fred Rolland <frolland(a)redhat.com>
8 years, 7 months
Change in vdsm[ovirt-3.6]: Add an empty metadata qos element to the created domain
by Martin Sivak
Martin Sivák has uploaded a new change for review.
Change subject: Add an empty metadata qos element to the created domain
......................................................................
Add an empty metadata qos element to the created domain
Libvirt reports an error every time VDSM queries for the metadata
element when there is none. This patch adds an empty default
element to get rid of those errors.
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1219903
Change-Id: Ibc5db925b55ea8e583a11d548a27dc3fd0886fee
Signed-off-by: Martin Sivak <msivak(a)redhat.com>
Reviewed-on: https://gerrit.ovirt.org/45664
Continuous-Integration: Jenkins CI
Reviewed-by: Francesco Romani <fromani(a)redhat.com>
(cherry picked from commit deadb606de96fc84d8d912d56bbc042974074f54)
---
M tests/vmTests.py
M tests/vmTestsData.py
M vdsm/virt/vm.py
M vdsm/virt/vmxml.py
4 files changed, 55 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/99/45799/1
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 1ac1ea7..d48526b 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -113,13 +113,16 @@
def testDomXML(self):
expectedXML = """
- <domain type="kvm">
+ <domain xmlns:ns0="http://ovirt.org/vm/tune/1.0" type="kvm">
<name>testVm</name>
<uuid>9ffe28b6-6134-4b1e-8804-1185f49c436f</uuid>
<memory>1048576</memory>
<currentMemory>1048576</currentMemory>
<vcpu current="8">160</vcpu>
<devices/>
+ <metadata>
+ <ns0:qos/>
+ </metadata>
</domain>"""
domxml = vmxml.Domain(self.conf, self.log, caps.Architecture.X86_64)
diff --git a/tests/vmTestsData.py b/tests/vmTestsData.py
index 9f17976..e1f53f3 100644
--- a/tests/vmTestsData.py
+++ b/tests/vmTestsData.py
@@ -32,7 +32,8 @@
'guestNumaNodes': []},
"""<?xml version="1.0" encoding="utf-8"?>
- <domain type="kvm">
+ <domain type="kvm"
+ xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
<name>testVm</name>
<uuid>%(vmId)s</uuid>
<memory>1048576</memory>
@@ -51,6 +52,9 @@
</channel>
<input bus="ps2" type="mouse"/>
</devices>
+ <metadata>
+ <ovirt:qos/>
+ </metadata>
<os>
<type arch="x86_64" machine="pc">hvm</type>
<smbios mode="sysinfo"/>
@@ -97,6 +101,7 @@
"""<?xml version="1.0" encoding="utf-8"?>
<domain type="kvm"
+ xmlns:ovirt="http://ovirt.org/vm/tune/1.0"
xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0">
<name>testVm</name>
<uuid>%(vmId)s</uuid>
@@ -117,6 +122,9 @@
<input bus="usb" type="mouse"/>
<emulator>/usr/bin/qemu-system-ppc64</emulator>
</devices>
+ <metadata>
+ <ovirt:qos/>
+ </metadata>
<os>
<type arch="ppc64" machine="pc">hvm</type>
</os>
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index a398fe6..7b6dcfb 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -73,6 +73,8 @@
from .vmtune import update_io_tune_dom, collect_inner_elements
from .vmtune import io_tune_values_to_dom, io_tune_dom_to_values
from . import vmxml
+from .vmxml import METADATA_VM_TUNE_URI, METADATA_VM_TUNE_ELEMENT
+from .vmxml import METADATA_VM_TUNE_PREFIX
from .utils import isVdsmImage, cleanup_guest_socket
from vmpowerdown import VmShutdown, VmReboot
@@ -84,8 +86,6 @@
_AGENT_CHANNEL_DEVICES = (_VMCHANNEL_DEVICE_NAME, _QEMU_GA_DEVICE_NAME)
DEFAULT_BRIDGE = config.get("vars", "default_bridge")
-
-METADATA_VM_TUNE_URI = 'http://ovirt.org/vm/tune/1.0'
# A libvirt constant for undefined cpu quota
_NO_CPU_QUOTA = 0
@@ -2368,7 +2368,7 @@
try:
self._dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
- metadata_xml, 'ovirt',
+ metadata_xml, METADATA_VM_TUNE_PREFIX,
METADATA_VM_TUNE_URI, 0)
except libvirt.libvirtError as e:
self.log.exception("updateVmPolicy failed")
@@ -2389,7 +2389,8 @@
:return: XML DOM object representing the root qos element
"""
- metadata_xml = "<qos></qos>"
+ metadata_xml = "<%s></%s>" % (METADATA_VM_TUNE_ELEMENT,
+ METADATA_VM_TUNE_ELEMENT)
try:
metadata_xml = self._dom.metadata(
@@ -2401,7 +2402,7 @@
return None
metadata = _domParseStr(metadata_xml)
- return metadata.getElementsByTagName("qos")[0]
+ return metadata.getElementsByTagName(METADATA_VM_TUNE_ELEMENT)[0]
def _findDeviceByNameOrPath(self, device_name, device_path):
for device in self._devices[hwclass.DISK]:
diff --git a/vdsm/virt/vmxml.py b/vdsm/virt/vmxml.py
index 2c51272..60e3357 100644
--- a/vdsm/virt/vmxml.py
+++ b/vdsm/virt/vmxml.py
@@ -28,6 +28,10 @@
import caps
+METADATA_VM_TUNE_URI = 'http://ovirt.org/vm/tune/1.0'
+METADATA_VM_TUNE_ELEMENT = 'qos'
+METADATA_VM_TUNE_PREFIX = 'ovirt'
+
def has_channel(domXML, name):
domObj = etree.fromstring(domXML)
@@ -91,8 +95,12 @@
class Element(object):
- def __init__(self, tagName, text=None, **attrs):
- self._elem = xml.dom.minidom.Document().createElement(tagName)
+ def __init__(self, tagName, text=None, namespaceUri=None, **attrs):
+ if namespaceUri is not None:
+ self._elem = xml.dom.minidom.Document().createElementNS(
+ namespaceUri, tagName)
+ else:
+ self._elem = xml.dom.minidom.Document().createElement(tagName)
self.setAttrs(**attrs)
if text is not None:
self.appendTextNode(text)
@@ -103,6 +111,9 @@
def setAttrs(self, **attrs):
for attrName, attrValue in attrs.iteritems():
self._elem.setAttribute(attrName, attrValue)
+
+ def setAttr(self, attrName, attrValue):
+ self._elem.setAttribute(attrName, attrValue)
def appendTextNode(self, text):
textNode = xml.dom.minidom.Document().createTextNode(text)
@@ -178,6 +189,8 @@
self._devices = Element('devices')
self.dom.appendChild(self._devices)
+ self.appendMetadata()
+
def appendClock(self):
"""
Add <clock> element to domain:
@@ -205,6 +218,27 @@
self.dom.appendChild(m)
+ def appendMetadata(self):
+ """
+ Add the namespaced qos metadata element to the domain
+
+ <domain xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ ...
+ <metadata>
+ <ovirt:qos xmlns:ovirt=>
+ </metadata>
+ ...
+ </domain>
+ """
+
+ self._metadata = Element('metadata')
+ self._metadata.appendChild(Element(METADATA_VM_TUNE_PREFIX + ':' +
+ METADATA_VM_TUNE_ELEMENT,
+ namespaceUri=METADATA_VM_TUNE_URI))
+ self.dom.setAttr('xmlns:' + METADATA_VM_TUNE_PREFIX,
+ METADATA_VM_TUNE_URI)
+ self.dom.appendChild(self._metadata)
+
def appendOs(self):
"""
Add <os> element to domain:
--
To view, visit https://gerrit.ovirt.org/45799
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibc5db925b55ea8e583a11d548a27dc3fd0886fee
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.6
Gerrit-Owner: Martin Sivák <msivak(a)redhat.com>
8 years, 7 months
Change in vdsm[ovirt-3.5]: net: run dhclient in its own process group.
by ibarkan@redhat.com
Hello Dan Kenigsberg,
I'd like you to do a code review. Please visit
https://gerrit.ovirt.org/43853
to review the following change.
Change subject: net: run dhclient in its own process group.
......................................................................
net: run dhclient in its own process group.
This is done to prevent systemd from killing supervdsm dhclient child
processes during supervdsm stop (or restart). Forking dhclient in
its own process group prevents systemd from doing this.
Since dhclient is deliberately killed either directly by supervdsm or
indirectly by executing ifdown on a device and since executing a
process in a different process group is harmless, the separate
cgroup is now the default behaviour.
This patch also fixes https://bugzilla.redhat.com/1187244 in a less
clumsy way than KillMode=process.
Change-Id: I82848a36b52cd8e9dec188d865ef86edc4bb7488
Signed-off-by: Ido Barkan <ibarkan(a)redhat.com>
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1228322
Reviewed-on: https://gerrit.ovirt.org/43005
Reviewed-by: Dan Kenigsberg <danken(a)redhat.com>
Continuous-Integration: Jenkins CI
---
M init/systemd/vdsm-network.service.in
M vdsm/network/configurators/dhclient.py
M vdsm/network/configurators/ifcfg.py
3 files changed, 17 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/53/43853/1
diff --git a/init/systemd/vdsm-network.service.in b/init/systemd/vdsm-network.service.in
index 9680f06..c3fa44c 100644
--- a/init/systemd/vdsm-network.service.in
+++ b/init/systemd/vdsm-network.service.in
@@ -10,7 +10,6 @@
ExecStartPre=@BINDIR@/vdsm-tool --vvverbose --append --logfile=@VDSMLOGDIR(a)/upgrade.log upgrade-unified-persistence
ExecStartPre=@BINDIR@/vdsm-tool --vvverbose --append --logfile=@VDSMLOGDIR(a)/upgrade.log upgrade-3.0.0-networks
ExecStart=@BINDIR@/vdsm-tool restore-nets
-KillMode=process
RemainAfterExit=yes
[Install]
diff --git a/vdsm/network/configurators/dhclient.py b/vdsm/network/configurators/dhclient.py
index 0b83b24..b2af4a0 100644
--- a/vdsm/network/configurators/dhclient.py
+++ b/vdsm/network/configurators/dhclient.py
@@ -23,12 +23,15 @@
import signal
import threading
+from vdsm import cmdutils
from vdsm import ipwrapper
from vdsm import netinfo
from vdsm.utils import CommandPath
from vdsm.utils import execCmd
from vdsm.utils import pgrep
from vdsm.utils import rmFile
+
+DHCLIENT_CGROUP = 'vdsm-dhclient'
class DhcpClient(object):
@@ -37,20 +40,22 @@
LEASE_FILE = LEASE_DIR + 'dhclient-%s.lease'
DHCLIENT = CommandPath('dhclient', '/sbin/dhclient')
- def __init__(self, iface):
+ def __init__(self, iface, cgroup=DHCLIENT_CGROUP):
self.iface = iface
self.pidFile = self.PID_FILE % self.iface
if not os.path.exists(self.LEASE_DIR):
os.mkdir(self.LEASE_DIR)
self.leaseFile = (self.LEASE_FILE % self.iface)
+ self._cgroup = cgroup
def _dhclient(self):
# Ask dhclient to stop any dhclient running for the device
if os.path.exists(os.path.join(netinfo.NET_PATH, self.iface)):
kill_dhclient(self.iface)
- rc, out, err = execCmd([self.DHCLIENT.cmd, '-1', '-pf',
- self.pidFile, '-lf', self.leaseFile,
- self.iface])
+ cmd = [self.DHCLIENT.cmd, '-1', '-pf', self.pidFile, '-lf',
+ self.leaseFile, self.iface]
+ cmd = cmdutils.systemd_run(cmd, scope=True, slice=self._cgroup)
+ rc, out, err = execCmd(cmd)
return rc, out, err
def start(self, async):
diff --git a/vdsm/network/configurators/ifcfg.py b/vdsm/network/configurators/ifcfg.py
index c3f9893..b988925 100644
--- a/vdsm/network/configurators/ifcfg.py
+++ b/vdsm/network/configurators/ifcfg.py
@@ -32,6 +32,7 @@
from libvirt import libvirtError, VIR_ERR_NO_NETWORK
from vdsm.config import config
+from vdsm import cmdutils
from vdsm import constants
from vdsm import ipwrapper
from vdsm import netinfo
@@ -784,10 +785,15 @@
return rc
-def ifup(iface, async=False):
+def ifup(iface, async=False, cgroup=dhclient.DHCLIENT_CGROUP):
"Bring up an interface"
def _ifup(netIf):
- rc, out, err = utils.execCmd([constants.EXT_IFUP, netIf], raw=False)
+ cmd = [constants.EXT_IFUP, netIf]
+
+ if cgroup is not None:
+ cmd = cmdutils.systemd_run(cmd, scope=True, slice=cgroup)
+
+ rc, out, err = utils.execCmd(cmd, raw=False)
if rc != 0:
# In /etc/sysconfig/network-scripts/ifup* the last line usually
--
To view, visit https://gerrit.ovirt.org/43853
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I82848a36b52cd8e9dec188d865ef86edc4bb7488
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5
Gerrit-Owner: Ido Barkan <ibarkan(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
8 years, 7 months
Change in vdsm[ovirt-3.5]: net: backport cmdutils.systemd_run
by ibarkan@redhat.com
Ido Barkan has uploaded a new change for review.
Change subject: net: backport cmdutils.systemd_run
......................................................................
net: backport cmdutils.systemd_run
This is a minimal backport of cmdutils to 3.5. cmdutils is only a
partial version of what was already included in the master branch. This
was done to avoid meeting many dependencies just in order to fix a bug
in the stable branch.
Change-Id: I7686e80c0880dcc28fa735d1dd3ab658136889f9
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M configure.ac
M debian/vdsm-python.install
M lib/vdsm/Makefile.am
A lib/vdsm/cmdutils.py
M lib/vdsm/constants.py.in
M tests/Makefile.am
A tests/cmdutilsTests.py
M vdsm.spec.in
M vdsm/sudoers.vdsm.in
9 files changed, 87 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/52/43852/1
diff --git a/configure.ac b/configure.ac
index 7d3472c..46c857b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,6 +264,7 @@
AC_PATH_PROG([SU_PATH], [su], [/bin/su])
AC_PATH_PROG([SYSCTL_PATH], [sysctl], [/sbin/sysctl])
AC_PATH_PROG([SYSTEMCTL_PATH], [systemctl], [/bin/systemctl])
+AC_PATH_PROG([SYSTEMD_RUN_PATH], [systemd-run], [/usr/bin/systemd-run])
AC_PATH_PROG([TAR_PATH], [tar], [/bin/tar])
AC_PATH_PROG([TC_PATH], [tc], [/sbin/tc])
AC_PATH_PROG([TEE_PATH], [tee], [/usr/bin/tee])
diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index 5f142a7..142dfce 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -2,6 +2,7 @@
./usr/bin/vdsm-tool
./usr/lib/python2.7/dist-packages/vdsm/SecureXMLRPCServer.py
./usr/lib/python2.7/dist-packages/vdsm/__init__.py
+./usr/lib/python2.7/dist-packages/vdsm/cmdutils.py
./usr/lib/python2.7/dist-packages/vdsm/compat.py
./usr/lib/python2.7/dist-packages/vdsm/config.py
./usr/lib/python2.7/dist-packages/vdsm/constants.py
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index aaf26bf..a0f5c72 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -23,6 +23,7 @@
dist_vdsmpylib_PYTHON = \
__init__.py \
+ cmdutils.py \
compat.py \
define.py \
exception.py \
diff --git a/lib/vdsm/cmdutils.py b/lib/vdsm/cmdutils.py
new file mode 100644
index 0000000..5d1c96e
--- /dev/null
+++ b/lib/vdsm/cmdutils.py
@@ -0,0 +1,32 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from . import constants
+
+
+def systemd_run(cmd, scope=False, unit=None, slice=None):
+ command = [constants.EXT_SYSTEMD_RUN]
+ if scope:
+ command.append('--scope')
+ if unit:
+ command.append('--unit=%s' % unit)
+ if slice:
+ command.append('--slice=%s' % slice)
+ command.extend(cmd)
+ return command
diff --git a/lib/vdsm/constants.py.in b/lib/vdsm/constants.py.in
index 4539d26..e75796a 100644
--- a/lib/vdsm/constants.py.in
+++ b/lib/vdsm/constants.py.in
@@ -168,3 +168,4 @@
EXT_CURL_IMG_WRAP = '@LIBEXECDIR@/curl-img-wrap'
EXT_FC_SCAN = '@LIBEXECDIR@/fc-scan'
+EXT_SYSTEMD_RUN = '@SYSTEMD_RUN_PATH@'
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ec9ab0b..bd15c19 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -29,6 +29,7 @@
cPopenTests.py \
capsTests.py \
clientifTests.py \
+ cmdutilsTests.py \
configNetworkTests.py \
fileVolumeTests.py \
fileUtilTests.py \
diff --git a/tests/cmdutilsTests.py b/tests/cmdutilsTests.py
new file mode 100644
index 0000000..a8c928b
--- /dev/null
+++ b/tests/cmdutilsTests.py
@@ -0,0 +1,47 @@
+#
+# Copyright 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from vdsm import cmdutils
+from vdsm import constants
+
+from testlib import VdsmTestCase
+
+
+class SystemdRunTests(VdsmTestCase):
+
+ def test_defaults(self):
+ cmd = cmdutils.systemd_run(['a', 'b'])
+ res = [constants.EXT_SYSTEMD_RUN, 'a', 'b']
+ self.assertEqual(cmd, res)
+
+ def test_scope(self):
+ cmd = cmdutils.systemd_run(['a', 'b'], scope=True)
+ res = [constants.EXT_SYSTEMD_RUN, '--scope', 'a', 'b']
+ self.assertEqual(cmd, res)
+
+ def test_unit(self):
+ cmd = cmdutils.systemd_run(['a', 'b'], unit='unit')
+ res = [constants.EXT_SYSTEMD_RUN, '--unit=unit', 'a', 'b']
+ self.assertEqual(cmd, res)
+
+ def test_slice(self):
+ cmd = cmdutils.systemd_run(['a', 'b'], slice='slice')
+ res = [constants.EXT_SYSTEMD_RUN, '--slice=slice', 'a', 'b']
+ self.assertEqual(cmd, res)
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 8a54ed8..4f06070 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1251,6 +1251,7 @@
%dir %{python_sitelib}/%{vdsm_name}
%dir %{python_sitelib}/%{vdsm_name}/tool
%{python_sitelib}/%{vdsm_name}/__init__.py*
+%{python_sitelib}/%{vdsm_name}/cmdutils.py*
%{python_sitelib}/%{vdsm_name}/compat.py*
%{python_sitelib}/%{vdsm_name}/config.py*
%{python_sitelib}/%{vdsm_name}/constants.py*
diff --git a/vdsm/sudoers.vdsm.in b/vdsm/sudoers.vdsm.in
index dff5539..121e2bf 100644
--- a/vdsm/sudoers.vdsm.in
+++ b/vdsm/sudoers.vdsm.in
@@ -32,7 +32,8 @@
@MULTIPATH_PATH@, \
@SETSID_PATH@ @IONICE_PATH@ -c ? -n ? @SU_PATH@ vdsm -s /bin/sh -c /usr/libexec/vdsm/spmprotect.sh*, \
@SERVICE_PATH@ vdsmd *, \
- @REBOOT_PATH@ -f
+ @REBOOT_PATH@ -f, \
+ @SYSTEMD_RUN_PATH@
vdsm ALL=(ALL) NOPASSWD: VDSM_LIFECYCLE, VDSM_STORAGE
Defaults:vdsm !requiretty
--
To view, visit https://gerrit.ovirt.org/43852
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7686e80c0880dcc28fa735d1dd3ab658136889f9
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5
Gerrit-Owner: Ido Barkan <ibarkan(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: Add an empty metadata qos element to the created domain
by Martin Sivak
Martin Sivák has uploaded a new change for review.
Change subject: Add an empty metadata qos element to the created domain
......................................................................
Add an empty metadata qos element to the created domain
Libvirt reports an error every time VDSM queries for the metadata
element when there is none. This patch adds an empty default
element to get rid of those errors.
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1219903
Change-Id: Ibc5db925b55ea8e583a11d548a27dc3fd0886fee
Signed-off-by: Martin Sivak <msivak(a)redhat.com>
---
M tests/vmTests.py
M tests/vmTestsData.py
M vdsm/virt/vm.py
M vdsm/virt/vmxml.py
4 files changed, 51 insertions(+), 9 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/64/45664/1
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 30c7473..f26a0ac 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -112,13 +112,16 @@
def testDomXML(self):
expectedXML = """
- <domain type="kvm">
+ <domain xmlns:ns0="http://ovirt.org/vm/tune/1.0" type="kvm">
<name>testVm</name>
<uuid>9ffe28b6-6134-4b1e-8804-1185f49c436f</uuid>
<memory>1048576</memory>
<currentMemory>1048576</currentMemory>
<vcpu current="8">160</vcpu>
<devices/>
+ <metadata>
+ <ns0:qos/>
+ </metadata>
</domain>"""
domxml = vmxml.Domain(self.conf, self.log, caps.Architecture.X86_64)
diff --git a/tests/vmTestsData.py b/tests/vmTestsData.py
index 9f17976..e1f53f3 100644
--- a/tests/vmTestsData.py
+++ b/tests/vmTestsData.py
@@ -32,7 +32,8 @@
'guestNumaNodes': []},
"""<?xml version="1.0" encoding="utf-8"?>
- <domain type="kvm">
+ <domain type="kvm"
+ xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
<name>testVm</name>
<uuid>%(vmId)s</uuid>
<memory>1048576</memory>
@@ -51,6 +52,9 @@
</channel>
<input bus="ps2" type="mouse"/>
</devices>
+ <metadata>
+ <ovirt:qos/>
+ </metadata>
<os>
<type arch="x86_64" machine="pc">hvm</type>
<smbios mode="sysinfo"/>
@@ -97,6 +101,7 @@
"""<?xml version="1.0" encoding="utf-8"?>
<domain type="kvm"
+ xmlns:ovirt="http://ovirt.org/vm/tune/1.0"
xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0">
<name>testVm</name>
<uuid>%(vmId)s</uuid>
@@ -117,6 +122,9 @@
<input bus="usb" type="mouse"/>
<emulator>/usr/bin/qemu-system-ppc64</emulator>
</devices>
+ <metadata>
+ <ovirt:qos/>
+ </metadata>
<os>
<type arch="ppc64" machine="pc">hvm</type>
</os>
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 73f3cfd..e36cbe1 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -71,6 +71,7 @@
from .vmtune import update_io_tune_dom, collect_inner_elements
from .vmtune import io_tune_values_to_dom, io_tune_dom_to_values
from . import vmxml
+from .vmxml import METADATA_VM_TUNE_URI, METADATA_VM_TUNE_ELEMENT, METADATA_VM_TUNE_PREFIX
from .utils import isVdsmImage, cleanup_guest_socket
from vmpowerdown import VmShutdown, VmReboot
@@ -82,8 +83,6 @@
_AGENT_CHANNEL_DEVICES = (_VMCHANNEL_DEVICE_NAME, _QEMU_GA_DEVICE_NAME)
DEFAULT_BRIDGE = config.get("vars", "default_bridge")
-
-METADATA_VM_TUNE_URI = 'http://ovirt.org/vm/tune/1.0'
# A libvirt constant for undefined cpu quota
_NO_CPU_QUOTA = 0
@@ -2387,7 +2386,7 @@
try:
self._dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
- metadata_xml, 'ovirt',
+ metadata_xml, METADATA_VM_TUNE_PREFIX,
METADATA_VM_TUNE_URI, 0)
except libvirt.libvirtError as e:
self.log.exception("updateVmPolicy failed")
@@ -2408,7 +2407,8 @@
:return: XML DOM object representing the root qos element
"""
- metadata_xml = "<qos></qos>"
+ metadata_xml = "<%s></%s>" % (METADATA_VM_TUNE_ELEMENT,
+ METADATA_VM_TUNE_ELEMENT)
try:
metadata_xml = self._dom.metadata(
@@ -2420,7 +2420,7 @@
return None
metadata = _domParseStr(metadata_xml)
- return metadata.getElementsByTagName("qos")[0]
+ return metadata.getElementsByTagName(METADATA_VM_TUNE_ELEMENT)[0]
def _findDeviceByNameOrPath(self, device_name, device_path):
for device in self._devices[hwclass.DISK]:
diff --git a/vdsm/virt/vmxml.py b/vdsm/virt/vmxml.py
index 2c51272..7ade30c 100644
--- a/vdsm/virt/vmxml.py
+++ b/vdsm/virt/vmxml.py
@@ -28,6 +28,9 @@
import caps
+METADATA_VM_TUNE_URI = 'http://ovirt.org/vm/tune/1.0'
+METADATA_VM_TUNE_ELEMENT = 'qos'
+METADATA_VM_TUNE_PREFIX = 'ovirt'
def has_channel(domXML, name):
domObj = etree.fromstring(domXML)
@@ -91,8 +94,11 @@
class Element(object):
- def __init__(self, tagName, text=None, **attrs):
- self._elem = xml.dom.minidom.Document().createElement(tagName)
+ def __init__(self, tagName, text=None, namespaceUri=None, **attrs):
+ if namespaceUri is not None:
+ self._elem = xml.dom.minidom.Document().createElementNS(namespaceUri, tagName)
+ else:
+ self._elem = xml.dom.minidom.Document().createElement(tagName)
self.setAttrs(**attrs)
if text is not None:
self.appendTextNode(text)
@@ -103,6 +109,9 @@
def setAttrs(self, **attrs):
for attrName, attrValue in attrs.iteritems():
self._elem.setAttribute(attrName, attrValue)
+
+ def setAttr(self, attrName, attrValue):
+ self._elem.setAttribute(attrName, attrValue)
def appendTextNode(self, text):
textNode = xml.dom.minidom.Document().createTextNode(text)
@@ -178,6 +187,8 @@
self._devices = Element('devices')
self.dom.appendChild(self._devices)
+ self.appendMetadata()
+
def appendClock(self):
"""
Add <clock> element to domain:
@@ -205,6 +216,26 @@
self.dom.appendChild(m)
+ def appendMetadata(self):
+ """
+ Add the namespaced qos metadata element to the domain
+
+ <domain xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ ...
+ <metadata>
+ <ovirt:qos xmlns:ovirt=>
+ </metadata>
+ ...
+ </domain>
+ """
+
+ self._metadata = Element('metadata')
+ self._metadata.appendChild(Element(METADATA_VM_TUNE_PREFIX + ':' + METADATA_VM_TUNE_ELEMENT,
+ namespaceUri=METADATA_VM_TUNE_URI))
+ self.dom.setAttr('xmlns:' + METADATA_VM_TUNE_PREFIX,
+ METADATA_VM_TUNE_URI)
+ self.dom.appendChild(self._metadata)
+
def appendOs(self):
"""
Add <os> element to domain:
--
To view, visit https://gerrit.ovirt.org/45664
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibc5db925b55ea8e583a11d548a27dc3fd0886fee
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Sivák <msivak(a)redhat.com>
8 years, 7 months
Change in vdsm[master]: automation: enable pep8
by Dan Kenigsberg
Dan Kenigsberg has uploaded a new change for review.
Change subject: automation: enable pep8
......................................................................
automation: enable pep8
We now have a single check-patch job.
Change-Id: If2266725af30e45b414d040f7f8d6b47d46bf947
Signed-off-by: Dan Kenigsberg <danken(a)redhat.com>
---
M automation/check-patch.sh
1 file changed, 0 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/53/45753/1
diff --git a/automation/check-patch.sh b/automation/check-patch.sh
index 51f7ee3..68a3083 100755
--- a/automation/check-patch.sh
+++ b/automation/check-patch.sh
@@ -10,8 +10,6 @@
# this redefines 'ugly' but looks like NOSE_EXCLUDE works at test method level,
# not at module neither at testcase level, so we have no choice but this.
export NOSE_EXCLUDE=".*testGetBondingOptions.*|testMirroring.*|testToggleIngress|testException|testQdiscsOfDevice|testReplacePrio"
-# disable pep8 checks on unit test, since we have seperate job on it.
-export PEP8=$(which true)
sh -x autogen.sh --system
make all
--
To view, visit https://gerrit.ovirt.org/45753
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If2266725af30e45b414d040f7f8d6b47d46bf947
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dan Kenigsberg <danken(a)redhat.com>
8 years, 7 months