Calculated expressions in a Cloud Apps product configuration
When setting up a Cloud Apps product configuration, users can use calculated expressions in string values of resource attributes. Such expressions allow you to dynamically generate an attribute value based on calculations, input parameters, and values of other attributes.
Basic syntax
The expressions are based on interpolation syntax
Interpolation
The expressions are enclosed in double curly braces:
Hello {{ expression }} world!
Escaping
To output the {{ and }} combinations, use the \ escape character:
\{{outputs{{\}}outputs}}
Basic use cases
# Simple interpolation
name: "{{ input.environment }}-server"
# Mixed text with expressions
description: "Server for {{ input.environment }} (environment) in {{ input.region }} (region)"
# Escaping
template: "Use \{{ variable \}} to substitute values"
Data types
Strings
String literals are enclosed in single or double quotes:
"string in double quotes"
'string in single quotes'
Numbers
# Integers
42
-17
# Decimal fractions
3.14
-2.5
Boolean values
true
false
Operators
Arithmetic operators
+: Addition-: Subtraction*: Multiplication/: Division%: Remainder of division
# Examples
cpu_count: "{{ input.base_cpu + 2 }}"
memory_gb: "{{ input.memory_mb / 1024 }}"
Comparison operators
==: Equal to!=: Not equal to<: Less than>: Greater than<=: Less than or equal to>=: Greater than or equal to
# Example
high_availability: "{{ input.node_count >= 3 }}"
Logical operators
&&: LogicalAND||: LogicalOR!: LogicalNOT
# Examples
enable_backup: "{{ input.environment == 'prod' && input.backup_enabled }}"
use_spot: "{{ input.cost_optimization || input.environment != 'prod' }}"
is_dev: "{{ !input.production }}"
Ternary operator
Conditional operator condition ? value_if_true : value_if_false
# Examples
instance_type: "{{ input.environment == 'prod' ? 'large' : 'small' }}"
replica_count: "{{ input.high_availability ? 3 : 1 }}"
Variables
Resources
Access to attributes of created resources:
resource.<resource_type>.<resource_name>.<attribute>
# Examples
vpc_id: "{{ resource.yandex_vpc_network.main.id }}"
subnet_cidr: "{{ resource.yandex_vpc_subnet.private.v4_cidr_blocks[0] }}"
instance_ip: "{{ resource.yandex_compute_instance.web_server.network_interface.0.nat_ip_address }}"
Data sources
Access to data source attributes:
data.<source_type>.<source_name>.<attribute>
# Examples
image_id: "{{ data.yandex_compute_image.ubuntu.id }}"
zone_id: "{{ data.yandex_dns_zone.main.zone_id }}"
folder_id: "{{ data.yandex_resourcemanager_folder.current.folder_id }}"
Input parameters
Access to parameters provided by the user:
input.<parameter_name>
# Examples
environment: "{{ input.environment }}"
region: "{{ input.deployment_region }}"
instance_count: "{{ input.replica_count }}"
Artifacts
Access to artifacts, such as Docker images:
artifact.<artifact_name>
# Examples
container_image: "{{ artifact.web_app_image }}"
deployment_package: "{{ artifact.application_archive }}"
Application attributes
Access to system attributes of the current application (Cloud Apps product instance):
application.id: Unique application IDapplication.folderId: Yandex Cloud folder IDapplication.serviceAccountId: Service account ID
# Examples
app_id: "{{ application.id }}"
folder_id: "{{ application.folderId }}"
service_account: "{{ application.serviceAccountId }}"
Access chains
Complex data structures use access chains. The names of variables are written in snake_caseFolder Id → folder_id.
Use dot notation for access to the attributes of a resource or nested object:
<resource>.<level_1_attribute>.<level_2_attribute>.<...>.<level_n_attribute>
Use square bracket notation for access to the elements of an array or map (associative array):
<array>[0].<attribute>["<element>"]
# Access to nested fields via dot
network_id: "{{ resource.yandex_compute_instance.resources.cores }}"
# Access to array elements via square brackets
first_ip: "{{ resource.yandex_vpc_subnet.public.v4_cidr_blocks[0] }}"
second_ip: "{{ resource.yandex_vpc_subnet.public.v4_cidr_blocks[1] }}"
# Combined access
instance_zone: "{{ resource.yandex_compute_instance_group.web.instances[0].zone_id }}"
Functions
min()
Returns the minimum value from the list of arguments:
# Examples
min_cpu: "{{ min(input.cpu_request, 4, input.cpu_limit) }}"
min_memory: "{{ min(1, input.memory_gb) }}"
max()
Returns the maximum value from the list of arguments:
# Examples
max_cpu: "{{ max(input.cpu_request, 2) }}"
max_replicas: "{{ max(input.min_replicas, 1, input.desired_replicas) }}"
Filters
Filters are applied to expressions via | and allow transforming data:
abs
Absolute value of the number:
positive_value: "{{ input.offset | abs }}"
# input: -5 -> output: 5
base64decode
Decoding from Base64
decoded_data: "{{ input.encoded_config | base64decode }}"
base64encode
Encoding a string to Base64
encoded_data: "{{ input.user_data | base64encode }}"
capitalize
All words in a string are capitalized without converting the string to lowercase:
label: "{{ input.type | capitalize }}"
# input: "dataBase" -> output: "DataBase"
default
Default:
region: "{{ input.region | default('ru-central1-a') }}"
# If input.region is empty or null, 'ru-central1-a' will be used
ident
Adding spaces to the beginning of a string:
value: "{{ input.data | ident(2) }}"
# input: "some: 3" -> output: " some: 3"
length
Length of a string or array:
name_length: "{{ input.service_name | length }}"
# input: "webapp" -> output: 6
lower
Converting a string to lowercase:
resource_name: "{{ input.service_name | lower }}"
# input: "WebApp" -> output: "webapp"
replace
Replacing a substring:
# Replacing spaces with hyphens
safe_name: "{{ input.display_name | replace(' ', '-') | lower }}"
# input: "My Service" -> output: "my-service"
sha256
Calculating the SHA256
config_hash: "{{ input.configuration | sha256 }}"
title
Converting a string to lowercase, then capitalizing all words:
display_name: "{{ input.service_name | title }}"
# input: "weB serVice" -> output: "Web Service"
trim
Removing spaces from the beginning and end of a string:
clean_name: "{{ input.name | trim }}"
# input: " app " -> output: "app"
upper
Converting a string to uppercase:
env_name: "{{ input.environment | upper }}"
# input: "prod" -> output: "PROD"
Filter chains
You can join filters together to form chains:
# Combining multiple filters
resource_name: "{{ input.service_name | trim | lower | replace(' ', '-') }}"
# input: " Web Service " -> output: "web-service"
# Using default
final_name: "{{ input.custom_name | default('default-app') | upper }}"
# If input.custom_name is empty -> output: "DEFAULT-APP"
Recommendations and limitations
When using expressions in resource names, explicitly add the unique Cloud Apps product ID. This will allow you to install several applications at once into the same user folder without risking a conflict of resource names.
- type: resource.yandex_compute_instance
name: web_server
config:
name: "my-best-application-{{ application.id }}"
...
Practical use cases
VM configuration
- type: resource.yandex_compute_instance
name: web_server
config:
name: "{{ input.environment }}-web-{{ input.instance_number | default(1) }}-{{ application.id }}"
hostname: "{{ input.service_name | lower | replace(' ', '-') }}.{{ input.domain }}"
cores: "{{ min(input.cpu_cores, 2) }}"
memory: "{{ input.memory_gb * 1024 }}"
boot_disk:
image_id: "{{ data.yandex_compute_image.ubuntu.id }}"
size: "{{ input.disk_size | default(20) }}"
network_interface:
subnet_id: "{{ resource.yandex_vpc_subnet.main.id }}"
nat: "{{ input.environment != 'prod' }}"
metadata:
user-data: |
users:
- name: {{ input.username }}
sudo: 'ALL=(ALL) NOPASSWD:ALL'
shell: /bin/bash
ssh_authorized_keys:
- {{ input.public_key }}
labels:
environment: "{{ input.environment }}"
project: "{{ application.id }}"
cost-center: "{{ input.cost_center | default('default') | upper }}"
Conditional database configuration
- type: resource.yandex_mdb_postgresql_cluster
name: main_db
config:
name: "{{ input.project_name | lower }}-{{ input.environment }}-db-{{ application.id }}"
# Instance size depends on the environment
resources:
resource_preset_id: "{{ input.environment == 'prod' ? 's3-c8-m32' : 's3-c2-m8' }}"
disk_size: "{{ input.environment == 'prod' ? 100 : 20 }}"
disk_type_id: "{{ input.environment == 'prod' ? 'network-ssd' : 'network-hdd' }}"
# Network
network_id: "{{ resource.yandex_vpc_network.main.id }}"
# Access configuration
config:
access:
web_sql: "{{ input.environment == 'dev' }}"
serverless: "{{ input.enable_functions | default(false) }}"
Configuring security groups
- type: resource.yandex_vpc_security_group
name: web_sg
config:
name: "{{ input.project_name }}-web-sg-{{ application.id }}"
network_id: "{{ resource.yandex_vpc_network.main.id }}"
ingress:
# HTTP access
- protocol: TCP
port: 80
v4_cidr_blocks: "{{ input.allow_public_access ? ['0.0.0.0/0'] : input.allowed_cidrs }}"
# HTTPS access only for prod
- protocol: TCP
port: 443
v4_cidr_blocks: "{{ input.environment == 'prod' ? ['0.0.0.0/0'] : [] }}"
# SSH access only from certain IPs
- protocol: TCP
port: 22
v4_cidr_blocks: "{{ input.admin_cidrs | default(['10.0.0.0/8']) }}"
Best practices
Using default values
# Always set reasonable default values for fields with optional values
instance_type: "{{ input.instance_type | default('s3-c4-m8') }}"
region: "{{ input.region | default('ru-central1-a') }}"
Value validation
# Use conditional expressions for validation
cpu_cores: "{{ max(min(input.cpu_cores, 32), 1) }}"
memory_gb: "{{ input.memory_gb >= 1 ? input.memory_gb : 1 }}"
Human-readable resource names
# Create resource names that make sense
name: "{{ input.project_name | lower | replace(' ', '-') }}-{{ input.environment }}-{{ input.component }}"
Conditional logic for environments
# Distinguish configuration by environment
backup_enabled: "{{ input.environment == 'prod' || input.environment == 'staging' }}"
monitoring_level: "{{ input.environment == 'prod' ? 'detailed' : 'basic' }}"
Security
# Limit access based on environment
public_access: "{{ input.environment == 'dev' && input.debug_mode }}"