Beispiel #1
0
def genHandlerToRunDockerCLI(dockerImage, cliRelPath, restResource):
    """Generates a handler to run docker CLI using girder_worker

    Parameters
    ----------
    dockerImage : str
        Docker image in which the CLI resides
    cliRelPath : str
        Relative path of the CLI which is needed to run the CLI by running
        the command docker run `dockerImage` `cliRelPath`
    restResource : girder.api.rest.Resource
        The object of a class derived from girder.api.rest.Resource to which
        this handler will be attached

    Returns
    -------
    function
        Returns a function that runs the CLI using girder_worker
    """

    cliName = os.path.normpath(cliRelPath).replace(os.sep, '.')

    # get xml spec
    str_xml = subprocess.check_output(
        ['docker', 'run', dockerImage, cliRelPath, '--xml'])

    # parse cli xml spec
    xmlFile = 'temp.xml'
    with open(xmlFile, 'w') as f:
        f.write(str_xml)

    clim = CLIModule(xmlFile)

    os.remove(xmlFile)

    # create CLI description string
    str_description = ['Description: <br/><br/>' + clim.description]

    if clim.version is not None and len(clim.version) > 0:
        str_description.append('Version: ' + clim.version)

    if clim.license is not None and len(clim.license) > 0:
        str_description.append('License: ' + clim.license)

    if clim.contributor is not None and len(clim.contributor) > 0:
        str_description.append('Author(s): ' + clim.contributor)

    if clim.acknowledgements is not None and \
       len(clim.acknowledgements) > 0:
        str_description.append('Acknowledgements: ' + clim.acknowledgements)

    str_description = '<br/><br/>'.join(str_description)

    # do stuff needed to create REST endpoint for cLI
    handlerDesc = Description(clim.title).notes(str_description)

    # get CLI parameters
    index_params, opt_params, simple_out_params = _getCLIParameters(clim)

    # add indexed input parameters
    index_input_params = filter(lambda p: p.channel == 'input', index_params)

    _addIndexedInputParamsToHandler(index_input_params, handlerDesc)

    # add indexed output parameters
    index_output_params = filter(lambda p: p.channel == 'output', index_params)

    _addIndexedOutputParamsToHandler(index_output_params, handlerDesc)

    # add optional input parameters
    opt_input_params = filter(lambda p: p.channel != 'output', opt_params)

    _addOptionalInputParamsToHandler(opt_input_params, handlerDesc)

    # add optional output parameters
    opt_output_params = filter(lambda p: p.channel == 'output', opt_params)

    _addOptionalOutputParamsToHandler(opt_output_params, handlerDesc)

    # add returnparameterfile if there are simple output params
    if len(simple_out_params) > 0:
        _addReturnParameterFileParamToHandler(handlerDesc)

    # define CLI handler function
    @boundHandler(restResource)
    @access.user
    @describeRoute(handlerDesc)
    def cliHandler(self, **hargs):

        user = self.getCurrentUser()
        token = self.getCurrentToken()['_id']

        # create job
        jobModel = self.model('job', 'jobs')
        jobTitle = '.'.join((restResource.resourceName, cliName))
        job = jobModel.createJob(title=jobTitle,
                                 type=jobTitle,
                                 handler='worker_handler',
                                 user=user)
        kwargs = {
            'validate': False,
            'auto_convert': True,
            'cleanup': True,
            'inputs': dict(),
            'outputs': dict()
        }

        # create job info
        jobToken = jobModel.createJobToken(job)
        kwargs['jobInfo'] = wutils.jobInfoSpec(job, jobToken)

        # initialize task spec
        taskSpec = {
            'name': cliName,
            'mode': 'docker',
            'docker_image': dockerImage,
            'pull_image': True,
            'inputs': [],
            'outputs': []
        }

        _addIndexedInputParamsToTaskSpec(index_input_params, taskSpec)

        _addIndexedOutputParamsToTaskSpec(index_output_params, taskSpec, hargs)

        _addOptionalInputParamsToTaskSpec(opt_input_params, taskSpec)

        _addOptionalOutputParamsToTaskSpec(opt_output_params, taskSpec, hargs)

        if len(simple_out_params) > 0:
            _addReturnParameterFileParamToTaskSpec(taskSpec, hargs)

        kwargs['task'] = taskSpec

        # add input/output parameter bindings
        _addIndexedInputParamBindings(index_input_params, kwargs['inputs'],
                                      hargs, token)

        _addIndexedOutputParamBindings(index_output_params, kwargs['outputs'],
                                       hargs, user, token)

        _addOptionalInputParamBindings(opt_input_params, kwargs['inputs'],
                                       hargs, user, token)

        _addOptionalOutputParamBindings(opt_output_params, kwargs['outputs'],
                                        hargs, user, token)

        if len(simple_out_params) > 0:
            _addReturnParameterFileBinding(kwargs['outputs'], hargs, user,
                                           token)

        # construct container arguments
        containerArgs = [cliRelPath]

        _addOptionalInputParamsToContainerArgs(opt_input_params, containerArgs,
                                               hargs)

        _addOptionalOutputParamsToContainerArgs(opt_input_params,
                                                containerArgs, kwargs, hargs)

        _addReturnParameterFileToContainerArgs(containerArgs, kwargs, hargs)

        _addIndexedParamsToContainerArgs(index_params, containerArgs, hargs)

        taskSpec['container_args'] = containerArgs

        # schedule job
        job['kwargs'] = kwargs
        job = jobModel.save(job)
        jobModel.scheduleJob(job)

        # return result
        return jobModel.filter(job, user)

    handlerFunc = cliHandler

    # loadmodel stuff for indexed input params on girder
    index_input_params_on_girder = filter(_is_on_girder, index_input_params)

    for param in index_input_params_on_girder:

        curModel = _SLICER_TYPE_TO_GIRDER_MODEL_MAP[param.typ]
        curMap = {param.name + _girderInputFileSuffix: param.name}

        handlerFunc = loadmodel(map=curMap,
                                model=curModel,
                                level=AccessType.READ)(handlerFunc)

    # loadmodel stuff for indexed output params on girder
    index_output_params_on_girder = filter(_is_on_girder, index_output_params)

    for param in index_output_params_on_girder:

        curModel = 'folder'
        curMap = {param.name + _girderOutputFolderSuffix: param.name}

        handlerFunc = loadmodel(map=curMap,
                                model=curModel,
                                level=AccessType.WRITE)(handlerFunc)

    return handlerFunc
