Aravinda VK has uploaded a new change for review.
Change subject: vdsm: verbs for managing gluster services
......................................................................
vdsm: verbs for managing gluster services
Verbs to manage or get status of gluster related services.
glusterServicesGet: To get the status of all gluster services or to get
status of single gluster service.
Output structure:
{'value': [{'name': SERVICE_NAME, 'pid': PID, 'status': STATUS},..]}
glusterServicesManage: To start/stop/restart gluster services like
glusterd, memcache, swift, smb.
Output structure:
{'value': True}
Change-Id: I8a16bf566d17e186a66503391dfd04b2f2bb4bb4
Signed-off-by: Aravinda VK <[email protected]>
---
M vdsm/gluster/api.py
M vdsm/gluster/cli.py
M vdsm/gluster/exception.py
M vdsm_cli/vdsClientGluster.py
4 files changed, 230 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/94/11094/1
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 5f0b0ed..a26d520 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -216,6 +216,15 @@
status = self.svdsmProxy.glusterVolumeProfileInfo(volumeName, nfs)
return {'profileInfo': status}
+ @exportAsVerb
+ def servicesManage(self, serviceName, action):
+ return self.svdsmProxy.glusterServicesManage(serviceName, action)
+
+ @exportAsVerb
+ def servicesGet(self, serviceName=None):
+ serviceName = None if serviceName == "" else serviceName
+ return self.svdsmProxy.glusterServicesGet(serviceName)
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index a3950fc..99203e9 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -23,12 +23,32 @@
from vdsm import utils
from vdsm import netinfo
+from vdsm import constants
import exception as ge
from hostname import getHostNameFqdn, HostNameException
+import ConfigParser
+import re
_glusterCommandPath = utils.CommandPath("gluster",
"/usr/sbin/gluster",
)
+
+_swiftCommandPath = utils.CommandPath("swift-init",
+ "/usr/bin/swift-init",
+ )
+
+statusTypes = {"INACTIVE": "STOPPED",
+ "STOPPED": "STOPPED",
+ "ACTIVE": "RUNNING",
+ "RUNNING": "RUNNING",
+ "FAILED": "FAILED"}
+
+SUPPORTED_GLUSTER_SERVICES = ["glusterd", "memcached", "swift", "smb"]
+
+SWIFT_SERVICES = ["proxy-server",
+ "container-server",
+ "account-server",
+ "object-server"]
def _getGlusterVolCmd():
@@ -37,6 +57,13 @@
def _getGlusterPeerCmd():
return [_glusterCommandPath.cmd, "--mode=script", "peer"]
+
+
+def _getGlusterServiceCmd(serviceName, action):
+ if serviceName == "swift":
+ return [_swiftCommandPath.cmd, "main", action]
+ else:
+ return [constants.EXT_SERVICE, serviceName, action]
def exportToSuperVdsm(func):
@@ -880,3 +907,144 @@
return _parseVolumeProfileInfo(xmltree, nfs)
except (etree.ParseError, AttributeError, ValueError):
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+def _parseSwiftServiceStatus(statusStr):
+ statusLines = statusStr.split("\n")
+ swiftStatus = []
+ noServicesRunningPat = "No\s(%s)" % "|".join(SWIFT_SERVICES)
+ servicesRunningPat = "(%s) running \((\d+)\s+" % "|".join(SWIFT_SERVICES)
+
+ for line in statusLines:
+ noServiceRunningMatch = re.search(noServicesRunningPat,
+ line,
+ re.IGNORECASE)
+ serviceRunningMatch = re.search(servicesRunningPat,
+ line,
+ re.IGNORECASE)
+
+ if noServiceRunningMatch:
+ swiftStatus.append({"name": noServiceRunningMatch.group(1),
+ "pid": "",
+ "status": "STOPPED"})
+ elif serviceRunningMatch:
+ swiftStatus.append({"name": serviceRunningMatch.group(1),
+ "pid": serviceRunningMatch.group(2),
+ "status": "RUNNING"})
+
+ if len(swiftStatus) == 0:
+ for service in SWIFT_SERVICES:
+ swiftStatus.append({"name": service,
+ "status": "STOPPED",
+ "pid": ""})
+
+ return swiftStatus
+
+
+def _parseServiceStatus(name, statusStr):
+ """
+ Sample output:
+ case 1: running
+ glusterd (pid 15943) is running...
+
+ case2: stopped
+ glusterd is stopped
+ """
+ serviceStatus = {"name": name, "status": "STOPPED", "pid": ""}
+ m = re.search("\(PID\s+(\d+)\).+(RUNNING)", statusStr, re.IGNORECASE)
+ if m:
+ serviceStatus["pid"] = m.group(1)
+ serviceStatus["status"] = statusTypes[m.group(2).upper()]
+ elif re.search("FAILED", statusStr.upper()):
+ serviceStatus["status"] = statusTypes["FAILED"]
+
+ return [serviceStatus]
+
+
+def _parseSystemCtlStatus(name, statusStr):
+ serviceStatus = {"name": name, "status": "STOPPED", "pid": ""}
+ lines = statusStr.split("\n")
+ for line in lines:
+ statusMatch = re.search("Active:\s+(\S+)\s", line, re.IGNORECASE)
+ pidMatch = re.search("Main PID:\s+(\S+)\s", line, re.IGNORECASE)
+ if statusMatch:
+ serviceStatus["status"] = statusTypes[statusMatch.group(1).upper()]
+ elif pidMatch and serviceStatus["status"] == "RUNNING":
+ serviceStatus["pid"] = pidMatch.group(1)
+
+ return [serviceStatus]
+
+
+def _parseStatus(serviceName, statusStr):
+ if serviceName == "swift":
+ status = _parseSwiftServiceStatus(statusStr)
+ elif re.search("Loaded:", statusStr, re.IGNORECASE):
+ status = _parseSystemCtlStatus(serviceName, statusStr)
+ else:
+ status = _parseServiceStatus(serviceName, statusStr)
+
+ return status
+
+
+def _servicesException(action, rc, out, err):
+ if action == "start":
+ raise ge.GlusterServicesStartFailedException(1, out, err)
+ elif action == "stop":
+ raise ge.GlusterServicesStopFailedException(rc, out, err)
+ else:
+ raise ge.GlusterServicesRestartFailedException(1, out, err)
+
+
+@exportToSuperVdsm
+def servicesManage(serviceName, action):
+ """
+ Performs start/stop/restart the gluster related services
+
+ :param serviceName service name on which operation has to be performed
+ :param action start/stop/restart
+ :returns {"value": True}
+ """
+ # Allowing to start any service can have side effects
+ if serviceName not in SUPPORTED_GLUSTER_SERVICES:
+ serviceErrorMsg = "%s: Service not supported" % serviceName
+ _servicesException(action, 1, [""], [serviceErrorMsg])
+
+ cmd = _getGlusterServiceCmd(serviceName, action)
+
+ rc, out, err = _execGluster(cmd)
+ if rc != 0:
+ _servicesException(action, rc, "", out)
+
+ return {"value": True}
+
+
+@exportToSuperVdsm
+def servicesGet(serviceName=None):
+ """
+ Returns status of all gluster services if serviceName parameter is not set
+ else returns status of that particular service.
+ {'value': [{'name': SERVICE_NAME, 'pid': PID, 'status': STATUS},..]}
+
+ :param serviceName Default is None, service name for which status is
+ fetched
+ :returns list of dict with PID and status details for each service
+ Ex: {"value": [{"name": "glusterd", "status": "RUNNING", pid: "1027"},..]}
+ """
+ serviceStatus = []
+
+ if serviceName is None:
+ for aService in SUPPORTED_GLUSTER_SERVICES:
+ rc, out, err = _execGluster(_getGlusterServiceCmd(aService,
+ "status"))
+ serviceStatus += _parseStatus(aService, "\n".join(out))
+ else:
+ if serviceName not in SUPPORTED_GLUSTER_SERVICES:
+ serviceErrorMsg = "%s: Service not supported" % serviceName
+ raise ge.GlusterServicesGetFailedException(1,
+ err=[serviceErrorMsg])
+
+ rc, out, err = _execGluster(_getGlusterServiceCmd(serviceName,
+ "status"))
+ serviceStatus += _parseStatus(serviceName, "\n".join(out))
+
+ return {"value": serviceStatus}
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index e921d7d..0a2cfb6 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -390,3 +390,23 @@
class GlusterHostsListFailedException(GlusterHostException):
code = 4407
message = "Hosts list failed"
+
+
+class GlusterServicesStartFailedException(GlusterGeneralException):
+ code = 4408
+ message = "Start service failed"
+
+
+class GlusterServicesStopFailedException(GlusterGeneralException):
+ code = 4409
+ message = "Stop service failed"
+
+
+class GlusterServicesRestartFailedException(GlusterGeneralException):
+ code = 4410
+ message = "Restart service failed"
+
+
+class GlusterServicesGetFailedException(GlusterGeneralException):
+ code = 4411
+ message = "Get Services status failed"
diff --git a/vdsm_cli/vdsClientGluster.py b/vdsm_cli/vdsClientGluster.py
index be47696..bde5805 100644
--- a/vdsm_cli/vdsClientGluster.py
+++ b/vdsm_cli/vdsClientGluster.py
@@ -18,7 +18,7 @@
#
import pprint as pp
-
+import json
from vdsClient import service
@@ -272,6 +272,21 @@
pp.pprint(status)
return status['status']['code'], status['status']['message']
+ def do_glusterServicesManage(self, args):
+ params = self._eqSplit(args)
+ serviceName = params.get('serviceName', '')
+ action = params.get('action', '')
+ status = self.s.glusterServicesManage(serviceName, action)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
+ def do_glusterServicesGet(self, args):
+ params = self._eqSplit(args)
+ serviceName = params.get('serviceName', '')
+ status = self.s.glusterServicesGet(serviceName)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
def getGlusterCmdDict(serv):
return \
@@ -468,4 +483,20 @@
('volumeName=<volume_name> [nfs={yes|no}]\n\t'
'<volume_name> is existing volume name',
'get gluster volume profile info'
- )), }
+ )),
+ 'glusterServicesManage': (
+ serv.do_glusterServicesManage,
+ ('serviceName=<serviceName> action=<action>\n\t',
+ 'servicesName is name of the service on which action needs '
+ 'to be performed',
+ 'action can be start/stop or restart',
+ 'Performs start/stop/restart of gluster services'
+ )),
+ 'glusterServicesGet': (
+ serv.do_glusterServicesGet,
+ ('[serviceName=<serviceName>]',
+ 'Returns status of all gluster services if serviceName is '
+ 'not set'
+ '(swift, glusterd, smb, memcached)'
+ )),
+ }
--
To view, visit http://gerrit.ovirt.org/11094
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8a16bf566d17e186a66503391dfd04b2f2bb4bb4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Aravinda VK <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches