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

got update for experiment files cli working

parent 7f682ca8
No related branches found
No related tags found
No related merge requests found
#!/bin/sh
# Run command
if [ -z $DM_ROOT_DIR ]; then
cd `dirname $0` && myDir=`pwd`
setupFile=$myDir/../setup.sh
if [ ! -f $setupFile ]; then
echo "Cannot find setup file: $setupFile"
exit 1
fi
source $setupFile > /dev/null
fi
source dm_command_setup.sh
eval "$DM_ROOT_DIR/src/python/dm/cat_web_service/cli/updateExperimentFilesCli.py $DM_COMMAND_ARGS"
......@@ -8,6 +8,7 @@ from dm.common.utility.encoder import Encoder
from dm.common.exceptions.dmException import DmException
from dm.common.exceptions.invalidRequest import InvalidRequest
from dm.common.objects.fileMetadata import FileMetadata
from dm.common.objects.asynchronousOperation import AsynchronousOperation
from catRestApi import CatRestApi
class FileCatApi(CatRestApi):
......@@ -54,6 +55,38 @@ class FileCatApi(CatRestApi):
responseData = self.sendSessionRequest(url=url, method='PUT')
return FileMetadata(responseData)
# Update dict must be of the form key:(oldValue,newValue)
@CatRestApi.execute
def updateExperimentFiles(self, experimentName, updateDict):
if not experimentName:
raise InvalidRequest('Invalid experiment name provided.')
if not updateDict:
raise InvalidRequest('Invalid update dictionary provided.')
url = '%s/filesByExperiment/%s' % (self.getContextRoot(), experimentName)
url += '?updateDict=%s' % (Encoder.encode(json.dumps(updateDict)))
responseData = self.sendSessionRequest(url=url, method='PUT')
return self.toDmObjectList(responseData, FileMetadata)
# Update dict must be of the form key:(oldValue,newValue)
@CatRestApi.execute
def updateExperimentFilesAsync(self, experimentName, updateDict):
if not experimentName:
raise InvalidRequest('Invalid experiment name provided.')
if not updateDict:
raise InvalidRequest('Invalid update dictionary provided.')
url = '%s/filesByExperimentAsync/%s' % (self.getContextRoot(), experimentName)
url += '?updateDict=%s' % (Encoder.encode(json.dumps(updateDict)))
responseData = self.sendSessionRequest(url=url, method='PUT')
return AsynchronousOperation(responseData)
@CatRestApi.execute
def getAsyncUpdateStatus(self, id):
if not id:
raise InvalidRequest('Invalid async operation id provided.')
url = '%s/asyncUpdates/%s' % (self.getContextRoot(), id)
responseData = self.sendSessionRequest(url=url, method='GET')
return AsynchronousOperation(responseData)
@CatRestApi.execute
def getExperimentFiles(self, experimentName, queryDict={}):
if not experimentName:
......
#!/usr/bin/env python
from dm.cat_web_service.api.fileCatApi import FileCatApi
from dm.common.exceptions.invalidRequest import InvalidRequest
from catWebServiceSessionCli import CatWebServiceSessionCli
class UpdateExperimentFilesCli(CatWebServiceSessionCli):
def __init__(self):
CatWebServiceSessionCli.__init__(self, validArgCount=self.ANY_NUMBER_OF_POSITIONAL_ARGS)
self.addOption('', '--experiment', dest='experimentName', help='Experiment name.')
self.addOption('', '--asynchronous', dest='asynchronous', action='store_true', default=False, help='Use asynchronous operation. With this flag, command will return asynchronous update id, which may be used to retrieve update status at a later time.')
def checkArgs(self):
if self.options.experimentName is None:
raise InvalidRequest('Experiment name must be provided.')
def getExperimentName(self):
return self.options.experimentName
def getAsynchronousFlag(self):
return self.options.asynchronous
def runCommand(self):
self.parseArgs(usage="""
dm-update-experiment-files --experiment=EXPERIMENTNAME
[--asynchronous]
key1:oldValue1:newValue1 [, key2:oldValue2:newValue2, ...]
Description:
Update experiment files in the metadata catalog. For every specified key
replacement <old value> => <new value> will be made. In case of strings,
replacements are done on substrings. For lists, replacements are done
on every list member. In synchronous mode, the command will return list
of updated files. In asynchronous mode, the command will return update
operation id, so that status can be retrieved at a later time.
""")
self.checkArgs()
api = FileCatApi(self.getLoginUsername(), self.getLoginPassword(), self.getServiceHost(), self.getServicePort(), self.getServiceProtocol())
updateDict = self.splitArgsIntoDictOfTuples()
if not self.getAsynchronousFlag():
fileMetadataList = api.updateExperimentFiles(self.getExperimentName(), updateDict)
for fileMetadata in fileMetadataList:
print fileMetadata.getDisplayString(self.getDisplayKeys(), self.getDisplayFormat())
else:
asyncOperation = api.updateExperimentFilesAsync(self.getExperimentName(), updateDict)
print asyncOperation.getDisplayString(self.getDisplayKeys(), self.getDisplayFormat())
#######################################################################
# Run command.
if __name__ == '__main__':
cli = UpdateExperimentFilesCli()
cli.run()
......@@ -55,6 +55,23 @@ class FileRouteDescriptor:
'method' : ['PUT']
},
{
'name' : 'updateExperimentFilesAsync',
'path' : '%s/filesByExperimentAsync/:(experimentName)' % contextRoot,
'controller' : fileSessionController,
'action' : 'updateExperimentFilesAsync',
'method' : ['PUT']
},
# Get experiment files update status
{
'name' : 'getAsyncUpdateStatus',
'path' : '%s/asyncUpdates/:(id)' % contextRoot,
'controller' : fileSessionController,
'action' : 'getAsyncUpdateStatus',
'method' : ['GET']
},
# Get experiment file info list
{
'name' : 'getExperimentFiles',
......
......@@ -3,6 +3,7 @@
import cherrypy
import json
from dm.common.utility.encoder import Encoder
from dm.common.utility.dictUtility import DictUtility
from dm.common.service.dmSessionController import DmSessionController
from dm.cat_web_service.service.impl.fileSessionControllerImpl import FileSessionControllerImpl
......@@ -77,14 +78,40 @@ class FileSessionController(DmSessionController):
if not encodedUpdateDict:
raise InvalidRequest('Invalid update dict provided.')
updateDict = json.loads(Encoder.decode(encodedUpdateDict))
synchronousResponse = kwargs.get('synchronousResponse', True)
if synchronousResponse:
self.logger.debug('Updating files for experiment %s with: %s' % (experimentName, updateDict))
response = self.fileSessionControllerImpl.updateExperimentFiles(experimentName, updateDict).getFullJsonRep()
else:
response = self.fileSessionControllerImpl.updateExperimentFilesAsync(experimentName, updateDict).getFullJsonRep()
# Update dict must be of the form key:(oldValue,newValue)
# JSON will convert tuples to lists, so we have to convert those back
updateDict = DictUtility.convertListsToTuples(updateDict)
response = self.listToJson(self.fileSessionControllerImpl.updateExperimentFiles(experimentName, updateDict))
return response
@cherrypy.expose
@DmSessionController.require(DmSessionController.canManageStation())
@DmSessionController.execute
def updateExperimentFilesAsync(self, experimentName, **kwargs):
if not experimentName:
raise InvalidRequest('Invalid experiment name provided.')
encodedUpdateDict = kwargs.get('updateDict')
if not encodedUpdateDict:
raise InvalidRequest('Invalid update dict provided.')
updateDict = json.loads(Encoder.decode(encodedUpdateDict))
# Update dict must be of the form key:(oldValue,newValue)
# JSON will convert tuples to lists, so we have to convert those back
updateDict = DictUtility.convertListsToTuples(updateDict)
response = self.fileSessionControllerImpl.updateExperimentFilesAsync(experimentName, updateDict).getFullJsonRep()
return response
@cherrypy.expose
@DmSessionController.require(DmSessionController.canManageStation())
@DmSessionController.execute
def getAsyncUpdateStatus(self, id, **kwargs):
if not id:
raise InvalidRequest('Invalid async operation id provided.')
return self.fileSessionControllerImpl.getAsyncUpdateStatus(id).getFullJsonRep()
@cherrypy.expose
@DmSessionController.require(DmSessionController.canManageStation())
@DmSessionController.execute
......
......@@ -5,6 +5,7 @@
#
import threading
import uuid
from dm.common.constants import dmProcessingStatus
from dm.common.objects.dmObject import DmObject
from dm.common.objects.dmObjectManager import DmObjectManager
......@@ -32,7 +33,7 @@ class FileSessionControllerImpl(DmObjectManager):
return self.fileMongoDbApi.updateExperimentFileById(fileInfo)
def updateExperimentFiles(self, experimentName, updateDict, asyncOp=None):
return self.fileMongoDbApi.updateExperimentFiles(experimentName, updateDict, asyncOp)
return self.fileMongoDbApi.updateExperimentFiles(experimentName, updateDict, asyncOp=asyncOp)
def updateExperimentFilesAsync(self, experimentName, updateDict):
opId = str(uuid.uuid4())
......@@ -49,6 +50,9 @@ class FileSessionControllerImpl(DmObjectManager):
self.logger.debug('Scheduled files update for experiment %s with: %s' % (experimentName, updateDict))
return asyncOp
def getAsyncUpdateStatus(self, id):
return self.asyncOpTracker.get(id)
def getExperimentFiles(self, experimentName, queryDict):
return self.fileMongoDbApi.getExperimentFiles(experimentName, queryDict=queryDict)
......
......@@ -23,6 +23,7 @@ class DmCli(object):
""" Base dm command line interface class. """
DEFAULT_SESSION_CACHE_FILE = OsUtility.getUserHomeDir() + '/.dm/.session.cache'
ANY_NUMBER_OF_POSITIONAL_ARGS = 10000000
RESERVED_STRING = '__||__'
def __init__(self, validArgCount=0):
self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
......@@ -180,6 +181,25 @@ class DmCli(object):
argDict[key] = value
return argDict
def splitArgsIntoDictOfTuples(self, keyValueDelimiter=':'):
""" Returns the command line argument list as dictionary of
key/(value1,value2,...) pairs. Each argument is split using specified
delimiter. """
argDict = {}
for a in self.args:
# Find escaped delimiter first
escapedDelimiter = '\%s' % keyValueDelimiter
a2 = a.replace(escapedDelimiter, self.RESERVED_STRING)
sList = a2.split(keyValueDelimiter)
# Restore delimiter
for i in range(0,len(sList)):
sList[i] = sList[i].replace(self.RESERVED_STRING, keyValueDelimiter)
key = sList[0]
value = tuple(sList[i] for i in range(1,len(sList)))
argDict[key] = value
return argDict
def getArg(self, i):
""" Returns the i-th command line argument. """
return self.args[i]
......
......@@ -6,6 +6,6 @@ class AsynchronousOperation(DmObject):
DEFAULT_KEY_LIST = [ 'id', 'name', 'type', 'message', 'status' ]
def __init__(self, dict):
def __init__(self, dict={}):
DmObject.__init__(self, dict)
#!/usr/bin/env python
import copy
import types
class DictUtility:
......@@ -40,6 +41,24 @@ class DictUtility:
del dict2[key]
return dict2
@classmethod
def convertListsToTuples(cls, dict, includeKeys=[], excludeKeys=[]):
dict2 = copy.deepcopy(dict)
if len(includeKeys):
for key in includeKeys:
value = dict.get(key)
if type(value) is types.ListType:
dict2[key] = tuple(value[i] for i in range(0,len(value)))
else:
for key in dict.keys():
if key not in excludeKeys:
value = dict.get(key)
if type(value) is types.ListType:
dict2[key] = tuple(value[i] for i in range(0,len(value)))
return dict2
#######################################################################
# Testing.
if __name__ == '__main__':
......
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