From 7f990d008fc6d136ba8646ddf376c87cb4197a92 Mon Sep 17 00:00:00 2001 From: Sinisa Veseli <sveseli@aps.anl.gov> Date: Wed, 22 Mar 2017 20:20:32 +0000 Subject: [PATCH] fix issue with suds cache --- src/python/dm/__init__.py | 2 +- src/python/dm/aps_bss/api/apsBssApi.py | 14 +++--- src/python/dm/aps_bss/impl/bssClient.py | 11 +++-- src/python/dm/common/api/dmApi.py | 1 - src/python/dm/common/api/dmSudsApi.py | 61 +++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 14 deletions(-) create mode 100755 src/python/dm/common/api/dmSudsApi.py diff --git a/src/python/dm/__init__.py b/src/python/dm/__init__.py index 3e733647..f4bbd36e 100644 --- a/src/python/dm/__init__.py +++ b/src/python/dm/__init__.py @@ -1 +1 @@ -__version__ = "1.1 (2017.03.13)" +__version__ = "1.1 (2017.03.22)" diff --git a/src/python/dm/aps_bss/api/apsBssApi.py b/src/python/dm/aps_bss/api/apsBssApi.py index 11e4f934..42bc938b 100755 --- a/src/python/dm/aps_bss/api/apsBssApi.py +++ b/src/python/dm/aps_bss/api/apsBssApi.py @@ -2,10 +2,10 @@ import os from dm.common.exceptions.configurationError import ConfigurationError -from dm.common.api.dmApi import DmApi +from dm.common.api.dmSudsApi import DmSudsApi from dm.aps_bss.impl.bssClient import BssClient -class ApsBssApi(DmApi): +class ApsBssApi(DmSudsApi): ''' Data Management API for APS Beamline Scheduling System. ''' def __init__(self, beamlineName=None, username=None, password=None, loginFile=None): ''' @@ -31,7 +31,7 @@ class ApsBssApi(DmApi): >>> api = ApsBssApi(beamlineName='1-ID-B,C,E', username='dm', password='XYZ') ''' - DmApi.__init__(self) + DmSudsApi.__init__(self) if not username or not password: if not loginFile: loginFile = os.environ.get('DM_BSS_LOGIN_FILE') @@ -55,7 +55,7 @@ class ApsBssApi(DmApi): self.beamlineName = beamlineName self.bssClient = BssClient(username, password) - @DmApi.execute2 + @DmSudsApi.executeSudsCall def listRuns(self): ''' List all available runs. @@ -70,7 +70,7 @@ class ApsBssApi(DmApi): ''' return self.bssClient.listRuns() - @DmApi.execute2 + @DmSudsApi.executeSudsCall def getCurrentRun(self): ''' Find current run. @@ -83,7 +83,7 @@ class ApsBssApi(DmApi): ''' return self.bssClient.getCurrentRun() - @DmApi.execute2 + @DmSudsApi.executeSudsCall def listBeamlineProposals(self, runName=None): ''' List beamline proposals for a given run. @@ -103,7 +103,7 @@ class ApsBssApi(DmApi): runName = self.getCurrentRun()['name'] return self.bssClient.listBeamlineProposals(self.beamlineName, runName) - @DmApi.execute2 + @DmSudsApi.executeSudsCall def getBeamlineProposal(self, proposalId, runName=None): ''' Get beamline proposal with a given id. diff --git a/src/python/dm/aps_bss/impl/bssClient.py b/src/python/dm/aps_bss/impl/bssClient.py index dc81e6f4..df8f129f 100644 --- a/src/python/dm/aps_bss/impl/bssClient.py +++ b/src/python/dm/aps_bss/impl/bssClient.py @@ -6,6 +6,7 @@ import string from suds.wsse import Security from suds.wsse import UsernameToken from suds.client import Client +from suds.cache import NoCache from dm.common.exceptions.objectNotFound import ObjectNotFound from dm.common.objects.runInfo import RunInfo @@ -18,7 +19,7 @@ from dm.common.utility.loggingManager import LoggingManager class BssClient: WSDL_URL = 'https://schedule.aps.anl.gov/beamschedds/springws' - CACHE_DURATION_IN_SECONDS = 10 + #CACHE_DURATION_IN_SECONDS = 10 def __init__(self, username, password): self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) @@ -29,12 +30,12 @@ class BssClient: runScheduleServiceUrl = self.WSDL_URL + '/runScheduleService/runScheduleWebService.wsdl' try: - self.runScheduleServiceClient = Client(runScheduleServiceUrl) - self.runScheduleServiceClient.options.cache.setduration(seconds=self.CACHE_DURATION_IN_SECONDS) + self.runScheduleServiceClient = Client(runScheduleServiceUrl, cache=NoCache()) + #self.runScheduleServiceClient.options.cache.setduration(seconds=self.CACHE_DURATION_IN_SECONDS) self.setSoapHeader(self.runScheduleServiceClient, username, password) - self.beamlineScheduleServiceClient = Client(beamlineScheduleServiceUrl) - self.beamlineScheduleServiceClient.options.cache.setduration(seconds=self.CACHE_DURATION_IN_SECONDS) + self.beamlineScheduleServiceClient = Client(beamlineScheduleServiceUrl, cache=NoCache()) + #self.beamlineScheduleServiceClient.options.cache.setduration(seconds=self.CACHE_DURATION_IN_SECONDS) self.setSoapHeader(self.beamlineScheduleServiceClient, username, password) except Exception, ex: self.logger.error('Cannot open BSS connection: %s' % str(ex)) diff --git a/src/python/dm/common/api/dmApi.py b/src/python/dm/common/api/dmApi.py index 9de12e9d..d1c0ed1b 100755 --- a/src/python/dm/common/api/dmApi.py +++ b/src/python/dm/common/api/dmApi.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -import json from functools import wraps from decorator import decorator from dm.common.exceptions.dmException import DmException diff --git a/src/python/dm/common/api/dmSudsApi.py b/src/python/dm/common/api/dmSudsApi.py new file mode 100755 index 00000000..a9aecb6b --- /dev/null +++ b/src/python/dm/common/api/dmSudsApi.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import os +import shutil +from functools import wraps +from decorator import decorator + +from dm.common.exceptions.dmException import DmException +from dm.common.api.dmApi import DmApi + +class DmSudsApi(DmApi): + """ Base dm api class that utilizes suds calls. """ + + SUDS_CACHE_DIR = '/tmp/suds' + + def __init__(self, username=None, password=None): + DmApi.__init__(self, username=username, password=password) + + # Remove suds cache directory if it exists. + # Workaround for bug in current suds package that leaves + # cache files behind, which may result in permission denied errors + # for multiple users + @classmethod + def removeSudsCache(cls): + if os.path.exists(cls.SUDS_CACHE_DIR): + try: + shutil.rmtree(cls.SUDS_CACHE_DIR) + except Exception, ex: + cls.getLogger().warn('Cannot remove suds cache %s: %s' % (cls.SUDS_CACHE_DIR, ex)) + + # Exception decorator for api calls + # Use two decorators for the sake of documentation + @classmethod + def executeSudsCall(cls, *dargs, **dkwargs): + def internalCall(func): + @wraps(func) + def wrappedCall(func, *args, **kwargs): + try: + response = func(*args, **kwargs) + cls.removeSudsCache() + return response + except DmException, ex: + cls.removeSudsCache() + raise ex + except Exception, ex: + cls.getLogger().exception('%s' % ex) + cls.removeSudsCache() + raise DmException(exception=ex) + return decorator(wrappedCall, func) + if len(dargs) == 1 and callable(dargs[0]): + return internalCall(dargs[0]) + else: + return internalCall + +####################################################################### +# Testing. + +if __name__ == '__main__': + pass + + -- GitLab