コード例 #1
0
    def post(self, action_execution):
        """Create new action_execution."""
        body = json.loads(pecan.request.body)

        LOG.info("Create action_execution [action_execution=%s]" % body)

        action_input = action_execution.input or None
        description = action_execution.description or None

        if action_input:
            try:
                action_input = json.loads(action_execution.input)

                if not isinstance(action_input, dict):
                    raise TypeError("Input should be dict type.")
            except (TypeError, ValueError) as e:
                raise exc.InputException(
                    "Input should be JSON-serialized dict string. Actual: %s, "
                    "error: %s" % (action_execution.input, e))

        name = action_execution.name
        params = body.get('params', {})

        if not name:
            raise exc.InputException(
                "Please provide at least action name to run action.")

        action_ex = rpc.get_engine_client().start_action(
            name, action_input, description=description, **params)

        return ActionExecution.from_dict(action_ex).to_dict()
コード例 #2
0
ファイル: workflows.py プロジェクト: kurtenbachkyle/mistral
def _get_environment(params):
    env = params.get('env', {})

    if not env:
        return {}

    if isinstance(env, dict):
        env_dict = env
    elif isinstance(env, six.string_types):
        env_db = db_api.load_environment(env)

        if not env_db:
            raise exc.InputException(
                'Environment is not found: %s' % env
            )

        env_dict = env_db.variables
    else:
        raise exc.InputException(
            'Unexpected value type for environment [env=%s, type=%s]'
            % (env, type(env))
        )

    if ('evaluate_env' in params and
            not params['evaluate_env']):
        return env_dict
    else:
        return expr.evaluate_recursively(env_dict, {'__env': env_dict})
コード例 #3
0
ファイル: execution.py プロジェクト: holcekt/mistral
        def _compute_delta(wf_ex):
            with db_api.transaction():
                # ensure that workflow execution exists
                db_api.get_workflow_execution(
                    id,
                    fields=(db_models.WorkflowExecution.id,)
                )

                delta = {}

                if wf_ex.state:
                    delta['state'] = wf_ex.state

                if wf_ex.description:
                    delta['description'] = wf_ex.description

                if wf_ex.params and wf_ex.params.get('env'):
                    delta['env'] = wf_ex.params.get('env')

                # Currently we can change only state, description, or env.
                if len(delta.values()) <= 0:
                    raise exc.InputException(
                        'The property state, description, or env '
                        'is not provided for update.'
                    )

                # Description cannot be updated together with state.
                if delta.get('description') and delta.get('state'):
                    raise exc.InputException(
                        'The property description must be updated '
                        'separately from state.'
                    )

                # If state change, environment cannot be updated
                # if not RUNNING.
                if (delta.get('env') and
                        delta.get('state') and
                        delta['state'] != states.RUNNING):
                    raise exc.InputException(
                        'The property env can only be updated when workflow '
                        'execution is not running or on resume from pause.'
                    )

                if delta.get('description'):
                    wf_ex = db_api.update_workflow_execution(
                        id,
                        {'description': delta['description']}
                    )

                if not delta.get('state') and delta.get('env'):
                    wf_ex = db_api.get_workflow_execution(id)
                    wf_ex = wf_service.update_workflow_execution_env(
                        wf_ex,
                        delta.get('env')
                    )

                return delta, wf_ex
コード例 #4
0
def validate_input(with_items_input):
    # Take only mapped values and check them.
    values = list(with_items_input.values())

    if not all([isinstance(v, list) for v in values]):
        raise exc.InputException("Wrong input format for: %s. List type is"
                                 " expected for each value." %
                                 with_items_input)

    required_len = len(values[0])

    if not all(len(v) == required_len for v in values):
        raise exc.InputException("Wrong input format for: %s. All arrays must"
                                 " have the same length." % with_items_input)
コード例 #5
0
ファイル: tasks.py プロジェクト: shubhamdang/mistral
    def _get_with_items_values(self):
        """Returns all values evaluated from 'with-items' expression.

        Example:
          DSL:
            with-items:
              - var1 in <% $.arrayI %>
              - var2 in <% $.arrayJ %>

        where arrayI = [1,2,3] and arrayJ = [a,b,c]

        The result of the method in this case will be:
            {
                'var1': [1,2,3],
                'var2': [a,b,c]
            }

        :return: Evaluated 'with-items' expression values.
        """

        exp_res = self.evaluate(self.task_spec.get_with_items())

        # Expression result may contain iterables instead of lists in the
        # dictionary values. So we need to convert them into lists and
        # perform all needed checks.

        result = {}

        required_len = -1

        for var, items in exp_res.items():
            if not isinstance(items, collections.Iterable):
                raise exc.InputException(
                    "Wrong input format for: %s. Iterable type is"
                    " expected for each value." % result)

            items_list = list(items)

            result[var] = items_list

            if required_len < 0:
                required_len = len(items_list)
            elif len(items_list) != required_len:
                raise exc.InputException(
                    "Wrong input format for: %s. All arrays must"
                    " have the same length." % exp_res)

        return result