def genHandlerToRunDockerCLI(dockerImage, cliRelPath, restResource):
    """Generates a handler to run docker CLI using girder_worker

    Parameters
    ----------
    dockerImage : str
        Docker image in which the CLI resides
    cliRelPath : str
        Relative path of the CLI which is needed to run the CLI by running
        the command docker run `dockerImage` `cliRelPath`
    restResource : girder.api.rest.Resource
        The object of a class derived from girder.api.rest.Resource to which
        this handler will be attached

    Returns
    -------
    function
        Returns a function that runs the CLI using girder_worker
    """

    cliName = os.path.normpath(cliRelPath).replace(os.sep, '.')

    # get xml spec
    str_xml = subprocess.check_output(['docker', 'run', dockerImage,
                                       cliRelPath, '--xml'])

    # parse cli xml spec
    xmlFile = 'temp.xml'
    with open(xmlFile, 'w') as f:
        f.write(str_xml)

    clim = CLIModule(xmlFile)

    os.remove(xmlFile)

    # create CLI description string
    str_description = ['Description: <br/><br/>' + clim.description]

    if clim.version is not None and len(clim.version) > 0:
        str_description.append('Version: ' + clim.version)

    if clim.license is not None and len(clim.license) > 0:
        str_description.append('License: ' + clim.license)

    if clim.contributor is not None and len(clim.contributor) > 0:
        str_description.append('Author(s): ' + clim.contributor)

    if clim.acknowledgements is not None and \
       len(clim.acknowledgements) > 0:
        str_description.append(
            'Acknowledgements: ' + clim.acknowledgements)

    str_description = '<br/><br/>'.join(str_description)

    # do stuff needed to create REST endpoint for cLI
    handlerDesc = Description(clim.title).notes(str_description)

    # get CLI parameters
    index_params, opt_params, simple_out_params = _getCLIParameters(clim)

    # add indexed input parameters
    index_input_params = filter(lambda p: p.channel == 'input', index_params)

    _addIndexedInputParamsToHandler(index_input_params, handlerDesc)

    # add indexed output parameters
    index_output_params = filter(lambda p: p.channel == 'output', index_params)

    _addIndexedOutputParamsToHandler(index_output_params, handlerDesc)

    # add optional input parameters
    opt_input_params = filter(lambda p: p.channel != 'output', opt_params)

    _addOptionalInputParamsToHandler(opt_input_params, handlerDesc)

    # add optional output parameters
    opt_output_params = filter(lambda p: p.channel == 'output', opt_params)

    _addOptionalOutputParamsToHandler(opt_output_params, handlerDesc)

    # add returnparameterfile if there are simple output params
    if len(simple_out_params) > 0:
        _addReturnParameterFileParamToHandler(handlerDesc)

    # define CLI handler function
    @boundHandler(restResource)
    @access.user
    @describeRoute(handlerDesc)
    def cliHandler(self, **hargs):

        user = self.getCurrentUser()
        token = self.getCurrentToken()['_id']

        # create job
        jobModel = self.model('job', 'jobs')
        jobTitle = '.'.join((restResource.resourceName, cliName))
        job = jobModel.createJob(title=jobTitle,
                                 type=jobTitle,
                                 handler='worker_handler',
                                 user=user)
        kwargs = {
            'validate': False,
            'auto_convert': True,
            'cleanup': True,
            'inputs': dict(),
            'outputs': dict()
        }

        # create job info
        jobToken = jobModel.createJobToken(job)
        kwargs['jobInfo'] = wutils.jobInfoSpec(job, jobToken)

        # initialize task spec
        taskSpec = {'name': cliName,
                    'mode': 'docker',
                    'docker_image': dockerImage,
                    'pull_image': False,
                    'inputs': [],
                    'outputs': []}

        _addIndexedInputParamsToTaskSpec(index_input_params, taskSpec)

        _addIndexedOutputParamsToTaskSpec(index_output_params, taskSpec, hargs)

        _addOptionalInputParamsToTaskSpec(opt_input_params, taskSpec)

        _addOptionalOutputParamsToTaskSpec(opt_output_params, taskSpec, hargs)

        if len(simple_out_params) > 0:
            _addReturnParameterFileParamToTaskSpec(taskSpec, hargs)

        kwargs['task'] = taskSpec

        # add input/output parameter bindings
        _addIndexedInputParamBindings(index_input_params,
                                      kwargs['inputs'], hargs, token)

        _addIndexedOutputParamBindings(index_output_params,
                                       kwargs['outputs'], hargs, user, token)

        _addOptionalInputParamBindings(opt_input_params,
                                       kwargs['inputs'], hargs, user, token)

        _addOptionalOutputParamBindings(opt_output_params,
                                        kwargs['outputs'], hargs, user, token)

        if len(simple_out_params) > 0:
            _addReturnParameterFileBinding(kwargs['outputs'],
                                           hargs, user, token)

        # construct container arguments
        containerArgs = [cliRelPath]

        _addOptionalInputParamsToContainerArgs(opt_input_params,
                                               containerArgs, hargs)

        _addOptionalOutputParamsToContainerArgs(opt_input_params,
                                                containerArgs, kwargs, hargs)

        _addReturnParameterFileToContainerArgs(containerArgs, kwargs, hargs)

        _addIndexedParamsToContainerArgs(index_params,
                                         containerArgs, hargs)

        taskSpec['container_args'] = containerArgs

        # schedule job
        job['kwargs'] = kwargs
        job = jobModel.save(job)
        jobModel.scheduleJob(job)

        # return result
        return jobModel.filter(job, user)

    handlerFunc = cliHandler

    # loadmodel stuff for indexed input params on girder
    index_input_params_on_girder = filter(_is_on_girder, index_input_params)

    for param in index_input_params_on_girder:

        curModel = _SLICER_TYPE_TO_GIRDER_MODEL_MAP[param.typ]
        curMap = {param.name + _girderInputFileSuffix: param.name}

        handlerFunc = loadmodel(map=curMap,
                                model=curModel,
                                level=AccessType.READ)(handlerFunc)

    # loadmodel stuff for indexed output params on girder
    index_output_params_on_girder = filter(_is_on_girder, index_output_params)

    for param in index_output_params_on_girder:

        curModel = 'folder'
        curMap = {param.name + _girderOutputFolderSuffix: param.name}

        handlerFunc = loadmodel(map=curMap,
                                model=curModel,
                                level=AccessType.WRITE)(handlerFunc)

    return handlerFunc
