Aravinda VK has uploaded a new change for review.

Change subject: vdsm: Gluster UFO verbs
......................................................................

vdsm: Gluster UFO verbs

VDSM Gluster verbs for UFO(Unified File Object) using Swift
services.

glusterGetServices: To get the status of all UFO services
(glusterd, smb, memcached, swift)

glusterManageServices: To start/stop/restart UFO related
services(glusterd, smb, memcached, swift)

glusterGetSwiftConfig: Get swift config items

glusterSetSwiftConfig: Set the config items

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=850443

Change-Id: Ie966fb515275a0768f67cbbe2055a07002355327
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, 360 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/64/10864/1

diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 5f0b0ed..eb760b6 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -216,6 +216,27 @@
         status = self.svdsmProxy.glusterVolumeProfileInfo(volumeName, nfs)
         return {'profileInfo': status}
 
+    @exportAsVerb
+    def getSwiftConfig(self, serverType, section=None, configOpt=None):
+        section = None if section == "" else section
+        configOpt = None if configOpt == "" else configOpt
+        return self.svdsmProxy.glusterGetSwiftConfig(serverType,
+                                                     section,
+                                                     configOpt)
+
+    @exportAsVerb
+    def setSwiftConfig(self, serverType, configDict):
+        return self.svdsmProxy.glusterSetSwiftConfig(serverType,
+                                                     configDict)
+
+    @exportAsVerb
+    def manageServices(self, servicesDict):
+        return self.svdsmProxy.glusterManageServices(servicesDict)
+
+    @exportAsVerb
+    def getServices(self):
+        return self.svdsmProxy.glusterGetServices()
+
 
 def getGlusterMethods(gluster):
     l = []
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index 7136281..58d8890 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -25,10 +25,30 @@
 from vdsm import netinfo
 import exception as ge
 from hostname import getHostNameFqdn, HostNameException
+import ConfigParser
+import re
 
 _glusterCommandPath = utils.CommandPath("gluster",
                                         "/usr/sbin/gluster",
                                         )
+
+statusTypes = {"INACTIVE": "STOPPED",
+               "STOPPED": "STOPPED",
+               "ACTIVE": "RUNNING",
+               "RUNNING": "RUNNING",
+               "FAILED": "FAILED"}
+
+CONFIG_FILES = {"proxy-server": "/etc/swift/proxy-server.conf",
+                "account-server": "/etc/swift/account-server/1.conf",
+                "object-server": "/etc/swift/object-server/1.conf",
+                "container-server": "/etc/swift/container-server/1.conf"}
+
+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 ["/usr/bin/swift-init", "main", action]
+    else:
+        return ["/sbin/service", serviceName, action]
 
 
 def exportToSuperVdsm(func):
@@ -880,3 +907,225 @@
         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
