Change in vdsm[master]: NetReload: netmodels for addNetwork
by asegurap@redhat.com
Antoni Segura Puimedon has posted comments on this change.
Change subject: NetReload: netmodels for addNetwork
......................................................................
Patch Set 16: (2 inline comments)
....................................................
File vdsm/netconf/ifcfg.py
Line 95: self.configWriter.addBonding(bond.name, bridge=bridge,
Line 96: bondingOptions=bond.options,
Line 97: mtu=bond.mtu, ipaddr=ipaddr,
Line 98: netmask=netmask, gateway=gateway,
Line 99: bootproto=bootproto, **opts)
I did some testing with a previous version and the master behavior is:
Bond0 has eth2 and eth3 with ip 192.168.1.14/24 (done by using iproute2 cmdline). If I add a bridgeless network 'foo' on bond0 with eth2 and eth3 and with ip 172.16.0.2/16, the new ip conf gets written on /etc/sysconfig/network-scripts/ifcfg-bond0 but the the new IP is set besides the old one, not replacing it (just like in this patchset).
For nics though we need to do the flushing.
Line 100: for slave in bond.slaves:
Line 101: slave.configure(bonding=bond.name, **opts)
Line 102: ifup(bond.name, async)
Line 103: if network:
....................................................
File vdsm/netmodels.py
Line 140:
Line 141:
Line 142: class Bond(NetDevice):
Line 143: def __init__(self, name, configurator, ipconfig=None, mtu=None, slaves=(),
Line 144: options='mode=802.3ad miimon=150'):
Done
Line 145: self.validateName(name)
Line 146: self.slaves = slaves
Line 147: if options:
Line 148: self.validateOptions(name, options)
--
To view, visit http://gerrit.ovirt.org/14303
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: comment
Gerrit-Change-Id: Iba5c5b84760e27245cbe34c3b290c54e51278e72
Gerrit-PatchSet: 16
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
Gerrit-Reviewer: Giuseppe Vallarelli <gvallare(a)redhat.com>
Gerrit-Reviewer: Livnat Peer <lpeer(a)redhat.com>
Gerrit-Reviewer: Mark Wu <wudxw(a)linux.vnet.ibm.com>
Gerrit-Reviewer: oVirt Jenkins CI Server
9 years, 9 months
Change in vdsm[master]: supervdsm: Fix race regarding instance ident
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: supervdsm: Fix race regarding instance ident
......................................................................
supervdsm: Fix race regarding instance ident
- Move typeid registration to module initialization as it is a class
level operation
- Change callMethod() from lambda to a method and make expression
evaluation make sense and understandable. Lambdas are tricky :)
- Don't cache svdsm instance BaseManager does weird incref\decref and
indexes the transient instances by their `id(proxyObj)`. Lets just use
it's cache and avoid cache coherency issues.
Change-Id: I4f548cb9ad805508cf75df691e0ab58b3278dc87
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M vdsm/supervdsm.py
1 file changed, 15 insertions(+), 8 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/59/11759/1
diff --git a/vdsm/supervdsm.py b/vdsm/supervdsm.py
index 10abae0..fd641ab 100644
--- a/vdsm/supervdsm.py
+++ b/vdsm/supervdsm.py
@@ -59,6 +59,9 @@
class _SuperVdsmManager(BaseManager):
pass
+_SuperVdsmManager.register('instance')
+_SuperVdsmManager.register('open')
+
class ProxyCaller(object):
@@ -67,9 +70,11 @@
self._supervdsmProxy = supervdsmProxy
def __call__(self, *args, **kwargs):
- callMethod = lambda: \
- getattr(self._supervdsmProxy._svdsm, self._funcName)(*args,
- **kwargs)
+ def callMethod():
+ instance = self._supervdsmProxy.getInstance()
+ method = getattr(instance, self._funcName)
+ return method(*args, **kwargs)
+
if not self._supervdsmProxy.isRunning():
# getting inside only when svdsm is down. its rare case so we
# don't care that isRunning will run twice
@@ -144,11 +149,10 @@
self._cleanOldFiles()
self._authkey = None
self._manager = None
- self._svdsm = None
self._firstLaunch = True
def isRunning(self):
- if self._firstLaunch or self._svdsm is None:
+ if self._firstLaunch or self.getInstance() is None:
return False
try:
@@ -181,15 +185,18 @@
def _connect(self):
self._manager = _SuperVdsmManager(address=self.address,
authkey=self._authkey)
- self._manager.register('instance')
- self._manager.register('open')
self._log.debug("Trying to connect to Super Vdsm")
try:
self._manager.connect()
except Exception as ex:
self._log.warn("Connect to svdsm failed %s", ex)
raise
- self._svdsm = self._manager.instance()
+
+ def getInstance(self):
+ try:
+ return self._manager.instance()
+ except:
+ return None
def launch(self):
self._firstLaunch = False
--
To view, visit http://gerrit.ovirt.org/11759
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4f548cb9ad805508cf75df691e0ab58b3278dc87
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: vdsm.tool.service: fix _systemctlNative
by zhshzhou@linux.vnet.ibm.com
Zhou Zheng Sheng has uploaded a new change for review.
Change subject: vdsm.tool.service: fix _systemctlNative
......................................................................
vdsm.tool.service: fix _systemctlNative
_systemctlNative lists systemd units and check if the given service is
managed by systemd. There is a bug in the checking code. When
splitting words, it does not fetch the word from the resulting array.
The first word is the name of the unit/service. This patch fix the
problem.
Another small problem is it does not format the error message correctly,
this patch fix the formatting.
At last it fixes a bad doc string.
Change-Id: I3a3b903786d431ba306bb2cf3f7f35d6de38ed42
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
M lib/vdsm/tool/service.py
1 file changed, 3 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/05/15305/1
diff --git a/lib/vdsm/tool/service.py b/lib/vdsm/tool/service.py
index 8bcfefa..8b4e5c5 100644
--- a/lib/vdsm/tool/service.py
+++ b/lib/vdsm/tool/service.py
@@ -81,9 +81,9 @@
if rc != 0:
return (rc, out, err)
for line in out:
- if srvName + ".service" == line.split(" ", 1):
+ if srvName + ".service" == line.split(" ", 1)[0]:
return systemctlFun(srvName)
- return (1, "", "%s is not native systemctl service")
+ return (1, "", "%s is not native systemctl service" % srvName)
return wrapper
@_systemctlNative
@@ -276,7 +276,7 @@
@expose("service-restart")
def service_restart(srvName):
"""
- Get status of a system service
+ Restart a system service
"""
return _runAlts(_srvRestartAlts, srvName)
--
To view, visit http://gerrit.ovirt.org/15305
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3a3b903786d431ba306bb2cf3f7f35d6de38ed42
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
9 years, 9 months
Change in vdsm[master]: cpopen: Fix signal handling in sync points
by smizrahi@redhat.com
Saggi Mizrahi has uploaded a new change for review.
Change subject: cpopen: Fix signal handling in sync points
......................................................................
cpopen: Fix signal handling in sync points
Change-Id: Id2883091c377c1e4ff9f69b87fc137326b583ab8
Signed-off-by: Saggi Mizrahi <smizrahi(a)redhat.com>
---
M lib/cpopen/cpopen.c
1 file changed, 36 insertions(+), 21 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/65/15165/1
diff --git a/lib/cpopen/cpopen.c b/lib/cpopen/cpopen.c
index ca39406..620bf1e 100644
--- a/lib/cpopen/cpopen.c
+++ b/lib/cpopen/cpopen.c
@@ -64,6 +64,32 @@
return rv;
}
+/* Just like close() but retries on interrupt and tries to fill the buffer */
+static int
+safeRead(int fd, void *buff, size_t count) {
+ size_t bread = 0;
+ char* cbuff = buff;
+ int rv = 0;
+ while (bread < count) {
+ rv = read(fd, cbuff + bread, count - bread);
+ bread += rv;
+ /* EOF */
+ if (rv == 0) {
+ return bread;
+ } else if (rv < 0) {
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+ break;
+ default:
+ return rv;
+ }
+ }
+ }
+
+ return bread;
+}
+
static int
setCloseOnExec(int fd) {
int flags;
@@ -311,35 +337,24 @@
if (deathSignal) {
/* death signal sync point */
- while (1) {
- rv = read(errnofd[0], &childErrno, sizeof(int));
- if (rv < 0) {
- switch (errno) {
- case EINTR:
- case EAGAIN:
- break;
- default:
- PyErr_SetString(PyExc_OSError, strerror(childErrno));
- goto fail;
-
- }
- } else if (rv < sizeof(int)) {
- PyErr_SetString(PyExc_OSError, strerror(childErrno));
- goto fail;
- }
- break;
- }
-
- if (childErrno != 0) {
+ rv = safeRead(errnofd[0], &childErrno, sizeof(int));
+ if (rv != sizeof(int)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto fail;
+ } else if (childErrno != 0) {
PyErr_SetString(PyExc_OSError, strerror(childErrno));
goto fail;
}
}
/* error sync point */
- if (read(errnofd[0], &childErrno, sizeof(int)) == sizeof(int)) {
+ rv = safeRead(errnofd[0], &childErrno, sizeof(int));
+ if (rv == sizeof(int)) {
PyErr_SetString(PyExc_OSError, strerror(childErrno));
goto fail;
+ } else if (rv < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto fail;
}
safeClose(errnofd[0]);
--
To view, visit http://gerrit.ovirt.org/15165
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id2883091c377c1e4ff9f69b87fc137326b583ab8
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Saggi Mizrahi <smizrahi(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: domain: use the dd statistics for the domain delay
by Federico Simoncelli
Federico Simoncelli has uploaded a new change for review.
Change subject: domain: use the dd statistics for the domain delay
......................................................................
domain: use the dd statistics for the domain delay
The previous implementation of getReadDelay was calculating the reading
time (for the domain statistics) checking the execution time of dd.
This patch introduces a low level readspeed command to parse the more
accurate statistics provided by dd in the stderr.
Bug-Url: http://bugzilla.redhat.com/show_bug.cgi?id=948232
Change-Id: Ib3fa54dbbe3475b74bcfe5cbc0c60895818f8b3e
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M tests/miscTests.py
M vdsm/storage/blockSD.py
M vdsm/storage/misc.py
3 files changed, 61 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/49/15049/1
diff --git a/tests/miscTests.py b/tests/miscTests.py
index 96549c8..5011b91 100644
--- a/tests/miscTests.py
+++ b/tests/miscTests.py
@@ -883,6 +883,24 @@
self.assertRaises(misc.se.MiscFileReadException, misc.readfile, path)
+class ReadSpeed(TestCaseBase):
+ STATS_TEMPLATE = "%s byte%s (%s %sB) copied, %s s, %s %sB/s"
+ STATS_TESTS = (
+ ("1", "", "1", "", "1", "1", ""),
+ ("1024", "s", "1", "k", "1", "1", "k"),
+ ("1572864", "s", "1.5", "M", "1.5", "1", "M"),
+ ("1610612736", "s", "1.5", "G", "1000.5", "1.53", "M"),
+ )
+
+ def checkReadSpeedRegExp(self):
+ for stats in self.STATS_TESTS:
+ m = misc._readspeed_regex.match(self.STATS_TEMPLATE % stats)
+ self.assertNotEqual(m, None)
+
+ self.assertEqual(m.group("bytes"), stats[0])
+ self.assertEqual(m.group("seconds"), stats[4])
+
+
class PidExists(TestCaseBase):
def testPidExists(self):
"""
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index e8ce11c..86a22ee 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -591,9 +591,8 @@
return bsd
def getReadDelay(self):
- t = time.time()
- misc.readfile(lvm.lvPath(self.sdUUID, sd.METADATA), 4096)
- return time.time() - t
+ stats = misc.readspeed(lvm.lvPath(self.sdUUID, sd.METADATA), 4096)
+ return stats['seconds']
def getVolumeClass(self):
"""
diff --git a/vdsm/storage/misc.py b/vdsm/storage/misc.py
index 37dba7c..4c6ce2a 100644
--- a/vdsm/storage/misc.py
+++ b/vdsm/storage/misc.py
@@ -191,10 +191,7 @@
return str(ctime)
-def readfile(name, buffersize=None):
- """
- Read the content of the file using /bin/dd command
- """
+def _readfile(name, buffersize=None):
cmd = [constants.EXT_DD]
if fileUtils.pathRequiresFlagForDirectIO(name):
@@ -206,9 +203,49 @@
(rc, out, err) = execCmd(cmd, sudo=False)
if rc:
raise se.MiscFileReadException(name)
+
+ return rc, out, err
+
+
+def readfile(name, buffersize=None):
+ """
+ Read the content of the file using /bin/dd command
+ """
+ rc, out, err = _readfile(name, buffersize)
return out
+_readspeed_regex = re.compile(
+ "(?P<bytes>\d+) bytes? \([\d.]+ [kMGT]*B\) copied, "
+ "(?P<seconds>[\d.]+) s, "
+ "[\d.]+ [kMGT]*B/s"
+)
+
+
+def readspeed(path, buffersize=None):
+ """
+ Measures the amount of bytes transferred and the time elapsed
+ reading the content of the file/device
+ """
+ rc, out, err = _readfile(path, buffersize)
+
+ try:
+ # The statistics are located in the last line:
+ m = _readspeed_regex.match(err[-1])
+ except IndexError:
+ log.error("Unable to find dd statistics to parse")
+ raise se.MiscFileReadException(path)
+
+ if m is None:
+ log.error("Unable to parse dd output: '%s'", err[-1])
+ raise se.MiscFileReadException(path)
+
+ return {
+ 'bytes': int(m.group('bytes')),
+ 'seconds': float(m.group('seconds')),
+ }
+
+
def readblock(name, offset, size):
'''
Read (direct IO) the content of device 'name' at offset, size bytes
--
To view, visit http://gerrit.ovirt.org/15049
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib3fa54dbbe3475b74bcfe5cbc0c60895818f8b3e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: NetReload: netmodels for addNetwork
by wudxw@linux.vnet.ibm.com
Mark Wu has posted comments on this change.
Change subject: NetReload: netmodels for addNetwork
......................................................................
Patch Set 16: (1 inline comment)
....................................................
File vdsm/netmodels.py
Line 140:
Line 141:
Line 142: class Bond(NetDevice):
Line 143: def __init__(self, name, configurator, ipconfig=None, mtu=None, slaves=(),
Line 144: options='mode=802.3ad miimon=150'):
In objectivizeNetwork, Bond.objectivize is called with the parameter 'bondingOptions' passed from engine, and then Bond.objectivize just pass it to Bond.__init__ if it's creating a new bond. The default options 'mode=802.3ad miimon=150' used hear will be overridden by 'None'. It's not what we expect. So probably we need change the default value of options to 'None' in the signature, and assign 'mode=802.3ad miimon=150' to it if None is passed in.
Line 145: self.validateName(name)
Line 146: self.slaves = slaves
Line 147: if options:
Line 148: self.validateOptions(name, options)
--
To view, visit http://gerrit.ovirt.org/14303
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: comment
Gerrit-Change-Id: Iba5c5b84760e27245cbe34c3b290c54e51278e72
Gerrit-PatchSet: 16
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
Gerrit-Reviewer: Giuseppe Vallarelli <gvallare(a)redhat.com>
Gerrit-Reviewer: Livnat Peer <lpeer(a)redhat.com>
Gerrit-Reviewer: Mark Wu <wudxw(a)linux.vnet.ibm.com>
Gerrit-Reviewer: oVirt Jenkins CI Server
9 years, 9 months
Change in vdsm[master]: NetReload: netmodels for addNetwork
by wudxw@linux.vnet.ibm.com
Mark Wu has posted comments on this change.
Change subject: NetReload: netmodels for addNetwork
......................................................................
Patch Set 16: (1 inline comment)
....................................................
File vdsm/netconf/ifcfg.py
Line 88: if network:
Line 89: self.configWriter.createLibvirtNetwork(network, False, vlan.name)
Line 90: self._libvirtAdded.add(network)
Line 91:
Line 92: def configureBond(self, bond, network=None, bridge=None, vlan=None,
it looks the parameter vlan is useless here.
Line 93: **opts):
Line 94: ipaddr, netmask, gateway, bootproto, async = bond.getIpConfig()
Line 95: self.configWriter.addBonding(bond.name, bridge=bridge,
Line 96: bondingOptions=bond.options,
--
To view, visit http://gerrit.ovirt.org/14303
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: comment
Gerrit-Change-Id: Iba5c5b84760e27245cbe34c3b290c54e51278e72
Gerrit-PatchSet: 16
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Antoni Segura Puimedon <asegurap(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
Gerrit-Reviewer: Giuseppe Vallarelli <gvallare(a)redhat.com>
Gerrit-Reviewer: Livnat Peer <lpeer(a)redhat.com>
Gerrit-Reviewer: Mark Wu <wudxw(a)linux.vnet.ibm.com>
Gerrit-Reviewer: oVirt Jenkins CI Server
9 years, 9 months
Change in vdsm[master]: Supervdsm didn't create pid file when starting up
by ybronhei@redhat.com
Yaniv Bronhaim has uploaded a new change for review.
Change subject: Supervdsm didn't create pid file when starting up
......................................................................
Supervdsm didn't create pid file when starting up
This cause errors over sysV when trying to perform service operations
Change-Id: I649179ca1c614dfcff91da9fada785c57303f57c
Signed-off-by: Yaniv Bronhaim <ybronhei(a)redhat.com>
---
M vdsm/clientIF.py
M vdsm/supervdsmServer.py
2 files changed, 7 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/96/15196/1
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index 98fdac3..bb3d8cd 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -501,7 +501,7 @@
continue
if f == 'respawn.pid':
continue
- if f == 'svdsm.pid':
+ if f == 'supervdsmd.pid':
continue
if f == 'svdsm.sock':
continue
diff --git a/vdsm/supervdsmServer.py b/vdsm/supervdsmServer.py
index dd6d9ff..6b1a017 100644
--- a/vdsm/supervdsmServer.py
+++ b/vdsm/supervdsmServer.py
@@ -44,7 +44,8 @@
from storage.fileUtils import chown, resolveGid, resolveUid
from storage.fileUtils import validateAccess as _validateAccess
from vdsm.constants import METADATA_GROUP, EXT_UDEVADM, \
- DISKIMAGE_USER, DISKIMAGE_GROUP, P_LIBVIRT_VMCHANNELS, VDSM_USER
+ DISKIMAGE_USER, DISKIMAGE_GROUP, P_LIBVIRT_VMCHANNELS, VDSM_USER, \
+ P_VDSM_RUN
from storage.devicemapper import _removeMapping, _getPathsStatus
import configNetwork
from vdsm.config import config
@@ -358,6 +359,10 @@
if os.geteuid() != 0:
sys.exit(errno.EPERM)
+ pidfile = P_VDSM_RUN + 'supervdsmd.pid'
+ pid = str(os.getpid())
+ file(pidfile, 'w').write(pid + "\n")
+
log.debug("Parsing cmd args")
address = sys.argv[1]
--
To view, visit http://gerrit.ovirt.org/15196
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I649179ca1c614dfcff91da9fada785c57303f57c
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yaniv Bronhaim <ybronhei(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: closing file after writing
by ybronhei@redhat.com
Yaniv Bronhaim has uploaded a new change for review.
Change subject: closing file after writing
......................................................................
closing file after writing
Change-Id: Id328e1482680959ebb55eddc28615e6d6be1545b
Signed-off-by: Yaniv Bronhaim <ybronhei(a)redhat.com>
---
M vdsm/vdsm
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/54/15254/1
diff --git a/vdsm/vdsm b/vdsm/vdsm
index 96e657d..fef86db 100755
--- a/vdsm/vdsm
+++ b/vdsm/vdsm
@@ -83,7 +83,8 @@
pidfile = constants.P_VDSM_RUN + 'vdsmd.pid'
pid = str(os.getpid())
- file(pidfile, 'w').write(pid + "\n")
+ with open(pidfile, 'w') as f:
+ f.write(pid + "\n")
os.chmod(pidfile, 0664)
sysname, nodename, release, version, machine = os.uname()
--
To view, visit http://gerrit.ovirt.org/15254
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id328e1482680959ebb55eddc28615e6d6be1545b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yaniv Bronhaim <ybronhei(a)redhat.com>
9 years, 9 months
Change in vdsm[master]: [WIP] Changing startup and rpc for vdsm and supervdsm
by ybronhei@redhat.com
Yaniv Bronhaim has uploaded a new change for review.
Change subject: [WIP] Changing startup and rpc for vdsm and supervdsm
......................................................................
[WIP] Changing startup and rpc for vdsm and supervdsm
This patch runs vdsm as root, start external process for supervdsm and
drop privileges for vdsm.
Still in progress:
- need to add timestamp for supervdsm process
- define crash senerios
- remove Process and use fork instead
Change-Id: I4f1053e7d1264003fa265e44899d8b02f98bd68a
Signed-off-by: Yaniv Bronhaim <ybronhei(a)redhat.com>
---
M NEWS
M tests/superVdsmTests.py
M tests/testrunner.py
M vdsm.spec.in
M vdsm/supervdsm.py
M vdsm/supervdsmServer.py
M vdsm/vdsm
M vdsm/vdsmd.init.in
8 files changed, 245 insertions(+), 378 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/10/11910/1
diff --git a/NEWS b/NEWS
old mode 100644
new mode 100755
diff --git a/tests/superVdsmTests.py b/tests/superVdsmTests.py
index 87de66d..13164ac 100644
--- a/tests/superVdsmTests.py
+++ b/tests/superVdsmTests.py
@@ -1,73 +1,37 @@
from testrunner import VdsmTestCase as TestCaseBase
import supervdsm
-import testValidation
-import tempfile
-from vdsm import utils
import os
-import uuid
-from vdsm import constants
-from storage import misc
-from monkeypatch import MonkeyPatch
-from time import sleep
-
-
-(a)utils.memoized
-def getNeededPythonPath():
- testDir = os.path.dirname(__file__)
- base = os.path.dirname(testDir)
- vdsmPath = os.path.join(base, 'vdsm')
- cliPath = os.path.join(base, 'vdsm_cli')
- pyPath = "PYTHONPATH=" + ':'.join([base, vdsmPath, cliPath])
- return pyPath
-
-
-def monkeyStart(self):
- self._authkey = str(uuid.uuid4())
- self._log.debug("Launching Super Vdsm")
-
- superVdsmCmd = [getNeededPythonPath(), constants.EXT_PYTHON,
- supervdsm.SUPERVDSM,
- self._authkey, str(os.getpid()),
- self.pidfile, self.timestamp, self.address,
- str(os.getuid())]
- misc.execCmd(superVdsmCmd, sync=False, sudo=True)
- sleep(2)
+from multiprocessing import Process
+from supervdsmServer import SuperVdsmManager
class TestSuperVdsm(TestCaseBase):
+
def setUp(self):
- testValidation.checkSudo(['python', supervdsm.SUPERVDSM])
- self._proxy = supervdsm.getProxy()
-
- # temporary values to run temporary svdsm
- self.pidfd, pidfile = tempfile.mkstemp()
- self.timefd, timestamp = tempfile.mkstemp()
- self.addfd, address = tempfile.mkstemp()
-
- self._proxy.setIPCPaths(pidfile, timestamp, address)
+ self._proxy = None
+ self.svdsmProc = Process(target=SuperVdsmManager.
+ getInstance().restartSvdsm,
+ args=(os.getpid(), ))
+ self.svdsmProc.start()
+ # wait until next process starts
+ self._proxy = supervdsm.SuperVdsmProxy()
def tearDown(self):
- supervdsm.extraPythonPathList = []
- for fd in (self.pidfd, self.timefd, self.addfd):
- os.close(fd)
- self._proxy.kill() # cleanning old temp files
+ try:
+ self._proxy.stopSuperVdsm()
+ # Throwing exception when the server is closed
+ except:
+ pass
- @MonkeyPatch(supervdsm.SuperVdsmProxy, '_start', monkeyStart)
- def testIsSuperUp(self):
- self._proxy.ping() # this call initiate svdsm
- self.assertTrue(self._proxy.isRunning())
+ def testPing(self):
+ if self._proxy.ping():
+ return True
+ else:
+ return False
- @MonkeyPatch(supervdsm.SuperVdsmProxy, '_start', monkeyStart)
- def testKillSuper(self):
- self._proxy.ping()
- self._proxy.kill()
- self.assertFalse(self._proxy.isRunning())
- self._proxy.ping() # Launching vdsm after kill
- self.assertTrue(self._proxy.isRunning())
+ def testStartAndClose(self):
+ return True
- @MonkeyPatch(supervdsm.SuperVdsmProxy, '_start', monkeyStart)
- def testNoPidFile(self):
- self._proxy.ping() # svdsm is up
- self.assertTrue(self._proxy.isRunning())
- utils.rmFile(self._proxy.timestamp)
- self.assertRaises(IOError, self._proxy.isRunning)
+ def testGetDeviceInfo(self):
+ print self._proxy.getLsBlk()
+ return True
diff --git a/tests/testrunner.py b/tests/testrunner.py
index dfe9885..17d150b 100644
--- a/tests/testrunner.py
+++ b/tests/testrunner.py
@@ -28,13 +28,6 @@
from nose import core
from nose import result
-# Monkey patch pthreading in necessary
-if sys.version_info[0] == 2:
- # as long as we work with Python 2, we need to monkey-patch threading
- # module before it is ever used.
- import pthreading
- pthreading.monkey_patch()
-
from testValidation import SlowTestsPlugin
diff --git a/vdsm.spec.in b/vdsm.spec.in
index a6bd24c..01c0c9f 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -40,6 +40,7 @@
# BuildRequires needed by the tests during the build
BuildRequires: python-ethtool
BuildRequires: python-pthreading
+BuildRequires: python-rpyc
BuildRequires: libselinux-python
BuildRequires: libvirt-python
BuildRequires: genisoimage
@@ -76,6 +77,7 @@
Requires: rpm-python
Requires: nfs-utils
Requires: python-pthreading
+Requires: python-rpyc
Requires: m2crypto
Requires: %{name}-xmlrpc = %{version}-%{release}
diff --git a/vdsm/supervdsm.py b/vdsm/supervdsm.py
index 10abae0..51dea2f 100644
--- a/vdsm/supervdsm.py
+++ b/vdsm/supervdsm.py
@@ -21,43 +21,18 @@
import os
from multiprocessing import AuthenticationError
-from multiprocessing.managers import BaseManager
import logging
import threading
-import uuid
-from time import sleep
-from errno import ENOENT, ESRCH
-
-import storage.misc as misc
+import socket
from vdsm import constants, utils
+import rpyc
_g_singletonSupervdsmInstance = None
_g_singletonSupervdsmInstance_lock = threading.Lock()
-def __supervdsmServerPath():
- base = os.path.dirname(__file__)
-
- # serverFile can be both the py or pyc file. In oVirt node we don't keep
- # py files. this method looks for one of the two to calculate the absolute
- # path of supervdsmServer
- for serverFile in ("supervdsmServer.py", "supervdsmServer.pyc"):
- serverPath = os.path.join(base, serverFile)
- if os.path.exists(serverPath):
- return os.path.abspath(serverPath)
-
- raise RuntimeError("SuperVDSM Server not found")
-
-PIDFILE = os.path.join(constants.P_VDSM_RUN, "svdsm.pid")
-TIMESTAMP = os.path.join(constants.P_VDSM_RUN, "svdsm.time")
ADDRESS = os.path.join(constants.P_VDSM_RUN, "svdsm.sock")
-SUPERVDSM = __supervdsmServerPath()
-
-extraPythonPathList = []
-
-
-class _SuperVdsmManager(BaseManager):
- pass
+PORT = 669
class ProxyCaller(object):
@@ -70,22 +45,12 @@
callMethod = lambda: \
getattr(self._supervdsmProxy._svdsm, self._funcName)(*args,
**kwargs)
- if not self._supervdsmProxy.isRunning():
- # getting inside only when svdsm is down. its rare case so we
- # don't care that isRunning will run twice
- with self._supervdsmProxy.proxyLock:
- if not self._supervdsmProxy.isRunning():
- self._supervdsmProxy.launch()
-
try:
return callMethod()
- # handling internal exception that we raise to identify supervdsm
- # validation. only this exception can cause kill!
- except AuthenticationError:
- with self._supervdsmProxy.proxyLock:
- self._supervdsmProxy.kill()
- self._supervdsmProxy.launch()
- return callMethod()
+ except(IOError, socket.error, AuthenticationError):
+ #os.kill(os.getpid(), signal.SIGTERM)
+ print "method couldn't be called\n"
+ raise
class SuperVdsmProxy(object):
@@ -95,106 +60,19 @@
_log = logging.getLogger("SuperVdsmProxy")
def __init__(self):
- self.proxyLock = threading.Lock()
- self._firstLaunch = True
-
- # Declaration of public variables that keep files' names that svdsm
- # uses. We need to be able to change these variables so that running
- # tests doesn't disturb and already running VDSM on the host.
- self.setIPCPaths(PIDFILE, TIMESTAMP, ADDRESS)
-
- def setIPCPaths(self, pidfile, timestamp, address):
- self.pidfile = pidfile
- self.timestamp = timestamp
- self.address = address
-
- def open(self, *args, **kwargs):
- return self._manager.open(*args, **kwargs)
-
- def _cleanOldFiles(self):
- self._log.debug("Cleanning svdsm old files: %s, %s, %s",
- self.pidfile, self.timestamp, self.address)
- for f in (self.pidfile, self.timestamp, self.address):
- utils.rmFile(f)
-
- def _start(self):
- self._authkey = str(uuid.uuid4())
- self._log.debug("Launching Super Vdsm")
-
- # we pass to svdsm filenames and uid. Svdsm will use those filenames
- # to create its internal files and give to the passed uid the
- # permissions to read those files.
- superVdsmCmd = [constants.EXT_PYTHON, SUPERVDSM,
- self._authkey, str(os.getpid()),
- self.pidfile, self.timestamp, self.address,
- str(os.getuid())]
-
- misc.execCmd(superVdsmCmd, sync=False, sudo=True)
- sleep(2)
-
- def kill(self):
try:
- with open(self.pidfile, "r") as f:
- pid = int(f.read().strip())
- misc.execCmd([constants.EXT_KILL, "-9", str(pid)], sudo=True)
- except Exception:
- self._log.error("Could not kill old Super Vdsm %s",
- exc_info=True)
-
- self._cleanOldFiles()
- self._authkey = None
- self._manager = None
- self._svdsm = None
- self._firstLaunch = True
-
- def isRunning(self):
- if self._firstLaunch or self._svdsm is None:
- return False
-
- try:
- with open(self.pidfile, "r") as f:
- spid = f.read().strip()
- with open(self.timestamp, "r") as f:
- createdTime = f.read().strip()
- except IOError as e:
- # pid file and timestamp file must be exist after first launch,
- # otherwise excpetion will be raised to svdsm caller
- if e.errno == ENOENT and self._firstLaunch:
- return False
- else:
- raise
-
- try:
- pTime = str(misc.getProcCtime(spid))
- except OSError as e:
- if e.errno == ESRCH:
- # Means pid is not exist, svdsm was killed
- return False
- else:
- raise
-
- if pTime == createdTime:
- return True
- else:
- return False
+ utils.retry(self._connect, Exception, tries=3, sleep=3)
+ self._log.debug("Connected to Super Vdsm")
+ except:
+ print("Could not init super vdsm proxy")
def _connect(self):
- self._manager = _SuperVdsmManager(address=self.address,
- authkey=self._authkey)
- self._manager.register('instance')
- self._manager.register('open')
- self._log.debug("Trying to connect to Super Vdsm")
try:
- self._manager.connect()
- except Exception as ex:
- self._log.warn("Connect to svdsm failed %s", ex)
+ self._manager = rpyc.connect('localhost', PORT)
+ except Exception, ex:
+ print("Connect failed %s", ex)
raise
- self._svdsm = self._manager.instance()
-
- def launch(self):
- self._firstLaunch = False
- self._start()
- utils.retry(self._connect, Exception, timeout=60)
+ self._svdsm = self._manager.root
def __getattr__(self, name):
return ProxyCaller(self, name)
diff --git a/vdsm/supervdsmServer.py b/vdsm/supervdsmServer.py
index 83a5803..1924e2a 100755
--- a/vdsm/supervdsmServer.py
+++ b/vdsm/supervdsmServer.py
@@ -24,10 +24,11 @@
import os
import stat
import errno
-import threading
import re
from time import sleep
import signal
+import threading
+from supervdsm import PORT
from multiprocessing import Pipe, Process
from gluster import cli as gcli
import storage.misc as misc
@@ -38,13 +39,14 @@
from lsblk import getLsBlk as _getLsBlk
from storage.multipath import getScsiSerial as _getScsiSerial
from storage.iscsi import forceIScsiScan as _forceIScsiScan
-from storage.iscsi import getDevIscsiInfo as _getdeviSCSIinfo
from storage.iscsi import readSessionInfo as _readSessionInfo
-from supervdsm import _SuperVdsmManager
-from storage.fileUtils import chown, resolveGid, resolveUid
+from storage.iscsi import getDevIscsiInfo as _getdeviSCSIinfo
+from storage.fileUtils import resolveGid, resolveUid
from storage.fileUtils import validateAccess as _validateAccess
-from vdsm.constants import METADATA_GROUP, EXT_UDEVADM, \
+from vdsm.constants import EXT_UDEVADM, \
DISKIMAGE_USER, DISKIMAGE_GROUP, P_LIBVIRT_VMCHANNELS
+# P_VDSM_RUN
+
from storage.devicemapper import _removeMapping, _getPathsStatus
import configNetwork
from vdsm.config import config
@@ -53,12 +55,17 @@
import mkimage
from storage.multipath import MPATH_CONF
import zombieReaper
+import rpyc
+from rpyc.utils.server import ThreadedServer
+
_UDEV_RULE_FILE_DIR = "/etc/udev/rules.d/"
_UDEV_RULE_FILE_PREFIX = "99-vdsm-"
_UDEV_RULE_FILE_EXT = ".rules"
_UDEV_RULE_FILE_NAME = _UDEV_RULE_FILE_DIR + _UDEV_RULE_FILE_PREFIX + \
"%s-%s" + _UDEV_RULE_FILE_EXT
+#PIDFILE = P_VDSM_RUN + 'svdsm.pid'
+PIDFILE = '/tmp/file'
RUN_AS_TIMEOUT = config.getint("irs", "process_pool_timeout")
@@ -83,19 +90,18 @@
LOG_CONF_PATH = "/etc/vdsm/logger.conf"
-class _SuperVdsm(object):
+class _SuperVdsmService(rpyc.Service):
UDEV_WITH_RELOAD_VERSION = 181
-
log = logging.getLogger("SuperVdsm.ServerCallback")
@logDecorator
- def ping(self, *args, **kwargs):
+ def exposed_ping(self, *args, **kwargs):
# This method exists for testing purposes
return True
@logDecorator
- def getHardwareInfo(self, *args, **kwargs):
+ def exposed_getHardwareInfo(self, *args, **kwargs):
if platform.machine() in ('x86_64', 'i686'):
from dmidecodeUtil import getHardwareInfoStructure
return getHardwareInfoStructure()
@@ -104,53 +110,56 @@
return {}
@logDecorator
- def getDevicePartedInfo(self, *args, **kwargs):
+ def exposed_getDevicePartedInfo(self, *args, **kwargs):
return _getDevicePartedInfo(*args, **kwargs)
@logDecorator
- def getMdDeviceUuidMap(self, *args, **kwargs):
+ def exposed_getMdDeviceUuidMap(self, *args, **kwargs):
return _getMdDeviceUuidMap(*args, **kwargs)
@logDecorator
- def getLsBlk(self, *args, **kwargs):
+ def exposed_getLsBlk(self, *args, **kwargs):
return _getLsBlk(*args, **kwargs)
@logDecorator
- def readMultipathConf(self):
+ def exposed_stopSuperVdsm(self):
+ SuperVdsmManager.getInstance().closeServer()
+
+ @logDecorator
+ def exposed_readMultipathConf(self):
with open(MPATH_CONF) as f:
return [x.strip("\n") for x in f.readlines()]
@logDecorator
- def getScsiSerial(self, *args, **kwargs):
+ def exposed_getScsiSerial(self, *args, **kwargs):
return _getScsiSerial(*args, **kwargs)
@logDecorator
- def forceIScsiScan(self, *args, **kwargs):
+ def exposed_forceIScsiScan(self, *args, **kwargs):
return _forceIScsiScan(*args, **kwargs)
@logDecorator
- def removeDeviceMapping(self, devName):
+ def exposed_removeDeviceMapping(self, devName):
return _removeMapping(devName)
@logDecorator
- def getdeviSCSIinfo(self, *args, **kwargs):
+ def exposed_getdeviSCSIinfo(self, *args, **kwargs):
return _getdeviSCSIinfo(*args, **kwargs)
@logDecorator
- def readSessionInfo(self, sessionID):
+ def exposed_readSessionInfo(self, sessionID):
return _readSessionInfo(sessionID)
- @logDecorator
- def getPathsStatus(self):
+ def exposed_getPathsStatus(self):
return _getPathsStatus()
@logDecorator
- def getVmPid(self, vmName):
+ def exposed_getVmPid(self, vmName):
pidFile = "/var/run/libvirt/qemu/%s.pid" % vmName
return open(pidFile).read()
@logDecorator
- def prepareVmChannel(self, socketFile):
+ def exposed_prepareVmChannel(self, socketFile):
if socketFile.startswith(P_LIBVIRT_VMCHANNELS):
mode = os.stat(socketFile).st_mode | stat.S_IWGRP
os.chmod(socketFile, mode)
@@ -158,19 +167,19 @@
raise Exception("Incorporate socketFile")
@logDecorator
- def addNetwork(self, bridge, options):
+ def exposed_addNetwork(self, bridge, options):
return configNetwork.addNetwork(bridge, **options)
@logDecorator
- def delNetwork(self, bridge, options):
+ def exposed_delNetwork(self, bridge, options):
return configNetwork.delNetwork(bridge, **options)
@logDecorator
- def editNetwork(self, oldBridge, newBridge, options):
+ def exposed_editNetwork(self, oldBridge, newBridge, options):
return configNetwork.editNetwork(oldBridge, newBridge, **options)
@logDecorator
- def setupNetworks(self, networks={}, bondings={}, options={}):
+ def exposed_setupNetworks(self, networks={}, bondings={}, options={}):
return configNetwork.setupNetworks(networks, bondings, **options)
def _runAs(self, user, groups, func, args=(), kwargs={}):
@@ -216,17 +225,16 @@
return res
@logDecorator
- def validateAccess(self, user, groups, *args, **kwargs):
+ def exposed_validateAccess(self, user, groups, *args, **kwargs):
return self._runAs(user, groups, _validateAccess, args=args,
kwargs=kwargs)
@logDecorator
- def setSafeNetworkConfig(self):
+ def exposed_setSafeNetworkConfig(self):
return configNetwork.setSafeNetworkConfig()
@logDecorator
- def udevTrigger(self, guid):
- self.__udevReloadRules(guid)
+ def exposed_udevTrigger(self, guid):
cmd = [EXT_UDEVADM, 'trigger', '--verbose', '--action', 'change',
'--property-match=DM_NAME=%s' % guid]
rc, out, err = misc.execCmd(cmd, sudo=False)
@@ -235,7 +243,7 @@
%s, out %s\nerr %s" % (guid, out, err))
@logDecorator
- def appropriateDevice(self, guid, thiefId):
+ def exposed_appropriateDevice(self, guid, thiefId):
ruleFile = _UDEV_RULE_FILE_NAME % (guid, thiefId)
rule = 'SYMLINK=="mapper/%s", OWNER="%s", GROUP="%s"\n' % (guid,
DISKIMAGE_USER, DISKIMAGE_GROUP)
@@ -243,7 +251,7 @@
rf.write(rule)
@logDecorator
- def rmAppropriateRules(self, thiefId):
+ def exposed_rmAppropriateRules(self, thiefId):
re_apprDevRule = "^" + _UDEV_RULE_FILE_PREFIX + ".*?-" + thiefId + \
_UDEV_RULE_FILE_EXT + "$"
rules = [os.path.join(_UDEV_RULE_FILE_DIR, r) for r in
@@ -258,7 +266,7 @@
return fails
@logDecorator
- def ksmTune(self, tuningParams):
+ def exposed_ksmTune(self, tuningParams):
'''
Set KSM tuning parameters for MOM, which runs without root privilege
when it's lauched by vdsm. So it needs supervdsm's assistance to tune
@@ -267,7 +275,7 @@
return ksm.tune(tuningParams)
@logDecorator
- def setPortMirroring(self, networkName, ifaceName):
+ def exposed_setPortMirroring(self, networkName, ifaceName):
'''
Copy networkName traffic of a bridge to an interface
@@ -282,7 +290,7 @@
tc.setPortMirroring(networkName, ifaceName)
@logDecorator
- def unsetPortMirroring(self, networkName, target):
+ def exposed_unsetPortMirroring(self, networkName, target):
'''
Release captured mirror networkName traffic from networkName bridge
@@ -294,15 +302,15 @@
tc.unsetPortMirroring(networkName, target)
@logDecorator
- def mkFloppyFs(self, vmId, files):
+ def exposed_mkFloppyFs(self, vmId, files):
return mkimage.mkFloppyFs(vmId, files)
@logDecorator
- def mkIsoFs(self, vmId, files):
+ def exposed_mkIsoFs(self, vmId, files):
return mkimage.mkIsoFs(vmId, files)
@logDecorator
- def removeFs(self, path):
+ def exposed_removeFs(self, path):
return mkimage.removeFs(path)
def __udevReloadRules(self, guid):
@@ -332,95 +340,100 @@
return self.__udevVersion() > self.UDEV_WITH_RELOAD_VERSION
-def __pokeParent(parentPid, address, log):
- try:
- while True:
- os.kill(parentPid, 0)
- sleep(2)
- except Exception:
- utils.rmFile(address)
- log.debug("Killing SuperVdsm Process")
- os.kill(os.getpid(), signal.SIGTERM)
-
-
-def main():
+def bound_gluster():
def bind(func):
- def wrapper(_SuperVdsm, *args, **kwargs):
+ def wrapper(_SuperVdsmService, *args, **kwargs):
return func(*args, **kwargs)
return wrapper
for name in dir(gcli):
func = getattr(gcli, name)
if getattr(func, 'superVdsm', False):
- setattr(_SuperVdsm,
+ setattr(_SuperVdsmService,
'gluster%s%s' % (name[0].upper(), name[1:]),
logDecorator(bind(func)))
- try:
- logging.config.fileConfig(LOG_CONF_PATH)
- except:
- logging.basicConfig(filename='/dev/stdout', filemode='w+',
- level=logging.DEBUG)
- log = logging.getLogger("SuperVdsm.Server")
- log.warn("Could not init proper logging", exc_info=True)
- log = logging.getLogger("SuperVdsm.Server")
+class SuperVdsmManager():
- try:
- log.debug("Making sure I'm root")
- if os.geteuid() != 0:
- sys.exit(errno.EPERM)
+ _instance = None
+ _server = None
- log.debug("Parsing cmd args")
- authkey, parentPid, pidfile, timestamp, address, uid = sys.argv[1:]
+ @classmethod
+ def getInstance(cls):
+ if not cls._instance:
+ cls._instance = SuperVdsmManager()
+ return cls._instance
- log.debug("Creating PID and TIMESTAMP files: %s, %s",
- pidfile, timestamp)
- spid = os.getpid()
- with open(pidfile, "w") as f:
- f.write(str(spid) + "\n")
- with open(timestamp, "w") as f:
- f.write(str(misc.getProcCtime(spid) + "\n"))
-
- log.debug("Cleaning old socket %s", address)
- if os.path.exists(address):
- os.unlink(address)
-
- zombieReaper.registerSignalHandler()
-
- log.debug("Setting up keep alive thread")
-
- monThread = threading.Thread(target=__pokeParent,
- args=[int(parentPid), address, log])
- monThread.setDaemon(True)
- monThread.start()
-
+ def __pokeParent(self, parentPid):
try:
- log.debug("Creating remote object manager")
- manager = _SuperVdsmManager(address=address, authkey=authkey)
- manager.register('instance', callable=_SuperVdsm)
+ while True:
+ os.kill(parentPid, 0)
+ sleep(2)
+ except Exception:
+ os.kill(os.getpid(), signal.SIGKILL)
- server = manager.get_server()
- servThread = threading.Thread(target=server.serve_forever)
- servThread.setDaemon(True)
- servThread.start()
+ def initLog(self):
+ try:
+ logging.config.fileConfig(LOG_CONF_PATH)
+ except:
+ logging.basicConfig(filename='/dev/stdout', filemode='w+',
+ level=logging.DEBUG)
- for f in (address, timestamp, pidfile):
- chown(f, int(uid), METADATA_GROUP)
+ log = logging.getLogger("SuperVdsm.Server")
+ return log
- log.debug("Started serving super vdsm object")
+ def closeServer(self):
+ if self._server is not None:
+ self._server.close()
+ self._server = None
- # Python bug of thread.join() will block signal
- # http://bugs.python.org/issue1167930
- while servThread.isAlive():
- servThread.join(5)
+ def initServer(self):
+ try:
+ self._server = ThreadedServer(_SuperVdsmService,
+ port=PORT)
+ except Exception:
+ raise
+
+ def _killSupervdsm(self):
+ try:
+ with open(PIDFILE, "r") as f:
+ pid = int(f.read().strip())
+ # TODO: should check timestamp?
+ os.kill(pid, signal.SIGKILL)
+ except:
+ pass
+
+ def restartSvdsm(self, vdsmPid):
+ bound_gluster()
+ self.log = self.initLog()
+ try:
+ self.log.debug("closing old instance of supervdsm")
+
+ # kill old supervdsm
+ self._killSupervdsm()
+
+ self.log.debug("starting supervdsm server")
+ utils.retry(self.initServer, Exception, sleep=3, tries=3)
+ self.log.debug("Creating PID file %d", os.getpid())
+
+ # TODO: need to save timestamp before cleanning the old instance
+ with open(PIDFILE, "w") as f:
+ f.write(str(os.getpid()) + "\n")
+
+ self.log.debug("Cleaning old socket")
+
+ self.log.debug("Setting up keep alive thread")
+ monThread = threading.Thread(target=self.__pokeParent,
+ args=[int(vdsmPid)])
+ monThread.setDaemon(True)
+ monThread.start()
+
+ self.log.debug("Started serving super vdsm object")
+ self._server.start()
+
+ except Exception:
+ self.log.error("Could not start Super Vdsm", exc_info=True)
+ sys.exit(1)
finally:
- if os.path.exists(address):
- utils.rmFile(address)
-
- except Exception:
- log.error("Could not start Super Vdsm", exc_info=True)
- sys.exit(1)
-
-if __name__ == '__main__':
- main()
+ self.log.debug("super vdsm server is closed")
diff --git a/vdsm/vdsm b/vdsm/vdsm
index 4746a0f..dc9b679 100755
--- a/vdsm/vdsm
+++ b/vdsm/vdsm
@@ -10,31 +10,46 @@
import os
import sys
-import getopt
import signal
-import getpass
-import pwd
-import grp
import threading
import logging
-import syslog
from logging import config as lconfig
+from pwd import getpwnam
+from multiprocessing import Process
-from vdsm import constants
-import zombieReaper
-import dsaversion
if sys.version_info[0] == 2:
# as long as we work with Python 2, we need to monkey-patch threading
# module before it is ever used.
import pthreading
pthreading.monkey_patch()
-loggerConfFile = constants.P_VDSM_CONF + 'logger.conf'
+from vdsm.constants import VDSM_USER, VDSM_GROUP, \
+ P_VDSM_RUN, P_VDSM_CONF
+import dsaversion
+from supervdsmServer import SuperVdsmManager
+from storage.fileUtils import chown
+from supervdsm import getProxy
+from clientIF import clientIF
+import zombieReaper
def usage():
print "Usage: vdsm [OPTIONS]"
print " -h - Display this help message"
+
+loggerConfFile = P_VDSM_CONF + 'logger.conf'
+LOGFILE = '/var/log/vdsm/vdsm.log'
+
+
+def vdsmExit():
+ try:
+ cif = clientIF.getInstance()
+ cif.prepareForShutdown()
+ pass
+ except:
+ pass
+ finally:
+ getProxy().stopSuperVdsm()
def serve_clients(log):
@@ -43,6 +58,7 @@
def sigtermHandler(signum, frame):
if cif:
cif.prepareForShutdown()
+ vdsmExit()
def sigusr1Handler(signum, frame):
if cif and cif.irs:
@@ -58,7 +74,7 @@
cif.serve()
-def run():
+def initLogger():
lconfig.fileConfig(loggerConfFile)
logging.addLevelName(5, 'TRACE')
logging.TRACE = 5 # impolite but helpful
@@ -78,8 +94,26 @@
try:
logging.root.handlers.append(logging.StreamHandler())
log.handlers.append(logging.StreamHandler())
+ chown(LOGFILE, VDSM_USER, VDSM_GROUP)
+ except:
+ log.error("Exception raised", exc_info=True)
+ return log
- pidfile = constants.P_VDSM_RUN + 'vdsmd.pid'
+
+def startVdsm(log):
+ def dropPrivileges():
+ if os.getuid() != 0:
+ log.error("should start vdsm with root")
+ sys.exit(1)
+ vdsm_uid, vdsm_gid = getpwnam(VDSM_USER)[2:4:]
+
+ os.setgroups([])
+ os.setgid(vdsm_gid)
+ os.setuid(vdsm_uid)
+
+ try:
+ dropPrivileges()
+ pidfile = P_VDSM_RUN + 'vdsmd.pid'
file(pidfile, 'w').write(str(os.getpid()) + "\n")
os.chmod(pidfile, 0664)
@@ -89,59 +123,42 @@
nodename, release)
serve_clients(log)
except:
- log.error("Exception raised", exc_info=True)
-
- log.info("VDSM main thread ended. Waiting for %d other threads..." %
- (threading.activeCount() - 1))
- for t in threading.enumerate():
- if hasattr(t, 'stop'):
- t.stop()
- log.info(str(t))
+ log.error("start vdsm failed", exc_info=True)
+ raise
+ finally:
+ log.info("VDSM main thread ended. Waiting for %d other threads..."
+ % (threading.activeCount() - 1))
+ for t in threading.enumerate():
+ if hasattr(t, 'stop'):
+ t.stop()
+ log.info(str(t))
-def parse_args():
- opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
- for o, v in opts:
- o = o.lower()
- if o == "-h" or o == "--help":
- usage()
- sys.exit(0)
-
- if len(args) >= 1:
- usage()
- sys.exit(1)
-
-
-def __assertLogPermission():
- if not os.access(constants.P_VDSM_LOG, os.W_OK):
- syslog.syslog("vdsm log directory is not accessible")
- sys.exit(1)
-
- logfile = constants.P_VDSM_LOG + "/vdsm.log"
- if not os.path.exists(logfile):
- # if file not exist, and vdsm has an access to log directory- continue
- return
-
- if not os.access(logfile, os.W_OK):
- syslog.syslog("error in accessing vdsm log file")
- sys.exit(1)
-
-
-def __assertVdsmUser():
- username = getpass.getuser()
- if username != constants.VDSM_USER:
- syslog.syslog("VDSM failed to start: running user is not %s, trying "
- "to run from user %s" % (constants.VDSM_USER, username))
- sys.exit(1)
- group = grp.getgrnam(constants.VDSM_GROUP)
- if (constants.VDSM_USER not in group.gr_mem) and \
- (pwd.getpwnam(constants.VDSM_USER).pw_gid != group.gr_gid):
- syslog.syslog("VDSM failed to start: vdsm user is not in KVM group")
- sys.exit(1)
+def __waitSvdsm(svdsmProc):
+ logger.info("wait for svdsm start")
+ try:
+ svdsmProc.join()
+ except Exception:
+ logger.error("error occurs when waiting svdsm")
+ finally:
+ logger.info("supervdsm exited, prepare to restart")
+ vdsmExit()
if __name__ == '__main__':
- __assertVdsmUser()
- __assertLogPermission()
os.setpgrp()
- parse_args()
- run()
+ logger = initLogger()
+ cif = None
+
+ # When key is None, connections are restricted to child processes
+ vdsmPid = os.getpid()
+ svdsmProc = Process(target=SuperVdsmManager.
+ getInstance().restartSvdsm, args=(vdsmPid, ))
+ try:
+ svdsmProc.start()
+ waitThread = threading.Thread(target=__waitSvdsm,
+ args=[svdsmProc])
+ waitThread.setDaemon(True)
+ waitThread.start()
+ startVdsm(logger)
+ except:
+ vdsmExit()
diff --git a/vdsm/vdsmd.init.in b/vdsm/vdsmd.init.in
index 1f845c6..f15264c 100755
--- a/vdsm/vdsmd.init.in
+++ b/vdsm/vdsmd.init.in
@@ -499,7 +499,7 @@
LIBVIRT_LOG_FILTERS=`$GETCONFITEM $CONF_FILE vars libvirt_log_filters "1:libvirt 1:remote"` \
LIBVIRT_LOG_OUTPUTS=`$GETCONFITEM $CONF_FILE vars libvirt_log_outputs "1:file:/var/log/vdsm/libvirt.log"` \
- LC_ALL=C NICELEVEL=$vdsm_nice daemon --user=vdsm @VDSMDIR@/respawn --minlifetime 10 --daemon --masterpid $RESPAWNPIDFILE $VDSM_BIN
+ LC_ALL=C NICELEVEL=$vdsm_nice daemon @VDSMDIR@/respawn --minlifetime 10 --daemon --masterpid $RESPAWNPIDFILE $VDSM_BIN
RETVAL=$?
[ "$RETVAL" -eq 0 ] && log_success_msg $"$prog start" || log_failure_msg $"$prog start"
[ "$RETVAL" -eq 0 ] && touch /var/lock/subsys/vdsmd
--
To view, visit http://gerrit.ovirt.org/11910
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4f1053e7d1264003fa265e44899d8b02f98bd68a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yaniv Bronhaim <ybronhei(a)redhat.com>
9 years, 9 months