Fortinet black logo

Playbooks Guide

Dynamic Variables

Copy Link
Copy Doc ID 6cbc6fee-9e87-11eb-b70b-00505692583a:953224
Download PDF

Dynamic Variables

Overview

Dynamic variables are objects that can be set and accessed within a playbook. Any valid Python object can be a dynamic variable. This includes ints, strings, dictionaries, etc. Variables themselves have no type information associated with them; however, playbook steps do. Steps may attempt to coerce dynamic variables into the expected data type; however, it is mostly on the caller to pass the correct types.

Dynamic variables can be passed to playbook steps as arguments directly, or they may be embedded in a larger string, where they will act more as global variables (or macros), getting replaced by a string representation of themselves.

Syntax

Double curly braces ({{ }}) demarcate dynamic variables from the surrounding text. Anything that goes between the braces is a dynamic variable. The most basic use of the dynamic variable is as a simple dictionary lookup.

Tooltip

The general data structure you are using matters within the usage of the dynamic variable. JSON is the easiest data format to consume and use. XML may be converted into JSON directly so that it may also be used. The following examples assume that you are able to use a JSON format.

Let's look at some examples. Say you have an object (array) named users which has the following structure:

{
    'Alvian': 42,
    'Kreb': 413,
    'Mandu': 1
}

Example 1

You can then use dynamic variables to access the values of that object.

{{ vars.users.Alvian }}

This statement will evaluate to 42.

Example 2

There are {{ vars.users.Kreb }} Krebs in FortiSOAR.

This statement will evaluate to the string "There are 413 Krebs in FortiSOAR."

Example 3

{{ vars.users.does_not_exist }} 

This statement would evaluate to an error and would be displayed as:

no such element: users['does_not_exist']

Example 4

Say you modified the object (array) named users to have the following structure:

{
    'Alvian': 42,
    'Kreb': { 
    	'original': 413,
        'pi': 3.14
    },
    'Mandu': 1
}

To access the secondary array is as easy as adding an additional key for the key-value pair you desire to access.

{{ vars.users.Krebs.pi }} 

This statement would evaluate to 3.14. An alternative format for accessing the variable, which may be used in case of special characters present, is:

{{ vars.users['Krebs']['pi'] }}

This statement would evaluate identically to the previous, 3.14.

Implementation

The major driving force behind dynamic variables is Jinja2 templates. A general overview of how Jinja2 works can be found here.

Specifically, to render a template, Jinja takes two arguments: a context and a template string. The template string is the dynamic variable itself, which is provided by users in the playbook. The context object, on the other hand, will be created automatically before each and every playbook step. It contains various helper functions as well as the internal representation of the dynamic variable data.

Scope

Scope for dynamic variables is defined by the COPY_ENV_FOR_REFERENCE_WORKFLOW setting. Use this setting to pass variables to a reference playbook.

By default, the COPY_ENV_FOR_REFERENCE_WORKFLOW is set to false.

Functionality

There are several top-level objects that can be accessed within a dynamic variable.

Dictionary-like Objects

Most ordinary variables are stored under the vars namespace. Whenever a variable is declared using: class:workflow.tasks.set_variable, it will go under vars. Additionally, the playbook engine will automatically set the following variables:

  • vars.result: This contains the return value of the previous playbook step.
  • vars.input.records: This contains information about what triggered a playbook, i.e., the body of the inbound request.
  • vars.request.headers: This contains the metadata of all the headers that are part of the playbooks environment, and which can be used in the playbooks, such as X-RUNBYUSER which is a jinja template to retrieve the name of the user who triggered the playbook. Some other parameters are, trigger type, authorization, accept, host, content-type, etc.
  • vars.input.params.api_body: This contains the data passed from a Custom API Endpoint trigger.

Built-in Functions & Filters

Functions

  • arrow: Datetime functions:
{{ arrow.utcnow().int_timestamp }}

In version 7.0.0, FortiSOAR has updated the arrow library, due to which the timestamp attribute has been changed into int_timestamp for DateTime jinja expressions, . For more information see, https://arrow.readthedocs.io/en/latest/releases.html#id4

Note

New playbooks must use the int_timestamp for any DateTime jinja expressions.

More documentation can be found here

  • uuid: returns a uuid using python's uuid.uuid4() function
{{ uuid() }}

Filters

See the Jinja Filters and Functions chapter for information.

FAQS

How are dynamic variables used in condition steps?

Decision steps use dynamic variables with logical equalities of the form:

{{ 8 == 8 }}

This statement will return either the string 'True,' or 'False' which will automatically be converted into a real boolean value.