+    """
+    lines = statusStr.split("\n")
+    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 _getConfigItemsAsDict(items):
+    configItems = {}
+    for item in items:
+        configItems[item[0]] = item[1]
+    return configItems
+
+
+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
+
+
+@exportToSuperVdsm
+def manageServices(serviceDict):
+    """
+    Performs start/stop/restart the gluster related services
+
+    :param servicesDict dict with serviceName as key and action as value
+    Ex: {"glusterd": "start", "swift": "stop"}
+    :returns {"value": True}
+    """
+    serviceErrorMsg = ["Service not supported"]
+    for serviceName in serviceDict:
+        action = serviceDict[serviceName]
+
+        # Allowing to start any service can have side effects
+        if serviceName not in SUPPORTED_GLUSTER_SERVICES:
+            raise ge.ManageGlusterServicesFailedException(1,
+                                                          [""],
+                                                          serviceErrorMsg)
+
+        cmd = _getGlusterServiceCmd(serviceName, action)
+
+        rc, out, err = _execGluster(cmd)
+    return {"value": True}
+
+
+@exportToSuperVdsm
+def getServices():
+    """
+    Returns status of all gluster services
+
+    :param None
+    :returns list of dict with PID and status details for each service
+    Ex: {"value": [{"name": "glusterd", "status": "RUNNING", pid: "1027"},..]}
+    """
+    serviceStatus = []
+
+    for serviceName in SUPPORTED_GLUSTER_SERVICES:
+        rc, out, err = _execGluster(_getGlusterServiceCmd(serviceName,
+                                                          "status"))
+        serviceStatus += _parseStatus(serviceName, "\n".join(out))
+
+    return {"value": serviceStatus}
+
+
+@exportToSuperVdsm
+def getSwiftConfig(serverType, section=None, configOption=None):
+    """
+    Get values from the Swift config files, If section is None return all
+    the config items from file, else return config items only from that
+    section.
+    If configOption and section is set then return respective config item
+    else return all config items.
+
+    :param serverType Type of swift server(proxy-server, account-server,
+    object-server, container-server)
+    :param section (Optional) Section in config file
+    :param configOption (Optional) Config item in a section
+    :returns Dict with section name as keys
+    Ex: {"value": {"section": {"key1": "value1", "key2": "value2"}}}
+    """
+    config = ConfigParser.ConfigParser()
+    config_file = CONFIG_FILES[serverType]
+    config.readfp(open(config_file))
+    configValues = {}
+
+    # Since config.items or config.get for any section will include default
+    # values in the resulting items list of a section. To avoid including
+    # default options in every section
+    defaultValues = config.defaults()
+    config._defaults = {}
+
+    if section == None:
+        sections = config.sections()
+        configValues['DEFAULT'] = defaultValues
+
+        for section in sections:
+            items = _getConfigItemsAsDict(config.items(section))
+            configValues[section] = items
+    elif configOption == None:
+        if section.upper() == "DEFAULT":
+            configValues[section] = defaultValues
+        else:
+            items = {}
+            if config.has_section(section):
+                items = _getConfigItemsAsDict(config.items(section))
+            configValues[section] = items
+    elif config.has_option(section, configOption):
+        value = config.get(section, configOption)
+        configValues = {section: {configOption: value}}
+    else:
+        configValues = {section: {configOption: ""}}
+
+    return {"value": configValues}
+
+
+@exportToSuperVdsm
+def setSwiftConfig(serverType, configDict):
+    """
+    Set config values in swift config files
+    :param serverType Type of swift server(proxy-server, account-server,
+    object-server, container-server)
+    :param configDict Dict of items to update with section name as key
+    Ex: {"section1": {"configOpt1": "value1", "configOpt2": "value2"},..}
+    :returns Sets the config item and returns configChanged flag to indicate if
+    atleast one config item is changed, which helps engine to decide swift
+    restart is required or not. Ex: {"value": {"configChanged": True}}
+    """
+    config = ConfigParser.ConfigParser()
+    config_file = CONFIG_FILES[serverType]
+    config.readfp(open(config_file))
+    configChanged = False
+
+    for section in configDict:
+        if not config.has_section(section) and section.upper() != "DEFAULT":
+            config.add_section(section)
+
+        for configOption in configDict[section]:
+            value = configDict[section][configOption]
+            if config.has_option(section, configOption):
+                curr_val = config.get(section, configOption)
+            else:
+                curr_val = None
+
+            if curr_val != value:
+                config.set(section, configOption, str(value))
+                configChanged = True
+
+        # Update the config file only if atleast one config
+        # item updated
+        if configChanged:
+            f = open(config_file, "wb")
+            config.write(f)
+            f.close()
+
+    return {"value": {"configChanged": configChanged}}
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index e921d7d..0d520b5 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -390,3 +390,8 @@
 class GlusterHostsListFailedException(GlusterHostException):
     code = 4407
     message = "Hosts list failed"
+
+
+class ManageGlusterServicesFailedException(GlusterException):
+    code = 4408
+    message = "start/stop/restart of Gluster services failed"
diff --git a/vdsm_cli/vdsClientGluster.py b/vdsm_cli/vdsClientGluster.py
index be47696..e7ae180 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,56 @@
         pp.pprint(status)
         return status['status']['code'], status['status']['message']
 
+    def do_glusterGetSwiftConfig(self, args):
+        params = self._eqSplit(args)
+        serverType = params.get('serverType', '')
+        if serverType == "":
+            raise ValueError
+
+        section = params.get('section', '')
+        configOption = params.get('configOption', '')
+
+        status = self.s.glusterGetSwiftConfig(serverType,
+                                              section,
+                                              configOption)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterSetSwiftConfig(self, args):
+        params = self._eqSplit(args)
+        serverType = params.get('serverType', '')
+        if serverType == "":
+            raise ValueError
+        configDictStr = params.get('configDict', '{}')
+
+        try:
+            configDict = json.loads(configDictStr)
+        except:
+            raise ValueError
+
+        status = self.s.glusterSetSwiftConfig(serverType, configDict)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterManageServices(self, args):
+        params = self._eqSplit(args)
+        servicesDictStr = params.get('servicesDict', '')
+        if servicesDictStr == "":
+            raise ValueError
+        try:
+            servicesDict = json.loads(servicesDictStr)
+        except:
+            raise ValueError
+
+        status = self.s.glusterManageServices(servicesDict)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterGetServices(self, args):
+        status = self.s.glusterGetServices()
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
 
 def getGlusterCmdDict(serv):
     return \
@@ -468,4 +518,37 @@
              ('volumeName=<volume_name> [nfs={yes|no}]\n\t'
               '<volume_name> is existing volume name',
               'get gluster volume profile info'
-              )), }
+              )),
+         'glusterGetSwiftConfig': (
+            serv.do_glusterGetSwiftConfig,
+            ('serverType=<serverType> [section=<section> '
+             '[configOpt=<configOpt>]]\n\t',
+             'serverType is the type of swift service(proxy-server, '
+             'object-server, account-server, container-server)',
+             'section is the section in the config file',
+             'configOption is the config item in respective config file',
+             'returns the Swift config values'
+             )),
+         'glusterSetSwiftConfig': (
+            serv.do_glusterSetSwiftConfig,
+            ('serverType=<serverType> configDict=<configDict>\n\t',
+             'serverType is the type of swift service(proxy-server, '
+             'object-server, account-server, container-server)',
+             'configDict dict of config items which needs update'
+             '{"section1": {"key1": "value1", "key2": "value2"}..}',
+             'Updates the Swift configuration file'
+             )),
+         'glusterManageServices': (
+            serv.do_glusterManageServices,
+            ('servicesDict=<servicesDict>\n\t',
+             'servicesDict is dict of services with service name as key and '
+             'action as value( Ex: {"glusterd": "start", "swift": "stop"})',
+             'Performs start/stop/restart of gluster services'
+             )),
+         'glusterGetServices': (
+            serv.do_glusterGetServices,
+            ('',
+             'Returns status of all gluster services'
+             '(swift, glusterd, smb, memcached)'
+             )),
+         }


--
To view, visit http://gerrit.ovirt.org/10864
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie966fb515275a0768f67cbbe2055a07002355327
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