Substitution

Substitution allows a Snippet Argument to be updated with context-aware information. This features enables a Snippet Argument writer to develop more generic steps and have the Snippet Framework perform the required substitution to successfully query the data.

Substitution can be identified by the prefix $. These variables will be replaced before any steps execute to ensure all of the relevant information is populated. If the Snippet Argument contains a substitution key that is not present in the substitution dictionary, it will be ignored. For example, if you had a regular expression that utilized $, you will not have to make any modifications for it to be considered valid. It is best practice to encapsulate your substitution within curly brackets, {}. If you needed to use the component distinguished name as part of a URI, the snippet argument would be /path/${silo_comp_dn}/endpoint.

Argument

Usage

${silo_app_id}

The application ID of the Dynamic Application

${silo_gmtime}

The timestamp for the data when saving to the database for the Dynamic Application

${silo_freq}

The poll frequency of the Dynamic Application

${silo_did}

The Device ID (DID) of this device/component device

${silo_ip}

The IP address of this component device

${silo_guid}

The Globally Unique Identifier (GUID) of this component device

${silo_comp_name}

The name of this component device

${silo_comp_dn}

The Unique identifier for the DCM tree of this component device

${silo_comp_uid}

The Unique ID of this component device

${silo_root_did}

The root Device ID of this component device

${silo_root_name}

The root Device name of this component device

${silo_root_dn}

The root Device DN of this component device

${silo_root_uid}

The root Device UID of this component device

${silo_parent_did}

The parent Device ID of this component device

${silo_parent_name}

The parent Device name of this component device

${silo_parent_dn}

The parent Device DN of this component device

${silo_parent_uid}

The parent Device UID of this component device

Custom Substitution

Note

The usage of self within custom substitution is deprecated and can yield unexpected results. Data accessed from self can instead be retrieved with substitution functions utilizing out-of-the-box parameters.

You can write your custom substitution in the snippet code. An empty dictionary, called custom_substitution, lets you build your own custom substitutions. Custom Substitution must utilize alpha-numeric and underscore values as the keys or the substitution will not occur successfully. The substitution values should either be a string or a function that returns a string.

Custom substitution can also include functions. These functions have the ability to request any of the out-of-the-box substitution variables. This enables more control over how substitution works and allows for it to be more dynamic across collections. The substitution function must return a string or the collection will not be processed. For example, if you need to extract information out of silo_comp_dn for your substitution, you would write a function that requested silo_comp_dn and return the processed result.

Note

Parameters in the function signature should only use non-special characters for the substitution. If $ and {} are included in the function signature a syntax error will prevent any collections that utilize the snippet from collecting.

Example: String Substitution

In this example we want to add the substitution key, sub_key with a substitution value of sub value. An example Snippet Argument to consume this would be

low_code:
  version: 2
  steps:
   - static_value: ${sub_key}
from silo.apps.errors import error_manager
with error_manager(self):

    from silo.low_code import *
    from silo.apps.collection import create_collections, save_collections

    # =====================================
    # =========== User Editable ===========
    # =====================================
    # List any custom substitutions that need to occur within the snippet arguments
    custom_substitution = {"sub_key": "sub value"}
    # =====================================
    # ========= End User Editable =========
    # =====================================


    collections = create_collections(self)
    snippet_framework(collections, custom_substitution, snippet_id, app=self)
    save_collections(collections, self)

Example: Function Substitution

In this example we want to add the substitution key, new_sub_func that performs an operation against silo_comp_dn and returns the computed value. An example Snippet Argument to consume this would be

low_code:
  version: 2
  steps:
   - static_value: ${new_sub_func}
from silo.apps.errors import error_manager
with error_manager(self):

    from silo.low_code import *
    from silo.apps.collection import create_collections, save_collections

    # =====================================
    # =========== User Editable ===========
    # =====================================
    # List any custom substitutions that need to occur within the snippet arguments
    def my_sub_function(silo_comp_dn):
        return silo_comp_dn.split("/", 1)[0]


    custom_subs = {"new_sub_func": my_sub_function}
    # =====================================
    # ========= End User Editable =========
    # =====================================


    collections = create_collections(self)
    snippet_framework(collections, custom_substitution, snippet_id, app=self)
    save_collections(collections, self)

Example: SL1 Device IDs

For this example, we will collect the aligned organization for a given device. Since part of the URI is dynamic, in this case the device id, we will utilize substitution that will automatically substitute context-aware information into the Snippet Argument. The required operations for collecting the data will be as follows:

  • Perform a HTTP request to /api/device/<device_id> on localhost (due to this being an AIO we can use localhost instead of an ip address or hostname)

  • Interpret the text response as JSON

  • Select a value from the dictionary

After determining how to collect the data, we then need to determine if our tasks have existing steps around them. For this scenario, we will use the following steps:

Steps for collection

Operation

Step

Perform a HTTP request

http

Convert response from JSON

json

Convert the result to a dictionary

jmespath

Now that we know what steps to use, we will need to determine what arguments, if any, need to be supplied to the step.

Writing a custom substitution function

For this example, we want our custom substitution function to return /api/device/<device_id>. After referring to the Custom Substitution document, we can write a function that returns our string.

def generate_uri(silo_did):
    return "/api/device/{}".format(silo_did)

We would need to update the default snippet with our new function too.

from silo.apps.errors import error_manager
with error_manager(self):

    from silo.low_code import *
    from silo.apps.collection import create_collections, save_collections

    # =====================================
    # =========== User Editable ===========
    # =====================================
   def generate_uri(silo_did):
       return "/api/device/{}".format(silo_did)

    # List any custom substitutions that need to occur within the snippet arguments
    custom_substitution = {"generate_uri": generate_uri}
    # =====================================
    # ========= End User Editable =========
    # =====================================


    collections = create_collections(self)
    snippet_framework(collections, custom_substitution, snippet_id, app=self)
    save_collections(collections, self)

Determining Step Arguments

http

After reviewing the available arguments for http and determining that we will be specifying the entire URL, we only need to provide the step with the url arguments. The username / password will automatically be consumed from the credential. Since we plan to utilize the custom substitution function to generate the uri, we will reference that substitution within the url parameter.

http:
  url: http://localhost:80/${generate_uri}
json

After reviewing the available arguments for json, we notice that no arguments are required for this step.

json
jmespath

After reviewing the available arguments for jmespath, we determine that we will need to use value to extract our data.

Note

This section is not a deep-dive into jmespath. For additional documentation around jmespath, refer to the official documentation.

jmespath:
  value: organization

Creating the Snippet Argument

Now that we have the steps and their arguments to perform the collection, we need to write our final Snippet Argument using the low_code version 2 Syntax. We will add all our steps under the steps section, which takes a list of values.

low_code:
  version: 2
  steps:
    - http:
        url: http://localhost:80/${generate_uri}
    - json
    - jmespath:
        value: organization