Note

Decision steps advanced interface does not require the use of curly braces like {{ }}.

Dynamic Variables

Overview

Dynamic variables are objects that can be set and accessed within a playbook. Any valid Python object can be a dynamic variable. This includes ints, strings, dictionaries, etc. Variables themselves have no type information associated with them; however, playbook steps do. Steps may attempt to coerce dynamic variables into the expected data type; however, it is mostly on the caller to pass the correct types.

Dynamic variables can be passed to playbook steps as arguments directly, or they may be embedded in a larger string, where they will act more as global variables (or macros), getting replaced by a string representation of themselves.

Syntax

Double curly braces ({{ }}) demarcate dynamic variables from the surrounding text. Anything that goes between the braces is a dynamic variable. The most basic use of the dynamic variable is as a simple dictionary lookup.

Tooltip

The general data structure you are using matters within the usage of the dynamic variable. JSON is the easiest data format to consume and use. XML may be converted into JSON directly so that it may also be used. The following examples assume that you are able to use a JSON format.

Let's look at some examples. Say you have an object (array) named users which has the following structure:

{
    'Alvian': 42,
    'Kreb': 413,
    'Mandu': 1
}

Example 1

You can then use dynamic variables to access the values of that object.

{{ vars.users.Alvian }}

This statement will evaluate to 42.

Example 2

There are {{ vars.users.Kreb }} Krebs in FortiSOAR.

This statement will evaluate to the string "There are 413 Krebs in FortiSOAR."

Example 3

{{ vars.users.does_not_exist }} 

This statement would evaluate to an error and would be displayed as:

no such element: users['does_not_exist']

Example 4

Say you modified the object (array) named users to have the following structure:

{
    'Alvian': 42,
    'Kreb': { 
    	'original': 413,
        'pi': 3.14
    },
    'Mandu': 1
}

To access the secondary array is as easy as adding an additional key for the key-value pair you desire to access.

{{ vars.users.Krebs.pi }} 

This statement would evaluate to 3.14. An alternative format for accessing the variable, which may be used in case of special characters present, is:

{{ vars.users['Krebs']['pi'] }}

This statement would evaluate identically to the previous, 3.14.

Implementation

The major driving force behind dynamic variables is Jinja2 templates. A general overview of how Jinja2 works can be found here.

Specifically, to render a template, Jinja takes two arguments: a context and a template string. The template string is the dynamic variable itself, which is provided by users in the playbook. The context object, on the other hand, will be created automatically before each and every playbook step. It contains various helper functions as well as the internal representation of the dynamic variable data.

Scope

Scope for dynamic variables is defined by the COPY_ENV_FOR_REFERENCE_WORKFLOW setting. Use this setting to pass variables to a reference playbook.

By default, the COPY_ENV_FOR_REFERENCE_WORKFLOW is set to false.

Functionality

There are several top-level objects that can be accessed within a dynamic variable.

Dictionary-like Objects

Most ordinary variables are stored under the vars namespace. Whenever a variable is declared using: class:workflow.tasks.set_variable, it will go under vars. Additionally, the playbook engine will automatically set the following variables:

  • vars.result: This contains the return value of the previous playbook step.
  • vars.input.records: This contains information about what triggered a playbook, i.e., the body of the inbound request.
  • vars.request.headers: This contains the metadata of all the headers that are part of the playbooks environment, and which can be used in the playbooks, such as X-RUNBYUSER which is a jinja template to retrieve the name of the user who triggered the playbook. Some other parameters are, trigger type, authorization, accept, host, content-type, etc.
  • vars.input.params.api_body: This contains the data passed from a Custom API Endpoint trigger.

Built-in Functions & Filters

Functions

  • arrow: Datetime functions:
{{ arrow.utcnow().int_timestamp }}

In version 7.0.0, FortiSOAR has updated the arrow library, due to which the timestamp attribute has been changed into int_timestamp for DateTime jinja expressions, . For more information see, https://arrow.readthedocs.io/en/latest/releases.html#id4

Note

New playbooks must use the int_timestamp for any DateTime jinja expressions.

More documentation can be found here

  • uuid: returns a uuid using python's uuid.uuid4() function
{{ uuid() }}

Filters

See the Jinja Filters and Functions chapter for information.

FAQS

How are dynamic variables used in condition steps?

Decision steps use dynamic variables with logical equalities of the form:

{{ 8 == 8 }}

This statement will return either the string 'True,' or 'False' which will automatically be converted into a real boolean value.

Note

Decision steps advanced interface does not require the use of curly braces like {{ }}.