Example #1
0
    def recover_step(self, message: dict):
        ''' given an execution id and a pointer from the persistent storage,
        return the asociated process node to continue its execution '''
        try:
            pointer = Pointer.get_or_exception(message['pointer_id'])
            if pointer.status != 'ongoing':
                raise ModelNotFoundError(
                    'Specified pointer never existed, and never will', )

        except ModelNotFoundError:
            raise InconsistentState('Queued dead pointer')

        user = User.get_by('identifier', message.get('user_identifier'))

        if user is None:
            if message.get('user_identifier') == '__system__':
                user = User(identifier='__system__', fullname='System').save()
            else:
                raise InconsistentState('sent identifier of unexisten user')

        return (
            pointer,
            user,
            message['input'],
        )
Example #2
0
    def get_by_or_exception(cls, field, value):
        obj = cls.get_by(field, value)

        if obj is None:
            raise ModelNotFoundError('This object does not exist in database')

        return obj
Example #3
0
    def get_or_exception(cls, id):
        ''' Tries to retrieve an instance of this model from the database or
        raises an exception in case of failure '''
        obj = cls.get(id)

        if obj is None:
            raise ModelNotFoundError('This object does not exist in database')

        return obj
Example #4
0
def process_status(id):
    collection = mongo.db[app.config['EXECUTION_COLLECTION']]

    try:
        exc = next(collection.find({'id': id}))
    except StopIteration:
        raise ModelNotFoundError(
            'Specified execution never existed, and never will')

    return jsonify({
        'data': json_prepare(exc),
    })
Example #5
0
def execution_template(id):
    # load values
    collection = mongo.db[flask.current_app.config['EXECUTION_COLLECTION']]

    try:
        execution = next(collection.find({'id': id}))
    except StopIteration:
        raise ModelNotFoundError(
            'Specified execution never existed, and never will')

    if 'process_name' not in execution:
        return 'Not supported for old processes', 409

    context = make_context(execution, flask.current_app.config)

    # load template
    process_name = execution['process_name']
    name, version, _ = process_name.split('.')

    # Loaders will be inserted in inverse order and then reversed. The fallback
    # is the default template at ``templates/summary.html``
    paths = [
        path.join(path.dirname(path.realpath(__file__)), '../../templates'),
    ]

    app_template_path = flask.current_app.config['TEMPLATE_PATH']
    if app_template_path is not None and path.isdir(app_template_path):
        paths.append(app_template_path)

        process_dir = path.join(app_template_path, name)
        if path.isdir(process_dir):
            paths.append(process_dir)

        process_version_dir = path.join(process_dir, version)
        if path.isdir(process_version_dir):
            paths.append(process_version_dir)

    env = Environment(loader=FileSystemLoader(reversed(paths)),
                      autoescape=select_autoescape(['html', 'xml']))

    env.filters['datetimeformat'] = datetimeformat

    for name, function in flask.current_app.config['JINJA_FILTERS'].items():
        env.filters[name] = function

    return flask.make_response(
        env.get_template('summary.html').render(**context),
        200,
    )
Example #6
0
    def reload(self):
        ''' reloads this object so if it was updated in the database it now
        contains the new values'''
        key = self.key()
        redis = type(self).get_redis()

        if not redis.exists(key):
            raise ModelNotFoundError('This object has been deleted')

        data = debyte_hash(redis.hgetall(key))

        for fieldname, field in self.proxy:
            value = field.recover(data, redis)

            setattr(self, fieldname, value)

        return self
Example #7
0
    def cancel_execution(self, message):
        execution = Execution.get_or_exception(message['execution_id'])
        if execution.status != 'ongoing':
            raise ModelNotFoundError(
                'Specified execution never existed, and never will', )

        execution.status = 'cancelled'
        execution.finished_at = datetime.now()
        execution.save()

        for pointer in execution.pointers.q().filter(status='ongoing'):
            pointer.status = 'cancelled'
            pointer.finished_at = datetime.now()
            pointer.save()

        self.execution_collection().update_one({
            'id': execution.id,
        }, {
            '$set': {
                'status': execution.status,
                'finished_at': execution.finished_at
            }
        })

        self.pointer_collection().update_many(
            {
                'execution.id': execution.id,
                'state': 'ongoing',
            }, {
                '$set': {
                    'state': 'cancelled',
                    'finished_at': execution.finished_at
                }
            })

        self.pointer_collection().update_many({
            'execution.id': execution.id,
        }, {'$set': {
            'execution': execution.to_json(),
        }})
