Skip to content
Snippets Groups Projects
Commit 45222f1c authored by sveseli's avatar sveseli
Browse files

added api/impl classes for BSS integration

parent 696b1894
No related branches found
No related tags found
No related merge requests found
Release 1.1 ()
=============================
- Added the following functionality for managing DAQs:
- Max. run time specification causes DAQ to be stopped automatically
- Target directory specification causes files to be uploaded into
a specific directory relative to experiment root path
- Upload data/target directory on exit specify upload of the given
directory automatically after DAQ completes
- Added the following functionality for managing uploads:
- Target directory specification causes files to be uploaded into
a specific directory relative to experiment root path
- Introduced sphinx as python API documentation framework
Release 1.0 (01/31/2017)
=============================
......
build
.. automodule:: dm.aps_bss.api
.. currentmodule:: dm.aps_bss.api
ApsBssApi
---------
.. autoclass:: dm.aps_bss.api.apsBssApi.ApsBssApi()
:show-inheritance:
:members: __init__, listRuns, getCurrentRun, listBeamlineProposals, getBeamlineProposal
......@@ -13,6 +13,7 @@ The `dm` package contains python APIs for accessing Data Management services.
:caption: Contents:
dm.daq_web_service.api
dm.aps_bss.api
Indices and tables
==================
......
#!/usr/bin/env python
import os
from dm.common.exceptions.configurationError import ConfigurationError
from dm.common.api.dmApi import DmApi
from dm.aps_bss.impl.bssClient import BssClient
class ApsBssApi(DmApi):
''' Data Management API for APS Beamline Scheduling System. '''
def __init__(self, beamlineName=None, username=None, password=None):
'''
Constructor.
:param beamlineName: beamline name (if not provided, environment variable DM_BEAMLINE_NAME must be set)
:type beamlineName: str
:param username: BSS username (if not provided, environment variable DM_BSS_LOGIN_FILE must be set)
:type username: str
:param password: BSS password (if not provided, environment variable DM_BSS_LOGIN_FILE must be set)
:type password: str
:raises ConfigurationError: in case beamline name or username/password are not provided, and corresponding environment variables are not set
Note that environment variable DM_BSS_LOGIN_FILE should contain
path to a file containing BSS username and password as a single line in
the '<username>|<password>' form.
>>> api = ApsBssApi(beamlineName='1-ID-B,C,E', username='dm', password='XYZ')
'''
DmApi.__init__(self)
if not username or not password:
loginFile = os.environ.get('DM_BSS_LOGIN_FILE')
if loginFile:
try:
# Assume form <username>|<password>
tokenList = open(loginFile).readline().split('|')
if len(tokenList) == 2:
username = tokenList[0].strip()
password = tokenList[1].strip()
except Exception, ex:
raise ConfigurationError('Could not determine username/password from BSS login file: %s' % str(ex))
if not username or not password:
raise ConfigurationError('Username and/or password were not provided, and DM_BSS_LOGIN_FILE is not set.')
if not beamlineName:
beamlineName = os.environ.get('DM_BEAMLINE_NAME')
if not beamlineName:
raise ConfigurationError('Beamline name was not provided, and DM_BEAMLINE_NAME is not set.')
self.beamlineName = beamlineName
self.bssClient = BssClient(username, password)
@DmApi.execute2
def listRuns(self):
'''
List all available runs.
:returns: list of RunInfo objects
:raises DmException: for any error
>> runs = api.listRuns()
>> for run in runs:
>> print run['name']
'''
return self.bssClient.listRuns()
@DmApi.execute2
def getCurrentRun(self):
'''
Find current run.
:returns: RunInfo object
:raises DmException: for any error
>> run = api.getCurrentRun()
'''
return self.bssClient.getCurrentRun()
@DmApi.execute2
def listBeamlineProposals(self, runName=None):
'''
List beamline proposals for a given run.
:param runName: run name (if not provided, current run name will be used)
:type runName: str
:returns: list of ProposalInfo objects
:raises DmException: for any error
>> proposals = api.listBeamlineProposals()
>> for proposal in proposals:
>> print proposal['title']
'''
if not runName:
runName = self.getCurrentRun()['name']
return self.bssClient.listBeamlineProposals(self.beamlineName, runName)
@DmApi.execute2
def getBeamlineProposal(self, proposalId, runName=None):
'''
Get beamline proposal with a given id.
:param porposalId: proposal id
:type runName: str
:param runName: run name (if not provided, current run name will be used)
:type runName: str
:returns: ProposalInfo object
:raises ObjectNotFound: if proposal with the given id does not exist
:raises DmException: for any other error
>> proposal = api.getBeamlineProposal(42096)
>> for experimenter in proposal['experimenters']:
>> print experimenter['badge'], experimenter['lastName']
'''
if not runName:
runName = self.getCurrentRun()['name']
return self.bssClient.getBeamlineProposal(proposalId, self.beamlineName, runName)
#######################################################################
# Testing.
if __name__ == '__main__':
api = ApsBssApi('1-ID-B,C,E')
print 'RUNS', api.listRuns()
print 'CURRRENT RUN: ', api.getCurrentRun()
print 'PROPOSALS: ', api.listBeamlineProposals()
print
print 'FIND PROPOSAL: ', api.getBeamlineProposal(42096)
print 'FIND PROPOSAL: ', api.getBeamlineProposal(52096)
#!/usr/bin/env python
import datetime
from suds.wsse import Security
from suds.wsse import UsernameToken
from suds.client import Client
from dm.common.exceptions.objectNotFound import ObjectNotFound
from dm.common.objects.runInfo import RunInfo
from dm.common.objects.beamlineInfo import BeamlineInfo
from dm.common.objects.proposalInfo import ProposalInfo
from dm.common.objects.apsUserInfo import ApsUserInfo
from dm.common.exceptions.dmException import DmException
from dm.common.utility.loggingManager import LoggingManager
class BssClient:
WSDL_URL = 'https://schedule.aps.anl.gov/beamschedds/springws'
CACHE_DURATION_IN_SECONDS = 10
def __init__(self, username, password):
self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
self.__configure(username, password)
def __configure(self, username, password):
beamlineScheduleServiceUrl = self.WSDL_URL + '/beamlineScheduleService/beamlineScheduleWebService.wsdl'
runScheduleServiceUrl = self.WSDL_URL + '/runScheduleService/runScheduleWebService.wsdl'
try:
self.runScheduleServiceClient = Client(runScheduleServiceUrl)
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.setSoapHeader(self.beamlineScheduleServiceClient, username, password)
except Exception, ex:
self.logger.error('Cannot open BSS connection: %s' % str(ex))
raise DmException(exception=ex)
@classmethod
def setSoapHeader(cls, client, username, password):
security = Security()
token = UsernameToken(username, password)
token.setcreated()
security.tokens.append(token)
client.set_options(wsse=security)
def listRuns(self):
''' Return list of all runs. '''
result = self.runScheduleServiceClient.service.findAllRuns()
runArray = result.run
runs = []
for run in runArray:
runs.append(RunInfo({'name' : run.runName, 'startTime' : run.startTime, 'endTime' : run.endTime}))
return runs
def listRunsBetweenDates(self, startDate, endDate):
''' Find list of runs between given startDate and endDate. '''
result = self.runScheduleServiceClient.service.findAllRuns()
runArray = result.run
runs = []
for run in runArray:
if run.startTime >= startDate and run.endTime <= endDate:
runs.append(RunInfo({'name' : run.runName, 'startTime' : run.startTime, 'endTime' : run.endTime}))
return runs
def getRunForDates(self, startDate, endDate):
''' Find run that spans given startDate and endDate. '''
result = self.runScheduleServiceClient.service.findAllRuns()
runArray = result.run
for run in runArray:
if startDate >= run.startTime and endDate <= run.endTime:
return RunInfo({'name' : run.runName, 'startTime' : run.startTime, 'endTime' : run.endTime})
raise ObjectNotFound('No run found.')
def getCurrentRun(self):
''' Find current run. '''
now = datetime.datetime.now()
return self.getRunForDates(now, now)
def listBeamlines(self):
''' Find list of all beamlines. '''
result = self.beamlineScheduleServiceClient.service.findAllBeamlines()
beamlineArray = result.beamline
beamlines = []
for beamline in beamlineArray:
beamlines.append(BeamlineInfo({'name' : beamline.beamlineName, 'id' : beamline.id}))
return beamlines
def createProposalInfo(self, proposal):
experimenterArray = proposal.experimenters.experimenter
experimenters = []
for experimenter in experimenterArray:
user = ApsUserInfo({
'id' : experimenter.id,
'badge' : experimenter.badge,
'email' : experimenter.email,
'firstName' : experimenter.firstName,
'instId' : experimenter.instId,
'institution' : experimenter.institution,
'lastName' : experimenter.lastName
})
if hasattr(experimenter, 'piFlag'):
user['piFlag'] = experimenter.piFlag
experimenters.append(user)
proposalInfo = ProposalInfo({
'title' : proposal.proposalTitle,
'id' : proposal.id,
'experimenters' : experimenters
})
return proposalInfo
def listBeamlineProposals(self, beamlineName, runName):
''' Find beamline schedule for a given beamlineName and runName. '''
schedule = self.beamlineScheduleServiceClient.service.findBeamlineSchedule(beamlineName, runName)
activitiesArray = schedule.activities.activity
proposals = []
for activity in activitiesArray:
if hasattr(activity, 'beamtimeRequest'):
proposal = activity.beamtimeRequest.proposal
proposals.append(self.createProposalInfo(proposal))
return proposals
def getBeamlineProposal(self, proposalId, beamlineName, runName):
''' Find proposal with a given id, beamlineName and runName. '''
schedule = self.beamlineScheduleServiceClient.service.findBeamlineSchedule(beamlineName, runName)
activitiesArray = schedule.activities.activity
proposals = []
for activity in activitiesArray:
if hasattr(activity, 'beamtimeRequest'):
proposal = activity.beamtimeRequest.proposal
if proposal.id == proposalId:
return self.createProposalInfo(proposal)
raise ObjectNotFound('Proposal with id %s does not exist (beamline: %s; run: %s).' % (proposalId, beamlineName, runName))
if __name__ == '__main__':
bss = BssClient('DMADMIN', 'A2Fxew@11:76am')
now = datetime.datetime.now()
days = datetime.timedelta(days=180)
before = now - days
print before, now
runNames = bss.getRunsBetweenDates(before, now)
print 'RUNS: ', runNames
print 'CURRENT RUN: ', bss.getCurrentRun()
print bss.listBeamlines()
print bss.listBeamlineProposals('1-ID-B,C,E', '2017-1')
print
print bss.getBeamlineProposal(51190, '1-ID-B,C,E', '2017-1')
print
print bss.getBeamlineProposal(48258, '1-ID-B,C,E', '2017-1')
......@@ -15,7 +15,7 @@ from daqRestApi import DaqRestApi
class ExperimentDaqApi(DaqRestApi):
'''
This class is used to access experiment interface provided by the
Data Management API for accessing experiment interface provided by the
DAQ service on a DM experiment station.
'''
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment