Hello Ayal Baron, Bala.FA, Saggi Mizrahi, Federico Simoncelli, Dan Kenigsberg,
I'd like you to do a code review. Please visit
http://gerrit.ovirt.org/9671
to review the following change.
Change subject: Added gluster hooks support
......................................................................
Added gluster hooks support
New verbs:
* glusterEnableHook,
* glusterDisableHook
* glusterHooksList:
Output structure:
{GLUSTERCOMMAND: {'preHooks': 'enabled': [HOOK1, HOOK2, ...],
'disabled': [HOOK1, HOOK2, ...]},
{'postHooks': 'enabled': [HOOK1, HOOK2, ...],
'disabled': [HOOK1, HOOK2, ...]}, ...}
Change-Id: I3918aa035d90967f1297dc7fadcf14b6a9385c45
Signed-off-by: Timothy Asir <tjeyasin(a)redhat.com>
---
M vdsm/gluster/api.py
M vdsm/gluster/cli.py
M vdsm/gluster/exception.py
M vdsm_cli/vdsClientGluster.py
4 files changed, 247 insertions(+), 65 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/71/9671/1
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index b4c01c7..9aa8bb5 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -211,6 +211,18 @@
def volumeProfileStop(self, volumeName, options=None):
self.svdsmProxy.glusterVolumeProfileStop(volumeName)
+ @exportAsVerb
+ def hooksList(self, options=None):
+ return self.svdsmProxy.glusterHooksList()
+
+ @exportAsVerb
+ def enableHook(self, glusterCmd, level, hookName, options=None):
+ self.svdsmProxy.glusterEnableHook(glusterCmd, level, hookName)
+
+ @exportAsVerb
+ def disableHook(self, glusterCmd, level, hookName, options=None):
+ self.svdsmProxy.glusterDisableHook(glusterCmd, level, hookName)
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index c2c3542..abad8cb 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -18,6 +18,7 @@
# Refer to the README and COPYING files for full details of the license
#
+import os
import xml.etree.cElementTree as etree
from functools import wraps
@@ -29,6 +30,7 @@
_glusterCommandPath = utils.CommandPath("gluster",
"/usr/sbin/gluster",
)
+_glusterHooksPath = '/var/lib/glusterfs/hooks/1'
def _getGlusterVolCmd():
@@ -70,6 +72,16 @@
class TransportType:
TCP = 'TCP'
RDMA = 'RDMA'
+
+
+class HookLevel:
+ PRE = 'pre'
+ POST = 'post'
+
+
+class HookStatus:
+ ENABLE = 'S'
+ DISABLE = 'K'
def _execGluster(cmd):
@@ -754,3 +766,74 @@
except ge.GlusterCmdFailedException, e:
raise ge.GlusterVolumeProfileStopFailedException(rc=e.rc, err=e.err)
return True
+
+
+@exportToSuperVdsm
+def hooksList():
+ """
+ Returns:
+ {GLUSTERCOMMAND: {'preHooks': 'enabled': [HOOK1, HOOK2, ...],
+ 'disabled': [HOOK1, HOOK2, ...]},
+ {'postHooks': 'enabled': [HOOK1, HOOK2, ...],
+ 'disabled': [HOOK1, HOOK2, ...]}, ...}
+ """
+ def getEnabledHooks(files):
+ return [f[1:] for f in files if f.startswith(HookStatus.ENABLE)]
+
+ def getDisabledHooks(files):
+ return [f[1:] for f in files if f.startswith(HookStatus.DISABLE)]
+ hooks = {}
+ try:
+ for glusterCmd in os.listdir(_glusterHooksPath):
+ preList = os.listdir(os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel.PRE))
+ postList = os.listdir(os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel.POST))
+ hooks[glusterCmd] = \
+ {"preHooks": {"enabled": getEnabledHooks(preList),
+ "disabled": getDisabledHooks(preList)},
+ "postHooks": {"enabled": getEnabledHooks(postList),
+ "disabled": getDisabledHooks(postList)}}
+ except OSError, e:
+ raise ge.GlusterHookListException(err=[str(e)])
+ return hooks
+
+
+@exportToSuperVdsm
+def enableHook(glusterCmd, HookLevel, hookName):
+ enabledFile = os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel, "S%s" % hookName)
+ disabledFile = os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel, "K%s" % hookName)
+ if os.path.exists(disabledFile):
+ try:
+ os.rename(disabledFile, enabledFile)
+ return True
+ except OSError, e:
+ raise ge.GlusterEnableHookFailedException(err=[str(e)])
+ if os.path.exists(enabledFile):
+ raise ge.GlusterHookAlreadyEnabledException(
+ glusterCmd, HookLevel, hookName)
+ else:
+ raise ge.GlusterHookNotFoundException(
+ glusterCmd, HookLevel, hookName)
+
+
+@exportToSuperVdsm
+def disableHook(glusterCmd, HookLevel, hookName):
+ enabledFile = os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel, "S%s" % hookName)
+ disabledFile = os.path.join(
+ _glusterHooksPath, glusterCmd, HookLevel, "K%s" % hookName)
+ if os.path.exists(enabledFile):
+ try:
+ os.rename(enabledFile, disabledFile)
+ return True
+ except OSError, e:
+ raise ge.GlusterDisableHookFailedException(err=[str(e)])
+ if os.path.exists(disabledFile):
+ raise ge.GlusterHookAlreadyDisabledException(
+ glusterCmd, HookLevel, hookName)
+ else:
+ raise ge.GlusterHookNotFoundException(
+ glusterCmd, HookLevel, hookName)
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index 13cff62..9159801 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -346,6 +346,52 @@
message = "Volume profile stop failed"
+class GlusterEnableHookFailedException(GlusterVolumeException):
+ code = 4168
+ message = "enable gluster hooks failed"
+
+
+class GlusterDisableHookFailedException(GlusterVolumeException):
+ code = 4169
+ message = "disable gluster hooks failed"
+
+
+class GlusterHookAlreadyEnabledException(GlusterVolumeException):
+ code = 4170
+
+ def __init__(self, glusterCmd, level, hookName):
+ self.glusterCmd = glusterCmd
+ self.level = level
+ self.hookName = hookName
+ self.message = \
+ 'Hook %s of command %s, level %s already enabled' % \
+ (hookName, glusterCmd, level)
+
+
+class GlusterHookAlreadyDisabledException(GlusterVolumeException):
+ code = 4171
+
+ def __init__(self, glusterCmd, level, hookName):
+ self.glusterCmd = glusterCmd
+ self.level = level
+ self.hookName = hookName
+ self.message = \
+ 'Hook %s of command %s, level %s already disabled' % \
+ (hookName, glusterCmd, level)
+
+
+class GlusterHookNotFoundException(GlusterVolumeException):
+ code = 4172
+
+ def __init__(self, glusterCmd, level, hookName):
+ self.glusterCmd = glusterCmd
+ self.level = level
+ self.hookName = hookName
+ self.message = \
+ 'Hook %s for gluster command %s of action %s not found' % \
+ (hookName, level, glusterCmd)
+
+
# Host
class GlusterHostException(GlusterException):
code = 4400
diff --git a/vdsm_cli/vdsClientGluster.py b/vdsm_cli/vdsClientGluster.py
index 25e7dc6..3712955 100644
--- a/vdsm_cli/vdsClientGluster.py
+++ b/vdsm_cli/vdsClientGluster.py
@@ -257,38 +257,61 @@
status = self.s.glusterVolumeProfileStop(args[0])
return status['status']['code'],
status['status']['message']
+ def do_glusterHooksList(self, args):
+ status = self.s.glusterHooksList()
+ pp.pprint(status)
+ return status['status']['code'],
status['status']['message']
+
+ def do_glusterEnableHook(self, args):
+ params = self._eqSplit(args)
+ glusterCmd = params.get('glusterCommand', '')
+ level = params.get('level', '')
+ hookName = params.get('hookName', '')
+
+ status = self.s.glusterEnableHook(glusterCmd, level, hookName)
+ return status['status']['code'],
status['status']['message']
+
+ def do_glusterDisableHook(self, args):
+ params = self._eqSplit(args)
+ glusterCmd = params.get('glusterCommand', '')
+ level = params.get('level', '')
+ hookName = params.get('hookName', '')
+
+ status = self.s.glusterDisableHook(glusterCmd, level, hookName)
+ return status['status']['code'],
status['status']['message']
+
def getGlusterCmdDict(serv):
- return {
- 'glusterVolumeCreate':
- (serv.do_glusterVolumeCreate,
- ('volumeName=<volume_name> bricks=<brick[,brick, ...]>
'
- '[replica=<count>] [stripe=<count>]
[transport={tcp|rdma}]\n\t'
- '<volume_name> is name of new volume',
- '<brick[,brick, ...]> is brick(s) which will be used to '
- 'create volume',
- 'create gluster volume'
- )),
- 'glusterVolumesList':
- (serv.do_glusterVolumesList,
+ return \
+ {'glusterVolumeCreate': (
+ serv.do_glusterVolumeCreate,
+ ('volumeName=<volume_name> bricks=<brick[,brick, ...]> '
+ '[replica=<count>] [stripe=<count>]
[transport={tcp|rdma}]\n\t'
+ '<volume_name> is name of new volume',
+ '<brick[,brick, ...]> is brick(s) which will be used to '
+ 'create volume',
+ 'create gluster volume'
+ )),
+ 'glusterVolumesList': (
+ serv.do_glusterVolumesList,
('[volumeName=<volume_name>]\n\t'
'<volume_name> is existing volume name',
'list all or given gluster volume details'
)),
- 'glusterVolumeStart':
- (serv.do_glusterVolumeStart,
+ 'glusterVolumeStart': (
+ serv.do_glusterVolumeStart,
('volumeName=<volume_name> [force={yes|no}]\n\t'
'<volume_name> is existing volume name',
'start gluster volume'
)),
- 'glusterVolumeStop':
- (serv.do_glusterVolumeStop,
+ 'glusterVolumeStop': (
+ serv.do_glusterVolumeStop,
('volumeName=<volume_name> [force={yes|no}]\n\t'
'<volume_name> is existing volume name',
'stop gluster volume'
)),
- 'glusterVolumeBrickAdd':
- (serv.do_glusterVolumeBrickAdd,
+ 'glusterVolumeBrickAdd': (
+ serv.do_glusterVolumeBrickAdd,
('volumeName=<volume_name> bricks=<brick[,brick, ...]>
'
'[replica=<count>] [stripe=<count>]\n\t'
'<volume_name> is existing volume name\n\t'
@@ -296,132 +319,132 @@
'the volume',
'add bricks to gluster volume'
)),
- 'glusterVolumeSet':
- (serv.do_glusterVolumeSet,
+ 'glusterVolumeSet': (
+ serv.do_glusterVolumeSet,
('volumeName=<volume_name> option=<option>
value=<value>\n\t'
'<volume_name> is existing volume name\n\t'
'<option> is volume option\n\t'
'<value> is value to volume option',
'set gluster volume option'
)),
- 'glusterVolumeSetOptionsList':
- (serv.do_glusterVolumeSetOptionsList,
+ 'glusterVolumeSetOptionsList': (
+ serv.do_glusterVolumeSetOptionsList,
('',
'list gluster volume set options'
)),
- 'glusterVolumeReset':
- (serv.do_glusterVolumeReset,
+ 'glusterVolumeReset': (
+ serv.do_glusterVolumeReset,
('volumeName=<volume_name> [option=<option>]
[force={yes|no}]\n\t'
'<volume_name> is existing volume name',
'reset gluster volume or volume option'
)),
- 'glusterHostAdd':
- (serv.do_glusterHostAdd,
+ 'glusterHostAdd': (
+ serv.do_glusterHostAdd,
('hostName=<host>\n\t'
'<host> is hostname or ip address of new server',
'add new server to gluster cluster'
)),
- 'glusterVolumeRebalanceStart':
- (serv.do_glusterVolumeRebalanceStart,
+ 'glusterVolumeRebalanceStart': (
+ serv.do_glusterVolumeRebalanceStart,
('<volume_name>\n\t<volume_name> is existing volume
name',
'start volume rebalance'
)),
- 'glusterVolumeRebalanceStop':
- (serv.do_glusterVolumeRebalanceStop,
+ 'glusterVolumeRebalanceStop': (
+ serv.do_glusterVolumeRebalanceStop,
('<volume_name>\n\t<volume_name> is existing volume
name',
'stop volume rebalance'
)),
- 'glusterVolumeRebalanceStatus':
- (serv.do_glusterVolumeRebalanceStatus,
+ 'glusterVolumeRebalanceStatus': (
+ serv.do_glusterVolumeRebalanceStatus,
('<volume_name>\n\t<volume_name> is existing volume
name',
'get volume rebalance status'
)),
- 'glusterVolumeDelete':
- (serv.do_glusterVolumeDelete,
+ 'glusterVolumeDelete': (
+ serv.do_glusterVolumeDelete,
('volumeName=<volume_name> \n\t<volume_name> is existing
'
'volume name',
'delete gluster volume'
)),
- 'glusterHostRemove':
- (serv.do_glusterHostRemove,
+ 'glusterHostRemove': (
+ serv.do_glusterHostRemove,
('hostName=<host> [force={yes|no}]\n\t'
'<host> is hostname or ip address of a server in '
'gluster cluster',
'remove server from gluster cluster'
)),
- 'glusterVolumeReplaceBrickStart':
- (serv.do_glusterVolumeReplaceBrickStart,
+ 'glusterVolumeReplaceBrickStart': (
+ serv.do_glusterVolumeReplaceBrickStart,
('<volume_name> <existing_brick> <new_brick>
\n\t<volume_name> '
'is existing volume name\n\t<brick> is existing brick\n\t'
'<new_brick> is new brick',
'start volume replace brick'
)),
- 'glusterVolumeReplaceBrickAbort':
- (serv.do_glusterVolumeReplaceBrickAbort,
+ 'glusterVolumeReplaceBrickAbort': (
+ serv.do_glusterVolumeReplaceBrickAbort,
('<volume_name> <existing_brick> <new_brick>
\n\t<volume_name> '
'is existing volume name\n\t<brick> is existing brick\n\t'
'<new_brick> is new brick',
'abort volume replace brick'
)),
- 'glusterVolumeReplaceBrickPause':
- (serv.do_glusterVolumeReplaceBrickPause,
+ 'glusterVolumeReplaceBrickPause': (
+ serv.do_glusterVolumeReplaceBrickPause,
('<volume_name> <existing_brick> <new_brick>
\n\t<volume_name> '
'is existing volume name\n\t<brick> is existing brick\n\t'
'<new_brick> is new brick',
'pause volume replace brick'
)),
- 'glusterVolumeReplaceBrickStatus':
- (serv.do_glusterVolumeReplaceBrickStatus,
+ 'glusterVolumeReplaceBrickStatus': (
+ serv.do_glusterVolumeReplaceBrickStatus,
('<volume_name> <existing_brick> <new_brick>
\n\t<volume_name> '
'is existing volume name\n\t<brick> is existing brick\n\t'
'<new_brick> is new brick',
'get volume replace brick status'
)),
- 'glusterVolumeReplaceBrickCommit':
- (serv.do_glusterVolumeReplaceBrickCommit,
+ 'glusterVolumeReplaceBrickCommit': (
+ serv.do_glusterVolumeReplaceBrickCommit,
('<volume_name> <existing_brick> <new_brick>
\n\t<volume_name> '
'is existing volume name\n\t<brick> is existing brick\n\t'
'<new_brick> is new brick',
'commit volume replace brick'
)),
- 'glusterVolumeRemoveBrickStart':
- (serv.do_glusterVolumeRemoveBrickStart,
+ 'glusterVolumeRemoveBrickStart': (
+ serv.do_glusterVolumeRemoveBrickStart,
('<volume_name> [replica=<count>] bricks=brick[,brick] ...
\n\t'
'<volume_name> is existing volume name\n\t<brick> is '
'existing brick',
'start volume remove bricks'
)),
- 'glusterVolumeRemoveBrickStop':
- (serv.do_glusterVolumeRemoveBrickStop,
+ 'glusterVolumeRemoveBrickStop': (
+ serv.do_glusterVolumeRemoveBrickStop,
('<volume_name> [replica=<count>] bricks=brick[,brick] ...
\n\t'
'<volume_name> is existing volume name\n\t<brick> is '
'existing brick',
'stop volume remove bricks'
)),
- 'glusterVolumeRemoveBrickStatus':
- (serv.do_glusterVolumeRemoveBrickStatus,
+ 'glusterVolumeRemoveBrickStatus': (
+ serv.do_glusterVolumeRemoveBrickStatus,
('<volume_name> [replica=<count>] bricks=brick[,brick] ...
\n\t'
'<volume_name> is existing volume name\n\t<brick> is '
'existing brick',
'get volume remove bricks status'
)),
- 'glusterVolumeRemoveBrickCommit':
- (serv.do_glusterVolumeRemoveBrickCommit,
+ 'glusterVolumeRemoveBrickCommit': (
+ serv.do_glusterVolumeRemoveBrickCommit,
('<volume_name> [replica=<count>] bricks=brick[,brick] ...
\n\t'
'<volume_name> is existing volume name\n\t<brick> is '
'existing brick',
'commit volume remove bricks'
)),
- 'glusterVolumeRemoveBrickForce':
- (serv.do_glusterVolumeRemoveBrickForce,
+ 'glusterVolumeRemoveBrickForce': (
+ serv.do_glusterVolumeRemoveBrickForce,
('volumeName=<volume_name> bricks=<brick[,brick, ...]>
'
'[replica=<count>]\n\t'
'<volume_name> is existing volume name\n\t'
'<brick[,brick, ...]> is existing brick(s)',
'force volume remove bricks'
)),
- 'glusterVolumeStatus':
- (serv.do_glusterVolumeStatus,
+ 'glusterVolumeStatus': (
+ serv.do_glusterVolumeStatus,
('volumeName=<volume_name> [brick=<existing_brick>] '
'[option={detail | clients | mem}]\n\t'
'<volume_name> is existing volume name\n\t'
@@ -431,19 +454,37 @@
'get volume status of given volume with its all brick or '
'specified brick'
)),
- 'glusterHostsList':
- (serv.do_glusterHostsList,
+ 'glusterHostsList': (
+ serv.do_glusterHostsList,
('',
'list host info'
)),
- 'glusterVolumeProfileStart':
- (serv.do_glusterVolumeProfileStart,
+ 'glusterVolumeProfileStart': (
+ serv.do_glusterVolumeProfileStart,
('<volume_name>\n\t<volume_name> is existing volume
name',
'start gluster volume profile'
)),
- 'glusterVolumeProfileStop':
- (serv.do_glusterVolumeProfileStop,
+ 'glusterVolumeProfileStop': (
+ serv.do_glusterVolumeProfileStop,
('<volume_name>\n\t<volume_name> is existing volume
name',
'stop gluster volume profile'
)),
- }
+ 'glusterHooksList': (
+ serv.do_glusterHooksList,
+ ('',
+ 'list hooks info'
+ )),
+ 'glusterEnableHook': (
+ serv.do_glusterEnableHook,
+ ('<glusterCommand>=<gluster_command> <level>=[pre |
post] '
+ '<hookName>=<hook_name>\n\t'
+ '<hook_name> is an existing hook name',
+ 'Enable hook script'
+ )),
+ 'glusterDisableHook': (
+ serv.do_glusterDisableHook,
+ ('<glusterCommand>=<gluster_command> <level>=[pre |
post] '
+ '<hookName>=<hook_name>\n\t'
+ '<hook_name> is an existing hook name',
+ 'Disable hook script'
+ )), }
--
To view, visit
http://gerrit.ovirt.org/9671
To unsubscribe, visit
http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3918aa035d90967f1297dc7fadcf14b6a9385c45
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Timothy Asir <tjeyasin(a)redhat.com>
Gerrit-Reviewer: Ayal Baron <abaron(a)redhat.com>
Gerrit-Reviewer: Bala.FA <barumuga(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
Gerrit-Reviewer: Federico Simoncelli <fsimonce(a)redhat.com>
Gerrit-Reviewer: Saggi Mizrahi <smizrahi(a)redhat.com>