diff --git a/cloudslang_dsl_reference.rst b/cloudslang_dsl_reference.rst index 41a7c8d..0e855d4 100644 --- a/cloudslang_dsl_reference.rst +++ b/cloudslang_dsl_reference.rst @@ -76,6 +76,7 @@ and concepts are explained in detail below. - `required <#required>`__ - `default <#default>`__ - `private <#private>`__ + - `sensitive <#sensitive>`__ - `workflow <#workflow>`__ @@ -96,20 +97,23 @@ and concepts are explained in detail below. - `navigate <#navigate>`__ - - `asynchronous step <#asynchronous-step>`__ + - `parallel step <#parallel-step>`__ - - `async_loop <#async-loop>`__ + - `parallel_loop <#parallel-loop>`__ - `for <#for>`__ - `do <#do>`__ - - `publish <#publish>`__ - - `aggregate <#aggregate>`__ + - `publish <#publish>`__ - `navigate <#navigate>`__ - `on_failure <#on-failure>`__ - `outputs <#outputs>`__ + + - `value <#value>`__ + - `sensitive <#sensitive>`__ + - `results <#results>`__ - `extensions <#extensions>`__ @@ -125,6 +129,7 @@ and concepts are explained in detail below. - `required <#required>`__ - `default <#default>`__ - `private <#private>`__ + - `sensitive <#sensitive>`__ - `python_action <#python-action>`__ @@ -138,6 +143,10 @@ and concepts are explained in detail below. - `method_name <#method-name>`__ - `outputs <#outputs>`__ + + - `value <#value>`__ + - `sensitive <#value>`__ + - `results <#results>`__ - `extensions <#extensions>`__ @@ -259,13 +268,12 @@ different variable contexts that are accessible. Which contexts are accessible depends on the current section of the flow or operation. The table below summarizes the accessible contexts at any given location in a -flow or operation. At locations where more than one context is accessible, the -context labeled as **P0** overrides the context labeled as **P1**. +flow or operation. +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | Contexts/ | | Context | | Flow | | Operation | | Action | | Subflow/ | | Step | | Branched | | Already | | | Location | | Passed To | | Context | | Context | | Outputs | | Operation | | Arguments | | Step | | Bound | -| | | Executable | | | | Context | | Outputs | | | Published | | Values | +| | | Executable | | | | Context | | Outputs | | | Output | | Values | | | | | | | | Context | | | Values | | +==================+==============+===========+=============+===========+=============+=============+====================+================+ | | **flow** | Yes | | | | | | | Yes | @@ -278,22 +286,19 @@ context labeled as **P0** overrides the context labeled as **P1**. | | **inputs** | | | | | | | | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | **operation** | | | Yes | Yes | | | | Yes | -| | **outputs** | | | (P1) | (P0) | | | | | +| | **outputs** | | | | | | | | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | **operation** | | | Yes | Yes | | | | | -| | **results** | | | (P1) | (P0) | | | | | +| | **results** | | | | | | | | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | **step** | | Yes | | | | | | Yes | | | **arguments** | | | | | | | | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ -| | **step** | | | | | Yes | Yes | | Yes | -| | **publish** | | | | | (P0) | (P1) | | | +| | **step** | | | | | Yes | Yes | | Yes - using | Yes | +| | **publish** | | | | | | | | branches_context | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | **step** | | | | | Yes | Yes | | | -| | **navigation** | | | | | (P0) | (P1) | | | -+------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ -| | **step** | | | | | | | | Yes* - using | | -| | **aggregate** | | | | | | | | branches_context | | +| | **navigation** | | | | | | | | | +------------------+--------------+-----------+-------------+-----------+-------------+-------------+--------------------+----------------+ | | **action** | | | Yes | | | | | | | | **inputs** | | | | | | | | | @@ -302,122 +307,59 @@ context labeled as **P0** overrides the context labeled as **P1**. Keywords (A-Z) ============== -.. _aggregate: - -aggregate ---------- - -The key ``aggregate`` is a property of an `asynchronous -step <#asynchronous-step>`__ name. It is mapped to key:value pairs where -the key is the variable name to publish to the `flow's <#flow>`__ scope -and the value is the aggregation `expression <#expressions>`__. - -Defines the aggregation logic for an `asynchronous -step <#asynchronous-step>`__, generally making us of the -`branches_context <#branches-context>`__ construct. - -After all branches of an `asynchronous step <#asynchronous-step>`__ have -completed, execution of the flow continues with the ``aggregate`` section. The -expression of each name:value pair is evaluated and published to the -`flow's <#flow>`__ scope. The expression generally makes use of the -`branches_context <#branches-context>`__ construct to access the values -published by each of the `asynchronous loop's <#async_loop>`__ branches. - -For a list of which contexts are available in the ``aggregate`` section of a -`step <#step>`__, see `Contexts <#contexts>`__. - -For more information, see the :ref:`Asynchronous Loop ` -example. - -**Example - aggregates all of the published names into name\_list** - -.. code-block:: yaml - - aggregate: - - name_list: ${map(lambda x:str(x['name']), branches_context)} - -.. _async_loop: - -async_loop ------------ - -The key ``asyc_loop`` is a property of an `asynchronous -step's <#asynchronous-step>`__ name. It is mapped to the `asynchronous -step's <#asynchronous-step>`__ properties. - -For each value in the loop's list a branch is created and the ``do`` -will run an `operation <#operation>`__ or `subflow <#flow>`__. When all -the branches have finished, the `asynchronous -step's <#asynchronous-step>`__ `aggregation <#aggregate>`__ and -`navigation <#navigate>`__ will run. - -+-------------+----------+---------+-------------------+---------------------------------+------------------------------+ -| Property | Required | Default | Value Type | Description | More Info | -+=============+==========+=========+===================+=================================+==============================+ -| ``for`` | yes | -- | | variable ``in`` | loop values | `for <#for>`__ | -| | | | | list | | | -+-------------+----------+---------+-------------------+---------------------------------+------------------------------+ -| ``do`` | yes | -- | | operation or | | operation or subflow | | `do <#do>`__ | -| | | | | subflow call | | this step will | | `operation <#operation>`__ | -| | | | | | run in parallel | | `flow <#flow>`__ | -+-------------+----------+---------+-------------------+---------------------------------+------------------------------+ -| ``publish`` | no | -- | | list of | | operation or subflow | | `publish <#publish>`__ | -| | | | | key:value | | outputs to aggregate | | `aggregate <#aggregate>`__ | -| | | | | pairs | | and publish to the flow level | | `outputs <#outputs>`__ | -+-------------+----------+---------+-------------------+---------------------------------+------------------------------+ - -**Example: loop that breaks on a result of custom** - -.. code-block:: yaml - - - print_values: - async_loop: - for: value in values - do: - print_branch: - - ID: ${value} - publish: - - name - aggregate: - - name_list: ${map(lambda x:str(x['name']), branches_context)} - navigate: - - SUCCESS: print_list - - FAILURE: FAILURE - .. _branches_context: branches_context ------------------ +---------------- -May appear in the `aggregate <#aggregate>`__ section of an `asynchronous -step <#asynchronous-step>`__. +May appear in the `publish <#publish>`__ section of a `parallel +step <#parallel-step>`__. -As branches of an `async_loop <#async-loop>`__ complete, their -published values get placed as a dictionary into the +As branches of a `parallel_loop <#parallel-loop>`__ complete, values that have +been output and the branch's result get placed as a dictionary into the ``branches_context`` list. The list is therefore in the order the branches have completed. A specific value can be accessed using the index representing its -branch's place in the finishing order and the name of the variable. +branch's place in the finishing order and the name of the variable or the +`branch_result <#branch-result>`__ key. -**Example - retrieves the published name variable from the first branch -to finish** +**Example - retrieves the name variable from the first branch to finish** .. code-block:: yaml - aggregate: + publish: - first_name: ${branches_context[0]['name']} More commonly, the ``branches_context`` is used to aggregate the values that have been published by all of the branches. -**Example - aggregates all of the published name values into a list** +**Example - aggregates name values into a list** .. code-block:: yaml - aggregate: + publish: - name_list: ${map(lambda x:str(x['name']), branches_context)} +.. _branch_result: + +branch_result +------------- + +May appear in the `publish <#publish>`__ section of a `parallel +step <#parallel-step>`__. + +As branches of a `parallel_loop <#parallel-loop>`__ complete, branch results get +placed into the `branches_context <#branches-context>`__ list under the +``branch_result`` key. + +**Example - aggregates branch results** + +.. code-block:: yaml + + publish: + - branch_results_list: ${map(lambda x:str(x['branch_result']), branches_context)} + .. _break: break @@ -497,7 +439,7 @@ The expression's value will be passed to the `flow <#flow>`__ or - from_system_property: default: $ { get_sp('system.property.key') } -A default value can also be defined inline by entering it as the value +A default value can also be defined inline by entering it as the value mapped to the `input <#inputs>`__ parameter's key. **Example - inline default values** @@ -516,7 +458,7 @@ do -- The key ``do`` is a property of a `step <#step>`__ name, a -`loop <#loop>`__, or an `async_loop <#async-loop>`__. It is mapped to a +`loop <#loop>`__, or a `parallel_loop <#parallel-loop>`__. It is mapped to a property that references an `operation <#operation>`__ or `flow <#flow>`__. @@ -548,7 +490,9 @@ example. Arguments are passed to a `step <#step>`__ using a list of argument names and optional mapped `expressions <#expressions>`__. The step must pass values for all `inputs <#inputs>`__ found in the called `operation <#operation>`__ or -`subflow <#flow>`__ that are required and don't have a default value. +`subflow <#flow>`__ that are required and don't have a default value. Argument +names should be different than the `output <#outputs>`__ names found in the +`operation <#operation>`__ or `subflow <#flow>`__ being called in the step. An argument name without an expression, or with a ``null`` value will take its value from a variable with the same name in the flow context. @@ -600,7 +544,7 @@ For a list of which contexts are available in the arguments section of a script: | print text + punctuation -.. _extensions: +.. _extensions_tag: extensions ---------- @@ -698,7 +642,7 @@ for --- The key ``for`` is a property of a `loop <#loop>`__ or an -`async_loop <#async-loop>`__. +`parallel_loop <#parallel-loop>`__. loop: for ~~~~~~~~~ @@ -771,24 +715,23 @@ expression** - text1: ${k} - text2: ${v} -async_loop: for -~~~~~~~~~~~~~~~~ +parallel_loop: for +~~~~~~~~~~~~~~~~~~ -An asynchronous for loops in parallel branches over the items in a list. +A parallel for loop loops in parallel branches over the items in a list. -The `asynchronous step <#asynchronous-step>`__ will run one branch for +The `parallel step <#parallel-step>`__ will run one branch for each element in the list. The ``for`` key is mapped to an iteration variable followed by ``in`` followed by a list or an expression that evaluates to a list. -**Example - step that asynchronously loops through the values in a -list** +**Example - step that loops in parallel through the values in a list** .. code-block:: yaml - print_values: - async_loop: + parallel_loop: for: value in values_list do: print_branch: @@ -868,22 +811,31 @@ input name may in turn be mapped to its properties or an input `expression <#expressions>`__. Inputs are used to pass parameters to `flows <#flow>`__ or -`operations <#operation>`__. +`operations <#operation>`__. Input names for a specific `flow <#flow>`__ or +`operation <#operation>`__ must be different than the `output <#outputs>`__ +names of the same `flow <#flow>`__ or `operation <#operation>`__. For a list of which contexts are available in the ``inputs`` section of a `flow <#flow>`__ or `operation <#operation>`__, see `Contexts <#contexts>`__. -+--------------+----------+---------+-------------+-----------------------------+--------------------------+ -| Property | Required | Default | Value Type | Description | More info | -+==============+==========+=========+=============+=============================+==========================+ -| ``required`` | no | true | boolean | is the input required | `required <#required>`__ | -+--------------+----------+---------+-------------+-----------------------------+--------------------------+ -| ``default`` | no | -- | expression | default value of the input | `default <#default>`__ | -+--------------+----------+---------+-------------+-----------------------------+--------------------------+ -| ``private`` | no | false | boolean | | if true, the default | `private <#private>`__ | -| | | | | | value always overrides | | -| | | | | | values passed in | | -+--------------+----------+---------+-------------+-----------------------------+--------------------------+ ++---------------+----------+---------------+------------+--------------------+----------------------------+ +| Property | Required | Default | Value Type | Description | More info | ++===============+==========+===============+============+====================+============================+ +| ``required`` | no | true | boolean | | is the input | `required <#required>`__ | +| | | | | | required | | ++---------------+----------+---------------+------------+--------------------+----------------------------+ +| ``default`` | no | -- | expression | | default value | `default <#default>`__ | +| | | | | | of the input | | ++---------------+----------+---------------+------------+--------------------+----------------------------+ +| ``private`` | no | false | boolean | | if true, the | `private <#private>`__ | +| | | | | | default value | | +| | | | | | always overrides | | +| | | | | | values passed in | | ++---------------+----------+---------------+------------+--------------------+----------------------------+ +| ``sensitive`` | no | | transitive | boolean | | is the input | `sensitive <#sensitive>`__ | +| | | | sensitivity | | | sensitive | | +| | | | or false | | | | ++---------------+----------+---------------+------------+--------------------+----------------------------+ **Example - several inputs** @@ -896,6 +848,8 @@ For a list of which contexts are available in the ``inputs`` section of a - input2 - input3: "default value" - input4: ${'var1 is ' + var1} + - password: + sensitive: true .. _java_action: @@ -1204,8 +1158,8 @@ mapped to a list of key:value pairs where the key is the received `flow <#flow>`__ `result <#results>`__ or ``on_failure``. Defines the navigation logic for a `standard step <#standard-step>`__, -an `iterative step <#iterative-step>`__ or an `asynchronous -step <#asynchronous-step>`__. The flow will continue with the +an `iterative step <#iterative-step>`__ or a `parallel +step <#parallel-step>`__. The flow will continue with the `step <#step>`__ or `flow <#flow>`__ `result <#results>`__ whose value is mapped to the `result <#results>`__ returned by the called `operation <#operation>`__ or `subflow <#flow>`__. @@ -1227,7 +1181,7 @@ For an `iterative step <#iterative-step>`__ the navigation logic runs when the last iteration of the `step <#step>`__ is completed or after exiting the iteration due to a `break <#break>`__. -For an `asynchronous step <#asynchronous-step>`__ the navigation logic +For a `parallel step <#parallel-step>`__ the navigation logic runs after the last branch has completed. If any of the branches returned a `result <#results>`__ of ``FAILURE``, the `flow <#flow>`__ will navigate to the `step <#step>`__ or `flow <#flow>`__ @@ -1235,7 +1189,7 @@ will navigate to the `step <#step>`__ or `flow <#flow>`__ `flow <#flow>`__ will navigate to the `step <#step>`__ or `flow <#flow>`__ `result <#results>`__ mapped to ``SUCCESS``. Note that the only `results <#results>`__ of an `operation <#operation>`__ or -`subflow <#flow>`__ called in an `async_loop <#async-loop>`__ that are +`subflow <#flow>`__ called in a `parallel_loop <#parallel-loop>`__ that are evaluated are ``SUCCESS`` and ``FAILURE``. Any other results will be evaluated as ``SUCCESS``. @@ -1329,16 +1283,32 @@ outputs The key ``outputs`` is a property of a `flow <#flow>`__ or `operation <#operation>`__. It is mapped to a list of output variable -names which may also contain `expression <#expressions>`__ values. -Output `expressions <#expressions>`__ must evaluate to strings. +names. Each output name may in turn be mapped to its properties or an output +`expression <#expressions>`__. Output `expressions <#expressions>`__ must +evaluate to strings. Defines the parameters a `flow <#flow>`__ or `operation <#operation>`__ exposes to possible `publication <#publish>`__ by a `step <#step>`__. The calling `step <#step>`__ refers to an output by its name. +Output names for a specific `flow <#flow>`__ or `operation <#operation>`__ must +be different than the `input <#inputs>`__ names of the same `flow <#flow>`__ or +`operation <#operation>`__. + For a list of which contexts are available in the ``outputs`` section of a `flow <#flow>`__ or `operation <#operation>`__, see `Contexts <#contexts>`__. ++---------------+----------+---------------+------------+-----------------+----------------------------+ +| Property | Required | Default | Value Type | Description | More info | ++===============+==========+===============+============+=================+============================+ +| ``value`` | no | -- | expression | | value of | `value <#value>`__ | +| | | | | | the output | | ++---------------+----------+---------------+------------+-----------------+----------------------------+ +| ``sensitive`` | no | | transitive | boolean | | is the output | `sensitive <#sensitive>`__ | +| | | | sensitivity | | | sensitive | | +| | | | or false | | | | ++---------------+----------+---------------+------------+-----------------+----------------------------+ + **Example - various types of outputs** .. code-block:: yaml @@ -1347,6 +1317,51 @@ For a list of which contexts are available in the ``outputs`` section of a - existing_variable - output2: ${some_variable} - output3: ${5 + 6} + - password: + value: ${password} + sensitive: true + +.. _parallel_loop_tag: + +parallel_loop +------------- + +The key ``parallel_loop`` is a property of a `parallel +step's <#parallel-step>`__ name. It is mapped to the `parallel +step's <#parallel-step>`__ properties. + +For each value in the loop's list a branch is created and the ``do`` +will run an `operation <#operation>`__ or `subflow <#flow>`__. When all +the branches have finished, the `parallel +step's <#parallel-step>`__ `publish <#publish>`__ and +`navigation <#navigate>`__ will run. + ++-------------+----------+---------+-------------------+---------------------------------+------------------------------+ +| Property | Required | Default | Value Type | Description | More Info | ++=============+==========+=========+===================+=================================+==============================+ +| ``for`` | yes | -- | | variable ``in`` | loop values | `for <#for>`__ | +| | | | | list | | | ++-------------+----------+---------+-------------------+---------------------------------+------------------------------+ +| ``do`` | yes | -- | | operation or | | operation or subflow | | `do <#do>`__ | +| | | | | subflow call | | this step will | | `operation <#operation>`__ | +| | | | | | run in parallel | | | ++-------------+----------+---------+-------------------+---------------------------------+------------------------------+ + +**Example: loop that breaks on a result of custom** + +.. code-block:: yaml + + - print_values: + parallel_loop: + for: value in values + do: + print_branch: + - ID: ${value} + publish: + - name_list: ${map(lambda x:str(x['name']), branches_context)} + navigate: + - SUCCESS: print_list + - FAILURE: FAILURE .. _private: @@ -1417,7 +1432,7 @@ publish ------- The key ``publish`` is a property of a `step <#step>`__ name, a -`loop <#loop>`__ or an `async_loop <#async-loop>`__. It is mapped to a +`loop <#loop>`__ or a `parallel_loop <#parallel-loop>`__. It is mapped to a list of key:value pairs where the key is the published variable name and the value is an `expression <#expressions>`__, usually involving an `output <#outputs>`__ received from an `operation <#operation>`__ or `flow <#flow>`__. @@ -1468,31 +1483,66 @@ during each iteration after the `operation <#operation>`__ or publish: - sum: ${sum + squared} -Asynchronous publish -~~~~~~~~~~~~~~~~~~~~ +Parallel publish +~~~~~~~~~~~~~~~~ -In an `asynchronous step <#asynchronous-step>`__ the publish mechanism -is run during each branch after the `operation <#operation>`__ or -`subflow <#flow>`__ has completed. Published variables and their values -are added as a dictionary to the -`branches_context <#branches-context>`__ list in the order they are -received from finished branches, allowing for aggregation. +In a `parallel step <#parallel-step>`__ the publish mechanism defines the +step's aggregation logic, generally making use of the +`branches_context <#branches-context>`__ construct. -**Example - publishing in an iterative step to aggregate output** +After all branches of a `parallel step <#parallel-step>`__ have +completed, execution of the flow continues with the ``publish`` section. The +expression of each name:value pair is evaluated and published to the +`flow's <#flow>`__ scope. The expression generally makes use of the +`branches_context <#branches-context>`__ construct to access the values +published by each of the `parallel loop's <#parallel_loop>`__ branches and their +results using the `branch_result <#branch-result>`__ key. + +For a list of which contexts are available in the ``publish`` section of a +`step <#step>`__, see `Contexts <#contexts>`__. + +For more information, see the :ref:`Parallel Loop ` +example. + +**Example - publishing in an parallel step to aggregate output** .. code-block:: yaml - print_values: - async_loop: + parallel_loop: for: value in values_list do: print_branch: - ID: ${value} - publish: - - name - aggregate: + publish: - name_list: ${map(lambda x:str(x['name']), branches_context)} +**Example - extracting information from a specific branch** + +.. code-block:: yaml + + - print_values: + parallel_loop: + for: value in values_list + do: + print_branch: + - ID: ${value} + publish: + - first_name: ${branches_context[0]['name']} + +**Example - create a list of branch results** + +.. code-block:: yaml + + - print_values: + parallel_loop: + for: value in values + do: + print_branch: + - ID: ${ value } + publish: + - branch_results_list: ${map(lambda x:str(x['branch_result']), branches_context)} + .. _python_action: python_action @@ -1527,7 +1577,7 @@ purposes. .. note:: The only results of an `operation <#operation>`__ or - `subflow <#flow>`__ called in an `async_loop <#async-loop>`__ that are + `subflow <#flow>`__ called in a `parallel_loop <#parallel-loop>`__ that are evaluated are ``SUCCESS`` and ``FAILURE``. Any other results will be evaluated as ``SUCCESS``. @@ -1767,6 +1817,43 @@ To import a Python script in a ``python_action``: If you have defined a ``JYTHONPATH`` environment variable, you will need to add the **python-lib** folder's path to its value. +.. _sensitive: + +sensitive +--------- + +The key ``sensitive`` is a property of an `input <#inputs>`__ or +`output <#outputs>`__ name. It is mapped to a boolean value. + +The values of variables marked as ``sensitive`` will not be printed in logs, +events or in outputs of the :doc:`CLI ` and +:doc:`Build Tool `. + +The sensitivity of an `input <#inputs>`__ or `output <#outputs>`__ is +transitive, and is therefore determined by its ``sensitive`` property and by the +sensitivity of variables used in its related value expression. + +**Example - two sensitive inputs** + +.. code-block:: yaml + + inputs: + - input1: + default: "default value" + sensitive: true + - input1plus: + default: ${ get("input1") + "something else" } + +**Example - two sensitive outputs** + +.. code-block:: yaml + + outputs: + - output1: + value: ${output1} + sensitive: true + - output2: ${already_sensitive_value} + .. _step: step @@ -1782,7 +1869,7 @@ There are several types of steps: - `standard <#standard-step>`__ - `iterative <#iterative-step>`__ -- `asynchronous <#asynchronous-step>`__ +- `parallel <#parallel-step>`__ **Example - step with two inputs, one of which contains a default value** @@ -1870,51 +1957,72 @@ to a step named "another_step"** - SUCCESS: another_step - FAILURE: FAILURE -Asynchronous Step -~~~~~~~~~~~~~~~~~ +Parallel Step +~~~~~~~~~~~~~ -An asynchronous step calls an `operation <#operation>`__ or -`subflow <#flow>`__ asynchronously, in parallel branches, for each value +A parallel step calls an `operation <#operation>`__ or +`subflow <#flow>`__ in parallel branches, for each value in a list. -The step name is mapped to the asynchronous step's properties. - -+----------------+----------+---------------------------+--------------+-----------------------+----------------------------+ -| Property | Required | Default | Value Type | Description | More Info | -+================+==========+===========================+==============+=======================+============================+ -| ``async_loop`` | yes | -- | key | | container for | `async_loop <#async-loop>`_| -| | | | | | async loop | | -| | | | | | properties | | -+----------------+----------+---------------------------+--------------+-----------------------+----------------------------+ -| ``aggregate`` | no | -- | | list of | | values to | `aggregate <#aggregate>`__ | -| | | | | key:values | | aggregate from | | -| | | | | | async branches | | -| | | | | | loop properties | | -+----------------+----------+---------------------------+--------------+-----------------------+----------------------------+ -| ``navigate`` | no | | ``FAILURE``: on_failure | | key:value | navigation logic | | `navigation <#navigate>`_| -| | | | or flow finish | | pairs | | | `results <#results>`__ | -| | | | ``SUCCESS``: next step | | | | -+----------------+----------+---------------------------+--------------+-----------------------+----------------------------+ - -**Example - step prints all the values in value_list asynchronously and +The step name is mapped to the parallel step's properties. + ++-------------------+----------+---------------------------+--------------+-----------------------+----------------------------------+ +| Property | Required | Default | Value Type | Description | More Info | ++===================+==========+===========================+==============+=======================+==================================+ +| ``parallel_loop`` | yes | -- | key | | container for | `parallel_loop <#parallel-loop>`_| +| | | | | | parallel loop | | +| | | | | | properties | | ++-------------------+----------+---------------------------+--------------+-----------------------+----------------------------------+ +| ``publish`` | no | -- | | list of | | values to | `publish <#publish>`__ | +| | | | | key:values | | aggregate from | | +| | | | | | parallel branches | | +| | | | | | loop properties | | ++-------------------+----------+---------------------------+--------------+-----------------------+----------------------------------+ +| ``navigate`` | no | | ``FAILURE``: on_failure | | key:value | navigation logic | | `navigation <#navigate>`_ | +| | | | or flow finish | | pairs | | | `results <#results>`__ | +| | | | ``SUCCESS``: next step | | | | ++-------------------+----------+---------------------------+--------------+-----------------------+----------------------------------+ + +**Example - step prints all the values in value_list in parallel and then navigates to a step named "another_step"** .. code-block:: yaml - print_values: - async_loop: + parallel_loop: for: value in values_list do: print_branch: - ID: ${value} - publish: - - name - aggregate: + publish: - name_list: ${map(lambda x:str(x['name']), branches_context)} navigate: - SUCCESS: another_step - FAILURE: FAILURE +.. _value: + +value +----- + +The key ``value`` is a property of an `output <#outputs>`__ name. It is +mapped to an `expression <#expressions>`__ value. + +The value key is most often used in conjunction with the `sensitive +<#sensitive>`__ key. Otherwise, an `output's <#outputs>`__ value can be defined +inline by mapping it to the `output <#outputs>`__ parameter's key. + + +**Example - output values** + +.. code-block:: yaml + + outputs: + - password: + value: ${password} + sensitive: true + - another_output: ${op_output} + .. _workflow: workflow diff --git a/cloudslang_editors.rst b/cloudslang_editors.rst index ce5cd1b..3ad3e3a 100644 --- a/cloudslang_editors.rst +++ b/cloudslang_editors.rst @@ -70,7 +70,7 @@ The following snippets are provided: +-----------------------+-----------------------------------------------------+ | for | template for an iterative step | +-----------------------+-----------------------------------------------------+ -| async | template for an asynchronous step | +| parallel_loop | template for a parallel step | +-----------------------+-----------------------------------------------------+ | property | template for a system property | +-----------------------+-----------------------------------------------------+ diff --git a/cloudslang_examples.rst b/cloudslang_examples.rst index 3f09632..536147f 100644 --- a/cloudslang_examples.rst +++ b/cloudslang_examples.rst @@ -9,7 +9,7 @@ concepts. - `Example 2 - Default Navigation <#example-2-default-navigation>`__ - `Example 3 - Subflow <#example-3-subflow>`__ - `Example 4 - Loops <#example-4-loops>`__ -- `Example 5 - Asynchronous Loop <#example-5-asynchronous-loop>`__ +- `Example 5 - Parallel Loop <#example-5-parallel-loop>`__ - `Example 6 - Operation Paths <#example-6-operation-paths>`__ Each of the examples below can be run by doing the following: @@ -384,39 +384,36 @@ looped on and various methods for handling loop breaks. results: - SUCCESS -.. _example_asynchronous_loop: +.. _example_parallel_loop: -Example 5 - Asynchronous Loop -============================= +Example 5 - Parallel Loop +========================= -This example demonstrates the usage of an asynchronous loop including +This example demonstrates the usage of a parallel loop including aggregation. -:download:`Download code ` +:download:`Download code ` -**Flow - async_loop_aggregate.sl** +**Flow - parallel_loop_aggregate.sl** .. code-block:: yaml - namespace: examples.async + namespace: examples.parallel flow: - name: async_loop_aggregate + name: parallel_loop_aggregate inputs: - values: [1,2,3,4] workflow: - print_values: - async_loop: + parallel_loop: for: value in values do: print_branch: - ID: ${value} - publish: - - name - - num - aggregate: + publish: - name_list: ${map(lambda x:str(x['name']), branches_context)} - first_name: ${branches_context[0]['name']} - last_name: ${branches_context[-1]['name']} @@ -432,7 +429,7 @@ aggregation. .. code-block:: yaml - namespace: examples.async + namespace: examples.parallel operation: name: print_branch diff --git a/code/examples_code/examples/async.zip b/code/examples_code/examples/async.zip deleted file mode 100644 index 79f2cb6..0000000 Binary files a/code/examples_code/examples/async.zip and /dev/null differ diff --git a/code/examples_code/examples/defaultnav.zip b/code/examples_code/examples/defaultnav.zip index 46dbcbc..6ede3d3 100644 Binary files a/code/examples_code/examples/defaultnav.zip and b/code/examples_code/examples/defaultnav.zip differ diff --git a/code/examples_code/examples/divide.zip b/code/examples_code/examples/divide.zip index c8e1573..2448a17 100644 Binary files a/code/examples_code/examples/divide.zip and b/code/examples_code/examples/divide.zip differ diff --git a/code/examples_code/examples/hello_world.zip b/code/examples_code/examples/hello_world.zip index 6192bd4..6a5ab42 100644 Binary files a/code/examples_code/examples/hello_world.zip and b/code/examples_code/examples/hello_world.zip differ diff --git a/code/examples_code/examples/loops.zip b/code/examples_code/examples/loops.zip index bf4bfff..4547afd 100644 Binary files a/code/examples_code/examples/loops.zip and b/code/examples_code/examples/loops.zip differ diff --git a/code/examples_code/examples/parallel.zip b/code/examples_code/examples/parallel.zip new file mode 100644 index 0000000..37fa44b Binary files /dev/null and b/code/examples_code/examples/parallel.zip differ diff --git a/code/examples_code/examples/async/async_loop_aggregate.sl b/code/examples_code/examples/parallel/parallel_loop_aggregate.sl similarity index 77% rename from code/examples_code/examples/async/async_loop_aggregate.sl rename to code/examples_code/examples/parallel/parallel_loop_aggregate.sl index 76447d3..4a886fe 100644 --- a/code/examples_code/examples/async/async_loop_aggregate.sl +++ b/code/examples_code/examples/parallel/parallel_loop_aggregate.sl @@ -1,22 +1,19 @@ -namespace: examples.async +namespace: examples.parallel flow: - name: async_loop_aggregate + name: parallel_loop_aggregate inputs: - values: [1,2,3,4] workflow: - print_values: - async_loop: + parallel_loop: for: value in values do: print_branch: - ID: ${value} - publish: - - name - - num - aggregate: + publish: - name_list: ${map(lambda x:str(x['name']), branches_context)} - first_name: ${branches_context[0]['name']} - last_name: ${branches_context[-1]['name']} diff --git a/code/examples_code/examples/async/print_branch.sl b/code/examples_code/examples/parallel/print_branch.sl similarity index 87% rename from code/examples_code/examples/async/print_branch.sl rename to code/examples_code/examples/parallel/print_branch.sl index af12309..4566fc0 100644 --- a/code/examples_code/examples/async/print_branch.sl +++ b/code/examples_code/examples/parallel/print_branch.sl @@ -1,4 +1,4 @@ -namespace: examples.async +namespace: examples.parallel operation: name: print_branch diff --git a/code/examples_code/examples/paths.zip b/code/examples_code/examples/paths.zip index 380ea08..3d910df 100644 Binary files a/code/examples_code/examples/paths.zip and b/code/examples_code/examples/paths.zip differ diff --git a/code/tutorial_code/tutorials_02.zip b/code/tutorial_code/tutorials_02.zip index c68220c..626c80f 100644 Binary files a/code/tutorial_code/tutorials_02.zip and b/code/tutorial_code/tutorials_02.zip differ diff --git a/code/tutorial_code/tutorials_03.zip b/code/tutorial_code/tutorials_03.zip index 8093a5b..8c4558e 100644 Binary files a/code/tutorial_code/tutorials_03.zip and b/code/tutorial_code/tutorials_03.zip differ diff --git a/code/tutorial_code/tutorials_04.zip b/code/tutorial_code/tutorials_04.zip index e69e9f5..a7477aa 100644 Binary files a/code/tutorial_code/tutorials_04.zip and b/code/tutorial_code/tutorials_04.zip differ diff --git a/code/tutorial_code/tutorials_05.zip b/code/tutorial_code/tutorials_05.zip index c23b09b..dce2d3e 100644 Binary files a/code/tutorial_code/tutorials_05.zip and b/code/tutorial_code/tutorials_05.zip differ diff --git a/code/tutorial_code/tutorials_06.zip b/code/tutorial_code/tutorials_06.zip index bc3d4d6..a75aea5 100644 Binary files a/code/tutorial_code/tutorials_06.zip and b/code/tutorial_code/tutorials_06.zip differ diff --git a/code/tutorial_code/tutorials_07.zip b/code/tutorial_code/tutorials_07.zip index 756a1a3..70aecd8 100644 Binary files a/code/tutorial_code/tutorials_07.zip and b/code/tutorial_code/tutorials_07.zip differ diff --git a/code/tutorial_code/tutorials_08.zip b/code/tutorial_code/tutorials_08.zip index b7bd41c..3227300 100644 Binary files a/code/tutorial_code/tutorials_08.zip and b/code/tutorial_code/tutorials_08.zip differ diff --git a/code/tutorial_code/tutorials_08/hiring/check_availability.sl b/code/tutorial_code/tutorials_08/hiring/check_availability.sl index cc437fe..ac4c740 100644 --- a/code/tutorial_code/tutorials_08/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_08/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_08/hiring/new_hire.sl b/code/tutorial_code/tutorials_08/hiring/new_hire.sl index 04277e3..33319c1 100644 --- a/code/tutorial_code/tutorials_08/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_08/hiring/new_hire.sl @@ -35,6 +35,7 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: print_fail - AVAILABLE: print_finish diff --git a/code/tutorial_code/tutorials_09.zip b/code/tutorial_code/tutorials_09.zip index 53b841a..ce5be6d 100644 Binary files a/code/tutorial_code/tutorials_09.zip and b/code/tutorial_code/tutorials_09.zip differ diff --git a/code/tutorial_code/tutorials_09/hiring/check_availability.sl b/code/tutorial_code/tutorials_09/hiring/check_availability.sl index dc4b651..ddbd043 100644 --- a/code/tutorial_code/tutorials_09/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_09/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_09/hiring/create_user_email.sl b/code/tutorial_code/tutorials_09/hiring/create_user_email.sl index d18fc47..c085bc3 100644 --- a/code/tutorial_code/tutorials_09/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_09/hiring/create_user_email.sl @@ -30,12 +30,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_09/hiring/new_hire.sl b/code/tutorial_code/tutorials_09/hiring/new_hire.sl index ba38cfb..9003a5b 100644 --- a/code/tutorial_code/tutorials_09/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_09/hiring/new_hire.sl @@ -28,6 +28,7 @@ flow: - attempt publish: - address + - password navigate: - CREATED: print_finish - UNAVAILABLE: print_fail diff --git a/code/tutorial_code/tutorials_10.zip b/code/tutorial_code/tutorials_10.zip index cf3ccaa..dd5127a 100644 Binary files a/code/tutorial_code/tutorials_10.zip and b/code/tutorial_code/tutorials_10.zip differ diff --git a/code/tutorial_code/tutorials_10/hiring/check_availability.sl b/code/tutorial_code/tutorials_10/hiring/check_availability.sl index e9f55e5..9b66eba 100644 --- a/code/tutorial_code/tutorials_10/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_10/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_10/hiring/create_user_email.sl b/code/tutorial_code/tutorials_10/hiring/create_user_email.sl index b07b3ad..100c42f 100644 --- a/code/tutorial_code/tutorials_10/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_10/hiring/create_user_email.sl @@ -30,12 +30,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_10/hiring/new_hire.sl b/code/tutorial_code/tutorials_10/hiring/new_hire.sl index bf0a883..a64443f 100644 --- a/code/tutorial_code/tutorials_10/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_10/hiring/new_hire.sl @@ -29,6 +29,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE diff --git a/code/tutorial_code/tutorials_11.zip b/code/tutorial_code/tutorials_11.zip index 3acd341..d8313cf 100644 Binary files a/code/tutorial_code/tutorials_11.zip and b/code/tutorial_code/tutorials_11.zip differ diff --git a/code/tutorial_code/tutorials_11/hiring/check_availability.sl b/code/tutorial_code/tutorials_11/hiring/check_availability.sl index 3dcdae5..c94bdf4 100644 --- a/code/tutorial_code/tutorials_11/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_11/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_11/hiring/create_user_email.sl b/code/tutorial_code/tutorials_11/hiring/create_user_email.sl index e54217f..a090969 100644 --- a/code/tutorial_code/tutorials_11/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_11/hiring/create_user_email.sl @@ -33,12 +33,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_11/hiring/new_hire.sl b/code/tutorial_code/tutorials_11/hiring/new_hire.sl index 6b7198e..3723cd1 100644 --- a/code/tutorial_code/tutorials_11/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_11/hiring/new_hire.sl @@ -37,6 +37,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE @@ -56,7 +57,7 @@ flow: - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish diff --git a/code/tutorial_code/tutorials_11/hiring/order.sl b/code/tutorial_code/tutorials_11/hiring/order.sl index a0c24b1..1c87a8b 100644 --- a/code/tutorial_code/tutorials_11/hiring/order.sl +++ b/code/tutorial_code/tutorials_11/hiring/order.sl @@ -14,12 +14,12 @@ operation: rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} diff --git a/code/tutorial_code/tutorials_12.zip b/code/tutorial_code/tutorials_12.zip index 7781fa0..702478b 100644 Binary files a/code/tutorial_code/tutorials_12.zip and b/code/tutorial_code/tutorials_12.zip differ diff --git a/code/tutorial_code/tutorials_12/hiring/check_availability.sl b/code/tutorial_code/tutorials_12/hiring/check_availability.sl index 085046f..291ee05 100644 --- a/code/tutorial_code/tutorials_12/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_12/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_12/hiring/create_user_email.sl b/code/tutorial_code/tutorials_12/hiring/create_user_email.sl index ed5b0d4..e3559ee 100644 --- a/code/tutorial_code/tutorials_12/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_12/hiring/create_user_email.sl @@ -33,12 +33,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_12/hiring/new_hire.sl b/code/tutorial_code/tutorials_12/hiring/new_hire.sl index f75f4e9..6b827c0 100644 --- a/code/tutorial_code/tutorials_12/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_12/hiring/new_hire.sl @@ -39,6 +39,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE @@ -58,7 +59,7 @@ flow: - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -80,7 +81,8 @@ flow: - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/code/tutorial_code/tutorials_12/hiring/order.sl b/code/tutorial_code/tutorials_12/hiring/order.sl index 911ec88..ad77789 100644 --- a/code/tutorial_code/tutorials_12/hiring/order.sl +++ b/code/tutorial_code/tutorials_12/hiring/order.sl @@ -14,12 +14,12 @@ operation: rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} diff --git a/code/tutorial_code/tutorials_13.zip b/code/tutorial_code/tutorials_13.zip index 32dafdd..b65c647 100644 Binary files a/code/tutorial_code/tutorials_13.zip and b/code/tutorial_code/tutorials_13.zip differ diff --git a/code/tutorial_code/tutorials_13/hiring/check_availability.sl b/code/tutorial_code/tutorials_13/hiring/check_availability.sl index 865f3cf..e9e7992 100644 --- a/code/tutorial_code/tutorials_13/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_13/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_13/hiring/create_user_email.sl b/code/tutorial_code/tutorials_13/hiring/create_user_email.sl index 32cbed2..bf5c8ed 100644 --- a/code/tutorial_code/tutorials_13/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_13/hiring/create_user_email.sl @@ -33,12 +33,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_13/hiring/new_hire.sl b/code/tutorial_code/tutorials_13/hiring/new_hire.sl index 00f221d..10f826f 100644 --- a/code/tutorial_code/tutorials_13/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_13/hiring/new_hire.sl @@ -38,6 +38,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE @@ -57,7 +58,7 @@ flow: - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -79,7 +80,8 @@ flow: - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/code/tutorial_code/tutorials_13/hiring/order.sl b/code/tutorial_code/tutorials_13/hiring/order.sl index 69de571..c11769a 100644 --- a/code/tutorial_code/tutorials_13/hiring/order.sl +++ b/code/tutorial_code/tutorials_13/hiring/order.sl @@ -14,12 +14,12 @@ operation: rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} diff --git a/code/tutorial_code/tutorials_14.zip b/code/tutorial_code/tutorials_14.zip index c8b23aa..f3624f5 100644 Binary files a/code/tutorial_code/tutorials_14.zip and b/code/tutorial_code/tutorials_14.zip differ diff --git a/code/tutorial_code/tutorials_14/hiring/check_availability.sl b/code/tutorial_code/tutorials_14/hiring/check_availability.sl index d679765..30a8979 100644 --- a/code/tutorial_code/tutorials_14/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_14/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_14/hiring/create_user_email.sl b/code/tutorial_code/tutorials_14/hiring/create_user_email.sl index f82c11c..00cb026 100644 --- a/code/tutorial_code/tutorials_14/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_14/hiring/create_user_email.sl @@ -33,12 +33,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_14/hiring/new_hire.sl b/code/tutorial_code/tutorials_14/hiring/new_hire.sl index 8d0c33c..b109ec5 100644 --- a/code/tutorial_code/tutorials_14/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_14/hiring/new_hire.sl @@ -38,6 +38,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE @@ -57,7 +58,7 @@ flow: - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -87,7 +88,8 @@ flow: - body: > ${fancy_text + '
' + 'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/code/tutorial_code/tutorials_14/hiring/order.sl b/code/tutorial_code/tutorials_14/hiring/order.sl index 001ec80..640c7c0 100644 --- a/code/tutorial_code/tutorials_14/hiring/order.sl +++ b/code/tutorial_code/tutorials_14/hiring/order.sl @@ -14,12 +14,12 @@ operation: rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} diff --git a/code/tutorial_code/tutorials_15.zip b/code/tutorial_code/tutorials_15.zip index fed6c93..4317e4f 100644 Binary files a/code/tutorial_code/tutorials_15.zip and b/code/tutorial_code/tutorials_15.zip differ diff --git a/code/tutorial_code/tutorials_15/hiring/check_availability.sl b/code/tutorial_code/tutorials_15/hiring/check_availability.sl index e1f474f..0a333e9 100644 --- a/code/tutorial_code/tutorials_15/hiring/check_availability.sl +++ b/code/tutorial_code/tutorials_15/hiring/check_availability.sl @@ -9,13 +9,19 @@ operation: python_action: script: | import random + import string rand = random.randint(0, 2) vacant = rand != 0 - #print vacant - + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' outputs: - available: ${vacant} - + - password: + value: ${password} + sensitive: true results: - UNAVAILABLE: ${rand == 0} - AVAILABLE diff --git a/code/tutorial_code/tutorials_15/hiring/create_user_email.sl b/code/tutorial_code/tutorials_15/hiring/create_user_email.sl index c078f12..727a7a4 100644 --- a/code/tutorial_code/tutorials_15/hiring/create_user_email.sl +++ b/code/tutorial_code/tutorials_15/hiring/create_user_email.sl @@ -33,12 +33,14 @@ flow: - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED outputs: - address + - password - availability results: diff --git a/code/tutorial_code/tutorials_15/hiring/hire_all.sl b/code/tutorial_code/tutorials_15/hiring/hire_all.sl index 89d7229..4b42054 100644 --- a/code/tutorial_code/tutorials_15/hiring/hire_all.sl +++ b/code/tutorial_code/tutorials_15/hiring/hire_all.sl @@ -11,19 +11,16 @@ flow: workflow: - process_all: - async_loop: + parallel_loop: for: name in names_list do: new_hire: - first_name: ${name['first']} - middle_name: ${name.get('middle','')} - last_name: ${name['last']} - publish: - - address - - total_cost - aggregate: + publish: - email_list: ${filter(lambda x:x != '', map(lambda x:str(x['address']), branches_context))} - - cost: ${sum(map(lambda x:x['total_cost'], branches_context))} + - cost: ${sum(map(lambda x:x['final_cost'], branches_context))} navigate: - SUCCESS: print_success - FAILURE: print_failure diff --git a/code/tutorial_code/tutorials_15/hiring/new_hire.sl b/code/tutorial_code/tutorials_15/hiring/new_hire.sl index 37bd9d8..2772df2 100644 --- a/code/tutorial_code/tutorials_15/hiring/new_hire.sl +++ b/code/tutorial_code/tutorials_15/hiring/new_hire.sl @@ -38,6 +38,7 @@ flow: - attempt publish: - address + - password break: - CREATED - FAILURE @@ -57,7 +58,7 @@ flow: - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -87,7 +88,8 @@ flow: - body: > ${fancy_text + '
' + 'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS @@ -100,4 +102,4 @@ flow: outputs: - address - - total_cost + - final_cost: ${total_cost} diff --git a/code/tutorial_code/tutorials_15/hiring/order.sl b/code/tutorial_code/tutorials_15/hiring/order.sl index 2cd5e11..f122015 100644 --- a/code/tutorial_code/tutorials_15/hiring/order.sl +++ b/code/tutorial_code/tutorials_15/hiring/order.sl @@ -14,12 +14,12 @@ operation: rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} diff --git a/developer_cloudslang.rst b/developer_cloudslang.rst index fe88c2f..d1eab67 100644 --- a/developer_cloudslang.rst +++ b/developer_cloudslang.rst @@ -303,71 +303,71 @@ event data map keys are enclosed in square brackets - [KEYNAME]. - [STEP_NAME] - [TYPE] -+---------------------------+-----------------------+-------------------------------+ -| Type [TYPE] | Usage | Event Data | -+===========================+=======================+===============================+ -| EVENT_INPUT_START | | Input binding | [INPUTS] | -| | | started for | | -| | | flow or operation | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_INPUT_END | | Input binding | [BOUND_INPUTS] | -| | | finished for | | -| | | flow or operation | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_STEP_START | Step started | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_ARGUMENT_START | | Argument binding | [ARGUMENTS] | -| | | started for step | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_ARGUMENT_END | | Step arguments | [BOUND_ARGUMENTS] | -| | | resolved | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_OUTPUT_START | | Output binding | | [executableResults] | -| | | started for | | [executableOutputs] | -| | | flow or operation | | [actionReturnValues] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_OUTPUT_END | | Output binding | | [OUTPUTS] | -| | | finished for | | [RESULT] | -| | | flow or operation | | [EXECUTABLE_NAME] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_OUTPUT_START | | Output binding | | [operationReturnValues] | -| | | started for step | | [stepNavigationValues] | -| | | | [stepPublishValues] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_OUTPUT_END | | Output binding | | [nextPosition] | -| | | finished for step | | [RESULT] | -| | | | [OUTPUTS] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_EXECUTION_FINISHED | | Execution finished | | [RESULT] | -| | | running | | [OUTPUTS] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_ACTION_START | | Before action | | [TYPE] | -| | | invocation | | [CALL_ARGUMENTS] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_ACTION_END | | After successful | [RETURN_VALUES] | -| | | action invocation | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_ACTION_ERROR | | Exception in | [EXCEPTION] | -| | | action execution | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_SPLIT_BRANCHES | | Async loop | [BOUND_ASYNC_LOOP_EXPRESSION] | -| | | expression bound | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_BRANCH_START | | Async loop | | [splitItem] | -| | | branch created | | [refId] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_BRANCH_END | | Async loop | [branchReturnValues] | -| | | branch ended | | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_JOIN_BRANCHES_START | | Async loop output | | [stepNavigationValues] | -| | | binding started | | [stepAggregateValues] | -+---------------------------+-----------------------+-------------------------------+ -| EVENT_JOIN_BRANCHES_END | | Async loop output | | [nextPosition] | -| | | binding finished | | [RESULT] | -| | | | [OUTPUTS] | -+---------------------------+-----------------------+-------------------------------+ -| SLANG_EXECUTION_EXCEPTION | | Exception in | | [IS_BRANCH] | -| | | previous step | | [executionIdContext] | -| | | | [systemContext] | -| | | | [EXECUTION_CONTEXT] | -+---------------------------+-----------------------+-------------------------------+ ++---------------------------+------------------------+----------------------------------+ +| Type [TYPE] | Usage | Event Data | ++===========================+========================+==================================+ +| EVENT_INPUT_START | | Input binding | [INPUTS] | +| | | started for | | +| | | flow or operation | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_INPUT_END | | Input binding | [BOUND_INPUTS] | +| | | finished for | | +| | | flow or operation | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_STEP_START | Step started | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_ARGUMENT_START | | Argument binding | [ARGUMENTS] | +| | | started for step | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_ARGUMENT_END | | Step arguments | [BOUND_ARGUMENTS] | +| | | resolved | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_OUTPUT_START | | Output binding | | [executableResults] | +| | | started for | | [executableOutputs] | +| | | flow or operation | | [actionReturnValues] | ++---------------------------+-----------------------+-----------------------------------+ +| EVENT_OUTPUT_END | | Output binding | | [OUTPUTS] | +| | | finished for | | [RESULT] | +| | | flow or operation | | [EXECUTABLE_NAME] | ++---------------------------+-----------------------+-----------------------------------+ +| EVENT_OUTPUT_START | | Output binding | | [operationReturnValues] | +| | | started for step | | [stepNavigationValues] | +| | | | [stepPublishValues] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_OUTPUT_END | | Output binding | | [nextPosition] | +| | | finished for step | | [RESULT] | +| | | | [OUTPUTS] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_EXECUTION_FINISHED | | Execution finished | | [RESULT] | +| | | running | | [OUTPUTS] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_ACTION_START | | Before action | | [TYPE] | +| | | invocation | | [CALL_ARGUMENTS] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_ACTION_END | | After successful | [RETURN_VALUES] | +| | | action invocation | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_ACTION_ERROR | | Exception in | [EXCEPTION] | +| | | action execution | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_SPLIT_BRANCHES | | parallel loop | [BOUND_PARALLEL_LOOP_EXPRESSION] | +| | | expression bound | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_BRANCH_START | | Parallel loop | | [splitItem] | +| | | branch created | | [refId] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_BRANCH_END | | Parallel loop | [branchReturnValues] | +| | | branch ended | | ++---------------------------+------------------------+----------------------------------+ +| EVENT_JOIN_BRANCHES_START | | Parallel loop output | | [stepNavigationValues] | +| | | binding started | | [stepAggregateValues] | ++---------------------------+------------------------+----------------------------------+ +| EVENT_JOIN_BRANCHES_END | | Parallel loop output | | [nextPosition] | +| | | binding finished | | [RESULT] | +| | | | [OUTPUTS] | ++---------------------------+------------------------+----------------------------------+ +| SLANG_EXECUTION_EXCEPTION | | Exception in | | [IS_BRANCH] | +| | | previous step | | [executionIdContext] | +| | | | [systemContext] | +| | | | [EXECUTION_CONTEXT] | ++---------------------------+------------------------+----------------------------------+ diff --git a/section_tutorial.rst b/section_tutorial.rst index f5b895d..b6b0d9e 100644 --- a/section_tutorial.rst +++ b/section_tutorial.rst @@ -20,4 +20,4 @@ Contents: 12: Existing Content 13: System Properties 14: 3rd Party Python Packages - 15: Asynchronous Loop \ No newline at end of file + 15: Parallel Loop diff --git a/tutorial/08_lesson.rst b/tutorial/08_lesson.rst index 2e32193..51ee792 100644 --- a/tutorial/08_lesson.rst +++ b/tutorial/08_lesson.rst @@ -1,11 +1,11 @@ -Lesson 8 - Input Parameters -=========================== +Lesson 8 - Input and Output Parameters +====================================== Goal ---- -In this lesson we'll learn how to change the way inputs behave using -input properties. +In this lesson we'll learn how to change the way inputs and outputs behave using +input and output properties. Get Started ----------- @@ -161,8 +161,10 @@ Let's make the ``middle_name`` optional. We'll have to set its - domain - attempt -**YAML Note:** Don't forget to add a colon (``:``) to the input name -before adding its properties. +.. note:: + + **YAML Note:** Don't forget to add a colon (``:``) to the input name + before adding its properties. For more information, see :ref:`required` in the DSL reference. @@ -257,6 +259,64 @@ inputs and the ``generate_address`` step. For more information, see :ref:`private` in the DSL reference. +Sensitive +--------- + +Finally, we can mark both inputs and outputs as ``sensitive``. When a variable +is marked as sensitive, its value will not be printed in logs, events or in +outputs of the CLI and Build Tool. + +In the ``check_availability`` operation, let's create a temporary password if +an email address is available. We'll just add a few lines to our script to +randomly generate a short password if the address is available. In the +``outputs`` section, we'll mark that password as ``sensitive``. Notice, +that when we add a ``sensitive`` property to an output we have to add a +``value`` property as well. + +.. code-block:: yaml + + python_action: + script: | + import random + rand = random.randint(0, 2) + vacant = rand != 0 + # print vacant + if vacant == True: + password = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) + else: + password = '' + + outputs: + - available: ${vacant} + - password: + value: ${password} + sensitive: true + +You can now run the ``check_availability`` operation and see how the ``password`` +output is not printed to the screen. + +.. code-block:: bash + + run --f /tutorials/hiring/check_availability.sl --i address=john.doe@somecompany.com + +In the ``new_hire`` flow we'll add ``password`` to the ``publish`` section of +the ``check_address`` step to be used later on. + +.. code-block:: yaml + + - check_address: + do: + check_availability: + - address + publish: + - availability: ${available} + - password + navigate: + - UNAVAILABLE: print_fail + - AVAILABLE: print_finish + +For more information, see :ref:`sensitive` in the DSL reference. + Run It ------ @@ -322,6 +382,7 @@ New Code - Complete - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: print_fail - AVAILABLE: print_finish @@ -376,3 +437,36 @@ New Code - Complete results: - FAILURE: ${address == ''} - SUCCESS + +**check_availability.sl** + +.. code-block:: yaml + + namespace: tutorials_08.hiring + + operation: + name: check_availability + + inputs: + - address + + python_action: + script: | + import random + import string + rand = random.randint(0, 2) + vacant = rand != 0 + # print vacant + if vacant == True: + password = ''.join(random.choice(string.letters) for _ in range(6)) + else: + password = '' + + outputs: + - available: ${vacant} + - password: + value: ${password} + sensitive: true + results: + - UNAVAILABLE: ${rand == 0} + - AVAILABLE diff --git a/tutorial/09_lesson.rst b/tutorial/09_lesson.rst index 3d1c8cb..07858a9 100644 --- a/tutorial/09_lesson.rst +++ b/tutorial/09_lesson.rst @@ -16,7 +16,7 @@ flow itself and therefore it follows all the regular flow syntax. Move Code --------- -Now we'll steal a bunch of the code that currently sits in +The first thing we'll do is steal a bunch of the code that currently sits in **new_hire.sl**. Let's take everything up until the ``workflow`` key and copy it into the new flow and make a couple of changes. First, we won't need the imports, so we can just delete them. Next, we'll change @@ -59,6 +59,7 @@ Next let's create a ``workflow`` section and copy the - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: print_fail - AVAILABLE: print_finish @@ -119,6 +120,7 @@ flow. - address publish: - availability: ${available} + - password navigate: - UNAVAILABLE: UNAVAILABLE - AVAILABLE: CREATED @@ -130,6 +132,7 @@ outputs. outputs: - address + - password - availability Test It @@ -173,6 +176,7 @@ navigation. - attempt publish: - address + - password navigate: - CREATED: print_finish - UNAVAILABLE: print_fail @@ -257,6 +261,7 @@ New Code - Complete - attempt publish: - address + - password navigate: - CREATED: print_finish - UNAVAILABLE: print_fail @@ -307,6 +312,7 @@ New Code - Complete do: check_availability: - address + - password publish: - availability: ${available} navigate: @@ -315,6 +321,7 @@ New Code - Complete outputs: - address + - password - availability results: diff --git a/tutorial/10_lesson.rst b/tutorial/10_lesson.rst index ccbaf5e..a05a0bb 100644 --- a/tutorial/10_lesson.rst +++ b/tutorial/10_lesson.rst @@ -37,6 +37,7 @@ numbers. - attempt publish: - address + - password navigate: - CREATED: print_finish - UNAVAILABLE: print_fail @@ -146,6 +147,7 @@ to break on, which in our case is ``CREATED`` or ``FAILURE``. - attempt publish: - address + - password break: - CREATED - FAILURE @@ -236,6 +238,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE diff --git a/tutorial/11_lesson.rst b/tutorial/11_lesson.rst index e0bf4ca..215d052 100644 --- a/tutorial/11_lesson.rst +++ b/tutorial/11_lesson.rst @@ -23,9 +23,9 @@ Operation The ``order`` operation, as we'll call it, looks very similar to our ``check_availability`` operation. It uses a random number to simulate whether a given item is available. If the item is available, it will -return the ``price`` of the item as one output and the ``not_ordered`` +return the amount ``spent`` as one output and the ``not_ordered`` output will be empty. If the item is unavailable, it will return ``0`` -for the ``price`` of the item and the name of the item in the ``not_ordered`` +for the ``spent`` output and the name of the item in the ``not_ordered`` output. .. code-block:: yaml @@ -46,12 +46,12 @@ output. rand = random.randint(0, 2) available = rand != 0 not_ordered = item + ';' if rand == 0 else '' - price = 0 if rand == 0 else price + spent = 0 if rand == 0 else price if rand == 0: print 'Unavailable' outputs: - not_ordered - - price + - spent results: - UNAVAILABLE: ${rand == 0} @@ -125,7 +125,7 @@ back into the flow-level ``total_cost`` for each iteration of the publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} Finally we have to rewire all the navigation logic to take into account our new step. @@ -230,6 +230,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE @@ -249,7 +250,7 @@ New Code - Complete - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish diff --git a/tutorial/12_lesson.rst b/tutorial/12_lesson.rst index 6098440..253e355 100644 --- a/tutorial/12_lesson.rst +++ b/tutorial/12_lesson.rst @@ -107,9 +107,10 @@ call the ``send_mail`` operation. Let's put it right after the ``print_finish`` operation. We need to pass a host, port, from, to, subject and body. You'll need to substitute the values in angle brackets (``<>``) to work for your email host. Notice that the body value is -taken directly from the ``print_finish`` step with the slight change of -turning the ``\n`` into a ``
`` since the ``html_email`` input -defaults to true. +taken directly from the ``print_finish`` step with two slight changes. First, we +turned the ``\n`` into a ``
`` since the ``html_email`` input defaults to +true. Second, we added the temporary password published by the +``create_email_address`` step. .. code-block:: yaml @@ -123,7 +124,8 @@ defaults to true. - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS @@ -196,6 +198,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE @@ -215,7 +218,7 @@ New Code - Complete - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -237,7 +240,8 @@ New Code - Complete - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/tutorial/13_lesson.rst b/tutorial/13_lesson.rst index 94bb66f..f0908f5 100644 --- a/tutorial/13_lesson.rst +++ b/tutorial/13_lesson.rst @@ -101,7 +101,8 @@ values from the system properties file. - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS @@ -183,6 +184,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE @@ -202,7 +204,7 @@ New Code - Complete - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -224,7 +226,8 @@ New Code - Complete - subject: "${'New Hire: ' + first_name + ' ' + last_name}" - body: > ${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/tutorial/14_lesson.rst b/tutorial/14_lesson.rst index 11377bc..fbd216f 100644 --- a/tutorial/14_lesson.rst +++ b/tutorial/14_lesson.rst @@ -157,7 +157,8 @@ fancy text. - body: > ${fancy_text + '
' + 'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS @@ -180,7 +181,7 @@ Download the Code Up Next ------- -In the next lesson we'll see how to use an asynchronous loop. +In the next lesson we'll see how to use a parallel loop. New Code - Complete ------------------- @@ -229,6 +230,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE @@ -248,7 +250,7 @@ New Code - Complete - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -278,7 +280,8 @@ New Code - Complete - body: > ${fancy_text + '
' + 'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items:' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS diff --git a/tutorial/15_lesson.rst b/tutorial/15_lesson.rst index 77080ed..5931994 100644 --- a/tutorial/15_lesson.rst +++ b/tutorial/15_lesson.rst @@ -1,12 +1,12 @@ -Lesson 15 - Asynchronous Loop +Lesson 15 - Parallel Loop ============================= Goal ---- -In this lesson we'll learn how to loop asynchronously. When looping -asynchronously, a new branch is created for each value in a list and the -branches run in parallel. +In this lesson we'll learn how to loop in parallel. When looping in parallel, a +new branch is created for each value in a list and the action associated with +the step is run for each branch in parallel. Get Started ----------- @@ -33,14 +33,14 @@ proper indentation. outputs: - address - - total_cost + - final_cost: ${total_cost} Parent Flow ----------- Our new ``hire_all`` flow is going to take in a list of names of people being hired and will call the ``new_hire`` flow for each one of them. It -will be looping asynchronously, so all the ``new_hire`` flows will be +will be looping in parallel, so all the ``new_hire`` flows will be running simultaneously. In **hire_all.sl** we can start off as usual by declaring a @@ -65,7 +65,7 @@ which in our case is a list of names. Loop Syntax ----------- -An asynchronous loop looks pretty similar to a normal for loop, but with +A parallel loop looks pretty similar to a normal for loop, but with a few key differences. Let's create a new step named ``process_all`` in which we'll do our @@ -74,7 +74,7 @@ looping. Each branch of the loop will call the ``new_hire`` flow. .. code-block:: yaml - process_all: - async_loop: + parallel_loop: for: name in names_list do: new_hire: @@ -83,7 +83,7 @@ looping. Each branch of the loop will call the ``new_hire`` flow. - last_name: ${name['last']} As you can see, so far it is almost identical to a regular for loop, -except the ``loop`` key has been replaced by ``async_loop``. +except the ``loop`` key has been replaced by ``parallel_loop``. The ``names_list`` input will be a list of dictionaries containing name information with the keys ``first``, ``middle`` and ``last``. For each @@ -92,97 +92,62 @@ passed the corresponding name values. The various branches running the ``new_hire`` flow will run in parallel and the rest of the flow will continue only after all the branches have completed. -For more information, see :ref:`async_loop` in the DSL reference. +For more information, see :ref:`parallel_loop ` in the DSL +reference. Publish ------- -As in a regular loop, you can also include a ``publish`` section in an -asynchronous loop, but it works differently. In an asynchronous loop, -the published variables are not published to the flow's scope. Instead -they publish operation or subflow outputs to be used for aggregation -purposes in the ``aggregate`` section. +Next we perform aggregation in the ``publish`` section in a similar manner to +what we do in a normal for loop (as we did in lesson +:doc:`11 - Loop Aggregation <11_lesson>`). Publish occurs only after all +branches have completed. -Here we are publishing the ``address`` and ``total_cost`` outputs that -we just added to the ``new_hire`` flow. - -.. code-block:: yaml - - - process_all: - async_loop: - for: name in names_list - do: - new_hire: - - first_name: ${name['first']} - - middle_name: ${name.get('middle','')} - - last_name: ${name['last']} - publish: - - address - - total_cost - -For more information, see :ref:`publish` in the DSL reference. - -Aggregate ---------- - -Whereas aggregation takes place in the ``publish`` section of a normal for loop -(as we did in lesson :doc:`11 - Loop Aggregation <11_lesson>`), in an -asynchronous loop there is an additional ``aggregate`` section. - -Notice that the ``aggregate`` key is indented to be in line with the -``async_loop`` key, indicating that it does not run for each branch in the loop. -Aggregation occurs only after all branches have completed. - -In most cases the aggregation will make use of the ``branches_context`` -list. This is a list that is populated with all of the published outputs -from all of the branchs. For example, in our case, -``branches_context[0]`` will contain keys, corresponding to the -published variables ``address`` and ``total_cost``, mapped to the values -output by the first branch to complete. Similarly, ``branches_context[1]`` -will contain the keys ``address`` and ``total_cost`` mapped to the values output -by the second branch to complete. +In most cases the publish will make use of the ``branches_context`` +list. This is a list that is populated with all of the outputs from +all of the branches. For example, in our case, +``branches_context[0]`` will contain keys ``address`` and ``final_cost``, +corresponding to the values output by the first branch to complete. Similarly, +``branches_context[1]`` will contain the keys ``address`` and ``final_cost`` +mapped to the values output by the second branch to complete. There is no way to predict the order in which branches will complete, so -the ``branches_context`` is rarely accessed using particular indices. -Instead, Python expressions are used to extract the desired -aggregations. +the ``branches_context`` is rarely accessed using a particular index. Instead, +Python expressions are used to extract the desired aggregations. .. code-block:: yaml - process_all: - async_loop: + parallel_loop: for: name in names_list do: new_hire: - first_name: ${name['first']} - middle_name: ${name.get('middle','')} - last_name: ${name['last']} - publish: - - address - - total_cost - aggregate: + publish: - email_list: ${filter(lambda x:x != '', map(lambda x:str(x['address']), branches_context))} - - cost: ${sum(map(lambda x:x['total_cost'], branches_context))} + - cost: ${sum(map(lambda x:x['final_cost'], branches_context))} In our case we use the ``map()``, ``filter()`` and ``sum()`` Python functions to create a list of all the email addresses that were created and a sum of all the equipment costs. -Let's look a bit closer at one of the aggregations to better understand what's -going on. Each time a branch of the asynchronous loop is finished running the -``new_hire`` subflow it publishes a ``total_cost`` value. Each of those -individual ``total_cost`` values gets added to the ``branches_context`` list at +Let's look a bit closer at one of the publish aggregations to better understand +what's going on. Each time a branch of the parallel loop is finished running the +``new_hire`` subflow it publishes a ``final_cost`` value. Each of those +individual ``final_cost`` values gets added to the ``branches_context`` list at index ``n``, where ``n`` indicates the order the branches finish in, under the -``total_cost`` key. So, if we were to loop through the ``branches_context`` we -would find at ``branches_context[n][total_cost]`` the ``total_cost`` value that +``final_cost`` key. So, if we were to loop through the ``branches_context`` we +would find at ``branches_context[n][final_cost]`` the ``final_cost`` value that was published by the nth ``new_hire`` subflow to finish running. Instead of looping through the ``branches_context``, we use a Python lambda expression in conjunction with the ``map`` function to extract just the values of the -``total_cost`` from each ``branches_context[n][total_cost]`` to a new list. +``final_cost`` from each ``branches_context[n][final_cost]`` to a new list. Finally, we use the Python ``sum`` function to add up all the extracted values in our new list and publish that value as ``cost``. -For more information, see :ref:`aggregate` and :ref:`branches_context` in the +For more information, see :ref:`publish` and :ref:`branches_context` in the DSL reference. For more information on the Python constructs used here, see @@ -191,11 +156,10 @@ For more information on the Python constructs used here, see and `sum `__ in the Python documentation. - Navigate -------- -Navigation also works a bit differently in an asynchronous loop. If any +Navigation also works a bit differently in a parallel loop. If any of the branches return a result of ``FAILURE`` the flow will follow the navigation path of ``FAILURE``. Otherwise, the flow will follow the ``SUCCESS`` navigation path. @@ -209,19 +173,16 @@ navigate to the ``print_success`` step. .. code-block:: yaml - process_all: - async_loop: + parallel_loop: for: name in names_list do: new_hire: - first_name: ${name['first']} - middle_name: ${name.get('middle','')} - last_name: ${name['last']} - publish: - - address - - total_cost - aggregate: + publish: - email_list: ${filter(lambda x:x != '', map(lambda x:str(x['address']), branches_context))} - - cost: ${sum(map(lambda x:x['total_cost'], branches_context))} + - cost: ${sum(map(lambda x:x['final_cost'], branches_context))} navigate: - SUCCESS: print_success - FAILURE: print_failure @@ -339,6 +300,7 @@ New Code - Complete - attempt publish: - address + - password break: - CREATED - FAILURE @@ -358,7 +320,7 @@ New Code - Complete - cost: ${total_cost} publish: - all_missing: ${missing + not_ordered} - - total_cost: ${cost + price} + - total_cost: ${cost + spent} navigate: - AVAILABLE: print_finish - UNAVAILABLE: print_finish @@ -388,7 +350,8 @@ New Code - Complete - body: > ${fancy_text + '
' + 'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '
' + - 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost)} + 'Missing items: ' + all_missing + ' Cost of ordered items: ' + str(total_cost) + '
' + + 'Temporary password: ' + password} navigate: - FAILURE: FAILURE - SUCCESS: SUCCESS @@ -401,7 +364,7 @@ New Code - Complete outputs: - address - - total_cost + - final_cost: ${total_cost} **hire_all.sl** @@ -420,19 +383,16 @@ New Code - Complete workflow: - process_all: - async_loop: + parallel_loop: for: name in names_list do: new_hire: - first_name: ${name['first']} - middle_name: ${name.get('middle','')} - last_name: ${name['last']} - publish: - - address - - total_cost - aggregate: + publish: - email_list: ${filter(lambda x:x != '', map(lambda x:str(x['address']), branches_context))} - - cost: ${sum(map(lambda x:x['total_cost'], branches_context))} + - cost: ${sum(map(lambda x:x['final_cost'], branches_context))} navigate: - SUCCESS: print_success - FAILURE: print_failure