コード例 #6
0
    def post(self, action_ex):
        """Create new action_execution.

        :param action_ex: Action to execute
        """
        acl.enforce('action_executions:create', context.ctx())
        LOG.debug(
            "Create action_execution [action_execution=%s]",
            action_ex
        )
        name = action_ex.name
        description = action_ex.description or None
        action_input = action_ex.input or {}
        params = action_ex.params or {}
        namespace = action_ex.workflow_namespace or ''

        if not name:
            raise exc.InputException(
                "Please provide at least action name to run action."
            )

        values = rpc.get_engine_client().start_action(
            name,
            action_input,
            description=description,
            namespace=namespace,
            **params
        )

        return resources.ActionExecution.from_dict(values)
コード例 #7
0
ファイル: workflows.py プロジェクト: nmaludy/mistral
def update_workflows(definition, scope='private', identifier=None,
                     namespace=''):
    LOG.debug("updating workflows")
    wf_list_spec = spec_parser.get_workflow_list_spec_from_yaml(definition)
    wfs = wf_list_spec.get_workflows()

    if identifier and len(wfs) > 1:
        raise exc.InputException(
            "More than one workflows are not supported for "
            "update with identifier. [identifier: %s]" %
            identifier
        )

    db_wfs = []

    with db_api.transaction():
        for wf_spec in wf_list_spec.get_workflows():
            db_wfs.append(_update_workflow(
                wf_spec,
                definition,
                scope,
                namespace=namespace,
                identifier=identifier
            ))

    return db_wfs
コード例 #8
0
    def put(self, env):
        """Update an environment.

        :param env: Required. Environment structure to update
        """
        acl.enforce('environments:update', context.ctx())

        if not env.name:
            raise exceptions.InputException(
                'Name of the environment is not provided.'
            )

        LOG.info("Update environment [name=%s, env=%s]", env.name, env)

        definition = json.loads(wsme_pecan.pecan.request.body.decode())
        definition.pop('name')

        self._validate_environment(
            definition,
            ['description', 'variables', 'scope']
        )

        db_model = db_api.update_environment(env.name, env.to_dict())

        return resources.Environment.from_db_model(db_model)
コード例 #9
0
def validate_input(definition, input, spec=None):
    input_param_names = copy.copy((input or {}).keys())
    missing_param_names = []

    spec_input = (spec.get_input() if spec else
                  utils.get_input_dict_from_input_string(definition.input))

    for p_name, p_value in six.iteritems(spec_input):
        if p_value is utils.NotDefined and p_name not in input_param_names:
            missing_param_names.append(p_name)
        if p_name in input_param_names:
            input_param_names.remove(p_name)

    if missing_param_names or input_param_names:
        msg = 'Invalid input [name=%s, class=%s'
        msg_props = [definition.name, spec.__class__.__name__]

        if missing_param_names:
            msg += ', missing=%s'
            msg_props.append(missing_param_names)

        if input_param_names:
            msg += ', unexpected=%s'
            msg_props.append(input_param_names)

        msg += ']'

        raise exc.InputException(msg % tuple(msg_props))
    else:
        utils.merge_dicts(input, spec_input, overwrite=False)
コード例 #10
0
def update_workflows(definition, scope='private', identifier=None):
    wf_list_spec = spec_parser.get_workflow_list_spec_from_yaml(definition)
    wfs = wf_list_spec.get_workflows()

    if identifier and len(wfs) > 1:
        raise exc.InputException(
            "More than one workflows are not supported for update with UUID "
            "provided.")

    db_wfs = []

    with db_api.transaction():
        for wf_spec in wf_list_spec.get_workflows():
            db_wfs.append(
                _update_workflow(wf_spec,
                                 definition,
                                 scope,
                                 identifier=identifier))

    # Once transaction has committed we need to update specification cache.

    for db_wf, wf_spec in zip(db_wfs, wf_list_spec.get_workflows()):
        spec_parser.update_workflow_cache(db_wf.id, wf_spec)

    return db_wfs
