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(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, 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(a)redhat.com>