예제 #1
0
    def test_register_node__is_not_end_event(self):
        node_cls = MagicMock()

        FlowNodeClsFactory.register_node('key', node_cls)

        self.assertEqual(FlowNodeClsFactory.get_node_cls('key'), node_cls)
        flow.post_new_end_event_register.send.assert_not_called()

        FlowNodeClsFactory.nodes_cls.pop('key')
예제 #2
0
    def test_register_node__with_end_event(self):
        class TestEnd(EndEvent):
            pass

        FlowNodeClsFactory.register_node('key', TestEnd)
        self.assertEqual(FlowNodeClsFactory.get_node_cls('key'), TestEnd)
        flow.post_new_end_event_register.send.assert_called_once_with(
            sender=EndEvent, node_type='key', node_cls=TestEnd)

        FlowNodeClsFactory.nodes_cls.pop('key')
예제 #3
0
 def test_node_types_without_start_and_end_event(self):
     self.assertEqual(
         set(FlowNodeClsFactory.node_types_without_start_end_event()), {
             "ServiceActivity", "SubProcess", "ExclusiveGateway",
             "ParallelGateway", "ConditionalParallelGateway",
             "ConvergeGateway"
         })
예제 #4
0
    def _parse(self,
               root_pipeline_data=None,
               root_pipeline_params=None,
               params=None,
               is_subprocess=False,
               parent_context=None):
        """
        @summary: parse pipeline and subprocess recursively
        @param root_pipeline_data: root data from root pipeline parsing, witch will be passed to subprocess recursively
        @param root_pipeline_params: params from root pipeline for all subprocess
        @param params: params from parent for son subprocess
        @param is_subprocess: whither is subprocess
        @param parent_context: parent context for activity of subprocess to resolving inputs
        @return: Pipeline object
        """
        if root_pipeline_data is None:
            root_pipeline_data = {}
        if root_pipeline_params is None:
            root_pipeline_params = {}
        if params is None:
            params = {}

        pipeline_inputs = self.pipeline_tree[PE.data][PE.inputs]
        classification = classify_inputs(pipeline_inputs, params,
                                         is_subprocess, root_pipeline_params)

        output_keys = self.pipeline_tree[PE.data][PE.outputs]
        context = Context(classification['act_outputs'], output_keys)
        for key, info in classification['scope_info'].items():
            var = get_variable(key, info, context, root_pipeline_data)
            context.set_global_var(key, var)

        pipeline_data = deepcopy(root_pipeline_data)
        if is_subprocess:
            if parent_context is None:
                raise exceptions.DataTypeErrorException(
                    'parent context of subprocess cannot be none')
            for key, info in classification['subprocess_params'].items():
                var = get_variable(key, info, parent_context, pipeline_data)
                pipeline_data.update({key: var})

        start = self.pipeline_tree[PE.start_event]
        start_cls = FlowNodeClsFactory.get_node_cls(start[PE.type])
        start_event = start_cls(id=start[PE.id], name=start[PE.name])

        end = self.pipeline_tree[PE.end_event]
        end_cls = FlowNodeClsFactory.get_node_cls(end[PE.type])
        end_event = end_cls(id=end[PE.id],
                            name=end[PE.name],
                            data=DataObject({}))

        acts = self.pipeline_tree[PE.activities]
        act_objs = []
        for act in acts.values():
            act_cls = FlowNodeClsFactory.get_node_cls(act[PE.type])
            if act[PE.type] == PE.ServiceActivity:
                component = ComponentLibrary.get_component(
                    act[PE.component][PE.code], act[PE.component][PE.inputs])
                service = component.service()
                data = component.data_for_execution(context, pipeline_data)
                handler_path = act.get('failure_handler')
                failure_handler = import_string(
                    handler_path) if handler_path else None
                act_objs.append(
                    act_cls(id=act[PE.id],
                            service=service,
                            name=act[PE.name],
                            data=data,
                            error_ignorable=act.get(PE.error_ignorable, False),
                            skippable=act.get(PE.skippable)
                            or act.get(PE.skippable_old, True),
                            retryable=act.get(PE.retryable)
                            or act.get(PE.retryable_old, True),
                            timeout=act.get(PE.timeout),
                            failure_handler=failure_handler))
            elif act[PE.type] == PE.SubProcess:
                sub_tree = act[PE.pipeline]
                params = act[PE.params]
                sub_parser = PipelineParser(pipeline_tree=sub_tree)
                act_objs.append(
                    act_cls(id=act[PE.id],
                            pipeline=sub_parser._parse(
                                root_pipeline_data=root_pipeline_data,
                                root_pipeline_params=root_pipeline_params,
                                params=params,
                                is_subprocess=True,
                                parent_context=context),
                            name=act[PE.name]))
            else:
                raise exceptions.FlowTypeError(u"Unknown Activity type: %s" %
                                               act[PE.type])

        gateways = self.pipeline_tree[PE.gateways]
        flows = self.pipeline_tree[PE.flows]
        gateway_objs = []
        for gw in gateways.values():
            gw_cls = FlowNodeClsFactory.get_node_cls(gw[PE.type])
            if gw[PE.type] in {
                    PE.ParallelGateway, PE.ConditionalParallelGateway
            }:
                gateway_objs.append(
                    gw_cls(id=gw[PE.id],
                           converge_gateway_id=gw[PE.converge_gateway_id],
                           name=gw[PE.name]))
            elif gw[PE.type] in {PE.ExclusiveGateway, PE.ConvergeGateway}:
                gateway_objs.append(gw_cls(id=gw[PE.id], name=gw[PE.name]))
            else:
                raise exceptions.FlowTypeError(u"Unknown Gateway type: %s" %
                                               gw[PE.type])

        flow_objs_dict = {}
        for fl in flows.values():
            flow_nodes = act_objs + gateway_objs
            if fl[PE.source] == start[PE.id]:
                source = start_event
            else:
                source = filter(lambda x: x.id == fl[PE.source], flow_nodes)[0]
            if fl[PE.target] == end[PE.id]:
                target = end_event
            else:
                target = filter(lambda x: x.id == fl[PE.target], flow_nodes)[0]
            flow_objs_dict[fl[PE.id]] = SequenceFlow(fl[PE.id], source, target)
        flow_objs = flow_objs_dict.values()

        # add incoming and outgoing flow to acts
        if not isinstance(start[PE.outgoing], list):
            start[PE.outgoing] = [start[PE.outgoing]]
        for outgoing_id in start[PE.outgoing]:
            start_event.outgoing.add_flow(flow_objs_dict[outgoing_id])

        if not isinstance(end[PE.incoming], list):
            end[PE.incoming] = [end[PE.incoming]]
        for incoming_id in end[PE.incoming]:
            end_event.incoming.add_flow(flow_objs_dict[incoming_id])

        for act in act_objs:
            incoming = acts[act.id][PE.incoming]
            if isinstance(incoming, list):
                for s in incoming:
                    act.incoming.add_flow(flow_objs_dict[s])
            else:
                act.incoming.add_flow(flow_objs_dict[incoming])

            act.outgoing.add_flow(flow_objs_dict[acts[act.id][PE.outgoing]])

        for gw in gateway_objs:
            if isinstance(gw, ExclusiveGateway) or isinstance(
                    gw, ConditionalParallelGateway):
                for flow_id, con in gateways[gw.id][PE.conditions].items():
                    con_obj = Condition(con[PE.evaluate],
                                        flow_objs_dict[flow_id])
                    gw.add_condition(con_obj)

                if isinstance(gateways[gw.id][PE.incoming], list):
                    for incoming_id in gateways[gw.id][PE.incoming]:
                        gw.incoming.add_flow(flow_objs_dict[incoming_id])
                else:
                    gw.incoming.add_flow(
                        flow_objs_dict[gateways[gw.id][PE.incoming]])

                for outgoing_id in gateways[gw.id][PE.outgoing]:
                    gw.outgoing.add_flow(flow_objs_dict[outgoing_id])

            elif isinstance(gw, ParallelGateway):
                if isinstance(gateways[gw.id][PE.incoming], list):
                    for incoming_id in gateways[gw.id][PE.incoming]:
                        gw.incoming.add_flow(flow_objs_dict[incoming_id])
                else:
                    gw.incoming.add_flow(
                        flow_objs_dict[gateways[gw.id][PE.incoming]])

                for outgoing_id in gateways[gw.id][PE.outgoing]:
                    gw.outgoing.add_flow(flow_objs_dict[outgoing_id])

            elif isinstance(gw, ConvergeGateway):
                for incoming_id in gateways[gw.id][PE.incoming]:
                    gw.incoming.add_flow(flow_objs_dict[incoming_id])
                gw.outgoing.add_flow(
                    flow_objs_dict[gateways[gw.id][PE.outgoing]])

            else:
                raise exceptions.FlowTypeError(u"Unknown Gateway type: %s" %
                                               type(gw))

        context.duplicate_variables()
        pipeline_data = DataObject(pipeline_data)
        pipeline_spec = PipelineSpec(start_event, end_event, flow_objs,
                                     act_objs, gateway_objs, pipeline_data,
                                     context)
        return Pipeline(self.pipeline_tree[PE.id], pipeline_spec)
예제 #5
0
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""

from pipeline.core.flow import FlowNodeClsFactory

MAX_IN = 1000
MAX_OUT = 1000
FLOW_NODES_WITHOUT_STARTEVENT = FlowNodeClsFactory.node_types_without_start_event()

FLOW_NODES_WITHOUT_START_AND_END = FlowNodeClsFactory.node_types_without_start_end_event()

SOURCE_RULE = {
    "min_in": 0,
    "max_in": 0,
    "min_out": 1,
    "max_out": 1,
    "allowed_out": FLOW_NODES_WITHOUT_START_AND_END
}

SINK_RULE = {
    "min_in": 1,
    "max_in": MAX_IN,
    "min_out": 0,