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

Reply via email to