コード例 #11
0
ファイル: workflows.py プロジェクト: yangyimincn/mistral
def update_workflows(definition,
                     scope='private',
                     identifier=None,
                     namespace=''):
    LOG.debug("Updating workflows")

    wf_list_spec = spec_parser.get_workflow_list_spec_from_yaml(definition,
                                                                validate=True)
    wfs = wf_list_spec.get_workflows()

    if identifier and len(wfs) > 1:
        raise exc.InputException(
            "More than one workflows are not supported for "
            "update with identifier. [identifier: %s]" % identifier)

    db_wfs = []

    wfs_yaml = yaml.load(definition) if len(wfs) != 1 else None

    with db_api.transaction():
        for wf_spec in wfs:
            if len(wfs) != 1:
                definition = _cut_wf_definition_from_all(
                    wfs_yaml, wf_spec.get_name())

            db_wfs.append(
                _update_workflow(wf_spec,
                                 definition,
                                 scope,
                                 namespace=namespace,
                                 identifier=identifier))

    return db_wfs
コード例 #12
0
ファイル: environment.py プロジェクト: xavierhardy/mistral
    def _validate_environment(env_dict, legal_keys):
        if env_dict is None:
            return

        if set(env_dict) - set(legal_keys):
            raise exceptions.InputException(
                "Please, check your environment definition. Only: "
                "%s are allowed as definition keys." % legal_keys)
コード例 #13
0
def _get_environment(params):
    env = params.get('env', {})

    if isinstance(env, dict):
        return env

    if isinstance(env, six.string_types):
        env_db = db_api.load_environment(env)

        if not env_db:
            raise exc.InputException('Environment is not found: %s' % env)

        return env_db.variables

    raise exc.InputException(
        'Unexpected value type for environment [env=%s, type=%s]' %
        (env, type(env)))
コード例 #14
0
    def start_action(self,
                     action_name,
                     action_input,
                     description=None,
                     namespace='',
                     **params):
        with db_api.transaction():
            action = action_handler.build_action_by_name(action_name,
                                                         namespace=namespace)

            action.validate_input(action_input)

            sync = params.get('run_sync')
            save = params.get('save_result')
            target = params.get('target')
            timeout = params.get('timeout')

            is_action_sync = action.is_sync(action_input)

            if sync and not is_action_sync:
                raise exceptions.InputException(
                    "Action does not support synchronous execution.")

            if not sync and (save or not is_action_sync):
                action.schedule(action_input, target, timeout=timeout)
                return action.action_ex.get_clone()

            output = action.run(action_input,
                                target,
                                save=False,
                                timeout=timeout)
            state = states.SUCCESS if output.is_success() else states.ERROR

            if not save:
                # Action execution is not created but we need to return similar
                # object to the client anyway.
                return db_models.ActionExecution(name=action_name,
                                                 description=description,
                                                 input=action_input,
                                                 output=output.to_dict(),
                                                 state=state,
                                                 workflow_namespace=namespace)
            action_ex_id = u.generate_unicode_uuid()

            values = {
                'id': action_ex_id,
                'name': action_name,
                'description': description,
                'input': action_input,
                'output': output.to_dict(),
                'state': state,
                'is_sync': is_action_sync,
                'workflow_namespace': namespace
            }

            return db_api.create_action_execution(values)
コード例 #15
0
ファイル: types.py プロジェクト: shubhamdang/mistral
    def validate(self, value):
        if not value:
            return {}

        if not isinstance(value, dict):
            raise exc.InputException(
                'JsonType field value must be a dictionary [actual=%s]' %
                value)

        return value
コード例 #16
0
    def is_sync(self, input_dict):
        try:
            prepared_input_dict = self._prepare_input(input_dict)

            a = a_m.get_action_class(
                self.action_def.name)(**prepared_input_dict)

            return a.is_sync()
        except BaseException as e:
            raise exc.InputException(str(e))
コード例 #17
0
    def _get_action_input(self, ctx=None):
        input_dict = self._evaluate_expression(self.task_spec.get_input(), ctx)

        if not isinstance(input_dict, dict):
            raise exc.InputException(
                "Wrong dynamic input for task: %s. Dict type is expected. "
                "Actual type: %s. Actual value: %s" %
                (self.task_spec.get_name(), type(input_dict), str(input_dict)))

        return utils.merge_dicts(input_dict,
                                 self._get_action_defaults(),
                                 overwrite=False)