Beispiel #3
0
def genHandlerToRunDockerCLI(dockerImage, cliRelPath, cliXML, restResource): # noqa
    """Generates a handler to run docker CLI using girder_worker

    Parameters
    ----------
    dockerImage : str
        Docker image in which the CLI resides
    cliRelPath : str
        Relative path of the CLI which is needed to run the CLI by running
        the command docker run `dockerImage` `cliRelPath`
    cliXML:str
        Cached copy of xml spec for this cli
    restResource : girder.api.rest.Resource
        The object of a class derived from girder.api.rest.Resource to which
        this handler will be attached

    Returns
    -------
    function
        Returns a function that runs the CLI using girder_worker

    """

    cliName = os.path.normpath(cliRelPath).replace(os.sep, '.')

    # get xml spec
    str_xml = cliXML
    # parse cli xml spec
    with tempfile.NamedTemporaryFile(suffix='.xml') as f:
        f.write(str_xml)
        f.flush()
        clim = CLIModule(f.name)

    # create CLI description string
    str_description = ['Description: <br/><br/>' + clim.description]

    if clim.version is not None and len(clim.version) > 0:
        str_description.append('Version: ' + clim.version)

    if clim.license is not None and len(clim.license) > 0:
        str_description.append('License: ' + clim.license)

    if clim.contributor is not None and len(clim.contributor) > 0:
        str_description.append('Author(s): ' + clim.contributor)

    if clim.acknowledgements is not None and \
       len(clim.acknowledgements) > 0:
        str_description.append(
            'Acknowledgements: ' + clim.acknowledgements)

    str_description = '<br/><br/>'.join(str_description)

    # do stuff needed to create REST endpoint for cLI
    handlerDesc = Description(clim.title).notes(str_description)

    # print handlerDesc
    # get CLI parameters
    index_params, opt_params, simple_out_params = _getCLIParameters(clim)

    # print index_params [<CLIParameter 'inputMultipleImage' of type directory>,
    # <CLIParameter 'outputThresholding' of type file>, <CLIParameter 'tableFile' of type file>]
    # add indexed input parameters
    index_input_params = filter(lambda p: p.channel != 'output', index_params)
    # print index_input_params
    # print index_input_params [<CLIParameter 'inputMultipleImage' of type directory>]
    _addIndexedInputParamsToHandler(index_input_params, handlerDesc)

    # add indexed output parameters
    index_output_params = filter(lambda p: p.channel == 'output', index_params)

    _addIndexedOutputParamsToHandler(index_output_params, handlerDesc)

    # add optional input parameters
    opt_input_params = filter(lambda p: p.channel != 'output', opt_params)

    _addOptionalInputParamsToHandler(opt_input_params, handlerDesc)

    # add optional output parameters
    opt_output_params = filter(lambda p: p.channel == 'output', opt_params)

    _addOptionalOutputParamsToHandler(opt_output_params, handlerDesc)
    # print simple_out_params
    # add returnparameterfile if there are simple output params
    if len(simple_out_params) > 0:
        _addReturnParameterFileParamToHandler(handlerDesc)

    # define CLI handler function
    @boundHandler(restResource)
    @access.user
    @describeRoute(handlerDesc)
    def cliHandler(self, **hargs):
        # print 'in cliHandler hargs is '
        # print hargs
        user = self.getCurrentUser()
        token = self.getCurrentToken()['_id']

        # create job
        jobModel = self.model('job', 'jobs')
        jobTitle = '.'.join((restResource.resourceName, cliName))

        # User Group access control,
        # register group into particular job so that this user can access this job
        groups = list(Group().list(user=user))

        groupsAccess = []
        for eachGroup in groups:
            eachGroupAccess = {'id': eachGroup['_id'], 'level': 0}
            groupsAccess.append(eachGroupAccess)

        job = jobModel.createJob(title=jobTitle,
                                 type=jobTitle,
                                 handler='worker_handler',
                                 user=user,
                                 otherFields={'access': {'groups': groupsAccess}})
        kwargs = {
            'validate': False,
            'auto_convert': True,
            'cleanup': True,
            'inputs': dict(),
            'outputs': dict()
        }

        # create job info
        jobToken = jobModel.createJobToken(job)
        kwargs['jobInfo'] = wutils.jobInfoSpec(job, jobToken)

        # initialize task spec
        taskSpec = {'name': cliName,
                    'mode': 'docker',
                    'docker_image': dockerImage,
                    'pull_image': False,
                    'inputs': [],
                    'outputs': []}

        _addIndexedInputParamsToTaskSpec(index_input_params, taskSpec)

        _addIndexedOutputParamsToTaskSpec(index_output_params, taskSpec, hargs)

        _addOptionalInputParamsToTaskSpec(opt_input_params, taskSpec)

        _addOptionalOutputParamsToTaskSpec(opt_output_params, taskSpec, hargs)

        if len(simple_out_params) > 0:
            _addReturnParameterFileParamToTaskSpec(taskSpec, hargs)

        kwargs['task'] = taskSpec

        # add input/output parameter bindings
        _addIndexedInputParamBindings(index_input_params,
                                      kwargs['inputs'], hargs, token)

        _addIndexedOutputParamBindings(index_output_params,
                                       kwargs['outputs'], hargs, user, token)

        _addOptionalInputParamBindings(opt_input_params,
                                       kwargs['inputs'], hargs, user, token)

        _addOptionalOutputParamBindings(opt_output_params,
                                        kwargs['outputs'], hargs, user, token)

        if len(simple_out_params) > 0:
            _addReturnParameterFileBinding(kwargs['outputs'],
                                           hargs, user, token)

        # construct container arguments
        containerArgs = [cliRelPath]

        _addOptionalInputParamsToContainerArgs(opt_input_params,
                                               containerArgs, hargs)

        _addOptionalOutputParamsToContainerArgs(opt_output_params,
                                                containerArgs, kwargs, hargs)

        _addReturnParameterFileToContainerArgs(containerArgs, kwargs, hargs)

        # print 'index_params'
        # print index_params
        _addIndexedParamsToContainerArgs(index_params,
                                         containerArgs, hargs)

        taskSpec['container_args'] = containerArgs

        # schedule job
        job['kwargs'] = kwargs
        # print '-------job is-------'
        # print job
        job = jobModel.save(job)
        jobModel.scheduleJob(job)

        # return result
        return jobModel.filter(job, user)

    handlerFunc = cliHandler
    # print _is_on_girder
    # loadmodel stuff for indexed input params on girder
    index_input_params_on_girder = filter(_is_on_girder, index_input_params)
    # print '---------'
    # print index_input_params_on_girder
    for param in index_input_params_on_girder:
        if param.flag == '-item':
            curModel = 'item'
            # print curModel
            if curModel != 'url':

                suffix = '_girderItemId'
                curMap = {param.identifier() + suffix: param.identifier()}
                # print curMap
                handlerFunc = loadmodel(map=curMap,
                                        model=curModel,
                                        level=AccessType.READ)(handlerFunc)
        else:
            curModel = _SLICER_TYPE_TO_GIRDER_MODEL_MAP[param.typ]
            # print curModel
            if curModel != 'url':

                suffix = _SLICER_TYPE_TO_GIRDER_INPUT_SUFFIX_MAP[param.typ]
                curMap = {param.identifier() + suffix: param.identifier()}
            #    print curMap
                handlerFunc = loadmodel(map=curMap,
                                        model=curModel,
                                        level=AccessType.READ)(handlerFunc)

    # loadmodel stuff for indexed output params on girder
    index_output_params_on_girder = filter(_is_on_girder, index_output_params)

    for param in index_output_params_on_girder:
        if param.flag == '-item':
            _girderOutputItemSuffix = '_girderItemId'
            curModel = 'item'
            curMap = {param.identifier() + _girderOutputItemSuffix: param.identifier()}
        else:
            curModel = 'folder'
            curMap = {param.identifier() + _girderOutputFolderSuffix: param.identifier()}
        handlerFunc = loadmodel(map=curMap,
                                model=curModel,
                                level=AccessType.WRITE)(handlerFunc)

    return handlerFunc