Example #8
0
def execution_template(id):
    # load values
    collection = mongo.db[app.config['EXECUTION_COLLECTION']]

    try:
        exc = next(collection.find({'id': id}))
    except StopIteration:
        raise ModelNotFoundError(
            'Specified execution never existed, and never will'
        )

    execution = json_prepare(exc)

    if 'process_name' not in exc:
        return 'Not supported for old processes', 409

    # prepare default template
    default = ['<div><b>Available keys</b></div>']
    context = get_values(execution)

    for key in context:
        token = '<div>{}</div>'
        default.append(token.format(key, key))

    template_string = ''.join(default)

    # load template
    template_dir = app.config['TEMPLATE_PATH']
    process_name = execution['process_name']
    name, version, _ = process_name.split('.')

    # file or folder
    ff_name = '.'.join([name, version])

    template_name = None
    # If template file exists...
    if os.path.isfile(
        os.path.join(template_dir, ff_name + '.html')
    ):
        template_name = ff_name + '.html'
    # Else check for any folder...
    elif os.path.isfile(
        os.path.join(template_dir, ff_name + '/', 'template.html')
    ):
        # set loader for "includes"
        custom_loader = jinja2.ChoiceLoader([
            jinja2.FileSystemLoader([
                app.config['TEMPLATE_PATH'] + '/' + ff_name,
            ]),
        ])
        bp.jinja_loader = custom_loader

        # ... and return the "main template"
        template_name = ff_name + '/template.html'

    if template_name:
        with open(os.path.join(template_dir, template_name), 'r') as contents:
            template_string = contents.read()

    # return template interpolation
    return make_response(
        render_template_string(template_string, **context),
        200,
    )
Example #9
0
    def patch(self, message):
        execution = Execution.get_or_exception(message['execution_id'])
        if execution.status != 'ongoing':
            raise ModelNotFoundError(
                'Specified execution never existed, and never will', )

        xml = Xml.load(self.config, execution.process_name, direct=True)

        # set nodes with pointers as unfilled, delete pointers
        updates = {}

        user = User.get_by(
            'identifier',
            message.get('user_identifier'),
        )

        if user is None:
            if message.get('user_identifier') == '__system__':
                user = User(identifier='__system__', fullname='System').save()
            else:
                raise InconsistentState('sent identifier of unexisten user')

        for pointer in execution.pointers.q().filter(status='ongoing'):
            updates['state.items.{node}.state'.format(
                node=pointer.node_id, )] = 'unfilled'
            pointer.status = 'cancelled'
            pointer.finished_at = datetime.now()
            pointer.save()

            self.pointer_collection().update_one({
                'id': pointer.id,
            }, {
                '$set': {
                    'state': 'cancelled',
                    'finished_at': pointer.finished_at,
                    'patch': {
                        'comment':
                        message['comment'],
                        'inputs':
                        message['inputs'],
                        'actor':
                        user.to_json(include=[
                            '_type',
                            'fullname',
                            'identifier',
                        ]),
                    },
                },
            })

        self.execution_collection().update_one({
            'id': execution.id,
        }, {
            '$set': updates,
        })

        # retrieve updated state
        state = next(self.execution_collection().find({'id': execution.id}))

        state_updates, array_filters = cascade_invalidate(
            xml, state, message['inputs'], message['comment'])

        # update state
        self.execution_collection().update_one(
            {'id': state['id']},
            {'$set': state_updates},
            array_filters=array_filters,
        )

        # retrieve updated state
        state = next(self.execution_collection().find({'id': execution.id}))

        first_invalid_node = track_next_node(xml, state, self.get_mongo(),
                                             self.config)

        # wakeup and start execution from the found invalid node
        self.wakeup_and_notify(first_invalid_node, execution, state)