コード例 #18
0
    def put(self, environment):
        """Update an environment."""
        if not environment.name:
            raise exceptions.InputException(
                'Name of the environment is not provided.')

        LOG.info("Update environment [name=%s, env=%s]" %
                 (environment.name, environment))
        definition = json.loads(wsme_pecan.pecan.request.body)
        definition.pop('name')
        self._validate_environment(definition,
                                   ['description', 'variables', 'scope'])
        db_model = db_api.update_environment(environment.name,
                                             environment.to_dict())

        return Environment(**db_model.to_dict())
コード例 #19
0
    def post(self, action_ex):
        """Create new action_execution."""
        acl.enforce('action_executions:create', context.ctx())
        LOG.info("Create action_execution [action_execution=%s]" % action_ex)

        name = action_ex.name
        description = action_ex.description or None
        action_input = action_ex.input or {}
        params = action_ex.params or {}

        if not name:
            raise exc.InputException(
                "Please provide at least action name to run action.")

        action_ex = rpc.get_engine_client().start_action(
            name, action_input, description=description, **params)

        return ActionExecution.from_dict(action_ex)
コード例 #20
0
ファイル: actions.py プロジェクト: wenhulove333/mistral
def update_actions(definition, scope='private', identifier=None):
    action_list_spec = spec_parser.get_action_list_spec_from_yaml(definition)
    actions = action_list_spec.get_actions()

    if identifier and len(actions) > 1:
        raise exc.InputException("More than one actions are not supported for "
                                 "update with identifier. [identifier: %s]" %
                                 identifier)

    db_actions = []

    for action_spec in action_list_spec.get_actions():
        db_actions.append(
            update_action(action_spec,
                          definition,
                          scope,
                          identifier=identifier))

    return db_actions
コード例 #21
0
ファイル: workflows.py プロジェクト: xavierhardy/mistral
def update_workflows(definition, scope='private', identifier=None):
    wf_list_spec = spec_parser.get_workflow_list_spec_from_yaml(definition)
    wfs = wf_list_spec.get_workflows()

    if identifier and len(wfs) > 1:
        raise exc.InputException(
            "More than one workflows are not supported for update with UUID "
            "provided.")

    db_wfs = []

    with db_api.transaction():
        for wf_spec in wf_list_spec.get_workflows():
            db_wfs.append(
                _update_workflow(wf_spec,
                                 definition,
                                 scope,
                                 identifier=identifier))

    return db_wfs
コード例 #22
0
def validate_input(expected_input, actual_input, obj_name, obj_class):
    actual_input = actual_input or {}

    missing, unexpected = _compare_parameters(expected_input, actual_input)

    if missing or unexpected:
        msg = 'Invalid input [name=%s, class=%s'
        msg_props = [obj_name, obj_class]

        if missing:
            msg += ', missing=%s'
            msg_props.append(missing)

        if unexpected:
            msg += ', unexpected=%s'
            msg_props.append(unexpected)

        msg += ']'

        raise exc.InputException(msg % tuple(msg_props))
コード例 #23
0
ファイル: dynamic_action.py プロジェクト: shubhamdang/mistral
    def post(self, dyn_action):
        """Creates new dynamic action.

        :param dyn_action: Dynamic action to create.
        """
        acl.enforce('dynamic_actions:create', context.ctx())

        LOG.debug('Creating dynamic action [action=%s]', dyn_action)

        if not dyn_action.code_source_id and not dyn_action.code_source_name:
            raise exc.InputException(
                "Either 'code_source_id' or 'code_source_name'"
                " must be provided.")

        code_source = db_api.get_code_source(dyn_action.code_source_id
                                             or dyn_action.code_source_name,
                                             namespace=dyn_action.namespace)

        # TODO(rakhmerov): Ideally we also need to check if the specified
        # class exists in the specified code source. But probably it's not
        # a controller responsibility.

        db_model = rest_utils.rest_retry_on_db_error(
            db_api.create_dynamic_action_definition)({
                'name':
                dyn_action.name,
                'namespace':
                dyn_action.namespace,
                'class_name':
                dyn_action.class_name,
                'code_source_id':
                code_source.id,
                'code_source_name':
                code_source.name
            })

        return resources.DynamicAction.from_db_model(db_model)
