Expressions
Expressions enable users to dynamically configure input variables by utilizing the output of other resources or configurations. This helps platform teams in creating programmable templates for provisioning infrastructure and applications.
Using resource output as input to another via expressions typically refers to the practice of taking the output or information from one resource and using it as input or configuration for another resource. If it's a Terraform resource template, and there are output variables defined in the terraform configuration, that constitutes the output of the resource. Currently, only Terraform is supported.
Here is an example of a VPC Terraform output containing values that can be utilized as an input for other resources:
output "vpc_id" {
value = module.vpc.vpc_id
}
Application deployments¶
Let's take the example of an environment named env1 based on an environment template named envtemp. This environment includes resources such as vpc, rds, and a Rafay managed K8s cluster, where the K8s cluster and RDS depend on VPC.
A developer/data scientist wishing to deploy an application to the K8s cluster can avoid hardcoding the workload/application manifest with the environment details and instead use the following expression.
$(#environment["resource_name"]["varname"])$
Let's assume that the application needs to include details of the RDS instance. Below is an example snippet of the Terraform output for the RDS resource template.
output "rds_hostname" {
description = "RDS instance hostname"
value = aws_db_instance.db.address
sensitive = true
}
For this specific output example, the workload expression would be:
$(#environment["rds"]["rds_hostname"])$
Below is an example of a workload Helm value file with expressions, where RDS Terraform output values are passed as input values.
env:
celeryBrokerUrl: 'redis://$(#environment["ec-resoource-tmpl"].configuration_endpoint_address):6379/0'
celeryResultBackend: 'redis://$(#environment["ec-resoource-tmpl"].configuration_endpoint_address):6379/0'
debug: "True"
djangoDb: postgresql
postgresHost: '$(#environment["rds-resource-tmpl"].rds_hostname)'
postgresName: postgres
postgresPassword: '$(#environment["rds-resource-tmpl"].rds_password)'
postgresPort: '$(#environment["rds-resource-tmpl"].rds_port)'
postgresUser: '$(#environment["rds-resource-tmpl"].rds_username)'
In case the variable type is a list (array), utilize indexing to reference various values. For example, to bring up a load balancer that has multiple IPs, use the following expression:
$(#environment["loadbalancer"]["public_ips"][0])$
If you are leveraging Rafay Workloads, ensure to select the correct Environment Configuration based on the requirement.
Important
Workload Expressions feature can be leveraged even when third-party GitOps tools such as ArgoCD are used for application deployments.
Dynamic and Static Resource¶
There could be scenarios where the the output of a dynamic/static resource needs to be passed to another resource as part of the environment creation process. You can use the below expression for such scenarios:
$(resource."resource_name".output.otest1.value)$
Let's take an example where a resource template includes dynamic resources vpc and rds, and there is a requirement to pass the vpc ID to rds so that rds is installed in that particular vpc ID. To achieve this, pass the output of the vpc to the rds using the following expression:
$(resource."vpc".output.vpc_id.value)$
The above expression references the output value 'vpc_id' from the 'vpc' resource.
Similarly to dynamic resources, static resource outputs can also be passed to another resource.
Static Environment Resource¶
To pass the output of a static environment resource to another resource, use the below expression:
$(resource."static-env-0".resource."resource-2".output.test3.value)$
Lets' take the example where an environment named "env1" has already been created. If the user intends to create an additional environment with the "rds" resource on top of "env1" without modifying the existing "env1", follow the expression outlined below:
$(resource."env1".resource."rds".output.rds_hostname.value)$
The above expression employs the 'env1' environment name, the static resource name 'rds', and references the output value labeled as 'rds_hostname'. The values can be of any type, such as array, map, and string.
Users can utilize this expression to include 'env1' as a static resource in the new environment alongside the RDS.
Dedicated Resource(s)¶
When creating an environment template, user has the ability to add dynamic or static resources (pre-existing resources).
When the "dynamic" option is selected for resources, users are allowed to enable the dedicated option. When the dedicated option is enabled, dedicated resources are only brought up when a workload is published to that environment.
To use the workload attributes as part of the dedicated resource(s), use the following expression:
$(workload.name)$
(or)
$(workload.id)$
If ElastiCache is a dedicated resource that needs to be brought up for a workload, the user can use the workload name $(workload.name)$
as input to the name
variable of the ElastiCache. So, whenever a workload is published, the dedicated ElastiCache comes up with the name of the workload.
Note: When the workload is unpublished/destroyed, the dedicated resources within that workload will also be destroyed.
Environment Resource(s)¶
Assume a scenario where a user attempts to set up three to four environments using an environment template, and all the resources are being launched in the same AWS region. To prevent naming conflicts, utilize the following expression to create them with dynamic names and IDs.
$(environment.name)$
$(environment.id)$
$(environment.project.name)$
$(environment.project.id)$
$(environment.labels.key)$
Resource Artifact Variables¶
There are instances where the user intends to download Terraform working directory at different stages such as Init, Plan (pre-hook & post-hook), Apply, and Output. Users can download the required artifacts via container hooks using the expression below (from the working directory as a token and url). This enables users to access the artifacts and perform necessary actions such as scanning of terraform code, calculate the cost of the infrastructure etc.
You can use the expressions below to download artifacts:
Artifact Activity
$(resource."rtdependson-0".artifact.workdir.token)$
$(resource."rtdependson-0".artifact.workdir.url)$
Plan Activity
$(resource."rtdependson-0".plan.workdir.token)$
$(resource."rtdependson-0".plan.workdir.url)$
Trigger Expressions¶
Trigger expressions are used to enable dynamic event-driven responses within systems by allowing users to leverage the output of trigger events as input for subsequent actions or workflows.
Use the below trigger expressions to dynamically configure actions and workflows based on event triggers.
trigger.payload.is_sso_user
: To check if the user logged in using Single Sign-On credentialstrigger.payload.userid
: Retrieves the user's identification, typically their email addresstrigger.payload.username
: Fetches the username, which is usually the user's email addresstrigger.payload.type
(type: destroy, force-destroy, force-release-lock): Identifies the type of action triggered, such as deletion or lock releasetrigger.id
: Provides the unique identifier for the trigger eventtrigger.payload
: Represents all data associated with the trigger eventtrigger.reason
: Captures the reason behind the trigger event
Examples
-
When users initiate resource deletion actions, such as "destroy" or "force-destroy," the trigger expression
trigger.payload.type
identifies the type of deletion request. Based on the detected type, the system dynamically initiates automated cleanup processes, ensuring that associated resources are properly released and decommissioned -
When a user attempts to log in to the controller, the trigger expression
trigger.payload.is_sso_user
evaluates whether the user has authenticated using the Single Sign-On mechanism. If the user is an SSO user, expression returns true
Drivers Inputs and Outputs¶
Inputs¶
Dynamic inputs (expressions) can be configured across all fields within the driver. Users can provide values for these inputs during environment deployment or define them within the variables of the config context attached to the driver or defined directly inline. These expressions are evaluated within the execution context during workflow execution.
The standard format for these expressions is $(current.input.<variable-name>)$
, where
For example, if there is a variable named api_key
, reference it as $(current.input.api_key)$
in the configuration.
Below is an example of input file
{
"kind": "Driver",
"metadata": {
"name": "driver-test"
},
"spec": {
"config": {
"type": "container",
"container": {
"image": "jira:latest",
"arguments": [
"-ticket_id",
"$(current.input.ticket_id)$"
],
"env_vars": {
"API_KEY": "$(current.input.api_key)$"
}
}
},
"inputs": [
{
"data": {
"variables": [
{
"name": "api_key",
"value": "********",
"valueType": "text"
},
{
"name": "ticket_id",
"value": "1234",
"valueType": "text"
}
]
}
}
]
}
}
Outputs¶
Drivers' output can be utilized as inputs for subsequent drivers within the workflow. The HTTP driver's response payload is saved as output, while the Container driver uploads the output.json
file to the designated endpoint. This output can be referenced using specific expressions for different hooks.
Example: $(resource.test_resource.hook.onInit.create_ticket.output.ticket_id)$
.
This expression is used to retrieve the value of the ticket_id
generated by the create_ticket
hook during the onInit
stage of the test_resource
resource template. This allows you to reference and use the ticket_id
output in subsequent steps of the workflow.
In the following example, a resource template named "test_resource" includes two hooks: one at the onInit stage and another at the onCompletion stage. The onInit hook is responsible for creating a Jira ticket and uploading the output.json file, which contains the content '{"ticket_id": "1234"}'. The onCompletion hook then uses this data via the output expression $(resource.test_resource.hook.onInit.create_ticket.ticket_id)$
.
{
"kind": "ResourceTemplate",
"metadata": {
"name": "test_resource"
},
"spec": {
"hooks": {
"onInit": [
{
"name": "create_ticket",
"type": "driver",
"driver": {
"data": {
"config": {
"type": "container",
"container": {
"image": "jira:custom",
"commands": ["create"]
}
}
}
}
}
],
"onCompletion": [
{
"name": "send_ticket",
"type": "driver",
"driver": {
"data": {
"config": {
"type": "container",
"container": {
"image": "jira:custom",
"arguments": [
"--ticket-id",
"$(resource.test_resource.hook.onInit.create_ticket.output.ticket_id)$"
]
}
}
}
}
}
]
}
}
}
Resource Template Lifecycle Hooks¶
$(resource.resource_name.hook.onInit.hook_name.output)$
$(resource.resource_name.hook.onSuccess.hook_name.output)$
$(resource.resource_name.hook.onFailure.hook_name.output)$
$(resource.resource_name.hook.onCompletion.hook_name.output)$
Terraform Lifecycle Hooks¶
Deploy Hooks
$(resource.template_name.hook.deploy.init.before.hook_name.output)$
$(resource.template_name.hook.deploy.init.after.hook_name.output)$
$(resource.template_name.hook.deploy.plan.before.hook_name.output)$
$(resource.template_name.hook.deploy.plan.after.hook_name.output)$
$(resource.template_name.hook.deploy.apply.before.hook_name.output)$
$(resource.template_name.hook.deploy.apply.after.hook_name.output)$
$(resource.template_name.hook.deploy.output.before.hook_name.output)$
$(resource.template_name.hook.deploy.output.after.hook_name.output)$
Destroy Hooks
$(resource.template_name.hook.destroy.init.before.hook_name.output)$
$(resource.template_name.hook.destroy.init.after.hook_name.output)$
$(resource.template_name.hook.destroy.plan.before.hook_name.output)$
$(resource.template_name.hook.destroy.plan.after.hook_name.output)$
$(resource.template_name.hook.destroy.destroy.before.hook_name.output)$
$(resource.template_name.hook.destroy.destroy.after.hook_name.output)$
Environment Template Lifecycle Hooks¶
$(environment.hook.onInit.hook_name.output)$
$(environment.hook.onSuccess.hook_name.output)$
$(environment.hook.onFailure.hook_name.output)$
$(environment.hook.onCompletion.hook_name.output)$
Custom Provider¶
The expression $(resource.resource_name.task.task_name.output)$
is used to access the output of a specific task within a resource template. Here's how it breaks down:
resource.resource_name
: Refers to the resource template that contains the tasktask.task_name
: Specifies the particular task within that resource templateoutput
: Refers to the data produced by that task This expression allows subsequent tasks or components to use the output from a previous task, enabling data flow and dependency management within the workflow