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 avishwan@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, 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 avishwan@redhat.com