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:
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