コード例 #24
0
ファイル: dynamic_action.py プロジェクト: shubhamdang/mistral
    def put(self, dyn_action):
        """Update dynamic action.

        :param dyn_action: Dynamic action to create.
        """
        acl.enforce('dynamic_actions:update', context.ctx())

        LOG.debug('Updating dynamic action [action=%s]', dyn_action)

        if not dyn_action.id and not dyn_action.name:
            raise exc.InputException("Either 'name' or 'id' must be provided.")

        values = {'class_name': dyn_action.class_name}

        if dyn_action.scope:
            values['scope'] = dyn_action.scope

        # A client may also want to update a source code.
        if dyn_action.code_source_id or dyn_action.code_source_name:
            code_source = db_api.get_code_source(
                dyn_action.code_source_id or dyn_action.code_source_name,
                namespace=dyn_action.namespace)

            values['code_source_id'] = code_source.id
            values['code_source_name'] = code_source.name

        # TODO(rakhmerov): Ideally we also need to check if the specified
        # class exists in the specified code source. But probably it's not
        # a controller responsibility.

        db_model = rest_utils.rest_retry_on_db_error(
            db_api.update_dynamic_action_definition)(
                dyn_action.id or dyn_action.name,
                values,
                namespace=dyn_action.namespace)

        return resources.DynamicAction.from_db_model(db_model)
コード例 #25
0
    def validate(value):
        if not uuidutils.is_uuid_like(value):
            raise exc.InputException("Expected a uuid but received %s." %
                                     value)

        return value
コード例 #26
0
ファイル: execution.py プロジェクト: wookiist/mistral
    def put(self, id, wf_ex):
        """Update the specified workflow execution.

        :param id: UUID of execution to update.
        :param wf_ex: Execution object.
        """
        acl.enforce('executions:update', context.ctx())

        LOG.debug('Update execution [id=%s, execution=%s]', id, wf_ex)

        @rest_utils.rest_retry_on_db_error
        def _compute_delta(wf_ex):
            with db_api.transaction():
                # ensure that workflow execution exists
                db_api.get_workflow_execution(id)

                delta = {}

                if wf_ex.state:
                    delta['state'] = wf_ex.state

                if wf_ex.description:
                    delta['description'] = wf_ex.description

                if wf_ex.params and wf_ex.params.get('env'):
                    delta['env'] = wf_ex.params.get('env')

                # Currently we can change only state, description, or env.
                if len(delta.values()) <= 0:
                    raise exc.InputException(
                        'The property state, description, or env '
                        'is not provided for update.')

                # Description cannot be updated together with state.
                if delta.get('description') and delta.get('state'):
                    raise exc.InputException(
                        'The property description must be updated '
                        'separately from state.')

                # If state change, environment cannot be updated
                # if not RUNNING.
                if (delta.get('env') and delta.get('state')
                        and delta['state'] != states.RUNNING):
                    raise exc.InputException(
                        'The property env can only be updated when workflow '
                        'execution is not running or on resume from pause.')

                if delta.get('description'):
                    wf_ex = db_api.update_workflow_execution(
                        id, {'description': delta['description']})

                if not delta.get('state') and delta.get('env'):
                    wf_ex = db_api.get_workflow_execution(id)
                    wf_ex = wf_service.update_workflow_execution_env(
                        wf_ex, delta.get('env'))

                return delta, wf_ex

        delta, wf_ex = _compute_delta(wf_ex)

        if delta.get('state'):
            if states.is_paused(delta.get('state')):
                wf_ex = rpc.get_engine_client().pause_workflow(id)
            elif delta.get('state') == states.RUNNING:
                wf_ex = rpc.get_engine_client().resume_workflow(
                    id, env=delta.get('env'))
            elif states.is_completed(delta.get('state')):
                msg = wf_ex.state_info if wf_ex.state_info else None
                wf_ex = rpc.get_engine_client().stop_workflow(
                    id, delta.get('state'), msg)
            else:
                # To prevent changing state in other cases throw a message.
                raise exc.InputException(
                    "Cannot change state to %s. Allowed states are: '%s" %
                    (wf_ex.state, ', '.join([
                        states.RUNNING, states.PAUSED, states.SUCCESS,
                        states.ERROR, states.CANCELLED
                    ])))

        return resources.Execution.from_dict(
            wf_ex if isinstance(wf_ex, dict) else wf_ex.to_dict())
コード例 #27
0
ファイル: types.py プロジェクト: shubhamdang/mistral
    def validate(value):
        _, data = filter_utils.extract_filter_type_and_value(value)
        if not uuidutils.is_uuid_like(data):
            raise exc.InputException("Expected a uuid but received %s." % data)

        return data